nx_mcp_transport.nx
buildroot/runtime/nx_mcp_transport.nx
about
nx_mcp_call.nx -- the SOVEREIGN MCP client: POST a JSON-RPC tools/call to /mcp over our own TLS-1.3 and PRINT
the response body. Fills the gap surfaced 2026-07-17 ([[reference-sovereign-mcp-call-client-gap-2026-07-17]]):
nx_mgmt_client's `call` sends x-www-form-urlencoded (built for /api/login) so it mis-frames a JSON tools/call
(status=0); this client sends Content-Type: application/json + Accept + X-Nishi-Cap and echoes the body.
✅PROVEN 2026-07-17: `tools/call` WORKS end-to-end -- nishi_search returned real search hits, and
nx_dataplane_census returned 655 flat-file-debt rows (56KB, HTTP 200, isError:false) over sovereign TLS /mcp
with a least-authority cap. `initialize`/`tools/list`/`tools/call` all work; the sovereign JSON POST /mcp +
response-parse + body-print are complete. nx_mgmt_client CANNOT do this (it sends x-www-form-urlencoded -> the
daemon mis-frames the JSON -> status=0). That form-encoding -- NOT a daemon bug -- is why the doctrine's
"raw tools/call via nx_mgmt_client" path always failed. ⚠fork-exec tools are SLOW (census ~16s) so a client
needs patience; ⚠tools whose ELF FORKS CHILDREN (e.g. nx_status -> nx_hostctl sub-forks) return empty because
tr_run_capture (nx_tool_run.nx:21) dups the pipe to stdout/stderr but does NOT close the inherited request
SOCKET fd before execve -> forked grandchildren hold the connection open -> no clean close (a SEPARATE daemon
fix: add a close-fds-3..N loop in the child). Non-forking tools (search, census) work today.
tool_name "__initialize__" sends an initialize (open, no cap) probe. [[reference-sovereign-mcp-call-client-gap-2026-07-17]]
nx_mcp_call <base_url> <tool_name> <cap_file> [args_json_fragment]
e.g. nx_mcp_call https://nishifamily.com nx_dataplane_census /tmp/capfile
args_json_fragment (optional) is spliced into arguments after _cap, e.g. "argv":["a","b"]
REUSE (compose, don't rebuild TLS): copies nx_mgmt_client's PROVEN transport (build_request/send_drain/req)
verbatim -- renamed mc_* -- flipping ONLY the content-type. DRY debt: extract the shared transport into a
no-main lib later (nx_mgmt_client has a main(), so it can't be imported today). license_tier: ORIGINAL
dependencies 9 imports · 5 importers
imports: nx_acme_http.nxnx_https_url_for_fetch.nxnx_https_url_connect.nxnx_tls13_client_session_run.nxnx_tls13_client_session.nxnx_tls13.nxnx_tls13_record.nxnx_tls13_read_record_from_fd.nxnx_csprng.nx
imported by: nx_mcp_stdio.nxnx_mcp_stdio_candidate_t230.nxnx_mcp_stdio_http_t174.nxnx_mcp_stdio_sse_t316.nxnx_mcp_transport_gate.nx
structs
| none |
consts
| 32 | const MC_CONNECT_FAIL: i64 = 0 - 11 |
| 33 | const MC_HANDSHAKE_FAIL: i64 = 0 - 12 |
functions
| 35 | func mc_puts(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 } |
| 36 | func mc_putn(v: i64) -> i64 |
| 46 | func mc_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } called by 1: main |
| 47 | func mc_cat(d: *u8, o: i64, s: *u8) -> i64 { var i: i64 = 0; while s[i] != (0 as u8) { d[o + i] = s[i]; i = i + 1 } return o + i } |
| 48 | func mc_catb(d: *u8, o: i64, s: *u8, n: i64) -> i64 { var i: i64 = 0; while i < n { d[o + i] = s[i]; i = i + 1 } return o + i } called by 1: mc_build_request |
| 49 | func mc_catn(d: *u8, o: i64, v: i64) -> i64 called by 1: mc_build_request |
| 58 | func mc_write_n(fd: i64, buf: *u8, n: i64) -> i64 |
| 67 | func mc_read_file(path: *u8, out: *u8, cap: i64) -> i64 |
| 79 | func mc_rtrim_nl(buf: *u8, n: i64) -> i64 |
| 88 | func mc_join_url(base_url: *u8, suffix: *u8, out: *u8) -> i64 |
| 98 | func mc_build_request(method: *u8, method_len: i64, path: *u8, path_len: i64, host: *u8, host_len: i64, cap: *u8, cap_len: i64, ct: *u8, ct_len: i64, body: *u8, body_len: i64, out: *u8) -> i64 |
| 126 | func mc_http_expected(src: *u8, n: i64, capacity: i64) -> i64 |
| 137 | func mc_received_result(acc: i64, expected: i64) -> i64 |
| 145 | func mc_send_drain(s: *Tls13ClientSession, fd: i64, req: *u8, req_len: i64, out: *u8, out_cap: i64) -> i64 |
| 195 | func mc_req_timed(store: *TrustStore, full_url: *u8, target: *NxHttpsTarget, req: *u8, req_len: i64, out: *u8, out_cap: i64, timeout_secs: i64) -> i64 |
| 221 | func mc_req(store: *TrustStore, full_url: *u8, target: *NxHttpsTarget, req: *u8, req_len: i64, out: *u8, out_cap: i64) -> i64 calls 1: mc_req_timed |