Skip to main content

concinnity_dev/mcp/
mod.rs

1//! The Model Context Protocol: the one transport the runtime debug surface
2//! speaks.
3//!
4//! A running app serves MCP itself on its debug port (`cn debug`, or
5//! `cn editor --debug-port N`) over the Streamable HTTP transport in its
6//! stateless form, so any MCP client can post straight to
7//! `http://127.0.0.1:8777/mcp`. `cn mcp` is the stdio entry a client that
8//! spawns servers as child processes uses instead: it answers `initialize`,
9//! `tools/list` and `ping` from the verb catalog, so a client connects with no
10//! app running, and forwards each `tools/call` to the app.
11//!
12//! The tool surface is the debug protocol's own verb catalog, so this module
13//! declares no commands of its own. The split below is what keeps the protocol
14//! testable without a socket:
15//!   jsonrpc  message parsing and response building, transport-agnostic
16//!   tools    the catalog rendered as MCP tools, and the body one call carries
17//!   server   the methods answered, over an injected call executor
18//!   http     the app's transport: one request, one response, one connection
19//!   stdio    newline-delimited framing over any byte streams
20//!   app      the executor that runs a call against the live world snapshot
21//!   bridge   the executor that forwards a call to a running app
22//!   remote   the client that posts one JSON-RPC message to an app
23
24mod app;
25mod bridge;
26mod http;
27mod jsonrpc;
28mod remote;
29mod server;
30mod stdio;
31mod tools;
32
33pub(crate) use app::AppServer;
34
35/// Serve MCP over stdin and stdout until the client closes stdin, forwarding
36/// tool calls to the app on `port`.
37pub fn run(port: u16) -> std::io::Result<()> {
38    eprintln!("[mcp] forwarding tool calls to {}", remote::endpoint(port));
39    let server = server::Server::new(bridge::Forward::new(port));
40    let stdin = std::io::stdin();
41    let mut stdout = std::io::stdout();
42    stdio::serve(&server, stdin.lock(), &mut stdout)
43}