1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

MCP初学者が仕組みを理解するためにカスタムサーバーを作ってみる

1
Last updated at Posted at 2026-06-26

MCP(Model Context Protocol)とは

AIエージェントと外部システムを接続するためのオープンソース標準規格です。

MCPを使用することで、ClaudeやChatGPTなどのAIエージェントは、データソース(ローカルファイル、データベースなど)、ツール(検索エンジンなど)、ワークフロー(特殊なプロンプトなど)に接続し、必要な情報にアクセスしてタスクを実行できるようになります。

よくUSB-Cポートに例えられ、多様なデバイスを共通の規格で接続するように、MCPもAIと外部システムを共通の規格で接続しています。

Gemini_Generated_Image_du8759du8759du87.png

カスタムサーバーを作ってみる

理解を深めるため、実際に作ってみようと思います。

作るもの:

  • Figmaの情報を取得するMCPサーバー
    • get_figma_image: 指定したノードの画像をダウンロードし、output/フォルダに保存するツール
    • generate_component: 指定したノードから HTML+CSS Modulesのコンポーネントを生成し、output/フォルダに保存するツール
  • Claude Codeなど、MCP対応クライアントから呼び出せる

開発環境:

  • Node.js: v24.15.0
  • TypeScript: v6.0.3
  • Claude Code: v2.1.145

成果物

コードの全容はこちらです。
使い方はREADMEをご確認ください。

コードの解説

ここからはMCPサーバーに関わるコードを抜粋して解説していきます。

Figma APIに関わるコードは解説しませんので、気になる方はこちらの公式ドキュメントを参考にしてください。

ディレクトリ構成

figma-mcp/
├── src/
│   ├── index.ts          # ツール登録
│   ├── figma-client.ts   # Figma API クライアント
│   └── tools/            # ツールごとにファイルを分割
│       ├── get-figma-image.ts
│       └── generate-component.ts
├── dist/                 # ビルド出力
├── output/               # 生成された画像・コンポーネントの保存先
├── .env                  # 環境変数(gitignore済み)
└── .mcp.json             # MCP サーバー設定

.mcp.json

MCPサーバーの起動設定を定義するファイルです。
プロジェクトルートに.mcp.jsonを置いて、現在のプロジェクトのみMCPをインストールしています。

{
  "mcpServers": {
    "figma-mcp": {
      "command": "node",
      "args": ["dist/index.js"],
      "env": {}
    }
  }
}

command - サーバー起動を実行するコマンド
args - 引数(サーバーを起動させるファイルのパス)
env - 環境変数(今回は空)

index.ts

サーバー起動・ツール登録をしているファイルです。
公式のREADME通りに実装しています。

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";

MCPの公式SDKが提供するクラス。
MCPサーバーを作るための土台です。

import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";

MCPサーバーとクライアントの通信手段を実装するクラス。
Stdio = 標準入出力(stdin/stdout)を使って通信します。

// McpServerのインスタンスを作成
const server = new McpServer({ name: "figma-mcp", version: "1.0.0" });

// ツールを登録(importした関数を実行)
registerGetFigmaImage(server);
registerGenerateComponent(server);

// サーバー立ち上げ
async function main() {
  const transport = new StdioServerTransport();
  await server.connect(transport);
  console.error("Figma MCP サーバーが起動しました");
}

// 実行
main().catch((err) => {
  console.error(err);
  process.exit(1);
});

ツールを管理しやすくするため、ツール個別の処理は/tools配下に切り出しており、今回はimportした関数を実行しています。

tools/get-figma-image.ts

ツールの詳細を定義しているファイルです。

コンポーネント生成ツールを定義している tools/generate-component.ts もMCPツール登録の構造は同じなので割愛します。コールバック内部はそれぞれ異なる処理を行っており、詳細はリポジトリでご確認ください。

import { z } from "zod";

TypeScript向けの型定義・バリデーションライブラリです。
ツール登録の際、入力パラメータ(inputSchema)をzodで定義しています。
これにより「型安全なバリデーション」と「AIへのパラメータ説明の自動生成」が同時に行えます。

export function registerGetFigmaImage(server: McpServer) {
  server.registerTool(
    "get_figma_image",
    {
      description: "Figma の URL から画像を取得して保存します",
      inputSchema: {
        figmaUrl: z.url().describe("Figma の URL(例: https://www.figma.com/file/<KEY>/...?node-id=<ID>)"),
        format: z.enum(["png", "svg", "jpg"]).default("png").describe("画像フォーマット"),
        scale: z.number().min(0.5).max(4).default(2).describe("スケール倍率(0.5〜4, Retina は 2)"),
      }
    },
    async ({ figmaUrl, format, scale }) => {
      ...
    }
  );

ツールを登録するための関数です。

第一引数: ツールの名前
第二引数: ツール設定
 description: 自然言語で機能の説明
 inputSchema: 入力パラメータ
第三引数: コールバック関数(引数にはinputSchemaで定義したパラメータが展開されて渡ってくる)

return {
  content: [
    {
      type: "text",
      text: `✅ 画像を保存しました\n\n保存パス: ${filePath}\nノード ID: ${normalizedNodeId}\nフォーマット: ${format} (x${scale})`,
    },
  ],
};

contentは必須で返す必要があります。
今回はText Contentのみを返していますが、他にも色々なContentを返すことができます。
詳しくはこちらをご確認ください。

コードの解説は以上となります。

MCPサーバー内部の処理の流れ

ここからはMCPサーバーが呼び出されたとき、内部でどのような処理が行われているのか深掘りしました。

StdioServerTransportzodの役割を整理しながら見ていきます。

処理の流れ

①AIがパラメータを決定し、JSON形式でMCPサーバーに送信
 ↓
②StdioServerTransportがstdin経由で受け取り、オブジェクトに変換
 ↓
③zodがバリデーション
 ↓
④コールバック関数実行 → 外部API通信
 ↓
⑤結果をcontentにまとめてreturn
 ↓
⑥StdioServerTransportがstdout経由でAIに返す

②StdioServerTransportがstdin経由で受け取り、オブジェクトに変換

StdioServerTransportは、MCPサーバーとクライアントの通信手段を実装するクラスでした。

AIから送られてきたJSONをstdin経由で受け取り、MCPサーバーが扱えるオブジェクトに変換します。

③zodがバリデーション

zodは、TypeScript向けの型定義・バリデーションライブラリでした。

MCPサーバーでは主に2つの役割を担っています。

1. バリデーション

StdioServerTransportがオブジェクトに変換した値を、zodがバリデーションします。

// 分かりやすくコードを簡略化
inputSchema: {
  figmaUrl: z.url().describe("Figma の URL"),
  format: z.enum(["png", "jpg"]).describe("画像フォーマット"),
  scale: z.number().min(1).max(4).describe("画像のスケール"),
}

例えばscale: 10といった範囲外の数値が渡ってきた場合、zodがAIにエラーを返します。AIはエラーを受け取ると、値を修正して再度ツールを呼び出します。

もしzodがない場合、不正な値がコールバック関数に渡されてしまい、外部APIがエラーや意図しない結果を返してきます。自分でzodを使わずバリデーションを書くことはできますが、zodを使うことでより簡潔に型安全なバリデーションが書けます。

2. AIへのパラメータ説明の自動生成

zodで定義したスキーマは、SDKによって自動的にJSONスキーマに変換されます。

// zodで書いたスキーマ
scale: z.number().min(1).max(4).describe("画像のスケール")

// SDKが自動変換したJSONスキーマ
{
  "type": "number",
  "minimum": 1,
  "maximum": 4,
  "description": "画像のスケール"
}

このJSONスキーマはAIへの参考情報として渡され、AIが「scaleには1〜4の数値を入れるんだな」と理解し、ツールを正しく呼び出してくれます。
.describe()に書いた説明文もここで使用されます。

最後に

思っていたより少ないコードでMCPサーバーを構築できました。
APIさえ提供されていれば、自分好みのツールを作れるのがMCPの魅力だと感じます。
ぜひ試してみてください。

参考文献

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?