> Discover all available pages from the documentation index: https://mastra.ai/llms.txt # MCP overview Mastra supports the [Model Context Protocol (MCP)](https://modelcontextprotocol.io/introduction), an open standard for connecting AI agents to external tools and resources. Use [`MCPClient`](https://mastra.ai/reference/tools/mcp-client) to connect to MCP servers. Use [`MCPServer`](https://mastra.ai/reference/tools/mcp-server) to expose Mastra agents, tools, workflows, prompts, and resources to other MCP-compatible systems. ## Connect to MCP servers Install the MCP package: **npm**: ```bash npm install @mastra/mcp@latest ``` **pnpm**: ```bash pnpm add @mastra/mcp@latest ``` **Yarn**: ```bash yarn add @mastra/mcp@latest ``` **Bun**: ```bash bun add @mastra/mcp@latest ``` Configure each server with a local command or remote URL: ```typescript import { MCPClient } from '@mastra/mcp' export const mcpClient = new MCPClient({ id: 'my-mcp-client', servers: { wikipedia: { command: 'npx', args: ['-y', 'wikipedia-mcp'], }, weather: { url: new URL('https://weather.example.com/mcp'), requestInit: { headers: { Authorization: `Bearer ${process.env.WEATHER_API_KEY}`, }, }, }, }, }) ``` > **Authentication:** For OAuth-protected servers, use `authenticate()` to complete the browser-based authorization flow. Visit [OAuth authentication](https://mastra.ai/reference/tools/mcp-client) for configuration details. Pass tools from the configured servers to an agent: ```typescript import { Agent } from '@mastra/core/agent' import { mcpClient } from '../mcp/client' export const assistant = new Agent({ id: 'assistant', name: 'Assistant', instructions: ` Use the available MCP tools to answer questions. Include the source of any information you retrieve. `, model: 'openai/gpt-5.6-sol', tools: await mcpClient.listTools(), }) ``` ### Static and runtime tools Choose how to load tools based on whether the server configuration changes between requests: | | Static tools | Runtime toolsets | | ----------- | ---------------------------------- | ---------------------------------------- | | Method | `await mcpClient.listTools()` | `await mcpClient.listToolsets()` | | Use case | Shared, fixed configuration | Per-user or per-request configuration | | Credentials | Shared by all requests | Can vary between requests | | Agent API | `tools` in the `Agent` constructor | `toolsets` in `generate()` or `stream()` | The preceding agent example uses static tools. For runtime credentials, create a client for the request and pass its toolsets when calling the agent: ```typescript import { MCPClient } from '@mastra/mcp' import { mastra } from './mastra' export async function handleRequest(prompt: string, apiKey: string) { const userMcpClient = new MCPClient({ servers: { weather: { url: new URL('https://weather.example.com/mcp'), requestInit: { headers: { Authorization: `Bearer ${apiKey}` }, }, }, }, }) const agent = mastra.getAgent('assistant') const response = await agent.generate(prompt, { toolsets: await userMcpClient.listToolsets(), }) await userMcpClient.disconnect() return response.text } ``` Visit [`listTools()`](https://mastra.ai/reference/tools/mcp-client) and [`listToolsets()`](https://mastra.ai/reference/tools/mcp-client) for their full APIs. ### Tool approval Set `requireToolApproval` on a server to require approval for all its tools: ```typescript const mcpClient = new MCPClient({ servers: { github: { url: new URL('https://github.example.com/mcp'), requireToolApproval: true, }, }, }) ``` You can also provide a function that decides based on the tool name, arguments, or annotations: ```typescript requireToolApproval: ({ toolName }) => toolName.startsWith('delete_') ``` Treat tool annotations from servers you don't control as untrusted hints. Visit [tool approval](https://mastra.ai/reference/tools/mcp-client) for the callback context and security guidance. ### Security MCP servers run code and return content on your agent's behalf, so configure them with the same care as any other external dependency: - **Stdio subprocess environment**: subprocesses inherit only the MCP SDK's curated environment whitelist (for example `PATH` and `HOME` on POSIX), not the full parent environment. Set `inheritDefaultEnv: false` on a server to pass only the variables you list in `env`. - **Outbound host restriction**: when HTTP server URLs come from untrusted configuration, set `allowedHosts` to restrict which hosts the client will contact. On the default fetch path this also blocks redirect hops before they're sent; a custom `fetch` gets its final response URL validated after the request runs, so it must enforce redirect policy itself when preventing outbound contact is required. - **Tool response trust**: tool results are untrusted model input. Use [input and output processors](https://mastra.ai/docs/agents/processors) to inspect or sanitize content before it reaches the model, and `requireToolApproval` to gate sensitive tools. Visit the [MCPClient security reference](https://mastra.ai/reference/tools/mcp-client) for enforcement details of each option. ### MCP registries Registries provide hosted or packaged MCP servers. The client configuration above works with registry endpoints and commands. | Registry | Connection | Notes | | ----------------------------------------------- | ----------------- | --------------------------------------------- | | [Klavis AI](https://klavis.ai) | Hosted HTTP | Enterprise authentication and managed servers | | [mcp.run](https://www.mcp.run/) | Signed SSE URL | Treat the profile URL as a secret | | [Composio](https://mcp.composio.dev) | Hosted SSE URL | URLs are often tied to one user account | | [Smithery](https://smithery.ai) | CLI or hosted URL | Run local packages through `npx` | | [Apify](https://mcp.apify.com) | Hosted HTTP | Authenticate with an Apify API token | | [Ampersand](https://docs.withampersand.com/mcp) | SSE or stdio | Connect to configured SaaS integrations | Store signed URLs, API keys, and tokens in environment variables. Follow the registry's documentation to obtain the endpoint, command, and credentials for each server. ## Expose a Mastra MCP server Create an `MCPServer` to expose Mastra primitives to external MCP clients: ```typescript import { MCPServer } from '@mastra/mcp' import { assistant } from '../agents/assistant' import { weatherTool } from '../tools/weather' import { weatherWorkflow } from '../workflows/weather' export const mcpServer = new MCPServer({ id: 'my-mcp-server', name: 'My MCP Server', version: '1.0.0', agents: { assistant }, tools: { weatherTool }, workflows: { weatherWorkflow }, }) ``` Register the server on the main `Mastra` instance: ```typescript import { Mastra } from '@mastra/core/mastra' import { mcpServer } from './mcp/server' export const mastra = new Mastra({ mcpServers: { mcpServer }, }) ``` > **Authentication:** Protect HTTP MCP servers with OAuth middleware. Visit [OAuth protection](https://mastra.ai/reference/tools/mcp-server) for setup instructions. Visit the [`MCPServer` reference](https://mastra.ai/reference/tools/mcp-server) for prompts, resources, transports, and other server options. ### Publish a stdio server package Package a server that uses the standard input/output (stdio) transport when you want clients to run it locally through a command such as `npx`. Create a separate executable entry point that starts the server: ```typescript #!/usr/bin/env node import { mcpServer } from './server' mcpServer.startStdio().catch(error => { console.error('Failed to start MCP server:', error) process.exit(1) }) ``` Build the entry point as an executable Node.js file, then point the package's `bin` field to that output. Include the built file in the published package and keep the shebang as its first line: ```json { "bin": { "my-mcp-server": "dist/stdio.js" }, "files": ["dist"] } ``` After publishing the package, configure clients to run it by package name: ```typescript import { MCPClient } from '@mastra/mcp' const mcpClient = new MCPClient({ servers: { myServer: { command: 'npx', args: ['-y', '@your-org/my-mcp-server@1.0.0'], }, }, }) ``` Visit the [npm package publishing documentation](https://docs.npmjs.com/creating-and-publishing-scoped-public-packages) for package naming, authentication, and publication commands. ## Build MCP Apps The [MCP Apps extension](https://github.com/modelcontextprotocol/ext-apps) lets MCP tools serve interactive HTML interfaces through `ui://` resources. Mastra Studio renders these apps in sandboxed iframes on tool pages and in agent chat. Use an MCP App when a tool result benefits from interaction, such as a form, calculator, color picker, or data visualization. ### Define an app resource Return a short `content` summary for the model and place UI data in `structuredContent`. Link the tool to its app by setting `_meta.ui.resourceUri` to the same `ui://` URI used in `appResources`: ```typescript import { MCPServer } from '@mastra/mcp' import { createTool } from '@mastra/core/tools' import { z } from 'zod' export const calculatorTool = createTool({ id: 'calculatorWithUI', description: 'Calculate the sum of two numbers', inputSchema: z.object({ num1: z.number(), num2: z.number(), }), execute: async ({ num1, num2 }) => ({ content: [{ type: 'text', text: 'The result is displayed in the calculator app.' }], structuredContent: { result: num1 + num2 }, }), }) calculatorTool._meta = { ui: { resourceUri: 'ui://calculator/main' }, } export const calculatorMcpServer = new MCPServer({ id: 'calculator-app-server', name: 'Calculator App Server', version: '1.0.0', tools: { calculatorTool }, appResources: { 'ui://calculator/main': { name: 'Calculator', htmlPath: './src/mastra/mcp/calculator.html', }, }, }) ``` The model sees `content`, while the app receives `structuredContent`. Visit [`appResources`](https://mastra.ai/reference/tools/mcp-server) for inline HTML, file paths, metadata, and content security policy options. ### Connect the app to Studio Use the `App` class from `@modelcontextprotocol/ext-apps` inside the HTML resource. Register event handlers before calling `connect()`: ```html

Waiting for input

``` The guest-side APIs serve different parts of the interaction: | API | Purpose | | ---------------------- | ----------------------------------------------------- | | `app.ontoolinput` | Receive the arguments from the host tool call | | `app.callServerTool()` | Call an MCP tool from inside the iframe | | `app.sendMessage()` | Add a user message to chat and start a new model turn | | `app.connect()` | Connect to the host after registering event handlers | The interaction follows this sequence: 1. The agent calls the tool. 2. The tool returns model-facing `content` and UI-facing `structuredContent`. 3. Studio renders the associated app resource. 4. The app receives tool input and can call server tools or send chat messages. Visit the external [`App` API reference](https://apps.extensions.modelcontextprotocol.io/api/classes/app.App.html) for all guest-side methods and lifecycle hooks. ### Register MCP Apps For a local app, pass the tool to an agent and register its MCP server on `Mastra`: ```typescript import { Agent } from '@mastra/core/agent' import { Mastra } from '@mastra/core/mastra' import { calculatorMcpServer, calculatorTool } from './mcp/calculator' const calculatorAgent = new Agent({ id: 'calculator-agent', name: 'Calculator Agent', instructions: 'Use the calculator tool for arithmetic.', model: 'openai/gpt-5-mini', tools: { calculatorTool }, }) export const mastra = new Mastra({ agents: { calculatorAgent }, mcpServers: { calculatorMcpServer }, }) ``` For an external MCP server that implements MCP Apps, load its tools with `MCPClient.listTools()` and register its proxy so Studio can resolve the remote app resources: ```typescript import { Agent } from '@mastra/core/agent' import { Mastra } from '@mastra/core/mastra' import { mcpClient } from './mcp/client' const tools = await mcpClient.listTools() const mcpServers = mcpClient.toMCPServerProxies() const agent = new Agent({ id: 'remote-app-agent', name: 'Remote App Agent', instructions: 'Use the available remote tools.', model: 'openai/gpt-5-mini', tools, }) export const mastra = new Mastra({ agents: { agent }, mcpServers, }) ``` Tools loaded through `listTools()` include a `serverId` in `_meta.ui`, allowing Studio to resolve each app resource without scanning every server. Visit [`toMCPServerProxies()`](https://mastra.ai/reference/tools/mcp-client) for proxy configuration details. ### Sandbox security Mastra Studio uses [`@mcp-ui/client`](https://www.npmjs.com/package/@mcp-ui/client) to load app HTML through a sandbox proxy and communicate over JSON-RPC with `postMessage`. App iframes allow scripts, forms, and popups. They can't access the parent page's DOM, cookies, or storage. The host controls all communication with the guest app. ## Next steps - [Use tools with agents](https://mastra.ai/docs/agents/using-tools) - [`MCPClient` reference](https://mastra.ai/reference/tools/mcp-client) - [`MCPServer` reference](https://mastra.ai/reference/tools/mcp-server) - [MCP Apps extension specification](https://github.com/modelcontextprotocol/ext-apps)