### Install mcp-handler and Dependencies Source: https://github.com/vercel/mcp-handler/blob/main/README.md Install the mcp-handler package along with the Model Context Protocol SDK and Zod for schema validation. Ensure you use version 1.26.0 or later of the SDK due to a past security vulnerability. ```bash npm install mcp-handler @modelcontextprotocol/sdk@1.26.0 zod@^3 ``` -------------------------------- ### In-App MCP Client Usage Source: https://github.com/vercel/mcp-handler/blob/main/docs/CLIENTS.md Integrate the MCP client directly into your application using the SDK. This example demonstrates establishing a connection and making a request. ```typescript import { McpClient } from "@modelcontextprotocol/sdk/client"; const client = new McpClient({ transport: new SSEClientTransport("/api/mcp/mcp"), }); const result = await client.request("yourMethod", { param: "value" }); ``` -------------------------------- ### Dynamic Routing with Next.js Source: https://github.com/vercel/mcp-handler/blob/main/docs/ADVANCED.md Implement dynamic routing for multi-tenant or dynamic MCP servers using Next.js. This example shows how to create a handler that adapts to URL parameters for routing. ```typescript // app/dynamic/[p]/[transport]/route.ts import { createMcpHandler } from "mcp-handler"; import type { NextRequest } from "next/server"; import { z } from "zod"; const handler = async ( req: NextRequest, { params }: { params: Promise<{ p: string; transport: string }> } ) => { const { p, transport } = await params; return createMcpHandler( (server) => { server.registerTool( "roll_dice", { title: "Roll Dice", description: "Roll a dice with a specified number of sides.", inputSchema: { sides: z.number().int().min(2) }, }, async ({ sides }) => { const value = 1 + Math.floor(Math.random() * sides); return { content: [{ type: "text", text: `🎲 You rolled a ${value}!` }], }; } ); }, { capabilities: { tools: { roll_dice: { description: "Roll a dice" }, }, }, }, { redisUrl: process.env.REDIS_URL, basePath: `/dynamic/${p}`, verboseLogs: true, maxDuration: 60, } )(req); }; export { handler as GET, handler as POST, handler as DELETE }; ``` -------------------------------- ### Configure mcp-handler with Nuxt.js h3 Adapter Source: https://context7.com/vercel/mcp-handler/llms.txt Sets up mcp-handler for Nuxt 3 by wrapping it with the h3 framework adapter. This example registers two tools: 'search_products' and 'calculate_shipping'. ```typescript // server/api/mcp/[transport].ts import { createMcpHandler } from "mcp-handler"; import { fromWebHandler } from "h3"; import { z } from "zod"; const handler = createMcpHandler( (server) => { server.registerTool( "search_products", { title: "Search Products", description: "Search the product catalog", inputSchema: { query: z.string().describe("Search query"), category: z.string().optional().describe("Filter by category"), limit: z.number().int().min(1).max(100).default(10), }, }, async ({ query, category, limit }) => { // Simulated product search const products = [ { id: "1", name: "Widget A", category: "widgets", price: 29.99 }, { id: "2", name: "Gadget B", category: "gadgets", price: 49.99 }, ].filter( (p) => p.name.toLowerCase().includes(query.toLowerCase()) && (!category || p.category === category) ); return { content: [ { type: "text", text: JSON.stringify({ results: products.slice(0, limit), total: products.length, }), }, ], }; } ); server.registerTool( "calculate_shipping", { title: "Calculate Shipping", description: "Calculate shipping cost for an order", inputSchema: { weight: z.number().positive().describe("Weight in kg"), destination: z.string().describe("Destination country code"), express: z.boolean().default(false), }, }, async ({ weight, destination, express }) => { const baseRate = destination === "US" ? 5.99 : 15.99; const weightCost = weight * 2.5; const expressFee = express ? 10 : 0; const total = baseRate + weightCost + expressFee; return { content: [ { type: "text", text: `Shipping to ${destination}: $${total.toFixed(2)} (${ express ? "Express" : "Standard" })`, }, ], }; } ); }, { serverInfo: { name: "nuxt-ecommerce-mcp", version: "1.0.0", }, }, { basePath: "/api/mcp", maxDuration: 60, } ); export default fromWebHandler(handler); ``` -------------------------------- ### Create MCP Handler Source: https://context7.com/vercel/mcp-handler/llms.txt This example demonstrates how to create an MCP handler using `createMcpHandler`. It includes registering tools like 'roll_dice' and 'get_weather' with their respective input schemas and asynchronous logic. The handler is configured with server information, capabilities, and specific handler options such as basePath, maxDuration, verboseLogs, and redisUrl. ```APIDOC ## POST /api/[transport] ### Description Creates a route handler for MCP requests that can be exported directly as Next.js API route handlers. This is the primary entry point for setting up an MCP server with tool registration and configuration options. ### Method POST, GET ### Endpoint /api/[transport] ### Parameters #### Path Parameters - **transport** (string) - Required - The transport protocol (e.g., 'sse', 'http'). #### Query Parameters None explicitly defined in the example. #### Request Body Not explicitly defined in the example, but MCP requests typically involve a JSON payload defining the interaction. ### Request Example ```json { "action": "call", "toolName": "roll_dice", "arguments": { "sides": 6 } } ``` ### Response #### Success Response (200) - **content** (array) - The response content from the tool execution, typically an array of objects with 'type' and 'text' properties. #### Response Example ```json { "content": [ { "type": "text", "text": "You rolled a 4!" } ] } ``` ### Handler Configuration Options - **basePath** (string) - Optional - The base path for the API routes. Must match where `[transport]` is located. - **maxDuration** (number) - Optional - SSE connection timeout in seconds. - **verboseLogs** (boolean) - Optional - Enable debug logging. - **redisUrl** (string) - Optional - URL for Redis, used for SSE session resumability. ``` -------------------------------- ### Nuxt.js Usage with MCP Handler Source: https://github.com/vercel/mcp-handler/blob/main/docs/ADVANCED.md Example of integrating the MCP handler into a Nuxt.js application using `h3`'s `fromWebHandler` utility. This sets up a dynamic API endpoint for MCP. ```typescript // server/api/mcp/[transport].ts import { createMcpHandler } from "mcp-handler"; import { fromWebHandler } from "h3"; import { z } from "zod"; const handler = createMcpHandler( (server) => { server.registerTool( "roll_dice", { title: "Roll Dice", description: "Roll a dice with a specified number of sides.", inputSchema: { sides: z.number().int().min(2) }, }, async ({ sides }) => { const value = 1 + Math.floor(Math.random() * sides); return { content: [{ type: "text", text: `🎲 You rolled a ${value}!` }], }; } ); }, {} ); export default fromWebHandler(handler); ``` -------------------------------- ### Quick Start: Next.js API Route with Tool Registration Source: https://github.com/vercel/mcp-handler/blob/main/README.md Set up a Next.js API route using createMcpHandler. Register a 'roll_dice' tool that takes the number of sides as input and returns a random dice roll. The handler is configured with a base path and logging options. ```typescript // app/api/[transport]/route.ts import { createMcpHandler } from "mcp-handler"; import { z } from "zod"; const handler = createMcpHandler( (server) => { server.registerTool( "roll_dice", { title: "Roll Dice", description: "Roll a dice with a specified number of sides.", inputSchema: { sides: z.number().int().min(2), }, }, async ({ sides }) => { const value = 1 + Math.floor(Math.random() * sides); return { content: [{ type: "text", text: `🎲 You rolled a ${value}!` }], }; } ); }, {}, { basePath: "/api", // must match where [transport] is located maxDuration: 60, verboseLogs: true, } ); export { handler as GET, handler as POST }; ``` -------------------------------- ### Generate Protected Resource Metadata Source: https://context7.com/vercel/mcp-handler/llms.txt Generates OAuth Protected Resource Metadata for custom implementations. Useful when you need more control over the metadata response or want to add additional fields. This example shows how to use the generated metadata in a custom handler. ```typescript import { generateProtectedResourceMetadata } from "mcp-handler"; const metadata = generateProtectedResourceMetadata({ authServerUrls: ["https://auth.example.com"], resourceUrl: "https://api.example.com/mcp", additionalMetadata: { // RFC 9728 optional fields scopes_supported: ["read:data", "write:data", "admin"], bearer_methods_supported: ["header"], resource_signing_alg_values_supported: ["RS256", "ES256"], resource_documentation: "https://docs.example.com/mcp-api", }, }); // Use in custom handler export function GET(req: Request) { return new Response(JSON.stringify(metadata), { headers: { "Content-Type": "application/json", "Cache-Control": "max-age=3600", "Access-Control-Allow-Origin": "*", }, }); } ``` -------------------------------- ### Wrap MCP Handler with OAuth Authorization Source: https://context7.com/vercel/mcp-handler/llms.txt Wraps an MCP handler with OAuth authorization support. It validates bearer tokens, checks required scopes, and makes auth information available to tool handlers. Replace the example token verification logic with your actual authentication service. ```typescript // app/api/[transport]/route.ts import type { AuthInfo } from "@modelcontextprotocol/sdk/server/auth/types.js"; import { createMcpHandler, withMcpAuth } from "mcp-handler"; import { z } from "zod"; const handler = createMcpHandler( (server) => { server.registerTool( "get_user_data", { title: "Get User Data", description: "Retrieve authenticated user's data", inputSchema: { fields: z.array(z.string()).describe("Fields to retrieve"), }, }, async ({ fields }, extra) => { // Access auth info via extra.authInfo const userId = extra.authInfo?.extra?.userId; const clientId = extra.authInfo?.clientId; return { content: [ { type: "text", text: JSON.stringify({ userId, clientId, requestedFields: fields, scopes: extra.authInfo?.scopes, }), }, ], }; } ); }, {} ); // Token verification function - replace with your auth service const verifyToken = async ( req: Request, bearerToken?: string ): Promise => { if (!bearerToken) return undefined; // Example: Validate JWT or call auth service try { // const decoded = await validateJWT(bearerToken); const isValid = bearerToken.length > 10; // Replace with real validation if (!isValid) return undefined; return { token: bearerToken, scopes: ["read:user", "write:user"], clientId: "client-123", expiresAt: Math.floor(Date.now() / 1000) + 3600, // 1 hour extra: { userId: "user-456", permissions: ["admin"], }, }; } catch { return undefined; } }; // Wrap handler with authorization const authHandler = withMcpAuth(handler, verifyToken, { required: true, // Require authentication requiredScopes: ["read:user"], // Required OAuth scopes resourceMetadataPath: "/.well-known/oauth-protected-resource", resourceUrl: "https://api.example.com", // Optional: explicit public URL }); export { authHandler as GET, authHandler as POST }; ``` -------------------------------- ### In-app MCP Client Usage with SDK Source: https://context7.com/vercel/mcp-handler/llms.txt Demonstrates how to use the MCP SDK within an application to connect to an MCP server, list available tools, and call a tool. Requires StreamableHTTPClientTransport for connection. ```typescript // In-app client usage with MCP SDK import { Client } from "@modelcontextprotocol/sdk/client/index.js"; import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js"; const client = new Client({ name: "my-app", version: "1.0.0", }); const transport = new StreamableHTTPClientTransport( new URL("https://api.example.com/api/mcp") ); await client.connect(transport); // List available tools const { tools } = await client.listTools(); console.log("Available tools:", tools.map((t) => t.name)); // Call a tool const result = await client.callTool({ name: "roll_dice", arguments: { sides: 6 }, }); console.log("Result:", result.content); // Clean up await client.close(); ``` -------------------------------- ### Create Dynamic Multi-Tenant MCP Handler Source: https://context7.com/vercel/mcp-handler/llms.txt Dynamically create MCP handlers for routes with parameters like tenant and transport. This allows for tenant-specific tool registration and configuration based on URL parameters. ```typescript // app/dynamic/[tenant]/[transport]/route.ts import { createMcpHandler } from "mcp-handler"; import type { NextRequest } from "next/server"; import { z } from "zod"; const handler = async ( req: NextRequest, { params }: { params: Promise<{ tenant: string; transport: string }> } // Changed to Promise<{...}> to match Next.js 13.4+ behavior ) => { const { tenant, transport } = await params; // Load tenant-specific configuration const tenantConfig = await getTenantConfig(tenant); return createMcpHandler( (server) => { // Register tenant-specific tools server.registerTool( "tenant_info", { title: "Tenant Info", description: "Get information about the current tenant", inputSchema: {}, }, async () => ({ content: [ { type: "text", text: JSON.stringify({ tenant, name: tenantConfig.name, plan: tenantConfig.plan, }), }, ], }) ); // Conditionally register tools based on tenant plan if (tenantConfig.plan === "enterprise") { server.registerTool( "advanced_analytics", { title: "Advanced Analytics", description: "Enterprise-only analytics tool", inputSchema: { metric: z.string(), dateRange: z.object({ start: z.string(), end: z.string(), }), }, }, async ({ metric, dateRange }) => ({ content: [ { type: "text", text: `Analytics for ${metric}: {...}` }, ], }) ); } }, { serverInfo: { name: `${tenant}-mcp-server`, version: "1.0.0", }, }, { basePath: `/dynamic/${tenant}`, redisUrl: process.env.REDIS_URL, verboseLogs: process.env.NODE_ENV === "development", maxDuration: 60, } )(req); }; async function getTenantConfig(tenant: string) { // Fetch from database or config service return { name: tenant, plan: "enterprise" }; } export { handler as GET, handler as POST, handler as DELETE }; ``` -------------------------------- ### Client Connection: stdio-only via mcp-remote Source: https://github.com/vercel/mcp-handler/blob/main/README.md For stdio-only clients, use the mcp-remote package. This JSON configuration specifies the command and arguments to launch mcp-remote, connecting it to the MCP handler URL. ```json { "remote-example": { "command": "npx", "args": ["-y", "mcp-remote", "http://localhost:3000/api/mcp"] } } ``` -------------------------------- ### MCP Server Configuration for stdio-only Clients Source: https://context7.com/vercel/mcp-handler/llms.txt Configuration for stdio-only clients (like Claude Desktop) to connect via mcp-remote. Specify the command and arguments to run mcp-remote. ```json // Using mcp-remote for stdio-only clients (Claude Desktop) // macOS: ~/Library/Application Support/Claude/claude_desktop_config.json // Windows: %APPDATA%\Claude\claude_desktop_config.json { "mcpServers": { "my-server": { "command": "npx", "args": ["-y", "mcp-remote", "https://api.example.com/api/mcp"] } } } ``` -------------------------------- ### MCP Server Configuration for Direct Connection Source: https://context7.com/vercel/mcp-handler/llms.txt Configuration for streamable HTTP clients to connect directly to an MCP server. This JSON should be placed in ~/.cursor/mcp.json or your Claude Desktop config. ```json // Direct connection for Streamable HTTP clients // ~/.cursor/mcp.json or Claude Desktop config { "mcpServers": { "my-server": { "url": "https://api.example.com/api/mcp" } } } ``` -------------------------------- ### Create MCP Handler for Next.js API Route Source: https://context7.com/vercel/mcp-handler/llms.txt Use createMcpHandler to set up an MCP server endpoint in Next.js. Register tools, configure server info, and set handler options like basePath and maxDuration. Ensure basePath matches the route location. ```typescript import { createMcpHandler } from "mcp-handler"; import { z } from "zod"; const handler = createMcpHandler( // Server initialization function - register tools, prompts, and resources (server) => { server.registerTool( "roll_dice", { title: "Roll Dice", description: "Roll a dice with a specified number of sides.", inputSchema: { sides: z.number().int().min(2), }, }, async ({ sides }) => { const value = 1 + Math.floor(Math.random() * sides); return { content: [{ type: "text", text: `You rolled a ${value}!` }], }; } ); server.registerTool( "get_weather", { title: "Get Weather", description: "Get current weather for a location.", inputSchema: { location: z.string().describe("City name"), unit: z.enum(["celsius", "fahrenheit"]).default("celsius"), }, }, async ({ location, unit }) => { // Simulated weather data const temp = unit === "celsius" ? 22 : 72; return { content: [ { type: "text", text: `Weather in ${location}: ${temp}° ${unit}, partly cloudy`, }, ], }; } ); }, // Server options (capabilities, serverInfo) { serverInfo: { name: "my-mcp-server", version: "1.0.0", }, capabilities: { tools: {}, }, }, // Handler configuration { basePath: "/api", // Must match where [transport] is located maxDuration: 60, // SSE connection timeout in seconds verboseLogs: true, // Enable debug logging redisUrl: process.env.REDIS_URL, // Optional: for SSE resumability } ); export { handler as GET, handler as POST }; ``` -------------------------------- ### Extract Public URL and Origin from Request Source: https://context7.com/vercel/mcp-handler/llms.txt Use getPublicOrigin and getPublicUrl to correctly determine the public-facing URL and origin, respecting proxy headers like X-Forwarded-Host and X-Forwarded-Proto. Essential for generating callback URLs and resource identifiers. ```typescript import { getPublicOrigin, getPublicUrl } from "mcp-handler"; export async function GET(req: Request) { // getPublicOrigin returns just the origin (protocol + host) // Respects: X-Forwarded-Host, X-Forwarded-Proto, Forwarded (RFC 7239) const origin = getPublicOrigin(req); // Example: "https://api.example.com" // getPublicUrl returns the full URL with path const fullUrl = getPublicUrl(req); // Example: URL object for "https://api.example.com/api/mcp?session=123" // Use for constructing OAuth redirect URLs const callbackUrl = `${origin}/auth/callback`; // Use for generating resource identifiers const resourceId = fullUrl.toString(); return new Response( JSON.stringify({ origin, fullUrl: fullUrl.toString(), pathname: fullUrl.pathname, searchParams: Object.fromEntries(fullUrl.searchParams), }), { headers: { "Content-Type": "application/json" } } ); } // Header examples that getPublicOrigin handles: // X-Forwarded-Host: api.example.com // X-Forwarded-Proto: https // OR // Forwarded: for=192.0.2.60;proto=https;host=api.example.com ``` -------------------------------- ### Direct MCP Server Connection Source: https://github.com/vercel/mcp-handler/blob/main/docs/CLIENTS.md Use this configuration for clients that support Streamable HTTP. Ensure your MCP server is running and accessible at the specified URL. ```json { "remote-example": { "url": "http://localhost:3000/api/mcp" } } ``` -------------------------------- ### MCP Handler Configuration Options Source: https://github.com/vercel/mcp-handler/blob/main/docs/ADVANCED.md Defines the configuration interface for the MCP handler, including options for Redis connection, base path, SSE duration, and logging. ```typescript interface Config { redisUrl?: string; // Redis connection URL for pub/sub basePath?: string; // Base path for MCP endpoints maxDuration?: number; // Maximum duration for SSE connections (seconds) verboseLogs?: boolean; // Enable debug logging } ``` -------------------------------- ### Basic MCP Handler with Authorization Source: https://github.com/vercel/mcp-handler/blob/main/docs/AUTHORIZATION.md Integrates the MCP handler with `withMcpAuth` for token verification and scope checking. Access authenticated user information via `extra.authInfo` in tool handlers. ```typescript // app/api/[transport]/route.ts import type { AuthInfo } from "@modelcontextprotocol/sdk/server/auth/types.js"; import { createMcpHandler, withMcpAuth } from "mcp-handler"; import { z } from "zod"; const handler = createMcpHandler( (server) => { server.registerTool( "echo", { title: "Echo", description: "Echo a message", inputSchema: { message: z.string() }, }, async ({ message }, extra) => { // Access auth info via extra.authInfo return { content: [ { type: "text", text: `Echo: ${message}${extra.authInfo?.token ? ` for user ${extra.authInfo.clientId}` : ""}`, }, ], }; } ); }, {} ); // Token verification function const verifyToken = async ( req: Request, bearerToken?: string ): Promise => { if (!bearerToken) return undefined; // Replace with actual token verification logic const isValid = bearerToken.startsWith("__TEST_VALUE__"); if (!isValid) return undefined; return { token: bearerToken, scopes: ["read:stuff"], clientId: "user123", extra: { userId: "123" }, }; }; // Wrap handler with authorization const authHandler = withMcpAuth(handler, verifyToken, { required: true, requiredScopes: ["read:stuff"], resourceMetadataPath: "/.well-known/oauth-protected-resource", }); export { authHandler as GET, authHandler as POST }; ``` -------------------------------- ### Client Connection: Streamable HTTP Source: https://github.com/vercel/mcp-handler/blob/main/README.md Configure a client to connect directly using Streamable HTTP. This JSON configuration specifies the URL for the MCP handler endpoint. ```json { "remote-example": { "url": "http://localhost:3000/api/mcp" } } ``` -------------------------------- ### Proxying MCP Server with mcp-remote Source: https://github.com/vercel/mcp-handler/blob/main/docs/CLIENTS.md For clients limited to stdio, mcp-remote can proxy Streamable HTTP connections. This is useful for integrating with tools that expect stdin/stdout communication. ```json { "remote-example": { "command": "npx", "args": [ "-y", "mcp-remote", "http://localhost:3000/api/mcp" ] } } ``` -------------------------------- ### OAuth Protected Resource Metadata Endpoint Source: https://github.com/vercel/mcp-handler/blob/main/docs/AUTHORIZATION.md Configures the metadata endpoint for OAuth protected resources. Ensure the path matches `resourceMetadataPath` in your `withMcpAuth` configuration. ```typescript import { protectedResourceHandler, metadataCorsOptionsRequestHandler, } from "mcp-handler"; const handler = protectedResourceHandler({ authServerUrls: ["https://auth-server.com"], }); const corsHandler = metadataCorsOptionsRequestHandler(); export { handler as GET, corsHandler as OPTIONS }; ``` -------------------------------- ### Create OAuth Protected Resource Metadata Endpoint Source: https://context7.com/vercel/mcp-handler/llms.txt Creates an OAuth 2.0 Protected Resource Metadata endpoint based on RFC 9728. This endpoint tells clients which authorization servers can issue tokens for your MCP server. The CORS handler is for browser-based MCP clients. ```typescript // app/.well-known/oauth-protected-resource/route.ts import { protectedResourceHandler, metadataCorsOptionsRequestHandler, } from "mcp-handler"; // Create the metadata handler const handler = protectedResourceHandler({ // Array of OAuth authorization server issuer URLs authServerUrls: [ "https://auth.example.com", "https://accounts.google.com", ], // Optional: explicit resource URL (auto-detected from request if not provided) resourceUrl: "https://api.example.com", }); // CORS handler for browser-based MCP clients const corsHandler = metadataCorsOptionsRequestHandler(); export { handler as GET, corsHandler as OPTIONS }; // Response format: // { // "resource": "https://api.example.com", // "authorization_servers": [ // "https://auth.example.com", // "https://accounts.google.com" // ] // } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.