2025/08/07

テクノロジー

自作MCPを作ろう

この記事の目次

    はじめに

    「提供されているMCPでだけだと足りない...!」
    「自分 or 自社用にカスタマイズされたMCPを使いたい...!」
    そんな時のために、改めてMCPの構造と作り方を簡単に確認しておこうと思います。

    MCPとは

    Model Context Protocol の略。
    AIが外部のツールやリソースに簡単にアクセスできるやり取りを定義したもの。

    以前であればAPIを毎回生やしてそれを叩いてみるみたいなことが必要なくなります。
    また、AIがアクセスしやすくなるので、コンテキストの節約やコントロールがしやすくなるとかがありそうです。
    (この辺りの説明は最近トレンドなのでもう見飽きましたよね...)

    ですが、今回はMCPの仕組みを理解して、ある程度自分で作れるようになるというところを目指します。

    MCPのドキュメントやリソース類

    MCPの公式ドキュメント: https://modelcontextprotocol.io/introduction
    GitHub: https://github.com/modelcontextprotocol

    MCPのSDK (今回はTypeScriptで書きます)

    では早速作っていきます。

    クイックスタートをやってみる

    TypeScript上に載っているクイックスタートをやってみます。

    準備

    最初にプロジェクトを作ります

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

    package.json と ts-configを修正します。

    // package.json
    {
      "type": "module",
      "bin": {
        "my-mcp-server": "./build/index.js"
      },
      "scripts": {
        "build": "tsc && chmod 755 build/index.js"
      },
      "files": [
        "build"
      ],
      "description": "",
      "dependencies": {
        "@modelcontextprotocol/sdk": "^1.15.0",
         "zod": "^3.25.71"
      },
      "devDependencies": {
        "@types/node": "^24.0.10",
        "typescript": "^5.8.3"
      }
    }
    // tsconfig.json
    {
      "compilerOptions": {
        "target": "ES2022",
        "module": "Node16",
        "moduleResolution": "Node16",
        "outDir": "./build",
        "rootDir": "./src",
        "strict": true,
        "esModuleInterop": true,
        "skipLibCheck": true,
        "forceConsistentCasingInFileNames": true
      },
      "include": ["src/**/*"],
      "exclude": ["node_modules"]
    }

    サーバーの実装

    簡単に足し算をするMCPを作成してみます。

    ↓動作イメージ

    // src/server.ts
    import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
    import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
    import { z } from "zod";
    
    // Create an MCP server
    const server = new McpServer({
      name: "demo-server",
      version: "1.0.0"
    });
    
    // Add an addition tool
    server.registerTool("add",
      {
        title: "Addition Tool",
        description: "Add two numbers",
        inputSchema: { a: z.number(), b: z.number() }
      },
      async ({ a, b }) => ({
        content: [{ type: "text", text: String(a + b) }]
      })
    );
    
    // Add a dynamic greeting resource
    server.registerResource(
      "greeting",
      new ResourceTemplate("greeting://{name}", { list: undefined }),
      { 
        title: "Greeting Resource", // Display name for UI
        description: "Dynamic greeting generator"
      },
      async (uri, { name }) => ({
        contents: [{
          uri: uri.href,
          text: `Hello, ${name}!`
        }]
      })
    );
    
    // Start receiving messages on stdin and sending messages on stdout
    const transport = new StdioServerTransport();
    await server.connect(transport);

    具体的にコードを解説していきます。
    new McpServer でMCPサーバーのインスタンスを作成します。

    import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
    import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
    
    const server = new McpServer({
      name: "demo-server",
      version: "1.0.0"
    });

    次にツールを追加します。
    inputSchemaで、zodで入力値を管理しています。
    今回は、ただ足し算をするだけのツールを追加しています。

    import { z } from "zod";
    
    // Add an addition tool
    server.registerTool("add",
      {
        title: "Addition Tool", // ツールのタイトル
        description: "Add two numbers",// ツールの説明
        inputSchema: { a: z.number(), b: z.number() } // 入力値
      },
      async ({ a, b }) => ({
        content: [{ type: "text", text: String(a + b) }]// 実行関数: 2つの数値を受け取り、その合計を文字列として返す
    
      })
    );

    先ほど追加したコード中で、次に、リソースへの登録をします。
    これを登録すると、AIが greeting://名前 みたいな感じで参照してくれるようになります。(リソースについて)
    ※この後の動作確認では、リソースは検証せず、ツールのみ検証する方法記載しています。リソースとツールを 状況に応じて使い分けることをおすすめします。

    // Add a dynamic greeting resource
    server.registerResource(
      "greeting",
      new ResourceTemplate("greeting://{name}", { list: undefined }), // リソースのURL
      {
        title: "Greeting Resource", // リソースのタイトル
        description: "Dynamic greeting generator" // リソースのディスクリプション
      },
      async (uri, { name }) => ({
        contents: [{
          uri: uri.href,
          text: `Hello, ${name}!`
        }]
      })
    );

    最後にサーバーを実行する部分を書いたら完成です。

    // Start receiving messages on stdin and sending messages on stdout
    const transport = new StdioServerTransport();
    await server.connect(transport);

    動作確認までの準備

    今回はツールまで実行してみようと思います。最初にビルドします。

    npm run build

    build/index.jsが生成されるはずなので、絶対パスをコピーしておきます。

    そうすると、curosrの場合はこんな感じで設定しておきます。これで準備はOKです。

        "my-mcp-server": {
          "command": "node",
          "args": ["${コピーした絶対パス}/build/index.js"]
        }

    cursorのツールの欄を確認すると、こんな感じで追加した、MCPが利用できるようになっているはずです。

    こんな感じで、agentに投げると、mcpを叩いてくれるようになります。

    最後に

    今回は、MCPの構造を確認しながら、簡単なMCPを作ってみました...!
    意外と簡単に作れたので、必要そうなツールは個人的に作っていこうと思います。

    最後まで読んでいただきありがとうございました!

    ※本記事は2025年08月時点の情報です。

    著者:マイナビエンジニアブログ編集部