nx_mcp_control.nx source
↩ module page · 180 lines · 7513 B
1// Borrowed MCP control metadata. JSON stays at the boundary; no value tree
2// survives in the long-lived connector. Scratch sizes derive from this input.
3import "nx_json.nx"
4import "nx_mcp_route.nx"
5
6struct NxMcpControl {
7 method: i64,
8 id_kind: i64,
9 id_off: i64,
10 id_len: i64,
11 cancel_kind: i64,
12 cancel_off: i64,
13 cancel_len: i64,
14}
15struct NxMcpControlFrame { mode: i64, key: i64, params: i64 }
16
17// Object modes: key-or-end, colon, value, comma-or-end, mandatory-key.
18// Array modes: value-or-end, comma-or-end, mandatory-value.
19const MCT_OBJ_KEY: i64 = 1
20const MCT_OBJ_COLON: i64 = 2
21const MCT_OBJ_VALUE: i64 = 3
22const MCT_OBJ_NEXT: i64 = 4
23const MCT_OBJ_REQUIRED: i64 = 5
24const MCT_ARR_VALUE: i64 = 6
25const MCT_ARR_NEXT: i64 = 7
26const MCT_ARR_REQUIRED: i64 = 8
27const MCT_INITIALIZE: i64 = 1
28const MCT_INITIALIZED: i64 = 2
29const MCT_CANCEL: i64 = 3
30const MCT_OTHER: i64 = 4
31
32func mct_frame(frames: *u8, index: i64) -> *NxMcpControlFrame {
33 return (frames + index*__size_of(NxMcpControlFrame)) as *NxMcpControlFrame
34}
35
36func mct_scan(t: *NxJsonTok, frames: *u8, scratch: *u8, out: *NxMcpControl) -> i64 {
37 if nx_json_next(t) != NX_JSON_LBRACE { return -1 }
38 var depth: i64 = 1
39 let root_frame: *NxMcpControlFrame = mct_frame(frames,0)
40 root_frame.mode = MCT_OBJ_KEY
41 var root_seen: i64 = 0
42 var cancel_seen: i64 = 0
43 while depth > 0 {
44 let token: i64 = nx_json_next(t)
45 if token == NX_JSON_ERROR { return -1 }
46 if token == NX_JSON_EOF { return -1 }
47 let f: *NxMcpControlFrame = mct_frame(frames,depth-1)
48 var decoded: i64 = -1
49 if token == NX_JSON_STRING {
50 decoded = jx_decode_span(t.src+t.tok_off+1,t.tok_len-2,scratch,t.len+1)
51 if decoded < 0 { return -1 }
52 }
53 if f.mode == MCT_OBJ_KEY || f.mode == MCT_OBJ_REQUIRED {
54 if token == NX_JSON_RBRACE {
55 if f.mode == MCT_OBJ_REQUIRED { return -1 }
56 depth = depth-1; continue
57 }
58 if token != NX_JSON_STRING { return -1 }
59 f.key = 0
60 if depth == 1 {
61 if mr_equal(scratch,decoded,"method" as *u8) == 1 { f.key = 1 }
62 if mr_equal(scratch,decoded,"id" as *u8) == 1 { f.key = 2 }
63 if mr_equal(scratch,decoded,"params" as *u8) == 1 { f.key = 4 }
64 if mr_equal(scratch,decoded,"jsonrpc" as *u8) == 1 { f.key = 8 }
65 if f.key != 0 {
66 if (root_seen & f.key) != 0 { return -1 }
67 root_seen = root_seen | f.key
68 }
69 }
70 if f.params != 0 {
71 if mr_equal(scratch,decoded,"requestId" as *u8) == 1 {
72 if cancel_seen != 0 { return -1 }
73 cancel_seen = 1; f.key = 16
74 }
75 }
76 f.mode = MCT_OBJ_COLON; continue
77 }
78 if f.mode == MCT_OBJ_COLON {
79 if token != NX_JSON_COLON { return -1 }
80 f.mode = MCT_OBJ_VALUE; continue
81 }
82 if f.mode == MCT_OBJ_NEXT {
83 if token == NX_JSON_RBRACE { depth = depth-1; continue }
84 if token != NX_JSON_COMMA { return -1 }
85 f.mode = MCT_OBJ_REQUIRED; continue
86 }
87 if f.mode == MCT_ARR_NEXT {
88 if token == NX_JSON_RBRACKET { depth = depth-1; continue }
89 if token != NX_JSON_COMMA { return -1 }
90 f.mode = MCT_ARR_REQUIRED; continue
91 }
92 if f.mode == MCT_ARR_VALUE {
93 if token == NX_JSON_RBRACKET { depth = depth-1; continue }
94 }
95 let key: i64 = f.key
96 if f.mode != MCT_OBJ_VALUE { f.key = 0 }
97 if f.mode == MCT_OBJ_VALUE { f.mode = MCT_OBJ_NEXT } else { f.mode = MCT_ARR_NEXT }
98 if depth == 1 {
99 if key == 1 {
100 if token != NX_JSON_STRING { return -1 }
101 out.method = MCT_OTHER
102 if mr_equal(scratch,decoded,"initialize" as *u8) == 1 { out.method = MCT_INITIALIZE }
103 if mr_equal(scratch,decoded,"notifications/initialized" as *u8) == 1 { out.method = MCT_INITIALIZED }
104 if mr_equal(scratch,decoded,"notifications/cancelled" as *u8) == 1 { out.method = MCT_CANCEL }
105 }
106 if key == 8 {
107 if token != NX_JSON_STRING { return -1 }
108 if mr_equal(scratch,decoded,"2.0" as *u8) != 1 { return -1 }
109 }
110 }
111 if key == 2 || key == 16 {
112 if token != NX_JSON_STRING { if token != NX_JSON_NUMBER { return -1 } }
113 if token == NX_JSON_NUMBER {
114 var digit: i64 = 0
115 if t.src[t.tok_off] == (45 as u8) { digit=1 }
116 if digit >= t.tok_len { return -1 }
117 if t.src[t.tok_off+digit] == (48 as u8) { if t.tok_len-digit != 1 { return -1 } }
118 while digit < t.tok_len {
119 if nx_ascii_is_digit(t.src[t.tok_off+digit]) == 0 { return -1 }
120 digit=digit+1
121 }
122 }
123 var offset: i64 = t.tok_off
124 var count: i64 = t.tok_len
125 if token == NX_JSON_STRING { offset = offset+1; count = count-2 }
126 if key == 2 { out.id_kind=token; out.id_off=offset; out.id_len=count }
127 if key == 16 { out.cancel_kind=token; out.cancel_off=offset; out.cancel_len=count }
128 }
129 if token == NX_JSON_LBRACE || token == NX_JSON_LBRACKET {
130 let child: *NxMcpControlFrame = mct_frame(frames,depth)
131 child.mode = MCT_OBJ_KEY
132 if token == NX_JSON_LBRACKET { child.mode = MCT_ARR_VALUE }
133 child.key = 0; child.params = 0
134 if depth == 1 { if key == 4 { if token == NX_JSON_LBRACE { child.params=1 } } }
135 depth = depth+1; continue
136 }
137 if token != NX_JSON_STRING { if token != NX_JSON_NUMBER {
138 if token != NX_JSON_TRUE { if token != NX_JSON_FALSE { if token != NX_JSON_NULL { return -1 } } }
139 } }
140 }
141 if nx_json_next(t) != NX_JSON_EOF { return -1 }
142 if (root_seen & 9) != 9 { return -1 }
143 if out.method == MCT_INITIALIZE { if out.id_kind == 0 { return -1 } }
144 if out.method == MCT_INITIALIZED { if out.id_kind != 0 { return -1 } }
145 if out.method == MCT_CANCEL {
146 if out.id_kind != 0 { return -1 }
147 if out.cancel_kind == 0 { return -1 }
148 }
149 return 0
150}
151
152func mct_read(src: *u8, n: i64, out: *NxMcpControl) -> i64 {
153 if n <= 0 { return -1 }
154 out.method=0; out.id_kind=0; out.id_off=0; out.id_len=0
155 out.cancel_kind=0; out.cancel_off=0; out.cancel_len=0
156 let t: *NxJsonTok = nx_json_new(src,n)
157 var depth: i64 = 0
158 var peak: i64 = 0
159 var valid: i64 = 1
160 while true {
161 let k: i64 = nx_json_next(t)
162 if k == NX_JSON_ERROR { valid=0; break }
163 if k == NX_JSON_EOF { break }
164 if k == NX_JSON_LBRACE || k == NX_JSON_LBRACKET { depth=depth+1; if depth>peak { peak=depth } }
165 if k == NX_JSON_RBRACE || k == NX_JSON_RBRACKET { depth=depth-1; if depth<0 { valid=0; break } }
166 }
167 var result: i64 = -1
168 if depth != 0 { valid=0 }
169 if peak == 0 { valid=0 }
170 if valid != 0 {
171 let frame_bytes: i64 = peak*__size_of(NxMcpControlFrame)
172 let frames: *u8 = sys_mmap(frame_bytes)
173 let scratch: *u8 = sys_mmap(n+1)
174 t.pos=0
175 result=mct_scan(t,frames,scratch,out)
176 sys_munmap(frames,frame_bytes); sys_munmap(scratch,n+1)
177 }
178 sys_munmap(t as *u8,__size_of(NxJsonTok))
179 return result
180}