メインコンテンツへ移動

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:

string
サーバーの一意な識別子。サーバーを Mastra に登録してもこの ID は保持され、getMCPServerById() でサーバーを取得する際に使用できます。

name:

string
サーバーを表す名前(例: 'My Weather and Agent Server')。

version:

string
サーバーのセマンティックバージョン(例: '1.0.0')。

tools:

ToolsInput
キーが Tool 名、値が Mastra Tool の定義(createTool または Vercel AI SDK で作成)であるオブジェクト。これらの Tool は直接公開されます。

agents?:

Record<string, Agent>
キーが Agent の識別子、値が Mastra Agent インスタンスであるオブジェクト。各 Agent は ask_<agentIdentifier> という名前の Tool に自動変換されます。Agent のコンストラクター設定には、空でない文字列の description プロパティを**必ず**定義してください。この値が Tool の説明に使用されます。Agent の説明が未指定または空の場合、MCPServer の初期化時にエラーがスローされます。

workflows?:

Record<string, Workflow>
キーが Workflow の識別子、値が Mastra Workflow インスタンスであるオブジェクト。各 Workflow は run_<workflowKey> という名前の Tool に変換されます。Workflow の inputSchema が Tool の入力スキーマになります。Workflow には、Tool の説明に使われる空でない文字列の description プロパティを**必ず**指定してください。説明が未指定または空の場合、エラーがスローされます。Tool は workflow.createRun()、続いて run.start({ inputData: <tool_input> }) を呼び出して Workflow を実行します。Agent または Workflow から生成した Tool 名(例: ask_myAgentrun_myWorkflow)が明示的に定義した Tool 名や別の生成名と重複した場合、明示的に定義した Tool が優先され、警告が記録されます。それ以降に重複する Agent や Workflow はスキップされます。

description?:

string
MCP サーバーの機能を示す省略可能な説明。

instructions?:

string
サーバーとその機能の使用方法を示す省略可能な指示。

mapAuthInfoToUser?:

({ authInfo, extra, requestContext }) => unknown | null | undefined | Promise<unknown | null | undefined>
extra.authInfo の MCP Transport 認証データを、Mastra の FGA チェックで使用する user 値へマッピングします。OAuth で保護された MCP サーバーを、FGA Provider を持つ Mastra インスタンスへ登録する場合に使用します。

fga?:

{ resourceMapping?: Partial<Record<'tool' | 'tools', { fgaResourceType: string; deriveId?: ({ user, resourceId, requestContext }) => string | undefined }>>; permissionMapping?: Record<string, string> }
この MCP サーバーの tools/listtools/call の FGA チェックに使用するリソースおよび権限のマッピングを上書きします。MCP の認可スコープを、内部の Agent や Workflow による Tool 実行とは別に設定する場合に使用します。

repository?:

Repository
サーバーのソースコードに関する省略可能なリポジトリ情報。

releaseDate?:

string
このサーバーバージョンの省略可能なリリース日(ISO 8601 文字列)。未指定の場合、インスタンス化した時刻がデフォルトになります。

isLatest?:

boolean
最新バージョンかどうかを示す省略可能なフラグ。未指定の場合、デフォルトは true です。

packageCanonical?:

'npm' | 'docker' | 'pypi' | 'crates' | string
サーバーをパッケージとして配布する場合の省略可能な標準パッケージ形式(例: 'npm'、'docker')。

packages?:

PackageInfo[]
このサーバー用にインストールできるパッケージの省略可能なリスト。

remotes?:

RemoteInfo[]
このサーバーのリモートアクセスポイントの省略可能なリスト。

resources?:

MCPServerResources
サーバーによる MCP Resource の処理方法を定義するオブジェクト。詳細は Resource handling セクションを参照してください。

prompts?:

MCPServerPrompts
サーバーによる MCP Prompt の処理方法を定義するオブジェクト。詳細は Prompt handling セクションを参照してください。

appResources?:

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 の出力として返します。
  • 名前の重複。 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:

URL
ユーザーがリクエストしている Web アドレス。

ssePath:

string
client が SSE に接続する URL のパス(例:'/sse')。

messagePath:

string
client がメッセージを送信する URL のパス(例:'/message')。

req:

any
Web サーバーから受け取るリクエストオブジェクト。

res:

any
データの返信に使用する、Web サーバーのレスポンスオブジェクト。

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:

URL
ユーザーがリクエストしている Web アドレス。

ssePath:

string
client が SSE に接続する URL のパス(例:'/hono-sse')。

messagePath:

string
client がメッセージを送信する URL のパス(例:'/message')。

req:

any
Web サーバーから受け取るリクエストオブジェクト。

res:

any
データの返信に使用する、Web サーバーのレスポンスオブジェクト。

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 を使用する場合

各リクエストが新しいステートレスな実行コンテキストで処理される環境にデプロイする場合は、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/subscriberesources/unsubscribe には永続的な接続が必要です
  • Resource 更新通知 - resources.notifyUpdated() で client に通知するには、有効な購読と永続的な接続が必要です
  • Prompt リスト変更通知 - prompts.notifyListChanged() で client に更新をプッシュするには、永続的な接続が必要です
  • Tool リスト変更通知 - toolActions.notifyListChanged() で client に更新をプッシュするには、永続的な接続が必要です
  • サーバーログ通知 - sendLoggingMessage() で client にログメッセージをプッシュするには、永続的な接続が必要です

これらの機能は、長時間稼働するサーバー環境(Node.js サーバー、Docker コンテナなど)では通常どおり動作します。

startHTTP メソッドに必要な値の詳細は次のとおりです。

url:

URL
ユーザーがリクエストしている Web アドレス。

httpPath:

string
MCP server が HTTP リクエストを処理する URL のパス(例:'/mcp')。

req:

http.IncomingMessage
Web サーバーから受け取るリクエストオブジェクト。

res:

http.ServerResponse
データの返信に使用する、Web サーバーのレスポンスオブジェクト。

options:

StreamableHTTPServerTransportOptions
HTTP transport のオプション設定。詳細は次のオプション表を参照してください。

StreamableHTTPServerTransportOptions オブジェクトを使用すると、HTTP transport の動作をカスタマイズできます。利用可能なオプションは次のとおりです。

serverless:

boolean
true の場合、セッション管理なしのステートレスモードで動作します。各リクエストは新しいサーバーインスタンスで個別に処理されます。呼び出し間でセッションを保持できないサーバーレス環境(Cloudflare Workers、Supabase Edge Functions、Vercel Edge など)に不可欠です。デフォルトは false です。

serverlessStreaming:

boolean
true の場合、サーバーレスリクエストはバッファリングされた JSON レスポンスの代わりに、リクエストスコープの SSE ストリーミングを使用します。これにより、リクエスト内の notifications/progress が最終結果より前に client に届きます。serverless: true と併用した場合にのみ有効です。デフォルトは、後方互換性のある動作を維持する false(バッファリングされた JSON レスポンス)です。有効になるのは進捗などのリクエストスコープの通知だけであり、Elicitation、購読、リクエスト外の通知には引き続きセッション状態が必要です。

sessionIdGenerator:

(() => string) | undefined
一意のセッション ID を生成する関数。暗号学的に安全で、グローバルに一意な文字列を使用する必要があります。セッション管理を無効にするには undefined を返します。

onsessioninitialized:

(sessionId: string) => void
新しいセッションが初期化されたときに呼び出されるコールバック。有効な MCP セッションの追跡に役立ちます。

enableJsonResponse:

boolean
true の場合、サーバーは Server-Sent Events(SSE)によるストリーミングの代わりに、通常の JSON レスポンスを返します。デフォルトは false です。

eventStore:

EventStore
メッセージを再開可能にするためのイベントストア。指定すると、client は再接続してメッセージストリームを再開できます。

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:

string
実行する Tool の ID または名前。

args:

any
Tool の execute 関数に渡す引数。

executionContext?:

object
messages や toolCallId など、Tool の実行に使用するオプションのコンテキスト。

Resource の処理
Resource の処理への直接リンク

MCP Resource とは?
MCP Resource とは?への直接リンク

Resource は Model Context Protocol(MCP)の中核となるプリミティブで、サーバーがクライアントから読み取り可能なデータやコンテンツを公開し、LLM との対話のコンテキストとして利用できるようにします。MCP サーバーが提供する次のようなあらゆる種類のデータを表します。

  • ファイルの内容
  • データベースのレコード
  • API レスポンス
  • リアルタイムのシステムデータ
  • スクリーンショットや画像
  • ログファイル

Resource は一意の URI(例:file:///home/user/documents/report.pdfpostgres://database/customers/schema)で識別され、テキスト(UTF-8 エンコード)またはバイナリデータ(base64 エンコード)を格納できます。

クライアントは、次の方法で Resource を検出できます。

  1. 直接 Resource:サーバーは resources/list エンドポイントを介して、具体的な Resource の一覧を公開します。
  2. 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 をインスタンス化する方法を示しています。

Elicitation
Elicitationへの直接リンク

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 機能を使用できます。

  1. Tool がメッセージとスキーマを指定して context.mcp.elicitation.sendRequest() を呼び出す
  2. 接続済みの MCP クライアントにリクエストが送信される
  3. クライアントが UI やコマンドラインなどを介してユーザーにリクエストを提示する
  4. ユーザーが情報を入力するか、リクエストを拒否またはキャンセルする
  5. クライアントがサーバーにレスポンスを返す
  6. 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 つの方法で応答できます。

  1. 承認action: 'accept'):ユーザーがデータを入力し、送信を確定した
    • 送信されたデータを含む content フィールドがある
  2. 拒否action: 'decline'):ユーザーが情報の提供を明示的に拒否した
    • content フィールドはない
  3. キャンセルaction: 'cancel'):ユーザーが判断せずにリクエストを閉じた
    • content フィールドはない

Tool では、3 種類すべてのレスポンスを適切に処理してください。

セキュリティ上の考慮事項
セキュリティ上の考慮事項への直接リンク

  • パスワード、社会保障番号(SSN)、クレジットカード番号などの機密情報は絶対に要求しない
  • すべてのユーザー入力を指定したスキーマに照らして検証する
  • 拒否とキャンセルを適切に処理する
  • データ収集の理由を明確に示す
  • ユーザーのプライバシーと設定を尊重する

Tool 実行 API
Tool 実行 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-resourceProtected 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:

string
MCP サーバーの正規 URL。Protected Resource Metadata で返されます。

oauth.authorizationServers:

string[]
このリソースの Token を発行できる認可サーバーの URL。

oauth.scopesSupported?:

string[]
= ['mcp:read', 'mcp:write']
この MCP サーバーがサポートする Scope。

oauth.resourceName?:

string
このリソースサーバーの人が読める名前。

oauth.validateToken?:

(token: string, resource: string) => Promise<TokenValidationResult>
Access Token を検証する関数。指定しない場合、Token は検証なしで受け入れられます(本番環境では非推奨)。

mcpPath?:

string
= '/mcp'
MCP エンドポイントを提供するパス。このパスへのリクエストにのみ認証が必要です。

認証コンテキスト
認証コンテキストへの直接リンク

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.resourceMappingfga.permissionMapping を使用します。この上書きは、この MCP Server の tools/listtools/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 に設定した内容
sessionIdMCP 接続のセッション識別子
signalリクエストをキャンセルするための AbortSignal
sendNotification通知を送信する MCP プロトコル関数
sendRequestリクエストを送信する MCP プロトコル関数

完全な例
完全な例への直接リンク

Identity Provider の JSON Web Key Set(JWKS)を使用して JSON Web Token(JWT)を検証するために、jose をインストールします。

npm install 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):

string
アプリリソースを識別する ui:// URI(例: ui://calculator/main)。

各値は AppResource オブジェクトです。

name:

string
UI リソースの表示名。

description?:

string
UI リソースの説明(任意)。

html?:

string
UI のインライン HTML コンテンツ。html または htmlPath のいずれかを指定します。

htmlPath?:

string
HTML ファイルへのパス。Server の起動時に解決されます。html または htmlPath のいずれかを指定します。

meta?:

McpUiResourceMeta
公式 ext-apps SDK の UI リソースメタデータ(CSP、権限、レンダリング設定)。

例への直接リンク

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を参照してください。

On this page