Skip to main content
Glama
by hamchowderr
CLAUDE.md9.74 kB
# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Project Overview This is an MCP (Model Context Protocol) server template designed to run on Vercel using serverless functions. It uses the `mcp-handler` package (v1.0.1) to create MCP servers that expose tools, prompts, and resources via HTTP/SSE transports. ## Development Commands **Local development:** ```sh vercel dev ``` **Test the MCP server (SSE transport):** ```sh node scripts/test-client.mjs https://your-deployment-url.vercel.app # Or for local testing: node scripts/test-client.mjs http://localhost:3000 ``` **Test the MCP server (Streamable HTTP transport):** ```sh node scripts/test-streamable-http-client.mjs https://your-deployment-url.vercel.app ``` ## Architecture ### Request Flow ``` Client Request ↓ Vercel Edge Network ↓ vercel.json rewrites all /(.+) → /api/server ↓ api/server.ts exports handler as GET/POST/DELETE ↓ mcp-handler routes by HTTP method + path ↓ - /mcp → Streamable HTTP transport - /sse → SSE transport ↓ Zod validation → Handler execution → Response ``` ### Core Components **`api/server.ts`** - The main MCP server handler. All routes are rewritten to this file via `vercel.json`. This is where you define MCP tools, prompts, and resources. **Pattern:** ```typescript import { createMcpHandler } from "mcp-handler"; import { z } from "zod"; const handler = createMcpHandler((server) => { // Define tools, prompts, resources here }); // CRITICAL: Export all three HTTP methods export { handler as GET, handler as POST, handler as DELETE }; ``` **Why all three HTTP methods?** - `GET` - Used for SSE transport connections and listing operations - `POST` - Primary method for tool invocations and MCP protocol requests - `DELETE` - Used for cleanup/disconnection operations **`mcp-handler`** - Wraps `@modelcontextprotocol/sdk` to create a Vercel-compatible serverless MCP server. Internally handles routing, transport negotiation, and protocol operations. **`vercel.json`** - Rewrites ALL routes to `/api/server`, enabling the MCP server to handle both `/mcp` (HTTP transport) and `/sse` (SSE transport) endpoints from a single serverless function. ### Transport Types The server supports two transport mechanisms: **1. Streamable HTTP (`/mcp` endpoint)** ```javascript import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js"; const transport = new StreamableHTTPClientTransport(new URL(`${origin}/mcp`)); ``` - Request-response pattern with streaming support - Better for serverless/stateless environments like Vercel - Primary endpoint for MCP client integration **2. SSE - Server-Sent Events (`/sse` endpoint)** ```javascript import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js"; const transport = new SSEClientTransport(new URL(`${origin}/sse`)); ``` - Real-time, long-lived connections - Server pushes events as a stream - Uses HTTP GET for establishing connection ### Server API Methods The `server` object passed to `createMcpHandler()` provides these methods: **`server.tool(name, description, schema, handler)`** Defines a callable tool with automatic Zod validation. ```typescript server.tool( "get_weather", // Tool identifier "Get current weather at a location", // Human-readable description { // Zod schema object latitude: z.number(), longitude: z.number(), city: z.string(), }, async ({ latitude, longitude, city }) => { // Typed handler // Implementation return { content: [{ type: "text", text: "..." }], }; }, ); ``` **Schema patterns:** ```typescript // Simple validation { sides: z.number().int().min(2) } // Complex validation { email: z.string().email(), age: z.number().int().min(0).max(120), tags: z.array(z.string()).optional(), metadata: z.record(z.string(), z.any()).default({}), } ``` **`server.prompt()` and `server.resource()`** These capabilities exist in the MCP protocol but are not demonstrated in this template. Based on the client capabilities (see `scripts/test-client.mjs:16`), they follow similar patterns to `server.tool()`. ## Response Format Tool handlers **must** return an object with a `content` array: ```typescript return { content: [ { type: "text", text: "Response message" }, ], }; ``` **Multiple content items:** ```typescript return { content: [ { type: "text", text: "First piece of info" }, { type: "text", text: "Second piece of info" }, ], }; ``` **Content types:** - `type: "text"` - Text content (requires `text` field) - `type: "image"` - Image data (likely requires `url` or `data`) - `type: "resource"` - Resource references (not demonstrated in template) **Required fields:** - `content` array (required) - Each item must have `type` - Type-specific fields (e.g., `text` for "text" type) ## Input Validation Validation uses Zod schemas defined in the tool's third parameter. The `mcp-handler` automatically validates inputs before calling your handler. **Common Zod validators:** ```typescript z.string() // Any string z.number() // Any number z.number().int() // Integer only z.number().min(2) // Minimum value z.string().email() // Email format z.string().url() // URL format z.array(z.string()) // Array of strings z.object({ ... }) // Nested object .optional() // Make field optional .default(value) // Default value ``` **Validation failures** are handled automatically by `mcp-handler` and return errors to the client before your handler is invoked. ## Error Handling The template examples don't show explicit error handling, but recommended pattern: ```typescript server.tool( "fetch_data", "Fetches data from external API", { url: z.string().url() }, async ({ url }) => { try { const response = await fetch(url); if (!response.ok) { throw new Error(`HTTP ${response.status}: ${response.statusText}`); } const data = await response.json(); return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }], }; } catch (error) { return { content: [{ type: "text", text: `Error: ${error.message}` }], }; } }, ); ``` ## MCP Client Integration **For MCP client applications (like Claude Desktop):** ``` https://your-deployment-url.vercel.app/mcp ``` **Client connection pattern:** ```javascript import { Client } from "@modelcontextprotocol/sdk/client/index.js"; import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js"; const transport = new StreamableHTTPClientTransport( new URL("https://your-deployment-url.vercel.app/mcp") ); const client = new Client( { name: "my-client", version: "1.0.0" }, { capabilities: { prompts: {}, resources: {}, tools: {} } } ); await client.connect(transport); const tools = await client.listTools(); ``` ## Vercel Configuration **vercel.json structure:** ```json { "rewrites": [{ "source": "/(.+)", "destination": "/api/server" }], "functions": { "api/server.ts": { "maxDuration": 60 } } } ``` **Critical settings:** - **Fluid Compute**: Must be enabled in Vercel dashboard for efficient execution - **Max Duration**: - Default: 60 seconds (all accounts) - Pro/Enterprise: Can increase to 800 seconds - **Rewrites**: Routes ALL paths to the single serverless function ## Dependencies **Production:** - `mcp-handler` (^1.0.1) - Serverless MCP handler wrapping `@modelcontextprotocol/sdk` - `zod` (^3.24.2) - Schema validation **Development:** - `@types/node` (^22.13.10) - TypeScript type definitions **Package manager:** pnpm v9.4.0 ## TypeScript Configuration **Module system:** NodeNext (ES modules with Node.js resolution) - `"type": "module"` in package.json - Use `.mjs` for scripts or ES module syntax in `.ts` files **Compiler options:** - Target: ES2021 - Strict mode: enabled - Declaration files: generated - Includes: `src/**/*` and `api/**/*` ## Adding New Tools 1. Import dependencies in `api/server.ts` 2. Define tool inside `createMcpHandler()` callback 3. Use Zod schemas for type-safe parameters 4. Return `{ content: [...] }` format 5. Add error handling for external API calls **Example:** ```typescript server.tool( "my_tool", "Description of what the tool does", { param1: z.string(), param2: z.number().optional(), }, async ({ param1, param2 }) => { try { // Tool implementation const result = await someOperation(param1, param2); return { content: [{ type: "text", text: result }], }; } catch (error) { return { content: [{ type: "text", text: `Error: ${error.message}` }], }; } }, ); ``` ## Extension Points Based on MCP protocol capabilities, you can extend this template with: 1. **Multiple tools** - Add as many `server.tool()` calls as needed 2. **Prompts** - Use `server.prompt()` to define reusable prompt templates 3. **Resources** - Use `server.resource()` to expose data or documents 4. **External APIs** - Integrate with any HTTP API (see weather tool example) 5. **State management** - mcp-handler includes Redis support for caching/sessions ## Common Pitfalls 1. ❌ Forgetting to export all three HTTP methods (GET, POST, DELETE) 2. ❌ Returning raw strings instead of `{ content: [...] }` format 3. ❌ Not wrapping content in an array 4. ❌ Skipping Zod validation (loses type safety) 5. ❌ Exceeding maxDuration without upgrading Vercel plan 6. ❌ Not enabling Fluid Compute in Vercel settings

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/hamchowderr/vercel-mcp-template'

If you have feedback or need assistance with the MCP directory API, please join our Discord server