1. Conduid
  2. AI
  3. Tanstack Start
MCP server · AI

Tanstack Start

MCP (Model Context Protocol) integration for TanStack Start

Unclaimed last commit 6 months ago ai
43Fair

Scored 5 days ago · breakdown

About Tanstack Start

Tanstack Start is an MCP server published by codyde in the AI category: mCP (Model Context Protocol) integration for TanStack Start.

The repository has 3 stars and 0 forks, with the last commit 6 months ago. Six months or more without a commit doesn't mean the server is broken, but check the open issues before depending on it in production.

Install

From source
git clone https://github.com/codyde/mcp-tanstack-start

This server has no ConduID identity, so agent calls to it are not receipted. Pin the version you install and review the source before granting it credentials.

Ask AI

✦

Ask AI about Tanstack Start

Powered by Claude · Grounded in docs

I know everything about Tanstack Start. Ask me about installation, configuration, usage, or troubleshooting.

Security checks

Static checks derived from the repository 5 days ago. Heuristics on the source, not an audit.

  • ✓README presentThe repository ships documentation.
  • !License declaredNo license file. Legally you have no right to use it in a product.
  • !Tests presentNo tests found. Behaviour changes may go unnoticed between versions.
  • ✓Dependencies pinnedA lockfile pins dependency versions.
  • ✓No dynamic code executionSource scan found no eval, dynamic Function, or shell execution.
  • !Scoped permissionsDoesn't declare a permission scope. Assume it can do anything its process can.

Releases

v0.4.1v0.4.1 - Zod 4 Compatibility · 2 Apr 2026What's Changed Added Zod 4 compatibility for `extractZodShape()` schema extraction Added `isZodSchemaLike()` and `isZodRawShape()` helpers for robust schema detection across Zod 3 and 4 Accept raw shape objects (`{ key: z.string() }`)…
v0.4.0v0.4.0 - Stateless Mode by Default · 30 Nov 2025🚀 Stateless Mode by Default This release makes mcp-tanstack-start work reliably on serverless, edge, and container deployments. ⚠️ Breaking Changes Default mode is now stateless - sessions are handled gracefully without persistent storage…
v0.3.0v0.3.0 · 30 Nov 2025feat: implement Mcp-Session-Id based session management per MCP spec Added proper session management with unique session IDs per client Sessions are tracked via Mcp-Session-Id header as per the spec Support for multiple concurrent client…
v0.2.0v0.2.0 - mcp-tanstack-start · 29 Nov 2025Breaking Changes Package renamed from `mcp-start` to `mcp-tanstack-start` Update your dependencies: npm uninstall mcp-start npm install mcp-tanstack-start Update your imports: // Before import { createMcpServer, defineTool } from…
v0.1.1v0.1.1 · 29 Nov 2025What's Changed Bug Fixes Fix TypeScript variance error when passing tool arrays to `createMcpServer` Add `AnyToolDefinition` type alias for proper type compatibility Details The generic `ToolDefinition<TParams>` type caused variance issues…

README

mcp-tanstack-start

MCP (Model Context Protocol) integration for TanStack Start. Build AI-powered tools that can be called by LLMs using the standardized MCP protocol.

Implements the MCP 2025-06-18 Streamable HTTP transport specification.

Installation

npm install mcp-tanstack-start @modelcontextprotocol/sdk zod

or with your preferred package manager:

pnpm add mcp-tanstack-start @modelcontextprotocol/sdk zod
yarn add mcp-tanstack-start @modelcontextprotocol/sdk zod

Quick Start

Get up and running with a single file. Here's a complete MCP server with tools in one API route:

// src/routes/api/mcp.ts
import { createFileRoute } from '@tanstack/react-router'
import { createMcpServer, defineTool } from 'mcp-tanstack-start'
import { z } from 'zod'

// Define a tool
const echoTool = defineTool({
  name: 'echo',
  description: 'Echo back a message',
  parameters: z.object({
    message: z.string().describe('The message to echo back'),
  }),
  execute: async ({ message }) => {
    return `You said: ${message}`
  },
})

// Create the MCP server
const mcp = createMcpServer({
  name: 'my-tanstack-app',
  version: '1.0.0',
  instructions: `This is my TanStack Start app with MCP tools.
You can use the available tools to interact with the application.`,
  tools: [echoTool],
})

// Wire up all HTTP methods with a single handler
export const Route = createFileRoute('/api/mcp')({
  server: {
    handlers: {
      all: async ({ request }) => mcp.handleRequest(request),
    } as Record<string, (ctx: { request: Request }) => Promise<Response>>,
  },
})

That's it! Your MCP server is now live at /api/mcp.

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).

Breaking It Down

Setting Up the API Route

The API route is where your MCP server lives. It handles:

  • POST - JSON-RPC requests (initialize, tools/list, tools/call, etc.)
  • GET - SSE streams for server-to-client notifications
  • DELETE - Session termination

The simplest approach uses a single all handler:

// src/routes/api/mcp.ts
import { createFileRoute } from '@tanstack/react-router'

export const Route = createFileRoute('/api/mcp')({
  server: {
    handlers: {
      all: async ({ request }) => mcp.handleRequest(request),
    } as Record<string, (ctx: { request: Request }) => Promise<Response>>,
  },
})

If you prefer to be explicit about which methods your API supports, you can define each handler separately:

// src/routes/api/mcp.ts
import { createFileRoute } from '@tanstack/react-router'

export const Route = createFileRoute('/api/mcp')({
  server: {
    handlers: {
      GET: async ({ request }) => mcp.handleRequest(request),
      POST: async ({ request }) => mcp.handleRequest(request),
      DELETE: async ({ request }) => mcp.handleRequest(request),
    },
  },
})

Both approaches work identically - choose whichever style you prefer.

Creating the MCP Server

The MCP server manages your tools and handles the protocol communication:

const mcp = createMcpServer({
  name: 'my-tanstack-app',      // Server name
  version: '1.0.0',              // Server version
  instructions: `Optional instructions for AI assistants about how to use your tools.`,
  tools: [echoTool],             // Array of tools
})

Defining Tools

Tools are the functions that LLMs can call. Each tool has a name, description, parameters (defined with Zod), and an execute function:

import { defineTool } from 'mcp-tanstack-start'
import { z } from 'zod'

const echoTool = defineTool({
  name: 'echo',
  description: 'Echo back a message',
  parameters: z.object({
    message: z.string().describe('The message to echo back'),
  }),
  execute: async ({ message }) => {
    return `You said: ${message}`
  },
})

The parameters object uses Zod schemas for type-safe validation. The execute function receives the validated parameters and returns a string response.

Security

Origin Validation

By default, the server only accepts requests from localhost origins to prevent DNS rebinding attacks. Configure allowed origins for production:

const mcp = createMcpServer({
  name: 'my-app',
  version: '1.0.0',
  tools: [...],
  transport: {
    allowedOrigins: [
      'https://my-app.com',
      'https://api.my-app.com',
    ],
  },
})

⚠️ Warning: Setting allowedOrigins: ["*"] disables Origin validation entirely. This is NOT recommended for production deployments.

Authentication

Protect your MCP endpoint with authentication:

// src/routes/api/mcp.ts
import { createFileRoute } from '@tanstack/react-router'
import { withMcpAuth } from 'mcp-tanstack-start'
import { mcp } from '../../mcp'
import { verifyJWT } from '../../lib/auth'

const authenticatedHandler = withMcpAuth(
  async (request, auth) => {
    return mcp.handleRequest(request, { auth })
  },
  async (request) => {
    const token = request.headers.get('Authorization')?.replace('Bearer ', '')
    if (!token) return null
    try {
      const claims = await verifyJWT(token)
      return { token, claims }
    } catch {
      return null
    }
  }
)

export const Route = createFileRoute('/api/mcp')({
  server: {
    handlers: {
      all: async ({ request }) => authenticatedHandler(request),
    } as Record<string, (ctx: { request: Request }) => Promise<Response>>,
  },
})

Access auth in tools:

const userDataTool = defineTool({
  name: 'get_user_data',
  description: 'Get data for the authenticated user',
  parameters: z.object({}),
  execute: async (params, context) => {
    const userId = context.auth?.claims?.sub
    if (!userId) {
      return { content: [{ type: 'text', text: 'Not authenticated' }], isError: true }
    }
    const userData = await fetchUserData(userId)
    return JSON.stringify(userData)
  },
})

API Reference

createMcpServer(config)

Creates an MCP server instance.

const mcp = createMcpServer({
  name: string,           // Server name
  version: string,        // Server version
  tools?: ToolDefinition[], // Array of tools
  instructions?: string,  // Optional instructions for AI
  transport?: {           // Transport configuration
    stateful?: boolean,            // Enable stateful sessions (default: false)
    sessionStore?: SessionStore,   // Custom session store (for stateful mode)
    allowedOrigins?: string[],     // Allowed origins for CORS/DNS rebinding protection
    sessionTimeout?: number,       // Session timeout in ms (default: 1 hour)
    requestTimeout?: number,       // Request timeout in ms (default: 30 seconds)
    maxBodySize?: number,          // Max request body size (default: 1MB)
    enableJsonResponse?: boolean,  // Use JSON instead of SSE for responses
    enableResumability?: boolean,  // Enable SSE event IDs for resumability
  }
})

// Returns
mcp.handleRequest(request: Request, options?: { auth?, signal? }): Promise<Response>
mcp.addTool(tool: ToolDefinition): void
mcp.getInfo(): { name: string; version: string }

Transport Modes

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.

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.

// Stateless (default) - works on serverless/edge/distributed
const mcp = createMcpServer({
  name: 'my-app',
  version: '1.0.0',
  tools: [...],
});

// Stateful with in-memory sessions (single instance only)
const mcp = createMcpServer({
  name: 'my-app',
  version: '1.0.0',
  tools: [...],
  transport: {
    stateful: true,
    sessionTimeout: 3600000, // 1 hour
  }
});

// Stateful with custom session store (distributed deployments)
const mcp = createMcpServer({
  name: 'my-app',
  version: '1.0.0',
  tools: [...],
  transport: {
    stateful: true,
    sessionStore: myRedisSessionStore,
  }
});

Custom Session Store

Implement the SessionStore interface to persist sessions in Redis, DynamoDB, or any other storage:

import type { SessionStore, SessionData } from 'mcp-tanstack-start';

const redisSessionStore: SessionStore = {
  async get(id: string): Promise<SessionData | null> {
    const data = await redis.get(`mcp:session:${id}`);
    return data ? JSON.parse(data) : null;
  },
  async set(id: string, session: SessionData, ttlMs: number): Promise<void> {
    await redis.set(`mcp:session:${id}`, JSON.stringify(session), 'PX', ttlMs);
  },
  async delete(id: string): Promise<void> {
    await redis.del(`mcp:session:${id}`);
  },
};

Transport Options

Option Default Description
stateful false Enable stateful session mode. When false, runs in stateless mode suitable for serverless/edge/distributed.
sessionStore In-memory Custom session store (only used when stateful: true).
allowedOrigins ["http://localhost", ...] Origins allowed for CORS. Set to ["*"] to allow all (not recommended for production).
sessionTimeout 3600000 (1 hour) How long before inactive sessions are cleaned up (stateful mode only).
requestTimeout 30000 (30 sec) Timeout for individual requests.
maxBodySize 1048576 (1MB) Maximum request body size in bytes.
enableJsonResponse false Return JSON instead of SSE for POST responses.
enableResumability true Include SSE event IDs for client reconnection support (stateful mode only).

defineTool(config)

Defines a tool with type-safe parameters.

defineTool({
  name: string,
  description: string,
  parameters: ZodSchema,
  execute: (params, context) => Promise<string | Content[] | ToolResult>
})

withMcpAuth(handler, verifyToken, options?)

Wraps a handler with authentication.

withMcpAuth(handler, verifyToken, {
  realm?: string,              // WWW-Authenticate realm
  requiredScopes?: string[],   // Required scopes
  allowUnauthenticated?: boolean,
})

Content Helpers

  • text(content: string) - Create text content
  • image(data: string, mimeType: string) - Create image content (base64)
  • resource(uri: string, options?) - Create embedded resource

Protocol

Implements the MCP 2025-06-18 Streamable HTTP transport:

Endpoints

Method Purpose
POST JSON-RPC requests (single message per request, no batches)
GET SSE stream for server-to-client notifications (stateful mode only)
DELETE Session termination

Features

  • Stateless by Default - Works on serverless, edge, and distributed environments out of the box
  • Optional Stateful Mode - Enable persistent sessions for SSE push notifications
  • Pluggable Session Store - Bring your own Redis, DynamoDB, or other storage for distributed deployments
  • Graceful Session Recovery - In stateless mode, missing sessions are handled gracefully without errors
  • Origin Validation - DNS rebinding attack protection
  • SSE Resumability - Event IDs with Last-Event-ID header support (stateful mode)
  • Protocol Versioning - MCP-Protocol-Version header with fallback to 2025-03-26

Supported Methods

initialize, initialized, tools/list, tools/call, ping

Required Headers

Clients must include:

  • Accept: application/json, text/event-stream (both required)
  • Content-Type: application/json
  • Mcp-Session-Id: <session-id> (after initialization)
  • MCP-Protocol-Version: <version> (recommended)

Examples

Check out the example blog implementation to see mcp-tanstack-start in action with:

  • Blog post listing and retrieval
  • Content search
  • Server info tools

License

MIT

README fetched from the repository 5 days ago. The original is authoritative.

Questions

About Tanstack Start

How do I install Tanstack Start?

No package has been published for this server, so install it from source: clone the repository and follow its README.

Is Tanstack Start safe to use with an AI agent?

Its trust score is 43 out of 100 (fair). It passes 3 of the 6 static security checks run so far; the failures are listed above. It has no ConduID identity yet, so agent calls to it are not receipted.

Is Tanstack Start still maintained?

The last commit was 6 months ago. That's long enough that you should check whether the maintainer is responding to issues before depending on it.