Cursor 怎麼跟 Server 講話?不是用 PID 嗎? (Pipe vs PID)
Cursor 怎麼跟 Server 講話?不是用 PID 嗎? (Pipe vs PID)
這是一個非常敏銳的問題!因為在人類的邏輯裡,要寄信給某人通常需要「地址」或「身分證字號(PID)」。
但在程式設計(特別是 Parent/Child Process 模型)中,答案是:不是用 PID 來傳資料,是用「物件參考 (Object Reference)」或是「檔案描述符 (File Descriptor)」。
為了讓您完全理解,我們試著假裝自己是 Cursor 的開發者,用 Node.js 寫一段「控制中心」的程式碼。看完這段 Code,您就會瞬間明白。
1. 模擬 Cursor 內部的運作 (The "Parent's View")
當 Cursor 啟動您的 MCP Server 時,它會執行類似這樣的 Node.js 程式碼:
const { spawn } = require('child_process');
// 1. 啟動行程 (Spawn)
// 這裡會回傳一個 "ChildProcess 物件",我們把它存入變數
const myMcpServer = spawn('bun', ['run', 'server.ts']);
// 此時,myMcpServer 這個變數就是那條「專屬電話線」的控制端
// Cursor 把這個變數存在記憶體裡,可能是一個 Map:
// toolsMap.set('my-math-server', myMcpServer);
// -------------------------------------------------
// 2. 當 Cursor 想傳資料給您的 Server 時
// 它不需要去查 PID,它只需要拿出上面那個變數,往它的 stdin 寫入即可
const message = { jsonrpc: "2.0", method: "tools/call", params: { name: "add", arguments: { a: 1, b: 2 } } };
// 【關鍵動作】直接寫入該物件的 stdin 串流
myMcpServer.stdin.write(JSON.stringify(message) + "\n");
// -------------------------------------------------
// 3. 當您的 Server 回傳資料時
// Cursor 監聽這個物件的 stdout 事件
myMcpServer.stdout.on('data', (data) => {
console.log(`收到來自 MCP Server 的回應: ${data}`);
});
2. 為什麼不用 PID? (The "Leash" Analogy)
想像您是一個遛狗的人(Cursor),您手裡牽著兩條狗(兩個 MCP Server)。
- PID 就像是狗脖子上的名牌編號(例如:9527)。
- stdin/stdout 就像是您手裡握著的牽繩。
當您想讓左邊那隻狗停下來時,您會:
- 查名牌法(PID):先看它的名牌是 9527,然後對著空氣大喊:「編號 9527 的狗,停下!」(這就像網路通訊,需要地址)。
- 拉繩子法(Stream Reference):您根本不在乎它的編號是多少,您只是拉動左手握著的那條繩子。
Cursor 就是用拉繩子法。因為它就是創造這個 Process 的人,它天生就持有這個 Process 的輸入/輸出控制權(Handle/Stream)。
3. 技術底層:OS Kernel 怎麼對應?
雖然 Cursor 程式碼層級是用變數(物件)來操作,但到了作業系統(Ubuntu Kernel)層級,這確實是對應到數字(File Descriptor):
- Cursor (Parent) 呼叫
write()。 - Node.js 查詢
myMcpServer.stdin底層對應的 File Descriptor (例如 FD 14)。 - Cursor 告訴 Kernel:「把資料寫進 FD 14」。
- Kernel 查表發現:FD 14 連接的是一條 Pipe,這條 Pipe 的另一端連著 PID 5678 (Child) 的 FD 0 (stdin)。
- 資料流進 Child 的 stdin。
總結
- 控制資料傳輸 (Data Flow):不使用 PID。使用的是記憶體中的 Stream 物件 (Handle)。Cursor 知道「這個變數」對應「那個 Server」。
- 控制生命週期 (Lifecycle):才使用 PID。如果 Cursor 想強制殺掉 Server (例如您按了 Stop 按鈕),它會呼叫
process.kill(pid),這時候才需要 PID。
所以,您的 Server 就像是 Cursor 手中的風箏,線一直都在 Cursor 手上,它不需要叫風箏的名字就能傳遞訊號。