OpenCodeでMCPサーバーを自作する方法:カスタムツール追加ガイド

OpenCodeのMCPサーバーをTypeScriptで自作し、カスタムツールを追加する方法を解説。実用的なコード例と手順で拡張機能を実現。

OpenCodeMCPサーバー自作カスタムツールTypeScript拡張2026/5/25

はじめに

OpenCodeは、AIアシスタントと連携してコード生成や編集を効率化するツールですが、標準機能だけでは足りない場面もあります。そこで役立つのがMCP(Model Context Protocol)サーバーの自作です。MCPサーバーを自作することで、OpenCodeにカスタムツールや外部サービスとの連携機能を追加できます。本記事では、TypeScriptを使用してMCPサーバーを一から作成し、OpenCodeにカスタムツールを追加する手順を詳しく解説します。

MCPサーバーとは

MCP(Model Context Protocol)は、AIモデル(OpenCodeのAIアシスタント)と外部ツールやデータソースを接続するためのプロトコルです。MCPサーバーを自作することで、以下のようなことが可能になります。

  • 独自のAPI呼び出し
  • ファイルシステム操作
  • データベースクエリ
  • 外部サービスの統合
  • OpenCodeは標準でいくつかのMCPサーバーをサポートしていますが、カスタムツールを追加するには自分でサーバーを実装する必要があります。

    前提条件

  • Node.js 18以上がインストール済み
  • npmまたはyarnが使用可能
  • OpenCodeがインストール済み(CLIツール)
  • TypeScriptの基礎知識
  • ステップ1:プロジェクトのセットアップ

    まずは新しいディレクトリを作成し、TypeScriptプロジェクトを初期化します。

    mkdir my-mcp-server
    cd my-mcp-server
    npm init -y
    npm install typescript @types/node ts-node --save-dev
    npm install @modelcontextprotocol/sdk
    

    @modelcontextprotocol/sdkはMCPサーバーを構築するための公式SDKです。次にTypeScriptの設定ファイルを作成します。

    npx tsc --init
    

    tsconfig.jsonを開き、outDir./distrootDir./srcに設定します。

    ステップ2:基本的なMCPサーバーの実装

    src/index.tsを作成し、以下のコードを記述します。これは最小限のMCPサーバーで、"hello"というツールを提供します。

    import { Server } from "@modelcontextprotocol/sdk/server/index.js";
    import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
    import {
      CallToolRequestSchema,
      ListToolsRequestSchema,
    } from "@modelcontextprotocol/sdk/types.js";
    

    // サーバーインスタンスを作成 const server = new Server( { name: "my-mcp-server", version: "1.0.0", }, { capabilities: { tools: {}, }, } );

    // ツール一覧を返すハンドラー server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: [ { name: "hello", description: "挨拶を返すツール", inputSchema: { type: "object", properties: { name: { type: "string", description: "名前", }, }, required: ["name"], }, }, ], }; });

    // ツール実行ハンドラー server.setRequestHandler(CallToolRequestSchema, async (request) => { if (request.params.name === "hello") { const name = request.params.arguments?.name as string; return { content: [ { type: "text", text: こんにちは、${name}さん!, }, ], }; } throw new Error(Unknown tool: ${request.params.name}); });

    // 標準入出力トランスポートでサーバーを起動 const transport = new StdioServerTransport(); await server.connect(transport);

    ステップ3:カスタムツールの追加

    次に、実際に役立つカスタムツールを追加しましょう。例として、ファイルの内容を読み取るツールread_fileを実装します。

    src/index.tsを編集し、ListToolsRequestSchemaのハンドラー内のtools配列に新しいツール定義を追加します。

    tools: [
      {
        name: "hello",
        description: "挨拶を返すツール",
        inputSchema: {
          type: "object",
          properties: {
            name: {
              type: "string",
              description: "名前",
            },
          },
          required: ["name"],
        },
      },
      {
        name: "read_file",
        description: "指定されたファイルの内容を読み取ります",
        inputSchema: {
          type: "object",
          properties: {
            path: {
              type: "string",
              description: "ファイルのパス",
            },
          },
          required: ["path"],
        },
      },
    ],
    

    次に、CallToolRequestSchemaのハンドラーにread_fileの処理を追加します。

    if (request.params.name === "hello") {
      // 既存の処理
    } else if (request.params.name === "read_file") {
      const path = request.params.arguments?.path as string;
      try {
        const fs = await import("fs/promises");
        const content = await fs.readFile(path, "utf-8");
        return {
          content: [
            {
              type: "text",
              text: content,
            },
          ],
        };
      } catch (error: any) {
        return {
          content: [
            {
              type: "text",
              text: エラー: ${error.message},
            },
          ],
          isError: true,
        };
      }
    }
    

    同様に、他にも便利なツールを追加できます。例えば、現在の日時を返すget_current_timeや、簡単な計算を行うcalculateなどが考えられます。

    ステップ4:ビルドと実行

    TypeScriptをコンパイルします。

    npx tsc
    

    これでdist/index.jsが生成されます。サーバーをテストするには、以下のコマンドで直接実行できます。

    node dist/index.js
    

    ただし、MCPサーバーは標準入出力を介して通信するため、通常はOpenCodeから呼び出します。

    ステップ5:OpenCodeへの接続

    OpenCodeの設定ファイル(通常は~/.opencode/config.json)を編集し、MCPサーバーを追加します。

    {
      "mcpServers": {
        "my-mcp-server": {
          "command": "node",
          "args": ["/absolute/path/to/my-mcp-server/dist/index.js"],
          "env": {}
        }
      }
    }
    

    パスは絶対パスで指定してください。設定後、OpenCodeを再起動すると、AIアシスタントがカスタムツールを認識し、使用できるようになります。

    高度なカスタマイズ

    ツールの入力スキーマを詳細に設定する

    JSON Schemaに従って、より複雑な入力スキーマを定義できます。例えば、read_fileにエンコーディングオプションを追加する場合:

    inputSchema: {
      type: "object",
      properties: {
        path: { type: "string" },
        encoding: { type: "string", enum: ["utf-8", "ascii", "base64"] },
      },
      required: ["path"],
    }
    

    リソースの提供

    ツールだけでなく、リソースを提供することもできます。リソースは読み取り専用のデータで、AIが参照できます。

    import { ListResourcesRequestSchema, ReadResourceRequestSchema } from "@modelcontextprotocol/sdk/types.js";
    

    server.setRequestHandler(ListResourcesRequestSchema, async () => ({ resources: [ { uri: "file:///config.json", name: "設定ファイル", mimeType: "application/json", }, ], }));

    server.setRequestHandler(ReadResourceRequestSchema, async (request) => { if (request.params.uri === "file:///config.json") { const content = JSON.stringify({ key: "value" }); return { contents: [ { uri: request.params.uri, mimeType: "application/json", text: content, }, ], }; } throw new Error("Resource not found"); });

    エラーハンドリングの改善

    ツール実行時にエラーが発生した場合、isError: trueを設定してエラーメッセージを返すことで、AIが適切に処理できます。

    トラブルシューティング

    サーバーが認識されない

  • OpenCodeの設定ファイルのパスが正しいか確認
  • サーバーが実行可能かどうか、直接起動してテスト
  • ログを確認(~/.opencode/logs/
  • TypeScriptのエラー

  • @modelcontextprotocol/sdkのバージョンが最新か確認
  • tsconfig.jsonmoduleResolutionnodeに設定
  • まとめ

    OpenCodeでMCPサーバーを自作することで、AIアシスタントの機能を大幅に拡張できます。TypeScriptとSDKを使えば、複雑なツールも比較的簡単に実装可能です。今回紹介した手順をベースに、あなたのワークフローに合わせたカスタムツールを開発してみてください。

    次のステップとして、外部APIを呼び出すツールやデータベース操作ツールなどに挑戦すると、さらにOpenCodeの活用範囲が広がります。

    🛡️
    ContentLens 品質チェック済み

    この記事はAI品質チェッカーContentLensで分析されています。記事を貼り付けるだけで誰でも無料で品質スコアを確認できます。