MCPのstdioとStreamable HTTPの違い|ローカル・リモート構成の選び方

MCPのstdioとStreamable HTTPの違い|ローカル・リモート構成の選び方 AI開発

MCPサーバーを開発するときは、クライアントとの通信方式としてstdioまたはStreamable HTTPを選択します。

どちらを選んでも、MCPサーバーが提供するTools、Resources、Promptsといった機能は基本的に同じです。異なるのは、サーバーの起動方法、メッセージの送受信経路、認証方法、複数ユーザーへの対応、デプロイ方法です。

結論として、ユーザーのパソコン上で動作し、ローカルファイルやローカルアプリへアクセスするMCPサーバーにはstdioが向いています。

クラウドAPIや社内システムを複数ユーザーへ提供する場合は、Streamable HTTPが向いています。

MCPの公式アーキテクチャでも、stdioを使うローカルMCPサーバーは通常一つのMCPクライアントへ接続し、Streamable HTTPを使うリモートMCPサーバーは複数のクライアントへサービスを提供する構成として説明されています。

この記事では、stdioとStreamable HTTPの仕組みを比較し、ローカル・リモート構成の選び方を解説します。WindowsでMCPサーバーが起動しない場合の切り分けはMCPサーバーが起動しない原因|Windowsのパス・環境変数・stdioを確認、GitHubやDBへの接続方法はClaude Code MCP完全ガイドもあわせてご覧ください。

スポンサーリンク
  1. MCPのトランスポートとは
  2. stdioとは
  3. stdioではクライアントがサーバーを起動する
  4. stdioの通信内容
  5. Streamable HTTPとは
  6. Streamable HTTPのストリーミングとは
  7. 旧HTTP+SSE方式との違い
  8. stdioとStreamable HTTPの最も大きな違い
  9. stdioはローカル専用なのか
  10. Streamable HTTPはリモート専用なのか
  11. stdioが向いている構成
  12. Streamable HTTPが向いている構成
  13. インストール方法の違い
  14. 更新方法の違い
  15. 認証方法の違い
  16. stdioの認証情報はプロセスごとに分けやすい
  17. Streamable HTTPではユーザーの分離が必要
  18. セキュリティの違い
  19. Streamable HTTPではHTTPSを使用する
  20. プロセス管理の違い
  21. 複数クライアントへの対応
  22. 状態を持つツールの設計
  23. レイテンシの違い
  24. オフライン環境での違い
  25. ログと監視の違い
  26. 障害範囲の違い
  27. TypeScriptでstdioサーバーを作る
  28. TypeScriptでStreamable HTTPサーバーを作る
  29. 一つのツール実装を両方の方式で使う
  30. MCP Inspectorで両方をテストする
  31. ローカルファイルを扱うならstdioを選ぶ
  32. クラウドAPIをラップするならStreamable HTTPを選ぶ
  33. 一人だけが使う外部API連携ならどちらを選ぶか
  34. 社内専用MCPサーバーの選び方
  35. デスクトップアプリへ同梱する場合
  36. サーバーレス環境での選び方
  37. stdioからStreamable HTTPへ移行する場合
  38. Streamable HTTPからstdioへ移行する場合
  39. 両方を提供する方法
  40. stdioを選ぶ基準
  41. Streamable HTTPを選ぶ基準
  42. MCPのstdioとStreamable HTTPに関するよくある質問
  43. まとめ

MCPのトランスポートとは

MCPでは、LLMアプリケーションとMCPサーバーがJSON-RPC形式のメッセージを交換します。

モデルが利用できるツールを取得するときはtools/list、ツールを実行するときはtools/callなどのメッセージが送信されます。

このJSON-RPCメッセージを、クライアントとサーバーの間でどのように運ぶかを定義するのがトランスポートです。

2026年7月28日版のMCP仕様では、標準トランスポートとしてstdioとStreamable HTTPが定義されています。

stdioでは、クライアントが起動した子プロセスの標準入力と標準出力を使います。Streamable HTTPでは、一つのMCPエンドポイントへHTTP POSTを送り、JSONまたはリクエスト単位のSSEストリームで応答を受け取ります。

トランスポートが異なっても、ツールの名前、入力スキーマ、実行処理といったMCPサーバーの中核ロジックは共通化できます。

stdioとは

stdioはStandard Input and Outputの略で、プロセスの標準入力と標準出力を通信に使用する方式です。

MCPクライアントは、設定に書かれたコマンドを子プロセスとして起動します。

mcp.json
{
  "mcpServers": {
    "local-tools": {
      "type": "stdio",
      "command": "node",
      "args": [
        "C:/mcp/local-tools/dist/index.js"
      ]
    }
  }
}

この設定では、MCPクライアントが内部的に次のようなコマンドを実行します。

内部の処理イメージ
node C:/mcp/local-tools/dist/index.js

サーバーが起動すると、クライアントはJSON-RPCメッセージをサーバーのstdinへ書き込みます。

サーバーはメッセージを読み取り、結果をstdoutへ出力します。

MCP 2026年7月28日仕様では、一つのJSON-RPCメッセージを一行として送信し、改行をメッセージの区切りとして使用します。stdoutには有効なMCPメッセージ以外を出力できません。

stdioではクライアントがサーバーを起動する

stdioの大きな特徴は、MCPサーバーをユーザーが別途起動しなくてもよいことです。

Claude DesktopやVS CodeなどのMCPホストが必要になった時点でサーバーを起動し、接続が不要になればプロセスを終了できます。

Webサーバーのように、常時起動するサービスを別途用意する必要はありません。

MCPクライアントごとにサーバープロセスが作られるため、プロセスのライフサイクルとMCP接続のライフサイクルがほぼ一致します。

サーバープロセスが終了すれば接続も終了し、クライアントが再接続すると新しいプロセスが起動します。

stdioの通信内容

stdioでは、クライアントからサーバーへのメッセージがstdinへ送られます。

サーバーからクライアントへのメッセージはstdoutへ送られます。

ログはstderrへ出力します。

良い例
console.error(
  "MCPサーバーを起動しました。",
);

次のコードは使用できません。

悪い例
console.log(
  "MCPサーバーを起動しました。",
);

console.log()はstdoutへ文字列を出力するため、クライアントが起動メッセージをJSON-RPCとして解析しようとします。

その結果、Unexpected tokenis not valid JSONなどのエラーが発生します。

MCP仕様では、サーバーがstderrへ情報、デバッグ、エラーログを出力することは認められています。クライアントも、stderrへの出力があるだけでサーバーエラーと判断すべきではないとされています。

Streamable HTTPとは

Streamable HTTPは、MCPサーバーを独立したHTTPサービスとして稼働させる方式です。

MCPクライアントは、設定されたURLへHTTPリクエストを送信します。

mcp.json
{
  "mcpServers": {
    "remote-tools": {
      "type": "http",
      "url": "https://api.example.com/mcp"
    }
  }
}

サーバーは、通常のWeb APIと同じようにクラウド、VPS、社内サーバー、コンテナ環境などへデプロイできます。

一つのデプロイ済みMCPサーバーを、複数のユーザーや複数のMCPクライアントから利用できます。

2026年7月28日仕様では、サーバーは一つのMCPエンドポイントを公開し、クライアントはJSON-RPCメッセージごとにHTTP POSTを送信します。

サーバーは、一つのJSONオブジェクトまたはリクエスト単位のSSEストリームで応答します。

Streamable HTTPのストリーミングとは

Streamable HTTPという名前から、すべての通信で常時ストリームを維持する仕組みを想像するかもしれません。

しかし、通常の短いツール実行では、サーバーが一つのJSONレスポンスを返して通信を終了できます。

長いツール実行、進捗通知、複数のメッセージが必要な処理では、レスポンスをtext/event-streamとして返し、SSEで複数のイベントを送信できます。

クライアントは、JSONレスポンスとSSEレスポンスの両方に対応する必要があります。

2026年7月28日仕様では、SSEストリームは基本的に一つのリクエストへ対応します。サーバーからの関連通知などを送信したあと、最終的なJSON-RPCレスポンスを送信してストリームを終了します。

旧HTTP+SSE方式との違い

MCPの古い記事やサンプルでは、HTTP+SSEまたはSSE Transportという名前が使われていることがあります。

HTTP+SSEは2024年11月5日版のMCP仕様で使われていた方式です。

Streamable HTTPは2025年3月26日版で、HTTP+SSEの後継として導入されました。

さらに、2026年7月28日版ではStreamable HTTPの仕組みが変更され、GETストリームとプロトコルレベルのセッションが削除されました。現在は、各JSON-RPCメッセージを自己完結したHTTP POSTとして送信する構成になっています。

古いサンプルに次のようなコードがある場合は、現在のSDKへそのまま移植できない可能性があります。

旧形式
import {
  SSEServerTransport,
} from "@modelcontextprotocol/sdk/server/sse.js";

TypeScript SDK v2ではSSEServerTransportが削除されており、リモートサーバーはStreamable HTTPへ移行するよう案内されています。WebSocketもMCPの標準トランスポートではなく、v2の標準クライアントではローカルにstdio、リモートにStreamable HTTPを使用します。

stdioとStreamable HTTPの最も大きな違い

stdioは、クライアントがサーバープロセスを起動します。

Streamable HTTPは、クライアントとは独立したサーバーをあらかじめ起動しておきます。

stdioではサーバーの場所をコマンドと引数で指定します。

mcp.json
{
  "type": "stdio",
  "command": "node",
  "args": [
    "C:/mcp/server/dist/index.js"
  ]
}

Streamable HTTPではURLを指定します。

mcp.json
{
  "type": "http",
  "url": "https://api.example.com/mcp"
}

この違いによって、インストール方法、認証、更新、スケーリング、障害対応が大きく変わります。

stdioはローカル専用なのか

stdioは主にローカルMCPサーバーで使用されます。

MCP公式のアーキテクチャでも、Claude Desktopがローカルのファイルシステムサーバーを起動する構成がstdioの代表例として紹介されています。

ただし、MCPの機能として「ローカルファイルしか扱えない」という制限があるわけではありません。

stdioで起動したMCPサーバーから、外部のWeb APIやクラウドデータベースへ接続することもできます。

たとえば、ユーザーのパソコン上でstdioサーバーを起動し、環境変数からAPIキーを読み込んでGitHub APIへ接続できます。

この場合、MCPサーバー自体はローカルで動きますが、取得するデータはリモートにあります。

Streamable HTTPはリモート専用なのか

Streamable HTTPも、必ずインターネットへ公開しなければならないわけではありません。

開発中は、次のようなローカルURLで起動できます。

ローカルのブラウザアプリ、別プロセス、コンテナからMCPサーバーへ接続したい場合は、同じパソコン上でもStreamable HTTPが適しています。

ただし、ローカルだけで完結する単一クライアントの構成では、ポート管理やHTTP認証が不要なstdioのほうが簡単です。

「stdioはローカル、Streamable HTTPはリモート」は実用的な判断基準ですが、技術上の絶対的な制限ではありません。

stdioが向いている構成

stdioは、ユーザーのパソコンにあるファイル、アプリケーション、コマンド、開発環境へアクセスするサーバーに向いています。

たとえば、特定フォルダのファイルを検索するMCPサーバー、ローカルのGitリポジトリを操作するサーバー、SQLiteデータベースを参照するサーバー、開発用CLIを実行するサーバーが該当します。

MCPクライアントと同じユーザー権限でプロセスを起動できるため、既存のファイル権限やOSのアクセス制御を利用できます。

インターネットへポートを公開しないため、外部からHTTPエンドポイントを攻撃される範囲もありません。

ただし、MCPサーバーへ広いファイルアクセスやコマンド実行権限を与える場合は、ローカルであっても安全とは限りません。

ツールごとにアクセス可能なディレクトリやコマンドを制限する必要があります。

Streamable HTTPが向いている構成

Streamable HTTPは、複数ユーザーへ共通の機能を提供するサーバーに向いています。

たとえば、SaaSの顧客情報を検索するMCPサーバー、社内ナレッジベースへ接続するサーバー、クラウドストレージを操作するサーバー、外部APIをMCPツールとして提供するサーバーが該当します。

一つのサーバーを更新すれば、接続するすべてのユーザーへ新しい機能や修正を提供できます。

ユーザーごとにNode.jsやPython、依存パッケージをインストールしてもらう必要がありません。

MCP公式の開発ガイドでも、クラウドAPIをラップするサーバーでは、インストール不要で一つのデプロイから全ユーザーへ提供でき、OAuthフローも利用しやすいStreamable HTTPが基本の選択肢として案内されています。

インストール方法の違い

stdioでは、MCPサーバーを利用する各パソコンに実行環境とサーバー本体が必要です。

Node.js製のサーバーなら、Node.js、npmパッケージ、ビルド済みJavaScriptなどを配置します。

ユーザーが10人いれば、原則として10台のパソコンへ導入する必要があります。

Streamable HTTPでは、サーバーをクラウドなどへ一度デプロイし、ユーザーはURLを登録します。

サーバー側の依存関係はデプロイ環境だけにあればよく、ユーザーのパソコンにNode.jsがなくても接続できます。

ローカル環境のセットアップを減らしたい場合は、Streamable HTTPが有利です。

更新方法の違い

stdioサーバーを更新する場合は、各ユーザーのローカルファイルやnpmパッケージを更新する必要があります。

ユーザーごとに異なるバージョンが残ると、同じツールでも挙動が異なる可能性があります。

自動アップデート機能を用意する方法もありますが、MCPサーバーとは別に配布と更新の仕組みが必要です。

Streamable HTTPでは、サーバー側を更新すれば、基本的にすべてのクライアントへ反映されます。

不具合修正やツール追加を集中管理できるため、チームやサービスとして運用しやすくなります。

一方、サーバー側の変更が全ユーザーへ同時に影響するため、バージョニング、段階的リリース、ロールバックの仕組みが必要です。

認証方法の違い

stdioでは、MCPサーバーがローカルプロセスとして動作するため、APIキーやトークンは環境変数またはクライアント設定から受け取るのが基本です。

mcp.json
{
  "mcpServers": {
    "github-tools": {
      "type": "stdio",
      "command": "node",
      "args": [
        "C:/mcp/github/dist/index.js"
      ],
      "env": {
        "GITHUB_TOKEN": "${GITHUB_TOKEN}"
      }
    }
  }
}

MCPの認可仕様でも、stdioではHTTP向けの認可仕様を使用せず、環境変数などから認証情報を取得するよう定められています。

Streamable HTTPでは、HTTPヘッダーにアクセストークンを付けて認証できます。

ユーザー固有のデータや操作を提供する場合は、MCPのOAuth 2.1ベースの認可仕様へ対応する方法があります。

認証ヘッダー
Authorization: Bearer access_token

HTTPベースのMCPサーバーでは、ユーザー同意、アクセストークン、スコープ、トークン更新などを扱えます。

複数ユーザーの権限を区別したい場合は、Streamable HTTPのほうが適しています。

stdioの認証情報はプロセスごとに分けやすい

stdioでは、サーバープロセスごとに異なる環境変数を渡せます。

ユーザーAのクライアントから起動したプロセスにはユーザーAのトークン、ユーザーBのプロセスにはユーザーBのトークンを渡せます。

サーバー側で複数ユーザーのセッションを同時に管理する必要がありません。

ただし、設定ファイルへAPIキーを直接書くと、平文で保存される可能性があります。

OSの資格情報ストア、秘密情報管理ツール、クライアントが提供する安全な認証機能を利用することが重要です。

Streamable HTTPではユーザーの分離が必要

Streamable HTTPサーバーは複数ユーザーから同時に利用される可能性があります。

ツール処理で使用する認証情報、キャッシュ、会話状態、データベース接続をユーザーごとに分離しなければなりません。

サーバー全体で一つの変数に現在のユーザー情報を保存すると、同時実行時に別ユーザーの値で上書きされる危険があります。

悪い例
let currentUserId: string | null = null;

このようなグローバル状態は避け、HTTPリクエストから取得した認証情報をツール実行のコンテキストへ渡します。

src/request-context.ts
type RequestContext = {
  userId: string;
  accessToken: string;
  tenantId: string;
};

データベース検索でも、必ずuserIdtenantIdによるアクセス制御を適用します。

セキュリティの違い

stdioはネットワークポートを公開しないため、HTTPサーバー特有の攻撃を受けにくい構成です。

一方、MCPクライアントがサーバープロセスへ渡す権限は強力になる可能性があります。

ローカルファイルを読み書きするサーバーでは、アクセス可能なルートディレクトリを制限します。

シェルコマンドを実行するツールでは、ユーザー入力をそのままコマンド文字列へ結合しないようにします。

Streamable HTTPでは、通常のWeb APIと同じ対策に加えて、MCP仕様で定められたセキュリティ対策が必要です。

2026年7月28日仕様では、すべての接続でOriginヘッダーを検証し、不正なOriginにはHTTP 403を返す必要があります。ローカルでHTTPサーバーを動かす場合は、0.0.0.0ではなく127.0.0.1へバインドすることが推奨されています。適切な認証を実装することも求められています。

Streamable HTTPではHTTPSを使用する

インターネットや社内ネットワークを経由するMCPサーバーでは、HTTPSを使用します。

HTTPのままアクセストークンやツール引数を送ると、通信経路で内容を盗み見られる可能性があります。

TLSの終端をリバースプロキシやクラウドのロードバランサーで行う場合でも、MCPサーバーまでの内部通信と信頼境界を確認します。

認証だけでなく、ユーザーごとの認可、レート制限、監査ログ、入力サイズ制限も必要です。

プロセス管理の違い

stdioでは、MCPクライアントがサーバープロセスを管理します。

クライアントを終了すると、子プロセスも終了するのが基本です。

サーバーがクラッシュした場合、クライアントが再起動または再接続を行える場合があります。

Streamable HTTPでは、MCPサーバーを独立したサービスとして管理します。

Node.jsのプロセスマネージャー、Docker、Kubernetes、サーバーレス環境、クラウドプラットフォームなどを使用します。

ヘルスチェック、再起動、デプロイ、監視、ログ収集をサーバー運用側で用意する必要があります。

複数クライアントへの対応

stdioは、通常一つのクライアントプロセスと一つのサーバープロセスを接続します。

同じサーバー機能をClaude DesktopとVS Codeの両方で利用すると、それぞれが別のサーバープロセスを起動する可能性があります。

各プロセスは独立しているため、状態を共有しにくい一方、ユーザー間のデータ混入を避けやすくなります。

Streamable HTTPは、一つの独立したサーバーで複数のクライアント接続を処理できます。

同時接続数が増えた場合は、複数インスタンスへ水平スケールできます。

2026年7月28日仕様ではプロトコルレベルのセッションが削除され、各HTTPリクエストを自己完結させやすくなったため、従来よりロードバランサーで別インスタンスへ振り分けやすい構成になっています。

状態を持つツールの設計

stdioでは、一つのプロセス内に一時的な状態を保持できます。

ローカル状態の例
const openFiles =
  new Map<string, FileHandle>();

クライアントとの接続が続く限り、この状態を再利用できます。

ただし、プロセスが再起動すれば状態は失われます。

Streamable HTTPでは、特定のサーバーインスタンスのメモリへユーザー状態を保存すると、水平スケールや再起動時に問題になります。

必要な状態はデータベース、Redis、オブジェクトストレージなどへ保存するか、明示的なIDをツールの引数として受け渡します。

ツール引数でIDを渡す例
{
  "browser_id": "browser_123",
  "url": "https://example.com"
}

2026年7月28日版MCPでは、プロトコル自体がステートレスになっても、アプリケーション固有のIDをツール結果として返し、後続のツール呼び出しで再利用できます。

レイテンシの違い

stdioでは、同じパソコン上のプロセス間でデータを送受信します。

ネットワーク接続、DNS解決、TLSハンドシェイクといった処理がないため、通信部分の遅延を小さくできます。

ただし、ツール自体が外部APIへ接続する場合は、そのネットワーク遅延が発生します。

Streamable HTTPでは、MCPクライアントとサーバー間のネットワーク遅延が追加されます。

サーバーが別の地域にある場合、ツール呼び出しごとに往復時間が増えます。

ユーザーに近いリージョンへ配置する、HTTP接続を効率化する、不要なツール呼び出しを減らすといった対策が必要です。

一方、各ユーザーのパソコンで重い処理を実行するより、高性能なクラウドサーバーへ集約したほうが全体として速くなる場合もあります。

オフライン環境での違い

stdioサーバーがローカルデータだけを扱う場合、インターネット接続がなくても動作できます。

ローカルのファイル検索、コード解析、SQLite検索などが該当します。

Streamable HTTPは、基本的にサーバーへ到達できるネットワーク接続が必要です。

社内ネットワーク専用のMCPサーバーであればインターネットは不要ですが、社内VPNやLANへの接続が必要になります。

オフライン対応が重要なデスクトップツールではstdioが有利です。

ログと監視の違い

stdioでは、ログをstderrへ出力します。

MCPクライアントがstderrを収集する場合は、その画面やログファイルから確認できます。

src/log-tool-call.ts
console.error({
  event: "tool_called",
  toolName: "search_files",
  durationMs: 123,
});

複数ユーザーのログを一か所へ集約したい場合は、MCPサーバーから外部のログサービスへ送信する必要があります。

Streamable HTTPでは、通常のWebサービスと同じ監視基盤を利用できます。

リクエストID、ユーザーID、ツール名、処理時間、HTTPステータス、エラー率などを集中管理できます。

ロードバランサー、APIゲートウェイ、OpenTelemetry、APMサービスとも統合しやすくなります。

障害範囲の違い

stdioでは、通常一つのサーバープロセスの障害が一人のユーザーまたは一つのクライアントに限定されます。

サーバーがクラッシュしても、他のユーザーが起動したプロセスには影響しません。

一方、特定のパソコンだけで発生するPATH、Node.jsバージョン、権限、セキュリティソフトなどの問題が起こりやすくなります。

Streamable HTTPでは、サーバー障害がすべての利用者へ影響する可能性があります。

その代わり、運営側で障害を一元的に検知し、修正できます。

複数インスタンス、ヘルスチェック、フェイルオーバーを用意すれば、単一障害点を減らせます。

TypeScriptでstdioサーバーを作る

2026年8月時点の公式TypeScript SDK v2では、サーバー用パッケージが@modelcontextprotocol/serverとして提供されています。

v2はNode.js 20以上を前提としており、stdioトランスポートは@modelcontextprotocol/server/stdioから読み込みます。

必要なパッケージをインストールします。

PowerShell
npm install @modelcontextprotocol/server zod
npm install -D typescript @types/node

最小構成のstdioサーバーは次のとおりです。

src/stdio-server.ts
import {
  McpServer,
} from "@modelcontextprotocol/server";
import {
  StdioServerTransport,
} from "@modelcontextprotocol/server/stdio";
import { z } from "zod";

function createMcpServer(): McpServer {
  const server = new McpServer({
    name: "example-tools",
    version: "1.0.0",
  });

  server.registerTool(
    "greet",
    {
      description:
        "指定された名前へ挨拶します。",
      inputSchema: z.object({
        name: z
          .string()
          .trim()
          .min(1)
          .max(100),
      }),
    },
    async ({ name }) => {
      return {
        content: [
          {
            type: "text",
            text: `こんにちは、${name}さん。`,
          },
        ],
      };
    },
  );

  return server;
}

async function main(): Promise<void> {
  const server =
    createMcpServer();

  const transport =
    new StdioServerTransport();

  await server.connect(transport);

  console.error(
    "MCPサーバーをstdioで起動しました。",
  );
}

main().catch((error: unknown) => {
  console.error(
    "MCPサーバーの起動に失敗しました。",
    error,
  );

  process.exit(1);
});

MCP公式TypeScript SDKでも、StdioServerTransportを作成してserver.connect()へ渡す構成が基本例として案内されています。

TypeScriptでStreamable HTTPサーバーを作る

Node.jsとFastifyを使う場合は、公式SDKのFastifyアダプターとNode.js用HTTPトランスポートを利用できます。

PowerShell
npm install \
  @modelcontextprotocol/server \
  @modelcontextprotocol/node \
  @modelcontextprotocol/fastify \
  fastify \
  zod

次の例は、ローカルの127.0.0.1:3000でStreamable HTTPサーバーを起動します。

src/http-server.ts
import {
  createMcpFastifyApp,
} from "@modelcontextprotocol/fastify";
import {
  NodeStreamableHTTPServerTransport,
} from "@modelcontextprotocol/node";
import {
  McpServer,
} from "@modelcontextprotocol/server";
import { z } from "zod";

function createMcpServer(): McpServer {
  const server = new McpServer({
    name: "example-tools",
    version: "1.0.0",
  });

  server.registerTool(
    "greet",
    {
      description:
        "指定された名前へ挨拶します。",
      inputSchema: z.object({
        name: z
          .string()
          .trim()
          .min(1)
          .max(100),
      }),
    },
    async ({ name }) => {
      return {
        content: [
          {
            type: "text",
            text: `こんにちは、${name}さん。`,
          },
        ],
      };
    },
  );

  return server;
}

async function main(): Promise<void> {
  const app =
    createMcpFastifyApp();

  const mcpServer =
    createMcpServer();

  app.post(
    "/mcp",
    async (request, reply) => {
      const transport =
        new NodeStreamableHTTPServerTransport({
          sessionIdGenerator:
            undefined,
        });

      await mcpServer.connect(
        transport,
      );

      reply.raw.on(
        "close",
        () => {
          void transport.close();
        },
      );

      await transport.handleRequest(
        request.raw,
        reply.raw,
        request.body,
      );
    },
  );

  await app.listen({
    host: "127.0.0.1",
    port: 3000,
  });

  console.log(
    "http://127.0.0.1:3000/mcp",
  );
}

main().catch((error: unknown) => {
  console.error(error);
  process.exit(1);
});

公式SDKのFastify例でも、ステートレス構成ではリクエストごとにNodeStreamableHTTPServerTransportを作成し、handleRequest()へNode.jsのリクエストとレスポンスを渡します。

このコードはローカル開発用です。

インターネットへ公開する場合は、HTTPS、認証、Origin検証、レート制限、入力サイズ制限、監査ログを追加します。

一つのツール実装を両方の方式で使う

stdio版とStreamable HTTP版で同じツールを別々に実装すると、修正内容がずれる可能性があります。

サーバーを作成する関数を共通化し、起動用ファイルだけを分けます。

ファイル構成
src/
  server.ts
  stdio.ts
  http.ts

server.tsにはツール定義を置きます。

src/server.ts
import {
  McpServer,
} from "@modelcontextprotocol/server";
import { z } from "zod";

export function createMcpServer():
  McpServer {
  const server = new McpServer({
    name: "shared-tools",
    version: "1.0.0",
  });

  server.registerTool(
    "add",
    {
      description:
        "二つの数値を加算します。",
      inputSchema: z.object({
        first: z.number(),
        second: z.number(),
      }),
    },
    async ({
      first,
      second,
    }) => {
      return {
        content: [
          {
            type: "text",
            text: String(
              first + second,
            ),
          },
        ],
      };
    },
  );

  return server;
}

stdio.tsではstdioトランスポートへ接続します。

src/stdio.ts
import {
  StdioServerTransport,
} from "@modelcontextprotocol/server/stdio";
import {
  createMcpServer,
} from "./server.js";

const server =
  createMcpServer();

const transport =
  new StdioServerTransport();

await server.connect(transport);

http.tsではStreamable HTTPへ接続します。

この構成なら、開発中はstdioで手軽にテストし、本番環境ではStreamable HTTPとして公開することもできます。

MCP Inspectorで両方をテストする

MCP Inspectorは、stdioとStreamable HTTPの両方をテストできます。

stdioサーバーへ接続する場合は、実行コマンドを指定します。

PowerShell
npx @modelcontextprotocol/inspector \
  node dist/stdio.js

Streamable HTTPへ接続する場合は、URLとトランスポートを指定します。

PowerShell
npx @modelcontextprotocol/inspector \
  --server-url http://127.0.0.1:3000/mcp \
  --transport http

CLIからツール一覧を取得することもできます。

PowerShell
npx @modelcontextprotocol/inspector \
  --cli \
  http://127.0.0.1:3000/mcp \
  --transport http \
  --method tools/list

MCP Inspectorは、Web、CLI、TUIの三つの形式を持ち、いずれもstdioとHTTPの接続設定を共通して利用します。

ローカルファイルを扱うならstdioを選ぶ

ユーザーのパソコン内にあるファイルを扱うサーバーでは、stdioが基本です。

Streamable HTTPでクラウド上のサーバーへ移すと、クラウドサーバーからユーザーのローカルファイルへ直接アクセスできません。

ファイルをアップロードする仕組みや、ローカル側の別エージェントが必要になります。

次のような用途ではstdioが適しています。

stdioが適している用途
ローカルのGitリポジトリを検索する
ローカルファイルを書き換える
デスクトップアプリを操作する
開発用CLIを実行する
ユーザーごとのSQLiteを検索する

ただし、アクセス対象のフォルダを設定で限定し、パストラバーサルを防ぐ必要があります。

クラウドAPIをラップするならStreamable HTTPを選ぶ

MCPサーバーが最終的にクラウドAPIへ接続するだけなら、ユーザーのパソコン上で実行する必要はありません。

サーバー側でAPI連携を一元管理すれば、APIキーの保護、レート制限、キャッシュ、監査ログを集中管理できます。

次のような用途ではStreamable HTTPが適しています。

Streamable HTTPが適している用途
CRMの顧客情報を検索する
社内Wikiを検索する
チケット管理システムを操作する
SaaSの機能をMCPとして公開する
複数ユーザーへ共通ツールを提供する

ユーザー固有の権限がある場合は、アクセストークンからユーザーとテナントを特定し、ツール処理へ引き継ぎます。

一人だけが使う外部API連携ならどちらを選ぶか

個人用のMCPサーバーで外部APIへ接続する場合は、stdioでもStreamable HTTPでも実装できます。

設定を簡単にしたい場合はstdioが向いています。

環境変数へAPIキーを設定し、ローカルプロセスからAPIへ接続するだけで利用できます。

複数端末から同じサーバーを使いたい場合や、パソコンごとにインストールしたくない場合はStreamable HTTPが向いています。

ただし、インターネットへ公開することで認証やサーバー運用が必要になります。

一人用だから必ずstdioではなく、利用端末数と運用コストで判断します。

社内専用MCPサーバーの選び方

社内の複数ユーザーへナレッジ検索やデータベース操作を提供する場合は、社内ネットワーク上のStreamable HTTPが管理しやすくなります。

認証を社内のIDプロバイダーと連携し、ユーザーや部署ごとにアクセス可能なデータを制御できます。

サーバー更新も一か所で行えます。

一方、社員のパソコンにあるローカルリポジトリや未アップロードのファイルへアクセスする場合は、stdioが必要です。

社内向けでも、クラウドデータはStreamable HTTP、ローカルデータはstdioというように複数のMCPサーバーを組み合わせられます。

デスクトップアプリへ同梱する場合

自社のデスクトップアプリにMCPサーバーを同梱する場合は、stdioが扱いやすい構成です。

アプリが必要なときに子プロセスを起動し、終了時に一緒に停止できます。

使用するポートを探したり、別プロセスからのHTTPアクセスを防いだりする必要がありません。

一方、ブラウザベースのアプリや複数のプロセスから共有する必要がある場合は、localhostのStreamable HTTPを検討できます。

その場合も、127.0.0.1へバインドし、OriginとHostを検証します。

サーバーレス環境での選び方

stdioは、MCPクライアントが子プロセスを起動できる環境を前提としています。

一般的なサーバーレス関数へstdioサーバーをデプロイして、外部のMCPクライアントから接続することはできません。

クラウドへ公開する場合はStreamable HTTPを使用します。

TypeScript SDK v2では、Node.jsのIncomingMessageServerResponseを使う環境向けに@modelcontextprotocol/nodeが用意されています。

Cloudflare Workers、Deno、BunなどWeb標準のRequestResponseを使う環境では、@modelcontextprotocol/serverWebStandardStreamableHTTPServerTransportを直接利用します。

ただし、SSEを利用する長時間処理では、デプロイ先の最大実行時間やストリーミング対応も確認する必要があります。

stdioからStreamable HTTPへ移行する場合

ツールのビジネスロジックをcreateMcpServer()のような関数へ分離していれば、主な変更はトランスポート部分です。

stdio固有の環境変数は、HTTPリクエストの認証情報へ置き換えます。

プロセス内に保存していたユーザー状態は、リクエストコンテキスト、データベース、Redisなどへ移します。

stderrだけに出していたログは、集中ログやOpenTelemetryへ送信します。

ローカルファイルパスを受け取るツールは、リモートサーバーからアクセスできないため、ファイルアップロードやクラウドストレージのURIへ変更する必要があります。

HTTP化するだけで同じ機能を公開できるとは限らず、データの場所と権限モデルを見直す必要があります。

Streamable HTTPからstdioへ移行する場合

一人用またはローカル専用へ変更する場合は、HTTPサーバー、OAuth、デプロイ環境を削除し、stdioでクライアントから起動できます。

HTTPヘッダーから取得していたユーザー情報やAPIキーは、環境変数または設定ファイルから読み込みます。

複数ユーザー向けの共有状態が不要になるため、構成を大幅に簡単にできる場合があります。

ただし、各利用端末への配布、依存関係のインストール、アップデート方法が新たに必要です。

両方を提供する方法

開発者向けツールでは、stdio版とStreamable HTTP版を両方提供する方法があります。

ローカルのコードやファイルへアクセスするユーザーはstdioを使用します。

クラウド側に保存されたデータだけを使うユーザーはStreamable HTTPを使用します。

ツール定義とビジネスロジックを共有し、認証情報やデータアクセスだけをトランスポートごとに切り替えます。

src/tool-context.ts
type ToolContext =
  | {
      mode: "local";
      workspacePath: string;
    }
  | {
      mode: "remote";
      userId: string;
      tenantId: string;
      accessToken: string;
    };

ただし、同じツール名でもアクセスできるデータや権限が異なる場合は、説明文やメタデータで違いを明確にします。

stdioを選ぶ基準

ユーザーのローカルファイル、ローカルアプリ、CLIへアクセスする場合はstdioを選びます。

単一ユーザーまたは単一クライアント向けで、サーバー運用を用意したくない場合にも適しています。

オフラインで利用したい場合や、ネットワークポートを公開したくない場合もstdioが有利です。

一方、利用者ごとのインストールとアップデートが必要になる点、環境差による起動エラーが発生しやすい点を考慮します。WindowsでのMCPサーバー起動トラブルはMCPサーバーが起動しない原因|Windowsのパス・環境変数・stdioを確認で詳しく解説しています。

Streamable HTTPを選ぶ基準

複数ユーザーへ同じMCPサーバーを提供する場合はStreamable HTTPを選びます。

クラウドAPI、社内データベース、SaaS機能など、サーバー側に存在するデータへ接続する用途に適しています。

OAuth、アクセス制御、監査ログ、集中アップデート、水平スケールが必要な場合もStreamable HTTPが向いています。

一方、HTTPS、認証、Origin検証、サーバー監視、障害対応といったWebサービスの運用が必要になります。GitHubやFigma、DBへの具体的な接続例はClaude Code MCP完全ガイドで解説しています。

MCPのstdioとStreamable HTTPに関するよくある質問

QstdioとStreamable HTTPでツールの書き方は変わりますか?

Aツールの名前、説明、入力スキーマ、実行処理は基本的に共通です。異なるのは、McpServerを接続するトランスポートと、認証情報やリクエストコンテキストの受け取り方です。ツール定義を共通関数へ分離すれば、同じMCPサーバーを両方の方式で提供できます。

QStreamable HTTPではSSEが必須ですか?

AすべてのレスポンスをSSEにする必要はありません。短い処理はapplication/jsonで一つのレスポンスを返せます。複数の通知やストリーミングが必要な場合はtext/event-streamを使用します。クライアントは両方のレスポンス形式へ対応する必要があります。

QWebSocketを使ってもよいですか?

A独自トランスポートとして実装することはできますが、WebSocketはMCPの標準トランスポートではありません。公式TypeScript SDK v2では標準のWebSocketクライアントトランスポートが削除されており、ローカルにはstdio、リモートにはStreamable HTTPを使うよう案内されています。対応クライアントを広げたい場合は、標準トランスポートを使用するほうが安全です。

QlocalhostのHTTPとstdioではどちらが安全ですか?

A構成によりますが、単一のローカルクライアントからだけ利用するなら、ネットワークポートを開かないstdioのほうが管理項目は少なくなります。localhostのStreamable HTTPを使う場合は、127.0.0.1だけへバインドし、OriginとHostを検証します。ブラウザからのDNSリバインディング攻撃を防ぐ対策も必要です。

QStreamable HTTPなら自動的に複数ユーザーへ対応できますか?

AHTTPサーバーとして複数接続を受けられても、ユーザー分離が自動的に保証されるわけではありません。認証、認可、テナントフィルタ、キャッシュキー、ログ、レート制限をユーザーごとに設計する必要があります。グローバル変数へ現在のユーザーやアクセストークンを保存してはいけません。

Qstdioなら認証は不要ですか?

AMCPのHTTP向けOAuthフローは通常使用しませんが、外部APIへ接続するための認証情報は必要です。環境変数、設定ファイル、OSの資格情報ストアなどから取得します。また、MCPクライアントを操作できるユーザーが、サーバーに許可されたローカル権限を利用できる点にも注意が必要です。

まとめ

MCPのstdioとStreamable HTTPは、提供できるTools、Resources、Promptsではなく、サーバーの起動と通信方法が異なります。

stdioでは、MCPクライアントがサーバーを子プロセスとして起動し、stdinとstdoutでJSON-RPCメッセージを交換します。

ローカルファイル、Gitリポジトリ、デスクトップアプリ、CLIなど、ユーザーのパソコン上にあるリソースへアクセスする用途に向いています。

Streamable HTTPでは、独立して稼働するMCPサーバーのURLへHTTP POSTを送信し、JSONまたはSSEで応答を受け取ります。

クラウドAPI、社内システム、SaaSなどを複数ユーザーへ提供する用途に向いています。

単一ユーザー、ローカルデータ、オフライン利用、簡単な導入を重視する場合はstdioを選びます。

複数ユーザー、集中アップデート、OAuth、監査、水平スケールを重視する場合はStreamable HTTPを選びます。

2026年7月28日版のStreamable HTTPでは、旧仕様にあったGETストリームとプロトコルレベルのセッションが削除されました。古いHTTP+SSEやSSEServerTransportのサンプルをそのまま使用せず、現在のMCP仕様とSDKに合わせて実装することが重要です。WindowsでMCPサーバーが起動しない場合はMCPサーバーが起動しない原因|Windowsのパス・環境変数・stdioを確認、GitHubやDBへの接続方法はClaude Code MCP完全ガイドもあわせてご覧ください。