// Generated by scripts/generate-manifest.mjs. Do not edit by hand. import type { AddOnCompiled } from '../../../../../types.js' type TemplateRecord = Record type TemplateAddOn = TemplateRecord & { integrations?: Array routes?: Array } type TemplateRenderContext = { [key: string]: any packageManager: any projectName: any typescript: any tailwind: any blank: any js: any jsx: any fileRouter: any codeRouter: any routerOnly: any includeExamples: any addOnEnabled: Record addOnOption: Record addOns: Array integrations: Array routes: Array getPackageManagerAddScript: (...args: Array) => string getPackageManagerRunScript: (...args: Array) => string getPackageManagerExecuteScript: (...args: Array) => string relativePath: (...args: Array) => string integrationImportContent: (...args: Array) => string integrationImportCode: (...args: Array) => string | undefined renderTemplate: (content: string) => string ignoreFile: () => never } type TemplateRenderer = (context: TemplateRenderContext) => string | undefined function __escapeXML(value: unknown) { if (value === undefined || value === null) { return '' } return String(value).replace(/[&<>'"]/g, (character) => { switch (character) { case '&': return '&' case '<': return '<' case '>': return '>' case '"': return '"' case "'": return ''' default: return character } }) } export function getManifestTemplateKey(template: string) { let hash = 0x811c9dc5 for (let i = 0; i < template.length; i++) { hash ^= template.charCodeAt(i) hash = Math.imul(hash, 0x01000193) >>> 0 } return `${hash.toString(16).padStart(8, '0')}:${template.length}` } const templateRenderers: Record = { } export function hasManifestTemplate(template: string) { return getManifestTemplateKey(template) in templateRenderers } export function renderManifestTemplate( template: string, context: TemplateRenderContext, ) { const key = getManifestTemplateKey(template) const renderer = templateRenderers[key] if (!renderer) { throw new Error(`Template ${key} was not precompiled into the manifest`) } return renderer(context) ?? '' } export const addOn = { "name": "MCP", "phase": "setup", "description": "Expose your app as an MCP server so AI clients (Claude, Cursor) can call into it.", "link": "https://mcp.dev", "modes": [ "file-router" ], "type": "add-on", "category": "api", "color": "#10B981", "priority": 42, "warning": "MCP is still in development and may change significantly or not be compatible with other add-ons.\nThe MCP implementation does not support authentication.", "routes": [ { "icon": "Webhook", "url": "/demo/mcp-todos", "name": "MCP", "path": "src/routes/demo.mcp-todos.tsx", "jsName": "MCPTodosDemo" } ], "id": "mcp", "version": "0.0.0", "packageAdditions": { "dependencies": { "@modelcontextprotocol/sdk": "^1.27.1", "zod": "^4.3.6" } }, "readmeIsEjs": false, "files": { "_dot_gitignore.append": "mcp-todos.json", "src/mcp-todos.ts": "import fs from 'node:fs'\n\nconst todosPath = './mcp-todos.json'\n\n// In-memory todos storage\nconst todos = fs.existsSync(todosPath)\n ? JSON.parse(fs.readFileSync(todosPath, 'utf8'))\n : [\n {\n id: 1,\n title: 'Buy groceries',\n },\n ]\n\n// Subscription callbacks per userID\nlet subscribers: ((todos: Todo[]) => void)[] = []\n\nexport type Todo = {\n id: number\n title: string\n}\n\n// Get the todos for a user\nexport function getTodos(): Todo[] {\n return todos\n}\n\n// Add an item to the todos\nexport function addTodo(title: string) {\n todos.push({ id: todos.length + 1, title })\n fs.writeFileSync(todosPath, JSON.stringify(todos, null, 2))\n notifySubscribers()\n}\n\n// Subscribe to cart changes for a user\nexport function subscribeToTodos(callback: (todos: Todo[]) => void) {\n subscribers.push(callback)\n callback(todos)\n return () => {\n subscribers = subscribers.filter((cb) => cb !== callback)\n }\n}\n\n// Notify all subscribers of a user's cart\nfunction notifySubscribers() {\n for (const cb of subscribers) {\n try {\n cb(todos)\n } catch {}\n }\n}\n", "src/routes/demo/api.mcp-todos.ts": "import { createFileRoute } from '@tanstack/react-router'\n\nimport { addTodo, getTodos, subscribeToTodos } from '#/mcp-todos'\n\nexport const Route = createFileRoute('/api/mcp-todos')({\n server: {\n handlers: {\n GET: () => {\n const stream = new ReadableStream({\n start(controller) {\n function ping() {\n try {\n controller.enqueue(`event: ping\\n\\n`)\n setTimeout(ping, 1000)\n } catch {}\n }\n ping()\n const unsubscribe = subscribeToTodos((todos) => {\n controller.enqueue(`data: ${JSON.stringify(todos)}\\n\\n`)\n })\n const todos = getTodos()\n controller.enqueue(`data: ${JSON.stringify(todos)}\\n\\n`)\n return () => unsubscribe()\n },\n })\n return new Response(stream, {\n headers: { 'Content-Type': 'text/event-stream' },\n })\n },\n POST: async ({ request }) => {\n const { title } = await request.json()\n addTodo(title)\n return Response.json(getTodos())\n },\n },\n },\n})\n", "src/routes/demo/mcp-todos.tsx": "import { useCallback, useState, useEffect } from 'react'\nimport { createFileRoute } from '@tanstack/react-router'\n\ntype Todo = {\n id: number\n title: string\n}\n\nexport const Route = createFileRoute('/demo/mcp-todos')({\n component: ORPCTodos,\n})\n\nfunction ORPCTodos() {\n const [todos, setTodos] = useState([])\n\n useEffect(() => {\n const eventSource = new EventSource('/demo/api/mcp-todos')\n eventSource.onmessage = (event) => {\n setTodos(JSON.parse(event.data))\n }\n return () => eventSource.close()\n }, [])\n\n const [todo, setTodo] = useState('')\n\n const submitTodo = useCallback(async () => {\n await fetch('/demo/api/mcp-todos', {\n method: 'POST',\n body: JSON.stringify({ title: todo }),\n })\n setTodo('')\n }, [todo])\n\n return (\n
\n
\n

MCP

\n

Todos

\n
    \n {todos?.map((t) => (\n
  • \n {t.title}\n
  • \n ))}\n
\n
\n setTodo(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter') {\n submitTodo()\n }\n }}\n placeholder=\"Enter a new todo...\"\n className=\"demo-input\"\n />\n \n Add todo\n \n
\n
\n
\n )\n}\n", "src/routes/mcp.ts": "import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport { createFileRoute } from '@tanstack/react-router'\nimport z from 'zod'\n\nimport { handleMcpRequest } from '#/utils/mcp-handler'\n\nimport { addTodo } from '#/mcp-todos'\n\nconst server = new McpServer({\n name: 'start-server',\n version: '1.0.0',\n})\n\nserver.registerTool(\n 'addTodo',\n {\n title: 'Tool to add a todo to a list of todos',\n description: 'Add a todo to a list of todos',\n inputSchema: {\n title: z.string().describe('The title of the todo'),\n },\n },\n ({ title }) => ({\n content: [{ type: 'text', text: String(addTodo(title)) }],\n }),\n)\n\n// server.registerResource(\n// \"counter-value\",\n// \"count://\",\n// {\n// title: \"Counter Resource\",\n// description: \"Returns the current value of the counter\",\n// },\n// async (uri) => {\n// return {\n// contents: [\n// {\n// uri: uri.href,\n// text: `The counter is at 20!`,\n// },\n// ],\n// };\n// }\n// );\n\nexport const Route = createFileRoute('/mcp')({\n server: {\n handlers: {\n POST: async ({ request }) => handleMcpRequest(request, server),\n },\n },\n})\n", "src/utils/mcp-handler.ts": "import { InMemoryTransport } from '@modelcontextprotocol/sdk/inMemory.js'\n\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport type { JSONRPCMessage } from '@modelcontextprotocol/sdk/types.js'\n\nexport async function handleMcpRequest(\n request: Request,\n server: McpServer,\n): Promise {\n try {\n const jsonRpcRequest = (await request.json()) as JSONRPCMessage\n\n const [clientTransport, serverTransport] =\n InMemoryTransport.createLinkedPair()\n\n let responseData: JSONRPCMessage | null = null\n\n clientTransport.onmessage = (message: JSONRPCMessage) => {\n responseData = message\n }\n\n await server.connect(serverTransport)\n\n await clientTransport.start()\n await serverTransport.start()\n\n await clientTransport.send(jsonRpcRequest)\n\n await new Promise((resolve) => setTimeout(resolve, 10))\n\n await clientTransport.close()\n await serverTransport.close()\n\n return Response.json(responseData, {\n headers: {\n 'Content-Type': 'application/json',\n },\n })\n } catch (error) {\n console.error('MCP handler error:', error)\n\n // Return a JSON-RPC error response\n return Response.json(\n {\n jsonrpc: '2.0',\n error: {\n code: -32603,\n message: 'Internal server error',\n data: error instanceof Error ? error.message : String(error),\n },\n id: null,\n },\n {\n status: 500,\n headers: {\n 'Content-Type': 'application/json',\n },\n },\n )\n }\n}\n" }, "deletedFiles": [], "smallLogo": "ModelContextProtocol" } satisfies AddOnCompiled