Built by Metorial, the integration platform for agentic AI.

Learn More

yamato-snow/2025_McpLab_FastMCP

FastMCP

    Server Summary

    • Client session management

    • Tool and resource definition

    • Authentication support

    • Logging functionality

    • Error handling

    • Real-time updates via SSE

    • Progress notifications

    • CORS support

    • Prompt argument auto-completion

    • Sampling requests

    • Automatic SSE pinging

    • Route management

    • Testing and debugging with CLI tools

FastMCP

FastMCPは、クライアントセッション管理が可能なMCPサーバーを構築するためのTypeScriptフレームワークです。

[!NOTE]

Python実装版はFastMCP Pythonをご覧ください。

主な機能

FastMCPは以下の機能を提供します:

インストール方法

npm install fastmcp

クイックスタート

[!NOTE]

FastMCPの実際の使用例は多数あります。事例紹介をご覧ください。

import { FastMCP } from "fastmcp";
import { z } from "zod"; // または他の検証ライブラリ(Standard Schemaをサポートしているもの)

const server = new FastMCP({
  name: "マイサーバー",
  version: "1.0.0",
});

server.addTool({
  name: "add",
  description: "2つの数値を足し算します",
  parameters: z.object({
    a: z.number(),
    b: z.number(),
  }),
  execute: async (args) => {
    return String(args.a + args.b);
  },
});

server.start({
  transportType: "stdio",
});

これだけで動作するMCPサーバーができました!

ターミナルで以下のようにテストできます:

git clone https://github.com/punkpeye/fastmcp.git
cd fastmcp

pnpm install
pnpm build

# CLIを使った足し算サーバーの例をテスト:
npx fastmcp dev src/examples/addition.ts
# MCP Inspectorを使った足し算サーバーの例を検査:
npx fastmcp inspect src/examples/addition.ts

SSE

Server-Sent Events(SSE)は、サーバーがHTTPS接続を介してクライアントにリアルタイム更新を送信するメカニズムです。MCPにおいて、SSEは主にリモートMCP通信を可能にするために使用され、リモートマシンでホストされたMCPにアクセスしてネットワーク経由で更新を中継できるようにします。

SSEサポート付きでサーバーを実行することもできます:

server.start({
  transportType: "sse",
  sse: {
    endpoint: "/sse",
    port: 8080,
  },
});

これにより、サーバーが起動し、http://localhost:8080/sseでSSE接続をリッスンします。

その後、SSEClientTransportを使用してサーバーに接続できます:

import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";

const client = new Client(
  {
    name: "example-client",
    version: "1.0.0",
  },
  {
    capabilities: {},
  },
);

const transport = new SSEClientTransport(new URL(`http://localhost:8080/sse`));

await client.connect(transport);

基本概念

ツール

MCPのツールでは、サーバーが実行可能な関数を公開し、クライアントやLLMがアクションを実行するために呼び出すことができます。

FastMCPはツールパラメーターの定義にStandard Schema仕様を使用しています。これにより、Zod、ArkType、Valibotなど、仕様を実装している好みのスキーマ検証ライブラリを使用できます。

Zodの例:

import { z } from "zod";

server.addTool({
  name: "fetch-zod",
  description: "URLのコンテンツを取得します(Zodを使用)",
  parameters: z.object({
    url: z.string(),
  }),
  execute: async (args) => {
    return await fetchWebpageContent(args.url);
  },
});

ArkTypeの例:

import { type } from "arktype";

server.addTool({
  name: "fetch-arktype",
  description: "URLのコンテンツを取得します(ArkTypeを使用)",
  parameters: type({
    url: "string",
  }),
  execute: async (args) => {
    return await fetchWebpageContent(args.url);
  },
});

Valibotの例:

Valibotにはピア依存関係@valibot/to-json-schemaが必要です。

import * as v from "valibot";

server.addTool({
  name: "fetch-valibot",
  description: "URLのコンテンツを取得します(Valibotを使用)",
  parameters: v.object({
    url: v.string(),
  }),
  execute: async (args) => {
    return await fetchWebpageContent(args.url);
  },
});

文字列を返す

executeは文字列を返すことができます:

server.addTool({
  name: "download",
  description: "ファイルをダウンロードします",
  parameters: z.object({
    url: z.string(),
  }),
  execute: async (args) => {
    return "こんにちは、世界!";
  },
});

これは以下と同等です:

server.addTool({
  name: "download",
  description: "ファイルをダウンロードします",
  parameters: z.object({
    url: z.string(),
  }),
  execute: async (args) => {
    return {
      content: [
        {
          type: "text",
          text: "こんにちは、世界!",
        },
      ],
    };
  },
});

リストを返す

メッセージのリストを返したい場合は、contentプロパティを持つオブジェクトを返せます:

server.addTool({
  name: "download",
  description: "ファイルをダウンロードします",
  parameters: z.object({
    url: z.string(),
  }),
  execute: async (args) => {
    return {
      content: [
        { type: "text", text: "1つ目のメッセージ" },
        { type: "text", text: "2つ目のメッセージ" },
      ],
    };
  },
});

画像の返却

画像のコンテンツオブジェクトを作成するには、imageContentを使用します:

import { imageContent } from "fastmcp";

server.addTool({
  name: "download",
  description: "ファイルをダウンロードします",
  parameters: z.object({
    url: z.string(),
  }),
  execute: async (args) => {
    return imageContent({
      url: "https://example.com/image.png",
    });

    // または...
    // return imageContent({
    //   path: "/path/to/image.png",
    // });

    // または...
    // return imageContent({
    //   buffer: Buffer.from("iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=", "base64"),
    // });

    // または...
    // return {
    //   content: [
    //     await imageContent(...)
    //   ],
    // };
  },
});

imageContent関数は以下のオプションを受け取ります:

  • url: 画像のURL
  • path: 画像ファイルへのパス
  • buffer: バッファとしての画像データ

urlpathbufferのいずれか1つのみを指定する必要があります。

上の例は以下と同等です:

server.addTool({
  name: "download",
  description: "ファイルをダウンロードします",
  parameters: z.object({
    url: z.string(),
  }),
  execute: async (args) => {
    return {
      content: [
        {
          type: "image",
          data: "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=",
          mimeType: "image/png",
        },
      ],
    };
  },
});

ロギング

ツールはコンテキストオブジェクトのlogを使用してクライアントにメッセージをログ出力できます:

server.addTool({
  name: "download",
  description: "ファイルをダウンロードします",
  parameters: z.object({
    url: z.string(),
  }),
  execute: async (args, { log }) => {
    log.info("ファイルをダウンロード中...", {
      url: args.url,
    });

    // ...

    log.info("ファイルをダウンロードしました");

    return "完了";
  },
});

logオブジェクトには以下のメソッドがあります:

  • debug(message: string, data?: SerializableValue)
  • error(message: string, data?: SerializableValue)
  • info(message: string, data?: SerializableValue)
  • warn(message: string, data?: SerializableValue)

エラー

ユーザーに表示されるべきエラーは、UserErrorインスタンスとしてスローする必要があります:

import { UserError } from "fastmcp";

server.addTool({
  name: "download",
  description: "ファイルをダウンロードします",
  parameters: z.object({
    url: z.string(),
  }),
  execute: async (args) => {
    if (args.url.startsWith("https://example.com")) {
      throw new UserError("このURLは許可されていません");
    }

    return "完了";
  },
});

進捗通知

ツールはコンテキストオブジェクトのreportProgressを呼び出すことで進捗を報告できます:

server.addTool({
  name: "download",
  description: "ファイルをダウンロードします",
  parameters: z.object({
    url: z.string(),
  }),
  execute: async (args, { reportProgress }) => {
    reportProgress({
      progress: 0,
      total: 100,
    });

    // ...

    reportProgress({
      progress: 100,
      total: 100,
    });

    return "完了";
  },
});

リソース

リソースは、MCPサーバーがクライアントに提供したいあらゆる種類のデータを表します。これには以下が含まれます:

  • ファイルの内容
  • スクリーンショットや画像
  • ログファイル
  • その他多数

各リソースは一意のURIで識別され、テキストまたはバイナリデータを含むことができます。

server.addResource({
  uri: "file:///logs/app.log",
  name: "アプリケーションログ",
  mimeType: "text/plain",
  async load() {
    return {
      text: await readLogFile(),
    };
  },
});

[!NOTE]

loadは複数のリソースを返すことができます。これは例えば、ディレクトリが読み込まれたときにディレクトリ内のファイルのリストを返すために使用できます。

async load() {
  return [
    {
      text: "1つ目のファイルの内容",
    },
    {
      text: "2つ目のファイルの内容",
    },
  ];
}

loadでバイナリコンテンツを返すこともできます:

async load() {
  return {
    blob: 'base64でエンコードされたデータ'
  };
}

リソーステンプレート

リソーステンプレートを定義することもできます:

server.addResourceTemplate({
  uriTemplate: "file:///logs/{name}.log",
  name: "アプリケーションログ",
  mimeType: "text/plain",
  arguments: [
    {
      name: "name",
      description: "ログの名前",
      required: true,
    },
  ],
  async load({ name }) {
    return {
      text: `${name}のサンプルログ内容`,
    };
  },
});

リソーステンプレート引数の自動補完

リソーステンプレート引数の自動補完を有効にするために、complete関数を提供します:

server.addResourceTemplate({
  uriTemplate: "file:///logs/{name}.log",
  name: "アプリケーションログ",
  mimeType: "text/plain",
  arguments: [
    {
      name: "name",
      description: "ログの名前",
      required: true,
      complete: async (value) => {
        if (value === "サンプル") {
          return {
            values: ["サンプルログ"],
          };
        }

        return {
          values: [],
        };
      },
    },
  ],
  async load({ name }) {
    return {
      text: `${name}のサンプルログ内容`,
    };
  },
});

プロンプト

プロンプトは、サーバーが再利用可能なプロンプトテンプレートとワークフローを定義し、クライアントがユーザーやLLMに簡単に提示できるようにします。これにより、一般的なLLMインタラクションを標準化して共有するための強力な方法を提供します。

server.addPrompt({
  name: "git-commit",
  description: "Gitコミットメッセージを生成します",
  arguments: [
    {
      name: "changes",
      description: "Gitの差分または変更の説明",
      required: true,
    },
  ],
  load: async (args) => {
    return `これらの変更に対する簡潔かつ説明的なコミットメッセージを生成してください:\n\n${args.changes}`;
  },
});

プロンプト引数の自動補完

プロンプトは引数の自動補完を提供できます:

server.addPrompt({
  name: "countryPoem",
  description: "国についての詩を書きます",
  load: async ({ name }) => {
    return `こんにちは、${name}さん!`;
  },
  arguments: [
    {
      name: "name",
      description: "国の名前",
      required: true,
      complete: async (value) => {
        if (value === "日") {
          return {
            values: ["日本"],
          };
        }

        return {
          values: [],
        };
      },
    },
  ],
});

enumを使用したプロンプト引数の自動補完

引数にenum配列を提供すると、サーバーは自動的に引数の補完を提供します。

server.addPrompt({
  name: "countryPoem",
  description: "国についての詩を書きます",
  load: async ({ name }) => {
    return `こんにちは、${name}さん!`;
  },
  arguments: [
    {
      name: "name",
      description: "国の名前",
      required: true,
      enum: ["日本", "フランス", "イタリア"],
    },
  ],
});

認証

FastMCPではカスタム関数を使用してクライアントをauthenticateできます:

import { AuthError } from "fastmcp";

const server = new FastMCP({
  name: "マイサーバー",
  version: "1.0.0",
  authenticate: ({request}) => {
    const apiKey = request.headers["x-api-key"];

    if (apiKey !== '123') {
      throw new Response(null, {
        status: 401,
        statusText: "Unauthorized",
      });
    }

    // ここで返すものは`context.session`オブジェクトでアクセスできます
    return {
      id: 1,
    }
  },
});

これで、ツール内で認証されたセッションデータにアクセスできます:

server.addTool({
  name: "sayHello",
  execute: async (args, { session }) => {
    return `こんにちは、${session.id}さん!`;
  },
});

セッション

sessionオブジェクトはFastMCPSessionのインスタンスであり、アクティブなクライアントセッションを記述します。

server.sessions;

クライアントとサーバー間の1対1通信を可能にするために、各クライアント接続に対して新しいサーバーインスタンスを割り当てます。

型付きサーバーイベント

onメソッドを使用してサーバーから発行されるイベントをリッスンできます:

server.on("connect", (event) => {
  console.log("クライアント接続:", event.session);
});

server.on("disconnect", (event) => {
  console.log("クライアント切断:", event.session);
});

FastMCPSession

FastMCPSessionはクライアントセッションを表し、クライアントとやり取りするためのメソッドを提供します。

FastMCPSessionインスタンスの取得方法については、セッションの例を参照してください。

requestSampling

requestSamplingサンプリングリクエストを作成し、レスポンスを返します。

await session.requestSampling({
  messages: [
    {
      role: "user",
      content: {
        type: "text",
        text: "現在のディレクトリにはどのファイルがありますか?",
      },
    },
  ],
  systemPrompt: "あなたは役立つファイルシステムアシスタントです。",
  includeContext: "thisServer",
  maxTokens: 100,
});

clientCapabilities

clientCapabilitiesプロパティにはクライアント機能が含まれています。

session.clientCapabilities;

loggingLevel

loggingLevelプロパティは、クライアントによって設定されたロギングレベルを記述します。

session.loggingLevel;

roots

rootsプロパティには、クライアントによって設定されたルートが含まれています。

session.roots;

server

serverプロパティには、セッションに関連付けられたMCPサーバーのインスタンスが含まれています。

session.server;

型付きセッションイベント

onメソッドを使用してセッションから発行されるイベントをリッスンできます:

session.on("rootsChanged", (event) => {
  console.log("ルート変更:", event.roots);
});

session.on("error", (event) => {
  console.error("エラー:", event.error);
});

サーバーの実行

MCP-CLIでテスト

サーバーをテストしてデバッグする最速の方法は、fastmcp devを使用することです:

npx fastmcp dev server.js
npx fastmcp dev server.ts

これにより、mcp-cliを使用してターミナルでMCPサーバーをテストおよびデバッグするためのサーバーが実行されます。

MCP Inspectorで検査

もう一つの方法は、公式のMCP Inspectorを使用してWebUIでサーバーを検査することです:

npx fastmcp inspect server.ts

よくある質問

Claude Desktopで使用するには?

ガイド https://modelcontextprotocol.io/quickstart/user に従って、次の設定を追加してください:

{
  "mcpServers": {
    "my-mcp-server": {
      "command": "npx",
      "args": [
        "tsx",
        "/プロジェクトへのパス/src/index.ts"
      ],
      "env": {
        "環境変数名": "値"
      }
    }
  }
}

事例紹介

[!NOTE]

FastMCPを使用したサーバーを開発した場合は、ぜひPR提出して事例として紹介してください!

謝辞