MCPServer
MCPServer クラスは、既存の Mastra Tool と Agent を Model Context Protocol(MCP)サーバーとして公開する機能を提供します。これにより、Cursor、Windsurf、Claude Desktop などの MCP クライアントがこれらの機能へ接続し、Agent から利用できるようになります。
Mastra アプリケーション内で Tool や Agent を直接使用するだけなら、MCP サーバーを作成する必要はありません。この API は、Mastra の Tool と Agent を_外部の_ MCP クライアントへ公開するためのものです。
stdio(サブプロセス)と SSE(HTTP)の両方の MCP Transportに対応しています。
コンストラクターコンストラクターへの直接リンク
新しい MCPServer を作成するには、サーバーの基本情報、提供する Tool、必要に応じて Tool として公開する Agent を指定します。
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.6-sol',
})
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"
},
})
設定プロパティ設定プロパティへの直接リンク
コンストラクターは、次のプロパティを持つ MCPServerConfig オブジェクトを受け取ります。
id:
name:
version:
tools:
createTool または Vercel AI SDK で作成)であるオブジェクト。これらの Tool は直接公開されます。agents?:
ask_<agentIdentifier> という名前の Tool に自動変換されます。Agent のコンストラクター設定には、空でない文字列の description プロパティを**必ず**定義してください。この値が Tool の説明に使用されます。Agent の説明が未指定または空の場合、MCPServer の初期化時にエラーがスローされます。workflows?:
run_<workflowKey> という名前の Tool に変換されます。Workflow の inputSchema が Tool の入力スキーマになります。Workflow には、Tool の説明に使われる空でない文字列の description プロパティを**必ず**指定してください。説明が未指定または空の場合、エラーがスローされます。Tool は workflow.createRun()、続いて run.start({ inputData: <tool_input> }) を呼び出して Workflow を実行します。Agent または Workflow から生成した Tool 名(例: ask_myAgent、run_myWorkflow)が明示的に定義した Tool 名や別の生成名と重複した場合、明示的に定義した Tool が優先され、警告が記録されます。それ以降に重複する Agent や Workflow はスキップされます。description?:
instructions?:
mapAuthInfoToUser?:
extra.authInfo の MCP Transport 認証データを、Mastra の FGA チェックで使用する user 値へマッピングします。OAuth で保護された MCP サーバーを、FGA Provider を持つ Mastra インスタンスへ登録する場合に使用します。fga?:
tools/list と tools/call の FGA チェックに使用するリソースおよび権限のマッピングを上書きします。MCP の認可スコープを、内部の Agent や Workflow による Tool 実行とは別に設定する場合に使用します。repository?:
releaseDate?:
isLatest?:
packageCanonical?:
packages?:
remotes?:
resources?:
prompts?:
appResources?:
ui:// URI から App Resource 設定へのマップ。各エントリーは、MCP Apps 拡張機能(SEP-1865)を介して提供されるインタラクティブな HTML UI を定義します。詳細は MCP Apps セクションを参照してください。Agent を Tool として公開するAgent を Tool として公開するへの直接リンク
MCPServer には、Mastra Agent を呼び出し可能な Tool として自動公開する機能があります。設定の agents プロパティに Agent を指定すると、次のように処理されます。
-
Tool の命名: 各 Agent は
ask_<agentKey>という名前の Tool に変換されます。<agentKey>は、agentsオブジェクトでその Agent に使用したキーです。たとえばagents: { myAgentKey: myAgentInstance }と設定すると、ask_myAgentKeyという Tool が作成されます。 -
Tool の機能:
- 説明: 生成される Tool の説明は「Agent
<AgentName>に質問します。元の Agent の指示:<agent description>」という形式になります。 - 入力: Tool は、文字列の
messageプロパティを持つ単一のオブジェクト引数を受け取ります:{ message: "Your question for the agent" }。 - 実行: この Tool が呼び出されると、指定された
queryで対応する Agent のgenerate()メソッドを呼び出します。 - 出力: Agent の
generate()メソッドから得た結果を、そのまま Tool の出力として返します。
- 説明: 生成される Tool の説明は「Agent
-
名前の重複。
tools設定で明示的に定義した Tool と Agent から生成した Tool の名前が同じ場合(たとえばmyAgentKeyというキーの Agent とask_myAgentKeyという Tool がある場合)、明示的に定義した Tool が優先されます。重複した Agent は Tool に変換されず、警告が記録されます。
これにより、MCP クライアントは他の Tool と同様に、自然言語のクエリで Agent と簡単にやり取りできます。
Agent から Tool への変換Agent から Tool への変換への直接リンク
agents 設定プロパティに Agent を指定すると、MCPServer は Agent ごとに対応する Tool を自動作成します。Tool 名は ask_<agentIdentifier> となり、<agentIdentifier> には agents オブジェクトで使用したキーが入ります。
生成される Tool の説明は「Agent <agent.name> に質問します。Agent の説明: <agent.description>」となります。
Agent を Tool に変換するには、インスタンス化時の設定に空でない文字列の description プロパティを必ず指定してください(例: new Agent({ id: 'my-agent', name: 'myAgent', description: 'This agent does X.', ... }))。description が未指定または空の Agent を MCPServer に渡すと、MCPServer のインスタンス化時にエラーがスローされ、サーバーのセットアップに失敗します。
これにより、Agent の生成機能を MCP 経由ですぐに公開し、クライアントから Agent へ直接質問できるようになります。
Tool から MCP Context にアクセスするTool から MCP Context にアクセスするへの直接リンク
MCPServer で公開した Tool は、その呼び出し方に応じて2つの異なるプロパティから MCP Request Context(認証、セッション ID など)へアクセスできます。
| 呼び出しパターン | アクセス方法 |
|---|---|
| Tool の直接呼び出し | context?.mcp?.extra |
| Agent による Tool 呼び出し | context?.requestContext?.get("mcp.extra") |
共通パターン(どちらの Context でも使用可能):
const mcpExtra = context?.mcp?.extra ?? context?.requestContext?.get('mcp.extra')
const authInfo = mcpExtra?.authInfo
例: 両方の Context で動作する Tool例: 両方の Context で動作する Toolへの直接リンク
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()
},
})
メソッドメソッドへの直接リンク
以下の関数を MCPServer インスタンスで呼び出すことで、その動作を制御したり、情報を取得したりできます。
startStdio()startstdioへの直接リンク
このメソッドは、標準入出力(stdio)で通信するサーバーを起動します。通常、サーバーをコマンドラインプログラムとして実行する場合に使用します。
async startStdio(): Promise<void>
stdio を使用してサーバーを起動する例を次に示します。
const server = new MCPServer({
id: 'my-server',
name: 'My Server',
version: '1.0.0',
tools: {/* ... */},
})
await server.startStdio()
startSSE()startsseへの直接リンク
このメソッドを使用すると、MCP server を既存の Web サーバーに統合し、Server-Sent Events(SSE)で通信できます。Web サーバーが SSE パスまたはメッセージパスへのリクエストを受信したときに、Web サーバーのコードから呼び出します。
async startSSE({
url,
ssePath,
messagePath,
req,
res,
}: {
url: URL;
ssePath: string;
messagePath: string;
req: any;
res: any;
}): Promise<void>
HTTP サーバーのリクエストハンドラー内で startSSE を使用する例を次に示します。この例では、MCP client は http://localhost:1234/sse で MCP server に接続できます。
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 メソッドに必要な値の詳細は次のとおりです。
url:
ssePath:
messagePath:
req:
res:
startHonoSSE()starthonosseへの直接リンク
このメソッドを使用すると、MCP server を既存の Web サーバーに統合し、Server-Sent Events(SSE)で通信できます。Web サーバーが SSE パスまたはメッセージパスへのリクエストを受信したときに、Web サーバーのコードから呼び出します。
async startHonoSSE({
url,
ssePath,
messagePath,
req,
res,
}: {
url: URL;
ssePath: string;
messagePath: string;
req: any;
res: any;
}): Promise<void>
HTTP サーバーのリクエストハンドラー内で startHonoSSE を使用する例を次に示します。この例では、MCP client は http://localhost:1234/hono-sse で MCP server に接続できます。
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 メソッドに必要な値の詳細は次のとおりです。
url:
ssePath:
messagePath:
req:
res:
startHTTP()starthttpへの直接リンク
このメソッドを使用すると、MCP server を既存の Web サーバーに統合し、Streamable HTTP で通信できます。Web サーバーが HTTP リクエストを受信したときに、Web サーバーのコードから呼び出します。
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 client は http://localhost:1234/http で MCP server に接続できます。
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 を使用してステートレス動作を有効にします。
// 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 を使用します。
- Supabase Edge Functions
- Cloudflare Workers
- Vercel Edge Functions
- Netlify Edge Functions
- AWS Lambda
- Deno Deploy
次の環境では、デフォルトのセッションベースモード(serverless: true なし)を使用します。
- 長時間稼働する Node.js サーバー
- Docker コンテナ
- 従来型のホスティング(VPS、専用サーバー)
サーバーレスモードでは、セッション管理を無効にし、リクエストごとに新しいサーバーインスタンスを作成します。これは、呼び出し間でメモリが保持されないステートレス環境に必要です。
デフォルトでは、サーバーレスモードは各リクエストを単一の JSON レスポンスにバッファリングするため、Tool が送信した notifications/progress は client に届きません。代わりにリクエストスコープの SSE ストリーミングでリクエストを処理するには、serverlessStreaming: true を設定します。これにより、最終結果より前に進捗通知が配信されます。
await server.startHTTP({
url,
httpPath: '/mcp',
req: nodeReq,
res: nodeRes,
options: {
serverless: true,
serverlessStreaming: true, // ← Stream request-scoped notifications/progress
},
})
この場合もステートレスであり、mcp-session-id は不要で、保持もされません。有効になるのは、進捗など、現在のリクエストに限定された通知のみです。次のセッション依存機能は引き続き使用できません。
次の MCP 機能にはセッション状態または永続的な接続が必要なため、serverlessStreaming: true を使用する場合も含め、サーバーレスモードでは動作しません。
- Elicitation - Tool の実行中に対話形式でユーザー入力を求めるには、レスポンスを正しい client に返すためのセッション管理が必要です
- Resource の購読 - 購読状態を維持するため、
resources/subscribeとresources/unsubscribeには永続的な接続が必要です - Resource 更新通知 -
resources.notifyUpdated()で client に通知するには、有効な購読と永続的な接続が必要です - Prompt リスト変更通知 -
prompts.notifyListChanged()で client に更新をプッシュするには、永続的な接続が必要です - Tool リスト変更通知 -
toolActions.notifyListChanged()で client に更新をプッシュするには、永続的な接続が必要です - サーバーログ通知 -
sendLoggingMessage()で client にログメッセージをプッシュするには、永続的な接続が必要です
これらの機能は、長時間稼働するサーバー環境(Node.js サーバー、Docker コンテナなど)では通常どおり動作します。
startHTTP メソッドに必要な値の詳細は次のとおりです。
url:
httpPath:
req:
res:
options:
StreamableHTTPServerTransportOptions オブジェクトを使用すると、HTTP transport の動作をカスタマイズできます。利用可能なオプションは次のとおりです。
serverless:
true の場合、セッション管理なしのステートレスモードで動作します。各リクエストは新しいサーバーインスタンスで個別に処理されます。呼び出し間でセッションを保持できないサーバーレス環境(Cloudflare Workers、Supabase Edge Functions、Vercel Edge など)に不可欠です。デフォルトは false です。serverlessStreaming:
true の場合、サーバーレスリクエストはバッファリングされた JSON レスポンスの代わりに、リクエストスコープの SSE ストリーミングを使用します。これにより、リクエスト内の notifications/progress が最終結果より前に client に届きます。serverless: true と併用した場合にのみ有効です。デフォルトは、後方互換性のある動作を維持する false(バッファリングされた JSON レスポンス)です。有効になるのは進捗などのリクエストスコープの通知だけであり、Elicitation、購読、リクエスト外の通知には引き続きセッション状態が必要です。sessionIdGenerator:
undefined を返します。onsessioninitialized:
enableJsonResponse:
true の場合、サーバーは Server-Sent Events(SSE)によるストリーミングの代わりに、通常の JSON レスポンスを返します。デフォルトは false です。eventStore:
close()closeへの直接リンク
このメソッドはサーバーを閉じ、すべてのリソースを解放します。
async close(): Promise<void>
getServerInfo()getserverinfoへの直接リンク
このメソッドはサーバーの基本情報を返します。
getServerInfo(): ServerInfo
getServerDetail()getserverdetailへの直接リンク
このメソッドはサーバー情報の詳細を返します。
getServerDetail(): ServerDetail
getToolListInfo()gettoollistinfoへの直接リンク
このメソッドは、サーバーの作成時に設定された Tool を返します。読み取り専用のリストで、デバッグに役立ちます。
getToolListInfo(): ToolListInfo
getToolInfo()gettoolinfoへの直接リンク
このメソッドは、特定の Tool の詳細を返します。
getToolInfo(toolName: string): ToolInfo
executeTool()executetoolへの直接リンク
このメソッドは、指定した Tool を実行して結果を返します。
executeTool(toolName: string, input: any): Promise<any>
getStdioTransport()getstdiotransportへの直接リンク
startStdio() でサーバーを起動した場合、このメソッドを使用して stdio 通信を管理するオブジェクトを取得できます。主に内部確認やテストに使用します。
getStdioTransport(): StdioServerTransport | undefined
getSseTransport()getssetransportへの直接リンク
startSSE() でサーバーを起動した場合、このメソッドを使用して SSE 通信を管理するオブジェクトを取得できます。getStdioTransport と同様、主に内部確認やテストに使用します。
getSseTransport(): SSEServerTransport | undefined
getSseHonoTransport()getssehonotransportへの直接リンク
startHonoSSE() でサーバーを起動した場合、このメソッドを使用して SSE 通信を管理するオブジェクトを取得できます。getSseTransport と同様、主に内部確認やテストに使用します。
getSseHonoTransport(): SSETransport | undefined
getStreamableHTTPTransport()getstreamablehttptransportへの直接リンク
startHTTP() でサーバーを起動した場合、このメソッドを使用して HTTP 通信を管理するオブジェクトを取得できます。getSseTransport と同様、主に内部確認やテストに使用します。
getStreamableHTTPTransport(): StreamableHTTPServerTransport | undefined
tools()toolsへの直接リンク
この MCP server が提供する指定の Tool を実行します。
async executeTool(
toolId: string,
args: any,
executionContext?: { messages?: any[]; toolCallId?: string },
): Promise<any>
toolId:
args:
executionContext?:
Resource の処理Resource の処理への直接リンク
MCP Resource とは?MCP Resource とは?への直接リンク
Resource は Model Context Protocol(MCP)の中核となるプリミティブで、サーバーがクライアントから読み取り可能なデータやコンテンツを公開し、LLM との対話のコンテキストとして利用できるようにします。MCP サーバーが提供する次のようなあらゆる種類のデータを表します。
- ファイルの内容
- データベースのレコード
- API レスポンス
- リアルタイムのシステムデータ
- スクリーンショットや画像
- ログファイル
Resource は一意の URI(例:file:///home/user/documents/report.pdf、postgres://database/customers/schema)で識別され、テキスト(UTF-8 エンコード)またはバイナリデータ(base64 エンコード)を格納できます。
クライアントは、次の方法で Resource を検出できます。
- 直接 Resource:サーバーは
resources/listエンドポイントを介して、具体的な Resource の一覧を公開します。 - Resource テンプレート:実行時に定義される Resource の場合、サーバーはクライアントが Resource URI の構築に使用する URI テンプレート(RFC 6570)を公開できます。
Resource を読み取るには、クライアントが URI を指定して resources/read リクエストを送信します。クライアントがその Resource を購読している場合、サーバーは Resource 一覧の変更(notifications/resources/list_changed)や、特定の Resource の内容の更新(notifications/resources/updated)をクライアントに通知することもできます。
詳しくは、Resource に関する MCP 公式ドキュメントを参照してください。
MCPServerResources 型mcpserverresources-typeへの直接リンク
resources オプションには、MCPServerResources 型のオブジェクトを指定します。この型は、サーバーが Resource リクエストを処理するために使用するコールバックを定義します。
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 }
例:
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,
})
Resource の変更をクライアントに通知するResource の変更をクライアントに通知するへの直接リンク
利用可能な Resource やその内容が変更された場合、サーバーは該当する Resource を購読している接続済みクライアントに通知できます。
server.resources.notifyUpdated({ uri: string })serverresourcesnotifyupdated-uri-string-への直接リンク
uri で識別される特定の Resource の内容が更新されたときに、このメソッドを呼び出します。この URI を購読しているクライアントがある場合、そのクライアントは notifications/resources/updated メッセージを受信します。
async server.resources.notifyUpdated({ uri: string }): Promise<void>
例:
// After updating the content of 'file://data.txt'
await serverWithResources.resources.notifyUpdated({ uri: 'file://data.txt' })
server.resources.notifyListChanged()serverresourcesnotifylistchangedへの直接リンク
利用可能な Resource の一覧が変更されたとき(Resource が追加または削除された場合など)に、このメソッドを呼び出します。クライアントに notifications/resources/list_changed メッセージが送信され、Resource 一覧の再取得が促されます。
async server.resources.notifyListChanged(): Promise<void>
例:
// After adding a new resource to the list managed by 'myResourceHandlers.listResources'
await serverWithResources.resources.notifyListChanged()
Prompt の処理Prompt の処理への直接リンク
MCP Prompt とは?MCP Prompt とは?への直接リンク
Prompt は、MCP サーバーがクライアントに公開する再利用可能なテンプレートまたは Workflow です。引数を受け取り、Resource のコンテキストを含めることができます。また、バージョニングをサポートし、LLM との対話を標準化します。
Prompt は一意の名前(および任意のバージョン)で識別され、実行時に定義することも、静的に定義することもできます。
MCPServerPrompts 型mcpserverprompts-typeへの直接リンク
prompts オプションには、MCPServerPrompts 型のオブジェクトを指定します。この型は、サーバーが Prompt リクエストを処理するために使用するコールバックを定義します。
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[] }>
}
例:
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,
})
Prompt の変更をクライアントに通知するPrompt の変更をクライアントに通知するへの直接リンク
利用可能な Prompt が変更された場合、サーバーは接続済みクライアントに通知できます。
server.prompts.notifyListChanged()serverpromptsnotifylistchangedへの直接リンク
利用可能な Prompt の一覧が変更されたとき(Prompt が追加または削除された場合など)に、このメソッドを呼び出します。クライアントに notifications/prompts/list_changed メッセージが送信され、Prompt 一覧の再取得が促されます。
await serverWithPrompts.prompts.notifyListChanged()
Prompt 処理のベストプラクティスPrompt 処理のベストプラクティスへの直接リンク
- 明確で内容が分かる Prompt 名と説明を使用します。
getPromptMessagesですべての必須引数を検証します。- 破壊的変更を行う可能性がある場合は、
versionフィールドを含めます。 versionパラメーターを使用して、適切な Prompt ロジックを選択します。- Prompt 一覧が変更されたらクライアントに通知します。
- 分かりやすいメッセージでエラーを処理します。
- 引数の要件と利用可能なバージョンを文書化します。
Tool の動的管理Tool の動的管理への直接リンク
通常、Tool は MCPServer の構築時に指定しますが、サーバーの実行中に追加または削除することもできます。サーバーは、これらの操作を toolActions プロパティを介して公開します。Tool 一覧が変更されると、接続済みクライアントは notifications/tools/list_changed メッセージを受信し、Tool 一覧の再取得を促されます。
登録済みの Tool レジストリを返すメソッドが tools() であるため、このプロパティには toolActions という名前が付いています。
toolActions.add(tools)toolactionsaddtoolsへの直接リンク
実行中のサーバーに新しい Tool を登録し、接続済みクライアントに通知します。Tool は、コンストラクターに渡す Tool と同様に、レコードのキーで識別されます。既存のキーで Tool を追加すると、その Tool が置き換えられます。
async server.toolActions.add(tools: ToolsInput): Promise<void>
例:
import { createTool } from '@mastra/core/tools'
import { z } from 'zod'
const searchTool = createTool({
id: 'search',
description: 'Searches the knowledge base.',
inputSchema: z.object({ query: z.string() }),
execute: async ({ query }) => ({ results: [] }),
})
await server.toolActions.add({ searchTool })
toolActions.remove(toolIds)toolactionsremovetoolidsへの直接リンク
実行中のサーバーから Tool ID を指定して Tool を削除し、接続済みクライアントに通知します。不明な Tool ID は無視されます。少なくとも 1 つの Tool が削除された場合にのみ通知が送信されます。
async server.toolActions.remove(toolIds: string[]): Promise<void>
例:
await server.toolActions.remove(['searchTool'])
toolActions.notifyListChanged()toolactionsnotifylistchangedへの直接リンク
Tool レジストリを変更せずに、接続済みクライアントへ notifications/tools/list_changed メッセージを送信します。認可の変更など、別の理由で Tool の利用可否が変わった場合に呼び出します。
async server.toolActions.notifyListChanged(): Promise<void>
Mastra レジストリとの同期Mastra レジストリとの同期への直接リンク
サーバーが Mastra インスタンスに登録されている場合、toolActions.add() と toolActions.remove() は、起動時に行われる Tool の自動登録と同様に、Mastra インスタンスの Tool レジストリも更新します。追加した Tool は mastra.listTools() から利用可能になり(Tool 固有の id がある場合はそれをキーとして使用)、削除した Tool はレジストリから削除されます。
ロギングロギングへの直接リンク
MCP サーバーは、notifications/message を使用して構造化ログメッセージをクライアントに送信できます。クライアントは logging/setLevel リクエストを送信して詳細度を制御します。サーバーは、指定された最低レベルを下回るメッセージを破棄します(RFC 5424 の重大度順に準拠)。レベルはセッションごとに追跡されるため、クライアントごとに異なる詳細度を指定できます。
sendLoggingMessage()sendloggingmessageへの直接リンク
各クライアントの最低ログレベルに従い、接続済みのすべてのクライアントにログ通知を送信します。
async server.sendLoggingMessage(params: {
level: LoggingLevel;
data: unknown;
logger?: string;
}): Promise<void>
例:
await server.sendLoggingMessage({
level: 'info',
data: { message: 'Sync completed', itemsProcessed: 42 },
})
context.mcp.log()contextmcplogへの直接リンク
Tool の execute 関数内で context.mcp.log() を使用すると、その Tool を呼び出したクライアントにログメッセージを送信できます。
async context.mcp.log(
level: LoggingLevel,
message: string,
data?: Record<string, unknown>
): Promise<void>
例:
execute: async ({ location }, context) => {
await context.mcp.log('debug', 'Fetching weather', { location })
const weather = await fetchWeather(location)
await context.mcp.log('info', 'Weather fetched')
return weather
}
進捗通知進捗通知への直接リンク
長時間実行される Tool は、notifications/progress を使用して呼び出し元のクライアントに進捗を報告できます。進捗は、呼び出し元がリクエストに progressToken を含めて進捗追跡を要求した場合にのみ送信されます(Mastra の MCPClient は、enableProgressTracking が設定されている場合にこれを行います)。トークンが送信されていない場合、context.mcp.progress() は何も行いません。
context.mcp.progress()contextmcpprogressへの直接リンク
async context.mcp.progress(params: {
progress: number;
total?: number;
message?: string;
}): Promise<void>
例:
execute: async ({ items }, context) => {
for (const [index, item] of items.entries()) {
await processItem(item)
await context.mcp.progress({
progress: index + 1,
total: items.length,
message: `Processed ${item.name}`,
})
}
return { done: true }
}
通知の配信通知の配信への直接リンク
通知メソッド(resources.notifyListChanged()、prompts.notifyListChanged()、toolActions.notifyListChanged()、sendLoggingMessage())は、stdio/SSE 接続や各 Streamable HTTP セッションなど、すべてのトランスポートを介して接続済みの全クライアントに通知をブロードキャストします。例外は resources.notifyUpdated() で、resources/subscribe を介して Resource URI を購読したクライアントにのみ通知します。Streamable HTTP クライアントの購読はセッションごとに追跡されます。従来の SSE クライアントはメインのサーバーインスタンスを共有するため、1 つの購読セットを共有します。ステートレスな serverless モードを使用するクライアントは、リクエストごとに一時的なサーバーインスタンスが使用されるため、通知を受信できません。
例例への直接リンク
MCPServer のセットアップとデプロイの実践的な例については、MCP Server の公開ガイドを参照してください。
このページの冒頭にある例でも、Tool と Agent の両方を指定して MCPServer をインスタンス化する方法を示しています。
ElicitationElicitationへの直接リンク
Elicitation とはElicitation とはへの直接リンク
Elicitation は Model Context Protocol(MCP)の機能で、サーバーからユーザーに構造化された情報を要求できます。サーバーが実行時に追加データを収集する、対話型のワークフローを実現します。
MCPServer クラスには Elicitation 機能が自動的に組み込まれます。Tool は context.mcp オブジェクトを execute 関数で受け取り、このオブジェクトにはユーザー入力を要求する elicitation.sendRequest() メソッドが含まれます。
Tool 実行時のシグネチャTool 実行時のシグネチャへの直接リンク
MCP サーバーのコンテキスト内で Tool を実行すると、context.mcp オブジェクトを介して MCP 固有の機能を利用できます。
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
}
Elicitation の仕組みElicitation の仕組みへの直接リンク
一般的なユースケースは、Tool の実行中にユーザー入力が必要になる場合です。context パラメーターから提供される Elicitation 機能を使用できます。
- Tool がメッセージとスキーマを指定して
context.mcp.elicitation.sendRequest()を呼び出す - 接続済みの MCP クライアントにリクエストが送信される
- クライアントが UI やコマンドラインなどを介してユーザーにリクエストを提示する
- ユーザーが情報を入力するか、リクエストを拒否またはキャンセルする
- クライアントがサーバーにレスポンスを返す
- Tool がレスポンスを受け取り、実行を続ける
Tool で Elicitation を使用するTool で Elicitation を使用するへの直接リンク
Elicitation を使用してユーザーの連絡先情報を収集する Tool の例を次に示します。
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}`
}
},
}),
},
})
Elicitation リクエストのスキーマElicitation リクエストのスキーマへの直接リンク
requestedSchema は、プリミティブ型のプロパティだけを持つフラットなオブジェクトにする必要があります。次の型を使用できます。
- 文字列:
{ type: 'string', title: 'Display Name', description: 'Help text' } - 数値:
{ type: 'number', minimum: 0, maximum: 100 } - 真偽値:
{ type: 'boolean', default: false } - 列挙型:
{ type: 'string', enum: ['option1', 'option2'] }
スキーマの例:
{
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'],
}
レスポンスのアクションレスポンスのアクションへの直接リンク
ユーザーは Elicitation リクエストに対して、次の 3 つの方法で応答できます。
- 承認(
action: 'accept'):ユーザーがデータを入力し、送信を確定した- 送信されたデータを含む
contentフィールドがある
- 送信されたデータを含む
- 拒否(
action: 'decline'):ユーザーが情報の提供を明示的に拒否した- content フィールドはない
- キャンセル(
action: 'cancel'):ユーザーが判断せずにリクエストを閉じた- content フィールドはない
Tool では、3 種類すべてのレスポンスを適切に処理してください。
セキュリティ上の考慮事項セキュリティ上の考慮事項への直接リンク
- パスワード、社会保障番号(SSN)、クレジットカード番号などの機密情報は絶対に要求しない
- すべてのユーザー入力を指定したスキーマに照らして検証する
- 拒否とキャンセルを適切に処理する
- データ収集の理由を明確に示す
- ユーザーのプライバシーと設定を尊重する
Tool 実行 APITool 実行 APIへの直接リンク
Elicitation 機能は、Tool 実行時の options パラメーターを介して利用できます。
// 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)を使用する場合、Elicitation はセッションを認識します。複数のクライアントが同じサーバーに接続されている場合、Elicitation リクエストは Tool の実行を開始したクライアントセッションに送られます。
ElicitResult 型:
type ElicitResult = {
action: 'accept' | 'decline' | 'cancel'
content?: any // Only present when action is 'accept'
}
OAuth による保護OAuth による保護への直接リンク
MCP Auth Specification に従って OAuth 認証で MCP サーバーを保護するには、createOAuthMiddleware 関数を使用します。
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)
このミドルウェアは、次の処理を自動的に行います。
/.well-known/oauth-protected-resourceで Protected Resource Metadata を提供する(RFC 9728)- 認証が必要な場合、
401 Unauthorizedを適切なWWW-Authenticateヘッダーとともに返す - 指定されたバリデーターを使用して Bearer Token を検証する
Token の検証Token の検証への直接リンク
本番環境では、適切な Token 検証を使用してください。
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 ミドルウェアのオプションOAuth ミドルウェアのオプションへの直接リンク
oauth.resource:
oauth.scopesSupported?:
oauth.resourceName?:
oauth.validateToken?:
mcpPath?:
認証コンテキスト認証コンテキストへの直接リンク
HTTP ベースの Transport を使用する場合、Tool は context.mcp.extra を介してリクエストのメタデータにアクセスできます。これにより、HTTP ミドルウェアから MCP Tool へ認証情報、ユーザーコンテキスト、任意のカスタムデータを渡せます。
仕組み仕組みへの直接リンク
HTTP ミドルウェアで req.auth に設定した内容は、Tool 内で context.mcp.extra.authInfo として利用できます。
req.auth = { ... } → context?.mcp?.extra?.authInfo.extra = { ... }
FGA 用に認証データをマッピングするFGA 用に認証データをマッピングするへの直接リンク
きめ細かな認可(FGA)Provider を持つ Mastra インスタンスに MCPServer を登録すると、Mastra は Tool の一覧取得または呼び出しの前に requestContext.get('user') を確認します。HTTP MCP Transport は認証済みデータを extra.authInfo として渡すため、mapAuthInfoToUser を使用して FGA Provider が想定するユーザー形式を設定してください。
const server = new MCPServer({
id: 'my-server',
name: 'My Server',
version: '1.0.0',
tools: { getUserData },
mapAuthInfoToUser: ({ authInfo }) => {
const user = authInfo as {
extra?: {
userId?: string
organizationMembershipId?: string
}
}
if (!user.extra?.userId) {
return null
}
return {
id: user.extra.userId,
organizationMembershipId: user.extra.organizationMembershipId,
}
},
})
MCP Tool の FGA スコープを分けるMCP Tool の FGA スコープを分けるへの直接リンク
MCP Client に、内部の Agent または Workflow による Tool 実行とは異なる認可スコープが必要な場合は、fga.resourceMapping と fga.permissionMapping を使用します。この上書きは、この MCP Server の tools/list と tools/call のチェックにのみ適用されます。
import { MastraFGAPermissions } from '@mastra/core/auth/ee'
const server = new MCPServer({
id: 'my-server',
name: 'My Server',
version: '1.0.0',
tools: { getUserData },
mapAuthInfoToUser: ({ authInfo }) => {
const user = authInfo as {
extra?: {
userId?: string
organizationMembershipId?: string
}
}
if (!user.extra?.userId) {
return null
}
return {
id: user.extra.userId,
organizationMembershipId: user.extra.organizationMembershipId,
}
},
fga: {
resourceMapping: {
tool: {
fgaResourceType: 'user',
deriveId: ({ user }) => (user as { id: string }).id,
},
},
permissionMapping: {
[MastraFGAPermissions.TOOLS_EXECUTE]: 'read',
},
},
})
認証ミドルウェアの設定認証ミドルウェアの設定への直接リンク
Tool にデータを渡すには、HTTP Server のミドルウェアで Node.js のリクエストオブジェクトの req.auth に値を設定してから、server.startHTTP() を呼び出します。
import express from 'express'
type MCPAuthenticatedRequest = express.Request & {
auth?: {
token: string
clientId: string
scopes: string[]
expiresAt?: number
extra?: Record<string, unknown>
}
}
const app = express()
// Auth middleware - set req.auth before the MCP handler
app.use('/mcp', async (req, res, next) => {
const authorization = req.headers.authorization
if (!authorization?.startsWith('Bearer ')) {
res.status(401).json({ error: 'Missing bearer token' })
return
}
const token = authorization.slice('Bearer '.length)
try {
const user = await verifyToken(token)
// This entire object becomes context.mcp.extra.authInfo
const authenticatedRequest = req as MCPAuthenticatedRequest
authenticatedRequest.auth = {
token,
clientId: user.clientId,
scopes: user.scopes,
expiresAt: user.expiresAt,
extra: {
userId: user.userId,
email: user.email,
},
}
next()
} catch {
res.status(401).json({ error: 'Invalid or expired token' })
}
})
app.all('/mcp', async (req, res) => {
const url = new URL(req.url, `http://${req.headers.host}`)
await server.startHTTP({ url, httpPath: '/mcp', req, res })
})
Tool から認証データにアクセスするTool から認証データにアクセスするへの直接リンク
req.auth オブジェクトは、Tool の execute 関数内で context.mcp.extra.authInfo として利用できます。
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()
}
Agent に RequestContext を渡す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 オブジェクトthe-extra-objectへの直接リンク
完全な context.mcp.extra オブジェクトには、次の値が含まれます。
| プロパティ | 説明 |
|---|---|
authInfo | ミドルウェアで req.auth に設定した内容 |
sessionId | MCP 接続のセッション識別子 |
signal | リクエストをキャンセルするための AbortSignal |
sendNotification | 通知を送信する MCP プロトコル関数 |
sendRequest | リクエストを送信する MCP プロトコル関数 |
完全な例完全な例への直接リンク
Identity Provider の JSON Web Key Set(JWKS)を使用して JSON Web Token(JWT)を検証するために、jose をインストールします。
- npm
- pnpm
- Yarn
- Bun
npm install jose
pnpm add jose
yarn add jose
bun add jose
次の例では、ユーザーデータを Tool に渡す前に、Token の署名、発行者、Audience、アルゴリズム、有効期限、必須 Claim を検証します。
import express from 'express'
import { createRemoteJWKSet, jwtVerify } from 'jose'
import { MCPServer } from '@mastra/mcp'
import { createTool } from '@mastra/core/tools'
import { z } from 'zod'
type MCPAuthenticatedRequest = express.Request & {
auth?: {
token: string
clientId: string
scopes: string[]
expiresAt?: number
extra?: Record<string, unknown>
}
}
const issuer = process.env.JWT_ISSUER
const audience = process.env.JWT_AUDIENCE
const jwksUri = process.env.JWT_JWKS_URI
if (!issuer || !audience || !jwksUri) {
throw new Error('JWT_ISSUER, JWT_AUDIENCE, and JWT_JWKS_URI are required')
}
const jwks = createRemoteJWKSet(new URL(jwksUri))
const verifyToken = async (token: string) => {
const { payload } = await jwtVerify(token, jwks, {
issuer,
audience,
algorithms: ['RS256'],
requiredClaims: ['exp'],
})
const clientId =
typeof payload.client_id === 'string'
? payload.client_id
: typeof payload.azp === 'string'
? payload.azp
: undefined
if (!payload.sub || typeof payload.email !== 'string' || !clientId || !payload.exp) {
throw new Error('Token must contain sub, email, exp, and client_id or azp claims')
}
return {
userId: payload.sub,
clientId,
email: payload.email,
expiresAt: payload.exp,
scopes: typeof payload.scope === 'string' ? payload.scope.split(' ') : [],
}
}
// 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', async (req, res, next) => {
const authorization = req.headers.authorization
if (!authorization?.startsWith('Bearer ')) {
res.status(401).json({ error: 'Missing bearer token' })
return
}
const token = authorization.slice('Bearer '.length)
try {
const user = await verifyToken(token)
// This entire object becomes context.mcp.extra.authInfo
const authenticatedRequest = req as MCPAuthenticatedRequest
authenticatedRequest.auth = {
token,
clientId: user.clientId,
scopes: user.scopes,
expiresAt: user.expiresAt,
extra: {
userId: user.userId,
email: user.email,
},
}
next()
} catch {
res.status(401).json({ error: 'Invalid or expired token' })
}
})
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)
MCP Apps(appResources)mcp-apps-appresourcesへの直接リンク
appResources オプションを使用すると、MCP Apps 拡張機能を介して MCP Server からインタラクティブな HTML UI を提供できます。各エントリは ui:// URI を、Mastra Studio のサンドボックス化された iframe 内でレンダリングされる HTML アプリにマッピングします。
AppResources 型appresources-typeへの直接リンク
Key (URI):
ui:// URI(例: ui://calculator/main)。各値は AppResource オブジェクトです。
name:
description?:
html?:
html または htmlPath のいずれかを指定します。htmlPath?:
html または htmlPath のいずれかを指定します。meta?:
例例への直接リンク
import { MCPServer } from '@mastra/mcp'
import { createTool } from '@mastra/core/tools'
import { z } from 'zod'
const calculatorTool = createTool({
id: 'calculatorWithUI',
description: 'An interactive calculator',
inputSchema: z.object({
num1: z.number(),
num2: z.number(),
operation: z.enum(['add', 'subtract']),
}),
execute: async ({ num1, num2, operation }) => {
const result = operation === 'add' ? num1 + num2 : num1 - num2
return {
content: [{ type: 'text', text: 'An interactive calculator is displayed.' }],
structuredContent: { result },
}
},
})
const server = new MCPServer({
id: 'app-server',
name: 'App Server',
version: '1.0.0',
tools: { calculatorTool },
appResources: {
'ui://calculator/main': {
name: 'Interactive Calculator',
html: '<html><body><h2>Calculator</h2>...</body></html>',
},
},
})
Tool の _meta.ui.resourceUri に対応する ui:// URI を設定して、Tool をそのアプリリソースに関連付けます。Server は Tool の登録時に、このメタデータを自動的に正規化します。アプリブリッジ API の全仕様と使用パターンについては、MCP Appsを参照してください。
関連情報関連情報への直接リンク
- Mastra から MCP Server に接続する方法については、MCPClient のドキュメントを参照してください。
- Model Context Protocol の詳細については、@modelcontextprotocol/sdk のドキュメントを参照してください。