nx_mcp_stdio_http_t174.nx
buildroot/runtime/nx_mcp_stdio_http_t174.nx
about
MCP stdio to sovereign HTTPS. The server remains the authority for discovery and capability checks.
Each request runs in a child so the current TLS allocator cannot accumulate across a long session.
FAILURE SEMANTICS (lane conn, 2026-09-11). A per-request failure -- a child that exits non-zero, the
SIGALRM deadline, a non-2xx HTTP status, an over-budget response, a response-id mismatch, or a
TLS/transport failure -- produces a JSON-RPC 2.0 error response for THAT request id on the protocol
fd, and the connector KEEPS SERVING every other request. Two mechanisms, one shape:
* the request CHILD self-reports soft failures (it knows the http status / byte limit) by writing a
correlated error to its own pipe and exiting 0, so the parent forwards it like any response;
* the PARENT (mp_recover_pump) turns a child that died WITHOUT self-reporting -- a crash, or the
SIGALRM deadline killing it -- into a correlated error from that slot's pending id and continues.
An oversized OR malformed request line is consumed to its newline and answered with -32600 for its id
when the id is readable from the retained prefix; otherwise a stderr diagnostic. Notifications (no id)
never get a response. Only broken stdin/stdout, poll failure, or allocation failure ends the process.
Protocol-fd isolation (stdout dup'd away to stderr for library chatter, the real protocol pipe held on
a private fd) and response-id correlation are preserved. No magic numbers: every code/limit is named.
dependencies 5 imports · 0 importers
imports: nx_mcp_transport.nxnx_mcp_route.nxnx_request_pool.nxnx_mcp_control.nxnx_mcp_pending_http_t174.nx
imported by: nobody (leaf or entry point)
call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown
structs
| 55 | struct NxMcpErr { code: i64, stage: *u8, cause: *u8, measured: i64, next: *u8, http_data:*u8, http_n:i64 } |
consts
| 23 | const MS_F_DUPFD_CLOEXEC: i64 = 1030 |
| 24 | const MS_FIRST_PRIVATE_FD: i64 = 3 |
| 25 | const MS_STDIN: i64 = 0 |
| 26 | const MS_STDOUT: i64 = 1 |
| 27 | const MS_STDERR: i64 = 2 |
| 32 | const MS_OK: i64 = 0 |
| 33 | const MS_DUP: i64 = 0 - 1 |
| 34 | const MS_FATAL: i64 = 10 |
| 38 | const MSE_CODE_TRANSPORT: i64 = 0 - 32001 |
| 39 | const MSE_CODE_HTTPSTATUS: i64 = 0 - 32002 |
| 40 | const MSE_CODE_PARSE: i64 = 0 - 32003 |
| 41 | const MSE_CODE_BODY: i64 = 0 - 32004 |
| 42 | const MSE_CODE_RESPSIZE: i64 = 0 - 32005 |
| 43 | const MSE_CODE_IDENTITY: i64 = 0 - 32006 |
| 44 | const MSE_CODE_TRUSTSTORE: i64 = 0 - 32007 |
| 45 | const MSE_CODE_CREDENTIAL: i64 = 0 - 32008 |
| 46 | const MSE_CODE_URL: i64 = 0 - 32009 |
| 47 | const MSE_CODE_ROUTE: i64 = 0 - 32010 |
| 48 | const MSE_CODE_PROTOWRITE: i64 = 0 - 32011 |
| 49 | const MSO_CODE_DUP: i64 = 0 - 32013 |
| 50 | const MSO_CODE_INVALID: i64 = 0 - 32600 |
functions
| 57 | func ms_number(s: *u8) -> i64 called by 1: main |
| 72 | func ms_has_id(src: *u8, n: i64) -> i64 called by 1: ms_exchange |
| 106 | func ms_exchange(base: *u8, capfile: *u8, body: *u8, body_n: i64, response_cap: i64, protocol_fd: i64, timeout_secs: i64, err: *NxMcpErr) -> i64 |
| 213 | func ms_request(base: *u8, capfile: *u8, body: *u8, body_n: i64, response_cap: i64, protocol_fd: i64, timeout_secs: i64, argc: i64, argv: *i64, route_first: i64, pool: *NxRequestPool, pending: *u8, control: *NxMcpControl) -> i64 |
| 248 | func ms_drain(pool: *NxRequestPool, pending: *u8, protocol_fd: i64, timeout_secs: i64) -> i64 |
| 255 | func main(argc: i64, argv: *i64) -> i64 |