WAT Note(III).

ローカル環境でMCPサーバーを立てて利用する

Tatsuroh Wakasugi
Tatsuroh Wakasugi

最近「MCP サーバー」という言葉をよく見かけるようになりました。

ChatGPT や Cursor と外部データソースをつなぐ新しい仕組みですが、実際にどう動いているのか気になったので、今回は自分のローカル環境で MCP サーバーを立て、Cursor から使ってみたので、それについて書いていきます。

MCP とは

MCP(Model Context Protocol)は、AI アプリケーション(Cursor や ChatGPT など)を外部システムに接続するためのプロトコルです。

MCP でできること

MCP を使えば、AI アプリケーションはデータソース(ローカルファイル、データベースなど)、ツール(検索エンジン、計算機など)、ワークフロー(専門的な処理など)に接続できます。

具体的には

  • ローカルのファイルシステムへのアクセス
  • データベースへのクエリ実行
  • Slack、GitHub、Google Drive などの外部サービスとの連携
  • 天気情報やニュースなどの API 呼び出し
  • 独自の業務システムとの統合

などが行えます。

MCP の仕組み

MCP は、以下の 3 つのコンポーネントで構成されています。

MCP サーバー

外部のデータやツールへのアクセスを提供する側です。例えば

  • ファイルシステムにアクセスするサーバー
  • GitHub のリポジトリ情報を取得するサーバー
  • データベースにクエリを実行するサーバー

などがあります。

MCP クライアント

AI アプリケーション(Cursor、ChatGPT など)が MCP サーバーと通信するためのインターフェースです。

MCP プロトコル

クライアントとサーバーが共通の「言語」で話すためのルールです。これにより、異なる開発者が作ったサーバーでも、どのクライアントからでも使えるようになります。

ハンズオン:最小の MCP サーバーを作って Cursor から利用する

あなたのローカル PC で

「Cursor からローカルの MCP サーバー(stdio 方式)を使う」

という体験をします。

前提

  • Node.js(v18 以上)
  • npm または pnpm
  • Cursor

プロジェクト作成

今回の MCP サーバー用の Node.js プロジェクトを作成します。

最初に記載しておきますが、今回作成するプロジェクトの構成は以下の通りです。

mcp-demo
├── .cursor/
|   └── mcp.json
├── node_modules/
├── package-lock.json
├── package.json
├── server.ts
└── tsconfig.json

まず、以下のコマンドを実行してください。

mkdir mcp-demo
cd mcp-demo
npm init -y
npm i @modelcontextprotocol/sdk zod
npm i -D typescript tsx @types/node
npx tsc --init

tsconfig.json は、以下の通りに設定してください。(要点のみ記載)

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
    "strict": true,
    "esModuleInterop": true,
    "outDir": "dist"
  },
  "include": ["server.ts"]
}

package.json の scripts を以下の通り定義します。

{
  "scripts": {
    "dev": "tsx server.ts",
    "build": "tsc",
    "start": "node dist/server.js"
  }
}

MCP サーバーファイルを作成

MCP サーバーのファイルである server.ts を作ります。

このサーバーは 「今日の日付を返すだけ」という超シンプルな MCP サーバーです。

McpServer と stdio トランスポート(StdioServerTransport)で、入力なしのツール current_date を 1 つだけ公開します。

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

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

// 入力なし→現在日時を返す最小ツール
server.registerTool(
  "current_date",
  {
    title: "Current Date Tool",
    description: "Return current date/time and weekday (ja-JP)",
    inputSchema: {},
    outputSchema: { now: z.string(), weekday: z.string() },
  },
  async () => {
    const d = new Date();
    const output = {
      now: d.toISOString(),
      weekday: d.toLocaleDateString("ja-JP", { weekday: "long" }),
    };
    return {
      content: [{ type: "text", text: JSON.stringify(output) }],
      structuredContent: output,
    };
  }
);

// stdio で待ち受け(Cursor などがサブプロセスとして起動)
async function main() {
  const transport = new StdioServerTransport();
  await server.connect(transport);
}
main().catch((e) => {
  console.error("MCP server failed:", e);
  process.exit(1);
});

起動

作成が終わったら、ローカルで動作確認をしてみましょう。

とりあえず起動できれば OK です(実行自体は Cursor 側から行います)

npm run dev

Cursor 側の設定

Cursor は グローバル または プロジェクト単位で MCP サーバーを登録できます。

ここではプロジェクト単位(.cursor/mcp.json)で設定します。

プロジェクト直下にフォルダを作って設定ファイルを置きます。

mkdir -p .cursor

.cursor/mcp.json を以下のように作成します。

{
  "mcpServers": {
    "local-date-server": {
      "command": "node",
      "args": ["node_modules/.bin/tsx", "server.ts"],
      "transport": { "type": "stdio" },
      "env": {}
    }
  }
}

Cursor で利用する

作成したプロジェクト mcp-demo を Cursor で開きます。

右下または左下にある 「Settings」アイコン をクリックし、設定画面を開きます。

検索バーに「MCP」または「Model Context Protocol」と入力します。

作成したサーバー名が表示されるはずなので、OFF になっていたらチェックを ON にして下さい。

新しいチャットで、例えば「current_date ツールを実行して」

と指示すると、local-date-server が起動され、MCP ツールが呼ばれます。

(実行時には「Run Tool」ボタンの承認が求められることがあります。)

出力されれば完了です!

ハンズオンでの全体構成

今回行ったハンズオンでのシステム構成は以下の通りになります。

ここでまず、Cursor ではあなたがチャットに「current_date ツールを実行して」と入力すると

  • Cursor 内の LLM(例: GPT-4)に解釈させる
  • LLM が Chat の文脈から「これは current_date ツールを呼ぶべき」と判断する
  • Cursor の MCP クライアントが .cursor/mcp.json を読む
  • そこに書かれているコマンドを使って server.ts を起動
  • MCP サーバーに対して Model Context Protocol に従ってリクエスト送信

をしています。

今回 Cursor は「MCP クライアント」 の役割も担っています。

次に、server.ts の中で実行されているのが MCP サーバーで、以下の3行が MCP サーバーの中核になります。

const server = new McpServer({ name: "local-date-server", version: "1.0.0" });
const transport = new StdioServerTransport();
await server.connect(transport);

流れとしては以下のようになります。

  • registerTool() でツールを登録 ("current_date")
  • クライアント(Cursor)がリクエストを送信
  • McpServer がその JSON を受信・パース
  • 内部で current_date 関数を実行
  • JS の Date から現在時刻を生成
  • 結果を JSON 形式で stdout に返却

また、MCP プロトコルとはここでは JSON-RPC 2.0 をベースにした通信プロトコルで、

LLM クライアントと外部サービスをつなぐための標準化フォーマットになります。

ざっくり書くとクライアントからサーバーには以下のようなフォーマットで送られ、

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "current_date",
    "arguments": {}
  }
}

サーバーからクライアントには以下のようなフォーマットで送られます。

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "content": [
      {
        "type": "text",
        "text": "{\"now\":\"2025-11-01T12:00:00Z\",\"weekday\":\"土曜日\"}"
      }
    ],
    "structuredContent": {
      "now": "2025-11-01T12:00:00Z",
      "weekday": "土曜日"
    }
  }
}

このやり取りが、stdio 経由のストリーム(バイト列)で流れています。


今回は簡単で基本的な例をお見せしましたが、もう少し実用的な外部サービスや外部の API との連携などもやりたいと感じているので、今後広げて実践していきたいですね。

最後に注意点として、MCP サーバーは LLM が直接 API キーを扱わないため安全ですが、社内システムとつなぐ場合は認可設定を慎重にしましょう。