{"_id":"mcp-tanstack-start","_rev":"4-e1a19fa47230a933522ef342f42536f2","name":"mcp-tanstack-start","dist-tags":{"latest":"0.4.1"},"versions":{"0.2.0":{"name":"mcp-tanstack-start","version":"0.2.0","keywords":["mcp","model-context-protocol","tanstack","tanstack-start","ai","llm","tools"],"author":{"name":"Cody De Arkland"},"license":"MIT","_id":"mcp-tanstack-start@0.2.0","maintainers":[{"name":"codyde","email":"codydearkland@gmail.com"}],"homepage":"https://github.com/codyde/mcp-tanstack-start#readme","bugs":{"url":"https://github.com/codyde/mcp-tanstack-start/issues"},"dist":{"shasum":"ff5dfc5713245676c11ddab542df5d75c3bcdcdf","tarball":"https://registry.npmjs.org/mcp-tanstack-start/-/mcp-tanstack-start-0.2.0.tgz","fileCount":5,"integrity":"sha512-I/moTSq5XMtTbAZXwtJLkBP7MFS4QHxG6yq7egoNeaVAR/mnLCJVJ9T3dO3lcMDVYAJJ9cfELt7uxqlWfMuLbA==","signatures":[{"sig":"MEUCIQDoJYZuKDXO0tWErp6/wt0GTxYJm5TRqYvfZYGUNtmuiQIgL4Oj4/vgI8sOncGNSy5jJpbHdZs0AIEkUbEHfT8H4ds=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":84438},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","module":"dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"396ff3249087879a8c6f0a6240eda503b04e34d3","scripts":{"dev":"tsup --watch","build":"tsup","clean":"rm -rf dist","typecheck":"tsc --noEmit"},"_npmUser":{"name":"codyde","email":"codydearkland@gmail.com"},"repository":{"url":"git+https://github.com/codyde/mcp-tanstack-start.git","type":"git"},"_npmVersion":"10.8.2","description":"MCP (Model Context Protocol) integration for TanStack Start","directories":{},"_nodeVersion":"20.19.5","dependencies":{"@modelcontextprotocol/sdk":"^1.12.0"},"_hasShrinkwrap":false,"devDependencies":{"zod":"^3.24.0","tsup":"^8.3.0","typescript":"^5.7.0","@types/node":"^22.10.0"},"peerDependencies":{"zod":"^3.0.0"},"_npmOperationalInternal":{"tmp":"tmp/mcp-tanstack-start_0.2.0_1764444857874_0.9888179349788222","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"mcp-tanstack-start","version":"0.3.0","keywords":["mcp","model-context-protocol","tanstack","tanstack-start","ai","llm","tools"],"author":{"name":"Cody De Arkland"},"license":"MIT","_id":"mcp-tanstack-start@0.3.0","maintainers":[{"name":"codyde","email":"codydearkland@gmail.com"}],"homepage":"https://github.com/codyde/mcp-tanstack-start#readme","bugs":{"url":"https://github.com/codyde/mcp-tanstack-start/issues"},"dist":{"shasum":"a65bda845b3088d131adbc3971963b47b34db59c","tarball":"https://registry.npmjs.org/mcp-tanstack-start/-/mcp-tanstack-start-0.3.0.tgz","fileCount":5,"integrity":"sha512-mFeGyknrm0DvvxTc7QuA0sQhhjdiTIym5kmmzhmm5xPdeEuuSUXDn6wl9Ki4WAWvA5TOJMB+O2jt+H7SQWyAmA==","signatures":[{"sig":"MEYCIQDLJ/GfCG/QzFyrWgG6YU7PWNMVnBrfirCSLboUXWxGswIhAN6frLBvoKTq+WubcHjjMJap6XHgS4Y/iH21zqJ/X8rA","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":100315},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","module":"dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"d9bef663a4fc4a01e27c765cbc77aa5a146d9173","scripts":{"dev":"tsup --watch","build":"tsup","clean":"rm -rf dist","typecheck":"tsc --noEmit"},"_npmUser":{"name":"codyde","email":"codydearkland@gmail.com"},"repository":{"url":"git+https://github.com/codyde/mcp-tanstack-start.git","type":"git"},"_npmVersion":"10.8.2","description":"MCP (Model Context Protocol) integration for TanStack Start","directories":{},"_nodeVersion":"20.19.5","dependencies":{"@modelcontextprotocol/sdk":"^1.12.0"},"_hasShrinkwrap":false,"devDependencies":{"zod":"^3.24.0","tsup":"^8.3.0","typescript":"^5.7.0","@types/node":"^22.10.0"},"peerDependencies":{"zod":"^3.0.0"},"_npmOperationalInternal":{"tmp":"tmp/mcp-tanstack-start_0.3.0_1764483831382_0.320734634728459","host":"s3://npm-registry-packages-npm-production"}},"0.4.0":{"name":"mcp-tanstack-start","version":"0.4.0","keywords":["mcp","model-context-protocol","tanstack","tanstack-start","ai","llm","tools"],"author":{"name":"Cody De Arkland"},"license":"MIT","_id":"mcp-tanstack-start@0.4.0","maintainers":[{"name":"codyde","email":"codydearkland@gmail.com"}],"homepage":"https://github.com/codyde/mcp-tanstack-start#readme","bugs":{"url":"https://github.com/codyde/mcp-tanstack-start/issues"},"dist":{"shasum":"b0e1fb616b2eb2aa95c36538c34de10bd4dd58ca","tarball":"https://registry.npmjs.org/mcp-tanstack-start/-/mcp-tanstack-start-0.4.0.tgz","fileCount":5,"integrity":"sha512-KEnn64I4vc6hWgppGVmnYbsYKNfQgGWK+RNOZrbJw41iiD8RyXE6K90+9qJeJD8tp1rHh2Dfa0CPj+eShr1FLg==","signatures":[{"sig":"MEYCIQCrSHxV29DAKZLpN7FZ7TRD4snCFmC3+2mGPIukYDa14wIhAJeXsQheJz6+h273dspdiKPoQ68LqhhP2WiHogfqklhh","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":141459},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","module":"dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"196660c5532997907db6e4dc075e533ae1f74b0d","scripts":{"dev":"tsup --watch","build":"tsup","clean":"rm -rf dist","typecheck":"tsc --noEmit"},"_npmUser":{"name":"codyde","email":"codydearkland@gmail.com"},"repository":{"url":"git+https://github.com/codyde/mcp-tanstack-start.git","type":"git"},"_npmVersion":"10.8.2","description":"MCP (Model Context Protocol) integration for TanStack Start","directories":{},"_nodeVersion":"20.19.5","dependencies":{"@modelcontextprotocol/sdk":"^1.12.0"},"_hasShrinkwrap":false,"devDependencies":{"zod":"^3.24.0","tsup":"^8.3.0","typescript":"^5.7.0","@types/node":"^22.10.0"},"peerDependencies":{"zod":"^3.0.0"},"_npmOperationalInternal":{"tmp":"tmp/mcp-tanstack-start_0.4.0_1764489955866_0.4381272477917917","host":"s3://npm-registry-packages-npm-production"}},"0.4.1":{"name":"mcp-tanstack-start","version":"0.4.1","description":"MCP (Model Context Protocol) integration for TanStack Start","type":"module","main":"dist/index.js","module":"dist/index.js","types":"dist/index.d.ts","exports":{".":{"import":"./dist/index.js","types":"./dist/index.d.ts"}},"scripts":{"build":"tsup","dev":"tsup --watch","typecheck":"tsc --noEmit","clean":"rm -rf dist"},"keywords":["mcp","model-context-protocol","tanstack","tanstack-start","ai","llm","tools"],"author":{"name":"Cody De Arkland"},"repository":{"type":"git","url":"git+https://github.com/codyde/mcp-tanstack-start.git"},"bugs":{"url":"https://github.com/codyde/mcp-tanstack-start/issues"},"homepage":"https://github.com/codyde/mcp-tanstack-start#readme","license":"MIT","dependencies":{"@modelcontextprotocol/sdk":"^1.12.0"},"peerDependencies":{"zod":"^3.0.0"},"devDependencies":{"@types/node":"^22.10.0","tsup":"^8.3.0","typescript":"^5.7.0","zod":"^3.24.0"},"_id":"mcp-tanstack-start@0.4.1","gitHead":"cdc64418613383cc0a2e483a069d5ddc94b5f72d","_nodeVersion":"20.20.1","_npmVersion":"10.8.2","dist":{"integrity":"sha512-S0fWE1BtoIgVZ8AscGLnvzj6tJ7r5KWqDBgxMs+DLWOzd/iprGA+SZ95BsZSY2kouLcxqi7uCGhUtHNF8OwlxQ==","shasum":"c556aa9f1db4347cb37fd4df9b33ec4875384e54","tarball":"https://registry.npmjs.org/mcp-tanstack-start/-/mcp-tanstack-start-0.4.1.tgz","fileCount":5,"unpackedSize":144809,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDxTeyxzLZ+8IU4O4YcdQIyVWwK4kmZLA8zw2HxUVrtCAIgIa3J6TDUIUN+KDkzEEN+Fsef2CZy2q4LPD9Xng4UOCE="}]},"_npmUser":{"name":"codyde","email":"codydearkland@gmail.com"},"directories":{},"maintainers":[{"name":"codyde","email":"codydearkland@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/mcp-tanstack-start_0.4.1_1775176390118_0.12026602551747678"},"_hasShrinkwrap":false}},"time":{"created":"2025-11-29T19:34:17.874Z","modified":"2026-04-03T00:33:10.393Z","0.2.0":"2025-11-29T19:34:18.100Z","0.3.0":"2025-11-30T06:23:51.594Z","0.4.0":"2025-11-30T08:05:56.080Z","0.4.1":"2026-04-03T00:33:10.276Z"},"bugs":{"url":"https://github.com/codyde/mcp-tanstack-start/issues"},"author":{"name":"Cody De Arkland"},"license":"MIT","homepage":"https://github.com/codyde/mcp-tanstack-start#readme","keywords":["mcp","model-context-protocol","tanstack","tanstack-start","ai","llm","tools"],"repository":{"type":"git","url":"git+https://github.com/codyde/mcp-tanstack-start.git"},"description":"MCP (Model Context Protocol) integration for TanStack Start","maintainers":[{"name":"codyde","email":"codydearkland@gmail.com"}],"readme":"# mcp-tanstack-start\n\nMCP (Model Context Protocol) integration for [TanStack Start](https://tanstack.com/start). Build AI-powered tools that can be called by LLMs using the standardized MCP protocol.\n\nImplements the [MCP 2025-06-18 Streamable HTTP transport specification](https://modelcontextprotocol.io/specification/2025-06-18/basic/transports).\n\n## Installation\n\n```bash\nnpm install mcp-tanstack-start @modelcontextprotocol/sdk zod\n```\n\nor with your preferred package manager:\n\n```bash\npnpm add mcp-tanstack-start @modelcontextprotocol/sdk zod\nyarn add mcp-tanstack-start @modelcontextprotocol/sdk zod\n```\n\n## Quick Start\n\nGet up and running with a single file. Here's a complete MCP server with tools in one API route:\n\n```typescript\n// src/routes/api/mcp.ts\nimport { createFileRoute } from '@tanstack/react-router'\nimport { createMcpServer, defineTool } from 'mcp-tanstack-start'\nimport { z } from 'zod'\n\n// Define a tool\nconst echoTool = defineTool({\n  name: 'echo',\n  description: 'Echo back a message',\n  parameters: z.object({\n    message: z.string().describe('The message to echo back'),\n  }),\n  execute: async ({ message }) => {\n    return `You said: ${message}`\n  },\n})\n\n// Create the MCP server\nconst mcp = createMcpServer({\n  name: 'my-tanstack-app',\n  version: '1.0.0',\n  instructions: `This is my TanStack Start app with MCP tools.\nYou can use the available tools to interact with the application.`,\n  tools: [echoTool],\n})\n\n// Wire up all HTTP methods with a single handler\nexport const Route = createFileRoute('/api/mcp')({\n  server: {\n    handlers: {\n      all: async ({ request }) => mcp.handleRequest(request),\n    } as Record<string, (ctx: { request: Request }) => Promise<Response>>,\n  },\n})\n```\n\nThat's it! Your MCP server is now live at `/api/mcp`.\n\n> **Note:** We use lowercase `all` due to a case-sensitivity quirk in TanStack Start's handler lookup. The type assertion works around a mismatch between TypeScript types (which expect uppercase) and runtime behavior (which expects lowercase).\n\n## Breaking It Down\n\n### Setting Up the API Route\n\nThe API route is where your MCP server lives. It handles:\n- **POST** - JSON-RPC requests (initialize, tools/list, tools/call, etc.)\n- **GET** - SSE streams for server-to-client notifications\n- **DELETE** - Session termination\n\nThe simplest approach uses a single `all` handler:\n\n```typescript\n// src/routes/api/mcp.ts\nimport { createFileRoute } from '@tanstack/react-router'\n\nexport const Route = createFileRoute('/api/mcp')({\n  server: {\n    handlers: {\n      all: async ({ request }) => mcp.handleRequest(request),\n    } as Record<string, (ctx: { request: Request }) => Promise<Response>>,\n  },\n})\n```\n\nIf you prefer to be explicit about which methods your API supports, you can define each handler separately:\n\n```typescript\n// src/routes/api/mcp.ts\nimport { createFileRoute } from '@tanstack/react-router'\n\nexport const Route = createFileRoute('/api/mcp')({\n  server: {\n    handlers: {\n      GET: async ({ request }) => mcp.handleRequest(request),\n      POST: async ({ request }) => mcp.handleRequest(request),\n      DELETE: async ({ request }) => mcp.handleRequest(request),\n    },\n  },\n})\n```\n\nBoth approaches work identically - choose whichever style you prefer.\n\n### Creating the MCP Server\n\nThe MCP server manages your tools and handles the protocol communication:\n\n```typescript\nconst mcp = createMcpServer({\n  name: 'my-tanstack-app',      // Server name\n  version: '1.0.0',              // Server version\n  instructions: `Optional instructions for AI assistants about how to use your tools.`,\n  tools: [echoTool],             // Array of tools\n})\n```\n\n### Defining Tools\n\nTools are the functions that LLMs can call. Each tool has a name, description, parameters (defined with Zod), and an execute function:\n\n```typescript\nimport { defineTool } from 'mcp-tanstack-start'\nimport { z } from 'zod'\n\nconst echoTool = defineTool({\n  name: 'echo',\n  description: 'Echo back a message',\n  parameters: z.object({\n    message: z.string().describe('The message to echo back'),\n  }),\n  execute: async ({ message }) => {\n    return `You said: ${message}`\n  },\n})\n```\n\nThe `parameters` object uses Zod schemas for type-safe validation. The `execute` function receives the validated parameters and returns a string response.\n\n## Security\n\n### Origin Validation\n\nBy default, the server only accepts requests from localhost origins to prevent [DNS rebinding attacks](https://modelcontextprotocol.io/specification/2025-06-18/basic/transports#security-warning). Configure allowed origins for production:\n\n```typescript\nconst mcp = createMcpServer({\n  name: 'my-app',\n  version: '1.0.0',\n  tools: [...],\n  transport: {\n    allowedOrigins: [\n      'https://my-app.com',\n      'https://api.my-app.com',\n    ],\n  },\n})\n```\n\n> ⚠️ **Warning**: Setting `allowedOrigins: [\"*\"]` disables Origin validation entirely. This is NOT recommended for production deployments.\n\n## Authentication\n\nProtect your MCP endpoint with authentication:\n\n```typescript\n// src/routes/api/mcp.ts\nimport { createFileRoute } from '@tanstack/react-router'\nimport { withMcpAuth } from 'mcp-tanstack-start'\nimport { mcp } from '../../mcp'\nimport { verifyJWT } from '../../lib/auth'\n\nconst authenticatedHandler = withMcpAuth(\n  async (request, auth) => {\n    return mcp.handleRequest(request, { auth })\n  },\n  async (request) => {\n    const token = request.headers.get('Authorization')?.replace('Bearer ', '')\n    if (!token) return null\n    try {\n      const claims = await verifyJWT(token)\n      return { token, claims }\n    } catch {\n      return null\n    }\n  }\n)\n\nexport const Route = createFileRoute('/api/mcp')({\n  server: {\n    handlers: {\n      all: async ({ request }) => authenticatedHandler(request),\n    } as Record<string, (ctx: { request: Request }) => Promise<Response>>,\n  },\n})\n```\n\nAccess auth in tools:\n\n```typescript\nconst userDataTool = defineTool({\n  name: 'get_user_data',\n  description: 'Get data for the authenticated user',\n  parameters: z.object({}),\n  execute: async (params, context) => {\n    const userId = context.auth?.claims?.sub\n    if (!userId) {\n      return { content: [{ type: 'text', text: 'Not authenticated' }], isError: true }\n    }\n    const userData = await fetchUserData(userId)\n    return JSON.stringify(userData)\n  },\n})\n```\n\n## API Reference\n\n### `createMcpServer(config)`\n\nCreates an MCP server instance.\n\n```typescript\nconst mcp = createMcpServer({\n  name: string,           // Server name\n  version: string,        // Server version\n  tools?: ToolDefinition[], // Array of tools\n  instructions?: string,  // Optional instructions for AI\n  transport?: {           // Transport configuration\n    stateful?: boolean,            // Enable stateful sessions (default: false)\n    sessionStore?: SessionStore,   // Custom session store (for stateful mode)\n    allowedOrigins?: string[],     // Allowed origins for CORS/DNS rebinding protection\n    sessionTimeout?: number,       // Session timeout in ms (default: 1 hour)\n    requestTimeout?: number,       // Request timeout in ms (default: 30 seconds)\n    maxBodySize?: number,          // Max request body size (default: 1MB)\n    enableJsonResponse?: boolean,  // Use JSON instead of SSE for responses\n    enableResumability?: boolean,  // Enable SSE event IDs for resumability\n  }\n})\n\n// Returns\nmcp.handleRequest(request: Request, options?: { auth?, signal? }): Promise<Response>\nmcp.addTool(tool: ToolDefinition): void\nmcp.getInfo(): { name: string; version: string }\n```\n\n#### Transport Modes\n\n**Stateless Mode (Default)** - Works everywhere: serverless, edge, containers, and distributed environments. If a session is not found, requests are processed gracefully without errors. Ideal for Vercel, Netlify, Railway, Cloudflare Workers, etc.\n\n**Stateful Mode** - Enables persistent sessions for SSE push notifications. Requires either in-memory storage (single instance only) or a custom session store for distributed deployments.\n\n```typescript\n// Stateless (default) - works on serverless/edge/distributed\nconst mcp = createMcpServer({\n  name: 'my-app',\n  version: '1.0.0',\n  tools: [...],\n});\n\n// Stateful with in-memory sessions (single instance only)\nconst mcp = createMcpServer({\n  name: 'my-app',\n  version: '1.0.0',\n  tools: [...],\n  transport: {\n    stateful: true,\n    sessionTimeout: 3600000, // 1 hour\n  }\n});\n\n// Stateful with custom session store (distributed deployments)\nconst mcp = createMcpServer({\n  name: 'my-app',\n  version: '1.0.0',\n  tools: [...],\n  transport: {\n    stateful: true,\n    sessionStore: myRedisSessionStore,\n  }\n});\n```\n\n#### Custom Session Store\n\nImplement the `SessionStore` interface to persist sessions in Redis, DynamoDB, or any other storage:\n\n```typescript\nimport type { SessionStore, SessionData } from 'mcp-tanstack-start';\n\nconst redisSessionStore: SessionStore = {\n  async get(id: string): Promise<SessionData | null> {\n    const data = await redis.get(`mcp:session:${id}`);\n    return data ? JSON.parse(data) : null;\n  },\n  async set(id: string, session: SessionData, ttlMs: number): Promise<void> {\n    await redis.set(`mcp:session:${id}`, JSON.stringify(session), 'PX', ttlMs);\n  },\n  async delete(id: string): Promise<void> {\n    await redis.del(`mcp:session:${id}`);\n  },\n};\n```\n\n#### Transport Options\n\n| Option | Default | Description |\n|--------|---------|-------------|\n| `stateful` | `false` | Enable stateful session mode. When false, runs in stateless mode suitable for serverless/edge/distributed. |\n| `sessionStore` | In-memory | Custom session store (only used when `stateful: true`). |\n| `allowedOrigins` | `[\"http://localhost\", ...]` | Origins allowed for CORS. Set to `[\"*\"]` to allow all (not recommended for production). |\n| `sessionTimeout` | `3600000` (1 hour) | How long before inactive sessions are cleaned up (stateful mode only). |\n| `requestTimeout` | `30000` (30 sec) | Timeout for individual requests. |\n| `maxBodySize` | `1048576` (1MB) | Maximum request body size in bytes. |\n| `enableJsonResponse` | `false` | Return JSON instead of SSE for POST responses. |\n| `enableResumability` | `true` | Include SSE event IDs for client reconnection support (stateful mode only). |\n\n### `defineTool(config)`\n\nDefines a tool with type-safe parameters.\n\n```typescript\ndefineTool({\n  name: string,\n  description: string,\n  parameters: ZodSchema,\n  execute: (params, context) => Promise<string | Content[] | ToolResult>\n})\n```\n\n### `withMcpAuth(handler, verifyToken, options?)`\n\nWraps a handler with authentication.\n\n```typescript\nwithMcpAuth(handler, verifyToken, {\n  realm?: string,              // WWW-Authenticate realm\n  requiredScopes?: string[],   // Required scopes\n  allowUnauthenticated?: boolean,\n})\n```\n\n### Content Helpers\n\n- `text(content: string)` - Create text content\n- `image(data: string, mimeType: string)` - Create image content (base64)\n- `resource(uri: string, options?)` - Create embedded resource\n\n## Protocol\n\nImplements the [MCP 2025-06-18 Streamable HTTP transport](https://modelcontextprotocol.io/specification/2025-06-18/basic/transports):\n\n### Endpoints\n\n| Method | Purpose |\n|--------|---------|\n| **POST** | JSON-RPC requests (single message per request, no batches) |\n| **GET** | SSE stream for server-to-client notifications (stateful mode only) |\n| **DELETE** | Session termination |\n\n### Features\n\n- **Stateless by Default** - Works on serverless, edge, and distributed environments out of the box\n- **Optional Stateful Mode** - Enable persistent sessions for SSE push notifications\n- **Pluggable Session Store** - Bring your own Redis, DynamoDB, or other storage for distributed deployments\n- **Graceful Session Recovery** - In stateless mode, missing sessions are handled gracefully without errors\n- **Origin Validation** - DNS rebinding attack protection\n- **SSE Resumability** - Event IDs with `Last-Event-ID` header support (stateful mode)\n- **Protocol Versioning** - `MCP-Protocol-Version` header with fallback to `2025-03-26`\n\n### Supported Methods\n\n`initialize`, `initialized`, `tools/list`, `tools/call`, `ping`\n\n### Required Headers\n\nClients must include:\n- `Accept: application/json, text/event-stream` (both required)\n- `Content-Type: application/json`\n- `Mcp-Session-Id: <session-id>` (after initialization)\n- `MCP-Protocol-Version: <version>` (recommended)\n\n## Examples\n\nCheck out the [example blog implementation](https://github.com/codyde/codyde-start) to see mcp-tanstack-start in action with:\n- Blog post listing and retrieval\n- Content search\n- Server info tools\n\n## License\n\nMIT\n","readmeFilename":"README.md"}