Skip to content

Commit 13197fb

Browse files
authored
Merge pull request #2 from marimo-team/ms/generalize
feat: generalize extension to allow for other resources outside an MCP
2 parents 1a7c7d8 + 269077e commit 13197fb

22 files changed

+2352
-184
lines changed

.github/workflows/demo.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,13 @@ jobs:
3636
run: pnpm demo
3737

3838
- name: 📄 Setup Pages
39-
uses: actions/configure-pages@v3
39+
uses: actions/configure-pages@v5
4040

4141
- name: 📤 Upload artifact
42-
uses: actions/upload-pages-artifact@v2
42+
uses: actions/upload-pages-artifact@v3
4343
with:
4444
path: './demo/dist'
4545

4646
- name: 🚀 Deploy to GitHub Pages
4747
id: deployment
48-
uses: actions/deploy-pages@v2
48+
uses: actions/deploy-pages@v4

demo/index.html

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,15 @@ <h2 class="text-2xl font-bold mb-4">Demo prompts</h2>
3636
<div id="prompts" class="min-h-[50px]"></div>
3737
<p class="text-gray-500 text-sm">Type <code>/</code> to show prompts</p>
3838
</div>
39+
40+
<h2 class="text-2xl font-bold mb-4">Demo without MCP extension (using primitives)</h2>
41+
<div class="border rounded-lg p-4 bg-white shadow-sm">
42+
<div id="primitives-editor" class="min-h-[200px]"></div>
43+
<p class="text-gray-500 text-sm">
44+
This editor uses lower-level primitives: resource completion, hover tooltips, and markdown syntax highlighting
45+
without the full MCP extension. Type <code>@</code> to see resource completions.
46+
</p>
47+
</div>
3948
</main>
4049
<script type="module" src="./index.ts"></script>
4150
</body>

demo/index.ts

Lines changed: 136 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { autocompletion } from "@codemirror/autocomplete";
12
import { markdown } from "@codemirror/lang-markdown";
23
import { tooltips } from "@codemirror/view";
34
import type { Transport } from "@modelcontextprotocol/sdk/shared/transport.js";
@@ -9,7 +10,17 @@ import type {
910
PromptMessage,
1011
} from "@modelcontextprotocol/sdk/types.js";
1112
import { EditorView, basicSetup } from "codemirror";
12-
import { extractResources, mcpExtension } from "../src/mcp";
13+
import {
14+
extractResources,
15+
hoverResource,
16+
resourceCompletion,
17+
resourceInputFilter,
18+
resourceTheme,
19+
resourcesField,
20+
} from "../src";
21+
import type { Resource } from "../src";
22+
import { mcpExtension } from "../src/mcp";
23+
import { resourceDecorations } from "../src/resources/decoration";
1324

1425
class DemoTransport implements Transport {
1526
mockPrompts = [
@@ -196,15 +207,17 @@ Try typing @ to see MCP completions!
196207
const formattedResources = resources
197208
.map(
198209
({ resource }) =>
199-
`${resource.uri} (${resource.type}): ${resource.description || resource.name}`,
210+
`<resource>${resource.uri} (${resource.type}): ${resource.description || resource.name}</resource>`,
200211
)
201212
.join("\n");
202213

203214
if (formattedResources.length === 0) {
204215
prompt.textContent = "No resources found";
205216
} else {
206217
prompt.textContent = `
218+
<doc>
207219
${editor.state.doc.toString()}
220+
</doc>
208221
209222
Resources:
210223
${formattedResources}
@@ -214,5 +227,125 @@ ${formattedResources}
214227
document.querySelector("#editor")?.parentElement?.appendChild(button);
215228
document.querySelector("#editor")?.parentElement?.appendChild(prompt);
216229

217-
return { editor, promptEditor };
230+
// Create a demo using lower-level primitives without MCP extension
231+
const mockResources: Resource[] = [
232+
{
233+
name: "userGuide",
234+
uri: "file://docs/user-guide.md",
235+
mimeType: "text/markdown",
236+
description: "Complete user guide with examples and best practices",
237+
type: "file",
238+
data: {},
239+
},
240+
{
241+
name: "apiDocs",
242+
uri: "file://docs/api.md",
243+
mimeType: "text/markdown",
244+
description: "API reference documentation",
245+
type: "file",
246+
data: {},
247+
},
248+
{
249+
name: "config",
250+
uri: "var://app/config",
251+
mimeType: "application/json",
252+
description: "Application configuration object",
253+
type: "variable",
254+
data: {},
255+
},
256+
{
257+
name: "processData",
258+
uri: "function://utils/processData",
259+
mimeType: "application/javascript",
260+
description: "Processes user input data and returns formatted results",
261+
type: "function",
262+
data: {},
263+
},
264+
];
265+
266+
const markdownLanguage = markdown();
267+
268+
// Create extensions using primitives
269+
const primitivesExtensions = [
270+
basicSetup,
271+
markdownLanguage,
272+
resourcesField,
273+
resourceDecorations,
274+
resourceInputFilter,
275+
autocompletion({
276+
override: [
277+
resourceCompletion(
278+
async () => mockResources,
279+
// Custom formatter for completions
280+
(resource) => ({
281+
detail: `${resource.mimeType || "unknown"} - ${resource.uri}`,
282+
boost: resource.description ? 90 : 50,
283+
}),
284+
),
285+
],
286+
}),
287+
hoverResource({
288+
createTooltip: (resource) => {
289+
const dom = document.createElement("div");
290+
dom.className = "cm-tooltip-cursor cm-tooltip-below";
291+
dom.style.padding = "8px";
292+
dom.style.backgroundColor = "#f8f9fa";
293+
dom.style.border = "1px solid #dee2e6";
294+
dom.style.borderRadius = "4px";
295+
dom.style.maxWidth = "300px";
296+
297+
const title = document.createElement("strong");
298+
title.textContent = resource.name;
299+
title.style.color = "#495057";
300+
dom.appendChild(title);
301+
302+
const uri = document.createElement("div");
303+
uri.style.fontSize = "0.85em";
304+
uri.style.color = "#6c757d";
305+
uri.style.fontFamily = "monospace";
306+
uri.textContent = resource.uri;
307+
dom.appendChild(uri);
308+
309+
if (resource.description) {
310+
const desc = document.createElement("div");
311+
desc.style.marginTop = "6px";
312+
desc.style.fontSize = "0.9em";
313+
desc.textContent = resource.description;
314+
dom.appendChild(desc);
315+
}
316+
317+
if (resource.mimeType) {
318+
const mime = document.createElement("div");
319+
mime.style.marginTop = "4px";
320+
mime.style.fontSize = "0.8em";
321+
mime.style.color = "#868e96";
322+
mime.textContent = `Type: ${resource.mimeType}`;
323+
dom.appendChild(mime);
324+
}
325+
326+
return { dom };
327+
},
328+
}),
329+
resourceTheme,
330+
tooltips(),
331+
];
332+
333+
const primitivesEditor = new EditorView({
334+
doc: `# Primitives Demo
335+
336+
This editor demonstrates using the lower-level exported primitives:
337+
- \`resourceCompletion\` for autocomplete functionality
338+
- \`hoverResource\` for hover tooltips
339+
- \`resourcesField\` for state management
340+
- \`resourceTheme\` for styling
341+
- Standard CodeMirror markdown support
342+
343+
Try typing @ to see resource completions, then hover over the inserted resources:
344+
345+
@`,
346+
extensions: primitivesExtensions,
347+
parent: document.querySelector("#primitives-editor") ?? undefined,
348+
});
349+
350+
return { editor, promptEditor, primitivesEditor };
218351
})();

0 commit comments

Comments
 (0)