MCPサーバーとは
MCP(Model Context Protocol)の話になると「サーバーを立てる」「サーバーが提供する」とよく出てきますが、MCP サーバーが実際に何を動かしているのかは意外と整理されていません。OSS の modelcontextprotocol/servers には公式・コミュニティ製のサーバーが揃っており、いずれも JSON-RPC をベースにした素朴なアプリケーションとして実装されています。
MCP サーバーは特別な機械学習基盤ではなく、stdio・SSE・HTTP のいずれかで JSON-RPC メッセージを受け取り、(1) ツール、(2) リソース、(3) プロンプトテンプレートの 3 種を公開する普通のアプリケーションです。実装は TypeScript / Python / Java などの公式 SDK で数十行から書けます。
01.まず結論:JSON-RPC で 3 種を公開するアプリ
MCP サーバーの構造を一文でいうと「JSON-RPC でメッセージを受け取り、Tools・Resources・Prompts の 3 種類のプリミティブを公開するプロセス」です。AI クライアント(Claude Desktop / Claude Code / Cursor など)が、そのプロセスとメッセージをやり取りすることで「外部システムをつなぐ」が実現します。
MCP実務入門|AIエージェントと社内ツールをつなぐ接続標準
本記事は実装の中身に踏み込みます。導入判断・権限境界・運用ステップは別記事で整理しています。
02.MCPサーバーの内部構造
MCP サーバーは 3 層構成で考えると整理しやすくなります。
| 層 | 役割 | 実装の中身 |
|---|---|---|
| トランスポート層 | クライアントとのバイト列のやり取り | stdio(標準入出力) / SSE / Streamable HTTP |
| プロトコル層 | JSON-RPC 2.0 メッセージの解釈 | 公式 SDK(TypeScript / Python / Java など)が担当 |
| 業務ロジック層 | 実際の処理(API 呼び出し、DB 検索、ファイル読み書き) | サーバー作者が自前で書く部分 |
トランスポート層(stdio / SSE / HTTP)
ローカルで動かす MCP サーバーは、ほとんどが stdio です。クライアントが子プロセスとして起動し、標準入出力でメッセージを送受信します。リモートサーバー(社内 SaaS、認証付きシステム)には SSE / Streamable HTTP が使われます。
プロトコル層(JSON-RPC 2.0)
メッセージは JSON-RPC 2.0 形式です。標準的なリクエスト 1 つは以下のような構造になります。
{
"jsonrpc": "2.0",
"id": 42,
"method": "tools/call",
"params": {
"name": "search_customer",
"arguments": { "query": "山田" }
}
}サーバーは同じ id で結果を返します。
{
"jsonrpc": "2.0",
"id": 42,
"result": {
"content": [
{ "type": "text", "text": "顧客ID:1023, 名前:山田太郎" }
]
}
}業務ロジック層
実装者が書く部分です。たとえば「顧客検索ツール」なら、社内 CRM の検索 API を呼び、結果を整形して返します。MCP プロトコル自体は中身を関知しません。
03.3つのプリミティブ:Tools / Resources / Prompts
MCP サーバーが公開できる項目は 3 種類に整理されています。
| プリミティブ | 意味 | 主な用途 | クライアント API |
|---|---|---|---|
| Tools | AI が呼び出す関数・操作 | 検索、計算、CRM 更新、ファイル操作 | tools/list, tools/call |
| Resources | AI が読み込む対象(ファイル・ドキュメント・レコード) | 社内ドキュメント、データベースレコード | resources/list, resources/read |
| Prompts | 事前定義のプロンプトテンプレート | 「議事録要約テンプレ」「障害対応テンプレ」 | prompts/list, prompts/get |
「読む」が Resources、「実行する」が Tools です。ファイル取得を Resources 経由にすると、AI クライアントが取得可否を明示的に判断できます。逆にメール送信や CRM 更新は必ず Tools 側に置きます。書き込み系を Resources にしてはいけません。
04.ライフサイクル:initialize → list → call の実物
クライアントが capabilities と protocolVersion を交換
tools/list, resources/list, prompts/list で公開項目を取得
tools/call などで個別呼び出し。引数を JSON で渡す
戻り値(成功 or エラー)を JSON で受け取る
各ステップは JSON-RPC メッセージ 1 往復です。tools/list は通常初回のみ、tools/call はタスクごとに繰り返されます。
実際のメッセージ例を流れに沿って見ていきます。
① initialize(接続確立)
クライアントが最初に投げる初期化リクエストです。
-> client to server
{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2025-11-25",
"capabilities": {},
"clientInfo": { "name": "claude-desktop", "version": "0.7.0" }
}
}
<- server to client
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"protocolVersion": "2025-11-25",
"capabilities": {
"tools": {},
"resources": {},
"prompts": {}
},
"serverInfo": { "name": "crm-mcp", "version": "1.0.0" }
}
}※ `protocolVersion` は MCP 仕様のリリース日(YYYY-MM-DD 形式)で、2024-11-05 / 2025-03-26 / 2025-06-18 / 2025-11-25 と段階的に更新されてきました。本記事は 2026 年 5 月時点で最新の 2025-11-25 を使っています。クライアントとサーバーが対応バージョンを互いに通知し合い、最も新しい共通バージョンを選ぶネゴシエーション仕様です。
② tools/list(公開ツールの取得)
-> client to server
{ "jsonrpc": "2.0", "id": 2, "method": "tools/list" }
<- server to client
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"tools": [
{
"name": "search_customer",
"description": "顧客名やメールから顧客レコードを検索する(読み取り専用)",
"inputSchema": {
"type": "object",
"properties": {
"query": { "type": "string" }
},
"required": ["query"]
}
}
]
}
}③ tools/call(実行)
-> client to server
{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "search_customer",
"arguments": { "query": "山田 太郎" }
}
}
<- server to client
{
"jsonrpc": "2.0",
"id": 3,
"result": {
"content": [
{ "type": "text", "text": "顧客ID:1023 / 山田太郎 / yamada@example.com" }
],
"isError": false
}
}AI はこの結果を見て、次の判断(さらに別ツールを呼ぶ、ユーザーに回答する、など)を行います。
05.最小実装コード(TypeScript SDK)
公式 TypeScript SDK( modelcontextprotocol/typescript-sdk)を使うと、トランスポートと JSON-RPC は SDK が引き受けるので、業務ロジックだけ書けば済みます。
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: "crm-mcp", version: "1.0.0" },
{ capabilities: { tools: {} } },
);
// ツール一覧を返す
server.setRequestHandler(ListToolsRequestSchema, async () => ({
tools: [
{
name: "search_customer",
description: "顧客名やメールから顧客レコードを検索する(読み取り専用)",
inputSchema: {
type: "object",
properties: { query: { type: "string" } },
required: ["query"],
},
},
],
}));
// ツール実行
server.setRequestHandler(CallToolRequestSchema, async (req) => {
const { name, arguments: args } = req.params;
if (name !== "search_customer") {
return { content: [{ type: "text", text: "unknown tool" }], isError: true };
}
const query = args?.query ?? "";
// ここで実際の CRM API を叩く(疑似コード)
const hit = await crm.findByQuery(query);
return {
content: [{ type: "text", text: `顧客ID:${hit.id} / ${hit.name}` }],
isError: false,
};
});
// stdio で起動
const transport = new StdioServerTransport();
await server.connect(transport);Python SDK でもほぼ同じ構造で実装できます( modelcontextprotocol/python-sdk)。
06.公式・OSS の代表的なサーバー事例
公式リポジトリの modelcontextprotocol/servers に並んでいる代表的なサーバーと、その振る舞いを並べます。これらは MCP サーバーが実務で「何をしているか」の素直なサンプルです。
| サーバー | 公開する Tools / Resources の例 | 振る舞いの中身 |
|---|---|---|
| filesystem | read_file / write_file / list_directory / search_files | AI クライアントが起動時に許可したディレクトリ配下のファイルを操作。書き込み許可は明示する |
| github | search_repositories / create_issue / get_pull_request / merge_pull_request | GitHub REST API のラッパー。トークンは環境変数で渡し、API スコープでさらに制限 |
| slack | list_channels / post_message / search_messages | Slack Bot API のラッパー。bot token とチャンネル ID で範囲を制御 |
| postgres | query(読み取り専用 SQL)/ schema | PostgreSQL に直接接続し、SELECT のみ許可するなどの安全策を実装に組み込み |
| brave-search | brave_web_search / brave_local_search | Brave Search API を呼び、結果を整形して返す |
| puppeteer | navigate / screenshot / click / fill / evaluate | ヘッドレス Chrome を内部で起動し、AI からの指示でブラウザ操作 |
| memory(公式) | create_entities / read_graph / search_nodes | ローカルのナレッジグラフに対する追記・検索。AI 自身の「メモリ」用途 |
上記サーバーはすべて OSS でソースが公開されています。たとえば filesystem サーバーは「許可ディレクトリ内のファイル操作だけ受け付ける」というシンプルな約束で実装されており、コードを読むと「AI クライアントから来た JSON-RPC を fs API に橋渡ししているだけ」だと分かります。MCP サーバーは魔法ではなく、API ラッパー + 権限ガードの薄い層です。
07.トランスポート方式の違いと選び方
| 方式 | 向く用途 | 認証・運用 | 代表例 |
|---|---|---|---|
| stdio | ローカル実行、個人 PC で動く AI クライアント | プロセス起動時の環境変数で認証情報を渡す | Claude Desktop からの filesystem / github サーバー起動 |
| SSE / Streamable HTTP | 社内 SaaS・リモートサーバー | HTTP 認証ヘッダ、OAuth、API キー | 社内認証付き MCP サーバー、共有チームでの利用 |
stdio は「ローカルプロセス同士のやり取り」なので、認証情報をネットワークに流さずに済むのが利点です。一方、複数ユーザーで共有する場合や、社内 SaaS から接続する場合は SSE / HTTP の方が運用しやすくなります。
08.認証・セキュリティ・運用注意
| 観点 | 実装側で必ずやること | 外すと起きること |
|---|---|---|
| 認証情報 | 環境変数 / Secrets Manager から読み込み、ログに出さない | 鍵が AI 出力や監査ログに混入し漏洩 |
| スコープ制限 | GitHub なら repo 単位、Slack なら channel 単位で絞る | 別プロジェクトのデータも読まれてしまう |
| 副作用ツール | 削除・送信系は別ツールとして分離、説明にも明示 | AI が誤呼び出しで本番反映 |
| 入力検証 | JSON Schema + サーバー側で再検証 | AI が捏造した引数で API を不正に叩く |
| 監査ログ | tools/call の name / args / 結果サマリを記録 | 事故時の追跡ができない |
| 失敗時の戻り | isError: true と原因テキストを返す | 無限リトライ・暴走の原因 |
AIセキュリティ・権限設計|エージェントに何を触らせ、何を触らせないか
MCP サーバー側の権限設計と、AI クライアント側の境界設計はセットで考えます。
AIとデータ連携|業務システムと繋ぐ3つの役割と全体像
MCP サーバーが公開する Tools が呼ばれる Tool Use の境界は §02-1 で詳しく整理しています。
AIエージェントの外部接続入門|ツール利用・MCP・RAGの違いと設計図
MCP / Tool Use / RAG の役割分担を全体像で把握できるピラー記事です。
09.よくある質問(FAQ)
MCP サーバーはクラウドに置く必要がありますか?
用途次第です。個人 PC で完結するなら stdio で動くローカルサーバー、複数ユーザー / 社内 SaaS / 認証付きシステムに統合するならリモートの SSE / Streamable HTTP サーバーが向きます。両方とも公式仕様で対応されており、選択は運用要件次第です。
TypeScript / Python 以外でも MCP サーバーを書けますか?
書けます。公式 SDK は TypeScript / Python / Java / Kotlin / C# / Swift などに広がっています。プロトコルは JSON-RPC 2.0 なので、SDK が無い言語でも仕様に従って実装可能です。社内システムの実装言語に合わせて選びます。
Resources と Tools の違いは何ですか?
Resources は「読む対象(ファイル・ドキュメント・レコード)」、Tools は「実行する操作(関数呼び出し)」です。ファイル取得は Resources、ファイル削除や API 呼び出しは Tools。書き込み・送信などの副作用は必ず Tools 側で扱い、Resources で実行しないのが約束です。
MCP サーバーは AI を内部で持っていますか?
持っていません。AI / LLM 本体は AI クライアント(Claude Desktop / Claude Code / Cursor 等)側にあり、MCP サーバーは「外部 API や DB への橋渡し」を担うだけの普通のプロセスです。MCP サーバー単独で AI が動作することはありません。
公式 OSS の MCP サーバーをそのまま本番で使えますか?
汎用サーバー(filesystem / github / slack / postgres など)は社内ガイドライン・コンプライアンスに合うか確認してから採用します。社内独自業務(自社 CRM、独自 API、社内 DB)は、汎用サーバーが存在しないので自社で実装するのが現実的です。
MCP サーバーをデバッグする方法は?
JSON-RPC リクエスト / レスポンスのログを別ファイルに記録するのが基本です。公式の MCP Inspector(@modelcontextprotocol/inspector)を使うと、ブラウザ UI 上で接続テスト・ツール呼び出し・戻り値の可視化ができ、実装中の動作確認が大きく楽になります。
10.まとめ
MCP サーバーは「JSON-RPC でメッセージを受け取り、Tools・Resources・Prompts を公開する普通のアプリケーション」です。トランスポート層・プロトコル層は公式 SDK が引き受け、実装者が書くのは業務ロジック層だけ。最小実装は数十行で、modelcontextprotocol/servers に並ぶ公式 OSS(filesystem / github / slack / postgres / puppeteer / memory など)が「MCP サーバーが実際に何をしているか」のサンプルとして読める状態です。
運用では、認証情報・スコープ・副作用ツール・入力検証・監査ログ・失敗時の戻りの 6 点を実装側でしっかり設計するのが基本です。MCP は接続標準であって安全装置ではない、という前提で組み立てます。
社内向け MCP サーバーの設計・実装を支援します
AI 活用や AI エージェント導入のご相談、PoC、伴走支援をご検討の方は、お気軽にお問い合わせください。
AI・AIエージェント活用 基礎知識集
一覧に戻る →AIの基礎
プロンプト設計
データ連携
- ›AIとデータ連携
- ›MCP 実務入門
- ›MCPサーバーとは(この記事)
- ›RAG 実務入門
- ›Agentic RAG とは
- ›FineTuning / RAG / Promptの使い分け

