HTTP/SSEまたはstdioを介して、ツール、リソース、プロンプトをAIクライアントに公開するためのModel Context Protocolを実装するFastifyプラグインです。
別名 platformatic/mcp, @platformatic/mcp
- スター
- 66
- ツール
- 6
- ダウンロード数(30日間)
- —
- 最新バージョン
- —
- 最終コミット
- 2026年11月12日
- ライセンス
- Apache-2.0
Fastify MCPとは
FastifyはMCPサーバーです。 HTTP/SSEまたはstdioを介して、ツール、リソース、プロンプトをAIクライアントに公開するためのModel Context Protocolを実装するFastifyプラグインです。. 6個のツールを提供しており、app, options, debugなどがあります。
プロジェクトのREADMEから生成された概要
Fastify MCP server について
Fastifyアプリケーションを開発しているエンジニアは、このプラグインを使用することで、Model Context Protocolを用いてツール、リソース、プロンプトをAIクライアントに公開できます。リアルタイムストリーミングのためのServer-Sent Eventsを用いたHTTPや、ローカルプロセス用のstdioなど、複数の通信方式をサポートしています。サーバーは複数のバージョンにわたるプロトコルネゴシエーションを処理するため、古いクライアントとの互換性を維持しつつ、タスク拡張ツール呼び出しやエリシテーション(引き出し)サポートなどの最新機能へのアクセスを提供します。
この実装には、ローカルメモリまたは水平スケーリングと永続化のためのRedisバックエンドを使用できる、組み込みのセッション管理が含まれています。ツールやリソース用のアイコンメタデータ、型安全なスキーマ検証のためのTypeBox統合、DNSリバインディング攻撃を防ぐためのオリジン検証など、高度な機能を提供します。ユーザーは特定のHTTPメソッドを通じてセッションのライフサイクルを管理でき、本番環境におけるセキュリティとリソース効率を維持するために有効期限を設定できます。
できること
- 1カスタム算術ツールの公開開発者は、AIが使用できる加算や除算などの演算を行う計算機ツールを定義できます。
- 2アプリケーション設定ファイルの提供特定のJSON設定ファイルを、リソースとしてAIクライアントから利用可能にできます。
- 3自動コードレビューの生成特定のプログラミング言語に基づいてコードをレビューするようAIに指示する、専用のプロンプトを作成できます。
プロジェクトの README から作成されています。すべてのユースケースは、その引用と照らし合わせて確認されています。
Fastify MCPのインストール方法
フォーマット検証日 2026年11月10日Cursor に追加Gooseに追加Claude CodeにFastify MCPをインストール
$ claude mcp add mcp -- npx -y @platformatic/mcpCursorにFastify MCPをインストール
~/.cursor/mcp.json
{
"mcpServers": {
"mcp": {
"command": "npx",
"args": [
"-y",
"@platformatic/mcp"
]
}
}
}VS CodeにFastify MCPをインストール
.vscode/mcp.json
{
"servers": {
"mcp": {
"type": "stdio",
"command": "npx",
"args": [
"-y",
"@platformatic/mcp"
]
}
}
}VS Code CLIにFastify MCPをインストール
$ code --add-mcp '{"name":"mcp","type":"stdio","command":"npx","args":["-y","@platformatic/mcp"]}'Claude DesktopにFastify MCPをインストール
claude_desktop_config.json
{
"mcpServers": {
"mcp": {
"command": "npx",
"args": [
"-y",
"@platformatic/mcp"
]
}
}
}CodexにFastify MCPをインストール
$ codex mcp add mcp -- npx -y @platformatic/mcpCodex config.tomlにFastify MCPをインストール
~/.codex/config.toml
[mcp_servers.mcp] command = "npx" args = ["-y", "@platformatic/mcp"]
Gemini CLIにFastify MCPをインストール
$ gemini mcp add -s user mcp npx -- -y @platformatic/mcpGemini settings.jsonにFastify MCPをインストール
~/.gemini/settings.json
{
"mcpServers": {
"mcp": {
"command": "npx",
"args": [
"-y",
"@platformatic/mcp"
]
}
}
}Fastify MCPツール 6
READMEから検出appoptionsdebuginputoutputerror
| app | — | |
| options | — | |
| debug | — | |
| input | — | |
| output | — | |
| error | — |
設定
MCP_SECRET_KEYREDIS_PASSWORD
| 名前 | 説明 | 種類 |
|---|---|---|
| MCP_SECRET_KEY | — | |
| REDIS_PASSWORD | — |
自動チェック
実行日 2026年11月12日完全なレポート →自動チェックに合格しました。これはセキュリティ監査ではありません。コードを読み、サーバーに必要最小限のアクセス権を与えてください。 チェックの仕組み
- ソースリポジトリがリンクされており、アクセス可能合格
- オープンソースライセンス (OSI)合格
- 過去1年以内にコミットまたはリリースあり合格
- パッケージ名が有名なパッケージに酷似していない合格
- リモートエンドポイントがHTTPSを使用未チェック
- 破壊的なツールがラベル付けされている合格
- モデルへの隠れた指示がない合格
- パッケージおよびその依存関係に重大な勧告なし未チェック
README
GitHubで見るFastify MCP Server
A Fastify plugin that implements the Model Context Protocol (MCP) server using JSON-RPC 2.0. This plugin enables Fastify applications to expose tools, resources, and prompts following the MCP 2025-06-18 specification with full elicitation support.
Installation
npm install @platformatic/mcp
TypeBox Support (Optional)
For type-safe schema validation, install TypeBox:
npm install @sinclair/typebox
Features
- Complete MCP 2025-11-25 Support: Implements the current Model Context Protocol revision, negotiating down to
2025-06-18,2025-03-26and2024-11-05for older clients - Tasks (experimental): Task-augmented tool calls with polling, deferred result retrieval and cancellation
- Elicitation Support: Server-to-client information requests in both form and URL mode, with schema validation
- Icons: Optional icon metadata on tools, resources, resource templates and prompts
- TypeBox Validation: Type-safe schema validation with automatic TypeScript inference
- Security Enhancements: Input sanitization, rate limiting, and security assessment
- Multiple Transport Support: HTTP/SSE and stdio transports for flexible communication
- SSE Streaming: Server-Sent Events for real-time communication
- Horizontal Scaling: Redis-backed session management and message broadcasting
- Session Persistence: Message history and reconnection support with Last-Event-ID
- Memory & Redis Backends: Seamless switching between local and distributed storage
- Production Ready: Comprehensive test coverage, security features, and authentication support
Quick Start
import Fastify from 'fastify'
import mcpPlugin from '@platformatic/mcp'
// Or use named import:
// import { mcpPlugin } from '@platformatic/mcp'
const app = Fastify({ logger: true })
// Register the MCP plugin
await app.register(mcpPlugin, {
serverInfo: {
name: 'my-mcp-server',
version: '1.0.0'
},
capabilities: {
tools: { listChanged: true },
resources: { subscribe: true },
prompts: {}
},
instructions: 'This server provides custom tools and resources'
})
// Add tools, resources, and prompts with handlers
app.mcpAddTool({
name: 'calculator',
description: 'Performs basic arithmetic operations',
inputSchema: {
type: 'object',
properties: {
operation: { type: 'string', enum: ['add', 'subtract', 'multiply', 'divide'] },
a: { type: 'number' },
b: { type: 'number' }
},
required: ['operation', 'a', 'b']
}
}, async (params) => {
const { operation, a, b } = params
let result
switch (operation) {
case 'add': result = a + b; break
case 'subtract': result = a - b; break
case 'multiply': result = a * b; break
case 'divide': result = a / b; break
default: throw new Error('Invalid operation')
}
return {
content: [{ type: 'text', text: `Result: ${result}` }]
}
})
app.mcpAddResource({
uri: 'file://config.json',
name: 'Application Config',
description: 'Server configuration file',
mimeType: 'application/json'
}, async (uri, context) => {
// Read and return the configuration file
const config = { setting1: 'value1', setting2: 'value2' }
return {
contents: [{
uri,
text: JSON.stringify(config, null, 2),
mimeType: 'application/json'
}]
}
})
app.mcpAddPrompt({
name: 'code-review',
description: 'Generates code review comments',
arguments: [{
name: 'language',
description: 'Programming language',
required: true
}]
}, async (name, args, context) => {
const language = args?.language || 'javascript'
return {
messages: [{
role: 'user',
content: {
type: 'text',
text: `Please review this ${language} code for best practices, potential bugs, and improvements.`
}
}]
}
})
await app.listen({ port: 3000 })
In-process MCP Client
The plugin decorates the Fastify instance with mcpClient(), a client that talks to the
server through app.inject() — no port binding, so it's equally useful for tests or for
driving the server from other in-process code:
import { test } from 'node:test'
import assert from 'node:assert/strict'
import Fastify from 'fastify'
import type { FastifyInstance } from 'fastify'
import mcpPlugin from '@platformatic/mcp'
test('calls an MCP tool', async (t) => {
const app: FastifyInstance = Fastify()
t.after(() => app.close())
await app.register(mcpPlugin, { enableSSE: true })
app.mcpAddTool({
name: 'echo',
description: 'Echo a message',
inputSchema: {
type: 'object',
properties: {
message: { type: 'string' }
},
required: ['message'],
additionalProperties: false
}
}, async ({ message }) => {
return {
content: [{ type: 'text', text: message }]
}
})
await app.ready()
const client = app.mcpClient()
await client.initialize()
const response = await client.callTool('echo', {
message: 'hello'
})
assert.equal(response.statusCode, 200)
assert.ok('result' in response.body)
assert.deepEqual(response.body.result, {
content: [{ type: 'text', text: 'hello' }]
})
})
The client:
- Uses
app.inject()only (no port binding). - Manages sequential JSON-RPC request IDs per client instance.
initialize()performs the complete MCP lifecycle handshake (initializeplusnotifications/initialized).initialize()rejects whennotifications/initializedis not accepted with an empty202or204response.- Commits
mcp-session-idand negotiated protocol version only after the full initialization handshake succeeds. - Forwards headers passed to
initialize()to both lifecycle requests, except MCP-managedmcp-session-idandmcp-protocol-versiononnotifications/initialized. - Captures committed
mcp-session-idfrom successful initialization and sends it automatically on later requests. - Lets you pass custom headers (including authorization) globally or per request.
Responses are a discriminated union — narrow with 'result' in response.body or
'error' in response.body. Malformed or non-JSON-RPC responses throw a coded Fastify error
instead of returning.
Note: no OAuth/JWT credentials are generated for you.
Protocol Version Negotiation
The server answers initialize with the client's requested revision when it is one it
supports, and otherwise offers the newest one it has:
import { LATEST_PROTOCOL_VERSION, SUPPORTED_PROTOCOL_VERSIONS } from '@platformatic/mcp'
LATEST_PROTOCOL_VERSION // '2025-11-25'
SUPPORTED_PROTOCOL_VERSIONS // ['2025-11-25', '2025-06-18', '2025-03-26', '2024-11-05']
On the HTTP transport, requests after initialize must carry the agreed revision in the
MCP-Protocol-Version header. An unsupported value is answered with 400; an absent header
is treated as 2025-03-26, which predates the header.
Responses are shaped to the revision the client negotiated. A client on an older revision never sees a field or method that revision does not define:
< 2025-11-25 |
2025-11-25 |
|
|---|---|---|
tasks capability |
not advertised | advertised |
tasks/* methods |
-32601 method not found |
available |
task field on tools/call |
ignored | honoured |
icons on listings |
stripped | present |
execution.taskSupport |
stripped | present |
$schema on tool schemas |
omitted | JSON Schema 2020-12 |
| URL mode elicitation | refused | available |
The negotiated revision is stored on the session and is authoritative:
a request whose MCP-Protocol-Version header contradicts what the session agreed is rejected
with 400, so a client cannot opt into newer behaviour after negotiating an older revision.
When the header is omitted the session's revision is used in preference to the 2025-03-26
default. initialize is exempt, so a client may re-negotiate on an existing session.
A request sent without an
Mcp-Session-Idhas no session to remember the negotiation, so it is judged solely by its header. A client that omits it falls back to2025-03-26and will not see2025-11-25features. Compliant clients always send the header.
Sessions
Session management is part of the Streamable HTTP transport and works whether or not SSE is enabled:
initializeonPOST /mcpcreates a session and returns its id in theMcp-Session-Idresponse header. Clients send it back on later requests.DELETE /mcpwith theMcp-Session-Idheader terminates the session (204), answering404for an unknown session and400when the header is missing.enableSSEonly controlsGET /mcp. Without it,GET /mcpanswers405withAllow: POST, DELETE.
With SSE disabled, requests that do not carry an Mcp-Session-Id keep working statelessly and
no session is created for them. With SSE enabled, every request without a known session id gets
a new session, as before.
Sessions expire after sessionTtlMs milliseconds without activity (default 3600000, one
hour), so clients that disconnect without sending DELETE do not leave sessions behind. Every
request carrying the session id, every message stored for it, and every heartbeat on an open SSE
stream counts as activity, so a session in use is never expired from under a live connection.
The Redis store applies this as the key TTL; the memory store checks it on every read and sweeps
expired sessions on an unref'd timer that is cleared when the server closes.
await app.register(mcpPlugin, {
sessionTtlMs: 15 * 60_000 // expire sessions after 15 idle minutes
})
Request Body Errors
Body-parser failures and bodies that are not JSON-RPC messages on POST /mcp are answered
with a JSON-RPC error (with id: null) while keeping the HTTP status code:
| Cause | Status | JSON-RPC error |
|---|---|---|
| Malformed or empty JSON | 400 |
-32700 Parse error |
Body larger than Fastify's bodyLimit |
413 |
-32600 Invalid Request |
Unsupported Content-Type |
415 |
-32600 Invalid Request |
Not a JSON-RPC request, notification or response (null, a number, a string, a text/plain body, or an object with none of method, result or error) |
400 |
-32600 Invalid Request |
A body that is not a JSON-RPC message is rejected before any SSE session is created for it.
A JSON-RPC response posted by the client is answered with 202 and handed to
onClientResponse.
The body-parser error handler is scoped to the POST /mcp route. Any other error on that route, and every
error on your other routes, still goes to your own (or Fastify's default) error handler.
Origin Validation
Browser clients can be protected against DNS rebinding by allow-listing origins. A rejected
origin is answered with 403:
await app.register(mcpPlugin, {
allowedOrigins: ['https://app.example.com'] // omit to disable, '*' or true to allow any
})
Requests without an Origin header are always accepted — the header is set by browsers, so
its absence means the request did not come from one.
allowedOrigins must be true, '*' or an array of strings; any other value (including a
single origin string) makes registration throw. Wrap a single origin in an array.
CORS
The plugin does not set CORS headers on /mcp; browser clients need the application to
configure CORS for it, for example with @fastify/cors:
import cors from '@fastify/cors'
await app.register(cors, {
origin: ['https://app.example.com'],
methods: ['GET', 'POST', 'DELETE'],
allowedHeaders: [
'Content-Type',
'Authorization',
'Last-Event-ID',
'Mcp-Session-Id',
'Mcp-Protocol-Version',
'Mcp-Method',
'Mcp-Name'
],
exposedHeaders: ['Mcp-Session-Id']
})
await app.register(mcpPlugin, { /* ... */ })
allowedHeaders does not accept wildcards, so list any Mcp-Param-* headers your clients send.
When authorization is enabled, the /.well-known/* discovery endpoints answer cross-origin
requests from any origin on their own; that CORS handling is scoped to those routes and does not
affect the rest of the application.
Tasks (MCP 2025-11-25, experimental)
Tasks let a tool call return immediately with a task handle while the work continues in the
background. The client then polls tasks/get and collects the result with tasks/result.
Enable the feature on the plugin, then opt individual tools in with execution.taskSupport:
await app.register(mcpPlugin, { enableTasks: true })
app.mcpAddTool({
name: 'generate-report',
description: 'Builds a large report',
inputSchema: Type.Object({ month: Type.String() }),
execution: { taskSupport: 'optional' } // 'forbidden' (default) | 'optional' | 'required'
}, async (params) => {
return { content: [{ type: 'text', text: await buildReport(params.month) }] }
})
A client opts in per call by adding a task field:
// -> tools/call
{ "name": "generate-report", "arguments": { "month": "July" }, "task": { "ttl": 60000 } }
// <- CreateTaskResult
{ "task": { "taskId": "…", "status": "working", "ttl": 60000, "pollInterval": 1000 } }
Supported operations: tasks/get, tasks/result (blocks until the task is terminal),
tasks/list and tasks/cancel, plus optional notifications/tasks/status pushes over SSE.
A blocked tasks/result stops waiting when its client disconnects, and when the server
closes it answers with a JSON-RPC -32603 "Server shutting down" error, so app.close()
never waits on a task running on another instance.
Retention defaults to 60 seconds when the client does not request a ttl. Tasks are meant
for long-running work, so if your tools can outlive that, raise the bounds — otherwise a task
can expire before it finishes and its tasks/result returns "not found":
await app.register(mcpPlugin, {
enableTasks: true,
taskDefaultTtlMs: 15 * 60_000, // retention when the client requests no ttl
taskMaxTtlMs: 60 * 60_000 // ceiling on a client-requested ttl
})
A client-requested ttl must be a non-negative integer number of milliseconds; anything else
(a string, a negative or fractional number) is rejected with -32602 Invalid params. A valid
ttl is clamped between 1 second and taskMaxTtlMs, and the effective value is returned in the
CreateTaskResult.
Tasks are stored in memory by default and in Redis when a redis option is given, so any
instance can serve a poll for a task created on another.
tasks/list returns the caller's tasks newest first, 50 per page. When more remain, the
result carries an opaque nextCursor; pass it back as params.cursor to fetch the next
page. An unrecognised cursor is rejected with -32602 (Invalid params). The Redis store keeps
a per-owner index, so a listing only reads the caller's own tasks.
Custom TaskStore implementations must implement list(owner, { cursor, limit }), where
owner is { subject, issuer } and must match a record's authSubject and authIssuer
exactly, and return { tasks, nextCursor? }, throwing InvalidTaskCursorError for a cursor
they did not issue.
Each caller (token issuer and subject) may keep at most taskMaxRetainedPerPrincipal tasks stored
(default 100). Finished tasks count until their ttl expires, so one caller cannot fill the
store with results it never collects. When a caller is at its quota, its oldest finished task
is evicted to make room; if all of them are still running, the tools/call fails with
-32029 "Task limit reached". Without authorization every caller shares a single quota, so
raise it if you expect many concurrent anonymous tasks. The in-memory store also holds at most
1000 tasks in total; when full, it evicts the caller's oldest finished task, then the oldest
finished task of any caller, before refusing. The Redis store enforces the quota atomically
with a per-caller sorted set (mcp:tasks:owner:<issuer>:<subject>, each part percent-encoded,
or mcp:tasks:anonymous), so it holds across instances. Custom TaskStore implementations
should throw TaskLimitError from create() to produce the same response.
The instance running a task holds a lease on it and renews it every third of taskLeaseMs
(default 30 seconds). If that instance dies or shuts down before the task finishes, renewals
stop. Once the lease lapses, the next tasks/get or tasks/result (including one already
waiting) marks the task failed with the status message "Task owner lost", so the task no
longer reads working until its ttl runs out. A caller at taskMaxRetainedPerPrincipal gets
the same treatment for their orphaned tasks when they create a new one, so tasks nobody polls
cannot keep them locked out of their quota. The check is a compare-and-set, so a renewal or
completion that lands first always wins. With Redis, the lease is set and checked against the
Redis server clock, so clock skew between instances can never fail a task that is still running,
nor delay failing one whose owner is gone:
await app.register(mcpPlugin, {
enableTasks: true,
taskMaxRetainedPerPrincipal: 20, // tasks each caller may keep, finished ones included
taskLeaseMs: 30_000 // a dead instance's tasks are failed this long after its last renewal
})
Security: when authorization is enabled, tasks are bound to the issuer and sub of the
token that created them (a subject is only unique per issuer, so both must match, as for
sessions) and a requestor can only reach its own. Another user's task answers
tasks/get, tasks/result and tasks/cancel exactly like an unknown task id, and never
appears in tasks/list. Tasks created by a version that only recorded the subject have no
issuer; with authorization enabled they are unreachable and simply expire with their ttl.
Without authorization no requestor can be identified, so
tasks are reachable by anyone holding the (random UUID) task id, and tasks/list is both
unadvertised and refused — otherwise it would hand every anonymous task's id to any
caller and defeat that model.
Elicitation Support (MCP 2025-11-25)
The plugin supports the elicitation capability, allowing servers to request structured information from clients. This enables dynamic data collection with schema validation.
Two modes are available. Form mode collects structured data through the client, and URL mode sends the user out of band for anything sensitive — credentials, payments, third-party OAuth — so it never passes through the MCP client:
// URL mode: returns the elicitation id, or null if the request could not be sent
const elicitationId = await app.mcpElicitUrl(
sessionId,
'Authorize access to your Example Co files',
'https://mcp.example.com/connect'
)
// Later, once the out-of-band interaction finishes
if (elicitationId) {
await app.mcpNotifyElicitationComplete(sessionId, elicitationId)
}
Servers MUST NOT request passwords, API keys or payment details through form mode — use URL mode for those. URLs are rejected if they are malformed, use a scheme other than http(s), or embed credentials.
Basic Elicitation
Elicitation is a client capability: there is nothing to declare in the server's
capabilities. The client opts in by sending capabilities: { elicitation: {} } (form
mode only), or { elicitation: { form: {}, url: {} } }, in its initialize request.
mcpElicit() returns false, and mcpElicitUrl() null, when the client did not declare
the mode being requested, as the spec forbids sending it.
The request is delivered over the session's SSE stream, so the client must have it open
(GET /mcp). The client answers by POSTing a JSON-RPC response with the same id; the
plugin acknowledges it with 202 and passes it to onClientResponse.
import { Type } from '@sinclair/typebox'
// Register plugin with elicitation support
await app.register(mcpPlugin, {
enableSSE: true, // Required for elicitation
// Receives the client's answer (an ElicitResult) to each elicitation request
onClientResponse: async (response, { sessionId }) => {
if ('result' in response) {
app.log.info({ sessionId, id: response.id, result: response.result }, 'Elicitation answered')
}
}
})
// In your tool handler, request information from the client
app.mcpAddTool({
name: 'collect-user-info',
description: 'Collect user information',
inputSchema: Type.Object({})
}, async (_params, { sessionId }) => {
if (!sessionId) {
return {
content: [{ type: 'text', text: 'No session available' }],
isError: true
}
}
// Request user details with schema validation
const success = await app.mcpElicit(sessionId, 'Please enter your details', {
type: 'object',
properties: {
name: {
type: 'string',
description: 'Your full name',
minLength: 1,
maxLength: 100
},
email: {
type: 'string',
description: 'Your email address',
format: 'email'
},
age: {
type: 'integer',
description: 'Your age',
minimum: 0,
maximum: 150
},
preferences: {
type: 'array',
items: {
type: 'string',
enum: ['newsletter', 'updates', 'marketing']
},
description: 'Communication preferences'
}
},
required: ['name', 'email']
})
if (success) {
return {
content: [{ type: 'text', text: 'Information request sent to client' }]
}
} else {
return {
content: [{ type: 'text', text: 'Failed to send elicitation request' }],
isError: true
}
}
})
Advanced Elicitation with Custom Request IDs
// Request with custom ID for tracking
const requestId = 'user-profile-123'
const success = await app.mcpElicit(
sessionId,
'Complete your profile setup',
{
type: 'object',
properties: {
avatar: { type: 'string', description: 'Avatar URL' },
bio: { type: 'string', maxLength: 500, description: 'Short bio' },
skills: {
type: 'array',
items: {
type: 'string',
enum: ['typescript', 'rust', 'go', 'python']
},
maxItems: 4,
description: 'Your skills'
}
}
},
requestId
)
Security Considerations for Elicitation
⚠️ Important Security Notes:
- Elicitation requests are automatically validated for length and complexity
- Schema depth and size are limited to prevent DoS attacks
- Rate limiting should be implemented for production use
- Always validate client responses before using the data
- Never request sensitive information without explicit user consent
TypeBox Schema Validation
The plugin supports TypeBox schemas for type-safe validation with automatic TypeScript inference. This eliminates the need for manual type definitions and provides compile-time type checking.
Benefits
- Type Safety: Automatic TypeScript type inference from schemas
- Runtime Validation: Input validation with structured error messages
- Zero Duplication: Single source of truth for both types and validation
- IDE Support: Full autocomplete and IntelliSense for validated parameters
- Performance: Compiled validators with caching for optimal performance
Fastify MCPのよくある質問
Fastify MCPをClaude Codeに追加するには
ターミナルでclaude mcp add mcp -- npx -y @platformatic/mcpを実行します。すべてのプロジェクトで利用するには--scope userを追加します。
Fastify MCPをCursorに追加するには
~/.cursor/mcp.jsonを開き、上記のインストールセクションに示すCursor設定を使ってmcpServersの下にサーバーを追加します。
Fastify MCPが提供するツールは
6個のツールを提供しており、app, options, debug, input, outputなどがあります。
セッションの管理と有効期限はどのように設定されますか?
セッションは、設定可能な一定時間(デフォルトは1時間)の非アクティブ状態が続くと期限切れになります。RedisストアはキーのTTLを使用し、メモリストアはタイマーを使用して期限切れのセッションを削除します。