TypeScript MCP Client Libraries and Frameworks

Summary Table

Library/Framework Type Key Features Transport Support Best For Framework Integration Maturity
@modelcontextprotocol/sdk Official Core SDK Full MCP spec, tools/resources/prompts/sampling, type safety, Zod schemas stdio, Streamable HTTP, SSE Production servers & clients, foundation for other libraries Framework-agnostic ⭐⭐⭐ Mature
Vercel AI SDK 5 AI Framework with MCP Agent primitives (stopWhen/prepareStep), dynamic tools, type-safe chat, provider-executed tools, MCP-aligned tool schema stdio (dev only), Streamable HTTP, SSE Production AI apps with agents, Next.js/React/Svelte/Vue/Angular apps, agentic workflows React, Next.js, Svelte, Vue, Angular ⭐⭐⭐ Mature
Nanobot Full MCP Host Complete MCP host with orchestrator/LLM/DB, MCP-UI first-class, tools/prompts/sampling/elicitation, YAML config, stateful threads stdio, SSE, Streamable HTTP Production agents with UI, embeddable chat, agent-to-agent communication Framework-agnostic (deployable anywhere) ⭐⭐⭐ Mature
Mastra Full AI Framework Agents, workflows, RAG, integrations, evals, 40+ LLM providers, built-in playground, auto-transport detection stdio, Streamable HTTP, SSE (auto-detect) Full-stack AI apps, production agents, complex workflows with observability Next.js, Node.js, React, serverless ⭐⭐⭐ Mature
LangChain.js MCP Adapters Framework Adapter Converts MCP tools to LangChain tools, multi-server support, LangGraph integration stdio, Streamable HTTP, SSE Complex agent workflows, existing LangChain projects LangChain.js, LangGraph.js ⭐⭐⭐ Mature
mcp-use Complete Framework Agent framework + client library, streaming methods, LangChain integration, debugging stdio, SSE Building custom agents with observability, E2B sandboxing LangChain.js, AI SDK, React ⭐⭐ Growing
mcp-client (edanyal) Dedicated Client Event-based API, connection manager, Claude integration examples stdio, SSE Client-only needs, Claude tool calling, multi-server management Anthropic SDK ⭐⭐ Growing
@emqx-ai/mcp-mqtt-sdk MQTT Transport Browser + Node.js, Zod validation, automatic server discovery, MQTT pub/sub MQTT (WebSocket/TCP) Browser clients, IoT/edge scenarios, real-time messaging Framework-agnostic ⭐⭐ Growing
mcp-to-ai-sdk (Vercel CLI) Code Generation Generates static tool definitions from MCP servers, security/version control N/A (generates code) Production safety, preventing schema drift, vendoring tools AI SDK ⭐ New

Libraries and Frameworks

1. @modelcontextprotocol/sdk (Official TypeScript SDK)

The official TypeScript SDK implements the full MCP specification, making it easy to create MCP servers that expose resources, prompts and tools, build MCP clients that can connect to any MCP server, and use standard transports like stdio and Streamable HTTP.

Strengths:

  • Official support with full MCP specification coverage including tools, resources, prompts, and elicitation support
  • Strong type safety with Zod schema validation
  • Multiple transport options (stdio, Streamable HTTP, SSE)
  • Well-documented with active development

Best For:

  • Building production MCP servers and clients from scratch
  • Developers who want full control and closest-to-spec implementation
  • Foundation for building higher-level abstractions

Code Example:

import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';

const transport = new StdioClientTransport({
  command: 'node',
  args: ['server.js']
});

const client = new Client({
  name: 'my-client',
  version: '1.0.0'
});

await client.connect(transport);
const tools = await client.listTools();
const result = await client.callTool({
  name: 'my-tool',
  arguments: { param: 'value' }
});

2. Vercel AI SDK 5 (Major Redesign with Enhanced MCP Support)

AI SDK 5 aligns tool definition interface more closely with the Model Context Protocol (MCP) specification by renaming key concepts: parameters → inputSchema to better describe the schema's purpose of validating and typing the tool's input, and introducing an optional outputSchema property which aligns with the MCP specification and enables type-safety for client-side tool calling.

What's New in Version 5

Major Breaking Changes from v4:

  • Tool parameter naming changed to match MCP spec
  • New agent primitives for multi-step workflows
  • Redesigned streaming protocol
  • Enhanced type safety throughout

MCP-Specific Improvements:

The AI SDK supports connecting to Model Context Protocol servers to access their tools, enabling AI applications to discover and use tools across various services through a standardized interface, with support for HTTP transport (like StreamableHTTPClientTransport) recommended for production deployments.

The experimental_createMCPClient creates a lightweight Model Context Protocol client that connects to an MCP server, with its primary purpose being tool conversion between MCP tools and AI SDK tools.

Key Features

1. Agent Primitives (New in v5)

AI SDK 5 introduces stopWhen which transforms single-step calls into multi-step agents by running requests in a tool-calling loop until conditions are met, and prepareStep which gives you deterministic control over each step to configure model, context, tools, and more.

2. Dynamic Tools Support

Dynamic tools enable tools where input and output types are determined at runtime rather than development time, separated from static tools to provide type safety and flexibility, particularly useful for MCP servers where tools are not known during development.

3. Type-Safe Chat

New redesigned chat hooks with modularity for React, Svelte, Vue, and Angular with support for dynamic tool rendering.

4. Two Approaches for Tool Schemas

The client's tools method supports schema discovery where all tools offered by the server are automatically listed with input parameter types inferred from server schemas (simpler but no TypeScript safety), or explicit schema definition providing full TypeScript type safety and IDE autocompletion during development.

Transport Options

Recommended transports include HTTP transport using StreamableHTTPClientTransport from MCP's official TypeScript SDK for production deployments, SSE as an alternative HTTP-based transport, and stdio for local development only as it cannot be deployed to production environments.

Strengths

  • Agent-First Design: Built-in support for multi-step agentic workflows
  • Production-Ready: Customers have seen over 90% savings using Fluid compute on Vercel versus traditional serverless for AI inference and agentic workloads
  • Type Safety: Full TypeScript support with compile-time checking
  • Framework Support: Works with React, Next.js, Svelte, Vue, Angular
  • Streaming: Advanced streaming capabilities with real-time UI updates
  • Provider Agnostic: Unified API across OpenAI, Anthropic, Google, etc.

Best For

  • Building production AI applications with sophisticated agents
  • Next.js and React applications requiring real-time streaming
  • Teams using Vercel's deployment platform
  • Projects requiring both static and dynamic MCP tools
  • Applications needing deterministic control over agent execution

Code Examples

Basic MCP Client Setup (v5):

import { experimental_createMCPClient as createMCPClient } from 'ai';
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';

// Production: Use Streamable HTTP
const url = new URL('https://your-mcp-server.com/mcp');
const client = await createMCPClient({
  transport: new StreamableHTTPClientTransport({ url })
});

// Get tools with automatic schema discovery
const tools = await client.tools();

// Or with explicit type safety
const tools = await client.tools({
  schemas: {
    add: {
      inputSchema: {
        type: 'object',
        properties: {
          a: { type: 'number' },
          b: { type: 'number' }
        },
        required: ['a', 'b']
      }
    }
  }
});

// Always close the client when done
await client.close();

Using MCP Tools with Agent (v5):

import {
  generateText,
  experimental_createMCPClient as createMCPClient,
  stepCountIs,
  hasToolCall
} from 'ai';
import { openai } from '@ai-sdk/openai';

const client = await createMCPClient({
  transport: { type: 'sse', url: 'http://localhost:8080/sse' }
});

const tools = await client.tools();

// Multi-step agent with stopping conditions
const result = await generateText({
  model: openai('gpt-4'),
  prompt: 'Research the latest TypeScript features and create a summary',
  tools,
  stopWhen: [
    stepCountIs(10), // Stop after 10 steps
    hasToolCall('create_summary') // Or when summary tool is called
  ],
  prepareStep: async (step) => {
    // Control each step dynamically
    return {
      // Compress messages to stay within token limits
      messages: step.messages.slice(-5),
      // Switch models based on complexity
      model: step.stepCount > 5
        ? openai('gpt-4')
        : openai('gpt-3.5-turbo'),
      // Enable/disable tools as needed
      tools: step.stepCount < 3
        ? tools
        : tools.filter(t => t.name === 'create_summary')
    };
  }
});

await client.close();

Agent Class Approach (v5):

import {
  Experimental_Agent as Agent,
  experimental_createMCPClient as createMCPClient,
  stepCountIs,
  tool
} from 'ai';
import { openai } from '@ai-sdk/openai';

const client = await createMCPClient({
  transport: { type: 'sse', url: 'http://localhost:8080/sse' }
});

const mcpTools = await client.tools();

// Combine static and dynamic tools
const agent = new Agent({
  model: openai('gpt-4'),
  tools: {
    ...mcpTools,
    // Add static tools
    localTool: tool({
      description: 'A local tool',
      inputSchema: { /* ... */ },
      execute: async (input) => { /* ... */ }
    })
  },
  stopWhen: stepCountIs(10)
});

const result = await agent.run({
  messages: [{ role: 'user', content: 'Complete this task' }]
});

await client.close();

Next.js Route Handler with MCP (v5):

// app/api/chat/route.ts
import { streamText } from 'ai';
import { experimental_createMCPClient as createMCPClient } from 'ai';
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
import { openai } from '@ai-sdk/openai';

export async function POST(req: Request) {
  const { messages } = await req.json();

  const client = await createMCPClient({
    transport: new StreamableHTTPClientTransport({
      url: new URL(process.env.MCP_SERVER_URL!)
    })
  });

  const tools = await client.tools();

  const result = streamText({
    model: openai('gpt-4'),
    messages,
    tools,
    stopWhen: [stepCountIs(5)],
    onFinish: async () => {
      await client.close();
    }
  });

  return result.toDataStreamResponse();
}

React Component with Dynamic MCP Tools (v5):

'use client';

import { useChat } from '@ai-sdk/react';

export default function Chat() {
  const { messages, input, handleInputChange, handleSubmit } = useChat({
    api: '/api/chat',
    // Handle dynamic tools from MCP
    onToolCall: ({ toolCall }) => {
      console.log('Tool called:', toolCall.toolName);
    }
  });

  return (
    <div>
      {messages.map(message => (
        <div key={message.id}>
          {/* Render regular messages */}
          {message.role === 'user' && <p>{message.content}</p>}

          {/* Render assistant responses with dynamic tools */}
          {message.role === 'assistant' && (
            <>
              {message.parts.map((part, i) => {
                if (part.type === 'text') {
                  return <p key={i}>{part.text}</p>;
                }
                if (part.type === 'tool-call') {
                  return (
                    <div key={i}>
                      Calling tool: {part.toolName}
                    </div>
                  );
                }
                if (part.type === 'dynamic-tool') {
                  return (
                    <div key={i}>
                      Dynamic MCP tool: {part.toolName}
                    </div>
                  );
                }
              })}
            </>
          )}
        </div>
      ))}

      <form onSubmit={handleSubmit}>
        <input value={input} onChange={handleInputChange} />
        <button type="submit">Send</button>
      </form>
    </div>
  );
}

Important Considerations

Security: Tool names, descriptions, and argument schemas become part of your agent's prompt and can change unexpectedly without warning, leading to security, cost, and quality issues even when the upstream MCP server has not been compromised.

Solution: Use mcp-to-ai-sdk CLI to generate static tool definitions:

npm install -g @vercel/mcp-to-ai-sdk

# Generate vendored tools
npx @vercel/mcp-to-ai-sdk generate \
  --server-url http://localhost:3000 \
  --output ./src/mcp-tools.ts

# Use in your code
import { myTool } from './src/mcp-tools';

Transport Recommendations:

  • Production: Use StreamableHTTPClientTransport (HTTP-based, stateless)
  • Development: Use stdio for local MCP servers
  • Legacy: SSE supported but HTTP is preferred

3. Nanobot (Full MCP Host Framework)

Nanobot was written from the ground up to support the MCP ecosystem, with all functionality delivered via MCP servers and fully leveraging MCP features like tools, prompts, sampling, elicitation and more, while Nanobots are full AI agents that are also exposed as MCP servers so users can chat with them via any app that is an MCP client.

What Makes Nanobot Unique

At its core, Nanobot functions as an MCP host, a concept that goes beyond simple client-server models, integrating a client, an orchestrator, an LLM connection, a database, and managing resources and users to provide a complete agent experience.

Key Philosophy: Nanobot makes it simple to wrap any MCP server with reasoning, system prompts, tool orchestration, and rich MCP-UI support, enabling developers to build agents that don't just expose functions, but deliver interactive, engaging user experiences.

Key Features

1. Complete MCP Host

  • Not just a client - full host implementation
  • Integrated orchestrator, LLM connection, and database
  • PostgreSQL backend for production use
  • Stateful threads for persistent context

2. First-Class MCP-UI Support First-class support for MCP-UI spec allowing you to render interactive React components directly inside chat clients—build playable games, shopping carts, dashboards, and more.

3. Agent-to-Agent Communication Nanobots are exposed as MCP servers themselves, enabling agent-to-agent communication patterns where agents can talk to other agents via MCP.

4. YAML-Based Configuration Configuration is straightforward using a YAML file that defines the prompt, starter messages, MCP server, icons and descriptions.

5. Full MCP Feature Support

  • Tools, resources, prompts
  • Sampling support
  • Elicitation support
  • Progress notifications
  • Change subscriptions

Architecture

MCP Host Components:

  • Client: Connects to MCP servers
  • Orchestrator: Manages tool execution and workflows
  • LLM Connection: Handles model interactions
  • Database: Stores conversation state and context
  • User Management: Multi-user support

Strengths

  • Production-Ready: Built with production use in mind, ships as an executable and requires a Postgres database
  • Embeddable: Can be deployed anywhere or embedded in applications/websites
  • Rich UI: Best-in-class MCP-UI support for interactive experiences
  • Stateful: Persistent threads maintain context across sessions
  • Flexible: Can act as both client and server
  • Community-Driven: Flexible, extensible, and community-driven with full transparency and active development

Best For

  • Building production-grade conversational AI agents
  • Applications requiring rich, interactive UI components
  • Multi-user agent deployments
  • Agent-to-agent communication scenarios
  • Embedding MCP-powered agents in existing applications
  • Games, e-commerce, support tools with visual interfaces

Code Examples

Basic Nanobot Configuration (YAML):

name: blackjack_agent
description: An AI agent that plays blackjack with the user
version: 1.0.0

prompt: |
  You are a professional blackjack dealer. Help users play the game
  by managing the deck, enforcing rules, and tracking the game state.

starter_messages:
  - "Welcome to Blackjack! Would you like to start a new game?"

mcp_server:
  command: "node"
  args: ["blackjack-server.js"]

tools:
  - start_game
  - hit
  - stand
  - check_score

ui_enabled: true
stateful: true

icons:
  agent: "♠️"

database:
  postgres_url: "${DATABASE_URL}"

Running Nanobot (CLI):

# Install
npm install -g nanobot

# Set environment variables
export OPENAI_API_KEY=sk-...
export DATABASE_URL=postgresql://...

# Run with config
nanobot run --config blackjack-agent.yaml

# Or programmatically
nanobot start --port 3000

Embedding Nanobot in an Application:

import { Nanobot } from 'nanobot';

const bot = new Nanobot({
  config: './agent-config.yaml',
  database: {
    url: process.env.DATABASE_URL
  },
  llm: {
    provider: 'openai',
    model: 'gpt-4',
    apiKey: process.env.OPENAI_API_KEY
  }
});

await bot.start();

// Expose as API endpoint
app.post('/chat', async (req, res) => {
  const { message, userId, threadId } = req.body;

  const response = await bot.chat({
    userId,
    threadId,
    message
  });

  res.json(response);
});

Using Nanobot's MCP-UI with React:

The recommended approach is to serve your React component from an external URL:

// In your MCP server
import { createUIResource } from '@mcp-ui/server';

server.tool('show_game_state', {}, async () => {
  const gameState = {
    dealerHand: ['King', 'Ace'],
    playerHand: ['10', 'Queen'],
    playerScore: 20,
    dealerScore: 11
  };

  return {
    content: [{
      type: 'resource',
      resource: createUIResource({
        uri: 'ui://blackjack/table',
        content: {
          type: 'externalUrl',
          iframeUrl: `https://yourapp.com/blackjack-ui?state=${encodeURIComponent(JSON.stringify(gameState))}`
        }
      })
    }]
  };
});

React Component (served at https://yourapp.com/blackjack-ui):

// blackjack-ui.tsx
import React, { useEffect, useState } from 'react';
import './styles.css';

interface GameState {
  dealerHand: string[];
  playerHand: string[];
  playerScore: number;
  dealerScore: number;
}

export default function BlackjackUI() {
  const [gameState, setGameState] = useState<GameState | null>(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    // Get game state from URL params
    const params = new URLSearchParams(window.location.search);
    const state = params.get('state');
    if (state) {
      setGameState(JSON.parse(state));
      setLoading(false);
    }
  }, []);

  const callMCPTool = (toolName: string) => {
    // Send message back to MCP host
    window.parent.postMessage(
      {
        type: 'tool-call',
        toolName,
        params: {}
      },
      '*'
    );
  };

  if (loading) return <div className="loading">Loading game...</div>;
  if (!gameState) return <div className="error">No game state</div>;

  return (
    <div className="blackjack-container">
      <div className="game-area">
        <div className="dealer-section">
          <h3>Dealer</h3>
          <div className="hand">
            {gameState.dealerHand.map((card, i) => (
              <div key={i} className="card">{card}</div>
            ))}
          </div>
          <p className="score">Score: {gameState.dealerScore}</p>
        </div>

        <div className="divider" />

        <div className="player-section">
          <h3>Your Hand</h3>
          <div className="hand">
            {gameState.playerHand.map((card, i) => (
              <div key={i} className="card">{card}</div>
            ))}
          </div>
          <p className="score">Score: {gameState.playerScore}</p>
        </div>
      </div>

      <div className="controls">
        <button
          onClick={() => callMCPTool('hit')}
          className="btn btn-primary"
        >
          Hit
        </button>
        <button
          onClick={() => callMCPTool('stand')}
          className="btn btn-secondary"
        >
          Stand
        </button>
      </div>
    </div>
  );
}

TypeScript/React Approach (Alternative - Bundle with Vite):

If you prefer bundling the React component directly:

// In your MCP server
import { createUIResource } from '@mcp-ui/server';
import { readFileSync } from 'fs';

// Build your React component with Vite, then reference the bundle
const bundledComponent = readFileSync('./dist/blackjack-ui.js', 'utf-8');

server.tool('show_game_state', {}, async () => {
  const gameState = {
    dealerHand: ['King', 'Ace'],
    playerHand: ['10', 'Queen'],
    playerScore: 20,
    dealerScore: 11
  };

  return {
    content: [{
      type: 'resource',
      resource: createUIResource({
        uri: 'ui://blackjack/table',
        content: {
          type: 'rawHtml',
          htmlString: `
            <div id="root"></div>
            <script>
              window.gameState = ${JSON.stringify(gameState)};
            </script>
            <script>${bundledComponent}</script>
          `
        }
      })
    }]
  };
});

Setup Your React App Project Structure:

project/
  server/  [Your MCP server]
    src/
      index.ts
    package.json

  ui/  [Your React UI]
    src/
      blackjack-ui.tsx
      styles.css
    vite.config.ts
    package.json
    dist/  [Build output]

  nanobot.yaml  [Nanobot config]

Development Workflow:

# Terminal 1: Start your MCP server
cd server
npm run dev

# Terminal 2: Build React UI with hot reload
cd ui
npm run dev

# Terminal 3: Run Nanobot
nanobot run --config nanobot.yaml

Integration Patterns

1. Standalone Deployment:

# Deploy as a service
nanobot serve --config prod-agent.yaml --port 8080

2. Embedded in Next.js:

// pages/api/agent/[...slug].ts
import { Nanobot } from 'nanobot';

const bot = new Nanobot({
  config: './config/agent.yaml'
});

export default async function handler(req, res) {
  return bot.handleRequest(req, res);
}

3. Agent-to-Agent Communication:

# Agent A config
name: researcher_agent
mcp_server:
  command: "node"
  args: ["researcher-server.js"]

downstream_agents:
  - url: "mcp://writer-agent:3001"
    name: writer
# Agent B config
name: writer_agent
mcp_server:
  command: "node"
  args: ["writer-server.js"]
  expose_as_server: true
  port: 3001

Important Considerations

Database Requirement: Nanobot requires PostgreSQL for production deployments to maintain stateful threads and user sessions.

MCP-UI Support: Nanobot's strength lies in its ability to combine a basic MCP server with MCP-UI for enhanced user interaction and stateful threads for persistent context, transforming purely text-based interactions into rich, visual experiences.


4. Mastra (Full-Stack TypeScript AI Framework)

From the team behind Gatsby, Mastra is a framework for building AI-powered applications and agents with a modern TypeScript stack, including everything needed to go from early prototypes to production-ready applications, integrating with frontend and backend frameworks like React, Next.js, and Node.

What Makes Mastra Unique

Batteries-Included Approach: Mastra is a batteries-included TypeScript framework for agentic apps providing one stack, one set of primitives, and no glue code.

MCP Integration: The @mastra/mcp package provides a client implementation for the Model Context Protocol, wrapping the official @modelcontextprotocol/sdk and providing Mastra-specific functionality with automatic transport detection.

Key Features

1. Complete AI Application Stack

  • Agents: Autonomous systems with tool calling
  • Workflows: Complex multi-step processes
  • RAG: Knowledge base integration
  • Integrations: Auto-generated, type-safe API clients
  • Evals: Automated LLM output testing

2. Model Routing Mastra uses Vercel AI SDK for model routing, connecting to 40+ providers through one standard interface including OpenAI, Anthropic, Gemini, and more.

3. MCP Client with Auto-Detection The client automatically detects the transport type based on server configuration: if you provide a command, it uses Stdio transport; if you provide a url, it first attempts Streamable HTTP transport and falls back to legacy SSE transport if connection fails.

4. Built-in Development Tools

  • Integrated local playground
  • Swagger UI for API documentation
  • Hot reload with auto-inspector
  • MCP docs server for IDE integration

5. Production Deployment Can deploy anywhere: Vercel, Netlify, Cloudflare, or as standalone server

Strengths

  • TypeScript-First: Purpose-built for TypeScript with full type safety
  • Unified Interface: Single framework for agents, workflows, RAG, and integrations
  • Developer Experience: If you know TypeScript, you already know 90% of Mastra
  • Observability: Built-in eval framework and monitoring
  • Flexible Deployment: Local, serverless, or containerized
  • Active Development: From the Gatsby team with strong community

Best For

  • Full-stack AI application development
  • Teams wanting batteries-included framework
  • Production applications with complex workflows
  • Projects requiring both agents and RAG
  • Teams already using TypeScript/React ecosystem
  • Applications needing comprehensive observability

Code Examples

Quick Start with create-mastra:

# Create new project
npm create mastra@latest my-agent \
  --components agents,tools \
  --llm openai \
  --example

cd my-agent
npm run dev

Basic Agent with MCP Tools:

import { Agent } from '@mastra/core/agent';
import { MastraMCPClient } from '@mastra/mcp';
import { openai } from '@ai-sdk/openai';

// Initialize MCP client
const mcpClient = new MastraMCPClient({
  name: 'github-client',
  server: {
    command: 'npx',
    args: ['-y', '@modelcontextprotocol/server-github']
  },
  timeout: 60000
});

await mcpClient.connect();
const tools = await mcpClient.tools();

// Create agent with MCP tools
const agent = new Agent({
  name: 'GitHub Insights Agent',
  instructions: `
    You analyze GitHub repos.
    - If user omits owner/repo, ask for them.
    - Return stars, forks, issues, license and last push.
    - Offer health summary.
  `,
  model: openai('gpt-4o-mini'),
  tools
});

// Use the agent
const result = await agent.generate({
  messages: ['Show me stats for vercel/next.js']
});

console.log(result.text);

MCP with Remote Server (SSE):

import { MastraMCPClient } from '@mastra/mcp';

const mcpClient = new MastraMCPClient({
  name: 'apify-client',
  server: {
    url: new URL('https://mcp.apify.com/sse'),
    requestInit: {
      headers: {
        Authorization: `Bearer ${process.env.APIFY_TOKEN}`
      }
    },
    eventSourceInit: {
      async fetch(input, init) {
        const headers = new Headers(init?.headers || {});
        headers.set('authorization', `Bearer ${process.env.APIFY_TOKEN}`);
        return fetch(input, { ...init, headers });
      }
    }
  },
  timeout: 300000 // 5 minutes
});

await mcpClient.connect();
const tools = await mcpClient.tools();

Complete Mastra Application:

// src/mastra/index.ts
import { Mastra } from '@mastra/core';
import { githubAgent } from './agents/github';
import { researchWorkflow } from './workflows/research';

export const mastra = new Mastra({
  agents: {
    githubAgent
  },
  workflows: {
    researchWorkflow
  }
});

// Start development server
// npm run dev
// Playground: http://localhost:4111

Using with mcp.run Registry:

import { MCPAgent, MCPClient } from 'mcp-use';
import { openai } from '@ai-sdk/openai';

const config = {
  mcpServers: {
    weather: {
      command: 'npx',
      args: ['-y', '@modelcontextprotocol/server-weather']
    }
  }
};

const client = MCPClient.fromDict(config);
const agent = new MCPAgent({
  llm: openai('gpt-4'),
  client
});

await agent.run('What's the weather in San Francisco?');

Next.js Integration:

// app/api/agent/route.ts
import { mastra } from '@/mastra';
import { NextRequest } from 'next/server';

export async function POST(req: NextRequest) {
  const { message } = await req.json();

  const result = await mastra.agents.githubAgent.generate({
    messages: [message]
  });

  return Response.json({ response: result.text });
}

Workflow Example:

import { Workflow, Step } from '@mastra/core';
import { MastraMCPClient } from '@mastra/mcp';

const researchWorkflow = new Workflow({
  name: 'research-workflow',

  steps: [
    new Step({
      id: 'search',
      execute: async ({ input }) => {
        const client = new MastraMCPClient({
          name: 'search-client',
          server: { command: 'npx', args: ['-y', '@mcp/server-search'] }
        });
        await client.connect();
        const tools = await client.tools();
        // Use search tool
        return { results: /* search results */ };
      }
    }),

    new Step({
      id: 'analyze',
      execute: async ({ input }) => {
        // Analyze search results
        return { analysis: /* ... */ };
      }
    }),

    new Step({
      id: 'summarize',
      execute: async ({ input }) => {
        // Generate final summary
        return { summary: /* ... */ };
      }
    })
  ]
});

IDE Integration (Cursor/Windsurf):

// .cursor/mcp.json or ~/.codeium/windsurf/mcp_config.json
{
  "mcpServers": {
    "mastra": {
      "command": "npx",
      "args": ["-y", "@mastra/mcp-docs-server"]
    }
  }
}

This gives your IDE access to complete Mastra documentation for better autocomplete and AI assistance.

Development Workflow

1. Local Development:

npm run dev
# Opens playground at http://localhost:4111
# Swagger UI at http://localhost:4111/swagger-ui
# OpenAPI docs at http://localhost:4111/openapi.json

2. Testing with Evals:

import { Eval } from '@mastra/core/evals';

const eval = new Eval({
  name: 'agent-accuracy',
  agent: githubAgent,
  testCases: [
    {
      input: 'Show me vercel/next.js stats',
      expected: /* expected structure */
    }
  ]
});

await eval.run();

3. Production Deployment:

// Deploy to Vercel
import { VercelDeployer } from '@mastra/deployer/vercel';

const deployer = new VercelDeployer({
  mastra,
  apiRoutes: true
});

await deployer.deploy();

Integration Ecosystem

Supported Integrations:

  • GitHub, GitLab
  • Google Drive, Sheets
  • Slack, Discord
  • Notion, Airtable
  • Stripe, Shopify
  • 100+ more with type-safe clients

Example Integration:

import { GitHub } from '@mastra/github';

const github = new GitHub({
  apiKey: process.env.GITHUB_TOKEN
});

// Auto-generated, type-safe API
const repos = await github.listRepos({
  org: 'vercel'
});

Important Considerations

Learning Curve: While TypeScript-first, the comprehensive feature set means there's more to learn compared to simpler client libraries.

Bundle Size: Full framework is larger than minimal client libraries. Use tree-shaking and only import what you need.

Best Fit: Ideal when you need multiple capabilities (agents + RAG + workflows) rather than just MCP client functionality.


5. LangChain.js MCP Adapters (@langchain/mcp-adapters)

The LangChain MCP Adapters package converts MCP tools into LangChain and LangGraph-compatible tools, enables interaction with tools across multiple MCP servers, and seamlessly integrates the hundreds of tool servers already published into LangGraph Agents.

Strengths:

  • Seamless integration with the growing ecosystem of MCP tool servers into LangChain and LangGraph agents, handling all protocol-specific details
  • Multi-server support out of the box
  • Pre-built agent templates (ReAct, etc.)
  • Excellent for complex agentic workflows

Best For:

  • Existing LangChain.js projects
  • Complex multi-step agent workflows
  • Teams familiar with LangChain patterns
  • Projects requiring agent orchestration

Code Example:

import { loadMCPTools } from '@langchain/mcp-adapters/tools.js';
import { MultiServerMCPClient } from '@langchain/mcp-adapters/client.js';
import { createReactAgent } from '@langchain/langgraph/prebuilt';
import { ChatOpenAI } from '@langchain/openai';

const client = new MultiServerMCPClient({
  'math': {
    command: 'node',
    args: ['math-server.js'],
    transport: 'stdio'
  }
});

const tools = await loadMCPTools(client);
const llm = new ChatOpenAI({ model: 'gpt-4' });
const agent = createReactAgent({ llm, tools });

const response = await agent.invoke({
  messages: [{ role: 'user', content: 'What is 5 + 3?' }]
});

6. mcp-use (Complete TypeScript Framework)

MCP-Use is a complete TypeScript framework for building and using MCP applications, providing both a powerful client library for connecting LLMs to MCP servers and a server framework for building MCP servers with UI capabilities.

Strengths:

  • Multiple streaming methods including step-by-step and token-level streaming, AI SDK integration for building streaming UIs with Vercel AI SDK and React hooks, and sandboxed execution in E2B containers
  • Built-in observability with Langfuse integration
  • OAuth flow support
  • Rich debugging capabilities

Best For:

  • Building custom AI agents with full observability
  • Projects requiring detailed execution tracking
  • Teams needing both client and server capabilities
  • Development with sandboxed environments

Code Example:

import { MCPAgent, MCPClient } from 'mcp-use';
import { ChatOpenAI } from '@langchain/openai';

const config = {
  mcpServers: {
    playwright: {
      command: 'npx',
      args: ['@playwright/mcp@latest']
    }
  }
};

const client = MCPClient.fromDict(config);
const llm = new ChatOpenAI({ model: 'gpt-4' });
const agent = new MCPAgent({ llm, client, maxSteps: 5 });

// Streaming with detailed steps
for await (const step of agent.stream('Navigate to example.com')) {
  console.log(`Tool: ${step.action.tool}`);
  console.log(`Result: ${step.observation}`);
}

7. mcp-client (by edanyal)

A TypeScript MCP client library that provides connection management through MCPConnectionManager, working seamlessly with Claude's native tool calling and supporting both stdio and SSE transports.

Strengths:

  • Focused client-only implementation
  • Connection manager for multi-server scenarios
  • Direct Claude SDK integration examples
  • Simple, straightforward API

Best For:

  • Projects only needing client functionality (not servers)
  • Direct integration with Anthropic's Claude
  • Managing multiple MCP server connections
  • Simpler use cases without heavy frameworks

Code Example:

import { MCPConnectionManager } from 'mcp-client';
import { Anthropic } from '@anthropic-ai/sdk';

const manager = new MCPConnectionManager();
await manager.initialize('./mcp-config.json');

const memoryClient = manager.getClient('memory');
const tools = await memoryClient?.listTools();

const anthropic = new Anthropic({
  apiKey: process.env.ANTHROPIC_API_KEY
});

const response = await anthropic.messages.create({
  model: 'claude-3-5-sonnet-20241022',
  tools: tools,
  messages: [{ role: 'user', content: 'Remember: User likes TypeScript' }]
});

8. @emqx-ai/mcp-mqtt-sdk (MQTT Transport)

A TypeScript SDK for implementing Model Context Protocol over MQTT, working seamlessly in browser (WebSocket) and Node.js (TCP) environments, with full TypeScript support and Zod schema validation, using MQTT as the transport layer for reliable MCP communication.

Strengths:

  • Universal support for both browser and Node.js with automatic environment detection, automatic server discovery over MQTT topics, and complete support for MCP tools and resources
  • Push/subscribe model for real-time updates
  • No HTTP needed - works over MQTT
  • Built-in server discovery

Best For:

  • Browser-based MCP clients
  • IoT and edge computing scenarios
  • Real-time, event-driven architectures
  • Scenarios where HTTP isn't ideal

Code Example:

import { McpMqttClient } from '@emqx-ai/mcp-mqtt-sdk';

const client = new McpMqttClient({
  host: 'mqtt://broker.emqx.io:1883',
  name: 'Browser MCP Client',
  version: '1.0.0'
});

client.on('serverDiscovered', async (server) => {
  console.log('Found server:', server.name);
  await client.initializeServer(server.serverId);
});

client.on('serverInitialized', async (server) => {
  const tools = await client.listTools(server.serverId);
  const result = await client.callTool(
    server.serverId,
    'add',
    { a: 5, b: 3 }
  );
});

await client.connect();

9. mcp-to-ai-sdk (Vercel Code Generator)

A CLI that generates static AI SDK tool definitions from any MCP server, providing performance through selective loading, reliability through version control as tool schemas remain stable, and customization through local editing to refine descriptions.

Strengths:

  • Prevents security issues from malicious prompts injected into tool descriptions, prevents privilege escalation from new tools added to servers, and maintains stability by vendoring definitions in your codebase
  • Static tool definitions = no runtime surprises
  • Works with authenticated MCP servers
  • Customizable generated code

Best For:

  • Production environments requiring stability
  • Security-sensitive applications
  • Preventing schema drift
  • Teams wanting to audit/modify tool definitions

Usage:

# Install
npm install -g @vercel/mcp-to-ai-sdk

# Generate tools from an MCP server
npx @vercel/mcp-to-ai-sdk generate \
  --server-url http://localhost:3000 \
  --output ./src/mcp-tools.ts

# Then import in your code
import { myTool } from './mcp-tools';
import { generateText } from 'ai';

const result = await generateText({
  model: openai('gpt-4'),
  tools: [myTool],
  prompt: 'Use the tool'
});

Decision Matrix

Choose @modelcontextprotocol/sdk if:

  • You need full MCP spec compliance
  • Building custom infrastructure
  • Want closest-to-spec implementation
  • Need maximum flexibility and control

Choose Vercel AI SDK 5 if:

  • Building production AI applications with sophisticated multi-step agents
  • Using React, Next.js, Svelte, Vue, or Angular
  • Need fine-grained control over agent execution (stopWhen/prepareStep)
  • Want type-safe integration with dynamic MCP tools
  • Deploying to Vercel with Fluid compute
  • Need streaming UI with real-time updates
  • Building agentic workflows with deterministic control

Choose Nanobot if:

  • Building production conversational agents with rich UI
  • Need complete MCP host (not just client)
  • Want first-class MCP-UI support for interactive experiences
  • Building games, e-commerce, or visual agent experiences
  • Need stateful, multi-user agent deployments
  • Want agent-to-agent communication
  • Prefer YAML-based configuration
  • Need embeddable agent solution

Choose Mastra if:

  • Building full-stack AI applications from scratch
  • Need agents + workflows + RAG + integrations in one framework
  • Want batteries-included TypeScript solution
  • Building production apps with comprehensive observability
  • Prefer integrated development environment with playground
  • Need support for 40+ LLM providers
  • Want type-safe integrations with popular services
  • Team is already comfortable with TypeScript

Choose LangChain.js MCP Adapters if:

  • Already using LangChain.js/LangGraph
  • Building complex multi-step agents
  • Need pre-built agent patterns
  • Require advanced orchestration

Choose mcp-use if:

  • Need both client AND server capabilities
  • Want built-in observability
  • Require detailed execution tracking
  • Building custom agentic frameworks

Choose mcp-client if:

  • Only need client functionality
  • Integrating with Claude directly
  • Want simple, straightforward API
  • Don't need heavy framework features

Choose @emqx-ai/mcp-mqtt-sdk if:

  • Building browser-based clients
  • Need real-time, event-driven architecture
  • Working with IoT/edge scenarios
  • Want automatic server discovery

Choose mcp-to-ai-sdk if:

  • Prioritizing security and stability
  • Need to prevent schema drift
  • Want to audit/customize tool definitions
  • Deploying to production

Recommendations for Your Stack

Since you code in JavaScript/TypeScript and React, here are the top recommendations:

For Production Applications with Rich UI:

  1. Nanobot - Best for conversational agents with interactive UI components, stateful threads, and embeddable deployment
  2. Vercel AI SDK 5 - Best for React/Next.js apps with sophisticated multi-step agents and streaming

For Full-Stack AI Applications:

  1. Mastra - Comprehensive framework with agents, workflows, RAG, and integrations all in one
  2. Vercel AI SDK 5 - If you're heavily invested in Vercel's ecosystem

For Complex Agent Workflows:

  1. Mastra - If you need the full suite (agents + workflows + RAG + observability)
  2. LangChain.js MCP Adapters - If you need sophisticated agent orchestration patterns

For Simple Integrations:

  1. @modelcontextprotocol/sdk - If you want bare-metal control
  2. mcp-client - If you only need client features

For Browser-First Applications:

  1. @emqx-ai/mcp-mqtt-sdk - Ideal for browser-based MCP clients with real-time features

Framework Comparison: Nanobot vs Mastra vs AI SDK 5

Feature Nanobot Mastra AI SDK 5
Primary Focus MCP Host + Interactive Agents Full AI Application Framework UI Framework + Agents
MCP-UI Support ⭐⭐⭐ First-class ⚠️ Via integrations ⚠️ Partial
Setup Complexity Medium (YAML + DB) Low (npm create) Low
Database Required ✅ PostgreSQL ❌ Optional ❌ No
Stateful Threads ✅ Built-in ✅ Via memory ⚠️ Custom
Agent-to-Agent ✅ Native ⚠️ Via workflows ❌ No
Workflows ⚠️ Via orchestrator ✅ Native ⚠️ prepareStep
RAG Support ⚠️ Via MCP servers ✅ Native ❌ No
LLM Providers OpenAI, Anthropic 40+ providers All via AI SDK
Best For Rich UI agents Full-stack AI apps React/Next.js

Additional TypeScript Resources

  • Official MCP TypeScript SDK Examples: Multiple example servers and clients in the repository's /examples directory
  • Nanobot Examples: Check the GitHub repo for Blackjack game, e-commerce agents, and more
  • Mastra Documentation: Comprehensive docs with examples for agents, workflows, and RAG
  • Speakeasy SDK Generator: Every TypeScript SDK generated by Speakeasy now bundles a runnable MCP server
  • Community Examples: Many production-ready examples on GitHub

The TypeScript/JavaScript ecosystem for MCP is rapidly maturing with excellent options for different use cases. Nanobot stands out for rich, interactive agent experiences with MCP-UI. Mastra excels as a comprehensive framework for full-stack AI applications. Vercel AI SDK 5 remains the top choice for React-focused teams building sophisticated streaming agents.