AIエージェントの実用化において、「AIモデルにいかにして社内の独自データやシステムへ安全にアクセスさせるか」という課題は珍しくありません。プロンプトエンジニアリングによる静的なコンテキスト提供には限界があり、動的なデータ取得やシステム操作を可能にする「ツール連携」が不可欠です。
本記事では、Anthropic社が提唱するオープンスタンダード「Model Context Protocol(MCP)」に焦点を当て、エンジニア向けに実践的なツール連携の手法を解説します。Node.jsを用いたカスタムMCPサーバーの実装を通じて、既存の社内APIをAIに接続するためのアーキテクチャ設計とコードレベルでの実装力を身につけることを目指します。
本チュートリアルのゴール:MCPが解決する「データ連携の壁」
AIモデルと外部データを接続する際、従来の手法が抱えていた課題を整理し、MCPがどのように「共通規格」として開発工数を削減するのかを解説します。
なぜ今、Model Context Protocol(MCP)が必要なのか
これまでのAIエージェント開発では、各LLMプロバイダー(OpenAI、Anthropicなど)が提供する独自のFunction Calling(ツール呼び出し)APIに合わせて、個別のミドルウェアや統合コードを記述する必要がありました。このアプローチには、以下のような構造的な問題が存在します。
- ベンダーロックインのリスク:特定のLLMのインターフェースに強く依存するため、モデルの切り替えや複数モデルの併用時に多大な改修コストが発生します。
- 車輪の再発明:データベースへのクエリ実行やファイル操作といった一般的な機能であっても、プロジェクトごとに連携ロジックをゼロから書き直すケースが散見されます。
- セキュリティの境界が曖昧:AIモデルと社内システムが密結合になりやすく、アクセス権限の制御や監査ログの取得が複雑化します。
これらの課題を解決するために登場したのがMCPです。MCPは、AIクライアント(ホスト)と外部データソース(サーバー)の間の通信を標準化するオープンプロトコルです。MCPを採用することで、一度開発したMCPサーバーは、Claude Desktopだけでなく、CursorなどのMCP互換のIDEや、LangChain、LlamaIndexといったフレームワークからも再利用可能になります。つまり、「N対N」の複雑な統合を「1対1」のシンプルな標準インターフェースに置き換えることができるのです。
本ガイドで構築する連携システムの全体像
本チュートリアルでは、最終的に「自社固有のAPI(例:社内リソース管理システム)をAIから直接呼び出し、情報を取得・操作できる状態」を目指します。具体的には、以下のアーキテクチャを構築します。
- Host(クライアント):Claude Desktop(将来的なIDEでの活用も見据えた標準的なホスト環境)
- MCP Server:Node.jsと公式の
@modelcontextprotocol/sdkを使用して自作するカスタムサーバー - Data Source:ローカルのSQLiteデータベース、またはモック化された社内API
この構成を体験することで、MCPの通信レイヤーがどのようにJSON-RPCメッセージを処理し、AIの推論プロセスに外部データを提供するのか、その根底にある設計思想を肌で理解できるはずです。
Step 1:開発環境のセットアップとMCPアーキテクチャの理解
ここからは、具体的な環境構築手順と、MCPの基本構造について解説します。単なるツールの導入手順にとどまらず、各コンポーネントが論理的にどう連携しているのかを把握することが重要です。
必要なツール(Node.js, Claude Desktop)の準備
カスタムMCPサーバーを開発・テストするために、以下の環境を準備します。バージョン等の最新要件については、必ず公式ドキュメントを参照してください。
- Node.js:サーバーサイドの実装に使用します。LTS(長期サポート)バージョンの利用を推奨します。
- パッケージマネージャー:
npmまたはpnpm。 - Claude Desktop:開発したMCPサーバーをテストするためのホストアプリケーションとして機能します。
環境が整ったら、MCPサーバーのプロジェクトディレクトリを作成し、初期化を行います。
mkdir my-mcp-server
cd my-mcp-server
npm init -y
npm install @modelcontextprotocol/sdk
npm install -D typescript @types/node tsx
tsconfig.json を適切に設定し、TypeScriptを用いた型安全な開発環境を構築します。AIとの連携において、インターフェースの型定義を厳密に行うことは、予期せぬエラーを防ぐ上で極めて重要です。
MCPの「ホスト・サーバー・リソース」の関係性
コードを書き始める前に、MCPの主要な概念を整理しておきましょう。
- Host(ホスト):Claude DesktopなどのAIアプリケーション。ユーザーからのプロンプトを受け取り、必要に応じてMCPサーバーと通信します。
- Client(クライアント):Hostの内部に存在し、サーバーとの実際のプロトコル通信(JSON-RPC)を担います。
- Server(サーバー):外部システムとの接続を抽象化し、以下の3つの主要な機能(Capabilities)をクライアントに公開します。
- Resources(リソース):ファイルやデータベースのレコードなど、AIが読み取ることができる静的なデータ。
- Tools(ツール):APIの実行やデータの書き込みなど、AIが実行できる関数(アクション)。本記事の主眼です。
- Prompts(プロンプト):再利用可能なプロンプトのテンプレート。
今回は、社内APIとの連携を想定し、「Tools」の機能にフォーカスして実装を進めます。
Step 2:既存のMCPサーバーを活用したクイック連携(Google Drive / SQLite)
ゼロからカスタムサーバーを開発する前に、既に公開されている公式・コミュニティ提供のMCPサーバーを利用して、連携の仕組みを体感することをおすすめします。
公式・コミュニティ提供サーバーの導入手順
Anthropicやオープンソースコミュニティは、SQLite、PostgreSQL、Google Drive、GitHubなど、一般的なデータソース向けのMCPサーバーを多数公開しています。これらのサーバーは、多くの場合 npx コマンドを通じて直接実行可能です。
例えば、ローカルのSQLiteデータベースにAIを接続する場合、特別なコードを書くことなく、設定ファイルにサーバーの起動コマンドを追記するだけで完了します。
config.jsonの編集と接続確認
Claude Desktopをホストとして使用する場合、設定ファイル(claude_desktop_config.json)を編集してMCPサーバーを登録します。設定ファイルの配置場所はOSによって異なります(最新のパスは公式ドキュメントで確認してください)。
以下は、SQLite MCPサーバーを登録する設定例です。
{
"mcpServers": {
"sqlite-db": {
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-sqlite",
"/path/to/your/database.db"
]
}
}
}
この設定を保存し、Claude Desktopを再起動すると、AIモデルは指定されたSQLiteデータベースのスキーマを読み取り、必要に応じてSQLクエリを生成・実行してデータを取得できるようになります。
「設定ファイルを1つ書き換えるだけで、AIの能力が外部システムへと拡張される」というこの体験こそが、MCPの強力な抽象化の恩恵です。
Step 3:【実践】Node.jsによるカスタムMCPサーバーの自作
既存のサーバーでは対応できない自社固有のAPIや業務ロジックをAIに接続するためには、カスタムMCPサーバーの実装が必要です。ここからが本チュートリアルのメインパートです。
MCP SDKを使用したサーバーの基本コード
TypeScriptを使用して、カスタムMCPサーバーの基盤を構築します。まず、サーバーのインスタンスを作成し、標準入出力(stdio)を使用した通信トランスポートを設定します。stdioトランスポートは、ホストプロセスがサブプロセスとしてサーバーを起動する際に最も一般的に使用される方式です。
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: "internal-api-server",
version: "1.0.0",
},
{
capabilities: {
tools: {}, // ツール機能を使用することを宣言
},
}
);
なぜこの記述が必要なのでしょうか。Server クラスは、MCPのプロトコル仕様に基づくJSON-RPCのルーティングやエラーハンドリングを隠蔽し、開発者がビジネスロジックに集中できるようにするためのラッパーです。capabilities で tools を宣言することで、クライアントに対して「このサーバーはツール実行の機能を提供している」と通知します。
社内APIを「ツール」として定義する実装方法
次に、AIが利用可能な「ツール(関数)」を定義し、AIからのリクエストを受け取って社内APIを叩くロジックを実装します。
MCPでは、主に2つのリクエストをハンドリングする必要があります。
ListToolsRequestSchema:利用可能なツールのリストと、その引数のスキーマ(JSON Schema形式)をクライアントに返す。CallToolRequestSchema:クライアントからのツール実行要求を受け取り、処理を実行して結果を返す。
以下は、架空の社内顧客API(https://api.example.com/v1/customers)から顧客情報を検索するツールを実装する例です。
// 1. 利用可能なツールの定義
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: "search_customer",
description: "社内データベースから顧客情報を検索します。",
inputSchema: {
type: "object",
properties: {
query: {
type: "string",
description: "検索キーワード(企業名や担当者名)",
},
},
required: ["query"],
},
},
],
};
});
// 2. ツール実行要求のハンドリング
server.setRequestHandler(CallToolRequestSchema, async (request) => {
if (request.params.name === "search_customer") {
const query = String(request.params.arguments?.query);
try {
// 実際の社内APIの呼び出し(フェッチ処理)
const response = await fetch(`https://api.example.com/v1/customers?q=${encodeURIComponent(query)}`, {
headers: {
"Authorization": `Bearer ${process.env.INTERNAL_API_KEY}`
}
});
if (!response.ok) {
throw new Error(`API Error: ${response.statusText}`);
}
const data = await response.json();
// AIに結果を返す
return {
content: [
{
type: "text",
text: JSON.stringify(data, null, 2),
},
],
};
} catch (error) {
return {
content: [
{
type: "text",
text: `検索中にエラーが発生しました: ${error}`,
},
],
isError: true,
};
}
}
throw new Error("Unknown tool");
});
// サーバーの起動
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("Internal API MCP Server running on stdio");
}
main().catch(console.error);
この実装のポイントは、inputSchema によってAIに対して「どのような引数が必要か」を明確に定義している点です。AIモデルはこのスキーマを解析し、ユーザーのプロンプトから適切な引数を抽出して CallToolRequestSchema を送信します。開発者は、受け取った引数を用いて外部APIを呼び出し、その結果をテキスト(または画像等)としてAIに返却するだけで、複雑な連携が完了します。
Step 4:セキュリティと運用を考慮した実装のベストプラクティス
実務環境(特にエンタープライズ用途)でMCPを運用する場合、単に動くコードを書くだけでは不十分です。AIエージェントに社内システムへのアクセス権を与える性質上、厳密なセキュリティ設計が求められます。
APIキーの安全な管理方法
カスタムMCPサーバー内で外部APIを呼び出す際、APIキーやシークレットをハードコードすることは厳禁です。必ず環境変数(.envファイルなど)を通じて注入する設計にしてください。
Claude DesktopからMCPサーバーを起動する場合、claude_desktop_config.json の env プロパティを使用して環境変数を渡すことができます。
{
"mcpServers": {
"internal-api": {
"command": "npx",
"args": ["tsx", "/path/to/my-mcp-server/index.ts"],
"env": {
"INTERNAL_API_KEY": "your-secure-api-key"
}
}
}
}
AIによる予期せぬ挙動を防ぐバリデーション
AIは確率的なモデルであるため、常に期待通りの引数を生成するとは限りません。ツール側で入力を盲信せず、厳格なバリデーションを行う必要があります。
TypeScript環境であれば、Zod などのスキーマ検証ライブラリを導入し、request.params.arguments の型と内容を実行前に検証するアプローチが有効です。
また、「実行権限の設計」も重要です。データの「読み取り(Read)」ツールは比較的安全ですが、データの「書き込み(Write/Update/Delete)」ツールをAIに公開する場合は、重大なリスクを伴います。書き込み操作に関しては、AIが直接実行するのではなく、「操作の提案」にとどめ、最終的な実行は人間が承認する(Human-in-the-Loop)ワークフローを組み込むことを強く推奨します。
トラブルシューティングと次のステップ:高度なAIエージェント構築へ
MCPサーバーの開発中に行き詰まりやすいポイントとその解決策、そして今後の展望について解説します。
よくある接続エラー(PATH問題・依存関係)
MCPサーバーが正常に起動しない場合、多くは設定ファイルの問題か、環境のPATH設定に起因します。
- コマンドが見つからない:
commandに指定したnpxやnodeが、ホストアプリケーション(Claude Desktop等)の実行環境から参照できないケースがあります。フルパス(例:/usr/local/bin/node)を指定することで解決する場合があります。 - ログの確認:Claude Desktopの場合、専用のログファイル(
mcp.logなど)が出力されます。接続に失敗した際は、まずこのログを確認し、サーバーの標準エラー出力(console.error)にどのようなメッセージが出ているかを特定してください。 - 単体デバッグ:Anthropicが提供する
mcp-inspectorなどのデバッグツールを使用すると、ホストアプリケーションを介さずに、ブラウザ上でMCPサーバーとの直接通信をテストできます。開発時はこのインスペクターを活用し、サーバー単体での動作確認を先行させることが効率的です。
MCPを活用した自動化ワークフローの構想
本ガイドでは、単一の社内APIをツールとして公開する基本的な実装を解説しました。しかし、MCPの真の価値は、複数のMCPサーバーを組み合わせた「自律的なAIエージェント」の構築にあります。
例えば、「社内データベースから顧客情報を検索するサーバー」「Slackに通知を送るサーバー」「Google Driveから提案書を読み込むサーバー」を同時にホストに接続したとします。AIモデルは、これらのツールを自律的に使い分け、「顧客情報を検索し、過去の提案書を参照しながら新たなドラフトを作成し、担当者にSlackでレビュー依頼を送る」といった複雑なワークフローを一気通貫で実行できるようになります。
LangChainやLlamaIndexといったLLMオーケストレーションフレームワークもMCPのサポートを進めており、今後は「プロンプトを書く」ことから「適切なツール群(MCPサーバー)を設計・提供する」ことへ、エンジニアの役割がシフトしていくでしょう。
自社への適用を検討する際は、まずは限定的な読み取り専用のデータソースから接続を試し、AIがどのようにツールを活用するかを観察することから始めるのが効果的です。実際の動作環境でテストを行うことで、導入リスクを軽減し、よりセキュアで実用的なシステム構築への道筋が見えてきます。デモ環境の構築やトライアルを通じて、MCPがもたらす新しいデータ連携の可能性をぜひ体感してください。
コメント