MCP服务器
🌐 MCPServer
MCPServer 类提供了将你现有的 Mastra 工具和代理暴露为模型上下文协议(MCP)服务器的功能。这允许任何 MCP 客户端(如 Cursor、Windsurf 或 Claude Desktop)连接到这些功能,并将其提供给代理使用。
🌐 The MCPServer class provides the functionality to expose your existing Mastra tools and Agents as a Model Context Protocol (MCP) server. This allows any MCP client (like Cursor, Windsurf, or Claude Desktop) to connect to these capabilities and make them available to an agent.
请注意,如果你只需要在 Mastra 应用中直接使用你的工具或代理,则不必一定创建 MCP 服务器。此 API 专门用于将你的 Mastra 工具和代理暴露给外部 MCP 客户端。
🌐 Note that if you only need to use your tools or agents directly within your Mastra application, you don't necessarily need to create an MCP server. This API is specifically for exposing your Mastra tools and agents to external MCP clients.
它同时支持 stdio(子进程)和 SSE(HTTP)MCP 传输。
🌐 It supports both stdio (subprocess) and SSE (HTTP) MCP transports.
构造函数Direct link to 构造函数
🌐 Constructor
要创建一个新的 MCPServer,你需要提供一些关于服务器的基本信息、它将提供的工具,以及可选的你希望作为工具公开的任何代理。
🌐 To create a new MCPServer, you need to provide some basic information about your server, the tools it will offer, and optionally, any agents you want to expose as tools.
import { Agent } from "@mastra/core/agent";
import { createTool } from "@mastra/core/tools";
import { MCPServer } from "@mastra/mcp";
import { z } from "zod";
import { dataProcessingWorkflow } from "../workflows/dataProcessingWorkflow";
const myAgent = new Agent({
id: "my-example-agent",
name: "MyExampleAgent",
description: "A generalist to help with basic questions."
instructions: "You are a helpful assistant.",
model: "openai/gpt-5.1",
});
const weatherTool = createTool({
id: "getWeather",
description: "Gets the current weather for a location.",
inputSchema: z.object({ location: z.string() }),
execute: async (inputData) => `Weather in ${inputData.location} is sunny.`,
});
const server = new MCPServer({
id: "my-custom-server",
name: "My Custom Server",
version: "1.0.0",
description: "A server that provides weather data and agent capabilities",
instructions: "Use the available tools to help users with weather information and data processing tasks.",
tools: { weatherTool },
agents: { myAgent }, // this agent will become tool "ask_myAgent"
workflows: {
dataProcessingWorkflow, // this workflow will become tool "run_dataProcessingWorkflow"
}
});
配置属性Direct link to 配置属性
🌐 Configuration Properties
构造函数接受一个具有以下属性的 MCPServerConfig 对象:
🌐 The constructor accepts an MCPServerConfig object with the following properties:
id:
name:
version:
tools:
agents?:
workflows?:
description?:
instructions?:
repository?:
releaseDate?:
isLatest?:
packageCanonical?:
packages?:
remotes?:
resources?:
prompts?:
将代理揭露为工具Direct link to 将代理揭露为工具
🌐 Exposing Agents as Tools
MCPServer 的一个强大功能是它能够自动将你的 Mastra 代理公开为可调用工具。当你在配置的 agents 属性中提供代理时:
🌐 A powerful feature of MCPServer is its ability to automatically expose your Mastra Agents as callable tools. When you provide agents in the agents property of the configuration:
- 工具命名:每个代理都会被转换为一个名为
ask_<agentKey>的工具,其中<agentKey>是你在agents对象中为该代理使用的键。例如,如果你配置了agents: { myAgentKey: myAgentInstance },将会创建一个名为ask_myAgentKey的工具。 - 工具功能:
- 描述:生成工具的描述格式为:“向代理
<AgentName>提问。原始代理说明:<agent description>”。 - 输入:该工具期望接收一个包含
message属性(字符串)的单个对象参数:{ message: "Your question for the agent" }。 - 执行:当调用此工具时,它会调用对应代理的
generate()方法,并传入提供的query。 - 输出:代理的
generate()方法的直接结果将作为工具的输出返回。
- 描述:生成工具的描述格式为:“向代理
- 名称冲突:如果在
tools配置中显式定义的工具与代理生成的工具同名(例如,你有一个名为ask_myAgentKey的工具,同时还有一个键为myAgentKey的代理),显式定义的工具将优先。在这种冲突情况下,代理不会被转换为工具,并且会记录一条警告。
这使得允许 MCP 客户端像使用其他工具一样,通过自然语言查询与你的代理进行互动变得非常简单。
🌐 This makes it straightforward to allow MCP clients to interact with your agents using natural language queries, just like any other tool.
代理到工具转换Direct link to 代理到工具转换
🌐 Agent-to-Tool Conversion
当你在 agents 配置属性中提供代理时,MCPServer 将自动为每个代理创建一个相应的工具。该工具将被命名为 ask_<agentIdentifier>,其中 <agentIdentifier> 是你在 agents 对象中使用的键。
🌐 When you provide agents in the agents configuration property, MCPServer will automatically create a corresponding tool for each agent. The tool will be named ask_<agentIdentifier>, where <agentIdentifier> is the key you used in the agents object.
这个生成工具的描述将是:“向代理 <agent.name> 提问。代理描述:<agent.description>”。
🌐 The description for this generated tool will be: "Ask agent <agent.name> a question. Agent description: <agent.description>".
重要:要将一个代理转换为工具,该代理在实例化时其配置中必须设置非空的 description 字符串属性(例如,new Agent({ name: 'myAgent', description: 'This agent does X.', ... }))。如果将一个缺少或空 description 的代理传递给 MCPServer,在实例化 MCPServer 时将抛出错误,服务器设置将失败。
这使你能够通过MCP快速展示代理的生成能力,从而让客户可以直接“向”你的代理提问。
🌐 This allows you to quickly expose the generative capabilities of your agents through the MCP, enabling clients to "ask" your agents questions directly.
在工具中访问MCP上下文Direct link to 在工具中访问MCP上下文
🌐 Accessing MCP Context in Tools
通过 MCPServer 暴露的工具可以根据工具的调用方式,通过两种不同的属性访问 MCP 请求上下文(认证、会话 ID 等):
🌐 Tools exposed through MCPServer can access MCP request context (authentication, session IDs, etc.) via two different properties depending on how the tool is invoked:
| 调用模式 | 访问方式 |
|---|---|
| 直接工具调用 | context?.mcp?.extra |
| 代理工具调用 | context?.requestContext?.get("mcp.extra") |
通用模式(适用于两种情况):
const mcpExtra = context?.mcp?.extra ?? context?.requestContext?.get("mcp.extra");
const authInfo = mcpExtra?.authInfo;
示例:在两种环境下都能使用的工具Direct link to 示例:在两种环境下都能使用的工具
🌐 Example: Tool that works in both contexts
import { createTool } from "@mastra/core/tools";
import { z } from "zod";
const fetchUserData = createTool({
id: "fetchUserData",
description: "Fetches user data using authentication from MCP context",
inputSchema: z.object({
userId: z.string().describe("The ID of the user to fetch"),
}),
execute: async (inputData, context) => {
// Access MCP authentication context
// When called directly via MCP: context.mcp.extra
// When called via agent: context.requestContext.get('mcp.extra')
const mcpExtra = context?.mcp?.extra || context?.requestContext?.get("mcp.extra");
const authInfo = mcpExtra?.authInfo;
if (!authInfo?.token) {
throw new Error("Authentication required");
}
const response = await fetch(`https://api.example.com/users/${inputData.userId}`, {
headers: {
Authorization: `Bearer ${authInfo.token}`,
},
});
return response.json();
},
});
方法Direct link to 方法
🌐 Methods
这些是在 MCPServer 实例上可以调用的函数,用于控制其行为和获取信息。
🌐 These are the functions you can call on an MCPServer instance to control its behavior and get information.
startStdio()Direct link to startStdio()
使用此方法启动服务器,使其通过标准输入和输出(stdio)进行通信。当作为命令行程序运行服务器时,这很常见。
🌐 Use this method to start the server so it communicates using standard input and output (stdio). This is typical when running the server as a command-line program.
async startStdio(): Promise<void>
以下是如何使用 stdio 启动服务器:
🌐 Here's how you would start the server using stdio:
const server = new MCPServer({
id: "my-server",
name: "My Server",
version: "1.0.0",
tools: { /* ... */ },
});
await server.startStdio();
startSSE()Direct link to startSSE()
这种方法可以帮助你将 MCP 服务器与现有的网页服务器集成,以使用服务器发送事件(SSE)进行通信。当你的网页服务器接收到 SSE 或消息路径的请求时,你将在服务器的代码中调用此方法。
🌐 This method helps you integrate the MCP server with an existing web server to use Server-Sent Events (SSE) for communication. You'll call this from your web server's code when it receives a request for the SSE or message paths.
async startSSE({
url,
ssePath,
messagePath,
req,
res,
}: {
url: URL;
ssePath: string;
messagePath: string;
req: any;
res: any;
}): Promise<void>
下面是一个示例,展示如何在 HTTP 服务器请求处理程序中使用 startSSE。在此示例中,MCP 客户端可以在 http://localhost:1234/sse 连接到你的 MCP 服务器:
🌐 Here's an example of how you might use startSSE within an HTTP server request handler. In this example an MCP client could connect to your MCP server at http://localhost:1234/sse:
import http from "http";
const httpServer = http.createServer(async (req, res) => {
await server.startSSE({
url: new URL(req.url || "", `http://localhost:1234`),
ssePath: "/sse",
messagePath: "/message",
req,
res,
});
});
httpServer.listen(PORT, () => {
console.log(`HTTP server listening on port ${PORT}`);
});
以下是 startSSE 方法所需值的详细信息:
🌐 Here are the details for the values needed by the startSSE method:
url:
ssePath:
messagePath:
req:
res:
startHonoSSE()Direct link to startHonoSSE()
这种方法可以帮助你将 MCP 服务器与现有的网页服务器集成,以使用服务器发送事件(SSE)进行通信。当你的网页服务器接收到 SSE 或消息路径的请求时,你将在服务器的代码中调用此方法。
🌐 This method helps you integrate the MCP server with an existing web server to use Server-Sent Events (SSE) for communication. You'll call this from your web server's code when it receives a request for the SSE or message paths.
async startHonoSSE({
url,
ssePath,
messagePath,
req,
res,
}: {
url: URL;
ssePath: string;
messagePath: string;
req: any;
res: any;
}): Promise<void>
下面是一个示例,展示如何在 HTTP 服务器请求处理程序中使用 startHonoSSE。在此示例中,MCP 客户端可以在 http://localhost:1234/hono-sse 连接到你的 MCP 服务器:
🌐 Here's an example of how you might use startHonoSSE within an HTTP server request handler. In this example an MCP client could connect to your MCP server at http://localhost:1234/hono-sse:
import http from "http";
const httpServer = http.createServer(async (req, res) => {
await server.startHonoSSE({
url: new URL(req.url || "", `http://localhost:1234`),
ssePath: "/hono-sse",
messagePath: "/message",
req,
res,
});
});
httpServer.listen(PORT, () => {
console.log(`HTTP server listening on port ${PORT}`);
});
以下是 startHonoSSE 方法所需值的详细信息:
🌐 Here are the details for the values needed by the startHonoSSE method:
url:
ssePath:
messagePath:
req:
res:
startHTTP()Direct link to startHTTP()
此方法可帮助你将 MCP 服务器与现有的 Web 服务器集成,以便使用可流式传输的 HTTP 进行通信。当你的 Web 服务器收到 HTTP 请求时,你将在其代码中调用此方法。
🌐 This method helps you integrate the MCP server with an existing web server to use streamable HTTP for communication. You'll call this from your web server's code when it receives HTTP requests.
async startHTTP({
url,
httpPath,
req,
res,
options = { sessionIdGenerator: () => randomUUID() },
}: {
url: URL;
httpPath: string;
req: http.IncomingMessage;
res: http.ServerResponse<http.IncomingMessage>;
options?: StreamableHTTPServerTransportOptions;
}): Promise<void>
下面是一个示例,展示如何在 HTTP 服务器请求处理程序中使用 startHTTP。在此示例中,MCP 客户端可以在 http://localhost:1234/http 连接到你的 MCP 服务器:
🌐 Here's an example of how you might use startHTTP within an HTTP server request handler. In this example an MCP client could connect to your MCP server at http://localhost:1234/http:
import http from "http";
const httpServer = http.createServer(async (req, res) => {
await server.startHTTP({
url: new URL(req.url || "", "http://localhost:1234"),
httpPath: `/mcp`,
req,
res,
options: {
sessionIdGenerator: () => randomUUID(),
},
});
});
httpServer.listen(PORT, () => {
console.log(`HTTP server listening on port ${PORT}`);
});
对于无服务器环境(Supabase Edge Functions、Cloudflare Workers、Vercel Edge 等),使用 serverless: true 来启用无状态操作:
🌐 For serverless environments (Supabase Edge Functions, Cloudflare Workers, Vercel Edge, etc.), use serverless: true to enable stateless operation:
// Supabase Edge Function example
import { serve } from "https://deno.land/std@0.168.0/http/server.ts";
import { MCPServer } from "@mastra/mcp";
// Note: You will need to convert req/res format from Deno to Node
import { toReqRes, toFetchResponse } from "fetch-to-node";
const server = new MCPServer({
id: "my-serverless-mcp",
name: "My Serverless MCP",
version: "1.0.0",
tools: { /* your tools */ },
});
serve(async (req) => {
const url = new URL(req.url);
if (url.pathname === "/mcp") {
// Convert Deno Request to Node.js-compatible format
const { req: nodeReq, res: nodeRes } = toReqRes(req);
await server.startHTTP({
url,
httpPath: "/mcp",
req: nodeReq,
res: nodeRes,
options: {
serverless: true, // ← Enable stateless mode for serverless
},
});
return toFetchResponse(nodeRes);
}
return new Response("Not found", { status: 404 });
});
何时使用 serverless: true
在部署到每个请求都在新的、无状态的执行上下文中运行的环境时使用 serverless: true:
🌐 Use serverless: true when deploying to environments where each request runs in a fresh, stateless execution context:
- Supabase 边缘函数
- Cloudflare 工作者
- Vercel 边缘函数
- Netlify 边缘函数
- AWS Lambda
- Deno 部署
使用默认的基于会话的模式(不使用 serverless: true)用于:
🌐 Use the default session-based mode (without serverless: true) for:
- 长寿的 Node.js 服务器
- Docker 容器
- 传统托管(VPS,专用服务器)
无服务器模式禁用会话管理,并为每个请求创建新的服务器实例,这对于内存不会在调用之间保持的无状态环境是必要的。
🌐 The serverless mode disables session management and creates fresh server instances per request, which is necessary for stateless environments where memory doesn't persist between invocations.
注意: 以下 MCP 功能需要会话状态或持久连接,在无服务器模式下无法使用:
- 获取信息 - 在工具执行过程中进行的互动用户输入请求需要会话管理以将响应归回到正确的客户端
- 资源订阅 -
resources/subscribe和resources/unsubscribe需要持久连接以维持订阅状态 - 资源更新通知 -
resources.notifyUpdated()需要主动订阅和持续连接以通知客户端 - 提示列表更改通知 -
prompts.notifyListChanged()需要持久连接以向客户端推送更新
这些功能在长时间运行的服务器环境中(Node.js 服务器、Docker 容器等)可以正常工作。
🌐 These features work normally in long-lived server environments (Node.js servers, Docker containers, etc.).
以下是 startHTTP 方法所需值的详细信息:
🌐 Here are the details for the values needed by the startHTTP method:
url:
httpPath:
req:
res:
options:
StreamableHTTPServerTransportOptions 对象允许你自定义 HTTP 传输的行为。以下是可用的选项:
🌐 The StreamableHTTPServerTransportOptions object allows you to customize the behavior of the HTTP transport. Here are the available options:
serverless:
sessionIdGenerator:
onsessioninitialized:
enableJsonResponse:
eventStore:
close()Direct link to close()
此方法会关闭服务器并释放所有资源。
🌐 This method closes the server and releases all resources.
async close(): Promise<void>
getServerInfo()Direct link to getServerInfo()
此方法可让你查看服务器的基本信息。
🌐 This method gives you a look at the server's basic information.
getServerInfo(): ServerInfo
getServerDetail()Direct link to getServerDetail()
这种方法可以让你详细了解服务器的信息。
🌐 This method gives you a detailed look at the server's information.
getServerDetail(): ServerDetail
getToolListInfo()Direct link to getToolListInfo()
此方法让你查看在创建服务器时设置的工具。这是一个只读列表,可用于调试目的。
🌐 This method gives you a look at the tools that were set up when you created the server. It's a read-only list, useful for debugging purposes.
getToolListInfo(): ToolListInfo
getToolInfo()Direct link to getToolInfo()
此方法为你提供有关特定工具的详细信息。
🌐 This method gives you detailed information about a specific tool.
getToolInfo(toolName: string): ToolInfo
executeTool()Direct link to executeTool()
此方法执行一个特定的工具并返回结果。
🌐 This method executes a specific tool and returns the result.
executeTool(toolName: string, input: any): Promise<any>
getStdioTransport()Direct link to getStdioTransport()
如果你使用 startStdio() 启动了服务器,你可以使用它来获取管理 stdio 通信的对象。这主要用于内部检查或测试。
🌐 If you started the server with startStdio(), you can use this to get the object that manages the stdio communication. This is mostly for checking things internally or for testing.
getStdioTransport(): StdioServerTransport | undefined
getSseTransport()Direct link to getSseTransport()
如果你使用 startSSE() 启动服务器,你可以使用它来获取管理 SSE 通信的对象。像 getStdioTransport 一样,这主要用于内部检查或测试。
🌐 If you started the server with startSSE(), you can use this to get the object that manages the SSE communication. Like getStdioTransport, this is mainly for internal checks or testing.
getSseTransport(): SSEServerTransport | undefined
getSseHonoTransport()Direct link to getSseHonoTransport()
如果你使用 startHonoSSE() 启动服务器,你可以使用它来获取管理 SSE 通信的对象。像 getSseTransport 一样,这主要用于内部检查或测试。
🌐 If you started the server with startHonoSSE(), you can use this to get the object that manages the SSE communication. Like getSseTransport, this is mainly for internal checks or testing.
getSseHonoTransport(): SSETransport | undefined
getStreamableHTTPTransport()Direct link to getStreamableHTTPTransport()
如果你使用 startHTTP() 启动服务器,你可以使用它来获取管理 HTTP 通信的对象。像 getSseTransport 一样,它主要用于内部检查或测试。
🌐 If you started the server with startHTTP(), you can use this to get the object that manages the HTTP communication. Like getSseTransport, this is mainly for internal checks or testing.
getStreamableHTTPTransport(): StreamableHTTPServerTransport | undefined
tools()Direct link to tools()
执行此 MCP 服务器提供的特定工具。
🌐 Executes a specific tool provided by this MCP server.
async executeTool(
toolId: string,
args: any,
executionContext?: { messages?: any[]; toolCallId?: string },
): Promise<any>
toolId:
args:
executionContext?:
资源管理Direct link to 资源管理
🌐 Resource Handling
MCP 资源是什么?Direct link to MCP 资源是什么?
🌐 What are MCP Resources?
资源是模型上下文协议(MCP)中的核心原语,它允许服务器公开数据和内容,客户端可以读取这些数据并将其用作与大语言模型(LLM)交互的上下文。它们代表了MCP服务器希望提供的任何类型的数据,例如:
🌐 Resources are a core primitive in the Model Context Protocol (MCP) that allow servers to expose data and content that can be read by clients and used as context for LLM interactions. They represent any kind of data that an MCP server wants to make available, such as:
- 文件内容
- 数据库记录
- API 响应
- 实时系统数据
- 截图和图片
- 日志文件
资源通过唯一的 URI(例如 file:///home/user/documents/report.pdf、postgres://database/customers/schema)进行标识,并且可以包含文本(UTF-8 编码)或二进制数据(base64 编码)。
🌐 Resources are identified by unique URIs (e.g., file:///home/user/documents/report.pdf, postgres://database/customers/schema) and can contain either text (UTF-8 encoded) or binary data (base64 encoded).
客户可以通过以下方式发现资源:
🌐 Clients can discover resources through:
- 直接资源:服务器通过
resources/list端点暴露一系列具体资源。 - 资源模板:对于动态资源,服务器可以公开 URI 模板(RFC 6570),客户端可以使用这些模板来构建资源 URI。
要读取资源,客户端使用 URI 发出 resources/read 请求。如果客户端已订阅该资源,服务器还可以通知客户端资源列表的更改(notifications/resources/list_changed)或特定资源内容的更新(notifications/resources/updated)。
🌐 To read a resource, clients make a resources/read request with the URI. Servers can also notify clients about changes to the resource list (notifications/resources/list_changed) or updates to specific resource content (notifications/resources/updated) if a client has subscribed to that resource.
有关更详细的信息,请参阅官方 MCP 资源文档。
🌐 For more detailed information, refer to the official MCP documentation on Resources.
MCPServerResources 型Direct link to mcpserverresources-type
🌐 MCPServerResources Type
resources 选项接受一个类型为 MCPServerResources 的对象。该类型定义了你的服务器将用来处理资源请求的回调函数:
🌐 The resources option takes an object of type MCPServerResources. This type defines the callbacks your server will use to handle resource requests:
export type MCPServerResources = {
// Callback to list available resources
listResources: () => Promise<Resource[]>;
// Callback to get the content of a specific resource
getResourceContent: ({
uri,
}: {
uri: string;
}) => Promise<MCPServerResourceContent | MCPServerResourceContent[]>;
// Optional callback to list available resource templates
resourceTemplates?: () => Promise<ResourceTemplate[]>;
};
export type MCPServerResourceContent = { text?: string } | { blob?: string };
示例:
🌐 Example:
import { MCPServer } from "@mastra/mcp";
import type {
MCPServerResourceContent,
Resource,
ResourceTemplate,
} from "@mastra/mcp";
// Resources/resource templates will generally be dynamically fetched.
const myResources: Resource[] = [
{ uri: "file://data/123.txt", name: "Data File", mimeType: "text/plain" },
];
const myResourceContents: Record<string, MCPServerResourceContent> = {
"file://data.txt/123": { text: "This is the content of the data file." },
};
const myResourceTemplates: ResourceTemplate[] = [
{
uriTemplate: "file://data/{id}",
name: "Data File",
description: "A file containing data.",
mimeType: "text/plain",
},
];
const myResourceHandlers: MCPServerResources = {
listResources: async () => myResources,
getResourceContent: async ({ uri }) => {
if (myResourceContents[uri]) {
return myResourceContents[uri];
}
throw new Error(`Resource content not found for ${uri}`);
},
resourceTemplates: async () => myResourceTemplates,
};
const serverWithResources = new MCPServer({
id: "resourceful-server",
name: "Resourceful Server",
version: "1.0.0",
tools: {
/* ... your tools ... */
},
resources: myResourceHandlers,
});
通知客户资源变更Direct link to 通知客户资源变更
🌐 Notifying Clients of Resource Changes
如果可用的资源或其内容发生变化,你的服务器可以通知订阅了该特定资源的已连接客户端。
🌐 If the available resources or their content change, your server can notify connected clients that are subscribed to the specific resource.
server.resources.notifyUpdated({ uri: string })Direct link to serverresourcesnotifyupdated-uri-string-
当特定资源(通过其 uri 标识)的内容已更新时调用此方法。如果有任何客户端订阅了该 URI,它们将收到 notifications/resources/updated 消息。
🌐 Call this method when the content of a specific resource (identified by its uri) has been updated. If any clients are subscribed to this URI, they will receive a notifications/resources/updated message.
async server.resources.notifyUpdated({ uri: string }): Promise<void>
示例:
🌐 Example:
// After updating the content of 'file://data.txt'
await serverWithResources.resources.notifyUpdated({ uri: "file://data.txt" });
server.resources.notifyListChanged()Direct link to serverresourcesnotifylistchanged
当可用资源的整体列表发生变化时(例如,添加或删除了资源)调用此方法。这将向客户端发送 notifications/resources/list_changed 消息,提示它们重新获取资源列表。
🌐 Call this method when the overall list of available resources has changed (e.g., a resource was added or removed). This will send a notifications/resources/list_changed message to clients, prompting them to re-fetch the list of resources.
async server.resources.notifyListChanged(): Promise<void>
示例:
🌐 Example:
// After adding a new resource to the list managed by 'myResourceHandlers.listResources'
await serverWithResources.resources.notifyListChanged();
提示处理Direct link to 提示处理
🌐 Prompt Handling
什么是MCP提示?Direct link to 什么是MCP提示?
🌐 What are MCP Prompts?
提示是 MCP 服务器向客户端提供的可重用模板或工作流程。它们可以接受参数、包含资源上下文、支持版本控制,并可用于标准化 LLM 交互。
🌐 Prompts are reusable templates or workflows that MCP servers expose to clients. They can accept arguments, include resource context, support versioning, and be used to standardize LLM interactions.
提示由唯一名称(可选版本)标识,并且可以是动态或静态的。
🌐 Prompts are identified by a unique name (and optional version) and can be dynamic or static.
MCPServerPrompts 型Direct link to mcpserverprompts-type
🌐 MCPServerPrompts Type
prompts 选项接受一个类型为 MCPServerPrompts 的对象。该类型定义了你的服务器将用来处理提示请求的回调函数:
🌐 The prompts option takes an object of type MCPServerPrompts. This type defines the callbacks your server will use to handle prompt requests:
export type MCPServerPrompts = {
// Callback to list available prompts
listPrompts: () => Promise<Prompt[]>;
// Callback to get the messages/content for a specific prompt
getPromptMessages?: ({
name,
version,
args,
}: {
name: string;
version?: string;
args?: any;
}) => Promise<{ prompt: Prompt; messages: PromptMessage[] }>;
};
示例:
🌐 Example:
import { MCPServer } from "@mastra/mcp";
import type { Prompt, PromptMessage, MCPServerPrompts } from "@mastra/mcp";
const prompts: Prompt[] = [
{
name: "analyze-code",
description: "Analyze code for improvements",
version: "v1",
},
{
name: "analyze-code",
description: "Analyze code for improvements (new logic)",
version: "v2",
},
];
const myPromptHandlers: MCPServerPrompts = {
listPrompts: async () => prompts,
getPromptMessages: async ({ name, version, args }) => {
if (name === "analyze-code") {
if (version === "v2") {
const prompt = prompts.find(
(p) => p.name === name && p.version === "v2",
);
if (!prompt) throw new Error("Prompt version not found");
return {
prompt,
messages: [
{
role: "user",
content: {
type: "text",
text: `Analyze this code with the new logic: ${args.code}`,
},
},
],
};
}
// Default or v1
const prompt = prompts.find((p) => p.name === name && p.version === "v1");
if (!prompt) throw new Error("Prompt version not found");
return {
prompt,
messages: [
{
role: "user",
content: { type: "text", text: `Analyze this code: ${args.code}` },
},
],
};
}
throw new Error("Prompt not found");
},
};
const serverWithPrompts = new MCPServer({
id: "promptful-server",
name: "Promptful Server",
version: "1.0.0",
tools: {
/* ... */
},
prompts: myPromptHandlers,
});
通知客户提示更改Direct link to 通知客户提示更改
🌐 Notifying Clients of Prompt Changes
如果可用的提示发生变化,你的服务器可以通知已连接的客户端:
🌐 If the available prompts change, your server can notify connected clients:
server.prompts.notifyListChanged()Direct link to serverpromptsnotifylistchanged
当可用提示的整体列表发生变化时(例如,添加或删除了提示)调用此方法。这将向客户端发送 notifications/prompts/list_changed 消息,提示它们重新获取提示列表。
🌐 Call this method when the overall list of available prompts has changed (e.g., a prompt was added or removed). This will send a notifications/prompts/list_changed message to clients, prompting them to re-fetch the list of prompts.
await serverWithPrompts.prompts.notifyListChanged();
提示处理最佳实践Direct link to 提示处理最佳实践
🌐 Best Practices for Prompt Handling
- 使用清晰、描述性的提示名称和说明。
- 验证
getPromptMessages中的所有必需参数。 - 如果你预计会进行破坏性更改,请包含
version字段。 - 使用
version参数来选择正确的提示逻辑。 - 当提示列表更改时通知客户。
- 使用信息丰富的消息处理错误。
- 记录参数期望值和可用版本。
示例Direct link to 示例
🌐 Examples
有关设置和部署 MCPServer 的实际示例,请参阅 发布 MCP 服务器指南。
🌐 For practical examples of setting up and deploying an MCPServer, see the Publishing an MCP Server guide.
本页开头的示例还演示了如何使用工具和代理实例化 MCPServer。
🌐 The example at the beginning of this page also demonstrates how to instantiate MCPServer with both tools and agents.
引出Direct link to 引出
🌐 Elicitation
什么是引导?Direct link to 什么是引导?
🌐 What is Elicitation?
引出是模型上下文协议(MCP)中的一项功能,允许服务器从用户处请求结构化信息。这使得服务器能够在交互式工作流程中动态收集额外数据。
🌐 Elicitation is a feature in the Model Context Protocol (MCP) that allows servers to request structured information from users. This enables interactive workflows where servers can collect additional data dynamically.
MCPServer 类自动包含引导功能。工具在它们的 execute 函数中接收一个 context.mcp 对象,该对象包含一个用于请求用户输入的 elicitation.sendRequest() 方法。
🌐 The MCPServer class automatically includes elicitation capabilities. Tools receive a context.mcp object in their execute function that includes an elicitation.sendRequest() method for requesting user input.
工具执行签名Direct link to 工具执行签名
🌐 Tool Execution Signature
当工具在 MCP 服务器环境中执行时,它们会通过 context.mcp 对象获取 MCP 特定的功能:
🌐 When tools are executed within an MCP server context, they receive MCP-specific capabilities via the context.mcp object:
execute: async (inputData, context) => {
// input contains the tool's inputData parameters
// context.mcp contains server capabilities like elicitation and authentication info
// Access authentication information (when available)
if (context.mcp?.extra?.authInfo) {
console.log("Authenticated request from:", context.mcp.extra.authInfo.clientId);
}
// Use elicitation capabilities
const result = await context.mcp.elicitation.sendRequest({
message: "Please provide information",
requestedSchema: {
/* schema */
},
});
return result;
};
引导工作原理Direct link to 引导工作原理
🌐 How Elicitation Works
一个常见的用例是在工具执行期间。当工具需要用户输入时,它可以使用通过上下文参数提供的引导功能:
🌐 A common use case is during tool execution. When a tool needs user input, it can use the elicitation functionality provided through the context parameter:
- 该工具使用一个消息和模式调用
context.mcp.elicitation.sendRequest() - 请求已发送给已连接的MCP客户端
- 客户端向用户呈现请求(通过用户界面、命令行等)
- 用户提供输入、拒绝或取消请求
- 客户端将响应发送回服务器
- 该工具接收响应并继续执行
在工具中使用引导Direct link to 在工具中使用引导
🌐 Using Elicitation in Tools
下面是一个使用引导方法收集用户联系信息的工具示例:
🌐 Here's an example of a tool that uses elicitation to collect user contact information:
import { MCPServer } from "@mastra/mcp";
import { createTool } from "@mastra/core/tools";
import { z } from "zod";
const server = new MCPServer({
id: "interactive-server",
name: "Interactive Server",
version: "1.0.0",
tools: {
collectContactInfo: createTool({
id: "collectContactInfo",
description: "Collects user contact information through elicitation",
inputSchema: z.object({
reason: z
.string()
.optional()
.describe("Reason for collecting contact info"),
}),
execute: async (inputData, context) => {
const { reason } = inputData;
// Log session info if available
console.log("Request from session:", context.mcp?.extra?.sessionId);
try {
// Request user input via elicitation
const result = await context.mcp.elicitation.sendRequest({
message: reason
? `Please provide your contact information. ${reason}`
: "Please provide your contact information",
requestedSchema: {
type: "object",
properties: {
name: {
type: "string",
title: "Full Name",
description: "Your full name",
},
email: {
type: "string",
title: "Email Address",
description: "Your email address",
format: "email",
},
phone: {
type: "string",
title: "Phone Number",
description: "Your phone number (optional)",
},
},
required: ["name", "email"],
},
});
// Handle the user's response
if (result.action === "accept") {
return `Contact information collected: ${JSON.stringify(result.content, null, 2)}`;
} else if (result.action === "decline") {
return "Contact information collection was declined by the user.";
} else {
return "Contact information collection was cancelled by the user.";
}
} catch (error) {
return `Error collecting contact information: ${error}`;
}
},
}),
},
});
引导请求模式Direct link to 引导请求模式
🌐 Elicitation Request Schema
requestedSchema 必须是一个仅含基本属性的平面对象。支持的类型包括:
🌐 The requestedSchema must be a flat object with primitive properties only. Supported types include:
- 字符串:
{ type: 'string', title: 'Display Name', description: 'Help text' } - 编号:
{ type: 'number', minimum: 0, maximum: 100 } - 布尔:
{ type: 'boolean', default: false } - 枚举:
{ type: 'string', enum: ['option1', 'option2'] }
示例模式:
🌐 Example schema:
{
type: 'object',
properties: {
name: {
type: 'string',
title: 'Full Name',
description: 'Your complete name',
},
age: {
type: 'number',
title: 'Age',
minimum: 18,
maximum: 120,
},
newsletter: {
type: 'boolean',
title: 'Subscribe to Newsletter',
default: false,
},
},
required: ['name'],
}
响应行动Direct link to 响应行动
🌐 Response Actions
用户可以通过三种方式回应引导请求:
🌐 Users can respond to elicitation requests in three ways:
- 接受 (
action: 'accept'):用户提供了数据并确认提交- 包含提交数据的
content字段
- 包含提交数据的
- 拒绝 (
action: 'decline'):用户明确拒绝提供信息- 没有内容字段
- 取消 (
action: 'cancel'):用户在未作出决定的情况下关闭了请求- 没有内容字段
工具应适当地处理所有三种响应类型。
🌐 Tools should handle all three response types appropriately.
安全注意事项Direct link to 安全注意事项
🌐 Security Considerations
- 绝不要请求敏感信息,如密码、社会保障号码或信用卡号码
- 根据提供的模式验证所有用户输入
- 优雅地处理拒绝和取消
- 提供清晰的数据收集理由
- 尊重用户隐私和偏好
工具执行 APIDirect link to 工具执行 API
🌐 Tool Execution API
该引出功能可以通过工具执行中的 options 参数使用:
🌐 The elicitation functionality is available through the options parameter in tool execution:
// Within a tool's execute function
execute: async (inputData, context) => {
// Use elicitation for user input
const result = await context.mcp.elicitation.sendRequest({
message: string, // Message to display to user
requestedSchema: object // JSON schema defining expected response structure
}): Promise<ElicitResult>
// Access authentication info if needed
if (context.mcp?.extra?.authInfo) {
// Use context.mcp.extra.authInfo.token, etc.
}
}
请注意,当使用基于 HTTP 的传输(SSE 或 HTTP)时,信息提取是会话感知的。这意味着当多个客户端连接到同一服务器时,信息提取请求会被路由到发起工具执行的正确客户端会话。
🌐 Note that elicitation is session-aware when using HTTP-based transports (SSE or HTTP). This means that when multiple clients are connected to the same server, elicitation requests are routed to the correct client session that initiated the tool execution.
ElicitResult 类型:
🌐 The ElicitResult type:
type ElicitResult = {
action: "accept" | "decline" | "cancel";
content?: any; // Only present when action is 'accept'
};
OAuth 保护Direct link to OAuth 保护
🌐 OAuth Protection
要根据 MCP 身份验证规范 使用 OAuth 身份验证保护你的 MCP 服务器,请使用 createOAuthMiddleware 函数:
🌐 To protect your MCP server with OAuth authentication per the MCP Auth Specification, use the createOAuthMiddleware function:
import http from "node:http";
import { MCPServer, createOAuthMiddleware, createStaticTokenValidator } from "@mastra/mcp";
const mcpServer = new MCPServer({
id: "protected-server",
name: "Protected MCP Server",
version: "1.0.0",
tools: { /* your tools */ },
});
// Create OAuth middleware
const oauthMiddleware = createOAuthMiddleware({
oauth: {
resource: "https://mcp.example.com/mcp",
authorizationServers: ["https://auth.example.com"],
scopesSupported: ["mcp:read", "mcp:write"],
resourceName: "My Protected MCP Server",
validateToken: createStaticTokenValidator(["allowed-token-1"]),
},
mcpPath: "/mcp",
});
// Create HTTP server with OAuth protection
const httpServer = http.createServer(async (req, res) => {
const url = new URL(req.url || "", "https://mcp.example.com");
// Apply OAuth middleware first
const result = await oauthMiddleware(req, res, url);
if (!result.proceed) return; // Middleware handled response (401, metadata, etc.)
// Token is valid, proceed to MCP handler
await mcpServer.startHTTP({ url, httpPath: "/mcp", req, res });
});
httpServer.listen(3000);
中间件自动执行:
🌐 The middleware automatically:
- 在
/.well-known/oauth-protected-resource提供 受保护的资源元数据(RFC 9728) - 当需要身份验证时,返回带有适当
WWW-Authenticate头的401 Unauthorized - 使用你提供的验证器验证承载令牌
令牌验证Direct link to 令牌验证
🌐 Token Validation
在生产环境中,请使用适当的令牌验证:
🌐 For production, use proper token validation:
import { createOAuthMiddleware, createIntrospectionValidator } from "@mastra/mcp";
// Option 1: Token introspection (RFC 7662)
const middleware = createOAuthMiddleware({
oauth: {
resource: "https://mcp.example.com/mcp",
authorizationServers: ["https://auth.example.com"],
validateToken: createIntrospectionValidator(
"https://auth.example.com/oauth/introspect",
{ clientId: "mcp-server", clientSecret: "secret" }
),
},
});
// Option 2: Custom validation (JWT, database lookup, etc.)
const customMiddleware = createOAuthMiddleware({
oauth: {
resource: "https://mcp.example.com/mcp",
authorizationServers: ["https://auth.example.com"],
validateToken: async (token, resource) => {
const decoded = await verifyJWT(token);
if (!decoded) {
return { valid: false, error: "invalid_token" };
}
return {
valid: true,
scopes: decoded.scope?.split(" ") || [],
subject: decoded.sub,
};
},
},
});
OAuth 中间件选项Direct link to OAuth 中间件选项
🌐 OAuth Middleware Options
oauth.resource:
oauth.scopesSupported?:
oauth.resourceName?:
oauth.validateToken?:
mcpPath?:
认证上下文Direct link to 认证上下文
🌐 Authentication Context
在使用基于 HTTP 的传输时,工具可以通过 context.mcp.extra 访问请求元数据。这允许你将认证信息、用户上下文或任何自定义数据从你的 HTTP 中间件传递给 MCP 工具。
🌐 Tools can access request metadata via context.mcp.extra when using HTTP-based transports. This allows you to pass authentication info, user context, or any custom data from your HTTP middleware to your MCP tools.
工作原理Direct link to 工作原理
🌐 How It Works
无论你在 HTTP 中间件中将 req.auth 设置为何值,它都会在你的工具中作为 context.mcp.extra.authInfo 可用:
🌐 Whatever you set on req.auth in your HTTP middleware becomes available as context.mcp.extra.authInfo in your tools:
req.auth = { ... } → context?.mcp?.extra?.authInfo.extra = { ... }
设置认证中间件Direct link to 设置认证中间件
🌐 Setting Up Authentication Middleware
要将数据传递给你的工具,请在调用 server.startHTTP() 之前,在你的 HTTP 服务器中间件的 Node.js 请求对象上填充 req.auth。
🌐 To pass data to your tools, populate req.auth on the Node.js request object in your HTTP server middleware before calling server.startHTTP().
import express from "express";
const app = express();
// Auth middleware - set req.auth before the MCP handler
app.use("/mcp", (req, res, next) => {
const token = req.headers.authorization?.replace("Bearer ", "");
const user = verifyToken(token);
// This entire object becomes context.mcp.extra.authInfo
// @ts-ignore - req.auth is read by the MCP SDK
req.auth = {
token,
userId: user.userId,
email: user.email,
};
next();
});
app.all("/mcp", async (req, res) => {
const url = new URL(req.url, `http://${req.headers.host}`);
await server.startHTTP({ url, httpPath: "/mcp", req, res });
});
在工具中访问认证数据Direct link to 在工具中访问认证数据
🌐 Accessing Auth Data in Tools
req.auth 对象在你的工具的 execute 函数中可作为 context.mcp.extra.authInfo 使用:
🌐 The req.auth object is available as context.mcp.extra.authInfo in your tool's execute function:
execute: async (inputData, context) => {
// Access the auth data you set in middleware
const authInfo = context?.mcp?.extra?.authInfo;
if (!authInfo?.extra?.userId) {
return { error: "Authentication required" };
}
// Use the auth data
console.log("User ID:", authInfo.extra.userId);
console.log("Email:", authInfo.extra.email);
const response = await fetch("/api/data", {
headers: { Authorization: `Bearer ${authInfo.token}` },
signal: context?.mcp?.extra?.signal,
});
return response.json();
};
将 RequestContext 传递给代理Direct link to passing-requestcontext-through-to-agent
🌐 Passing RequestContext through to agent
execute: async (inputData, context) => {
// Access the auth data you set in middleware
const authInfo = context?.mcp?.extra?.authInfo;
const requestContext = context.requestContext || new RequestContext().set('someKey', authInfo)
if (!authInfo?.extra?.userId) {
return { error: "Authentication required" };
}
// Use the auth data
console.log("User ID:", authInfo.extra.userId);
console.log("Email:", authInfo.extra.email);
const agent = context?.mastra?.getAgentById('some-agent-id');
if (!agent) {
return { error: "Agent 'some-agent-id' not found" }
}
const response = await agent.generate(prompt, { requestContext })
return response.text
};
extra 对象Direct link to the-extra-object
🌐 The extra Object
完整的 context.mcp.extra 对象包含:
🌐 The full context.mcp.extra object contains:
| 属性 | 描述 |
|---|---|
authInfo | 在中间件中对 req.auth 设置的任何内容 |
sessionId | MCP 连接的会话标识符 |
signal | 用于请求取消的 AbortSignal |
sendNotification | 用于发送通知的 MCP 协议函数 |
sendRequest | 用于发送请求的 MCP 协议函数 |
完整示例Direct link to 完整示例
🌐 Complete Example
下面是一个完整的示例,展示了从中间件到工具的数据流:
🌐 Here's a complete example showing the data flow from middleware to tool:
import express from "express";
import { MCPServer } from "@mastra/mcp";
import { createTool } from "@mastra/core/tools";
import { z } from "zod";
const verifyToken = (token: string) => {
// TODO: Implement token verification
return {
userId: "123",
email: "test@test.com",
};
};
// 1. Define your tool that uses auth context
const getUserData = createTool({
id: "get-user-data",
description: "Fetches data for the authenticated user",
inputSchema: z.object({}),
execute: async (inputData, context) => {
const authInfo = context?.mcp?.extra?.authInfo;
if (!authInfo?.extra?.userId) {
return { error: "Authentication required" };
}
// Access the data you set in middleware
return {
userId: authInfo.extra.userId,
email: authInfo.extra.email,
};
},
});
// 2. Create the MCP server with your tools
const server = new MCPServer({
id: "my-server",
name: "My Server",
version: "1.0.0",
tools: { getUserData },
});
// 3. Set up Express with auth middleware
const app = express();
app.use("/mcp", (req, res, next) => {
const token = req.headers.authorization?.replace("Bearer ", "");
const user = verifyToken(token);
// This entire object becomes context.mcp.extra.authInfo
// @ts-ignore - req.auth is read by the MCP SDK
req.auth = {
token,
userId: user.userId,
email: user.email,
};
next();
});
app.all("/mcp", async (req, res) => {
const url = new URL(req.url, `http://${req.headers.host}`);
await server.startHTTP({ url, httpPath: "/mcp", req, res });
});
app.listen(3000);
相关信息Direct link to 相关信息
🌐 Related Information
- 要在 Mastra 中连接到 MCP 服务器,请参阅 MCPClient 文档。
- 关于模型上下文协议的更多信息,请参见 @modelcontextprotocol/sdk 文档。