From 8fffb2f746e3e053c4b40a8496fa87de23f8df2a Mon Sep 17 00:00:00 2001 From: Den Delimarsky Date: Thu, 19 Mar 2026 01:50:36 +0000 Subject: [PATCH] =?UTF-8?q?feat(plugin):=20mcp-server-dev=20=E2=80=94=20cl?= =?UTF-8?q?ose=20remote-path=20dead-end=20with=20deploy/test/connect=20gui?= =?UTF-8?q?dance?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The remote HTTP path (starred default) previously ended at localhost:3000 with no next steps. Adds CF Workers deploy reference, Inspector test commands, user-connection guide, and a versions ledger. Swaps the build-mcp-app scaffold from stdio to streamable-HTTP to match the remote-first stance. --- .../skills/build-mcp-app/SKILL.md | 17 ++- .../skills/build-mcp-server/SKILL.md | 7 +- .../references/deploy-cloudflare-workers.md | 106 ++++++++++++++++++ .../references/remote-http-scaffold.md | 42 +++++++ .../build-mcp-server/references/versions.md | 25 +++++ 5 files changed, 192 insertions(+), 5 deletions(-) create mode 100644 plugins/mcp-server-dev/skills/build-mcp-server/references/deploy-cloudflare-workers.md create mode 100644 plugins/mcp-server-dev/skills/build-mcp-server/references/versions.md diff --git a/plugins/mcp-server-dev/skills/build-mcp-app/SKILL.md b/plugins/mcp-server-dev/skills/build-mcp-app/SKILL.md index 147f8cb..d2337d3 100644 --- a/plugins/mcp-server-dev/skills/build-mcp-app/SKILL.md +++ b/plugins/mcp-server-dev/skills/build-mcp-app/SKILL.md @@ -174,16 +174,17 @@ Keep widgets **small and single-purpose**. A picker picks. A chart displays. Don **Install:** ```bash -npm install @modelcontextprotocol/sdk @modelcontextprotocol/ext-apps zod +npm install @modelcontextprotocol/sdk @modelcontextprotocol/ext-apps zod express ``` **Server (`src/server.ts`):** ```typescript import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; -import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; +import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js"; import { registerAppTool, registerAppResource, RESOURCE_MIME_TYPE } from "@modelcontextprotocol/ext-apps/server"; +import express from "express"; import { readFileSync } from "node:fs"; import { z } from "zod"; @@ -206,9 +207,19 @@ registerAppResource(server, "Contact Picker", "ui://widgets/picker.html", {}, }), ); -await server.connect(new StdioServerTransport()); +const app = express(); +app.use(express.json()); +app.post("/mcp", async (req, res) => { + const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: undefined }); + res.on("close", () => transport.close()); + await server.connect(transport); + await transport.handleRequest(req, res, req.body); +}); +app.listen(process.env.PORT ?? 3000); ``` +For local-only widget apps (driving a desktop app, reading local files), swap the transport to `StdioServerTransport` and package via the `build-mcpb` skill. + **Widget (`widgets/picker.html`):** ```html diff --git a/plugins/mcp-server-dev/skills/build-mcp-server/SKILL.md b/plugins/mcp-server-dev/skills/build-mcp-server/SKILL.md index a1fdeea..2ba063e 100644 --- a/plugins/mcp-server-dev/skills/build-mcp-server/SKILL.md +++ b/plugins/mcp-server-dev/skills/build-mcp-server/SKILL.md @@ -67,7 +67,8 @@ A hosted service speaking MCP over streamable HTTP. This is the **recommended pa **Choose this unless** the server *must* touch the user's local machine. -→ Scaffold with `references/remote-http-scaffold.md` +→ **Fastest deploy:** Cloudflare Workers — `references/deploy-cloudflare-workers.md` (zero to live URL in two commands) +→ **Portable Node/Python:** `references/remote-http-scaffold.md` (Express or FastMCP, runs on any host) ### Elicitation (structured input, no UI build) @@ -157,7 +158,7 @@ If the user already has a language/stack in mind, go with it — both produce id Once you've settled the four decisions (deployment model, tool pattern, framework, auth), do **one** of: -1. **Remote HTTP, no UI** → Scaffold inline using `references/remote-http-scaffold.md`. This skill can finish the job. +1. **Remote HTTP, no UI** → Scaffold inline using `references/remote-http-scaffold.md` (portable) or `references/deploy-cloudflare-workers.md` (fastest deploy). This skill can finish the job. 2. **MCP app (UI widgets)** → Summarize the decisions so far, then load the **`build-mcp-app`** skill. 3. **MCPB (bundled local)** → Summarize the decisions so far, then load the **`build-mcpb`** skill. 4. **Local stdio prototype** → Scaffold inline (simplest case), flag the MCPB upgrade path. @@ -198,8 +199,10 @@ Tools are one of three server primitives. Most servers start with tools and neve ## Reference files - `references/remote-http-scaffold.md` — minimal remote server in TS SDK and FastMCP +- `references/deploy-cloudflare-workers.md` — fastest deploy path (Workers-native scaffold) - `references/tool-design.md` — writing tool descriptions and schemas Claude understands well - `references/auth.md` — OAuth, CIMD, DCR, token storage patterns - `references/resources-and-prompts.md` — the two non-tool primitives - `references/elicitation.md` — spec-native user input mid-tool (capability check + fallback) - `references/server-capabilities.md` — instructions, sampling, roots, logging, progress, cancellation +- `references/versions.md` — version-sensitive claims ledger (check when updating) diff --git a/plugins/mcp-server-dev/skills/build-mcp-server/references/deploy-cloudflare-workers.md b/plugins/mcp-server-dev/skills/build-mcp-server/references/deploy-cloudflare-workers.md new file mode 100644 index 0000000..2df110a --- /dev/null +++ b/plugins/mcp-server-dev/skills/build-mcp-server/references/deploy-cloudflare-workers.md @@ -0,0 +1,106 @@ +# Deploy to Cloudflare Workers + +Fastest path from zero to a live `https://` MCP URL. Free tier, no credit card to start, two commands to deploy. + +**Trade-off:** This is a Workers-native scaffold, not a deploy target for the Express scaffold in `remote-http-scaffold.md`. Different runtime. If you need portability across hosts, stick with Express. If you just want it live, start here. + +--- + +## Bootstrap + +```bash +npm create cloudflare@latest -- my-mcp-server \ + --template=cloudflare/ai/demos/remote-mcp-authless +cd my-mcp-server +``` + +This pulls a minimal template with the right deps (`agents`, `zod`) and a working `wrangler.jsonc`. + +--- + +## `src/index.ts` + +Replace the template's calculator example with your tools. Use `registerTool()` (same API as the Express scaffold — the `McpServer` instance is identical): + +```typescript +import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { McpAgent } from "agents/mcp"; +import { z } from "zod"; + +export class MyMCP extends McpAgent { + server = new McpServer( + { name: "my-service", version: "0.1.0" }, + { instructions: "Prefer search_items before get_item — IDs aren't guessable." }, + ); + + async init() { + this.server.registerTool( + "search_items", + { + description: "Search items by keyword. Returns up to `limit` matches.", + inputSchema: { + query: z.string().describe("Search keywords"), + limit: z.number().int().min(1).max(50).default(10), + }, + annotations: { readOnlyHint: true }, + }, + async ({ query, limit }) => { + const results = await upstreamApi.search(query, limit); + return { content: [{ type: "text", text: JSON.stringify(results, null, 2) }] }; + }, + ); + } +} + +export default { + fetch(request: Request, env: Env, ctx: ExecutionContext) { + const url = new URL(request.url); + if (url.pathname === "/mcp") { + return MyMCP.serve("/mcp").fetch(request, env, ctx); + } + return new Response("Not found", { status: 404 }); + }, +}; +``` + +`McpAgent` is Cloudflare's wrapper — it handles the streamable-HTTP transport, session routing, and Durable Object plumbing. Your code only touches `this.server`, which is the same `McpServer` class from the SDK. Everything in `tool-design.md` and `server-capabilities.md` applies unchanged. + +--- + +## `wrangler.jsonc` + +The template ships this. The Durable Objects block is **boilerplate** — `McpAgent` uses DO for session state. You don't interact with it directly. + +```jsonc +{ + "name": "my-mcp-server", + "main": "src/index.ts", + "compatibility_date": "2025-03-10", + "compatibility_flags": ["nodejs_compat"], + "migrations": [{ "new_sqlite_classes": ["MyMCP"], "tag": "v1" }], + "durable_objects": { + "bindings": [{ "class_name": "MyMCP", "name": "MCP_OBJECT" }] + } +} +``` + +If you rename the `MyMCP` class, update both `new_sqlite_classes` and `class_name` to match. + +--- + +## Run and deploy + +```bash +npx wrangler dev # → http://localhost:8787/mcp +npx wrangler deploy # → https://my-mcp-server..workers.dev/mcp +``` + +`wrangler deploy` prints the live URL. That's the URL users paste into Claude. + +Secrets (upstream API keys): `npx wrangler secret put UPSTREAM_API_KEY`, then read `env.UPSTREAM_API_KEY` inside `init()`. + +--- + +## OAuth + +Cloudflare ships `@cloudflare/workers-oauth-provider` — a drop-in that handles the authorization server side (CIMD/DCR endpoints, token issuance, consent UI). It wraps your `McpAgent` and gates `/mcp` behind a token check. See `auth.md` for the protocol details; the CF template `cloudflare/ai/demos/remote-mcp-github-oauth` shows the wiring. diff --git a/plugins/mcp-server-dev/skills/build-mcp-server/references/remote-http-scaffold.md b/plugins/mcp-server-dev/skills/build-mcp-server/references/remote-http-scaffold.md index af44a0b..7a9afbb 100644 --- a/plugins/mcp-server-dev/skills/build-mcp-server/references/remote-http-scaffold.md +++ b/plugins/mcp-server-dev/skills/build-mcp-server/references/remote-http-scaffold.md @@ -155,6 +155,48 @@ server.registerTool( --- +## Test it + +The MCP Inspector connects to any transport and lets you poke tools interactively. + +```bash +# Interactive — opens a UI on localhost:6274 +npx @modelcontextprotocol/inspector +# → select "Streamable HTTP", paste http://localhost:3000/mcp, Connect +``` + +For scripted checks (CI, smoke tests): + +```bash +npx @modelcontextprotocol/inspector --cli http://localhost:3000/mcp \ + --transport http --method tools/list + +npx @modelcontextprotocol/inspector --cli http://localhost:3000/mcp \ + --transport http --method tools/call --tool-name search_items --tool-arg query=test +``` + +--- + +## Connect users + +Once deployed, users add the URL directly — no install step. + +| Surface | How | +|---|---| +| **Claude Code** | `claude mcp add --transport http ` (add `--scope user` for global, `--header "Authorization: Bearer ..."` for auth) | +| **Claude Desktop / Claude.ai** | Settings → Connectors → Add custom connector. **Not** `claude_desktop_config.json` — remote servers configured there are ignored. | +| **Connector directory** | Anthropic maintains a submission guide for listing in the public connector directory. | + +--- + +## Deploy + +**Fastest path:** Cloudflare Workers — two commands from zero to a live `https://` URL on the free tier. Uses a Workers-native scaffold (not Express). → `deploy-cloudflare-workers.md` + +**This Express scaffold** runs on any Node host — Render, Railway, Fly.io, a VPS. Containerize it (`node:20-slim`, copy, `npm ci`, `node dist/server.js`) and ship. FastMCP is the same story with a Python base image. + +--- + ## Deployment checklist - [ ] `POST /mcp` responds to `initialize` with server capabilities diff --git a/plugins/mcp-server-dev/skills/build-mcp-server/references/versions.md b/plugins/mcp-server-dev/skills/build-mcp-server/references/versions.md new file mode 100644 index 0000000..81e2110 --- /dev/null +++ b/plugins/mcp-server-dev/skills/build-mcp-server/references/versions.md @@ -0,0 +1,25 @@ +# Version pins + +Every version-sensitive claim in this skill, in one place. When updating the skill, check these first. + +| Claim | Where stated | Last verified | +|---|---|---| +| `@modelcontextprotocol/ext-apps@1.2.2` CDN pin | `build-mcp-app/SKILL.md`, `build-mcp-app/references/widget-templates.md` (4×) | 2026-03 | +| Claude Code ≥2.1.76 for elicitation | `elicitation.md:15`, `build-mcp-server/SKILL.md:43,76` | 2026-03 | +| MCP spec 2025-11-25 CIMD/DCR status | `auth.md:20,24,41` | 2026-03 | +| MCPB manifest schema v0.4 | `build-mcpb/references/manifest-schema.md` | 2026-03 | +| CF `agents` SDK / `McpAgent` API | `deploy-cloudflare-workers.md` | 2026-03 | +| CF template path `cloudflare/ai/demos/remote-mcp-authless` | `deploy-cloudflare-workers.md` | 2026-03 | + +## How to verify + +```bash +# ext-apps latest +npm view @modelcontextprotocol/ext-apps version + +# CF template still exists +gh api repos/cloudflare/ai/contents/demos/remote-mcp-authless/src/index.ts --jq '.sha' + +# MCPB schema +curl -sI https://raw.githubusercontent.com/anthropics/mcpb/main/schemas/mcpb-manifest-v0.4.schema.json | head -1 +```