nx_tools_api_gate.nx source
↩ module page · 280 lines · 18591 B
1// nx_tools_api_gate.nx -- drives ta_handle_pfx IN-PROCESS (no socket, no curl): register two test tools, then
2// assert the REST surface (/api/tools) and the MCP surface (/mcp: tools/list, initialize, error) are well-formed.
3// Proves R0 = MCP-compatible + superset, sovereignly. license_tier: ORIGINAL
4import "nx_tools_api.nx"
5import "nx_gate.nx"
6
7func tg_has(out: *u8, n: i64, needle: *u8) -> i64 { if ta_indexof(out, n, needle) >= 0 { return 1 } return 0 }
8// NUL-terminated string at pointer `p` (an argv entry, stored as i64) equals the NUL-terminated `expect`?
9func tg_streq(p: i64, expect: *u8) -> i64 {
10 let a: *u8 = p as *u8
11 var i: i64 = 0
12 while expect[i] != (0 as u8) { if a[i] != expect[i] { return 0 } i = i + 1 }
13 if a[i] != (0 as u8) { return 0 }
14 return 1
15}
16// buf[o2[0], o2[0]+o2[1]) equals the NUL-terminated expect? (for offset/len pairs like ta_query_cap emits)
17func tg_slice_eq(buf: *u8, o2: *i64, expect: *u8) -> i64 {
18 var n: i64 = 0
19 while expect[n] != (0 as u8) { n = n + 1 }
20 if o2[1] != n { return 0 }
21 var i: i64 = 0
22 while i < n { if buf[o2[0] + i] != expect[i] { return 0 } i = i + 1 }
23 return 1
24}
25func tg_write(path: *u8, content: *u8) -> i64 {
26 let fd: i64 = __syscall(257, 0 - 100, path, 0x241, 0x1a4, 0, 0) // O_WRONLY|O_CREAT|O_TRUNC, 0644
27 if fd < 0 { return 0 - 1 }
28 var n: i64 = 0; while content[n] != (0 as u8) { n = n + 1 }
29 sys_write(fd, content, n); sys_close(fd)
30 return 0
31}
32
33func main() -> i64 {
34 gw("=== nx_tools_api_gate: sovereign agent-facing API (MCP-compatible + superset) ===\n" as *u8)
35 let TP: *u8 = "knowledge/toolreg-test-tapi-" as *u8
36 tool_register_pfx(TP, "nx_http_probe" as *u8, "sovereign HTTP GET probe" as *u8, "nx_http_probe <path>" as *u8, "gate-proven" as *u8)
37 tool_register_pfx(TP, "nx_mgmt_client" as *u8, "drive the control-plane over TLS-1.3" as *u8, "nx_mgmt_client <url> call ..." as *u8, "gate-10/10" as *u8)
38
39 var pass: i64 = 0
40 var tot: i64 = 0
41 let out: *u8 = sys_mmap(1048576)
42
43 // T1: GET /api/tools -> 200 + BOTH tools + the superset gate-status field (beyond MCP)
44 let r1: *u8 = "GET /api/tools HTTP/1.1\r\nHost: x\r\nConnection: close\r\n\r\n" as *u8
45 let n1: i64 = ta_handle_pfx(TP, r1, ta_slen(r1), out)
46 tot = tot + 1
47 var t1: i64 = 0
48 if tg_has(out, n1, "200 OK" as *u8) == 1 { if tg_has(out, n1, "nx_http_probe" as *u8) == 1 { if tg_has(out, n1, "nx_mgmt_client" as *u8) == 1 { if tg_has(out, n1, "\"status\":\"gate-proven\"" as *u8) == 1 { t1 = 1 } } } }
49 if t1 == 1 { pass = pass + 1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
50 gw("T1 REST /api/tools: 200 + both tools + gate-status (the beyond-MCP field)\n" as *u8)
51
52 // T2: POST /mcp tools/list -> JSON-RPC 2.0, id echoed, MCP-shaped tools with inputSchema
53 let r2: *u8 = "POST /mcp HTTP/1.1\r\nHost: x\r\nContent-Type: application/json\r\nContent-Length: 47\r\n\r\n{\"jsonrpc\":\"2.0\",\"id\":7,\"method\":\"tools/list\"}" as *u8
54 let n2: i64 = ta_handle_pfx(TP, r2, ta_slen(r2), out)
55 tot = tot + 1
56 var t2: i64 = 0
57 if tg_has(out, n2, "\"jsonrpc\":\"2.0\"" as *u8) == 1 { if tg_has(out, n2, "\"id\":7" as *u8) == 1 { if tg_has(out, n2, "\"inputSchema\"" as *u8) == 1 { if tg_has(out, n2, "nx_http_probe" as *u8) == 1 { t2 = 1 } } } }
58 if t2 == 1 { pass = pass + 1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
59 gw("T2 MCP tools/list: JSON-RPC 2.0, id echoed, MCP-shaped tools\n" as *u8)
60
61 // T3: POST /mcp initialize -> protocolVersion + serverInfo (handshake)
62 let r3: *u8 = "POST /mcp HTTP/1.1\r\nHost: x\r\nContent-Length: 46\r\n\r\n{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"initialize\"}" as *u8
63 let n3: i64 = ta_handle_pfx(TP, r3, ta_slen(r3), out)
64 tot = tot + 1
65 var t3: i64 = 0
66 if tg_has(out, n3, "\"protocolVersion\"" as *u8) == 1 { if tg_has(out, n3, "\"serverInfo\"" as *u8) == 1 { t3 = 1 } }
67 if t3 == 1 { pass = pass + 1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
68 gw("T3 MCP initialize: protocolVersion + serverInfo\n" as *u8)
69
70 // T4: unknown method -> JSON-RPC error -32601 (fail-closed), id still echoed
71 let r4: *u8 = "POST /mcp HTTP/1.1\r\nHost: x\r\nContent-Length: 44\r\n\r\n{\"jsonrpc\":\"2.0\",\"id\":9,\"method\":\"bogus/x\"}" as *u8
72 let n4: i64 = ta_handle_pfx(TP, r4, ta_slen(r4), out)
73 tot = tot + 1
74 var t4: i64 = 0
75 if tg_has(out, n4, "-32601" as *u8) == 1 { if tg_has(out, n4, "\"id\":9" as *u8) == 1 { t4 = 1 } }
76 if t4 == 1 { pass = pass + 1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
77 gw("T4 MCP unknown method: JSON-RPC error -32601\n" as *u8)
78
79 // T5: unknown path -> 404 not_found
80 let r5: *u8 = "GET /nope HTTP/1.1\r\nHost: x\r\n\r\n" as *u8
81 let n5: i64 = ta_handle_pfx(TP, r5, ta_slen(r5), out)
82 tot = tot + 1
83 var t5: i64 = 0
84 if tg_has(out, n5, "404" as *u8) == 1 { t5 = 1 }
85 if t5 == 1 { pass = pass + 1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
86 gw("T5 unknown path: 404 not_found\n" as *u8)
87
88 // ---- R3: MCP resources (not tools-only) -- initialize advertises the capability; list + read serve content ----
89 let rr1: *u8 = "POST /mcp HTTP/1.1\r\nHost: x\r\n\r\n{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"initialize\"}" as *u8
90 let nr1: i64 = ta_handle_pfx(TP, rr1, ta_slen(rr1), out)
91 tot = tot + 1
92 var tr1: i64 = 0
93 if tg_has(out, nr1, "\"resources\"" as *u8) == 1 { if tg_has(out, nr1, "\"prompts\"" as *u8) == 1 { tr1 = 1 } }
94 if tr1 == 1 { pass = pass + 1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
95 gw("T-R3a MCP initialize advertises the resources + prompts capabilities\n" as *u8)
96
97 let rr2: *u8 = "POST /mcp HTTP/1.1\r\nHost: x\r\n\r\n{\"jsonrpc\":\"2.0\",\"id\":2,\"method\":\"resources/list\"}" as *u8
98 let nr2: i64 = ta_handle_pfx(TP, rr2, ta_slen(rr2), out)
99 tot = tot + 1
100 var tr2: i64 = 0
101 if tg_has(out, nr2, "nishi://sota/ecosystem-maturity" as *u8) == 1 { if tg_has(out, nr2, "nishi://doctrine/operating" as *u8) == 1 { tr2 = 1 } }
102 if tr2 == 1 { pass = pass + 1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
103 gw("T-R3b MCP resources/list -> 2 resource URIs (grade + doctrine)\n" as *u8)
104
105 let rr3: *u8 = "POST /mcp HTTP/1.1\r\nHost: x\r\n\r\n{\"jsonrpc\":\"2.0\",\"id\":3,\"method\":\"resources/read\",\"params\":{\"uri\":\"nishi://doctrine/operating\"}}" as *u8
106 let nr3: i64 = ta_handle_pfx(TP, rr3, ta_slen(rr3), out)
107 tot = tot + 1
108 var tr3: i64 = 0
109 if tg_has(out, nr3, "\"contents\"" as *u8) == 1 { if tg_has(out, nr3, "nx_ship" as *u8) == 1 { tr3 = 1 } }
110 if tr3 == 1 { pass = pass + 1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
111 gw("T-R3c MCP resources/read doctrine -> contents with the operating text\n" as *u8)
112
113 let rp1: *u8 = "POST /mcp HTTP/1.1\r\nHost: x\r\n\r\n{\"jsonrpc\":\"2.0\",\"id\":4,\"method\":\"prompts/list\"}" as *u8
114 let np1: i64 = ta_handle_pfx(TP, rp1, ta_slen(rp1), out)
115 tot = tot + 1
116 var tp1: i64 = 0
117 if tg_has(out, np1, "operate-nishi" as *u8) == 1 { if tg_has(out, np1, "ship-target" as *u8) == 1 { tp1 = 1 } }
118 if tp1 == 1 { pass = pass + 1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
119 gw("T-R3d MCP prompts/list -> 2 prompt templates\n" as *u8)
120
121 let rp2: *u8 = "POST /mcp HTTP/1.1\r\nHost: x\r\n\r\n{\"jsonrpc\":\"2.0\",\"id\":5,\"method\":\"prompts/get\",\"params\":{\"name\":\"ship-target\",\"arguments\":{\"target\":\"nx_widget\"}}}" as *u8
122 let np2: i64 = ta_handle_pfx(TP, rp2, ta_slen(rp2), out)
123 tot = tot + 1
124 var tp2: i64 = 0
125 if tg_has(out, np2, "\"messages\"" as *u8) == 1 { if tg_has(out, np2, "nx_widget" as *u8) == 1 { tp2 = 1 } }
126 if tp2 == 1 { pass = pass + 1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
127 gw("T-R3e MCP prompts/get ship-target -> messages with the target arg filled\n" as *u8)
128
129 // ---- R2 argv passing: params.arguments.argv (JSON string array) -> native argv (multi-arg tools/call) ----
130 let av: *i64 = sys_mmap(8192) as *i64
131 let sb: *u8 = sys_mmap(65536)
132
133 // T6: a realistic 4-element argv is parsed positionally (this is exactly nx_mgmt_client's call shape)
134 let jb6: *u8 = "{\"params\":{\"name\":\"nx_mgmt_client\",\"arguments\":{\"argv\":[\"https://nishifamily.com\",\"call\",\"GET\",\"/api/health\"]}}}" as *u8
135 let ac6: i64 = ta_json_str_array(jb6, ta_slen(jb6), "\"argv\"" as *u8, av, 1, 250, sb, 65536)
136 tot = tot + 1
137 var t6: i64 = 0
138 if ac6 == 4 { if tg_streq(av[1], "https://nishifamily.com" as *u8) == 1 { if tg_streq(av[2], "call" as *u8) == 1 { if tg_streq(av[3], "GET" as *u8) == 1 { if tg_streq(av[4], "/api/health" as *u8) == 1 { t6 = 1 } } } } }
139 if t6 == 1 { pass = pass + 1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
140 gw("T6 tools/call argv: params.arguments.argv -> 4-element native argv (multi-arg organs callable)\n" as *u8)
141
142 // T7: no argv key -> 0 args (argless back-compat: already-working no-arg tools are unaffected)
143 let jb7: *u8 = "{\"params\":{\"name\":\"nx_http_probe\",\"arguments\":{}}}" as *u8
144 let ac7: i64 = ta_json_str_array(jb7, ta_slen(jb7), "\"argv\"" as *u8, av, 1, 250, sb, 65536)
145 tot = tot + 1
146 var t7: i64 = 0
147 if ac7 == 0 { t7 = 1 }
148 if t7 == 1 { pass = pass + 1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
149 gw("T7 tools/call no argv -> 0 args (argless back-compat preserved)\n" as *u8)
150
151 // T8: empty array [] -> 0 args (not treated as one empty arg)
152 let jb8: *u8 = "{\"argv\":[]}" as *u8
153 let ac8: i64 = ta_json_str_array(jb8, ta_slen(jb8), "\"argv\"" as *u8, av, 1, 250, sb, 65536)
154 tot = tot + 1
155 var t8: i64 = 0
156 if ac8 == 0 { t8 = 1 }
157 if t8 == 1 { pass = pass + 1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
158 gw("T8 tools/call empty argv [] -> 0 args\n" as *u8)
159
160 // T9: an escaped quote inside an arg must NOT terminate the string early. Build the input as RAW BYTES so no
161 // backslash source-literal is needed: {"argv":["a\"b"]} -> exactly one arg whose value is a"b (3 bytes).
162 let eb: *u8 = sys_mmap(64)
163 var eo: i64 = ta_cat(eb, 0, "{\"argv\":[\"a" as *u8)
164 eb[eo] = 92 as u8; eo = eo + 1 // literal backslash
165 eb[eo] = 34 as u8; eo = eo + 1 // literal quote
166 eo = ta_cat(eb, eo, "b\"]}" as *u8)
167 let ac9: i64 = ta_json_str_array(eb, eo, "\"argv\"" as *u8, av, 1, 250, sb, 65536)
168 tot = tot + 1
169 var t9: i64 = 0
170 if ac9 == 1 { if tg_streq(av[1], "a\"b" as *u8) == 1 { t9 = 1 } }
171 if t9 == 1 { pass = pass + 1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
172 gw("T9 tools/call argv JSON-unescape: an escaped quote inside an arg does not split it\n" as *u8)
173
174 // T10: maxn is honored -- a 4-element array with maxn=2 yields exactly 2 (fail-closed, no overflow)
175 let ac10: i64 = ta_json_str_array(jb6, ta_slen(jb6), "\"argv\"" as *u8, av, 1, 2, sb, 65536)
176 tot = tot + 1
177 var t10: i64 = 0
178 if ac10 == 2 { t10 = 1 }
179 if t10 == 1 { pass = pass + 1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
180 gw("T10 tools/call argv respects maxn cap (4 elems, maxn=2 -> 2, no overflow)\n" as *u8)
181
182 // ---- R1 rich MCP tool schemas: title + annotations (safety hints) + outputSchema, data-driven ----
183 tg_write("/tmp/tg_schemas.conf" as *u8, "argecho\tEcho Args\t1\t0\t1\t0\tnewline argv echo\n" as *u8)
184 let sb2: *u8 = sys_mmap(4096)
185
186 // T11: a KNOWN tool emits its title + ACCURATE annotations (read-only, non-destructive, idempotent) + outputSchema
187 let l11: i64 = ta_emit_mcp_schema_from("/tmp/tg_schemas.conf" as *u8, "argecho" as *u8, 7, sb2, 0)
188 tot = tot + 1
189 var t11: i64 = 0
190 if tg_has(sb2, l11, "\"title\":\"Echo Args\"" as *u8) == 1 { if tg_has(sb2, l11, "\"readOnlyHint\":true" as *u8) == 1 { if tg_has(sb2, l11, "\"destructiveHint\":false" as *u8) == 1 { if tg_has(sb2, l11, "\"outputSchema\"" as *u8) == 1 { t11 = 1 } } } }
191 if t11 == 1 { pass = pass + 1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
192 gw("T11 MCP rich schema: known tool -> title + accurate annotations + outputSchema (MCP tools-spec parity)\n" as *u8)
193
194 // T12: an UNKNOWN tool -> MCP-safe DEFAULT annotations (NOT read-only, POSSIBLY destructive) + NO title (cautious)
195 let l12: i64 = ta_emit_mcp_schema_from("/tmp/tg_schemas.conf" as *u8, "nosuchtool" as *u8, 10, sb2, 0)
196 tot = tot + 1
197 var t12: i64 = 0
198 if tg_has(sb2, l12, "\"readOnlyHint\":false" as *u8) == 1 { if tg_has(sb2, l12, "\"destructiveHint\":true" as *u8) == 1 { if tg_has(sb2, l12, "\"title\"" as *u8) == 0 { t12 = 1 } } }
199 if t12 == 1 { pass = pass + 1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
200 gw("T12 MCP rich schema: unknown tool -> cautious default annotations, no title (safe-by-default)\n" as *u8)
201
202 // ---- 07-30 QUERY-STRING CAP PRESENTER (ta_query_cap) + HONEST DENY -----------------------------------
203 // Closes the measured root cause of the shell-fallback cascade (debt seq1235): a client that drops the
204 // X-Nishi-Cap header denies EVERY call for a whole session, and the old deny text was indistinguishable
205 // from a missing tool. T14-T18 prove the parser; T19-T21 prove it is WIRED and the deny is honest.
206 let qo: *i64 = sys_mmap(16) as *i64
207
208 // T14: ?cap=<token> is extracted verbatim, and the presenter is COMPILED IN (liveness marker)
209 let q14: *u8 = "POST /mcp?cap=abc~123~7.def HTTP/1.1\r\nHost: x\r\n\r\n{}" as *u8
210 tot = tot + 1
211 var t14: i64 = 0
212 if ta_query_cap_available() == 1 { if ta_query_cap(q14, ta_slen(q14), qo) == 1 { if tg_slice_eq(q14, qo, "abc~123~7.def" as *u8) == 1 { t14 = 1 } } }
213 if t14 == 1 { pass = pass + 1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
214 gw("T14 query cap: ?cap=<token> extracted verbatim from the request line\n" as *u8)
215
216 // T15: no query string at all -> absent (0), never a garbage slice
217 let q15: *u8 = "POST /mcp HTTP/1.1\r\nHost: x\r\n\r\n{}" as *u8
218 tot = tot + 1
219 var t15: i64 = 0
220 if ta_query_cap(q15, ta_slen(q15), qo) == 0 { t15 = 1 }
221 if t15 == 1 { pass = pass + 1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
222 gw("T15 query cap: no query string -> absent (fail-closed)\n" as *u8)
223
224 // T16: a query with other params but no cap -> absent
225 let q16: *u8 = "POST /mcp?other=1&x=2 HTTP/1.1\r\nHost: x\r\n\r\n{}" as *u8
226 tot = tot + 1
227 var t16: i64 = 0
228 if ta_query_cap(q16, ta_slen(q16), qo) == 0 { t16 = 1 }
229 if t16 == 1 { pass = pass + 1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
230 gw("T16 query cap: query without a cap param -> absent\n" as *u8)
231
232 // T17 NEG-CONTROL (the seq1293 substring-shadowing class): the key must match EXACTLY cap. A lookalike
233 // param must NEVER authorize -- otherwise recap= or capx= would silently present a capability.
234 let q17: *u8 = "POST /mcp?capx=zzz&recap=yyy&scap=www HTTP/1.1\r\nHost: x\r\n\r\n{}" as *u8
235 tot = tot + 1
236 var t17: i64 = 0
237 if ta_query_cap(q17, ta_slen(q17), qo) == 0 { t17 = 1 }
238 if t17 == 1 { pass = pass + 1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
239 gw("T17 query cap NEG: capx/recap/scap lookalikes do NOT authorize (exact key only)\n" as *u8)
240
241 // T18: cap as a NON-FIRST pair is found, and its value stops at & (not swallowing the rest of the query)
242 let q18: *u8 = "POST /mcp?a=1&cap=TOK99&z=9 HTTP/1.1\r\nHost: x\r\n\r\n{}" as *u8
243 tot = tot + 1
244 var t18: i64 = 0
245 if ta_query_cap(q18, ta_slen(q18), qo) == 1 { if tg_slice_eq(q18, qo, "TOK99" as *u8) == 1 { t18 = 1 } }
246 if t18 == 1 { pass = pass + 1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
247 gw("T18 query cap: found as a non-first pair, value terminates at &\n" as *u8)
248
249 // T19: tools/call with NO cap -> the deny SAYS SO, says the tool exists, and says not to fall back to shell
250 let d19: *u8 = "POST /mcp HTTP/1.1\r\nHost: x\r\n\r\n{\"jsonrpc\":\"2.0\",\"id\":11,\"method\":\"tools/call\",\"params\":{\"name\":\"nx_http_probe\"}}" as *u8
251 let n19: i64 = ta_handle_pfx(TP, d19, ta_slen(d19), out)
252 tot = tot + 1
253 var t19: i64 = 0
254 if tg_has(out, n19, "-32001" as *u8) == 1 { if tg_has(out, n19, "NO capability was presented" as *u8) == 1 { if tg_has(out, n19, "\"presented\":0" as *u8) == 1 { if tg_has(out, n19, "do NOT fall back to shell" as *u8) == 1 { t19 = 1 } } } }
255 if t19 == 1 { pass = pass + 1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
256 gw("T19 honest deny: no cap -> NO-capability-presented + presented:0 + do-not-shell (not no-such-tool)\n" as *u8)
257
258 // T20: a PRESENTED-but-invalid cap gets the OPPOSITE message -- the two cases have opposite remedies
259 let d20: *u8 = "POST /mcp HTTP/1.1\r\nHost: x\r\n\r\n{\"jsonrpc\":\"2.0\",\"id\":12,\"method\":\"tools/call\",\"params\":{\"name\":\"nx_http_probe\",\"_cap\":\"bogus~1~1.zzz\"}}" as *u8
260 let n20: i64 = ta_handle_pfx(TP, d20, ta_slen(d20), out)
261 tot = tot + 1
262 var t20: i64 = 0
263 if tg_has(out, n20, "\"presented\":1" as *u8) == 1 { if tg_has(out, n20, "does not grant this tool" as *u8) == 1 { if tg_has(out, n20, "NO capability was presented" as *u8) == 0 { t20 = 1 } } }
264 if t20 == 1 { pass = pass + 1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
265 gw("T20 honest deny: invalid cap -> presented:1 + does-not-grant (distinct remedy)\n" as *u8)
266
267 // T21 NON-VACUITY: the SAME bogus cap delivered ONLY via ?cap= must also report presented:1. This is the
268 // test that FAILS if ta_query_cap exists but is never called from ta_mcp_call -- it proves the WIRE.
269 let d21: *u8 = "POST /mcp?cap=bogus~1~1.zzz HTTP/1.1\r\nHost: x\r\n\r\n{\"jsonrpc\":\"2.0\",\"id\":13,\"method\":\"tools/call\",\"params\":{\"name\":\"nx_http_probe\"}}" as *u8
270 let n21: i64 = ta_handle_pfx(TP, d21, ta_slen(d21), out)
271 tot = tot + 1
272 var t21: i64 = 0
273 if tg_has(out, n21, "\"presented\":1" as *u8) == 1 { if tg_has(out, n21, "NO capability was presented" as *u8) == 0 { t21 = 1 } }
274 if t21 == 1 { pass = pass + 1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
275 gw("T21 NON-VACUITY: a cap presented ONLY via ?cap= reaches ta_mcp_call (presented:1) -- the wire is live\n" as *u8)
276
277 gw("\n=== nx_tools_api_gate " as *u8); gn(pass); gw("/" as *u8); gn(tot); gw(" ===\n" as *u8)
278 if pass == tot { gw("TOOLS-API GREEN -- MCP-compatible (initialize+tools/list) + superset (gate-status), sovereign\n" as *u8); sys_exit(0); return 0 }
279 gw("TOOLS-API RED\n" as *u8); sys_exit(1); return 1
280}