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?

【Typescript】最低限の手順でMCPサーバーを構築するメモ

Last updated at Posted at 2025-04-06

Model Context Protocol (MCP)はLLMアプリケーションとデータソースやツールを標準化された方法で連携させるためのプロトコルです。AIアプリケーションのための「USB-C」のようなものと考えると理解しやすいです(公式より)。

このメモでは、TypeScript SDKを使用してMCPサーバーを最小限のステップで構築する手順をまとめます。

前提環境

  • Node.js: v18.0.0以上
  • TypeScript: v5.0.0以上
  • MCP SDK: v1.8.0以上

1. プロジェクトセットアップ

新しいディレクトリを作成し、必要なパッケージをインストール。

mkdir minimal-mcp-server
cd minimal-mcp-server

npm init -y

npm install @modelcontextprotocol/sdk zod
npm install -D typescript @types/node

パッケージの役割:

  • @modelcontextprotocol/sdk: MCP用TypeScript実装
  • zod: 型安全なスキーマ検証ライブラリ
  • typescript: TSコンパイラ
  • @types/node: Node.js型定義

2. TypeScript設定

tsconfig.jsonを作成。

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "Node16",
    "moduleResolution": "Node16",
    "outDir": "./build",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  },
  "include": ["./**/*"],
  "exclude": ["node_modules"]
}

重要点:

  • ES2022ターゲット
  • Node16モジュール設定
  • 出力先は./build
  • ルートは./src
  • 厳格な型チェック有効

3. package.json設定

package.jsonを編集し、ESMモジュール形式設定とスクリプトを追加。

{
  "name": "minimal-mcp-server",
  "version": "1.0.0",
  "main": "index.js",
  "type": "module", // 追加
  "scripts": {
    "build": "tsc", // 追加
    "start": "node build/index.js" // 追加
  },
  "dependencies": {
    "@modelcontextprotocol/sdk": "^1.8.0",
    "zod": "^3.23.8"
  },
  "devDependencies": {
    "@types/node": "^22.0.2",
    "typescript": "^5.5.4"
  }
}

重要点:

  • "type": "module"でESM形式指定
  • ビルド・実行用スクリプト追加 (build, start)

4. MCPサーバー実装

srcディレクトリを作成しindex.tsを作成。

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

// サーバーインスタンス作成
const server = new McpServer({
  name: "minimal-mcp-server",
  version: "1.0.0",
});

// エコーツール定義
server.tool(
  "echo",
  "入力されたメッセージをそのまま返す簡単なツール",
  {
    message: z.string().describe("エコーするメッセージ"),
  },
  async ({ message }) => {
    return {
      content: [
        {
          type: "text",
          text: `Echo: ${message}`,
        },
      ],
    };
  }
);

// 日時ツール追加
server.tool(
  "get-current-time",
  "現在の日時を取得するツール",
  {},
  async () => {
    const now = new Date();
    return {
      content: [
        {
          type: "text",
          text: `現在の日時: ${now.toLocaleString()}`,
        },
      ],
    };
  }
);

// サーバー起動
async function main() {
  const transport = new StdioServerTransport();
  await server.connect(transport);
  console.log("MCP Server running on stdio");
}

main().catch((error) => {
  console.error("Fatal error:", error);
  process.exit(1);
});

MCPツールの構成要素:

  • 名前:一意の識別子
  • 説明:機能説明
  • パラメータスキーマ:入力パラメータはZodで検証
  • ハンドラ関数:実際の処理

公式の例はZodを使っていますがArkTypeでも可です

5. ビルドと実行

サーバーをビルドして実行。

npm run build
node build/index.js

「MCP Server running on stdio」メッセージが表示されれば成功。

6. テストと検証

MCP Inspectorでテスト。

npx @modelcontextprotocol/inspector node build/index.js

Inspectorが起動し、ツールやリソースが確認できる。

7. LLMクライアント接続

Claude Desktop設定

設定ファイルを編集:

  • MacOS: ~/Library/Application Support/Claude/claude_desktop_config.json
  • Windows: %AppData%\Claude\claude_desktop_config.json
{
  "mcpServers": {
    "minimal-mcp": {
      "command": "node",
      "args": ["/絶対パス/minimal-mcp-server/build/index.js"]
    }
  }
}

Cursor設定

  1. Settings → MCPセクション → 「Add new MCP server」
  2. 入力情報:
    • Name: minimal-mcp
    • Type: command
    • Command: node /絶対パス/minimal-mcp-server/build/index.js

8. 拡張方法

リソース追加

リソースについて、私も十分に理解しているわけではないですが、Claude Desktopではメッセージへの添付などがしやすくなります(プラグのアイコンから)

Screenshot 2025-04-06 at 21.07.45.png

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

// 静的リソース
server.resource(
  "info",
  "info://server",
  async (uri) => ({
    contents: [{
      uri: uri.href,
      text: "このサーバーに関する情報"
    }]
  })
);

// 動的リソース
server.resource(
  "user-info",
  new ResourceTemplate("users://{userId}", { list: undefined }),
  async (uri, { userId }) => ({
    contents: [{
      uri: uri.href,
      text: `ユーザーID: ${userId} の情報`
    }]
  })
);

HTTP/SSEトランスポート

import express from "express";
import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";

const app = express();
const transports = {};

app.get("/sse", async (_, res) => {
  const transport = new SSEServerTransport('/messages', res);
  transports[transport.sessionId] = transport;
  res.on("close", () => {
    delete transports[transport.sessionId];
  });
  await server.connect(transport);
});

app.post("/messages", async (req, res) => {
  const sessionId = req.query.sessionId;
  const transport = transports[sessionId];
  if (transport) {
    await transport.handlePostMessage(req, res);
  } else {
    res.status(400).send('セッションが見つかりません');
  }
});

app.listen(3000, () => {
  console.log("MCP Server running on http://localhost:3000");
});

参考

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?