Skip to main content
Glama
AGENTS.md7.46 kB
# MCP Deploy Agent Instructions ## Purpose You are converting an MCP (Model Context Protocol) server to be deployable on Vercel serverless. Your goal is to create a working MCP endpoint that can be accessed via HTTP. ## CRITICAL: mcp-handler REQUIRES Next.js App Router **The mcp-handler package ONLY works with Next.js App Router!** If you use `api/server.ts` or vanilla Vercel serverless, you will get: ``` TypeError: Cannot read properties of undefined (reading 'addEventListener') ``` You MUST use `app/mcp/route.ts` with Next.js! --- ## CRITICAL: Use the Fork Template Approach **DO NOT modify the source MCP repo directly.** Instead: 1. **Fork the working template**: `vercel-labs/mcp-for-next.js` 2. **Read the source MCP's `src/index.ts`** to understand its tools 3. **Update `app/mcp/route.ts`** in the forked repo with converted tools 4. **Deploy to Vercel** (no vercel.json needed - Vercel auto-detects Next.js) This approach works because the template has all the correct configurations already. --- ## Working File Structure (Next.js App Router) ``` project/ ├── app/ │ ├── mcp/ │ │ └── route.ts # Creates /mcp endpoint (MODIFY THIS FILE) │ └── [transport]/ │ └── route.ts # Alternative: creates /mcp AND /sse endpoints ├── package.json # MUST have next, react, react-dom, mcp-handler, zod ├── tsconfig.json # Uses moduleResolution: "bundler" └── next.config.ts # Minimal: export default {} ``` **NO vercel.json needed!** Vercel auto-detects Next.js projects. --- ## How to Convert Tools from Source MCP ### Source Pattern (what you'll find in src/index.ts): ```typescript import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { z } from "zod"; const server = new McpServer({ name: "example", version: "1.0.0" }); server.tool( "tool-name", "Tool description", { param1: z.string().describe("Description"), param2: z.number().optional().describe("Optional param"), }, async ({ param1, param2 }) => { // implementation return { content: [{ type: "text", text: result }] }; }, ); const transport = new StdioServerTransport(); await server.connect(transport); ``` ### Converted Pattern (what you write in app/mcp/route.ts): ```typescript import { createMcpHandler } from "mcp-handler"; import { z } from "zod"; const handler = createMcpHandler( async (server) => { server.tool( "tool-name", "Tool description", { param1: z.string().describe("Description"), param2: z.number().optional().describe("Optional param"), }, async ({ param1, param2 }) => { // implementation (or command generation for CLI tools) return { content: [{ type: "text", text: result }] }; } ); }, { capabilities: { tools: { "tool-name": { description: "Tool description" } } } }, { basePath: "", maxDuration: 60, verboseLogs: true, disableSse: true } ); // CRITICAL: Use named exports for Next.js App Router! export { handler as GET, handler as POST, handler as DELETE }; ``` --- ## CRITICAL: CLI Tools Cannot Execute on Serverless If the source MCP uses `node-pty`, `spawn()`, `exec()`, or any CLI execution: **These DO NOT work on Vercel serverless!** Instead, convert them to **return the command string** that users can run locally: ### Example: Converting a CLI-based tool **Source (uses node-pty):** ```typescript server.tool( "do-cero", "Execute Cero for subdomain enumeration", { target: z.string().describe("Target host"), concurrency: z.number().optional(), ports: z.array(z.string()).optional(), }, async ({ target, concurrency, ports }) => { const cero = pty.spawn('cero', [target, ...args]); // ... execute and return output }, ); ``` **Converted (returns command):** ```typescript server.tool( "do-cero", "Execute Cero for subdomain enumeration. Returns command to run locally.", { target: z.string().describe("Target host"), concurrency: z.number().optional(), ports: z.array(z.string()).optional(), }, async ({ target, concurrency, ports }) => { const args: string[] = [target]; if (concurrency) args.push("-c", String(concurrency)); if (ports && ports.length > 0) args.push("-p", ports.join(",")); const command = `cero ${args.join(" ")}`; return { content: [{ type: "text", text: `To run cero locally, execute:\n\n${command}\n\nRun this on your local machine where cero is installed.` }] }; } ); ``` --- ## Packages That DO NOT Work on Serverless Remove these from dependencies if present in source: - `node-pty` - PTY/terminal emulation - `execa`, `cross-spawn` - child process helpers - Any CLI wrapper packages The required dependencies are: - `next` (REQUIRED for mcp-handler!) - `react` (REQUIRED for Next.js) - `react-dom` (REQUIRED for Next.js) - `mcp-handler` (the Vercel MCP handler) - `zod` (for schema validation) --- ## Common Mistakes That Cause Errors ### 500 "addEventListener undefined" Error: - **Cause**: Using `api/server.ts` instead of `app/mcp/route.ts` - **Fix**: mcp-handler REQUIRES Next.js App Router! Use `app/mcp/route.ts` ### HTTP 406 Errors: 1. **Installing @modelcontextprotocol/sdk directly** - conflicts with mcp-handler 2. **Empty capabilities object** - MUST include tool definitions: ```typescript // WRONG: { capabilities: { tools: {} } } // CORRECT: { capabilities: { tools: { "tool-name": { description: "..." } } } } ``` ### Build Errors: - **Missing Next.js**: package.json MUST have next, react, react-dom - **Wrong exports**: Use `export { handler as GET, handler as POST, handler as DELETE };` - **Creating vercel.json**: Not needed for Next.js - delete it if present! --- ## Verification Checklist Before deploying, verify: - [ ] `app/mcp/route.ts` uses `createMcpHandler` from `mcp-handler` - [ ] All tools from source are converted and included - [ ] Each tool is listed in `capabilities.tools` with description - [ ] CLI execution code replaced with command generation - [ ] No `node-pty`, `spawn()`, `exec()` calls remain - [ ] Uses named exports: `export { handler as GET, handler as POST, handler as DELETE };` - [ ] package.json has: next, react, react-dom, mcp-handler, zod - [ ] NO vercel.json created (Vercel auto-detects Next.js) --- ## Testing the Deployment After deployment, test with: ```bash node scripts/test-http-client.mjs https://your-project.vercel.app "/mcp" ``` The endpoint should be at `/mcp` (Next.js App Router creates this from app/mcp/route.ts). --- ## Quick Reference: Conversion Steps 1. `github_fork_repo("vercel-labs", "mcp-for-next.js", "source-name-mcp")` 2. `github_read_file(sourceOwner, sourceRepo, "src/index.ts", "main")` - understand tools 3. `github_read_file(yourUsername, "source-name-mcp", "app/mcp/route.ts", "main")` - get SHA 4. Convert tools and write: `github_write_file(..., convertedCode, sha, ...)` 5. `vercel_create_project(...)` then `vercel_deploy(...)` 6. Poll `vercel_check_status(...)` until READY 7. `test_mcp_endpoint(productionUrl + "/mcp")` - verify it works 8. If errors, read logs, fix, redeploy - **NEVER GIVE UP**

Latest Blog Posts

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/ozgurozkan123/mcpsmuggler'

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