MCP客户端
🌐 MCPClient
MCPClient 类提供了一种在 Mastra 应用中管理多个 MCP 服务器连接及其工具的方法。它负责连接的生命周期管理、工具的命名空间管理,并提供对所有配置服务器上工具的访问。
🌐 The MCPClient class provides a way to manage multiple MCP server connections and their tools in a Mastra application. It handles connection lifecycle, tool namespacing, and provides access to tools across all configured servers.
此类取代了已弃用的 MastraMCPClient。
🌐 This class replaces the deprecated MastraMCPClient.
构造函数Direct link to 构造函数
🌐 Constructor
创建 MCPClient 类的新实例。
🌐 Creates a new instance of the MCPClient class.
constructor({
id?: string;
servers: Record<string, MastraMCPServerDefinition>;
timeout?: number;
}: MCPClientOptions)
MCP客户端选项Direct link to MCP客户端选项
🌐 MCPClientOptions
id?:
servers:
timeout?:
MastraMCP服务器定义Direct link to MastraMCP服务器定义
🌐 MastraMCPServerDefinition
在 servers 地图中的每个服务器都是使用 MastraMCPServerDefinition 类型配置的。传输类型是根据提供的参数检测的:
🌐 Each server in the servers map is configured using the MastraMCPServerDefinition type. The transport type is detected based on the provided parameters:
- 如果提供
command,它将使用 Stdio 传输。 - 如果提供了
url,它会先尝试使用可流式 HTTP 传输,如果初始连接失败,则回退到传统的 SSE 传输。
command?:
args?:
env?:
url?:
requestInit?:
eventSourceInit?:
fetch?:
logger?:
timeout?:
capabilities?:
authProvider?:
enableServerLogs?:
方法Direct link to 方法
🌐 Methods
listTools()Direct link to listTools()
从所有已配置的服务器中检索所有工具,工具名称会按服务器名称进行命名空间处理(格式为 serverName_toolName),以防止冲突。旨在传递给代理定义使用。
🌐 Retrieves all tools from all configured servers, with tool names namespaced by their server name (in the format serverName_toolName) to prevent conflicts.
Intended to be passed onto an Agent definition.
new Agent({ id: "agent", tools: await mcp.listTools() });
listToolsets()Direct link to listToolsets()
返回一个对象,将命名空间工具名称(格式为 serverName.toolName)映射到它们的工具实现。
旨在动态传入 generate 或 stream 方法中。
🌐 Returns an object mapping namespaced tool names (in the format serverName.toolName) to their tool implementations.
Intended to be passed dynamically into the generate or stream method.
const res = await agent.stream(prompt, {
toolsets: await mcp.listToolsets(),
});
disconnect()Direct link to disconnect()
断开所有 MCP 服务器的连接并清理资源。
🌐 Disconnects from all MCP servers and cleans up resources.
async disconnect(): Promise<void>
resources 属性Direct link to resources-property
🌐 resources Property
MCPClient 实例有一个 resources 属性,可用于访问与资源相关的操作。
🌐 The MCPClient instance has a resources property that provides access to resource-related operations.
const mcpClient = new MCPClient({
/* ...servers configuration... */
});
// Access resource methods via mcpClient.resources
const allResourcesByServer = await mcpClient.resources.list();
const templatesByServer = await mcpClient.resources.templates();
// ... and so on for other resource methods.
resources.list()Direct link to resourceslist
从所有已连接的 MCP 服务器检索所有可用资源,并按服务器名称分组。
🌐 Retrieves all available resources from all connected MCP servers, grouped by server name.
async list(): Promise<Record<string, Resource[]>>
示例:
🌐 Example:
const resourcesByServer = await mcpClient.resources.list();
for (const serverName in resourcesByServer) {
console.log(`Resources from ${serverName}:`, resourcesByServer[serverName]);
}
resources.templates()Direct link to resourcestemplates
从所有连接的 MCP 服务器检索所有可用的资源模板,并按服务器名称分组。
🌐 Retrieves all available resource templates from all connected MCP servers, grouped by server name.
async templates(): Promise<Record<string, ResourceTemplate[]>>
示例:
🌐 Example:
const templatesByServer = await mcpClient.resources.templates();
for (const serverName in templatesByServer) {
console.log(`Templates from ${serverName}:`, templatesByServer[serverName]);
}
resources.read(serverName: string, uri: string)Direct link to resourcesreadservername-string-uri-string
从指定服务器读取特定资源的内容。
🌐 Reads the content of a specific resource from a named server.
async read(serverName: string, uri: string): Promise<ReadResourceResult>
serverName:服务器的标识符(在servers构造函数选项中使用的键)。uri:要读取的资源的 URI。
示例:
🌐 Example:
const content = await mcpClient.resources.read(
"myWeatherServer",
"weather://current",
);
console.log("Current weather:", content.contents[0].text);
resources.subscribe(serverName: string, uri: string)Direct link to resourcessubscribeservername-string-uri-string
订阅指定服务器上特定资源的更新。
🌐 Subscribes to updates for a specific resource on a named server.
async subscribe(serverName: string, uri: string): Promise<object>
示例:
🌐 Example:
await mcpClient.resources.subscribe("myWeatherServer", "weather://current");
resources.unsubscribe(serverName: string, uri: string)Direct link to resourcesunsubscribeservername-string-uri-string
取消订阅特定服务器上特定资源的更新。
🌐 Unsubscribes from updates for a specific resource on a named server.
async unsubscribe(serverName: string, uri: string): Promise<object>
示例:
🌐 Example:
await mcpClient.resources.unsubscribe("myWeatherServer", "weather://current");
resources.onUpdated(serverName: string, handler: (params: { uri: string }) => void)Direct link to resourcesonupdatedservername-string-handler-params--uri-string---void
设置一个通知处理程序,当特定服务器上的订阅资源被更新时将调用该处理程序。
🌐 Sets a notification handler that will be called when a subscribed resource on a specific server is updated.
async onUpdated(serverName: string, handler: (params: { uri: string }) => void): Promise<void>
示例:
🌐 Example:
mcpClient.resources.onUpdated("myWeatherServer", (params) => {
console.log(`Resource updated on myWeatherServer: ${params.uri}`);
// You might want to re-fetch the resource content here
// await mcpClient.resources.read("myWeatherServer", params.uri);
});
resources.onListChanged(serverName: string, handler: () => void)Direct link to resourcesonlistchangedservername-string-handler---void
设置一个通知处理程序,当特定服务器上的可用资源总列表发生变化时将被调用。
🌐 Sets a notification handler that will be called when the overall list of available resources changes on a specific server.
async onListChanged(serverName: string, handler: () => void): Promise<void>
示例:
🌐 Example:
mcpClient.resources.onListChanged("myWeatherServer", () => {
console.log("Resource list changed on myWeatherServer.");
// You should re-fetch the list of resources
// await mcpClient.resources.list();
});
elicitation 属性Direct link to elicitation-property
🌐 elicitation Property
MCPClient 实例有一个 elicitation 属性,用于访问与引导收集相关的操作。引导收集允许 MCP 服务器向用户请求结构化信息。
🌐 The MCPClient instance has an elicitation property that provides access to elicitation-related operations. Elicitation allows MCP servers to request structured information from users.
const mcpClient = new MCPClient({
/* ...servers configuration... */
});
// Set up elicitation handler
mcpClient.elicitation.onRequest("serverName", async (request) => {
// Handle elicitation request from server
console.log("Server requests:", request.message);
console.log("Schema:", request.requestedSchema);
// Return user response
return {
action: "accept",
content: { name: "John Doe", email: "john@example.com" },
};
});
elicitation.onRequest(serverName: string, handler: ElicitationHandler)Direct link to elicitationonrequestservername-string-handler-elicitationhandler
设置一个处理函数,当任何已连接的 MCP 服务器发送归集请求时,该函数将被调用。处理函数接收请求并必须返回一个响应。
🌐 Sets up a handler function that will be called when any connected MCP server sends an elicitation request. The handler receives the request and must return a response.
ElicitationHandler 功能:
处理函数接收一个包含以下内容的请求对象:
🌐 The handler function receives a request object with:
message:一个用人类可读的方式描述所需信息的消息requestedSchema:定义预期响应结构的 JSON 模式
处理程序必须返回一个带有以下内容的 ElicitResult:
🌐 The handler must return an ElicitResult with:
action:'accept'、'decline'或'cancel'之一content:用户的数据(仅当操作为'accept'时)
示例:
mcpClient.elicitation.onRequest("serverName", async (request) => {
console.log(`Server requests: ${request.message}`);
// Example: Simple user input collection
if (request.requestedSchema.properties.name) {
// Simulate user accepting and providing data
return {
action: "accept",
content: {
name: "Alice Smith",
email: "alice@example.com",
},
};
}
// Simulate user declining the request
return { action: "decline" };
});
完整互动示例:
import { MCPClient } from "@mastra/mcp";
import { createInterface } from "readline";
const readline = createInterface({
input: process.stdin,
output: process.stdout,
});
function askQuestion(question: string): Promise<string> {
return new Promise((resolve) => {
readline.question(question, (answer) => resolve(answer.trim()));
});
}
const mcpClient = new MCPClient({
servers: {
interactiveServer: {
url: new URL("http://localhost:3000/mcp"),
},
},
});
// Set up interactive elicitation handler
await mcpClient.elicitation.onRequest("interactiveServer", async (request) => {
console.log(`\n📋 Server Request: ${request.message}`);
console.log("Required information:");
const schema = request.requestedSchema;
const properties = schema.properties || {};
const required = schema.required || [];
const content: Record<string, any> = {};
// Collect input for each field
for (const [fieldName, fieldSchema] of Object.entries(properties)) {
const field = fieldSchema as any;
const isRequired = required.includes(fieldName);
let prompt = `${field.title || fieldName}`;
if (field.description) prompt += ` (${field.description})`;
if (isRequired) prompt += " *required*";
prompt += ": ";
const answer = await askQuestion(prompt);
// Handle cancellation
if (answer.toLowerCase() === "cancel") {
return { action: "cancel" };
}
// Validate required fields
if (answer === "" && isRequired) {
console.log(`❌ ${fieldName} is required`);
return { action: "decline" };
}
if (answer !== "") {
content[fieldName] = answer;
}
}
// Confirm submission
console.log("\n📝 You provided:");
console.log(JSON.stringify(content, null, 2));
const confirm = await askQuestion(
"\nSubmit this information? (yes/no/cancel): ",
);
if (confirm.toLowerCase() === "yes" || confirm.toLowerCase() === "y") {
return { action: "accept", content };
} else if (confirm.toLowerCase() === "cancel") {
return { action: "cancel" };
} else {
return { action: "decline" };
}
});
prompts 属性Direct link to prompts-property
🌐 prompts Property
MCPClient 实例有一个 prompts 属性,可用于访问与提示相关的操作。
🌐 The MCPClient instance has a prompts property that provides access to prompt-related operations.
const mcpClient = new MCPClient({
/* ...servers configuration... */
});
// Access prompt methods via mcpClient.prompts
const allPromptsByServer = await mcpClient.prompts.list();
const { prompt, messages } = await mcpClient.prompts.get({
serverName: "myWeatherServer",
name: "current",
});
prompts.list()Direct link to promptslist
从所有已连接的 MCP 服务器检索所有可用的提示,并按服务器名称分组。
🌐 Retrieves all available prompts from all connected MCP servers, grouped by server name.
async list(): Promise<Record<string, Prompt[]>>
示例:
🌐 Example:
const promptsByServer = await mcpClient.prompts.list();
for (const serverName in promptsByServer) {
console.log(`Prompts from ${serverName}:`, promptsByServer[serverName]);
}
prompts.get({ serverName, name, args?, version? })Direct link to promptsget-servername-name-args-version-
从服务器检索特定的提示及其消息。
🌐 Retrieves a specific prompt and its messages from a server.
async get({
serverName,
name,
args?,
version?,
}: {
serverName: string;
name: string;
args?: Record<string, any>;
version?: string;
}): Promise<{ prompt: Prompt; messages: PromptMessage[] }>
示例:
🌐 Example:
const { prompt, messages } = await mcpClient.prompts.get({
serverName: "myWeatherServer",
name: "current",
args: { location: "London" },
});
console.log(prompt);
console.log(messages);
prompts.onListChanged(serverName: string, handler: () => void)Direct link to promptsonlistchangedservername-string-handler---void
设置通知处理程序,当特定服务器上的可用提示列表发生变化时将被调用。
🌐 Sets a notification handler that will be called when the list of available prompts changes on a specific server.
async onListChanged(serverName: string, handler: () => void): Promise<void>
示例:
🌐 Example:
mcpClient.prompts.onListChanged("myWeatherServer", () => {
console.log("Prompt list changed on myWeatherServer.");
// You should re-fetch the list of prompts
// await mcpClient.prompts.list();
});
progress 属性Direct link to progress-property
🌐 progress Property
MCPClient 实例具有一个 progress 属性,用于订阅在工具执行期间 MCP 服务器发送的进度通知。
🌐 The MCPClient instance has a progress property for subscribing to progress notifications emitted by MCP servers while tools execute.
const mcpClient = new MCPClient({
servers: {
myServer: {
url: new URL('http://localhost:4111/api/mcp/myServer/mcp'),
// Enabled by default; set to false to disable
enableProgressTracking: true,
},
},
});
// Subscribe to progress updates for a specific server
await mcpClient.progress.onUpdate('myServer', (params) => {
console.log('📊 Progress:', params.progress, '/', params.total);
if (params.message) console.log('Message:', params.message);
if (params.progressToken) console.log('Token:', params.progressToken);
});
progress.onUpdate(serverName: string, handler)Direct link to progressonupdateservername-string-handler
注册一个处理函数以接收来自指定服务器的进度更新。
🌐 Registers a handler function to receive progress updates from the specified server.
async onUpdate(
serverName: string,
handler: (params: {
progressToken: string;
progress: number;
total?: number;
message?: string;
}) => void,
): Promise<void>
注意:
🌐 Notes:
- 当
enableProgressTracking为 true(默认)时,工具调用会包含一个progressToken,这样你就可以将更新与特定运行相关联。 - 如果在执行工具时传入
runId,它将被用作progressToken。
要禁用服务器的进度跟踪:
🌐 To disable progress tracking for a server:
const mcpClient = new MCPClient({
servers: {
myServer: {
url: new URL('http://localhost:4111/api/mcp/myServer/mcp'),
enableProgressTracking: false,
},
},
});
引出Direct link to 引出
🌐 Elicitation
引导是一个功能,它允许 MCP 服务器从用户那里请求结构化信息。当服务器需要额外数据时,它可以发送一个引导请求,由客户端通过提示用户来处理。一个常见的例子是在使用工具时。
🌐 Elicitation is a feature that allows MCP servers to request structured information from users. When a server needs additional data, it can send an elicitation request that the client handles by prompting the user. A common example is during a tool call.
引导工作原理Direct link to 引导工作原理
🌐 How Elicitation Works
- 服务器请求:MCP 服务器工具使用消息和模式调用
server.elicitation.sendRequest() - 客户端处理器:你的启发式处理函数会随着请求被调用
- 用户交互:你的处理程序收集用户输入(通过用户界面、命令行等)
- 响应:你的处理程序会返回用户的响应(接受/拒绝/取消)
- 工具继续:服务器工具接收响应并继续执行
设定引导Direct link to 设定引导
🌐 Setting Up Elicitation
在调用使用引导的工具之前,你必须先设置引导处理程序:
🌐 You must set up an elicitation handler before tools that use elicitation are called:
import { MCPClient } from "@mastra/mcp";
const mcpClient = new MCPClient({
servers: {
interactiveServer: {
url: new URL("http://localhost:3000/mcp"),
},
},
});
// Set up elicitation handler
mcpClient.elicitation.onRequest("interactiveServer", async (request) => {
// Handle the server's request for user input
console.log(`Server needs: ${request.message}`);
// Your logic to collect user input
const userData = await collectUserInput(request.requestedSchema);
return {
action: "accept",
content: userData,
};
});
响应类型Direct link to 响应类型
🌐 Response Types
你的引导处理程序必须返回三种响应类型之一:
🌐 Your elicitation handler must return one of three response types:
-
接受:用户提供了数据并确认提交
return {
action: "accept",
content: { name: "John Doe", email: "john@example.com" },
}; -
拒绝:用户明确拒绝提供信息
return { action: "decline" }; -
取消:用户已拒绝或取消请求
return { action: "cancel" };
基于模式的输入收集Direct link to 基于模式的输入收集
🌐 Schema-Based Input Collection
requestedSchema 为服务器所需的数据提供结构:
🌐 The requestedSchema provides structure for the data the server needs:
await mcpClient.elicitation.onRequest("interactiveServer", async (request) => {
const { properties, required = [] } = request.requestedSchema;
const content: Record<string, any> = {};
for (const [fieldName, fieldSchema] of Object.entries(properties || {})) {
const field = fieldSchema as any;
const isRequired = required.includes(fieldName);
// Collect input based on field type and requirements
const value = await promptUser({
name: fieldName,
title: field.title,
description: field.description,
type: field.type,
required: isRequired,
format: field.format,
enum: field.enum,
});
if (value !== null) {
content[fieldName] = value;
}
}
return { action: "accept", content };
});
最佳实践Direct link to 最佳实践
🌐 Best Practices
- 始终处理引导:在调用可能使用引导的工具之前先设置好你的处理程序
- 验证输入:检查是否提供了必填字段
- 尊重用户选择:优雅地处理拒绝和取消的响应
- 清晰的界面:让用户明显知晓所请求的信息及其原因
- 安全:切勿自动接受有关敏感信息的请求
OAuth 认证Direct link to OAuth 认证
🌐 OAuth Authentication
要连接需要根据 MCP Auth 规范 进行 OAuth 认证的 MCP 服务器,请使用 MCPOAuthClientProvider:
🌐 For connecting to MCP servers that require OAuth authentication per the MCP Auth Specification, use the MCPOAuthClientProvider:
import { MCPClient, MCPOAuthClientProvider } from "@mastra/mcp";
// Create an OAuth provider
const oauthProvider = new MCPOAuthClientProvider({
redirectUrl: "http://localhost:3000/oauth/callback",
clientMetadata: {
redirect_uris: ["http://localhost:3000/oauth/callback"],
client_name: "My MCP Client",
grant_types: ["authorization_code", "refresh_token"],
response_types: ["code"],
},
onRedirectToAuthorization: (url) => {
// Handle authorization redirect (open browser, redirect response, etc.)
console.log(`Please visit: ${url}`);
},
});
// Use the provider with MCPClient
const client = new MCPClient({
servers: {
protectedServer: {
url: new URL("https://mcp.example.com/mcp"),
authProvider: oauthProvider,
},
},
});
快速令牌提供商Direct link to 快速令牌提供商
🌐 Quick Token Provider
用于测试或当你已经有有效的访问令牌时:
🌐 For testing or when you already have a valid access token:
import { MCPClient, createSimpleTokenProvider } from "@mastra/mcp";
const provider = createSimpleTokenProvider("your-access-token", {
redirectUrl: "http://localhost:3000/callback",
clientMetadata: {
redirect_uris: ["http://localhost:3000/callback"],
client_name: "Test Client",
},
});
const client = new MCPClient({
servers: {
testServer: {
url: new URL("https://mcp.example.com/mcp"),
authProvider: provider,
},
},
});
自定义令牌存储Direct link to 自定义令牌存储
🌐 Custom Token Storage
要在会话之间持久存储令牌,请实现 OAuthStorage 接口:
🌐 For persistent token storage across sessions, implement the OAuthStorage interface:
import { MCPOAuthClientProvider, OAuthStorage } from "@mastra/mcp";
class DatabaseOAuthStorage implements OAuthStorage {
constructor(private db: Database, private userId: string) {}
async set(key: string, value: string): Promise<void> {
await this.db.query(
"INSERT INTO oauth_tokens (user_id, key, value) VALUES (?, ?, ?) ON CONFLICT DO UPDATE SET value = ?",
[this.userId, key, value, value]
);
}
async get(key: string): Promise<string | undefined> {
const result = await this.db.query(
"SELECT value FROM oauth_tokens WHERE user_id = ? AND key = ?",
[this.userId, key]
);
return result?.[0]?.value;
}
async delete(key: string): Promise<void> {
await this.db.query(
"DELETE FROM oauth_tokens WHERE user_id = ? AND key = ?",
[this.userId, key]
);
}
}
const provider = new MCPOAuthClientProvider({
redirectUrl: "http://localhost:3000/callback",
clientMetadata: { /* ... */ },
storage: new DatabaseOAuthStorage(db, "user-123"),
});
示例Direct link to 示例
🌐 Examples
静态工具配置Direct link to 静态工具配置
🌐 Static Tool Configuration
对于你的整个应用只与 MCP 服务器有单一连接的工具,请使用 listTools() 并将工具传递给你的代理:
🌐 For tools where you have a single connection to the MCP server for you entire app, use listTools() and pass the tools to your agent:
import { MCPClient } from "@mastra/mcp";
import { Agent } from "@mastra/core/agent";
const mcp = new MCPClient({
servers: {
stockPrice: {
command: "npx",
args: ["tsx", "stock-price.ts"],
env: {
API_KEY: "your-api-key",
},
log: (logMessage) => {
console.log(`[${logMessage.level}] ${logMessage.message}`);
},
},
weather: {
url: new URL("http://localhost:8080/sse"),
},
},
timeout: 30000, // Global 30s timeout
});
// Create an agent with access to all tools
const agent = new Agent({
id: "multi-tool-agent",
name: "Multi-tool Agent",
instructions: "You have access to multiple tool servers.",
model: "openai/gpt-5.1",
tools: await mcp.listTools(),
});
// Example of using resource methods
async function checkWeatherResource() {
try {
const weatherResources = await mcp.resources.list();
if (weatherResources.weather && weatherResources.weather.length > 0) {
const currentWeatherURI = weatherResources.weather[0].uri;
const weatherData = await mcp.resources.read(
"weather",
currentWeatherURI,
);
console.log("Weather data:", weatherData.contents[0].text);
}
} catch (error) {
console.error("Error fetching weather resource:", error);
}
}
checkWeatherResource();
// Example of using prompt methods
async function checkWeatherPrompt() {
try {
const weatherPrompts = await mcp.prompts.list();
if (weatherPrompts.weather && weatherPrompts.weather.length > 0) {
const currentWeatherPrompt = weatherPrompts.weather.find(
(p) => p.name === "current",
);
if (currentWeatherPrompt) {
console.log("Weather prompt:", currentWeatherPrompt);
} else {
console.log("Current weather prompt not found");
}
}
} catch (error) {
console.error("Error fetching weather prompt:", error);
}
}
checkWeatherPrompt();
动态工具集Direct link to 动态工具集
🌐 Dynamic toolsets
当你需要为每个用户创建新的 MCP 连接时,使用 listToolsets() 并在调用 stream 或 generate 时添加工具:
🌐 When you need a new MCP connection for each user, use listToolsets() and add the tools when calling stream or generate:
import { Agent } from "@mastra/core/agent";
import { MCPClient } from "@mastra/mcp";
// Create the agent first, without any tools
const agent = new Agent({
id: "multi-tool-agent",
name: "Multi-tool Agent",
instructions: "You help users check stocks and weather.",
model: "openai/gpt-5.1",
});
// Later, configure MCP with user-specific settings
const mcp = new MCPClient({
servers: {
stockPrice: {
command: "npx",
args: ["tsx", "stock-price.ts"],
env: {
API_KEY: "user-123-api-key",
},
timeout: 20000, // Server-specific timeout
},
weather: {
url: new URL("http://localhost:8080/sse"),
requestInit: {
headers: {
Authorization: `Bearer user-123-token`,
},
},
},
},
});
// Pass all toolsets to stream() or generate()
const response = await agent.stream(
"How is AAPL doing and what is the weather?",
{
toolsets: await mcp.listToolsets(),
},
);
实例管理Direct link to 实例管理
🌐 Instance Management
MCPClient 类包括用于管理多个实例的内置内存泄漏预防功能:
🌐 The MCPClient class includes built-in memory leak prevention for managing multiple instances:
- 在没有
id的情况下创建多个配置相同的实例会抛出错误以防止内存泄漏 - 如果你需要多个配置相同的实例,请为每个实例提供一个唯一的
id - 在使用相同配置重新创建实例之前调用
await configuration.disconnect() - 如果你只需要一个实例,考虑将配置移动到更高的范围,以避免重新创建
例如,如果你尝试在没有 id 的情况下创建多个相同配置的实例:
🌐 For example, if you try to create multiple instances with the same configuration without an id:
// First instance - OK
const mcp1 = new MCPClient({
servers: {
/* ... */
},
});
// Second instance with same config - Will throw an error
const mcp2 = new MCPClient({
servers: {
/* ... */
},
});
// To fix, either:
// 1. Add unique IDs
const mcp3 = new MCPClient({
id: "instance-1",
servers: {
/* ... */
},
});
// 2. Or disconnect before recreating
await mcp1.disconnect();
const mcp4 = new MCPClient({
servers: {
/* ... */
},
});
服务器生命周期Direct link to 服务器生命周期
🌐 Server Lifecycle
MCPClient 优雅地处理服务器连接:
🌐 MCPClient handles server connections gracefully:
- 多服务器的自动连接管理
- 优雅的服务器关闭以防止开发过程中出现错误信息
- 断开连接时正确清理资源
使用自定义 Fetch 进行动态身份验证Direct link to 使用自定义 Fetch 进行动态身份验证
🌐 Using Custom Fetch for Dynamic Authentication
对于 HTTP 服务器,你可以提供一个自定义的 fetch 函数来处理动态身份验证、请求拦截或其他自定义行为。当你需要在每个请求上刷新令牌或自定义请求行为时,这尤其有用。
🌐 For HTTP servers, you can provide a custom fetch function to handle dynamic authentication, request interception, or other custom behavior. This is particularly useful when you need to refresh tokens on each request or customize request behavior.
当提供 fetch 时,requestInit、eventSourceInit 和 authProvider 变为可选,因为你可以在自定义的 fetch 函数中处理这些问题。
🌐 When fetch is provided, requestInit, eventSourceInit, and authProvider become optional, as you can handle these concerns within your custom fetch function.
const mcpClient = new MCPClient({
servers: {
apiServer: {
url: new URL("https://api.example.com/mcp"),
fetch: async (url, init) => {
// Refresh token on each request
const token = await getAuthToken(); // Your token refresh logic
return fetch(url, {
...init,
headers: {
...init?.headers,
Authorization: `Bearer ${token}`,
},
});
},
},
},
});
使用 SSE 请求头Direct link to 使用 SSE 请求头
🌐 Using SSE Request Headers
在使用传统的 SSE MCP 传输时,由于 MCP SDK 的一个漏洞,你必须同时配置 requestInit 和 eventSourceInit。或者,你可以使用一个自定义的 fetch 函数,该函数将自动用于 POST 请求和 SSE 连接:
🌐 When using the legacy SSE MCP transport, you must configure both requestInit and eventSourceInit due to a bug in the MCP SDK. Alternatively, you can use a custom fetch function which will be automatically used for both POST requests and SSE connections:
// Option 1: Using requestInit and eventSourceInit (required for SSE)
const sseClient = new MCPClient({
servers: {
exampleServer: {
url: new URL("https://your-mcp-server.com/sse"),
// Note: requestInit alone isn't enough for SSE
requestInit: {
headers: {
Authorization: "Bearer your-token",
},
},
// This is also required for SSE connections with custom headers
eventSourceInit: {
fetch(input: Request | URL | string, init?: RequestInit) {
const headers = new Headers(init?.headers || {});
headers.set("Authorization", "Bearer your-token");
return fetch(input, {
...init,
headers,
});
},
},
},
},
});
// Option 2: Using custom fetch (simpler, works for both Streamable HTTP and SSE)
const sseClientWithFetch = new MCPClient({
servers: {
exampleServer: {
url: new URL("https://your-mcp-server.com/sse"),
fetch: async (url, init) => {
const headers = new Headers(init?.headers || {});
headers.set("Authorization", "Bearer your-token");
return fetch(url, {
...init,
headers,
});
},
},
},
});
相关信息Direct link to 相关信息
🌐 Related Information
- 有关创建 MCP 服务器,请参阅 MCPServer 文档。
- 关于模型上下文协议的更多信息,请参见 @modelcontextprotocol/sdk 文档。