10. プロセス共有

同じ PC で 1 本のサーバーを、複数のホストから使う

📅 作成: 2026-09-07 / 更新: 2026-09-07

この資料の内容

  1. なぜ 1 本にまとめたいか
  2. 3 つのやり方
  3. localhost の HTTP
  4. stdio ブリッジ
  5. 常駐させる

なぜ 1 本にまとめたいか

stdio ではホストが子プロセスを起こします。ホストが 3 つあれば、同じサーバーが 3 つ立ちます。ウィンドウを 2 枚開けば 2 倍になります。

困ること中身
資源Node のプロセスが 1 本あたり数十 MB。10 本立てば無視できない
記憶が分かれる記憶の中に持った状態は共有されない。片方で覚えたことを他方は知らない
重い初期化索引の構築や接続の確立を、起動のたびに繰り返す
外部の上限API のレート制限や DB の接続数を、プロセスの数だけ食う
stdio のまま、ホストを 3 つ・ウィンドウを 2 枚ずつ使うと Claude Code ① Claude Code ② Codex ① Codex ② node 50 MB node 50 MB node 50 MB node 50 MB 同じものが 4 つ。状態は共有されない 1 本にまとめたい 記憶も接続も 1 つで済む ただし、起動と終了を自分で見る必要が出てくる
状態を持たないサーバーなら、増えても実害は小さい。共有が効くのは「重い」か「覚える」サーバー。

まず、本当に共有が要るか考えてください。メモサーバーのように状態をファイルに持つなら、プロセスが増えても結果は揃います。共有が効くのは、起動が重いか、記憶の中に状態を持つ場合です。

3 つのやり方

やり方仕組み難所
localhost の HTTP常駐を 1 本立て、各ホストは HTTP で繋ぐホスト側の設定を HTTP に変える必要がある
stdio ブリッジ各ホストには軽い stdio のプロセスを起こさせ、それが常駐へ中継するブリッジを自分で書く
名前付きパイプstdio と同じ形式をパイプで運ぶWindows 固有。SDK に既製品が無い
① localhost の HTTP ホスト HTTP 常駐サーバー :3333 設定を HTTP に変える ② stdio ブリッジ ホスト stdio ブリッジ HTTP 常駐サーバー :3333 設定は stdio のまま ③ 名前付きパイプ ホスト ブリッジ パイプ 常駐サーバー ポートを使わずに済む 仕様は「独自の運び方を作るなら、stdio と同じ改行区切りを使え」と勧めている
②は①の上に薄い層を足しただけ。ホスト側の設定を変えたくないときに効く。

localhost の HTTP

07 章で作ったものが、そのまま使えます。1 本立てて、各ホストから繋ぐだけです。

# 常駐させる(1 回だけ)
$env:PORT = "3333"
node docs/samples/07-http/server.mjs
# 各ホストから繋ぐ
claude mcp add --transport http memo http://localhost:3333/mcp
codex mcp add memo --url http://localhost:3333/mcp

外から叩かれないようにする

listen(PORT) はすべてのネットワークで待ち受けます。同じ PC だけに限るなら、明示します。

// 127.0.0.1 に限ると、外のマシンからは繋がらない
http.listen(PORT, '127.0.0.1', () => { /* ... */ });

認証の無いサーバーを外へ出さないでください。MCP サーバーはツールを実行する仕組みです。誰でも叩ける場所に置けば、誰でもコマンドを走らせられます。共有はあくまで同じ PC の中に留めるのが、この章の前提です。

listen(3333) すべてのネットワークで待つ 同じ LAN の誰でも繋がる ツールを実行できてしまう listen(3333, '127.0.0.1') 同じ PC の中だけ 外からは繋がらない 共有の用途にはこれで足りる
1 引数の listen は既定で全方位に開く。共有目的なら必ず絞る。

stdio ブリッジ

「ホスト側の設定は stdio のままにしたい」「HTTP を知らない人にも配りたい」。そのときはブリッジを挟みます。

やることは単純です。stdin で受けた行を HTTP に投げ、返ってきたものを stdout に書くだけ。samples/10-shared/bridge.mjs の全文は 70 行ほどです。

const TARGET = process.env.MCP_TARGET ?? 'http://localhost:3333/mcp';

async function forward(line) {
	const res = await fetch(TARGET, {
		method: 'POST',
		headers: {
			'content-type': 'application/json',
			// どちらの形で返してもよい、と伝える
			accept: 'application/json, text/event-stream',
		},
		body: line,
	});

	// 通知を中継したときは本文が無い(202 が返る)
	if (res.status === 202) return;

	const body = await res.text();
	for (const message of extractMessages(res.headers.get('content-type') ?? '', body)) {
		send(message);
	}
}

rl.on('line', (line) => {
	if (!line.trim()) return;
	forward(line).catch((err) => { /* エラーを返す(後述) */ });
});

失敗したときに固まらせない

本体が落ちていると fetch が失敗します。何も返さないとホストは待ち続けます。エラーを返して知らせます。

forward(line).catch((err) => {
	log('中継に失敗:', err.message);

	// 応答を待っているホストを固まらせないよう、エラーを返す。
	// 通知(id 無し)には返さない
	let id;
	try { id = JSON.parse(line).id; } catch { /* 壊れた行は無視 */ }
	if (id === undefined) return;

	send(JSON.stringify({
		jsonrpc: '2.0',
		id,
		error: { code: -32603, message: `本体へ中継できない: ${err.message}` },
	}));
});

確かめる

2 本のブリッジから同じ本体を見ていることを、テストで確かめました。

test('2 本のブリッジが同じ本体を見ている(片方で書いた内容が他方で読める)', async () => {
	const a = await connect(sample('10-shared/bridge.mjs'), { env: { MCP_TARGET: TARGET } });
	const b = await connect(sample('10-shared/bridge.mjs'), { env: { MCP_TARGET: TARGET } });

	try {
		const mark = `共有の確認 ${Date.now()}`;
		await a.callTool({ name: 'memo_add', arguments: { text: mark } });

		// 別のブリッジから探しても見つかる
		const found = await b.callTool({ name: 'memo_search', arguments: { query: '共有の確認' } });
		assert.match(textOf(found), new RegExp(mark));
	} finally {
		await a.close();
		await b.close();
	}
});
✔ ブリッジ越しでもツールの一覧が取れる (843.454ms)
✔ 2 本のブリッジが同じ本体を見ている(片方で書いた内容が他方で読める) (353.484ms)
✔ 本体が落ちているときは接続の時点で失敗する(固まらない) (151.9163ms)
Claude Code Codex ブリッジ 軽い・状態を持たない ブリッジ 軽い・状態を持たない 本体 1 本 重い初期化はここで 1 回だけ ブリッジ側には何も置かない。置くと共有の意味が薄れる
ブリッジは中身を持たない。だから何本立ててもよい。

常駐させる

共有の形にすると、本体を誰が起こすかという問題が出ます。stdio ではホストがやってくれていた仕事です。

やり方向く場面注意
手で起動試すとき閉じ忘れ・起動し忘れが起きる
スタートアップ自分の PCログオンしないと動かない
Windows サービス常に動かしたいユーザープロファイルを見られない場合がある
ブリッジが起こす起動忘れを無くしたい同時に起きたときの競合を自分で捌く
stdio ホストが全部やる 起動する 終了させる 落ちたら起こし直す こちらは何もしなくてよい 共有 自分が持つ 起動する仕掛けを用意する 落ちたことに気づく手立てを持つ 更新するとき、繋いでいる全員に影響 ここが共有の代償 1 本にまとめる利得と、面倒を見る手間を秤にかける
資源の節約と引き換えに、運用の仕事が増える。小さなサーバーなら stdio のままが楽。

選び方

状況お勧め
状態を持たない・起動が軽い共有しない。stdio のままでよい
起動が重い(索引・接続)localhost の HTTP
設定を変えたくない・配りたいstdio ブリッジ
ポートを使いたくない名前付きパイプ(自分で書く)

次の章へ

最後に、ここまでのものを 1 つにまとめます。コマンドを実行し、進み具合を知らせ、終わったら画面にも出すサーバーを作ります。