AIエージェント入門

MCPサーバーをTypeScriptで作る完全ガイド【2026年最新】

MCPサーバーをTypeScriptで作る完全ガイド【2026年最新】

この記事の結論

MCPサーバーをTypeScriptで実装する方法を解説。FastMCPとSDK公式の2アプローチを比較し、Claude Codeへの統合まで30分で完成させるステップを紹介します。

「MCPサーバーって、Pythonじゃないと作れないの?」

TypeScriptのプロジェクトでMCPを使いたいのに、チュートリアルがPython前提のものばかりで困った経験はないでしょうか。実は、TypeScriptでも同等以上のDXでMCPサーバーを構築できます。しかも、長期的な保守性ではTypeScriptに軍配が上がります。

この記事では、TypeScript でMCPサーバーを実装する2つのアプローチ(公式SDK vs FastMCP)を比較し、Claude Codeへの統合まで30分で完成させる手順をコピペ可能なコード付きで解説します。

MCP(Model Context Protocol)を30秒でおさらい

MCP は Anthropic が策定したオープン標準プロトコルです。AIアシスタント(Claude、Cursor、VS Code Copilot等)が外部ツールと会話するための「USBソケット」のような役割を果たします。

MCPサーバーが提供できるのは主に3種類:

  • Tools — LLMが呼び出せる関数(例:天気取得、DB検索)
  • Resources — ファイルやAPIレスポンスなどの読み取り専用データ
  • Prompts — 再利用可能なプロンプトテンプレート

既存のPython版MCPサーバー構築ガイドと合わせて読むと、言語選択の判断材料が揃います。

TypeScript vs Python:どちらで作るべきか

観点 TypeScript Python
型安全性 静的型チェック(コンパイル時エラー検出) 型ヒントは任意
セットアップ速度 やや遅い(ビルドステップ必要) 速い(FastMCPなら即起動)
長期保守性 IDEサポートが厚く、リファクタ安全 大規模になると型管理が煩雑
エコシステム Webサービスとの統合が容易 データサイエンス系ライブラリが豊富
Claude Code連携 公式SDK + FastMCP両対応 FastMCPが特に簡単
推奨ユースケース プロダクション長期運用、Webサービス統合 プロトタイプ、データ処理パイプライン

結論として、「今すぐ試したい」ならPython FastMCPが最速ですが、「チームで長期運用する」なら TypeScript が安全です。本記事ではTypeScript実装を中心に解説します。

【コード集1】公式SDK(@modelcontextprotocol/sdk)での実装

まずは公式 TypeScript SDK を使った基本的なMCPサーバーを作ります。

セットアップ

# プロジェクト初期化
mkdir my-mcp-server && cd my-mcp-server
npm init -y
npm install @modelcontextprotocol/sdk zod
npm install -D typescript @types/node ts-node

# tsconfig.json を作成
npx tsc --init --module nodenext --moduleResolution nodenext --target es2022 --outDir dist

動作環境: Node.js 20+, TypeScript 5.4+

基本的なMCPサーバー(天気情報ツール)

以下は、天気情報を取得するツールを持つMCPサーバーの完全な実装例です。

// src/index.ts
// 注意: 本番環境で使用する前に、必ずテスト環境で動作確認してください。

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";

// MCPサーバーを初期化
const server = new McpServer({
  name: "weather-server",
  version: "1.0.0",
});

// ツールを定義: 天気情報の取得
server.tool(
  "get_weather",
  "指定した都市の現在の天気情報を取得します",
  {
    city: z.string().describe("都市名(例: Tokyo, Osaka)"),
    units: z.enum(["metric", "imperial"]).default("metric"),
  },
  async ({ city, units }) => {
    // 実際の実装では外部APIを呼び出す
    // const apiKey = process.env.WEATHER_API_KEY;
    // const response = await fetch(`https://api.openweathermap.org/...`);

    // デモ用のモックレスポンス
    const temp = units === "metric" ? "22°C" : "72°F";
    return {
      content: [
        {
          type: "text",
          text: JSON.stringify({
            city,
            temperature: temp,
            condition: "晴れ",
            humidity: "60%",
            timestamp: new Date().toISOString(),
          }),
        },
      ],
    };
  }
);

// リソースを定義: 対応都市一覧
server.resource(
  "supported-cities",
  "mcp://weather-server/cities",
  async (uri) => ({
    contents: [
      {
        uri: uri.href,
        mimeType: "application/json",
        text: JSON.stringify({
          cities: ["Tokyo", "Osaka", "Kyoto", "Sapporo", "Fukuoka"],
        }),
      },
    ],
  })
);

// STDIOトランスポートで起動(Claude Code/Desktop用)
async function main() {
  const transport = new StdioServerTransport();
  await server.connect(transport);
  console.error("Weather MCP Server running on stdio");
}

main().catch(console.error);

ポイント: `console.error` でログを出力しているのは意図的です。STDIOトランスポートは stdin/stdout をMCPプロトコルの通信に使うため、デバッグログは stderr に向ける必要があります。

// package.json に追加
{
  "scripts": {
    "build": "tsc",
    "start": "node dist/index.js"
  }
}

【コード集2】FastMCP(TypeScript版)での実装

FastMCP にはPython版だけでなく、TypeScript版も存在します。よりシンプルなAPIで、ボイラープレートを大幅に削減できます。

# FastMCP TypeScript版のインストール
npm install fastmcp zod
// src/server.ts
// FastMCP TypeScript版 — 公式SDKより簡潔に書ける
// 注意: 本番環境で使用する前に、必ずテスト環境で動作確認してください。

import { FastMCP } from "fastmcp";
import { z } from "zod";

const server = new FastMCP({
  name: "My MCP Server",
  version: "1.0.0",
});

// ツール追加がシンプル
server.addTool({
  name: "calculate",
  description: "2つの数値の四則演算を実行します",
  parameters: z.object({
    a: z.number().describe("1つ目の数値"),
    b: z.number().describe("2つ目の数値"),
    operation: z.enum(["add", "subtract", "multiply", "divide"]),
  }),
  execute: async ({ a, b, operation }) => {
    const results: Record = {
      add: a + b,
      subtract: a - b,
      multiply: a * b,
      divide: b !== 0 ? a / b : NaN,
    };
    return String(results[operation]);
  },
});

// HTTP Streaming(本番リモート展開用)にも対応
server.start({
  transportType: "stdio", // ローカル開発用
  // transportType: "httpStream", // 本番用
  // port: 8080,
});

公式SDK vs FastMCP の選択基準:

  • ツールを5個以上追加する予定 → FastMCPのシンプルAPIが管理しやすい
  • 低レベルのプロトコル制御が必要 → 公式SDK
  • Cloudflare Workers等エッジ環境 → FastMCP(エッジランタイム対応済み)

【コード集3】Claude Codeへの統合

作成したMCPサーバーをClaude Codeに接続します。2つの方法があります。

方法A: CLIコマンドで登録(推奨)

# ビルドしてからClaude Codeに追加
npm run build

# グローバル登録(全プロジェクトで使用可能)
claude mcp add weather-server -- node /path/to/dist/index.js

# 環境変数ありの場合
claude mcp add weather-server 
  --env WEATHER_API_KEY=your-key 
  -- node /path/to/dist/index.js

# 登録確認
claude mcp list

方法B: プロジェクト設定ファイルで管理

// .mcp.json(プロジェクトルート)
{
  "mcpServers": {
    "weather-server": {
      "command": "node",
      "args": ["/path/to/dist/index.js"],
      "env": {
        "WEATHER_API_KEY": "${WEATHER_API_KEY}"
      }
    }
  }
}

`.mcp.json` をプロジェクトルートに置くと、そのディレクトリで `claude` コマンドを実行したときに自動的にMCPサーバーが起動します。チームでの共有に最適です。

FastMCP版を Claude Code に登録する場合

# FastMCP CLIで自動セットアップ(v2.10.3+)
fastmcp install claude-code server.py

# 手動で追加する場合
claude mcp add my-server -- node dist/server.js

Streamable HTTP:本番リモート展開のセットアップ

ローカルSTDIOではなく、チーム全員が使えるリモートMCPサーバーを立てる場合のコード例です。

// src/remote-server.ts — HTTPSで公開するMCPサーバー
// 注意: 本番環境で使用する前に、必ずテスト環境で動作確認してください。

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
import express from "express";
import { z } from "zod";

const app = express();
app.use(express.json());

const server = new McpServer({ name: "remote-mcp", version: "1.0.0" });

// ツール定義(省略)
server.tool("ping", "疎通確認", {}, async () => ({
  content: [{ type: "text", text: "pong" }],
}));

// MCP エンドポイント
app.all("/mcp", async (req, res) => {
  const transport = new StreamableHTTPServerTransport({
    sessionIdGenerator: undefined, // ステートレスモード
  });
  res.on("close", () => transport.close());
  await server.connect(transport);
  await transport.handleRequest(req, res, req.body);
});

const PORT = process.env.PORT ?? 8080;
app.listen(PORT, () => {
  console.log(`MCP Server listening on port ${PORT}`);
});

OAuth 2.1 認証を加えることで、本番環境でのセキュアな公開も可能です。詳細は MCP公式ドキュメント を参照してください。

セキュリティと運用のチェックリスト

チェック項目 対策
APIキーのハードコード禁止 process.env.API_KEYを使い、.envをgitignoreに追加
SSRF(サーバーサイドリクエストフォージェリ) URLを受け取るツールでは許可リストでドメインを制限
最小権限の原則 ツールは必要最小限の権限のみ要求。ファイルシステムへのアクセスは必要なパスのみ
入力検証 Zodスキーマで全入力を型安全に検証(サイズ制限も設定)
認証(リモートサーバー) OAuth 2.1 + スコープ付きトークン。APIキーのみは非推奨
ログ記録 ツール呼び出しと結果をsterrで記録(PII含む引数はマスク)

【要注意】よくある失敗パターンと回避策

失敗1: console.log でデバッグしてMCPが動かない

❌ STDIOサーバーで console.log を使う
⭕ 必ず console.error に変える

なぜ重要か: STDIOトランスポートは stdout をMCPプロトコルのデータ通信に使います。console.log で余分なデータが流れると、プロトコルパーサーが壊れてサーバーが無反応になります。

失敗2: ツールの戻り値の形式が間違っている

❌ 単純な文字列を返す: return "結果"
⭕ content配列を返す:

return {
  content: [{ type: "text", text: "結果" }],
};

なぜ重要か: MCPプロトコルはコンテンツブロック形式を要求します。型エラーにならないためにもTypeScriptの型チェックを活用しましょう。

失敗3: ビルドせずにTypeScriptファイルを直接実行しようとする

claude mcp add server -- node src/index.ts
npm run build && claude mcp add server -- node dist/index.js

回避策: 開発中は ts-node で直接実行できますが、本番(Claude Code登録)では必ずコンパイル済みのJSファイルを使いましょう。

失敗4: 環境変数のロードタイミング問題

.env ファイルを自動読み込みと仮定してAPIキーを参照
dotenv を使って明示的にロード、またはclaude mcpの--envフラグで渡す

// 正しい環境変数のロード
import "dotenv/config"; // または: import dotenv from "dotenv"; dotenv.config();
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";

参考・出典

まとめ:今日から始める3つのアクション

  1. 今日やること: 公式SDK版の「天気サーバー」コードをローカルで動かし、claude mcp add で Claude Code に接続する(所要30分)
  2. 今週中: 業務で使いたいAPIを1つ選び、MCPツールとして実装する。スプレッドシート読み取り・社内DB検索・Slack投稿など
  3. 今月中: Streamable HTTP でリモートサーバー化し、チーム全員のClaude Codeで共有。開発生産性の変化を測定する

あわせて読みたい:


この記事はAIgent Lab編集部がお届けしました。AIエージェントの設計・開発でお困りのことがあれば、Uravationのお問い合わせフォームからご相談ください。

Need help moving from reading to rollout?

この記事を読んで導入イメージが固まってきた方へ

Uravationでは、AIエージェントの要件整理、PoC設計、社内導入、研修まで一気通貫で支援しています。

この記事をシェア

X Facebook LINE

※ 本記事の情報は2026年4月時点のものです。サービスの料金・仕様は変更される可能性があります。最新情報は各サービスの公式サイトをご確認ください。

関連記事