ai-mcp
The `@tanstack/ai-mcp` package connects Claude agents and chat loops to Model Context Protocol servers, enabling access to MCP tools and resources through a unified API. Use it when you need server-side tool execution from external MCP servers via HTTP, SSE, or stdio transports, or when you want to load MCP resources and prompts into chat messages. Do not use for browser or client-side code.
git clone --depth 1 https://github.com/TanStack/ai /tmp/ai-mcp && cp -r /tmp/ai-mcp/packages/ai-mcp/skills/ai-mcp ~/.claude/skills/ai-mcpSKILL.md
# `@tanstack/ai-mcp`
This skill covers the `@tanstack/ai-mcp` package. Read `ai-core/tool-calling/SKILL.md`
first — MCP tools flow into `chat()` the same way hand-written tools do.
## When to use this package
Use `@tanstack/ai-mcp` when:
- A third-party MCP server exposes tools you want an agent or chat loop to call.
- You want to read MCP server resources (files, text, data) or prompts into a
`chat()` message list.
- You want generated TypeScript types for an external MCP server's tool
signatures (via the bundled `generate` CLI).
- You are running tool execution on the server side and want to connect to MCP
servers with HTTP (Streamable HTTP or SSE) or stdio transports.
Do NOT use this package for browser/client-side code — MCP connections are
server-side only.
## Install
```bash
pnpm add @tanstack/ai-mcp
```
The package has two subpath exports:
- `.` — main client API (`createMCPClient`, `createMCPClients`, converters, types)
- `./stdio` — Node-only stdio transport factory (`stdioTransport`); import it
separately so edge bundles stay clean
## `createMCPClient` — single server
```typescript
import { createMCPClient } from '@tanstack/ai-mcp'
const client = await createMCPClient({
transport: { type: 'http', url: 'https://mcp.example.com/mcp' },
prefix: 'weather', // optional: prefixes all tool names (e.g. 'weather_get_forecast')
name: 'my-app', // optional: client identity sent to the server
})
```
`createMCPClient` connects immediately and returns an `MCPClient`. Throws
`MCPConnectionError` if the connection fails.
### Transports
#### Streamable HTTP (default for internet-facing servers)
```typescript
const client = await createMCPClient({
transport: {
type: 'http',
url: 'https://mcp.example.com/mcp',
headers: { Authorization: 'Bearer sk-...' },
},
})
```
#### SSE
```typescript
const client = await createMCPClient({
transport: {
type: 'sse',
url: 'https://mcp.example.com/sse',
headers: { Authorization: 'Bearer sk-...' },
},
})
```
#### stdio (Node-only — import from `/stdio` subpath)
```typescript
import { createMCPClient } from '@tanstack/ai-mcp'
import { stdioTransport } from '@tanstack/ai-mcp/stdio'
const client = await createMCPClient({
transport: stdioTransport({
command: 'npx',
args: ['-y', 'my-mcp-server'],
env: { API_KEY: process.env.API_KEY ?? '' },
}),
})
```
#### Custom transport (escape hatch)
Pass any SDK `Transport` instance directly:
```typescript
import { createMCPClient } from '@tanstack/ai-mcp'
import { InMemoryTransport } from '@modelcontextprotocol/sdk/inMemory.js'
const [clientTransport] = InMemoryTransport.createLinkedPair()
const client = await createMCPClient({ transport: clientTransport })
```
### Authentication
Two levels:
- **Static tokens** — pass `headers` on the `http`/`sse` config (sent with
every request): `headers: { Authorization: 'Bearer ...' }`.
- **OAuth 2.1 (MCP authorization spec)** — pass `authProvider` on the
`http`/`sse` config. It accepts any `OAuthClientProvider` from
`@modelcontextprotocol/sdk/client/auth.js`; the SDK transport attaches
tokens, refreshes them, and retries on 401.
```typescript
import { createMCPClient } from '@tanstack/ai-mcp'
import type { OAuthClientProvider } from '@modelcontextprotocol/sdk/client/auth.js'
declare const myOAuthProvider: OAuthClientProvider // backed by stored tokens
const client = await createMCPClient({
transport: {
type: 'http',
url: 'https://mcp.example.com/mcp',
authProvider: myOAuthProvider,
},
})
```
Caveat: interactive authorization-code flows need `transport.finishAuth(code)`,
and `createMCPClient` does not expose its internal transport. For redirect
flows, construct the `StreamableHTTPClientTransport` yourself with the
`authProvider`, keep a reference, call `finishAuth(code)` in the OAuth
callback route, then pass the transport via the escape hatch above. For
server-side providers backed by pre-provisioned/refreshable tokens, the
config form is sufficient.
## Three type-safety modes
### Mode 1 — Auto-discovery (no types needed)
`client.tools()` lists every tool the server exposes. Args are typed `unknown`
at compile time but the tool's JSON Schema is forwarded to the LLM.
```typescript
const tools = await client.tools()
// tools: ServerTool[] (args unknown)
const stream = chat({
adapter: openaiText('gpt-5.5'),
messages,
tools,
})
```
Use `{ lazy: true }` to defer schema sending via the existing `LazyToolManager`:
```typescript
const tools = await client.tools({ lazy: true })
```
### Mode 2 — Typed via `toolDefinition` instances
Pass bare `toolDefinition()` instances (no `.server()` call) to `client.tools([...])`.
The MCP client binds a `callTool` proxy as the execute function while
input/output validation and TypeScript types come from the definitions' Zod schemas.
Only the named tools are returned (allowlist = the definitions' `name`s).
Throws `MCPToolNotFoundError` if the server does not expose a tool with that name.
```typescript
import { toolDefinition } from '@tanstack/ai'
import { createMCPClient } from '@tanstack/ai-mcp'
import { z } from 'zod'
const getWeatherDef = toolDefinition({
name: 'get_weather',
description: 'Current weather for a city',
inputSchema: z.object({ city: z.string() }),
outputSchema: z.object({ temperature: z.number(), conditions: z.string() }),
})
const client = await createMCPClient({
transport: { type: 'http', url: 'https://mcp.example.com/mcp' },
})
// Returns MappedServerTools<typeof defs> — fully typed per definition.
const tools = await client.tools([getWeatherDef])
```
### Mode 3 — Generated types (via `generate` CLI)
Run `npx @tanstack/ai-mcp generate` to introspect live servers and emit a
`ServerDescriptor` interface per server. Pass the generated interface as the
generic to `createMCPClient<WeatherServer>(...)` to narrow discovered tool
names to the server's literals (args stay untyped — use Mode 2 for typed args>
Triage all open GitHub issues, PRs, and discussions in the current repository by fanning out up to 100 parallel subagents (one per item), then produce a single prioritized report ranking which PRs to review first, which issues to address first, and which discussions need maintainer attention. Use when the user asks to "triage open issues/PRs", "triage discussions", "prioritize the backlog", "what should I review first", "sweep the repo", or any request to bulk-evaluate open GitHub work and recommend an order.
>
>
>
>
>
>