$npx -y skills add heymegabyte/claude-skills --skill 19-mcp-authoringWhen to author an MCP server, architecture overview (tools/resources/prompts), stdio vs HTTP+SSE transport tradeoffs, registration in .claude.json. Sub-modules: stdio-server-template.md (full TS code), http-server-on-workers.md (Hono + SSE on CF Workers), forge-mcp-from-openapi.m
| 1 | # 19 — MCP Authoring |
| 2 | |
| 3 | Three primitive types: |
| 4 | |
| 5 | - **Tools** — callable functions (JSON schema input → structured output). Model decides when to call. "Do something." |
| 6 | - **Resources** — addressable content (files, DB rows, feeds) returned as text/binary. "Read something." |
| 7 | - **Prompts** — reusable templates with typed args. "Fill and inject." |
| 8 | |
| 9 | Source authority: modelcontextprotocol.io/introduction, `@modelcontextprotocol/sdk` NPM. |
| 10 | |
| 11 | ## When to author an MCP server |
| 12 | |
| 13 | Build when: |
| 14 | |
| 15 | - A REST API/Worker would provide genuine agent value and schema-wrapping cost < benefit |
| 16 | - Tool set needs sharing across multiple Claude sessions without copy-pasting prompts |
| 17 | - CF Worker owns business logic and you want Claude persistent auth-aware access (HTTP transport = zero extra infra) |
| 18 | - Extending the forge pipeline (`--target=mcp-server` — see `forge-mcp-from-openapi.md`) |
| 19 | |
| 20 | Do NOT build when a simple `[[hono-api]]` route + direct `fetch` suffices — MCP adds SDK overhead not justified for one-off integrations. |
| 21 | |
| 22 | ## Architecture |
| 23 | |
| 24 | ``` |
| 25 | Claude Code / Claude Desktop |
| 26 | │ JSON-RPC 2.0 |
| 27 | ▼ |
| 28 | ┌──────────────┐ |
| 29 | │ MCP Server │ |
| 30 | │ ┌────────┐ │ |
| 31 | │ │ tools │ │ ← JSON-schema validated inputs + Zod-validated outputs |
| 32 | │ ├────────┤ │ |
| 33 | │ │resourc.│ │ ← URI-addressed, MIME-typed |
| 34 | │ ├────────┤ │ |
| 35 | │ │prompts │ │ ← Named templates with typed args |
| 36 | │ └────────┘ │ |
| 37 | └──────────────┘ |
| 38 | │ |
| 39 | ▼ |
| 40 | External system (D1 / R2 / Vectorize / external API) |
| 41 | ``` |
| 42 | |
| 43 | Every tool input: `z.parse()` before hitting the system. Every result: Zod-validated before returning. Per `[[contract-first-ai]]` and `[[zod-everywhere]]`. |
| 44 | |
| 45 | ## Transport decision |
| 46 | |
| 47 | | Criterion | stdio | HTTP + SSE | |
| 48 | |---|---|---| |
| 49 | | Where it runs | Local process, same machine as Claude | Any origin — CF Workers, remote server | |
| 50 | | Auth | None (process-level trust) | HTTP headers, Bearer tokens, CF Zero Trust | |
| 51 | | Session state | Process lifetime | DO / KV per session ID | |
| 52 | | Streaming | Native (stdout) | SSE (`text/event-stream`) | |
| 53 | | Setup | `~/.claude.json` mcpServers entry | CF Worker deploy + `.claude.json` remote entry | |
| 54 | | Best for | Dev tools, local scripts, secret-laden CLIs | Shared team tools, SaaS integrations, per-user auth | |
| 55 | |
| 56 | Per `[[cloudflare-lock-in-is-leverage]]`: prefer HTTP on CF Workers over any third-party MCP host. |
| 57 | |
| 58 | ## .claude.json registration |
| 59 | |
| 60 | ### stdio server |
| 61 | |
| 62 | ```json |
| 63 | { |
| 64 | "mcpServers": { |
| 65 | "my-local-tool": { |
| 66 | "command": "node", |
| 67 | "args": ["/absolute/path/to/mcp-server/dist/index.js"], |
| 68 | "env": { "DB_PATH": "/Users/Apple/data/mydb.sqlite" } |
| 69 | } |
| 70 | } |
| 71 | } |
| 72 | ``` |
| 73 | |
| 74 | ### HTTP server (CF Workers) |
| 75 | |
| 76 | ```json |
| 77 | { |
| 78 | "mcpServers": { |
| 79 | "my-worker-tool": { |
| 80 | "url": "https://my-mcp.workers.dev/mcp", |
| 81 | "headers": { "Authorization": "Bearer ${MY_MCP_TOKEN}" } |
| 82 | } |
| 83 | } |
| 84 | } |
| 85 | ``` |
| 86 | |
| 87 | Place at `~/.claude.json` (global) or `.claude.json` at repo root (project-scoped). |
| 88 | |
| 89 | ## Sub-modules |
| 90 | |
| 91 | - `stdio-server-template.md` — complete TypeScript stdio server with sample tool + resource + prompt |
| 92 | - `http-server-on-workers.md` — Hono + MCP SDK + SSE on CF Workers, wrangler.toml, auth |
| 93 | - `forge-mcp-from-openapi.md` — plan for extending `bin/forge-skill-from-openapi.mjs` to emit MCP servers |
| 94 | |
| 95 | ## Quality gates (every MCP server) |
| 96 | |
| 97 | 1. All tool inputs have a Zod schema — never accept raw `unknown` |
| 98 | 2. All tool results conform to a Zod output schema before returning |
| 99 | 3. Errors return MCP `isError: true` with structured `{ code, message }` — never throw raw JS errors |
| 100 | 4. Every tool `description` ≤2 sentences, specific enough for an LLM to decide when to call it |
| 101 | 5. No secret values in tool schemas or resource URIs — pass via `env` block in `.claude.json` |
| 102 | 6. Smoke-test with `npx @modelcontextprotocol/inspector` before registering |
| 103 | |
| 104 | ## Cross-links |
| 105 | |
| 106 | - `[[cloudflare-lock-in-is-leverage]]` — Workers HTTP transport over any third-party MCP host |
| 107 | - `[[ai-agent-supervisor]]` — MCP tools are the supervised boundary for agent actions |
| 108 | - `[[contrac |