{"_id":"@caleblawson/mcp","name":"@caleblawson/mcp","dist-tags":{"latest":"0.10.4"},"versions":{"0.10.4":{"name":"@caleblawson/mcp","version":"0.10.4","description":"Model Context Protocol (MCP) client implementation for Mastra, providing seamless integration with MCP-compatible AI models and tools.","type":"module","main":"dist/index.js","types":"dist/index.d.ts","exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}},"./package.json":"./package.json"},"keywords":[],"author":"","license":"Elastic-2.0","dependencies":{"@modelcontextprotocol/sdk":"^1.12.1","date-fns":"^4.1.0","exit-hook":"^4.0.0","fast-deep-equal":"^3.1.3","hono":"^4.7.11","uuid":"^11.1.0","zod-from-json-schema":"^0.0.5"},"peerDependencies":{"@mastra/core":"^0.10.2-alpha.0","zod":"^3.0.0"},"devDependencies":{"@ai-sdk/anthropic":"^1.2.12","@ai-sdk/openai":"^1.3.22","@hono/node-server":"^1.14.4","@mendable/firecrawl-js":"^1.25.5","@microsoft/api-extractor":"^7.52.8","@types/node":"^20.19.0","ai":"4.3.16","eslint":"^9.28.0","hono-mcp-server-sse-transport":"0.0.6","tsup":"^8.5.0","tsx":"^4.19.4","typescript":"^5.8.3","vitest":"^3.2.3","zod":"^3.25.57","zod-to-json-schema":"^3.24.5","@internal/lint":"0.0.13","@mastra/core":"npm:@caleblawson/core@0.10.7-alpha.0"},"scripts":{"build":"tsup src/index.ts --format esm,cjs --experimental-dts --clean --treeshake=smallest --splitting","build:watch":"pnpm build --watch","test:integration":"cd integration-tests && pnpm test:mcp","test":"pnpm test:integration && vitest run","lint":"eslint ."},"gitHead":"c31e90130a5c9765c23f688ecea70adc6164543d","_id":"@caleblawson/mcp@0.10.4","_integrity":"sha512-8u+Afg6ywieRs/7yP32qfAbAvJBIgOMojHHILGfhuWWTG1FrAjblqUxg6lJlwB+7qIMY5c3RFecuJI8i/lYIXA==","_resolved":"C:\\Users\\caleb\\AppData\\Local\\Temp\\0599bb3c121700dc75418ce628700482\\caleblawson-mcp-0.10.4.tgz","_from":"file:caleblawson-mcp-0.10.4.tgz","_nodeVersion":"21.2.0","_npmVersion":"10.2.3","dist":{"integrity":"sha512-8u+Afg6ywieRs/7yP32qfAbAvJBIgOMojHHILGfhuWWTG1FrAjblqUxg6lJlwB+7qIMY5c3RFecuJI8i/lYIXA==","shasum":"be8c6221390103ae17bf858b428f3fe0eef6a315","tarball":"https://registry.npmjs.org/@caleblawson/mcp/-/mcp-0.10.4.tgz","fileCount":66,"unpackedSize":569491,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCICV33xtRve26mVXE6Tl/e0/frdMhWaxK/Bad/9M+SAR9AiEArRPSZY29dMLR57fy0OyDrniUgB5Dv0WViNfMeFtx1/s="}]},"_npmUser":{"name":"caleblawson","email":"caleb.lawson@dynapt.com","actor":{"name":"caleblawson","email":"caleb.lawson@dynapt.com","type":"user"}},"directories":{},"maintainers":[{"name":"caleblawson","email":"caleb.lawson@dynapt.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/mcp_0.10.4_1750378235448_0.5530705959423039"},"_hasShrinkwrap":false}},"time":{"created":"2025-06-20T00:10:35.345Z","0.10.4":"2025-06-20T00:10:35.645Z","modified":"2025-06-20T00:10:35.921Z"},"maintainers":[{"name":"caleblawson","email":"caleb.lawson@dynapt.com"}],"description":"Model Context Protocol (MCP) client implementation for Mastra, providing seamless integration with MCP-compatible AI models and tools.","keywords":[],"license":"Elastic-2.0","readme":"# @mastra/mcp\r\n\r\nModel Context Protocol (MCP) client implementation for Mastra, providing seamless integration with MCP-compatible AI models and tools.\r\n\r\n## Installation\r\n\r\n```bash\r\nnpm install @mastra/mcp@latest\r\n```\r\n\r\n## Overview\r\n\r\nThe `@mastra/mcp` package provides a client implementation for the Model Context Protocol (MCP), enabling Mastra to communicate with MCP-compatible AI models and tools. It wraps the official `@modelcontextprotocol/sdk` and provides Mastra-specific functionality.\r\n\r\nThe client automatically detects the transport type based on your server configuration:\r\n\r\n- If you provide a `command`, it uses the Stdio transport.\r\n- If you provide a `url`, it first attempts to use the Streamable HTTP transport (protocol version 2025-03-26) and falls back to the legacy SSE transport (protocol version 2024-11-05) if the initial connection fails.\r\n\r\n## Usage\r\n\r\n```typescript\r\nimport { MCPClient } from '@mastra/mcp';\r\n\r\n// Create a client with a Stdio server\r\nconst stdioClient = new MCPClient({\r\n  servers: {\r\n    myStdioClient: {\r\n      command: 'your-mcp-server-command',\r\n      args: ['--your', 'args'],\r\n      env: { API_KEY: 'your-api-key' }, // optional environment variables\r\n      capabilities: {}, // optional ClientCapabilities\r\n      timeout: 60000, // optional timeout for tool calls in milliseconds\r\n    },\r\n  },\r\n});\r\n\r\n// Create a client with an HTTP server (tries Streamable HTTP, falls back to SSE)\r\nconst httpClient = new MCPClient({\r\n  servers: {\r\n    myHttpClient: {\r\n      url: new URL('https://your-mcp-server.com/mcp'), // Use the base URL for Streamable HTTP\r\n      requestInit: {\r\n        // Optional fetch request configuration\r\n        headers: { Authorization: 'Bearer your-token' },\r\n      },\r\n      // eventSourceInit is only needed for custom headers with the legacy SSE fallback\r\n      eventSourceInit: {\r\n        /* ... */\r\n      },\r\n    },\r\n  },\r\n});\r\n\r\n// Or create a client with SSE server\r\nconst sseClient = new MCPClient({\r\n  servers: {\r\n    mySseClient: {\r\n      url: new URL('https://your-mcp-server.com/sse'),\r\n      requestInit: {\r\n        headers: { Authorization: 'Bearer your-token' },\r\n      },\r\n      eventSourceInit: {\r\n        fetch(input: Request | URL | string, init?: RequestInit) {\r\n          const headers = new Headers(init?.headers || {});\r\n          headers.set('Authorization', 'Bearer your-token');\r\n          return fetch(input, {\r\n            ...init,\r\n            headers,\r\n          });\r\n        },\r\n      },\r\n      timeout: 60000, // optional timeout for tool calls in milliseconds\r\n    },\r\n  },\r\n});\r\n\r\n// Connect to the MCP server (using one of the clients above)\r\nawait httpClient.connect();\r\n\r\n// List available resources\r\nconst resources = await httpClient.resources();\r\n\r\n// Get available tools\r\nconst tools = await httpClient.tools();\r\n\r\n// Disconnect when done\r\nawait httpClient.disconnect();\r\n```\r\n\r\n## Managing Multiple MCP Servers\r\n\r\nFor applications that need to interact with multiple MCP servers, the `MCPClient` class provides a convenient way to manage multiple server connections and their tools. It also uses the automatic transport detection based on the `server` configuration:\r\n\r\n```typescript\r\nimport { MCPClient } from '@mastra/mcp';\r\n\r\nconst mcp = new MCPClient({\r\n  servers: {\r\n    // Stdio-based server\r\n    stockPrice: {\r\n      command: 'npx',\r\n      args: ['tsx', 'stock-price.ts'],\r\n      env: {\r\n        API_KEY: 'your-api-key',\r\n      },\r\n    },\r\n    // HTTP-based server (tries Streamable HTTP, falls back to SSE)\r\n    weather: {\r\n      url: new URL('http://localhost:8080/mcp'), // Use the base URL for Streamable HTTP\r\n      requestInit: {\r\n        // Optional fetch request configuration\r\n        headers: { 'X-Api-Key': 'weather-key' },\r\n      },\r\n    },\r\n  },\r\n});\r\n\r\n// Get all tools from all configured servers namespaced with the server name\r\nconst tools = await mcp.getTools();\r\n\r\n// Get tools grouped into a toolset object per-server\r\nconst toolsets = await mcp.getToolsets();\r\n```\r\n\r\n## Logging\r\n\r\nThe MCP client provides per-server logging capabilities, allowing you to monitor interactions with each MCP server separately:\r\n\r\n```typescript\r\nimport { MCPClient, LogMessage, LoggingLevel } from '@mastra/mcp';\r\n\r\n// Define a custom log handler\r\nconst weatherLogger = (logMessage: LogMessage) => {\r\n  console.log(`[${logMessage.level}] ${logMessage.serverName}: ${logMessage.message}`);\r\n\r\n  // Log data contains valuable information\r\n  console.log('Details:', logMessage.details);\r\n  console.log('Timestamp:', logMessage.timestamp);\r\n};\r\n\r\n// Initialize MCP configuration with server-specific loggers\r\nconst mcp = new MCPClient({\r\n  servers: {\r\n    weatherService: {\r\n      command: 'npx',\r\n      args: ['tsx', 'weather-mcp.ts'],\r\n      // Attach the logger to this specific server\r\n      logger: weatherLogger, // Use 'logger' key\r\n    },\r\n\r\n    stockPriceService: {\r\n      command: 'npx',\r\n      args: ['tsx', 'stock-mcp.ts'],\r\n      // Different logger for this service\r\n      logger: logMessage => {\r\n        // Use 'logger' key\r\n        // Just log errors and critical events for this service\r\n        if (['error', 'critical', 'alert', 'emergency'].includes(logMessage.level)) {\r\n          console.error(`Stock service ${logMessage.level}: ${logMessage.message}`);\r\n        }\r\n      },\r\n    },\r\n  },\r\n});\r\n```\r\n\r\n### Log Message Structure\r\n\r\nEach log message contains the following information:\r\n\r\n```typescript\r\ninterface LogMessage {\r\n  level: LoggingLevel; // MCP SDK standard log levels\r\n  message: string;\r\n  timestamp: Date;\r\n  serverName: string;\r\n  details?: Record<string, any>;\r\n}\r\n```\r\n\r\nThe `LoggingLevel` type is directly imported from the MCP SDK, ensuring compatibility with all standard MCP log levels: `'debug' | 'info' | 'notice' | 'warning' | 'error' | 'critical' | 'alert' | 'emergency'`.\r\n\r\n### Creating Reusable Loggers\r\n\r\nYou can create reusable logger factories for common patterns:\r\n\r\n```typescript\r\nimport fs from 'node:fs';\r\n\r\n// File logger factory with color coded output for different severity levels\r\nconst createFileLogger = (filePath: string) => {\r\n  return (logMessage: LogMessage) => {\r\n    // Format the message based on level\r\n    const prefix =\r\n      logMessage.level === 'emergency' ? '!!! EMERGENCY !!! ' : logMessage.level === 'alert' ? '! ALERT ! ' : '';\r\n\r\n    // Write to file with timestamp, level, etc.\r\n    fs.appendFileSync(\r\n      filePath,\r\n      `[${logMessage.timestamp.toISOString()}] [${logMessage.level.toUpperCase()}] ${prefix}${logMessage.message}\\n`,\r\n    );\r\n  };\r\n};\r\n\r\n// Use the factory in configuration\r\nconst mcp = new MCPClient({\r\n  servers: {\r\n    weatherService: {\r\n      command: 'npx',\r\n      args: ['tsx', 'weather-mcp.ts'],\r\n      logger: createFileLogger('./logs/weather.log'), // Use 'logger' key\r\n    },\r\n  },\r\n});\r\n```\r\n\r\nSee the `examples/server-logging.ts` file for comprehensive examples of various logging strategies.\r\n\r\n### Tools vs Toolsets\r\n\r\nThe MCPClient class provides two ways to access MCP tools:\r\n\r\n#### Tools (`getTools()`)\r\n\r\nUse this when:\r\n\r\n- You have a single MCP connection\r\n- The tools are used by a single user/context (CLI tools, automation scripts, etc)\r\n- Tool configuration (API keys, credentials) remains constant\r\n- You want to initialize an Agent with a fixed set of tools\r\n\r\n```typescript\r\nimport { Agent } from '@mastra/core/agent';\r\nimport { openai } from '@ai-sdk/openai';\r\n\r\nconst agent = new Agent({\r\n  name: 'CLI Assistant',\r\n  instructions: 'You help users with CLI tasks',\r\n  model: openai('gpt-4'),\r\n  tools: await mcp.getTools(), // Tools are fixed at agent creation\r\n});\r\n```\r\n\r\n#### Toolsets (`getToolsets()`)\r\n\r\nUse this when:\r\n\r\n- You need per-request tool configuration\r\n- Tools need different credentials per user\r\n- Running in a multi-user environment (web app, API, etc)\r\n- Tool configuration needs to change dynamically\r\n\r\n```typescript\r\nimport { MCPClient } from '@mastra/mcp';\r\nimport { Agent } from '@mastra/core/agent';\r\nimport { openai } from '@ai-sdk/openai';\r\n\r\n// Configure MCP servers with user-specific settings before getting toolsets\r\nconst mcp = new MCPClient({\r\n  servers: {\r\n    stockPrice: {\r\n      command: 'npx',\r\n      args: ['tsx', 'weather-mcp.ts'],\r\n      env: {\r\n        // These would be different per user\r\n        API_KEY: 'user-1-api-key',\r\n      },\r\n    },\r\n    weather: {\r\n      url: new URL('http://localhost:8080/mcp'), // Use the base URL for Streamable HTTP\r\n      requestInit: {\r\n        headers: {\r\n          // These would be different per user\r\n          Authorization: 'Bearer user-1-token',\r\n        },\r\n      },\r\n      // eventSourceInit is only needed for custom headers with the legacy SSE fallback\r\n      eventSourceInit: {\r\n        /* ... */\r\n      },\r\n    },\r\n  },\r\n});\r\n\r\n// Get the current toolsets configured for this user\r\nconst toolsets = await mcp.getToolsets();\r\n\r\n// Use the agent with user-specific tool configurations\r\nconst response = await agent.generate('What is the weather in London?', {\r\n  toolsets,\r\n});\r\n\r\nconsole.log(response.text);\r\n```\r\n\r\nThe `MCPClient` class automatically:\r\n\r\n- Manages connections to multiple MCP servers\r\n- Namespaces tools to prevent naming conflicts\r\n- Handles connection lifecycle and cleanup\r\n- Provides both flat and grouped access to tools\r\n\r\n## Accessing MCP Resources\r\n\r\nMCP servers can expose resources - data or content that can be retrieved and used in your application. The `MCPClient` class provides methods to access these resources across multiple servers:\r\n\r\n```typescript\r\nimport { MCPClient } from '@mastra/mcp';\r\n\r\nconst mcp = new MCPClient({\r\n  servers: {\r\n    weather: {\r\n      url: new URL('http://localhost:8080/mcp'),\r\n    },\r\n    dataService: {\r\n      command: 'npx',\r\n      args: ['tsx', 'data-service.ts'],\r\n    },\r\n  },\r\n});\r\n\r\n// Get resources from all connected MCP servers\r\nconst resources = await mcp.getResources();\r\n\r\n// Resources are grouped by server name\r\nconsole.log(Object.keys(resources)); // ['weather', 'dataService']\r\n\r\n// Each server entry contains an array of resources\r\nif (resources.weather) {\r\n  // Access resources from the weather server\r\n  const weatherResources = resources.weather;\r\n\r\n  // Each resource has uri, name, description, and mimeType\r\n  weatherResources.forEach(resource => {\r\n    console.log(`${resource.uri}: ${resource.name} (${resource.mimeType})`);\r\n  });\r\n\r\n  // Find a specific resource by URI\r\n  const forecast = weatherResources.find(r => r.uri === 'weather://forecast');\r\n  if (forecast) {\r\n    console.log(`Found forecast resource: ${forecast.description}`);\r\n  }\r\n}\r\n```\r\n\r\nThe `getResources()` method handles errors gracefully - if a server fails or doesn't support resources, it will be omitted from the results without causing the entire operation to fail.\r\n\r\n## Prompts\r\n\r\nMCP servers can also expose prompts, which represent structured message templates or conversational context for agents.\r\n\r\n### Listing Prompts\r\n\r\n```typescript\r\nconst prompts = await mcp.prompts.list();\r\nconsole.log(prompts.weather); // [ { name: 'current', ... }, ... ]\r\n```\r\n\r\n### Getting a Prompt and Messages\r\n\r\n```typescript\r\nconst { prompt, messages } = await mcp.prompts.get({ serverName: 'weather', name: 'current' });\r\nconsole.log(prompt); // { name: 'current', version: 'v1', ... }\r\nconsole.log(messages); // [ { role: 'assistant', content: { type: 'text', text: '...' } }, ... ]\r\n```\r\n\r\n### Handling Prompt List Change Notifications\r\n\r\n```typescript\r\nmcp.prompts.onListChanged({\r\n  serverName: 'weather',\r\n  handler: () => {\r\n    // Refresh prompt list or update UI\r\n  },\r\n});\r\n```\r\n\r\nPrompt notifications are delivered via SSE or compatible transports. Register handlers before expecting notifications.\r\n\r\n## SSE Authentication and Headers (Legacy Fallback)\r\n\r\nWhen the client falls back to using the legacy SSE (Server-Sent Events) transport and you need to include authentication or custom headers, you need to configure headers in a specific way. The standard `requestInit` headers won't work alone because SSE connections using the browser's `EventSource` API don't support custom headers directly.\r\n\r\nThe `eventSourceInit` configuration allows you to customize the underlying fetch request used for the SSE connection, ensuring your authentication headers are properly included.\r\n\r\nTo properly include authentication headers or other custom headers in SSE connections when using the legacy fallback, you need to use both `requestInit` and `eventSourceInit`:\r\n\r\n```typescript\r\nconst sseClient = new MCPClient({\r\n  servers: {\r\n    authenticatedSseClient: {\r\n      url: new URL('https://your-mcp-server.com/sse'), // Note the typical /sse path for legacy servers\r\n      // requestInit alone isn't enough for SSE connections\r\n      requestInit: {\r\n        headers: { Authorization: 'Bearer your-token' },\r\n      },\r\n      // eventSourceInit is required to include headers in the SSE connection\r\n      eventSourceInit: {\r\n        fetch(input: Request | URL | string, init?: RequestInit) {\r\n          const headers = new Headers(init?.headers || {});\r\n          headers.set('Authorization', 'Bearer your-token');\r\n          return fetch(input, {\r\n            ...init,\r\n            headers,\r\n          });\r\n        },\r\n      },\r\n    },\r\n  },\r\n});\r\n```\r\n\r\nThis configuration ensures that:\r\n\r\n1. The authentication headers are properly included in the SSE connection request\r\n2. The connection can be established with the required credentials\r\n3. Subsequent messages can be received through the authenticated connection\r\n\r\n```typescript\r\nconst sseClient = new MastraMCPClient({\r\n  name: 'authenticated-sse-client',\r\n  server: {\r\n    url: new URL('https://your-mcp-server.com/sse'), // Note the typical /sse path for legacy servers\r\n    // requestInit alone isn't enough for SSE connections\r\n    requestInit: {\r\n      headers: { Authorization: 'Bearer your-token' },\r\n    },\r\n    // eventSourceInit is required to include headers in the SSE connection\r\n    eventSourceInit: {\r\n      fetch(input: Request | URL | string, init?: RequestInit) {\r\n        const headers = new Headers(init?.headers || {});\r\n        headers.set('Authorization', 'Bearer your-token');\r\n        return fetch(input, {\r\n          ...init,\r\n          headers,\r\n        });\r\n      },\r\n    },\r\n  },\r\n});\r\n```\r\n\r\n## Configuration (`MastraMCPServerDefinition`)\r\n\r\nThe `server` parameter for both `MastraMCPClient` and `MCPConfiguration` uses the `MastraMCPServerDefinition` type. The client automatically detects the transport type based on the provided parameters:\r\n\r\n- If `command` is provided, it uses the Stdio transport.\r\n- If `url` is provided, it first attempts to use the Streamable HTTP transport and falls back to the legacy SSE transport if the initial connection fails.\r\n\r\nHere are the available options within `MastraMCPServerDefinition`:\r\n\r\n- **`command`**: (Optional, string) For Stdio servers: The command to execute.\r\n- **`args`**: (Optional, string[]) For Stdio servers: Arguments to pass to the command.\r\n- **`env`**: (Optional, Record<string, string>) For Stdio servers: Environment variables to set for the command.\r\n- **`url`**: (Optional, URL) For HTTP servers (Streamable HTTP or SSE): The URL of the server.\r\n- **`requestInit`**: (Optional, RequestInit) For HTTP servers: Request configuration for the fetch API. Used for the initial Streamable HTTP connection attempt and subsequent POST requests. Also used for the initial SSE connection attempt.\r\n- **`eventSourceInit`**: (Optional, EventSourceInit) **Only** for the legacy SSE fallback: Custom fetch configuration for SSE connections. Required when using custom headers with SSE.\r\n- **`logger`**: (Optional, LogHandler) Optional additional handler for logging.\r\n- **`timeout`**: (Optional, number) Server-specific timeout in milliseconds, overriding the global client/configuration timeout.\r\n- **`capabilities`**: (Optional, ClientCapabilities) Server-specific capabilities configuration.\r\n- **`enableServerLogs`**: (Optional, boolean, default: `true`) Whether to enable logging for this server.\r\n\r\n## Features\r\n\r\n- Standard MCP client implementation\r\n- Automatic tool conversion to Mastra format\r\n- Resource discovery and management\r\n- Multiple transport layers with automatic detection:\r\n  - Stdio-based for local servers (`command`)\r\n  - HTTP-based for remote servers (`url`): Tries Streamable HTTP first, falls back to legacy SSE.\r\n- Per-server logging capability using all standard MCP log levels\r\n- Automatic error handling and logging\r\n- Tool execution with context\r\n\r\n## Methods\r\n\r\n### `connect()`\r\n\r\nEstablishes connection with the MCP server.\r\n\r\n### `disconnect()`\r\n\r\nCloses the connection with the MCP server.\r\n\r\n### `resources()`\r\n\r\nLists available resources from the MCP server.\r\n\r\n### `tools()`\r\n\r\nRetrieves and converts MCP tools to Mastra-compatible format.\r\n\r\n## Tool Conversion\r\n\r\nThe package automatically converts MCP tools to Mastra's format:\r\n\r\n```typescript\r\nconst tools = await client.tools();\r\n// Returns: { [toolName: string]: MastraTool }\r\n\r\n// Each tool includes:\r\n// - Converted JSON schema\r\n// - Mastra-compatible execution wrapper\r\n// - Error handling\r\n// - Automatic context passing\r\n```\r\n\r\n## Error Handling\r\n\r\nThe client includes comprehensive error handling:\r\n\r\n- Connection errors\r\n- Tool execution errors\r\n- Resource listing errors\r\n- Schema conversion errors\r\n\r\n## Related Links\r\n\r\n- [Model Context Protocol Specification](https://modelcontextprotocol.io/specification)\r\n- [@modelcontextprotocol/sdk Documentation](https://github.com/modelcontextprotocol/typescript-sdk)\r\n- [Mastra Docs: Using MCP With Mastra](/docs/agents/mcp-guide)\r\n- [Mastra Docs: MCPConfiguration Reference](/reference/tools/mcp-configuration)\r\n- [Mastra Docs: MastraMCPClient Reference](/reference/tools/client)\r\n","readmeFilename":"README.md","_rev":"1-7c6440455e6cd5d05f3e2ba85ad75b76"}