Skip to content

MCP(1) -- STDIO

通信方式 stdio

stdio:每个在操作系统上执行中的进程都有几个接口 stdout stdin stderr 标准输入/输出/错误。

stdio,是在一台机器上不同进程间通信的一种方式。

js
// in node.js
console.log("hello console")
process.stdout.write("hello stdout")

我们在 node 中去跑一个 console.log,内部就是调用的 stdout.

js
console.log("PID:",process.pid)

process 对象上也可以拿到当前进程 ID,正如任务管理器里看到的一样。


bash
node server.js

当启用终端,然后输入 node xxx.js,那么终端进程就创建了一个 node 进程,然后把这个 xxx.js 作为参数,把参数发送给在 node 进程,代码在 node 进程中执行。

当我们xxx.js中还执行了一个 process.stdout.write("hello stdout") 时,会打印到终端。这背后其实就是终端进程监听了 node 进程的标准输出接口。


js
process.stdin.on('data', data=>{
	const resp = `哈哈,${data}`
	process.stdout.write(resp)
})

运行上面的脚本,会得到一个永不结束的进程,在终端输入并回车,可以给进程发消息,这背后就是终端进程,把用户输入,通过 node 进程的标准输入接口传入数据。


上面的实践中,终端相当于 Client,node 进程相当于 Server,已经有了一个交互的雏形,自然,这个 Client 我们也能自己写。

js
import { spawn } from 'child_process'

const serverProcess = spawn('node', ['server.js'])

// 监听 server 进程的标准输出
serverProcess.stdout.on('data', (data) => {
    console.log(data.toString())
})

// 利用标准输入接口,向 server 进程写入数据
serverProcess.stdin.write("hello server")

特点:适用于本地,stdio 通信高效、简介。

通信格式 JSON-RPC

Request

json
{
	"jsonrpc":"2.0",
	"method": "myMethod",
	"params": {
		"a": 5,
		"b": 6,
		...
	},
	"id": 1
}

Response

json
{
	"jsonrpc":"2.0",
	"result": 11,
	"id": 1
}

基于上面一种格式,我们可以在 node 中,基于标准输入接口做如下实现

js
import tools from './tool.js'

process.stdin.on('data', data => {

    const req = JSON.parse(data)
    const { method, params } = req
    const result = tools[method](params)

    const res = {
        jsonrpc: "2.0",
        result,
        id: req.id
    }

    process.stdout.write(JSON.stringify(res))
})

用这种方式,我们就可以实现规范的进程间通信交互和功能调用。A 进程没有执行某功能的能力,B 进程有,那么我们就可以用上边的实现,让 A 进程去找 B 进程执行后拿到结果。