Opinionated MCP Framework for TypeScript (@modelcontextprotocol/sdk compatible) - Build MCP Agents, Clients and Servers with support for ChatGPT Apps, Code Mode, OAuth, Notifications, Sampling, Observability and more.
npm install mcp-useš mcp-use is a complete TypeScript framework for building and using MCP (Model Context Protocol) applications. It provides both a powerful client library for connecting LLMs to MCP servers and a server framework for building your own MCP servers with UI capabilities.
š” Build custom AI agents, create MCP servers with React UI widgets, and debug everything with the built-in inspector - all in TypeScript.
| Package | Description | Version |
| ------------------------------------------------------------------------------------------------------------------- | ------------------------------------------- | --------------------------------------------------------------------------------------------------------------- |
| mcp-use | Core framework for MCP clients and servers |  |
| @mcp-use/cli | Build tool for MCP apps with UI widgets |  |
| @mcp-use/inspector | Web-based MCP server inspector and debugger |  |
| create-mcp-use-app | Create MCP apps with one command |  |
---
| Feature | Description |
| ------------------------------- | -------------------------------------------------------------------------- |
| š Ease of use | Create an MCP-capable agent in just a few lines of TypeScript. |
| š¤ LLM Flexibility | Works with any LangChain.js-supported LLM that supports tool calling. |
| š HTTP Support | Direct SSE/HTTP connection to MCP servers. |
| āļø Dynamic Server Selection | Agents select the right MCP server from a pool on the fly. |
| š§© Multi-Server Support | Use multiple MCP servers in one agent. |
| š”ļø Tool Restrictions | Restrict unsafe tools like filesystem or network. |
| š§ Custom Agents | Build your own agents with LangChain.js adapter or implement new adapters. |
| š Observability | Built-in support for Langfuse with dynamic metadata and tag handling. |
---
- Node.js 20.19.0 or higher
- npm, yarn, or pnpm (examples use pnpm)
``bashInstall from npm
npm install mcp-useLangChain.js and your LLM provider (e.g., OpenAI)
npm install langchain @langchain/openai dotenv
Create a
.env:`ini
OPENAI_API_KEY=your_api_key
`$3
`ts
import { ChatOpenAI } from "@langchain/openai";
import { MCPAgent, MCPClient } from "mcp-use";
import "dotenv/config";async function main() {
// 1. Configure MCP servers
const config = {
mcpServers: {
playwright: { command: "npx", args: ["@playwright/mcp@latest"] },
},
};
const client = MCPClient.fromDict(config);
// 2. Create LLM
const llm = new ChatOpenAI({ modelName: "gpt-4o" });
// 3. Instantiate agent
const agent = new MCPAgent({ llm, client, maxSteps: 20 });
// 4. Run query
const result = await agent.run(
"Find the best restaurant in Tokyo using Google Search"
);
console.log("Result:", result);
}
main().catch(console.error);
`---
š§ API Methods
$3
The
MCPAgent class provides several methods for executing queries with different output formats:####
run(query: string, maxSteps?: number): PromiseExecutes a query and returns the final result as a string.
`ts
const result = await agent.run("What tools are available?");
console.log(result);
`####
stream(query: string, maxSteps?: number): AsyncGeneratorYields intermediate steps during execution, providing visibility into the agent's reasoning process.
`ts
const stream = agent.stream("Search for restaurants in Tokyo");
for await (const step of stream) {
console.log(Tool: ${step.action.tool}, Input: ${step.action.toolInput});
console.log(Result: ${step.observation});
}
`####
streamEvents(query: string, maxSteps?: number): AsyncGeneratorYields fine-grained LangChain StreamEvent objects, enabling token-by-token streaming and detailed event tracking.
`ts
const eventStream = agent.streamEvents("What is the weather today?");
for await (const event of eventStream) {
// Handle different event types
switch (event.event) {
case "on_chat_model_stream":
// Token-by-token streaming from the LLM
if (event.data?.chunk?.content) {
process.stdout.write(event.data.chunk.content);
}
break;
case "on_tool_start":
console.log(\nTool started: ${event.name});
break;
case "on_tool_end":
console.log(Tool completed: ${event.name});
break;
}
}
`$3
-
run(): Best for simple queries where you only need the final result
- stream(): Best for debugging and understanding the agent's tool usage
- streamEvents(): Best for real-time UI updates with token-level streamingš AI SDK Integration
The library provides built-in utilities for integrating with Vercel AI SDK, making it easy to build streaming UIs with React hooks like
useCompletion and useChat.$3
`bash
npm install ai @langchain/anthropic
`$3
`ts
import { ChatAnthropic } from "@langchain/anthropic";
import { createTextStreamResponse } from "ai";
import {
createReadableStreamFromGenerator,
MCPAgent,
MCPClient,
streamEventsToAISDK,
} from "mcp-use";async function createApiHandler() {
const config = {
mcpServers: {
everything: {
command: "npx",
args: ["-y", "@modelcontextprotocol/server-everything"],
},
},
};
const client = new MCPClient(config);
const llm = new ChatAnthropic({ model: "claude-sonnet-4-20250514" });
const agent = new MCPAgent({ llm, client, maxSteps: 5 });
return async (request: { prompt: string }) => {
const streamEvents = agent.streamEvents(request.prompt);
const aiSDKStream = streamEventsToAISDK(streamEvents);
const readableStream = createReadableStreamFromGenerator(aiSDKStream);
return createTextStreamResponse({ textStream: readableStream });
};
}
`$3
`ts
import { streamEventsToAISDKWithTools } from "mcp-use";async function createEnhancedApiHandler() {
const config = {
mcpServers: {
everything: {
command: "npx",
args: ["-y", "@modelcontextprotocol/server-everything"],
},
},
};
const client = new MCPClient(config);
const llm = new ChatAnthropic({ model: "claude-sonnet-4-20250514" });
const agent = new MCPAgent({ llm, client, maxSteps: 8 });
return async (request: { prompt: string }) => {
const streamEvents = agent.streamEvents(request.prompt);
// Enhanced stream includes tool usage notifications
const enhancedStream = streamEventsToAISDKWithTools(streamEvents);
const readableStream = createReadableStreamFromGenerator(enhancedStream);
return createTextStreamResponse({ textStream: readableStream });
};
}
`$3
`ts
// pages/api/chat.ts or app/api/chat/route.ts
import { ChatAnthropic } from "@langchain/anthropic";
import { createTextStreamResponse } from "ai";
import {
createReadableStreamFromGenerator,
MCPAgent,
MCPClient,
streamEventsToAISDK,
} from "mcp-use";export async function POST(req: Request) {
const { prompt } = await req.json();
const config = {
mcpServers: {
everything: {
command: "npx",
args: ["-y", "@modelcontextprotocol/server-everything"],
},
},
};
const client = new MCPClient(config);
const llm = new ChatAnthropic({ model: "claude-sonnet-4-20250514" });
const agent = new MCPAgent({ llm, client, maxSteps: 10 });
try {
const streamEvents = agent.streamEvents(prompt);
const aiSDKStream = streamEventsToAISDK(streamEvents);
const readableStream = createReadableStreamFromGenerator(aiSDKStream);
return createTextStreamResponse({ textStream: readableStream });
} finally {
await client.closeAllSessions();
}
}
`$3
`tsx
// components/Chat.tsx
import { useCompletion } from "ai/react";export function Chat() {
const { completion, input, handleInputChange, handleSubmit } = useCompletion({
api: "/api/chat",
});
return (
{completion}
);
}
`$3
-
streamEventsToAISDK(): Converts streamEvents to basic text stream
- streamEventsToAISDKWithTools(): Enhanced stream with tool usage notifications
- createReadableStreamFromGenerator(): Converts async generator to ReadableStream---
š Observability & Monitoring
mcp-use-ts provides built-in observability support through the
ObservabilityManager, with integration for Langfuse and other observability platforms.#### To enable observability simply configure Environment Variables
`ini
.env
LANGFUSE_PUBLIC_KEY=pk-lf-your-public-key
LANGFUSE_SECRET_KEY=sk-lf-your-secret-key
LANGFUSE_HOST=https://cloud.langfuse.com # or your self-hosted instance
`$3
#### Dynamic Metadata and Tags
`ts
// Set custom metadata for the current execution
agent.setMetadata({
userId: "user123",
sessionId: "session456",
environment: "production",
});// Set tags for better organization
agent.setTags(["production", "user-query", "tool-discovery"]);
// Run query with metadata and tags
const result = await agent.run("Search for restaurants in Tokyo");
`#### Monitoring Agent Performance
`ts
// Stream events for detailed monitoring
const eventStream = agent.streamEvents("Complex multi-step query");for await (const event of eventStream) {
// Monitor different event types
switch (event.event) {
case "on_llm_start":
console.log("LLM call started:", event.data);
break;
case "on_tool_start":
console.log("Tool execution started:", event.name, event.data);
break;
case "on_tool_end":
console.log("Tool execution completed:", event.name, event.data);
break;
case "on_chain_end":
console.log("Agent execution completed:", event.data);
break;
}
}
`$3
To disable observability, either remove langfuse env variables or
`ts
const agent = new MCPAgent({
llm,
client,
observe: false,
});
`---
š Configuration File
You can store servers in a JSON file:
`json
{
"mcpServers": {
"playwright": {
"command": "npx",
"args": ["@playwright/mcp@latest"]
}
}
}
`Load it:
`ts
import { MCPClient } from "mcp-use";const client = MCPClient.fromConfigFile("./mcp-config.json");
`---
š Examples
We provide a comprehensive set of examples demonstrating various use cases. All examples are located in the
examples/ directory with a dedicated README.$3
`bash
Install dependencies
npm installRun any example
npm run example:airbnb # Search accommodations with Airbnb
npm run example:browser # Browser automation with Playwright
npm run example:chat # Interactive chat with memory
npm run example:stream # Demonstrate streaming methods (stream & streamEvents)
npm run example:stream_events # Comprehensive streamEvents() examples
npm run example:ai_sdk # AI SDK integration with streaming
npm run example:filesystem # File system operations
npm run example:http # HTTP server connection
npm run example:everything # Test MCP functionalities
npm run example:multi # Multiple servers in one session
`$3
- Browser Automation: Control browsers to navigate websites and extract information
- File Operations: Read, write, and manipulate files through MCP
- Multi-Server: Combine multiple MCP servers (Airbnb + Browser) in a single task
- Sandboxed Execution: Run MCP servers in isolated E2B containers
- OAuth Flows: Authenticate with services like Linear using OAuth2
- Streaming Methods: Demonstrate both step-by-step and token-level streaming
- AI SDK Integration: Build streaming UIs with Vercel AI SDK and React hooks
See the examples folder for detailed documentation and prerequisites.
---
š Multi-Server Example
`ts
const config = {
mcpServers: {
airbnb: { command: "npx", args: ["@openbnb/mcp-server-airbnb"] },
playwright: { command: "npx", args: ["@playwright/mcp@latest"] },
},
};
const client = MCPClient.fromDict(config);
const agent = new MCPAgent({ llm, client, useServerManager: true });
await agent.run("Search Airbnb in Barcelona, then Google restaurants nearby");
`---
š Tool Access Control
`ts
const agent = new MCPAgent({
llm,
client,
disallowedTools: ["file_system", "network"],
});
`---
š„ļø MCP Server Framework
Beyond being a powerful MCP client, mcp-use also provides a complete server framework for building your own MCP servers with built-in UI capabilities and automatic inspector integration.
$3
`ts
import { MCPServer } from "mcp-use/server";// Create your MCP server
const server = new MCPServer({
name: "my-awesome-server",
version: "1.0.0",
description: "My MCP server with tools, resources, and prompts",
});
// Define tools
server.tool("search_web", {
description: "Search the web for information",
parameters: z.object({
query: z.string().describe("Search query"),
}),
execute: async (args) => {
// Your tool implementation
return { results: await performSearch(args.query) };
},
});
// Define resources
server.resource("config", {
description: "Application configuration",
uri: "config://settings",
mimeType: "application/json",
fetch: async () => {
return JSON.stringify(await getConfig(), null, 2);
},
});
// Define prompts
server.prompt("code_review", {
description: "Review code for best practices",
arguments: [{ name: "code", description: "Code to review", required: true }],
render: async (args) => {
return
Please review this code:\n\n${args.code};
},
});// Start the server
server.listen(3000);
// š Inspector automatically available at http://localhost:3000/inspector
// š MCP endpoint available at http://localhost:3000/mcp
`$3
| Feature | Description |
| -------------------------- | ---------------------------------------------------------------- |
| š Auto Inspector | Inspector UI automatically mounts at
/inspector for debugging |
| šØ UI Widgets | Build custom React UI components served alongside your MCP tools |
| š OAuth Support | Built-in OAuth flow handling for secure authentication |
| š” Multiple Transports | HTTP/SSE and WebSocket support out of the box |
| š ļø TypeScript First | Full TypeScript support with type inference |
| ā»ļø Hot Reload | Development mode with automatic reloading |
| š Observability | Built-in logging and monitoring capabilities |$3
mcp-use provides a unified
uiResource() method for registering interactive UI widgets that are compatible with MCP-UI clients. This automatically creates both a tool (for dynamic parameters) and a resource (for static access).#### Quick Start
`ts
import { MCPServer } from "mcp-use/server";const server = new MCPServer({ name: "my-server", version: "1.0.0" });
// Register a widget - creates both tool and resource automatically
server.uiResource({
type: "externalUrl",
name: "kanban-board",
widget: "kanban-board",
title: "Kanban Board",
description: "Interactive task management board",
props: {
initialTasks: {
type: "array",
description: "Initial tasks",
required: false,
},
theme: {
type: "string",
default: "light",
},
},
size: ["900px", "600px"],
});
server.listen(3000);
`This automatically creates:
- Tool:
kanban-board - Accepts parameters and returns UIResource
- Resource: ui://widget/kanban-board - Static access with defaults#### Three Resource Types
1. External URL (Iframe)
Serve widgets from your filesystem via iframe:
`ts
server.uiResource({
type: "externalUrl",
name: "dashboard",
widget: "dashboard",
props: { userId: { type: "string", required: true } },
});
`2. Raw HTML
Direct HTML content rendering:
`ts
server.uiResource({
type: "rawHtml",
name: "welcome-card",
htmlContent: ,
});
`3. Remote DOM
Interactive components using MCP-UI React components:
`ts
server.uiResource({
type: "remoteDom",
name: "quick-poll",
script: ,
framework: "react",
});
`#### Get Started with Templates
`bash
Create a new project with UIResource examples
npx create-mcp-use-app my-app
Select: "MCP Server with UIResource widgets"
cd my-app
npm install
npm run dev
`$3
mcp-use supports building custom UI widgets for your MCP tools using React:
`tsx
// resources/task-manager.tsx
import React, { useState } from "react";
import { useMcp } from "mcp-use/react";export default function TaskManager() {
const { callTool } = useMcp();
const [tasks, setTasks] = useState([]);
const addTask = async (title: string) => {
const result = await callTool("create_task", { title });
setTasks([...tasks, result]);
};
return (
Task Manager
{/ Your UI implementation /}
);
}
`Build and serve widgets using the mcp-use CLI:
`bash
Development with hot reload and auto-open inspector
npx @mcp-use/cli devProduction build
npx @mcp-use/cli buildStart production server
npx @mcp-use/cli start
`$3
`ts
const server = new MCPServer({
name: "advanced-server",
version: "1.0.0",
description: "Advanced MCP server with custom configuration",
// Custom inspector path (default: /inspector)
inspectorPath: "/debug",
// Custom MCP endpoint (default: /mcp)
mcpPath: "/api/mcp",
// Enable CORS for browser access
cors: {
origin: ["http://localhost:3000", "https://myapp.com"],
credentials: true,
},
// OAuth configuration
oauth: {
clientId: process.env.OAUTH_CLIENT_ID,
clientSecret: process.env.OAUTH_CLIENT_SECRET,
authorizationUrl: "https://api.example.com/oauth/authorize",
tokenUrl: "https://api.example.com/oauth/token",
scopes: ["read", "write"],
},
// Custom middleware
middleware: [authenticationMiddleware, rateLimitingMiddleware],
});
`$3
Deploy your MCP server to any Node.js hosting platform:
`bash
Build for production
npm run buildStart with PM2
pm2 start dist/index.js --name mcp-serverDocker deployment
docker build -t my-mcp-server .
docker run -p 3000:3000 my-mcp-server
`$3
You can also integrate MCP server into existing Express applications:
`ts
import express from "express";
import { mountMCPServer } from "mcp-use/server";const app = express();
// Your existing routes
app.get("/api/health", (req, res) => res.send("OK"));
// Mount MCP server
const mcpServer = new MCPServer({
name: "integrated-server",
/ ... /
});
mountMCPServer(app, mcpServer, {
basePath: "/mcp-service", // Optional custom base path
});
app.listen(3000);
// Inspector at: http://localhost:3000/mcp-service/inspector
// MCP endpoint: http://localhost:3000/mcp-service/mcp
``Pietro Zullo | Zane | Luigi Pederzani |
MIT Ā© Zane