mcp-trellis 1.0.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (296) hide show
  1. package/README.md +63 -93
  2. package/dist/adapters/node-request.d.ts +53 -0
  3. package/dist/adapters/node-request.d.ts.map +1 -0
  4. package/dist/adapters/node-request.js +165 -0
  5. package/dist/adapters/node-request.js.map +1 -0
  6. package/dist/adapters/node.d.ts +13 -30
  7. package/dist/adapters/node.d.ts.map +1 -1
  8. package/dist/adapters/node.js +55 -101
  9. package/dist/adapters/node.js.map +1 -1
  10. package/dist/advanced.d.ts +18 -0
  11. package/dist/advanced.d.ts.map +1 -0
  12. package/dist/advanced.js +18 -0
  13. package/dist/advanced.js.map +1 -0
  14. package/dist/app-options.d.ts +132 -0
  15. package/dist/app-options.d.ts.map +1 -0
  16. package/dist/app-options.js +2 -0
  17. package/dist/app-options.js.map +1 -0
  18. package/dist/app.d.ts +2 -89
  19. package/dist/app.d.ts.map +1 -1
  20. package/dist/app.js +143 -63
  21. package/dist/app.js.map +1 -1
  22. package/dist/audit.d.ts +5 -5
  23. package/dist/audit.d.ts.map +1 -1
  24. package/dist/audit.js +19 -8
  25. package/dist/audit.js.map +1 -1
  26. package/dist/auth/bearer.d.ts +4 -1
  27. package/dist/auth/bearer.d.ts.map +1 -1
  28. package/dist/auth/bearer.js +19 -4
  29. package/dist/auth/bearer.js.map +1 -1
  30. package/dist/clients.js +1 -1
  31. package/dist/clients.js.map +1 -1
  32. package/dist/deprecated.d.ts +42 -0
  33. package/dist/deprecated.d.ts.map +1 -0
  34. package/dist/deprecated.js +35 -0
  35. package/dist/deprecated.js.map +1 -0
  36. package/dist/{body.d.ts → http/body.d.ts} +27 -6
  37. package/dist/http/body.d.ts.map +1 -0
  38. package/dist/{body.js → http/body.js} +33 -13
  39. package/dist/http/body.js.map +1 -0
  40. package/dist/http/http.d.ts +42 -0
  41. package/dist/http/http.d.ts.map +1 -0
  42. package/dist/http/http.js +100 -0
  43. package/dist/http/http.js.map +1 -0
  44. package/dist/http/origins.d.ts +37 -0
  45. package/dist/http/origins.d.ts.map +1 -0
  46. package/dist/http/origins.js +87 -0
  47. package/dist/http/origins.js.map +1 -0
  48. package/dist/{dispatch.d.ts → mcp/dispatch.d.ts} +1 -1
  49. package/dist/mcp/dispatch.d.ts.map +1 -0
  50. package/dist/mcp/dispatch.js +99 -0
  51. package/dist/mcp/dispatch.js.map +1 -0
  52. package/dist/{jsonrpc.d.ts → mcp/jsonrpc.d.ts} +9 -0
  53. package/dist/mcp/jsonrpc.d.ts.map +1 -0
  54. package/dist/mcp/jsonrpc.js +88 -0
  55. package/dist/mcp/jsonrpc.js.map +1 -0
  56. package/dist/{methods.d.ts → mcp/methods.d.ts} +60 -11
  57. package/dist/mcp/methods.d.ts.map +1 -0
  58. package/dist/mcp/methods.js +84 -0
  59. package/dist/mcp/methods.js.map +1 -0
  60. package/dist/{protocol.d.ts → mcp/protocol.d.ts} +1 -3
  61. package/dist/mcp/protocol.d.ts.map +1 -0
  62. package/dist/{protocol.js → mcp/protocol.js} +1 -3
  63. package/dist/mcp/protocol.js.map +1 -0
  64. package/dist/mcp/registry.d.ts +58 -0
  65. package/dist/mcp/registry.d.ts.map +1 -0
  66. package/dist/mcp/registry.js +81 -0
  67. package/dist/mcp/registry.js.map +1 -0
  68. package/dist/mcp/rpc-handlers.d.ts +11 -0
  69. package/dist/mcp/rpc-handlers.d.ts.map +1 -0
  70. package/dist/mcp/rpc-handlers.js +133 -0
  71. package/dist/mcp/rpc-handlers.js.map +1 -0
  72. package/dist/{tools.d.ts → mcp/tools.d.ts} +20 -1
  73. package/dist/mcp/tools.d.ts.map +1 -0
  74. package/dist/mcp/tools.js +166 -0
  75. package/dist/mcp/tools.js.map +1 -0
  76. package/dist/{validate.d.ts → mcp/validate.d.ts} +18 -21
  77. package/dist/mcp/validate.d.ts.map +1 -0
  78. package/dist/{validate.js → mcp/validate.js} +59 -41
  79. package/dist/mcp/validate.js.map +1 -0
  80. package/dist/oauth/audit.d.ts +20 -0
  81. package/dist/oauth/audit.d.ts.map +1 -0
  82. package/dist/oauth/audit.js +29 -0
  83. package/dist/oauth/audit.js.map +1 -0
  84. package/dist/oauth/cimd/cimd-parse.d.ts +4 -0
  85. package/dist/oauth/cimd/cimd-parse.d.ts.map +1 -0
  86. package/dist/oauth/cimd/cimd-parse.js +70 -0
  87. package/dist/oauth/cimd/cimd-parse.js.map +1 -0
  88. package/dist/oauth/cimd/cimd-ssrf.d.ts +8 -0
  89. package/dist/oauth/cimd/cimd-ssrf.d.ts.map +1 -0
  90. package/dist/oauth/cimd/cimd-ssrf.js +193 -0
  91. package/dist/oauth/cimd/cimd-ssrf.js.map +1 -0
  92. package/dist/oauth/cimd/cimd.d.ts +36 -0
  93. package/dist/oauth/cimd/cimd.d.ts.map +1 -0
  94. package/dist/oauth/cimd/cimd.js +132 -0
  95. package/dist/oauth/cimd/cimd.js.map +1 -0
  96. package/dist/oauth/cimd/types.d.ts +12 -0
  97. package/dist/oauth/cimd/types.d.ts.map +1 -0
  98. package/dist/oauth/cimd/types.js +3 -0
  99. package/dist/oauth/cimd/types.js.map +1 -0
  100. package/dist/oauth/config.d.ts +51 -0
  101. package/dist/oauth/config.d.ts.map +1 -0
  102. package/dist/oauth/config.js +108 -0
  103. package/dist/oauth/config.js.map +1 -0
  104. package/dist/oauth/constants.d.ts +11 -0
  105. package/dist/oauth/constants.d.ts.map +1 -1
  106. package/dist/oauth/constants.js +11 -0
  107. package/dist/oauth/constants.js.map +1 -1
  108. package/dist/oauth/{base64url.d.ts → crypto/base64url.d.ts} +0 -1
  109. package/dist/oauth/crypto/base64url.d.ts.map +1 -0
  110. package/dist/oauth/{base64url.js → crypto/base64url.js} +0 -1
  111. package/dist/oauth/crypto/base64url.js.map +1 -0
  112. package/dist/oauth/crypto/clientauth.d.ts +13 -0
  113. package/dist/oauth/crypto/clientauth.d.ts.map +1 -0
  114. package/dist/oauth/crypto/clientauth.js +195 -0
  115. package/dist/oauth/crypto/clientauth.js.map +1 -0
  116. package/dist/oauth/crypto/codes.d.ts +65 -0
  117. package/dist/oauth/crypto/codes.d.ts.map +1 -0
  118. package/dist/oauth/crypto/codes.js +121 -0
  119. package/dist/oauth/crypto/codes.js.map +1 -0
  120. package/dist/oauth/crypto/hkdf.d.ts +13 -0
  121. package/dist/oauth/crypto/hkdf.d.ts.map +1 -0
  122. package/dist/oauth/crypto/hkdf.js +30 -0
  123. package/dist/oauth/crypto/hkdf.js.map +1 -0
  124. package/dist/oauth/crypto/keycache.d.ts +19 -0
  125. package/dist/oauth/crypto/keycache.d.ts.map +1 -0
  126. package/dist/oauth/crypto/keycache.js +44 -0
  127. package/dist/oauth/crypto/keycache.js.map +1 -0
  128. package/dist/oauth/crypto/pkce.d.ts.map +1 -0
  129. package/dist/oauth/{pkce.js → crypto/pkce.js} +1 -1
  130. package/dist/oauth/crypto/pkce.js.map +1 -0
  131. package/dist/oauth/{sealed.d.ts → crypto/sealed.d.ts} +12 -3
  132. package/dist/oauth/crypto/sealed.d.ts.map +1 -0
  133. package/dist/oauth/{sealed.js → crypto/sealed.js} +22 -14
  134. package/dist/oauth/crypto/sealed.js.map +1 -0
  135. package/dist/oauth/{secrethash.d.ts → crypto/secrethash.d.ts} +14 -0
  136. package/dist/oauth/crypto/secrethash.d.ts.map +1 -0
  137. package/dist/oauth/{secrethash.js → crypto/secrethash.js} +27 -11
  138. package/dist/oauth/crypto/secrethash.js.map +1 -0
  139. package/dist/oauth/deprecated.d.ts +52 -0
  140. package/dist/oauth/deprecated.d.ts.map +1 -0
  141. package/dist/oauth/deprecated.js +49 -0
  142. package/dist/oauth/deprecated.js.map +1 -0
  143. package/dist/oauth/endpoints/authorize.d.ts +3 -0
  144. package/dist/oauth/endpoints/authorize.d.ts.map +1 -0
  145. package/dist/oauth/endpoints/authorize.js +209 -0
  146. package/dist/oauth/endpoints/authorize.js.map +1 -0
  147. package/dist/oauth/endpoints/callback.d.ts +20 -0
  148. package/dist/oauth/endpoints/callback.d.ts.map +1 -0
  149. package/dist/oauth/endpoints/callback.js +31 -0
  150. package/dist/oauth/endpoints/callback.js.map +1 -0
  151. package/dist/oauth/endpoints/consent-page.d.ts +5 -0
  152. package/dist/oauth/endpoints/consent-page.d.ts.map +1 -0
  153. package/dist/oauth/endpoints/consent-page.js +63 -0
  154. package/dist/oauth/endpoints/consent-page.js.map +1 -0
  155. package/dist/oauth/endpoints/consent.d.ts +29 -0
  156. package/dist/oauth/endpoints/consent.d.ts.map +1 -0
  157. package/dist/oauth/endpoints/consent.js +98 -0
  158. package/dist/oauth/endpoints/consent.js.map +1 -0
  159. package/dist/oauth/{metadata.d.ts → endpoints/metadata.d.ts} +8 -2
  160. package/dist/oauth/endpoints/metadata.d.ts.map +1 -0
  161. package/dist/oauth/{metadata.js → endpoints/metadata.js} +10 -4
  162. package/dist/oauth/endpoints/metadata.js.map +1 -0
  163. package/dist/oauth/endpoints/register.d.ts +10 -0
  164. package/dist/oauth/endpoints/register.d.ts.map +1 -0
  165. package/dist/oauth/endpoints/register.js +96 -0
  166. package/dist/oauth/endpoints/register.js.map +1 -0
  167. package/dist/oauth/{revoke.d.ts → endpoints/revoke.d.ts} +1 -1
  168. package/dist/oauth/endpoints/revoke.d.ts.map +1 -0
  169. package/dist/oauth/{revoke.js → endpoints/revoke.js} +8 -18
  170. package/dist/oauth/endpoints/revoke.js.map +1 -0
  171. package/dist/oauth/endpoints/token.d.ts +3 -0
  172. package/dist/oauth/endpoints/token.d.ts.map +1 -0
  173. package/dist/oauth/{token.js → endpoints/token.js} +32 -25
  174. package/dist/oauth/endpoints/token.js.map +1 -0
  175. package/dist/oauth/{wellknown.d.ts → endpoints/wellknown.d.ts} +1 -1
  176. package/dist/oauth/endpoints/wellknown.d.ts.map +1 -0
  177. package/dist/oauth/{wellknown.js → endpoints/wellknown.js} +7 -9
  178. package/dist/oauth/endpoints/wellknown.js.map +1 -0
  179. package/dist/oauth/policy/redirect.d.ts.map +1 -0
  180. package/dist/oauth/policy/redirect.js.map +1 -0
  181. package/dist/oauth/policy/reqbody.d.ts +18 -0
  182. package/dist/oauth/policy/reqbody.d.ts.map +1 -0
  183. package/dist/oauth/policy/reqbody.js +68 -0
  184. package/dist/oauth/policy/reqbody.js.map +1 -0
  185. package/dist/oauth/{resource.d.ts → policy/resource.d.ts} +1 -1
  186. package/dist/oauth/policy/resource.d.ts.map +1 -0
  187. package/dist/oauth/{resource.js → policy/resource.js} +2 -2
  188. package/dist/oauth/policy/resource.js.map +1 -0
  189. package/dist/oauth/{scope.d.ts → policy/scope.d.ts} +2 -2
  190. package/dist/oauth/policy/scope.d.ts.map +1 -0
  191. package/dist/oauth/{scope.js → policy/scope.js} +3 -3
  192. package/dist/oauth/policy/scope.js.map +1 -0
  193. package/dist/oauth/router.d.ts +10 -13
  194. package/dist/oauth/router.d.ts.map +1 -1
  195. package/dist/oauth/router.js +93 -115
  196. package/dist/oauth/router.js.map +1 -1
  197. package/dist/oauth/types.d.ts +99 -45
  198. package/dist/oauth/types.d.ts.map +1 -1
  199. package/dist/oauth/types.js +1 -90
  200. package/dist/oauth/types.js.map +1 -1
  201. package/dist/server.d.ts +12 -12
  202. package/dist/server.d.ts.map +1 -1
  203. package/dist/server.js +9 -8
  204. package/dist/server.js.map +1 -1
  205. package/dist/util/defined.d.ts +11 -0
  206. package/dist/util/defined.d.ts.map +1 -0
  207. package/dist/util/defined.js +15 -0
  208. package/dist/util/defined.js.map +1 -0
  209. package/dist/util/json.d.ts +3 -0
  210. package/dist/util/json.d.ts.map +1 -0
  211. package/dist/util/json.js +3 -0
  212. package/dist/util/json.js.map +1 -0
  213. package/docs/ROADMAP.md +35 -47
  214. package/docs/compatibility.md +84 -0
  215. package/docs/diagrams/mcp-trellis-architecture.html +305 -0
  216. package/docs/guide.md +37 -13
  217. package/docs/reference.md +54 -22
  218. package/docs/security.md +58 -9
  219. package/docs/troubleshooting.md +19 -0
  220. package/package.json +23 -10
  221. package/dist/adapters/origins.d.ts +0 -19
  222. package/dist/adapters/origins.d.ts.map +0 -1
  223. package/dist/adapters/origins.js +0 -52
  224. package/dist/adapters/origins.js.map +0 -1
  225. package/dist/body.d.ts.map +0 -1
  226. package/dist/body.js.map +0 -1
  227. package/dist/dispatch.d.ts.map +0 -1
  228. package/dist/dispatch.js +0 -119
  229. package/dist/dispatch.js.map +0 -1
  230. package/dist/http.d.ts +0 -17
  231. package/dist/http.d.ts.map +0 -1
  232. package/dist/http.js +0 -38
  233. package/dist/http.js.map +0 -1
  234. package/dist/jsonrpc.d.ts.map +0 -1
  235. package/dist/jsonrpc.js +0 -18
  236. package/dist/jsonrpc.js.map +0 -1
  237. package/dist/methods.d.ts.map +0 -1
  238. package/dist/methods.js +0 -130
  239. package/dist/methods.js.map +0 -1
  240. package/dist/oauth/authorize.d.ts +0 -3
  241. package/dist/oauth/authorize.d.ts.map +0 -1
  242. package/dist/oauth/authorize.js +0 -141
  243. package/dist/oauth/authorize.js.map +0 -1
  244. package/dist/oauth/base64url.d.ts.map +0 -1
  245. package/dist/oauth/base64url.js.map +0 -1
  246. package/dist/oauth/clientauth.d.ts +0 -24
  247. package/dist/oauth/clientauth.d.ts.map +0 -1
  248. package/dist/oauth/clientauth.js +0 -119
  249. package/dist/oauth/clientauth.js.map +0 -1
  250. package/dist/oauth/codes.d.ts +0 -30
  251. package/dist/oauth/codes.d.ts.map +0 -1
  252. package/dist/oauth/codes.js +0 -85
  253. package/dist/oauth/codes.js.map +0 -1
  254. package/dist/oauth/consent.d.ts +0 -65
  255. package/dist/oauth/consent.d.ts.map +0 -1
  256. package/dist/oauth/consent.js +0 -173
  257. package/dist/oauth/consent.js.map +0 -1
  258. package/dist/oauth/metadata.d.ts.map +0 -1
  259. package/dist/oauth/metadata.js.map +0 -1
  260. package/dist/oauth/pkce.d.ts.map +0 -1
  261. package/dist/oauth/pkce.js.map +0 -1
  262. package/dist/oauth/redirect.d.ts.map +0 -1
  263. package/dist/oauth/redirect.js.map +0 -1
  264. package/dist/oauth/reqbody.d.ts +0 -10
  265. package/dist/oauth/reqbody.d.ts.map +0 -1
  266. package/dist/oauth/reqbody.js +0 -29
  267. package/dist/oauth/reqbody.js.map +0 -1
  268. package/dist/oauth/resource.d.ts.map +0 -1
  269. package/dist/oauth/resource.js.map +0 -1
  270. package/dist/oauth/revoke.d.ts.map +0 -1
  271. package/dist/oauth/revoke.js.map +0 -1
  272. package/dist/oauth/scope.d.ts.map +0 -1
  273. package/dist/oauth/scope.js.map +0 -1
  274. package/dist/oauth/sealed.d.ts.map +0 -1
  275. package/dist/oauth/sealed.js.map +0 -1
  276. package/dist/oauth/secrethash.d.ts.map +0 -1
  277. package/dist/oauth/secrethash.js.map +0 -1
  278. package/dist/oauth/token.d.ts +0 -3
  279. package/dist/oauth/token.d.ts.map +0 -1
  280. package/dist/oauth/token.js.map +0 -1
  281. package/dist/oauth/wellknown.d.ts.map +0 -1
  282. package/dist/oauth/wellknown.js.map +0 -1
  283. package/dist/protocol.d.ts.map +0 -1
  284. package/dist/protocol.js.map +0 -1
  285. package/dist/registry.d.ts +0 -37
  286. package/dist/registry.d.ts.map +0 -1
  287. package/dist/registry.js +0 -77
  288. package/dist/registry.js.map +0 -1
  289. package/dist/tools.d.ts.map +0 -1
  290. package/dist/tools.js +0 -98
  291. package/dist/tools.js.map +0 -1
  292. package/dist/validate.d.ts.map +0 -1
  293. package/dist/validate.js.map +0 -1
  294. /package/dist/oauth/{pkce.d.ts → crypto/pkce.d.ts} +0 -0
  295. /package/dist/oauth/{redirect.d.ts → policy/redirect.d.ts} +0 -0
  296. /package/dist/oauth/{redirect.js → policy/redirect.js} +0 -0
@@ -33,30 +33,47 @@ const concatBytes = (chunks, total) => {
33
33
  };
34
34
  const toBytes = (chunk) => typeof chunk === "string" ? new TextEncoder().encode(chunk) : chunk;
35
35
  /**
36
- * Reads a Web `Request` body as text, rejecting early on an honest
37
- * oversized `Content-Length`, then aborting mid-stream — before the whole
38
- * body is buffered — if a chunked body (no `Content-Length`) exceeds
39
- * `maxBytes`. Falls back to `request.text()` when `request.body` is null
40
- * (some runtimes don't expose a streaming body), still enforcing the cap.
36
+ * Reads a bounded body as raw bytes, rejecting early on an honest oversized
37
+ * `Content-Length`, then aborting mid-stream — before the whole body is
38
+ * buffered — if a chunked body (no `Content-Length`) exceeds `maxBytes`.
39
+ * Falls back to `source.arrayBuffer()` (or `source.text()`) when
40
+ * `source.body` is null (some runtimes don't expose a streaming body),
41
+ * still enforcing the cap.
42
+ *
43
+ * Optional `signal` cancels the active reader on abort — needed when a hop
44
+ * timeout must stop a stalled stream (a locked `body.cancel()` is a no-op).
41
45
  */
42
- export const readBoundedText = async (request, maxBytes) => {
43
- const declared = declaredContentLength(request.headers);
46
+ export const readBoundedBytes = async (source, maxBytes, signal) => {
47
+ if (signal?.aborted)
48
+ throw new Error("body read aborted");
49
+ const declared = declaredContentLength(source.headers);
44
50
  if (declared !== null && declared > maxBytes) {
45
51
  throw new BodyTooLargeError(maxBytes);
46
52
  }
47
- const reader = request.body?.getReader();
53
+ const reader = source.body?.getReader();
48
54
  if (!reader) {
49
- const text = await request.text();
50
- if (new TextEncoder().encode(text).byteLength > maxBytes) {
55
+ // ponytail: no stream → arrayBuffer/text ignore signal; fine for request
56
+ // bodies. CIMD always has a stream on Node/undici. Upgrade: race abort
57
+ // or refuse the fallback when signal is required.
58
+ const bytes = source.arrayBuffer
59
+ ? new Uint8Array(await source.arrayBuffer())
60
+ : new TextEncoder().encode(await source.text());
61
+ if (bytes.byteLength > maxBytes)
51
62
  throw new BodyTooLargeError(maxBytes);
52
- }
53
- return text;
63
+ return bytes;
54
64
  }
65
+ const onAbort = () => {
66
+ void reader.cancel().catch(() => { });
67
+ };
68
+ signal?.addEventListener("abort", onAbort, { once: true });
55
69
  const chunks = [];
56
70
  let total = 0;
57
71
  try {
58
72
  for (;;) {
59
73
  const { done, value } = await reader.read();
74
+ // Cancel may settle read() as done — still treat abort as failure.
75
+ if (signal?.aborted)
76
+ throw new Error("body read aborted");
60
77
  if (done)
61
78
  break;
62
79
  // ponytail: one oversized chunk can briefly allocate maxBytes + highWaterMark
@@ -68,10 +85,13 @@ export const readBoundedText = async (request, maxBytes) => {
68
85
  }
69
86
  }
70
87
  finally {
88
+ signal?.removeEventListener("abort", onAbort);
71
89
  await reader.cancel().catch(() => { });
72
90
  }
73
- return new TextDecoder().decode(concatBytes(chunks, total));
91
+ return concatBytes(chunks, total);
74
92
  };
93
+ /** `readBoundedBytes`, decoded as UTF-8 — for JSON / form / text bodies. */
94
+ export const readBoundedText = async (source, maxBytes, signal) => new TextDecoder().decode(await readBoundedBytes(source, maxBytes, signal));
75
95
  export const isNodeReadable = (value) => typeof value?.on === "function" &&
76
96
  typeof value?.pause === "function" &&
77
97
  typeof value?.removeListener === "function";
@@ -0,0 +1 @@
1
+ {"version":3,"file":"body.js","sourceRoot":"","sources":["../../src/http/body.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ /** JSON `error` body / audit reason when a host port throws. */
2
+ export declare const INTERNAL_ERROR = "internal_error";
3
+ /** A caught value's audit-safe message — an `Error`'s own message, else its `String()` form. */
4
+ export declare const errorReason: (caught: unknown) => string;
5
+ /** Default cap on how long a response waits for an audit sink. */
6
+ export declare const DEFAULT_AUDIT_TIMEOUT_MS = 1000;
7
+ /**
8
+ * Run an audit sink so it can neither fail nor stall the response: errors
9
+ * are swallowed, and the wait is capped at `timeoutMs`. The timer is cleared
10
+ * as soon as the sink settles — a fast sink must not leave a pending timer
11
+ * holding the process (or a serverless invocation) open. Shared by the MCP
12
+ * `safeAudit` and OAuth `safeOAuthAudit`.
13
+ */
14
+ export declare const runAuditBounded: (sink: () => void | Promise<void>, timeoutMs: number) => Promise<void>;
15
+ export declare const corsHeaders: (extra?: Record<string, string>) => Record<string, string>;
16
+ export type JsonResponseOptions = {
17
+ /** Include permissive CORS headers. Default true (MCP). OAuth token set false. */
18
+ cors?: boolean;
19
+ };
20
+ /** Single-object JSON response — keeps the call site under the ≤3-params rule. */
21
+ export type JsonResponseInput = {
22
+ data: unknown;
23
+ status?: number;
24
+ headers?: Record<string, string>;
25
+ cors?: boolean;
26
+ };
27
+ export declare const jsonResponse: (input: JsonResponseInput) => Response;
28
+ export declare const emptyResponse: (status: number) => Response;
29
+ export declare const optionsResponse: (options?: JsonResponseOptions) => Response;
30
+ /** Reflect a validated browser Origin on MCP CORS instead of `*`. */
31
+ export declare const withReflectedCorsOrigin: (response: Response, origin: string) => Response;
32
+ export declare const methodNotAllowed: (message?: string, options?: JsonResponseOptions) => Response;
33
+ export declare const GET_ONLY: ReadonlySet<string>;
34
+ export declare const POST_ONLY: ReadonlySet<string>;
35
+ /** For endpoints that must not send permissive CORS headers (`/token`, `/revoke`, `/consent`). */
36
+ export declare const NO_CORS: JsonResponseOptions;
37
+ /**
38
+ * OPTIONS → 204; allowed verb → null (continue); otherwise → 405.
39
+ * Shared by OAuth handlers that all need the same method gate.
40
+ */
41
+ export declare const requireHttpMethod: (request: Request, allowed: ReadonlySet<string>, options?: JsonResponseOptions) => Response | null;
42
+ //# sourceMappingURL=http.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/http/http.ts"],"names":[],"mappings":"AAAA,gEAAgE;AAChE,eAAO,MAAM,cAAc,mBAAmB,CAAC;AAE/C,gGAAgG;AAChG,eAAO,MAAM,WAAW,GAAI,QAAQ,OAAO,KAAG,MACa,CAAC;AAE5D,kEAAkE;AAClE,eAAO,MAAM,wBAAwB,OAAO,CAAC;AAE7C;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,GAC1B,MAAM,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,EAChC,WAAW,MAAM,KAChB,OAAO,CAAC,IAAI,CAiBd,CAAC;AAEF,eAAO,MAAM,WAAW,GAAI,QAAQ,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAUhF,CAAC;AAEH,MAAM,MAAM,mBAAmB,GAAG;IAChC,kFAAkF;IAClF,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB,CAAC;AAEF,kFAAkF;AAClF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB,CAAC;AAEF,eAAO,MAAM,YAAY,GAAI,OAAO,iBAAiB,KAAG,QAWvD,CAAC;AAEF,eAAO,MAAM,aAAa,GAAI,QAAQ,MAAM,KAAG,QAI3C,CAAC;AAEL,eAAO,MAAM,eAAe,GAAI,UAAU,mBAAmB,KAAG,QAO5D,CAAC;AAEL,qEAAqE;AACrE,eAAO,MAAM,uBAAuB,GAAI,UAAU,QAAQ,EAAE,QAAQ,MAAM,KAAG,QAU5E,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAC3B,gBAA8B,EAC9B,UAAU,mBAAmB,KAC5B,QAKC,CAAC;AAEL,eAAO,MAAM,QAAQ,EAAE,WAAW,CAAC,MAAM,CAAoB,CAAC;AAC9D,eAAO,MAAM,SAAS,EAAE,WAAW,CAAC,MAAM,CAAqB,CAAC;AAChE,kGAAkG;AAClG,eAAO,MAAM,OAAO,EAAE,mBAAqC,CAAC;AAE5D;;;GAGG;AACH,eAAO,MAAM,iBAAiB,GAC5B,SAAS,OAAO,EAChB,SAAS,WAAW,CAAC,MAAM,CAAC,EAC5B,UAAU,mBAAmB,KAC5B,QAAQ,GAAG,IAIb,CAAC"}
@@ -0,0 +1,100 @@
1
+ /** JSON `error` body / audit reason when a host port throws. */
2
+ export const INTERNAL_ERROR = "internal_error";
3
+ /** A caught value's audit-safe message — an `Error`'s own message, else its `String()` form. */
4
+ export const errorReason = (caught) => caught instanceof Error ? caught.message : String(caught);
5
+ /** Default cap on how long a response waits for an audit sink. */
6
+ export const DEFAULT_AUDIT_TIMEOUT_MS = 1000;
7
+ /**
8
+ * Run an audit sink so it can neither fail nor stall the response: errors
9
+ * are swallowed, and the wait is capped at `timeoutMs`. The timer is cleared
10
+ * as soon as the sink settles — a fast sink must not leave a pending timer
11
+ * holding the process (or a serverless invocation) open. Shared by the MCP
12
+ * `safeAudit` and OAuth `safeOAuthAudit`.
13
+ */
14
+ export const runAuditBounded = async (sink, timeoutMs) => {
15
+ const settled = (async () => {
16
+ try {
17
+ await sink();
18
+ }
19
+ catch {
20
+ // Intentionally ignored.
21
+ }
22
+ })();
23
+ let timer;
24
+ const timeout = new Promise((resolve) => {
25
+ timer = setTimeout(resolve, timeoutMs);
26
+ });
27
+ try {
28
+ await Promise.race([settled, timeout]);
29
+ }
30
+ finally {
31
+ clearTimeout(timer);
32
+ }
33
+ };
34
+ export const corsHeaders = (extra) => ({
35
+ "Access-Control-Allow-Origin": "*",
36
+ "Access-Control-Allow-Methods": "GET, POST, OPTIONS",
37
+ "Access-Control-Allow-Headers": "Content-Type, Authorization, MCP-Protocol-Version",
38
+ // Response headers are opaque to browser JS by default unless explicitly
39
+ // exposed — without this, a browser-based MCP client reading a 401 can
40
+ // see the status but not WWW-Authenticate itself, i.e. not the
41
+ // resource_metadata URL RFC 9728 discovery depends on.
42
+ "Access-Control-Expose-Headers": "WWW-Authenticate",
43
+ ...extra,
44
+ });
45
+ export const jsonResponse = (input) => {
46
+ const cors = input.cors !== false;
47
+ return new Response(JSON.stringify(input.data), {
48
+ status: input.status ?? 200,
49
+ headers: {
50
+ "Content-Type": "application/json",
51
+ "Cache-Control": "no-store",
52
+ ...(cors ? corsHeaders() : {}),
53
+ ...input.headers,
54
+ },
55
+ });
56
+ };
57
+ export const emptyResponse = (status) => new Response(null, {
58
+ status,
59
+ headers: { ...corsHeaders(), "Cache-Control": "no-store" },
60
+ });
61
+ export const optionsResponse = (options) => new Response(null, {
62
+ status: 204,
63
+ headers: options?.cors === false
64
+ ? { "Cache-Control": "no-store" }
65
+ : { ...corsHeaders(), "Cache-Control": "no-store" },
66
+ });
67
+ /** Reflect a validated browser Origin on MCP CORS instead of `*`. */
68
+ export const withReflectedCorsOrigin = (response, origin) => {
69
+ const headers = new Headers(response.headers);
70
+ if (!headers.has("Access-Control-Allow-Origin"))
71
+ return response;
72
+ headers.set("Access-Control-Allow-Origin", origin);
73
+ headers.set("Vary", "Origin");
74
+ return new Response(response.body, {
75
+ status: response.status,
76
+ statusText: response.statusText,
77
+ headers,
78
+ });
79
+ };
80
+ export const methodNotAllowed = (message = "Method not allowed", options) => jsonResponse({
81
+ data: { error: message },
82
+ status: 405,
83
+ ...(options?.cors !== undefined ? { cors: options.cors } : {}),
84
+ });
85
+ export const GET_ONLY = new Set(["GET"]);
86
+ export const POST_ONLY = new Set(["POST"]);
87
+ /** For endpoints that must not send permissive CORS headers (`/token`, `/revoke`, `/consent`). */
88
+ export const NO_CORS = { cors: false };
89
+ /**
90
+ * OPTIONS → 204; allowed verb → null (continue); otherwise → 405.
91
+ * Shared by OAuth handlers that all need the same method gate.
92
+ */
93
+ export const requireHttpMethod = (request, allowed, options) => {
94
+ if (request.method === "OPTIONS")
95
+ return optionsResponse(options);
96
+ if (allowed.has(request.method))
97
+ return null;
98
+ return methodNotAllowed(undefined, options);
99
+ };
100
+ //# sourceMappingURL=http.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/http/http.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Origin allowlisting — Host-derived Node origins (multi-tenant) and browser
3
+ * `Origin` headers on MCP (DNS rebinding / CSRF). Same predicate shape as
4
+ * redirect allowlisting — not secret comparison.
5
+ */
6
+ export type OriginAllowlistOptions = {
7
+ /**
8
+ * Exact origins (`https://acme.example.com`) and/or `*.example.com`
9
+ * wildcards. Wildcards match https subdomains only (not the apex, not http).
10
+ * `"*"` admits any origin (loud opt-out).
11
+ *
12
+ * Empty/omitted list → admit all (only safe with a fixed `asNodeHandler`
13
+ * `origin`). Host-derived `asNodeHandler` requires a non-empty list at
14
+ * construction. Resolved origin outside the list → 400; a fixed `origin`
15
+ * absent from a non-empty list throws at construction.
16
+ */
17
+ allowedOrigins?: string[];
18
+ };
19
+ /**
20
+ * Host-derived / allowlist Origin check (Node `asNodeHandler` multi-tenant).
21
+ * Empty or omitted `allowedOrigins` → admit all (callers that derive origin
22
+ * from Host must require a non-empty list before reaching here).
23
+ * `"*"` admits any origin.
24
+ */
25
+ export declare const isAllowedOrigin: (origin: string, options?: OriginAllowlistOptions) => boolean;
26
+ /**
27
+ * Browser `Origin` on MCP Streamable HTTP (DNS rebinding / CSRF).
28
+ * No header → allow (native / server-to-server). Empty or omitted allowlist →
29
+ * deny any present Origin (secure default — opposite of `isAllowedOrigin`).
30
+ * `"*"` opts out.
31
+ */
32
+ export declare const isAllowedRequestOrigin: (originHeader: string | null, allowedRequestOrigins?: string[]) => boolean;
33
+ /** 403 when a present Origin fails the allowlist. `onDenied` runs first (audit). */
34
+ export declare const requestOriginDenied: (request: Request, allowedRequestOrigins: string[] | undefined, onDenied?: () => Promise<void>) => Promise<Response | null>;
35
+ /** When a non-wildcard allowlist admitted this Origin, reflect it on CORS. */
36
+ export declare const reflectCorsIfNeeded: (response: Response, request: Request, allowedRequestOrigins: string[] | undefined) => Response;
37
+ //# sourceMappingURL=origins.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"origins.d.ts","sourceRoot":"","sources":["../../src/http/origins.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,MAAM,MAAM,sBAAsB,GAAG;IACnC;;;;;;;;;OASG;IACH,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;CAC3B,CAAC;AAyCF;;;;;GAKG;AACH,eAAO,MAAM,eAAe,GAAI,QAAQ,MAAM,EAAE,UAAS,sBAA2B,KAAG,OAMtF,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,GACjC,cAAc,MAAM,GAAG,IAAI,EAC3B,wBAAwB,MAAM,EAAE,KAC/B,OAIF,CAAC;AAEF,oFAAoF;AACpF,eAAO,MAAM,mBAAmB,GAC9B,SAAS,OAAO,EAChB,uBAAuB,MAAM,EAAE,GAAG,SAAS,EAC3C,WAAW,MAAM,OAAO,CAAC,IAAI,CAAC,KAC7B,OAAO,CAAC,QAAQ,GAAG,IAAI,CAMzB,CAAC;AAEF,8EAA8E;AAC9E,eAAO,MAAM,mBAAmB,GAC9B,UAAU,QAAQ,EAClB,SAAS,OAAO,EAChB,uBAAuB,MAAM,EAAE,GAAG,SAAS,KAC1C,QAMF,CAAC"}
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Origin allowlisting — Host-derived Node origins (multi-tenant) and browser
3
+ * `Origin` headers on MCP (DNS rebinding / CSRF). Same predicate shape as
4
+ * redirect allowlisting — not secret comparison.
5
+ */
6
+ import { jsonResponse, withReflectedCorsOrigin } from "./http.js";
7
+ const originOf = (value) => {
8
+ try {
9
+ return new URL(value).origin;
10
+ }
11
+ catch {
12
+ return null;
13
+ }
14
+ };
15
+ const isExactOrigin = (origin, options) => {
16
+ const normalized = originOf(origin);
17
+ if (!normalized)
18
+ return false;
19
+ return Boolean(options.allowedOrigins?.some((entry) => {
20
+ if (entry.startsWith("*."))
21
+ return false;
22
+ return originOf(entry) === normalized;
23
+ }));
24
+ };
25
+ /** `*.example.com` matches `https://acme.example.com`, not the apex, not http. */
26
+ const isWildcardSubdomain = (origin, options) => {
27
+ const patterns = options.allowedOrigins ?? [];
28
+ try {
29
+ const { protocol, hostname } = new URL(origin);
30
+ if (protocol !== "https:")
31
+ return false;
32
+ return patterns.some((entry) => {
33
+ if (!entry.startsWith("*."))
34
+ return false;
35
+ const suffix = entry.slice(1); // ".example.com"
36
+ return hostname.endsWith(suffix) && hostname.length > suffix.length;
37
+ });
38
+ }
39
+ catch {
40
+ return false;
41
+ }
42
+ };
43
+ const ORIGIN_PREDICATES = [isExactOrigin, isWildcardSubdomain];
44
+ /**
45
+ * Host-derived / allowlist Origin check (Node `asNodeHandler` multi-tenant).
46
+ * Empty or omitted `allowedOrigins` → admit all (callers that derive origin
47
+ * from Host must require a non-empty list before reaching here).
48
+ * `"*"` admits any origin.
49
+ */
50
+ export const isAllowedOrigin = (origin, options = {}) => {
51
+ if (!options.allowedOrigins || options.allowedOrigins.length === 0) {
52
+ return true;
53
+ }
54
+ if (options.allowedOrigins.includes("*"))
55
+ return true;
56
+ return ORIGIN_PREDICATES.some((predicate) => predicate(origin, options));
57
+ };
58
+ /**
59
+ * Browser `Origin` on MCP Streamable HTTP (DNS rebinding / CSRF).
60
+ * No header → allow (native / server-to-server). Empty or omitted allowlist →
61
+ * deny any present Origin (secure default — opposite of `isAllowedOrigin`).
62
+ * `"*"` opts out.
63
+ */
64
+ export const isAllowedRequestOrigin = (originHeader, allowedRequestOrigins) => {
65
+ if (!originHeader)
66
+ return true;
67
+ if (!allowedRequestOrigins || allowedRequestOrigins.length === 0)
68
+ return false;
69
+ return isAllowedOrigin(originHeader, { allowedOrigins: allowedRequestOrigins });
70
+ };
71
+ /** 403 when a present Origin fails the allowlist. `onDenied` runs first (audit). */
72
+ export const requestOriginDenied = async (request, allowedRequestOrigins, onDenied) => {
73
+ if (isAllowedRequestOrigin(request.headers.get("Origin"), allowedRequestOrigins)) {
74
+ return null;
75
+ }
76
+ await onDenied?.();
77
+ return jsonResponse({ data: { error: "origin not allowed" }, status: 403, cors: false });
78
+ };
79
+ /** When a non-wildcard allowlist admitted this Origin, reflect it on CORS. */
80
+ export const reflectCorsIfNeeded = (response, request, allowedRequestOrigins) => {
81
+ const origin = request.headers.get("Origin");
82
+ if (!origin || !allowedRequestOrigins?.length || allowedRequestOrigins.includes("*")) {
83
+ return response;
84
+ }
85
+ return withReflectedCorsOrigin(response, origin);
86
+ };
87
+ //# sourceMappingURL=origins.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"origins.js","sourceRoot":"","sources":["../../src/http/origins.ts"],"names":[],"mappings":"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"}
@@ -3,5 +3,5 @@ export type { AuditEntry, McpHandlerOptions, McpPorts, Principal, ServerInfo, }
3
3
  export type McpHandler = {
4
4
  fetch: (request: Request) => Promise<Response>;
5
5
  };
6
- export declare const createMcpHandler: <TCtx>(options: McpHandlerOptions<TCtx>) => McpHandler;
6
+ export declare const createMcpHandler: <TCtx>(handlerOptions: McpHandlerOptions<TCtx>) => McpHandler;
7
7
  //# sourceMappingURL=dispatch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dispatch.d.ts","sourceRoot":"","sources":["../../src/mcp/dispatch.ts"],"names":[],"mappings":"AAmBA,OAAO,EAIL,KAAK,iBAAiB,EAKvB,MAAM,cAAc,CAAC;AAGtB,YAAY,EACV,UAAU,EACV,iBAAiB,EACjB,QAAQ,EACR,SAAS,EACT,UAAU,GACX,MAAM,cAAc,CAAC;AAEtB,MAAM,MAAM,UAAU,GAAG;IACvB,KAAK,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;CAChD,CAAC;AAkFF,eAAO,MAAM,gBAAgB,GAAI,IAAI,EAAE,gBAAgB,iBAAiB,CAAC,IAAI,CAAC,KAAG,UAwChF,CAAC"}
@@ -0,0 +1,99 @@
1
+ import { rejectQueryToken } from "../auth/bearer.js";
2
+ import { BodyTooLargeError, DEFAULT_MCP_BODY_LIMIT, readBoundedText } from "../http/body.js";
3
+ import { emptyResponse, errorReason, INTERNAL_ERROR, jsonResponse, methodNotAllowed, optionsResponse, } from "../http/http.js";
4
+ import { reflectCorsIfNeeded, requestOriginDenied } from "../http/origins.js";
5
+ import { JSONRPC_INTERNAL_ERROR, JSONRPC_PARSE_ERROR, JSONRPC_PAYLOAD_TOO_LARGE, protocolVersionHeaderError, rpcError, validateJsonRpcEnvelope, } from "./jsonrpc.js";
6
+ import { DEFAULT_PUBLIC_METHODS, DENIAL_REASONS, isNotification, resolveWwwAuthenticate, safeAudit, unauthorized, } from "./methods.js";
7
+ import { dispatchRpc } from "./rpc-handlers.js";
8
+ const parseBody = async (request) => {
9
+ let text;
10
+ try {
11
+ text = await readBoundedText(request, DEFAULT_MCP_BODY_LIMIT);
12
+ }
13
+ catch (caught) {
14
+ if (caught instanceof BodyTooLargeError) {
15
+ return jsonResponse({
16
+ data: rpcError(null, JSONRPC_PAYLOAD_TOO_LARGE, "Payload too large"),
17
+ status: 413,
18
+ });
19
+ }
20
+ return jsonResponse({ data: rpcError(null, JSONRPC_PARSE_ERROR, "Parse error"), status: 400 });
21
+ }
22
+ try {
23
+ return JSON.parse(text);
24
+ }
25
+ catch {
26
+ return jsonResponse({ data: rpcError(null, JSONRPC_PARSE_ERROR, "Parse error"), status: 400 });
27
+ }
28
+ };
29
+ /** Transport-level denial: no JSON-RPC method has been parsed yet. */
30
+ const auditDenial = (options, error, startedAt) => safeAudit(options, { method: "", ok: false, error, durationMs: Date.now() - startedAt });
31
+ const denyQueryStringToken = async (request, options, startedAt) => {
32
+ if (rejectQueryToken(new URL(request.url))) {
33
+ await auditDenial(options, DENIAL_REASONS.queryStringToken, startedAt);
34
+ return unauthorized(resolveWwwAuthenticate(options, request), "Token in query string is rejected. Use Authorization Bearer.");
35
+ }
36
+ return null;
37
+ };
38
+ const handleGet = async (request, options, startedAt) => {
39
+ const denied = await denyQueryStringToken(request, options, startedAt);
40
+ if (denied)
41
+ return denied;
42
+ if (!request.headers.get("authorization")) {
43
+ await auditDenial(options, DENIAL_REASONS.unauthorized, startedAt);
44
+ return unauthorized(resolveWwwAuthenticate(options, request));
45
+ }
46
+ return methodNotAllowed("Use POST for MCP");
47
+ };
48
+ const handlePost = async (request, options, startedAt) => {
49
+ const denied = await denyQueryStringToken(request, options, startedAt);
50
+ if (denied)
51
+ return denied;
52
+ const parsed = await parseBody(request);
53
+ if (parsed instanceof Response)
54
+ return parsed;
55
+ const envelope = validateJsonRpcEnvelope(parsed);
56
+ if (envelope instanceof Response)
57
+ return envelope;
58
+ const versionError = protocolVersionHeaderError(request, envelope);
59
+ if (versionError)
60
+ return versionError;
61
+ if (isNotification(envelope))
62
+ return emptyResponse(202);
63
+ return dispatchRpc({ req: request, body: envelope, options, startedAt });
64
+ };
65
+ export const createMcpHandler = (handlerOptions) => {
66
+ const options = {
67
+ ...handlerOptions,
68
+ publicMethods: handlerOptions.publicMethods ?? DEFAULT_PUBLIC_METHODS,
69
+ };
70
+ const HTTP_METHODS = {
71
+ OPTIONS: () => optionsResponse(),
72
+ GET: (request, startedAt) => handleGet(request, options, startedAt),
73
+ POST: (request, startedAt) => handlePost(request, options, startedAt),
74
+ };
75
+ return {
76
+ fetch: async (request) => {
77
+ const startedAt = Date.now();
78
+ try {
79
+ const originDenied = await requestOriginDenied(request, options.allowedRequestOrigins, () => auditDenial(options, DENIAL_REASONS.originNotAllowed, startedAt));
80
+ if (originDenied)
81
+ return originDenied;
82
+ const handler = HTTP_METHODS[request.method];
83
+ const response = await (handler ? handler(request, startedAt) : methodNotAllowed());
84
+ return reflectCorsIfNeeded(response, request, options.allowedRequestOrigins);
85
+ }
86
+ catch (caught) {
87
+ // A host port (authenticate/context/audit) threw. `fetch` must never
88
+ // reject — the caller gets an honest 500, not an unhandled rejection
89
+ // whose shape depends on which runtime is hosting this.
90
+ await auditDenial(options, errorReason(caught) || INTERNAL_ERROR, startedAt);
91
+ return reflectCorsIfNeeded(jsonResponse({
92
+ data: rpcError(null, JSONRPC_INTERNAL_ERROR, "Internal error"),
93
+ status: 500,
94
+ }), request, options.allowedRequestOrigins);
95
+ }
96
+ },
97
+ };
98
+ };
99
+ //# sourceMappingURL=dispatch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dispatch.js","sourceRoot":"","sources":["../../src/mcp/dispatch.ts"],"names":[],"mappings":"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"}
@@ -28,6 +28,15 @@ export declare const JSONRPC_INVALID_PARAMS = -32602;
28
28
  export declare const JSONRPC_INTERNAL_ERROR = -32603;
29
29
  export declare const JSONRPC_UNAUTHORIZED = -32001;
30
30
  export declare const JSONRPC_PAYLOAD_TOO_LARGE = -32002;
31
+ /** Authenticated but missing required scope — paired with HTTP 403. */
32
+ export declare const JSONRPC_INSUFFICIENT_SCOPE = -32003;
31
33
  export declare const rpcResult: (id: JsonRpcId, result: unknown) => JsonRpcSuccess;
32
34
  export declare const rpcError: (id: JsonRpcId, code: number, message: string) => JsonRpcFailure;
35
+ /** Batch / jsonrpc version / shape — returns a Response or a validated request. */
36
+ export declare const validateJsonRpcEnvelope: (parsed: unknown) => Response | JsonRpcRequest;
37
+ /**
38
+ * Spec requires `MCP-Protocol-Version` past `initialize`. Unknown → 400.
39
+ * Missing → assume `2025-03-26` (header BC rule; see `protocol.ts`).
40
+ */
41
+ export declare const protocolVersionHeaderError: (request: Request, jsonRpcRequest: JsonRpcRequest) => Response | null;
33
42
  //# sourceMappingURL=jsonrpc.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jsonrpc.d.ts","sourceRoot":"","sources":["../../src/mcp/jsonrpc.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;AAE/C,MAAM,MAAM,cAAc,GAAG;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,EAAE,CAAC,EAAE,SAAS,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,OAAO,EAAE,KAAK,CAAC;IACf,EAAE,EAAE,SAAS,CAAC;IACd,MAAM,EAAE,OAAO,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,OAAO,EAAE,KAAK,CAAC;IACf,EAAE,EAAE,SAAS,CAAC;IACd,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;CAC1C,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG,cAAc,GAAG,cAAc,CAAC;AAE9D,eAAO,MAAM,mBAAmB,SAAS,CAAC;AAC1C,eAAO,MAAM,uBAAuB,SAAS,CAAC;AAC9C,eAAO,MAAM,wBAAwB,SAAS,CAAC;AAC/C,eAAO,MAAM,sBAAsB,SAAS,CAAC;AAC7C,eAAO,MAAM,sBAAsB,SAAS,CAAC;AAC7C,eAAO,MAAM,oBAAoB,SAAS,CAAC;AAC3C,eAAO,MAAM,yBAAyB,SAAS,CAAC;AAChD,uEAAuE;AACvE,eAAO,MAAM,0BAA0B,SAAS,CAAC;AAEjD,eAAO,MAAM,SAAS,GAAI,IAAI,SAAS,EAAE,QAAQ,OAAO,KAAG,cAIzD,CAAC;AAEH,eAAO,MAAM,QAAQ,GAAI,IAAI,SAAS,EAAE,MAAM,MAAM,EAAE,SAAS,MAAM,KAAG,cAItE,CAAC;AAwCH,mFAAmF;AACnF,eAAO,MAAM,uBAAuB,GAAI,QAAQ,OAAO,KAAG,QAAQ,GAAG,cAkBpE,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,0BAA0B,GACrC,SAAS,OAAO,EAChB,gBAAgB,cAAc,KAC7B,QAAQ,GAAG,IAYb,CAAC"}
@@ -0,0 +1,88 @@
1
+ import { jsonResponse } from "../http/http.js";
2
+ import { PROTOCOL_VERSIONS } from "./protocol.js";
3
+ export const JSONRPC_PARSE_ERROR = -32700;
4
+ export const JSONRPC_INVALID_REQUEST = -32600;
5
+ export const JSONRPC_METHOD_NOT_FOUND = -32601;
6
+ export const JSONRPC_INVALID_PARAMS = -32602;
7
+ export const JSONRPC_INTERNAL_ERROR = -32603;
8
+ export const JSONRPC_UNAUTHORIZED = -32001;
9
+ export const JSONRPC_PAYLOAD_TOO_LARGE = -32002;
10
+ /** Authenticated but missing required scope — paired with HTTP 403. */
11
+ export const JSONRPC_INSUFFICIENT_SCOPE = -32003;
12
+ export const rpcResult = (id, result) => ({
13
+ jsonrpc: "2.0",
14
+ id,
15
+ result,
16
+ });
17
+ export const rpcError = (id, code, message) => ({
18
+ jsonrpc: "2.0",
19
+ id,
20
+ error: { code, message },
21
+ });
22
+ const isJsonRpcId = (id) => id === null || typeof id === "string" || typeof id === "number";
23
+ /**
24
+ * RFC-shaped JSON-RPC id for an error response — omitted → `null`; valid ids
25
+ * echoed; invalid shapes → `null` so we never reflect an illegal id.
26
+ */
27
+ const errorId = (jsonRpcRequest) => {
28
+ if (jsonRpcRequest.id === undefined)
29
+ return null;
30
+ return isJsonRpcId(jsonRpcRequest.id) ? jsonRpcRequest.id : null;
31
+ };
32
+ /** Runtime JSON-RPC Request shape — types alone do not enforce this. */
33
+ const jsonRpcShapeError = (jsonRpcRequest) => {
34
+ if (jsonRpcRequest.id !== undefined && !isJsonRpcId(jsonRpcRequest.id)) {
35
+ return jsonResponse({
36
+ data: rpcError(null, JSONRPC_INVALID_REQUEST, "id must be string, number, or null"),
37
+ status: 400,
38
+ });
39
+ }
40
+ const orphanResult = jsonRpcRequest.method === undefined &&
41
+ jsonRpcRequest.id === undefined &&
42
+ "result" in jsonRpcRequest;
43
+ if (orphanResult)
44
+ return null;
45
+ if (typeof jsonRpcRequest.method !== "string" || jsonRpcRequest.method.length === 0) {
46
+ return jsonResponse({
47
+ data: rpcError(errorId(jsonRpcRequest), JSONRPC_INVALID_REQUEST, "method must be a non-empty string"),
48
+ status: 400,
49
+ });
50
+ }
51
+ return null;
52
+ };
53
+ /** Batch / jsonrpc version / shape — returns a Response or a validated request. */
54
+ export const validateJsonRpcEnvelope = (parsed) => {
55
+ if (Array.isArray(parsed)) {
56
+ return jsonResponse({
57
+ data: rpcError(null, JSONRPC_INVALID_REQUEST, "Batch requests not supported"),
58
+ status: 400,
59
+ });
60
+ }
61
+ if (!parsed || typeof parsed !== "object") {
62
+ return jsonResponse({ data: rpcError(null, JSONRPC_PARSE_ERROR, "Parse error"), status: 400 });
63
+ }
64
+ const jsonRpcRequest = parsed;
65
+ if (jsonRpcRequest.jsonrpc !== "2.0") {
66
+ return jsonResponse({
67
+ data: rpcError(errorId(jsonRpcRequest), JSONRPC_INVALID_REQUEST, 'jsonrpc must be "2.0"'),
68
+ status: 400,
69
+ });
70
+ }
71
+ return jsonRpcShapeError(jsonRpcRequest) ?? jsonRpcRequest;
72
+ };
73
+ /**
74
+ * Spec requires `MCP-Protocol-Version` past `initialize`. Unknown → 400.
75
+ * Missing → assume `2025-03-26` (header BC rule; see `protocol.ts`).
76
+ */
77
+ export const protocolVersionHeaderError = (request, jsonRpcRequest) => {
78
+ if (jsonRpcRequest.method === "initialize")
79
+ return null;
80
+ const header = request.headers.get("MCP-Protocol-Version");
81
+ if (!header || PROTOCOL_VERSIONS.has(header))
82
+ return null;
83
+ return jsonResponse({
84
+ data: rpcError(errorId(jsonRpcRequest), JSONRPC_INVALID_REQUEST, `Unsupported MCP-Protocol-Version: ${header}`),
85
+ status: 400,
86
+ });
87
+ };
88
+ //# sourceMappingURL=jsonrpc.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jsonrpc.js","sourceRoot":"","sources":["../../src/mcp/jsonrpc.ts"],"names":[],"mappings":"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"}