@mcp-ts/client
v4.2.7
Published
A lightweight MCP client library for TypeScript with durable sessions across Redis, Supabase, Neon, and SQLite, cross-runtime agent support, and dynamic tool discovery to reduce LLM context usage.
Maintainers
Readme
@mcp-ts/client
High-performance Model Context Protocol (MCP) SDK for TypeScript and Node.js with OAuth 2.1 lifecycle management, multi-tenant durable sessions across Redis, SQLite, Neon, and Supabase, dynamic context-window optimization via ToolRouter, and first-class AI framework adapters.
npm install @mcp-ts/client @modelcontextprotocol/client @modelcontextprotocol/core🏗️ Architecture & Core Concepts
graph LR
subgraph Direct["Direct SDK Flow (TypeScript)"]
UI["Browser UI"]
Hook["useMcp Hook"]
API["Next.js /api/mcp"]
Mgr["McpManager"]
Store[("Redis / SQLite / File / Memory")]
MCP["MCP Servers"]
UI <--> Hook
Hook -- "HTTP RPC" --> API
API --> Mgr
Mgr -- "SSE events" --> Hook
Mgr <--> Store
Mgr <--> MCP
end┌────────────────────────────────────────────────────────┐
│ mcp │ App / Storage root
│ (Configures durable storage & tenants) │
└───────────────────────────┬────────────────────────────┘
│ .user(userId)
┌───────────────────────────▼────────────────────────────┐
│ McpUser │ User / Tenant context
│ (addMcpServer, listMcpServers, finishAuth, listTools) │
└─────────────┬───────────────────────────┬──────────────┘
│ │
┌─────────────▼───────────────┐ ┌─────────▼──────────────┐
│ McpManager │ │ ToolRouter │
│ (Connection pool & cache) │ │ (Context optimization) │
└─────────────┬───────────────┘ └─────────┬──────────────┘
│ │
┌─────────────▼───────────────┐ ┌─────────▼──────────────┐
│ McpClient │ │ AI Adapters │
│ (OAuth 2.1, SSE/HTTP) │ │ (AI SDK, LangChain...) │
└─────────────────────────────┘ └────────────────────────┘| Class / Module | Purpose | Primary Use Case |
| :--- | :--- | :--- |
| mcp / Mcp | App & Storage Root | Zero-config instance or app-wide database configuration |
| McpUser | User Context | Adding/listing MCP servers and running tools per user |
| McpClient | Single Connection | Direct connection to a single remote MCP server |
| McpManager | Connection Pool | High-throughput batch connection management |
| ToolRouter | Dynamic Optimization | 80–95% token savings using smart tool discovery |
| AIAdapter | Framework Bindings | Turn MCP servers into tools for Vercel AI SDK, LangChain, etc. |
🚀 Quick Start
1. Server-Side (Next.js App Router)
Expose a full MCP endpoint with authentication in your Next.js application:
// app/api/mcp/route.ts
import { createNextMcpHandler } from '@mcp-ts/client';
export const dynamic = 'force-dynamic';
export const runtime = 'nodejs';
export const { GET, POST } = createNextMcpHandler({
authenticate: async (req) => {
// Return user auth context / user ID
return { userId: 'user-123' };
}
});2. Client-Side (React Hook)
Connect and manage MCP servers directly from your React UI:
'use client';
import { useMcp } from '@mcp-ts/client/react';
export function McpControlPanel() {
const { connections, connect } = useMcp({
url: '/api/mcp',
userId: 'user-123',
});
return (
<div className="flex flex-col items-center gap-4">
<button
onClick={() =>
connect({
serverId: 'my-server',
serverName: 'My MCP Server',
serverUrl: 'https://mcp.example.com',
callbackUrl: `${window.location.origin}/callback`,
})
}
>
Connect Server
</button>
{connections.map((conn) => (
<div key={conn.sessionId} className="p-4 border rounded">
<h3>{conn.serverName}</h3>
<p>State: {conn.state}</p>
<p>Tools: {conn.tools.length}</p>
</div>
))}
</div>
);
}3. Programmatic User-Scoped Management
import { mcp } from '@mcp-ts/client';
const user = mcp.user('user_123');
// Connect an MCP server (supports SSE & Streamable HTTP)
const result = await user.addMcpServer('https://mcp.tavily.com/mcp');
if (result.authRequired) {
// Server requires OAuth 2.1 browser sign-in
console.log('Redirect user to:', result.authUrl);
} else {
console.log('Server connected! Session ID:', result.sessionId);
}
// In your OAuth callback route:
await user.finishAuth(code, state, iss);
// List all active user tools across connected servers
const { tools } = await user.listTools();
// Execute a tool directly
const response = await user.callTool('tavily_search', { query: 'Model Context Protocol' });OAuth client registration and CIMD
When an MCP server requires OAuth, the client chooses a registration method in this order:
- Supplied client information, when
clientInformationis already configured. - Client ID Metadata Documents (CIMD), when
clientMetadataUrlis configured and the authorization server advertisesclient_id_metadata_document_supported: true. - Dynamic Client Registration (DCR), as a fallback when CIMD is unavailable or unsupported.
Configure CIMD with a stable HTTPS URL for the metadata document:
const client = new MCPClient({
userId: 'user_123',
sessionId: 'session_123',
serverUrl: 'https://mcp.example.com/mcp',
serverId: 'example',
callbackUrl: 'https://app.example.com/oauth/callback',
clientMetadataUrl: 'https://app.example.com/oauth/client-metadata.json',
});The host application must serve that URL over HTTPS. The document must be valid JSON and include at least client_id, client_name, and redirect_uris. Its client_id must match the metadata URL exactly, including scheme, host, path, and any other URL components. The configured callbackUrl must be included in redirect_uris and remain identical throughout the authorization and callback flow.
For example, a framework-neutral GET route can return the document as JSON:
GET /oauth/client-metadata.json
Content-Type: application/json
{
"client_id": "https://app.example.com/oauth/client-metadata.json",
"client_name": "Example MCP Client",
"redirect_uris": ["https://app.example.com/oauth/callback"],
"token_endpoint_auth_method": "none"
}The authorization server decides whether CIMD is available from its OAuth metadata. When it does not advertise support, mcp-ts falls back to DCR if the server provides a registration endpoint.
🔌 Framework Adapters
Integrating with agent frameworks is simple using built-in adapters.
Vercel AI SDK
Pass all user MCP servers seamlessly to generateText or streamText:
// app/api/chat/route.ts
import { mcp } from '@mcp-ts/client';
import { AIAdapter } from '@mcp-ts/client/adapters/ai';
import { streamText } from 'ai';
import { openai } from '@ai-sdk/openai';
export async function POST(req: Request) {
const { messages, userId } = await req.json();
const user = mcp.user(userId);
const tools = await AIAdapter.getTools(user);
const result = streamText({
model: openai('gpt-4o'),
messages,
tools,
});
return result.toDataStreamResponse();
}AG-UI Adapter
import { McpManager } from '@mcp-ts/client';
import { AguiAdapter } from '@mcp-ts/client/adapters/agui-adapter';
const client = new McpManager('user_123');
await client.connect();
const adapter = new AguiAdapter(client);
const tools = await adapter.getTools();Mastra Adapter
import { McpManager } from '@mcp-ts/client';
import { MastraAdapter } from '@mcp-ts/client/adapters/mastra-adapter';
const client = new McpManager('user_123');
await client.connect();
const tools = await MastraAdapter.getTools(client);LangChain Adapter
import { mcp } from '@mcp-ts/client';
import { LangChainAdapter } from '@mcp-ts/client/adapters/langchain';
const user = mcp.user('user_123');
const tools = await LangChainAdapter.getTools(user);🧩 AG-UI Middleware
Execute MCP tools server-side when using remote agent frameworks (LangGraph, AutoGen, CrewAI, etc.):
import { HttpAgent } from '@ag-ui/client';
import { McpManager } from '@mcp-ts/client';
import { AguiAdapter } from '@mcp-ts/client/adapters/agui-adapter';
import { createMcpMiddleware } from '@mcp-ts/client/adapters/agui-middleware';
// 1. Connect to MCP servers
const client = new McpManager('user_123');
await client.connect();
// 2. Extract tools
const adapter = new AguiAdapter(client);
const mcpTools = await adapter.getTools();
// 3. Attach middleware to remote agent
const agent = new HttpAgent({ url: 'http://localhost:8000/agent' });
agent.use(
createMcpMiddleware({
toolPrefix: 'server-',
tools: mcpTools,
})
);The middleware intercepts tool calls from remote agents, executes MCP tools server-side, and returns results back to the agent.
🛠️ MCP Apps Extension (SEP-1865)
Render interactive UIs for your tools using McpAppRenderer:
import { useRenderToolCall } from '@copilotkit/react-core';
import { McpAppRenderer } from '@mcp-ts/client/react';
import { useMcpContext } from './mcp';
export function ToolRenderer() {
const { mcpClient } = useMcpContext();
useRenderToolCall({
name: '*',
render: ({ name, args, result, status }) => (
<McpAppRenderer
client={mcpClient}
name={name}
input={args}
result={result}
status={status}
/>
),
});
return null;
}🧠 Dynamic Tool Routing (ToolRouter)
For users with dozens or hundreds of tools, ToolRouter dynamically injects discovery meta-tools (mcp_search_tools, mcp_execute_tool) into the LLM context, reducing token usage by up to 95%:
import { mcp, ToolRouter } from '@mcp-ts/client';
import { AIAdapter } from '@mcp-ts/client/adapters/ai-adapter';
const user = mcp.user('user_123');
// 1. Dynamic discovery via ToolRouter (BM25 search + pinned tools):
const router = new ToolRouter(user, {
pinnedTools: ['slack_send_message'],
});
const tools = await AIAdapter.getTools(user, {
toolRouter: router,
});
// 2. OR zero-token dynamic context via AI SDK v7 deferLoading:
const deferredTools = await AIAdapter.getTools(user, {
deferLoading: true,
});⚙️ Storage Backends & Environment Setup
The library supports multiple durable storage backends out of the box. You can explicitly select one via MCP_TS_STORAGE_TYPE or specify it programmatically.
Supported Types: redis, sqlite, neon, supabase, file, memory.
Programmatic Configuration
import { Mcp, sessions } from '@mcp-ts/client';
// Redis storage
const mcp = new Mcp({
storage: sessions.use('redis', {
redisUrl: process.env.REDIS_URL,
}),
});
const user = mcp.user('user_123');Environment Variable Setup
Redis (Recommended for production):
MCP_TS_STORAGE_TYPE=redis REDIS_URL=redis://localhost:6379SQLite (Fast & Persistent):
MCP_TS_STORAGE_TYPE=sqlite MCP_TS_STORAGE_SQLITE_PATH=./sessions.dbNeon (Serverless Postgres):
MCP_TS_STORAGE_TYPE=neon NEON_DATABASE_URL=postgresql://user:[email protected]/dbname?sslmode=verify-full&channel_binding=requireFile System (Great for local dev):
MCP_TS_STORAGE_TYPE=file MCP_TS_STORAGE_FILE=./sessions.jsonIn-Memory (Default for testing):
MCP_TS_STORAGE_TYPE=memory
📦 Peer Dependencies & Package Exports
[!NOTE] Adapters and external storage backends are loaded via optional peer dependencies and must be installed independently. This ensures your application only includes the integrations you explicitly choose, keeping bundle sizes small.
Entry Points
| Entry Point | Description |
| :--- | :--- |
| @mcp-ts/client | Root exports: mcp, Mcp, McpUser, McpClient, McpManager, ToolRouter |
| @mcp-ts/client/adapters/ai | Vercel AI SDK integration (AIAdapter.getTools) |
| @mcp-ts/client/adapters/langchain | LangChain / LangGraph tool binding (LangChainAdapter.getTools) |
| @mcp-ts/client/adapters/mastra | Mastra agent framework adapter (MastraAdapter.getTools) |
| @mcp-ts/client/adapters/agui-adapter | AG-UI Client adapter |
| @mcp-ts/client/adapters/agui-middleware | AG-UI chat & streaming middleware |
| @mcp-ts/client/sse | Browser JSON-RPC client primitives |
| @mcp-ts/client/react | React hooks (useMcp, useMcpApps, useMcpOAuthPopup, McpAppRenderer) |
| @mcp-ts/client/vue | Vue composables (useMcp) |
| @mcp-ts/client/shared | Shared types, interfaces (BaseClient, ToolClient), and event emitters |
📚 Documentation Links
- Getting Started Guide
- Installation Guide
- AI SDK Integration
- Mastra Integration
- LangChain Integration
- Storage Backends Overview
- Redis Storage Guide
- Next.js Integration
- React Hook Guide
- API Reference
🤝 Contributing & License
- Read CONTRIBUTING.md for contribution guidelines.
- License: MIT © ZonLabs
