-
Notifications
You must be signed in to change notification settings - Fork 47
feat: publish example servers to npm #184
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Make example MCP App servers publishable to npm under the @modelcontextprotocol scope: - server-basic-react - server-basic-vanillajs - server-budget-allocator - server-cohort-heatmap - server-customer-segmentation - server-scenario-modeler - server-system-monitor - server-threejs - server-wiki-explorer Changes: - Remove `private: true` from example package.json files - Add proper npm metadata (description, repository, license, files) - Update ext-apps dependency from relative to ^0.2.2 - Copy server-utils.ts into each package for standalone use - Add publish-examples job to npm-publish.yml workflow The examples will be published automatically when a GitHub release is created, after the main SDK package is published. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
@modelcontextprotocol/ext-apps
@modelcontextprotocol/server-basic-react
@modelcontextprotocol/server-basic-vanillajs
@modelcontextprotocol/server-budget-allocator
@modelcontextprotocol/server-cohort-heatmap
@modelcontextprotocol/server-customer-segmentation
@modelcontextprotocol/server-scenario-modeler
@modelcontextprotocol/server-system-monitor
@modelcontextprotocol/server-threejs
@modelcontextprotocol/server-wiki-explorer
commit: |
Resolve conflicts by: - Keep server-utils.ts next to server.ts (not in src/) - Simplify server-utils.ts to stateless HTTP only (no SSE) - Keep main() with explicit --stdio handling in server.ts - Add integration-server from main for E2E testing - Add npm start alias from main
🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
ochafik
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @jerome3o-anthropic !
Merged main and resolved conflicts. Key changes after #182:
- Reverted the server-utils.ts location back to next to server.ts (not in src/)
- Simplified server-utils.ts to stateless HTTP only (removed SSE legacy endpoints)
- Kept main() with explicit --stdio handling in each server.ts
@jonathanhefner I reverted the inline stdio handling in server-utils.ts from #182 — IMO argv checking doesn't belong in a shared helper. Each server's main()
should own that decision, keeping server-utils.ts focused on just the HTTP transport setup.
Update golden screenshots for basic-react and basic-vanillajs after the tool output was simplified from JSON to plain text in #182. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
In that case, why not make it boolean parameter? e.g.: startServer(createServer, process.argv.includes("--stdio"));
// or
startServer(createServer, { stdio: process.argv.includes("--stdio") }); |
| // Two-part registration: tool + resource, tied together by the resource URI. | ||
| const resourceUri = "ui://get-time/mcp-app.html"; | ||
|
|
||
| // Register a tool with UI metadata. When the host calls this tool, it reads | ||
| // `_meta[RESOURCE_URI_META_KEY]` to know which resource to fetch and render | ||
| // as an interactive UI. | ||
| registerAppTool(server, | ||
| "get-time", | ||
| { | ||
| title: "Get Time", | ||
| description: "Returns the current server time as an ISO 8601 string.", | ||
| description: "Returns the current server time.", | ||
| inputSchema: {}, | ||
| _meta: { [RESOURCE_URI_META_KEY]: resourceUri }, | ||
| }, | ||
| async (): Promise<CallToolResult> => { | ||
| const time = new Date().toISOString(); | ||
| return { content: [{ type: "text", text: time }] }; | ||
| return { content: [{ type: "text", text: new Date().toISOString() }] }; | ||
| }, | ||
| ); | ||
|
|
||
| // Register the resource, which returns the bundled HTML/JavaScript for the UI. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since these are educational examples, I would like to preserve these comments.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hopefully restored
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did you mean restored in this PR or elsewhere? They still seem to be removed in the current diff for this PR.
| // Two-part registration: tool + resource, tied together by the resource URI. | ||
| const resourceUri = "ui://get-time/mcp-app.html"; | ||
|
|
||
| // Register a tool with UI metadata. When the host calls this tool, it reads | ||
| // `_meta[RESOURCE_URI_META_KEY]` to know which resource to fetch and render | ||
| // as an interactive UI. | ||
| // MCP Apps require two-part registration: a tool (what the LLM calls) and a | ||
| // resource (the UI it renders). The `_meta` field on the tool links to the | ||
| // resource URI, telling hosts which UI to display when the tool executes. | ||
| registerAppTool(server, | ||
| "get-time", | ||
| { | ||
| title: "Get Time", | ||
| description: "Returns the current server time as an ISO 8601 string.", | ||
| inputSchema: {}, | ||
| _meta: { [RESOURCE_URI_META_KEY]: resourceUri }, | ||
| _meta: { [RESOURCE_URI_META_KEY]: RESOURCE_URI }, | ||
| }, | ||
| async (): Promise<CallToolResult> => { | ||
| const time = new Date().toISOString(); | ||
| return { content: [{ type: "text", text: time }] }; | ||
| return { | ||
| content: [{ type: "text", text: JSON.stringify({ time }) }], | ||
| }; | ||
| }, | ||
| ); | ||
|
|
||
| // Register the resource, which returns the bundled HTML/JavaScript for the UI. | ||
| registerAppResource(server, | ||
| resourceUri, | ||
| resourceUri, | ||
| RESOURCE_URI, | ||
| RESOURCE_URI, | ||
| { mimeType: RESOURCE_MIME_TYPE }, | ||
| async (): Promise<ReadResourceResult> => { | ||
| const html = await fs.readFile(path.join(DIST_DIR, "mcp-app.html"), "utf-8"); | ||
|
|
||
| return { | ||
| contents: [ | ||
| { uri: resourceUri, mimeType: RESOURCE_MIME_TYPE, text: html }, | ||
| // Per the MCP App specification, "text/html;profile=mcp-app" signals | ||
| // to the Host that this resource is indeed for an MCP App UI. | ||
| { uri: RESOURCE_URI, mimeType: RESOURCE_MIME_TYPE, text: html }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like there was a bad rebase. This is reverting some of the changes I made in #182.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hopefully restored
@jonathanhefner The signature would be awkard tbh... If we want to make it real clean, should probably look like: export type ServerOptions = {
name?: string;
} & (
| { type: 'streamable-http', port: number, path?: string } // default path is /mcp
| { type: 'stdio' }
);But then it's more syntax to instantiate it... Wdyt? |
I'm not sure I see the value in providing I also think overriding the Anyway, if you prefer to have separate functions, that's fine. I would suggest something like: process.argv.includes("--stdio") ?
startStdioServer(createServer) :
startHttpServer(createServer); You could add a port argument to |
Summary
Make example MCP App servers publishable to npm under the
@modelcontextprotocolscope.New packages:
@modelcontextprotocol/server-basic-react@modelcontextprotocol/server-basic-vanillajs@modelcontextprotocol/server-budget-allocator@modelcontextprotocol/server-cohort-heatmap@modelcontextprotocol/server-customer-segmentation@modelcontextprotocol/server-scenario-modeler@modelcontextprotocol/server-system-monitor@modelcontextprotocol/server-threejs@modelcontextprotocol/server-wiki-explorerChanges:
private: truefrom example package.json files^0.2.2server-utils.tsinto each package for standalone usepublish-examplesjob tonpm-publish.ymlworkflow (matrix-based, runs in parallel after main SDK is published)The examples will be published automatically when a GitHub release is created.
Test plan
npm run examples:buildnpm publish --workspace examples/basic-server-react --dry-run🤖 Generated with Claude Code