Generate TypeScript types from a live MCP server and pass them to createMCPClient. A wrong tool name is then a type error.
You get:
Tool arguments stay unknown on this path. For typed arguments, also use the tools([toolDefinition(...)]) form.
List each server that you want types for. defineConfig gives the file type checks and autocomplete.
// mcp.config.ts
import { defineConfig } from '@tanstack/ai-mcp'
export default defineConfig({
servers: {
github: {
transport: { type: 'http', url: 'https://github-mcp.example.com/mcp' },
},
linear: {
transport: { type: 'http', url: 'https://linear-mcp.example.com/mcp' },
prefix: 'linear', // must match runtime createMCPClient({ prefix })
},
},
outFile: './mcp-types.generated.ts',
})npx @tanstack/ai-mcp generateThe CLI connects to each server, reads its tools, resources, and prompts, and writes the types to outFile. It uses the same handshake as createMCPClient: protocol 2026-07-28 first, then the 2025 handshake.
The generator writes one interface for each server, plus a map for the pool:
// AUTO-GENERATED by `npx @tanstack/ai-mcp generate`. Do not edit.
import type { ServerDescriptor } from '@tanstack/ai-mcp'
export interface GithubServer extends ServerDescriptor {
tools: {
'search_repositories': { input: { query: string; limit?: number }; output: unknown }
'create_issue': { input: { repo: string; title: string; body?: string }; output: unknown }
}
resources: {}
prompts: {}
capabilities: { tools: {} } & Record<string, unknown>
}
export interface LinearServer extends ServerDescriptor {
tools: {
'linear_create_issue': { input: { title: string; teamId: string }; output: unknown }
}
resources: {}
prompts: {}
capabilities: { tools: {} } & Record<string, unknown>
}
export interface MCPServers extends Record<string, ServerDescriptor> {
'github': GithubServer
'linear': LinearServer
}Pass the type as a generic to createMCPClient (one server) or createMCPClients (a pool).
One server:
import type { GithubServer } from './mcp-types.generated'
import { createMCPClient } from '@tanstack/ai-mcp'
const mcp = await createMCPClient<GithubServer>({
transport: { type: 'http', url: process.env.GITHUB_MCP_URL! },
})
const tools = await mcp.tools()
// Each tool name is narrowed from GithubServer['tools']A pool:
import type { MCPServers } from './mcp-types.generated'
import { createMCPClients } from '@tanstack/ai-mcp'
const pool = await createMCPClients<MCPServers>({
github: { transport: { type: 'http', url: process.env.GITHUB_MCP_URL! } },
linear: {
transport: { type: 'http', url: process.env.LINEAR_MCP_URL! },
prefix: 'linear',
},
})
// The config keys must be declared servers. A typo is a compile error.
const tools = await pool.tools()Now a misspelled tool name or pool key fails the type check. To give the typed client to chat(), see Managed MCP with chat().
Package names for an @modelcontextprotocol/sdk import are in MCP SDK packages.