import type * as http from 'node:http'; import type { ToolsInput, Agent } from '@mastra/core/agent'; import { MCPServerBase } from '@mastra/core/mcp'; import type { MCPServerConfig, ServerInfo, ServerDetailInfo, MCPServerHonoSSEOptions, MCPServerSSEOptions } from '@mastra/core/mcp'; import { RequestContext } from '@mastra/core/request-context'; import type { InternalCoreTool, MCPToolType } from '@mastra/core/tools'; import type { Workflow } from '@mastra/core/workflows'; import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import type { StreamableHTTPServerTransportOptions } from '@modelcontextprotocol/sdk/server/streamableHttp.js'; import type { Resource } from '@modelcontextprotocol/sdk/types.js'; import type { jsonSchemaValidator } from '@modelcontextprotocol/sdk/validation/types.js'; import type { SSEStreamingApi } from '../_types/hono/dist/types/helper/streaming/index.d.ts'; import { SSETransport } from '../_types/hono-mcp-server-sse-transport/build/index.d.ts'; import { ServerPromptActions } from './promptActions.js'; import { ServerResourceActions } from './resourceActions.js'; import type { MCPServerPrompts, MCPServerResources, ElicitationActions, AppResources } from './types.js'; /** * MCPServer exposes Mastra tools, agents, and workflows as a Model Context Protocol (MCP) server. * * This class allows any MCP client (like Cursor, Windsurf, or Claude Desktop) to connect and use your * Mastra capabilities. It supports both stdio (subprocess) and SSE (HTTP) MCP transports. * * @example * ```typescript * import { MCPServer } from '@mastra/mcp'; * import { createTool } from '@mastra/core/tools'; * import { z } from 'zod'; * * 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({ * name: 'My Weather Server', * version: '1.0.0', * tools: { weatherTool }, * }); * * await server.startStdio(); * ``` */ export declare class MCPServer extends MCPServerBase { private server; private stdioTransport?; private sseTransport?; private sseHonoTransports; private streamableHTTPTransports; private httpServerInstances; private resourceOptions?; private hasUiResources; private definedPrompts?; private promptOptions?; private jsonSchemaValidator?; private mapAuthInfoToUser?; private fga?; private subscriptions; private currentLoggingLevel; /** * Provides methods to notify clients about resource changes. * * @example * ```typescript * // Notify that a specific resource was updated * await server.resources.notifyUpdated({ uri: 'file://data.txt' }); * * // Notify that the resource list changed * await server.resources.notifyListChanged(); * ``` */ readonly resources: ServerResourceActions; /** * Provides methods to notify clients about prompt changes. * * @example * ```typescript * // Notify that the prompt list changed * await server.prompts.notifyListChanged(); * ``` */ readonly prompts: ServerPromptActions; /** * Provides methods for interactive user input collection during tool execution. * * @example * ```typescript * // Within a tool's execute function * const result = await options.elicitation.sendRequest({ * message: 'Please provide your email address', * requestedSchema: { * type: 'object', * properties: { * email: { type: 'string', format: 'email' } * }, * required: ['email'] * } * }); * ``` */ readonly elicitation: ElicitationActions; /** * Gets the stdio transport instance if the server was started using stdio. * * This is primarily for internal checks or testing purposes. * * @returns The stdio transport instance, or undefined if not using stdio transport */ getStdioTransport(): StdioServerTransport | undefined; /** * Gets the SSE transport instance if the server was started using SSE. * * This is primarily for internal checks or testing purposes. * * @returns The SSE transport instance, or undefined if not using SSE transport */ getSseTransport(): SSEServerTransport | undefined; /** * Gets the Hono SSE transport instance for a specific session. * * This is primarily for internal checks or testing purposes. * * @param sessionId - The session identifier * @returns The Hono SSE transport instance, or undefined if session not found */ getSseHonoTransport(sessionId: string): SSETransport | undefined; /** * Gets the underlying MCP SDK Server instance. * * This provides access to the low-level server instance for advanced use cases. * * @returns The Server instance from @modelcontextprotocol/sdk */ getServer(): Server; /** * Creates a new MCPServer instance. * * The server exposes tools, agents, and workflows to MCP clients. Agents are automatically * converted to tools named `ask_`, and workflows become tools named `run_`. * * @param opts - Configuration options for the server * @param opts.name - Descriptive name for the server (e.g., 'My Weather Server') * @param opts.version - Semantic version of the server (e.g., '1.0.0') * @param opts.tools - Object mapping tool names to tool definitions * @param opts.agents - Optional object mapping agent identifiers to Agent instances * @param opts.workflows - Optional object mapping workflow identifiers to Workflow instances * @param opts.resources - Optional resource configuration for exposing data and content * @param opts.prompts - Optional prompt configuration for exposing reusable templates * @param opts.id - Optional unique identifier (generated if not provided) * @param opts.description - Optional description of what the server does * @param opts.mapAuthInfoToUser - Optional mapper from MCP `extra.authInfo` to the FGA user context * * @example * ```typescript * import { MCPServer } from '@mastra/mcp'; * import { Agent } from '@mastra/core/agent'; * import { createTool } from '@mastra/core/tools'; * import { z } from 'zod'; * * const myAgent = new Agent({ * id: 'helper', * name: 'Helper Agent', * description: 'A helpful assistant', * instructions: 'You are helpful.', * model: 'openai/gpt-4o-mini', * }); * * const server = new MCPServer({ * name: 'My Server', * version: '1.0.0', * tools: { * weatherTool: createTool({ * id: 'getWeather', * description: 'Gets weather', * inputSchema: z.object({ location: z.string() }), * execute: async (inputData) => `Sunny in ${inputData.location}`, * }) * }, * agents: { myAgent }, * }); * ``` */ constructor(opts: MCPServerConfig & { resources?: MCPServerResources; prompts?: MCPServerPrompts; /** * Optional MCP App resources configuration. * * Registers `ui://` resources that serve interactive HTML UIs as defined * by the MCP Apps extension (SEP-1865). These are automatically merged * into the resource system and served alongside any user-provided resources. * * @example * ```typescript * const server = new MCPServer({ * name: 'My Server', * version: '1.0.0', * tools: { ... }, * appResources: { * 'ui://weather/dashboard': { * name: 'Weather Dashboard', * html: '...', * meta: { csp: { connectDomains: ['https://api.weather.com'] } }, * }, * }, * }); * ``` */ appResources?: AppResources; /** * Optional custom JSON Schema validator forwarded to the underlying MCP * SDK server. Use this to opt into a non-default validator * implementation. * * Pass `CfWorkerJsonSchemaValidator` (from * `@modelcontextprotocol/sdk/validation/cfworker`) when running in * Cloudflare Workers / V8 isolates: the default * `AjvJsonSchemaValidator` compiles validators with `new Function(...)`, * which workerd refuses to evaluate when a registered tool has an * `outputSchema`. * * @example * ```typescript * import { MCPServer } from '@mastra/mcp'; * import { CfWorkerJsonSchemaValidator } from '@modelcontextprotocol/sdk/validation/cfworker'; * * const server = new MCPServer({ * name: 'My Server', * version: '1.0.0', * tools: { ... }, * jsonSchemaValidator: new CfWorkerJsonSchemaValidator(), * }); * ``` */ jsonSchemaValidator?: jsonSchemaValidator; }); /** * Handle an elicitation request by sending it to the connected client. * This method sends an elicitation/create request to the client and waits for the response. * * @param request - The elicitation request containing message and schema * @param serverInstance - Optional server instance to use; defaults to main server for backward compatibility * @param options - Optional request options (timeout, signal, etc.) * @returns Promise that resolves to the client's response */ private handleElicitationRequest; /** * Reads and parses the JSON body from an HTTP request. * If the request body was already parsed by middleware (e.g., express.json()), * it uses the pre-parsed body from req.body. Otherwise, it reads from the stream. * * This allows the MCP server to work with Express apps that use express.json() * globally without requiring special route exclusions. * * @param req - The incoming HTTP request * @param options - Optional configuration * @param options.preParsedOnly - If true, only return pre-parsed body from middleware, * returning undefined if not available. This allows the caller to fall back to * their own body reading logic (e.g., SDK's getRawBody with size limits). */ private readJsonBody; /** * Merges appResources into the resource system alongside any user-provided resources. * * App resources are auto-registered as `ui://` resources with the MCP Apps MIME type. * If the user also provides a `resources` config, the two are merged — user callbacks * take precedence for overlapping URIs. */ private mergeAppResources; /** * Creates a new Server instance configured with all handlers for HTTP sessions. * Each HTTP client connection gets its own Server instance to avoid routing conflicts. */ private createServerInstance; /** * Registers all MCP handlers on a given server instance. * This allows us to create multiple server instances with identical functionality. */ private registerHandlersOnServer; /** * Registers resource-related handlers on a server instance. */ private registerResourceHandlersOnServer; /** * Registers prompt-related handlers on a server instance. */ private registerPromptHandlersOnServer; private convertAgentsToTools; private convertWorkflowsToTools; /** * Convert and validate all provided tools, logging registration status. * Also converts agents and workflows into tools. * @param tools Tool definitions * @param agentsConfig Agent definitions to be converted to tools, expected from MCPServerConfig * @param workflowsConfig Workflow definitions to be converted to tools, expected from MCPServerConfig * @returns Converted tools registry */ convertTools(tools: ToolsInput, agentsConfig?: Record, workflowsConfig?: Record): Record; /** * Starts the MCP server using standard input/output (stdio) transport. * * This is typically used when running the server as a command-line program that MCP clients * spawn as a subprocess (e.g., integration with Windsurf, Cursor, or Claude Desktop). * * @throws {MastraError} If the stdio connection fails * * @example * ```typescript * const server = new MCPServer({ * name: 'My Server', * version: '1.0.0', * tools: { weatherTool }, * }); * * await server.startStdio(); * ``` */ startStdio(): Promise; /** * Integrates the MCP server with an existing HTTP server using Server-Sent Events (SSE). * * Call this method from your web server's request handler for both the SSE and message paths. * This enables web-based MCP clients to connect to your server. * * @param options - Configuration for SSE integration * @param options.url - Parsed URL of the incoming request * @param options.ssePath - Path for establishing SSE connection (e.g., '/sse') * @param options.messagePath - Path for POSTing client messages (e.g., '/message') * @param options.req - Incoming HTTP request object * @param options.res - HTTP response object (must support .write/.end) * * @throws {MastraError} If SSE connection setup fails * * @example * ```typescript * import http from 'node: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(1234, () => { * console.log('MCP server listening on http://localhost:1234/sse'); * }); * ``` */ startSSE({ url, ssePath, messagePath, req, res }: MCPServerSSEOptions): Promise; /** * Integrates the MCP server with a Hono web framework using Server-Sent Events (SSE). * * Call this method from your Hono server's request handler for both the SSE and message paths. * This enables Hono-based web applications to expose MCP servers. * * @param options - Configuration for Hono SSE integration * @param options.url - Parsed URL of the incoming request * @param options.ssePath - Path for establishing SSE connection (e.g., '/hono-sse') * @param options.messagePath - Path for POSTing client messages (e.g., '/message') * @param options.context - Hono context object * * @throws {MastraError} If Hono SSE connection setup fails * * @example * ```typescript * import { Hono } from 'hono'; * * const app = new Hono(); * * app.all('*', async (c) => { * const url = new URL(c.req.url); * return await server.startHonoSSE({ * url, * ssePath: '/hono-sse', * messagePath: '/message', * context: c, * }); * }); * * export default app; * ``` */ startHonoSSE({ url, ssePath, messagePath, context }: MCPServerHonoSSEOptions): Promise; /** * Integrates the MCP server with an existing HTTP server using streamable HTTP transport. * * This is the recommended modern transport method, providing better session management and * reliability compared to SSE. Call this from your HTTP server's request handler. * * @param options - Configuration for HTTP integration * @param options.url - Parsed URL of the incoming request * @param options.httpPath - Path for the MCP endpoint (e.g., '/mcp') * @param options.req - Incoming HTTP request (http.IncomingMessage) * @param options.res - HTTP response object (http.ServerResponse) * @param options.options - Optional transport options * @param options.options.sessionIdGenerator - Function to generate unique session IDs (defaults to randomUUID) * @param options.options.onsessioninitialized - Callback when a new session is initialized * @param options.options.enableJsonResponse - If true, return JSON instead of SSE streaming * @param options.options.eventStore - Event store for message resumability * @param options.options.serverless - If true, run in stateless mode without session management (ideal for serverless environments) * * @throws {MastraError} If HTTP connection setup fails * * @example * ```typescript * import http from 'node:http'; * import { randomUUID } from 'node:crypto'; * * 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(), * onsessioninitialized: (sessionId) => { * console.log(`New MCP session: ${sessionId}`); * }, * }, * }); * }); * * httpServer.listen(1234); * ``` * * @example Serverless mode (Cloudflare Workers, Vercel Edge, etc.) * ```typescript * export default { * async fetch(request: Request) { * const url = new URL(request.url); * if (url.pathname === '/mcp') { * await server.startHTTP({ * url, * httpPath: '/mcp', * req: request, * res: response, * options: { serverless: true }, * }); * } * return new Response('Not found', { status: 404 }); * }, * }; * ``` */ startHTTP({ url, httpPath, req, res, options, }: { url: URL; httpPath: string; req: http.IncomingMessage; res: http.ServerResponse; options?: Partial & { serverless?: boolean; }; }): Promise; /** * Handles a stateless, serverless HTTP request without session management. * * This method bypasses all session/transport state and handles each request independently. * For serverless environments (Cloudflare Workers, Vercel Edge, etc.) where * persistent connections and session state cannot be maintained across requests. * * Each request gets a fresh transport and server instance that are discarded after the response. * * @param req - Incoming HTTP request * @param res - HTTP response object * @private */ private handleServerlessRequest; /** * Establishes the SSE connection for the MCP server. * * This is a lower-level method called internally by `startSSE()`. In most cases, * you should use `startSSE()` instead which handles both connection establishment * and message routing. * * @param params - Connection parameters * @param params.messagePath - Path for POST requests from the client * @param params.res - HTTP response object for the SSE stream * @throws {MastraError} If SSE connection establishment fails * * @example * ```typescript * // Usually called internally by startSSE() * await server.connectSSE({ * messagePath: '/message', * res: response * }); * ``` */ connectSSE({ messagePath, res, }: { messagePath: string; res: http.ServerResponse; }): Promise; /** * Establishes the Hono SSE connection for the MCP server. * * This is a lower-level method called internally by `startHonoSSE()`. In most cases, * you should use `startHonoSSE()` instead which handles both connection establishment * and message routing. * * @param params - Connection parameters * @param params.messagePath - Path for POST requests from the client * @param params.stream - Hono SSE streaming API object * @throws {MastraError} If Hono SSE connection establishment fails * * @example * ```typescript * // Usually called internally by startHonoSSE() * await server.connectHonoSSE({ * messagePath: '/message', * stream: sseStream * }); * ``` */ connectHonoSSE({ messagePath, stream }: { messagePath: string; stream: SSEStreamingApi; }): Promise; /** * Closes the MCP server and releases all resources. * * This method cleanly shuts down all active transports (stdio, SSE, HTTP) and their * associated connections. Call this when your application is shutting down. * * @throws {MastraError} If closing the server fails * * @example * ```typescript * // Graceful shutdown * process.on('SIGTERM', async () => { * await server.close(); * process.exit(0); * }); * ``` */ close(): Promise; /** * Gets basic information about the server. * * Returns metadata including server ID, name, description, repository, and version details. * This information conforms to the MCP Server schema. * * @returns Server information object * * @example * ```typescript * const info = server.getServerInfo(); * console.log(`${info.name} v${info.version_detail.version}`); * // Output: My Weather Server v1.0.0 * ``` */ getServerInfo(): ServerInfo; /** * Gets detailed information about the server including packaging and deployment metadata. * * Returns extended server information with package details, remotes, and deployment configurations. * This information conforms to the MCP ServerDetail schema. * * @returns Detailed server information object * * @example * ```typescript * const detail = server.getServerDetail(); * console.log(detail.package_canonical); // 'npm' * console.log(detail.packages); // Package installation info * ``` */ getServerDetail(): ServerDetailInfo; private convertSchema; /** * Gets a list of all tools provided by this MCP server with their schemas. * * Returns information about all registered tools including explicit tools, agent-derived tools, * and workflow-derived tools. Includes input/output schemas and tool types. * * @returns Object containing array of tool information * * @example * ```typescript * const toolList = server.getToolListInfo(); * toolList.tools.forEach(tool => { * console.log(`${tool.name}: ${tool.description}`); * console.log(`Type: ${tool.toolType || 'tool'}`); * }); * ``` */ getToolListInfo(requestContext?: RequestContext): { tools: Array<{ name: string; description?: string; inputSchema: any; outputSchema?: any; toolType?: MCPToolType; _meta?: Record; }>; } | Promise<{ tools: Array<{ name: string; description?: string; inputSchema: any; outputSchema?: any; toolType?: MCPToolType; _meta?: Record; }>; }>; /** * Gets information for a specific tool provided by this MCP server. * * Returns detailed information about a single tool including its name, description, schemas, and type. * Returns undefined if the tool is not found. * * @param toolId - The ID/name of the tool to retrieve * @returns Tool information object or undefined if not found * * @example * ```typescript * const toolInfo = server.getToolInfo('getWeather'); * if (toolInfo) { * console.log(toolInfo.description); * console.log(toolInfo.inputSchema); * } * ``` */ getToolInfo(toolId: string): { name: string; description?: string; inputSchema: any; outputSchema?: any; toolType?: MCPToolType; _meta?: Record; } | undefined; private createProxiedRequestContext; private resolveMappedFGAUser; private getAuthorizedConvertedToolEntries; private enforceToolExecutionFGA; private resolveToolFGAParams; /** * Executes a specific tool provided by this MCP server. * * This method validates the tool arguments against the input schema and executes the tool. * If validation fails, returns an error object instead of throwing. * * @param toolId - The ID/name of the tool to execute * @param args - The arguments to pass to the tool's execute function * @param executionContext - Optional context including messages and toolCallId * @returns Promise resolving to the tool execution result * @throws {MastraError} If the tool is not found or execution fails * * @example * ```typescript * const result = await server.executeTool( * 'getWeather', * { location: 'London' }, * { toolCallId: 'call_123' } * ); * console.log(result); * ``` */ executeTool(toolId: string, args: any, executionContext?: { messages?: any[]; toolCallId?: string; requestContext?: RequestContext; }): Promise; /** * Reads the content of a resource by URI. * * Used by the Studio API to proxy `ui://` resource reads for MCP Apps rendering. * * @param uri - The resource URI to read (e.g. `ui://weather/dashboard`) * @returns Promise resolving to the resource content */ readResource(uri: string): Promise<{ contents: Array<{ uri: string; text?: string; blob?: string; }>; }>; /** * Lists all resources available on this MCP server. * * Used by the Studio API to discover `ui://` resources for MCP Apps. * * @returns Promise resolving to the list of resources */ listResources(): Promise<{ resources: Resource[]; }>; } //# sourceMappingURL=server.d.ts.map