@nyuchi/mzizi-mcp 0.13.0 → 0.15.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 (73) hide show
  1. package/README.md +197 -26
  2. package/dist/auth/front.d.ts +8 -0
  3. package/dist/auth/front.d.ts.map +1 -1
  4. package/dist/auth/front.js +10 -0
  5. package/dist/auth/front.js.map +1 -1
  6. package/dist/auth/mcp-api-handler.d.ts +1 -1
  7. package/dist/auth/mcp-api-handler.d.ts.map +1 -1
  8. package/dist/auth/mcp-api-handler.js +4 -3
  9. package/dist/auth/mcp-api-handler.js.map +1 -1
  10. package/dist/auth/provider-options.d.ts +16 -0
  11. package/dist/auth/provider-options.d.ts.map +1 -0
  12. package/dist/auth/provider-options.js +21 -0
  13. package/dist/auth/provider-options.js.map +1 -0
  14. package/dist/docs-federation.d.ts +1 -1
  15. package/dist/docs-federation.d.ts.map +1 -1
  16. package/dist/docs-federation.js +1 -0
  17. package/dist/docs-federation.js.map +1 -1
  18. package/dist/env.d.ts +1 -0
  19. package/dist/env.d.ts.map +1 -1
  20. package/dist/floors.d.ts +117 -0
  21. package/dist/floors.d.ts.map +1 -0
  22. package/dist/floors.js +103 -0
  23. package/dist/floors.js.map +1 -0
  24. package/dist/fundi-client.d.ts +6 -0
  25. package/dist/fundi-client.d.ts.map +1 -1
  26. package/dist/fundi-client.js +14 -3
  27. package/dist/fundi-client.js.map +1 -1
  28. package/dist/generated/registry-pin.d.ts +8 -1
  29. package/dist/generated/registry-pin.d.ts.map +1 -1
  30. package/dist/generated/registry-pin.js +3 -1
  31. package/dist/generated/registry-pin.js.map +1 -1
  32. package/dist/generated/registry.d.ts +2 -2
  33. package/dist/generated/registry.d.ts.map +1 -1
  34. package/dist/generated/registry.js +381 -325
  35. package/dist/generated/registry.js.map +1 -1
  36. package/dist/generated/skills.d.ts +11 -1
  37. package/dist/generated/skills.d.ts.map +1 -1
  38. package/dist/generated/skills.js +216 -21
  39. package/dist/generated/skills.js.map +1 -1
  40. package/dist/http.d.ts +32 -2
  41. package/dist/http.d.ts.map +1 -1
  42. package/dist/http.js +109 -28
  43. package/dist/http.js.map +1 -1
  44. package/dist/limits.d.ts +32 -0
  45. package/dist/limits.d.ts.map +1 -0
  46. package/dist/limits.js +44 -0
  47. package/dist/limits.js.map +1 -0
  48. package/dist/origin.d.ts +55 -0
  49. package/dist/origin.d.ts.map +1 -0
  50. package/dist/origin.js +127 -0
  51. package/dist/origin.js.map +1 -0
  52. package/dist/rate-limit.d.ts +1 -1
  53. package/dist/rate-limit.d.ts.map +1 -1
  54. package/dist/rate-limit.js +3 -2
  55. package/dist/rate-limit.js.map +1 -1
  56. package/dist/registry.d.ts +1 -1
  57. package/dist/registry.d.ts.map +1 -1
  58. package/dist/registry.js +22 -1
  59. package/dist/registry.js.map +1 -1
  60. package/dist/server.d.ts +83 -4
  61. package/dist/server.d.ts.map +1 -1
  62. package/dist/server.js +109 -10
  63. package/dist/server.js.map +1 -1
  64. package/dist/stdio.js +5 -4
  65. package/dist/stdio.js.map +1 -1
  66. package/dist/tools.d.ts +21 -1
  67. package/dist/tools.d.ts.map +1 -1
  68. package/dist/tools.js +413 -114
  69. package/dist/tools.js.map +1 -1
  70. package/dist/worker.d.ts.map +1 -1
  71. package/dist/worker.js +19 -8
  72. package/dist/worker.js.map +1 -1
  73. package/package.json +18 -17
@@ -1 +1 @@
1
- {"version":3,"file":"skills.js","sourceRoot":"","sources":["../../src/generated/skills.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,6DAA6D;AAC7D,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,KAAK,EAAC,QAAQ,EAAC,UAAU,EAAC,OAAO,CAAU,CAAA;AAY5E,MAAM,CAAC,MAAM,cAAc,GAA4B;IACrD;QACE,MAAM,EAAE,gBAAgB;QACxB,UAAU,EAAE,UAAU;QACtB,aAAa,EAAE,+wBAA+wB;QAC9xB,UAAU,EAAE,o9sCAAo9sC;QACh+sC,QAAQ,EAAE,0DAA0D;KACrE;IACD;QACE,MAAM,EAAE,aAAa;QACrB,UAAU,EAAE,OAAO;QACnB,aAAa,EAAE,+qCAA+qC;QAC9rC,UAAU,EAAE,u7oDAAu7oD;QACn8oD,QAAQ,EAAE,uDAAuD;KAClE;IACD;QACE,MAAM,EAAE,cAAc;QACtB,UAAU,EAAE,QAAQ;QACpB,aAAa,EAAE,2uBAA2uB;QAC1vB,UAAU,EAAE,041BAA041B;QACt51B,QAAQ,EAAE,wDAAwD;KACnE;IACD;QACE,MAAM,EAAE,eAAe;QACvB,UAAU,EAAE,OAAO;QACnB,aAAa,EAAE,yxBAAyxB;QACxyB,UAAU,EAAE,q1mBAAq1mB;QACj2mB,QAAQ,EAAE,yDAAyD;KACpE;IACD;QACE,MAAM,EAAE,iBAAiB;QACzB,UAAU,EAAE,OAAO;QACnB,aAAa,EAAE,wmBAAwmB;QACvnB,UAAU,EAAE,myOAAmyO;QAC/yO,QAAQ,EAAE,2DAA2D;KACtE;IACD;QACE,MAAM,EAAE,iBAAiB;QACzB,UAAU,EAAE,KAAK;QACjB,aAAa,EAAE,+3BAA+3B;QAC94B,UAAU,EAAE,2uUAA2uU;QACvvU,QAAQ,EAAE,2DAA2D;KACtE;IACD;QACE,MAAM,EAAE,iBAAiB;QACzB,UAAU,EAAE,KAAK;QACjB,aAAa,EAAE,moCAAmoC;QAClpC,UAAU,EAAE,omRAAomR;QAChnR,QAAQ,EAAE,2DAA2D;KACtE;CACO,CAAA;AAEV,oDAAoD;AACpD,MAAM,CAAC,MAAM,cAAc,GAAG,QAAQ,CAAA"}
1
+ {"version":3,"file":"skills.js","sourceRoot":"","sources":["../../src/generated/skills.ts"],"names":[],"mappings":"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"}
package/dist/http.d.ts CHANGED
@@ -11,6 +11,15 @@
11
11
  import type { FundiToolContext } from "./fundi-client.js";
12
12
  import type { IssueDeskContext } from "./tools.js";
13
13
  import type { DocsFederationOptions } from "./docs-federation.js";
14
+ export { originRejection } from "./origin.js";
15
+ /**
16
+ * Add CORS headers: the caller's `Origin` echoed back when it was allowed (see
17
+ * `origin.ts`), never `*`. `Vary` is appended to, not replaced. Exported for
18
+ * tests only.
19
+ *
20
+ * @internal
21
+ */
22
+ export declare function withCors(response: Response, origin: string | null, allowed: boolean): Response;
14
23
  export interface HttpHandlerOptions {
15
24
  /** When set, expose the fundi trigger tool bound to the signed-in user. */
16
25
  fundi?: FundiToolContext;
@@ -25,10 +34,31 @@ export interface HttpHandlerOptions {
25
34
  };
26
35
  /** Docs federation settings, or `false` for none. Defaults to docs.mzizi.dev. */
27
36
  docs?: DocsFederationOptions | false;
37
+ /**
38
+ * Browser origins allowed to call the endpoint, by hostname, with the same
39
+ * scheme and port rules as the default list (see `origin.ts`). Omitted, the
40
+ * first-party sites and localhost. The Worker passes the default plus
41
+ * `MZIZI_ALLOWED_ORIGINS`.
42
+ */
43
+ allowedOrigins?: readonly string[];
28
44
  }
29
45
  /**
30
- * Build a fetch handler that serves the Mzizi MCP over Streamable HTTP.
31
- * Stateless — each request creates a fresh transport + server pair.
46
+ * Build a fetch handler that serves the Mzizi MCP over Streamable HTTP, on the
47
+ * official SDK (v2, `@modelcontextprotocol/server`).
48
+ *
49
+ * Stateless either way: every request gets a fresh `McpServer` from the same
50
+ * factory, with nothing shared between callers.
51
+ *
52
+ * - 2026-07-28 traffic (per-request `_meta`, `server/discover`) is served by
53
+ * the SDK's `createMcpHandler`.
54
+ * - 2025-era traffic (`initialize`) is served by the SDK's
55
+ * `WebStandardStreamableHTTPServerTransport` with JSON responses, exactly as
56
+ * before the migration, routed with the SDK's own `isLegacyRequest` so the
57
+ * two legs cannot disagree about which is which. `createMcpHandler`'s
58
+ * built-in legacy leg would answer the same requests over SSE; keeping JSON
59
+ * keeps every existing client's responses byte-for-byte the same shape.
60
+ * - GET and DELETE (2025 session operations this server has never offered)
61
+ * are answered with 405 rather than holding an SSE stream open.
32
62
  */
33
63
  export declare function createMziziHttpHandler(options?: HttpHandlerOptions): (request: Request) => Promise<Response>;
34
64
  //# sourceMappingURL=http.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AACzD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAClD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAA;AAqCjE,MAAM,WAAW,kBAAkB;IACjC,2EAA2E;IAC3E,KAAK,CAAC,EAAE,gBAAgB,CAAA;IACxB,+EAA+E;IAC/E,IAAI,CAAC,EAAE,gBAAgB,CAAA;IACvB;;;OAGG;IACH,SAAS,CAAC,EAAE;QAAE,KAAK,EAAE,OAAO,CAAA;KAAE,CAAA;IAC9B,iFAAiF;IACjF,IAAI,CAAC,EAAE,qBAAqB,GAAG,KAAK,CAAA;CACrC;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,GAAE,kBAAuB,IACxC,SAAS,OAAO,KAAG,OAAO,CAAC,QAAQ,CAAC,CA0BlE"}
1
+ {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AASH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AACzD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAClD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAA;AAGjE,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAE7C;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,EAAE,OAAO,GAAG,QAAQ,CAa9F;AAqBD,MAAM,WAAW,kBAAkB;IACjC,2EAA2E;IAC3E,KAAK,CAAC,EAAE,gBAAgB,CAAA;IACxB,+EAA+E;IAC/E,IAAI,CAAC,EAAE,gBAAgB,CAAA;IACvB;;;OAGG;IACH,SAAS,CAAC,EAAE;QAAE,KAAK,EAAE,OAAO,CAAA;KAAE,CAAA;IAC9B,iFAAiF;IACjF,IAAI,CAAC,EAAE,qBAAqB,GAAG,KAAK,CAAA;IACpC;;;;;OAKG;IACH,cAAc,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CACnC;AAiDD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,GAAE,kBAAuB,IAcxC,SAAS,OAAO,KAAG,OAAO,CAAC,QAAQ,CAAC,CAsClE"}
package/dist/http.js CHANGED
@@ -8,17 +8,28 @@
8
8
  * anonymous (the free tier) or signed in (WorkOS AuthKit via the OAuth provider)
9
9
  * before it reaches this handler.
10
10
  */
11
- import { WebStandardStreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js";
11
+ import { createMcpHandler, isLegacyRequest, WebStandardStreamableHTTPServerTransport, } from "@modelcontextprotocol/server";
12
+ import { corsHeadersFor, forbiddenOrigin, isAllowedOrigin } from "./origin.js";
12
13
  import { createMziziMcpServer } from "./server.js";
13
- const CORS_HEADERS = {
14
- "Access-Control-Allow-Origin": "*",
15
- "Access-Control-Allow-Methods": "GET, POST, DELETE, OPTIONS",
16
- "Access-Control-Allow-Headers": "Content-Type, MCP-Protocol-Version, MCP-Session-Id, apikey",
17
- };
18
- function withCors(response) {
14
+ // Part of the public `./http` export since before 0.14.0; kept (same signature).
15
+ export { originRejection } from "./origin.js";
16
+ /**
17
+ * Add CORS headers: the caller's `Origin` echoed back when it was allowed (see
18
+ * `origin.ts`), never `*`. `Vary` is appended to, not replaced. Exported for
19
+ * tests only.
20
+ *
21
+ * @internal
22
+ */
23
+ export function withCors(response, origin, allowed) {
19
24
  const headers = new Headers(response.headers);
20
- for (const [key, value] of Object.entries(CORS_HEADERS))
21
- headers.set(key, value);
25
+ for (const [key, value] of Object.entries(corsHeadersFor(origin, allowed))) {
26
+ if (key === "Vary") {
27
+ if (!/(^|,)\s*origin\s*(,|$)/i.test(headers.get("Vary") ?? ""))
28
+ headers.append(key, value);
29
+ }
30
+ else
31
+ headers.set(key, value);
32
+ }
22
33
  return new Response(response.body, {
23
34
  status: response.status,
24
35
  statusText: response.statusText,
@@ -44,32 +55,102 @@ function isOAuthDiscoveryPath(pathname) {
44
55
  * Build a fetch handler that serves the Mzizi MCP over Streamable HTTP.
45
56
  * Stateless — each request creates a fresh transport + server pair.
46
57
  */
58
+ /** Request bodies are small JSON-RPC calls; 1 MiB is generous. */
59
+ const MAX_REQUEST_BODY = 1024 * 1024;
60
+ const onerror = (error) => console.error("mzizi-mcp:", error.message);
61
+ function serverFor(options) {
62
+ return createMziziMcpServer({
63
+ fundi: options.fundi,
64
+ desk: options.desk,
65
+ anonymous: options.anonymous,
66
+ docs: options.docs,
67
+ });
68
+ }
69
+ const OPTIONS_KEY = "mzizi-mcp/handler-options";
70
+ /** Wrap per-request options as the SDK's pass-through `authInfo`. */
71
+ function carry(options) {
72
+ return { token: "", clientId: "mzizi-mcp", scopes: [], extra: { [OPTIONS_KEY]: options } };
73
+ }
74
+ let modern;
75
+ /**
76
+ * One `createMcpHandler` per isolate, not per request: it owns an event bus and
77
+ * a listen router, and building it on every request cost both each time. The
78
+ * factory still builds a fresh `McpServer` for every request, from the options
79
+ * that request carried (anonymous, or the signed-in user's fundi and desk).
80
+ */
81
+ function modernHandler() {
82
+ modern ??= createMcpHandler((ctx) => serverFor(ctx.authInfo?.extra?.[OPTIONS_KEY] ?? {}), {
83
+ legacy: "reject",
84
+ // "auto": a single JSON body unless a tool emits a message first, which
85
+ // none here does. ("json" would log a warning on every construction.)
86
+ maxRequestBodySize: MAX_REQUEST_BODY,
87
+ onerror,
88
+ });
89
+ return modern;
90
+ }
91
+ /**
92
+ * Build a fetch handler that serves the Mzizi MCP over Streamable HTTP, on the
93
+ * official SDK (v2, `@modelcontextprotocol/server`).
94
+ *
95
+ * Stateless either way: every request gets a fresh `McpServer` from the same
96
+ * factory, with nothing shared between callers.
97
+ *
98
+ * - 2026-07-28 traffic (per-request `_meta`, `server/discover`) is served by
99
+ * the SDK's `createMcpHandler`.
100
+ * - 2025-era traffic (`initialize`) is served by the SDK's
101
+ * `WebStandardStreamableHTTPServerTransport` with JSON responses, exactly as
102
+ * before the migration, routed with the SDK's own `isLegacyRequest` so the
103
+ * two legs cannot disagree about which is which. `createMcpHandler`'s
104
+ * built-in legacy leg would answer the same requests over SSE; keeping JSON
105
+ * keeps every existing client's responses byte-for-byte the same shape.
106
+ * - GET and DELETE (2025 session operations this server has never offered)
107
+ * are answered with 405 rather than holding an SSE stream open.
108
+ */
47
109
  export function createMziziHttpHandler(options = {}) {
110
+ const factory = () => serverFor(options);
111
+ async function serveLegacy(request) {
112
+ const transport = new WebStandardStreamableHTTPServerTransport({
113
+ sessionIdGenerator: undefined,
114
+ enableJsonResponse: true,
115
+ });
116
+ const server = await factory();
117
+ server.server.onerror = onerror;
118
+ await server.connect(transport);
119
+ return transport.handleRequest(request);
120
+ }
48
121
  return async function handle(request) {
122
+ const origin = request.headers.get("origin");
123
+ const allowed = isAllowedOrigin(origin, options.allowedOrigins);
124
+ const cors = (response) => withCors(response, origin, allowed);
125
+ // DNS-rebinding / cross-site defence (Streamable HTTP §Security): a
126
+ // request whose Origin is present and not on the allowlist is refused with
127
+ // 403 before anything else, preflight included, and before any server is
128
+ // built. No Origin header (every non-browser client) passes.
129
+ if (!allowed)
130
+ return cors(forbiddenOrigin(origin));
131
+ // (On the Worker the OAuth provider answers OPTIONS on /mcp itself, so this
132
+ // branch serves the embedded `./http` export; see the CHANGELOG, #295.)
49
133
  if (request.method === "OPTIONS") {
50
- return new Response(null, { status: 204, headers: CORS_HEADERS });
134
+ return cors(new Response(null, { status: 204 }));
51
135
  }
52
136
  // Answer auth-discovery probes with 404 so compliant MCP clients fall back
53
- // to anonymous access. Without this the request reaches the Streamable HTTP
54
- // transport, which rejects a discovery GET (no `text/event-stream` Accept)
55
- // with a 406 — a response clients can't read as auth metadata, so they
56
- // abort the connection instead of connecting unauthenticated.
137
+ // to anonymous access. Without this the request reaches the MCP handler,
138
+ // which cannot answer a discovery GET with metadata, and clients abort the
139
+ // connection instead of connecting unauthenticated.
57
140
  if (isOAuthDiscoveryPath(new URL(request.url).pathname)) {
58
- return withCors(new Response("Not Found", { status: 404 }));
141
+ return cors(new Response("Not Found", { status: 404 }));
59
142
  }
60
- const transport = new WebStandardStreamableHTTPServerTransport({
61
- sessionIdGenerator: undefined,
62
- enableJsonResponse: true,
63
- });
64
- const server = await createMziziMcpServer({
65
- fundi: options.fundi,
66
- desk: options.desk,
67
- anonymous: options.anonymous,
68
- docs: options.docs,
69
- });
70
- await server.connect(transport);
71
- const response = await transport.handleRequest(request);
72
- return withCors(response);
143
+ // Stateless: there is no standalone SSE stream to open and no session to
144
+ // end, so GET and DELETE are 405 rather than held-open connections.
145
+ if (request.method !== "POST") {
146
+ return cors(Response.json({ jsonrpc: "2.0", id: null, error: { code: -32000, message: "Method not allowed. This server is stateless: send every request as a POST." } }, { status: 405, headers: { Allow: "POST, OPTIONS" } }));
147
+ }
148
+ if (await isLegacyRequest(request, undefined, { maxRequestBodySize: MAX_REQUEST_BODY })) {
149
+ return cors(await serveLegacy(request));
150
+ }
151
+ // The per-request options ride to the shared handler's factory on authInfo,
152
+ // which the SDK passes through untouched and never reads itself.
153
+ return cors(await modernHandler().fetch(request, { authInfo: carry(options) }));
73
154
  };
74
155
  }
75
156
  //# sourceMappingURL=http.js.map
package/dist/http.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"http.js","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,wCAAwC,EAAE,MAAM,+DAA+D,CAAA;AACxH,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAA;AAKlD,MAAM,YAAY,GAAG;IACnB,6BAA6B,EAAE,GAAG;IAClC,8BAA8B,EAAE,4BAA4B;IAC5D,8BAA8B,EAAE,4DAA4D;CAC7F,CAAA;AAED,SAAS,QAAQ,CAAC,QAAkB;IAClC,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAA;IAC7C,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC;QAAE,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;IAChF,OAAO,IAAI,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE;QACjC,MAAM,EAAE,QAAQ,CAAC,MAAM;QACvB,UAAU,EAAE,QAAQ,CAAC,UAAU;QAC/B,OAAO;KACR,CAAC,CAAA;AACJ,CAAC;AAED,2EAA2E;AAC3E,0EAA0E;AAC1E,8EAA8E;AAC9E,6EAA6E;AAC7E,+EAA+E;AAC/E,+EAA+E;AAC/E,uCAAuC;AACvC,MAAM,wBAAwB,GAAG;IAC/B,uCAAuC;IACvC,yCAAyC;IACzC,mCAAmC;CACpC,CAAA;AAED,SAAS,oBAAoB,CAAC,QAAgB;IAC5C,OAAO,wBAAwB,CAAC,IAAI,CAClC,CAAC,MAAM,EAAE,EAAE,CAAC,QAAQ,KAAK,MAAM,IAAI,QAAQ,CAAC,UAAU,CAAC,GAAG,MAAM,GAAG,CAAC,CACrE,CAAA;AACH,CAAC;AAgBD;;;GAGG;AACH,MAAM,UAAU,sBAAsB,CAAC,UAA8B,EAAE;IACrE,OAAO,KAAK,UAAU,MAAM,CAAC,OAAgB;QAC3C,IAAI,OAAO,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YACjC,OAAO,IAAI,QAAQ,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,YAAY,EAAE,CAAC,CAAA;QACnE,CAAC;QACD,2EAA2E;QAC3E,4EAA4E;QAC5E,2EAA2E;QAC3E,uEAAuE;QACvE,8DAA8D;QAC9D,IAAI,oBAAoB,CAAC,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC;YACxD,OAAO,QAAQ,CAAC,IAAI,QAAQ,CAAC,WAAW,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,CAAA;QAC7D,CAAC;QACD,MAAM,SAAS,GAAG,IAAI,wCAAwC,CAAC;YAC7D,kBAAkB,EAAE,SAAS;YAC7B,kBAAkB,EAAE,IAAI;SACzB,CAAC,CAAA;QACF,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC;YACxC,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,SAAS,EAAE,OAAO,CAAC,SAAS;YAC5B,IAAI,EAAE,OAAO,CAAC,IAAI;SACnB,CAAC,CAAA;QACF,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAA;QAC/B,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,aAAa,CAAC,OAAO,CAAC,CAAA;QACvD,OAAO,QAAQ,CAAC,QAAQ,CAAC,CAAA;IAC3B,CAAC,CAAA;AACH,CAAC"}
1
+ {"version":3,"file":"http.js","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Response-size limits for the list and search tools.
3
+ *
4
+ * A tool result is read into a model's context, and the MCP builder guidance is
5
+ * to keep one under 25,000 characters. Before this cap, `mzizi_list_components`
6
+ * answered its default call with 146 KB (measured live 2026-11-01, issue #295).
7
+ *
8
+ * The cap is met by returning FEWER items, never by cutting text: the page
9
+ * shrinks, `next_offset` points at the first item left out, and the JSON text
10
+ * still matches `structuredContent` exactly.
11
+ */
12
+ /** Characters one list or search result may carry. */
13
+ export declare const CHARACTER_LIMIT = 25000;
14
+ /**
15
+ * The longest prefix of `items` whose page, `render(prefix)`, serialises under
16
+ * `limit`, keeping at least one item (a single oversized item is returned whole
17
+ * rather than as nothing). `render` builds the complete page, pagination fields
18
+ * included, so what is measured is what is sent.
19
+ *
20
+ * A binary search over the prefix length: about log2(n) renders (9 for 400
21
+ * rows) instead of one per item. The page's size only grows with its length,
22
+ * so the search is exact.
23
+ *
24
+ * bushtrade-mcp carries an identical copy in `src/limits.ts` (the packages
25
+ * share no code); keep the two the same.
26
+ */
27
+ export declare function fitToLimit<T, R>(items: T[], render: (page: T[]) => R, limit?: number): {
28
+ page: T[];
29
+ result: R;
30
+ truncated: boolean;
31
+ };
32
+ //# sourceMappingURL=limits.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"limits.d.ts","sourceRoot":"","sources":["../src/limits.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,sDAAsD;AACtD,eAAO,MAAM,eAAe,QAAS,CAAC;AAEtC;;;;;;;;;;;;GAYG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE,CAAC,EAC7B,KAAK,EAAE,CAAC,EAAE,EACV,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,CAAC,EACxB,KAAK,SAAkB,GACtB;IAAE,IAAI,EAAE,CAAC,EAAE,CAAC;IAAC,MAAM,EAAE,CAAC,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAE,CAa9C"}
package/dist/limits.js ADDED
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Response-size limits for the list and search tools.
3
+ *
4
+ * A tool result is read into a model's context, and the MCP builder guidance is
5
+ * to keep one under 25,000 characters. Before this cap, `mzizi_list_components`
6
+ * answered its default call with 146 KB (measured live 2026-11-01, issue #295).
7
+ *
8
+ * The cap is met by returning FEWER items, never by cutting text: the page
9
+ * shrinks, `next_offset` points at the first item left out, and the JSON text
10
+ * still matches `structuredContent` exactly.
11
+ */
12
+ /** Characters one list or search result may carry. */
13
+ export const CHARACTER_LIMIT = 25_000;
14
+ /**
15
+ * The longest prefix of `items` whose page, `render(prefix)`, serialises under
16
+ * `limit`, keeping at least one item (a single oversized item is returned whole
17
+ * rather than as nothing). `render` builds the complete page, pagination fields
18
+ * included, so what is measured is what is sent.
19
+ *
20
+ * A binary search over the prefix length: about log2(n) renders (9 for 400
21
+ * rows) instead of one per item. The page's size only grows with its length,
22
+ * so the search is exact.
23
+ *
24
+ * bushtrade-mcp carries an identical copy in `src/limits.ts` (the packages
25
+ * share no code); keep the two the same.
26
+ */
27
+ export function fitToLimit(items, render, limit = CHARACTER_LIMIT) {
28
+ const size = (r) => JSON.stringify(r, null, 2).length;
29
+ const full = render(items);
30
+ if (items.length <= 1 || size(full) <= limit)
31
+ return { page: items, result: full, truncated: false };
32
+ let lo = 1; // known to be kept (the floor), whether or not it fits
33
+ let hi = items.length - 1; // the largest length still possible
34
+ while (lo < hi) {
35
+ const mid = Math.ceil((lo + hi) / 2);
36
+ if (size(render(items.slice(0, mid))) <= limit)
37
+ lo = mid;
38
+ else
39
+ hi = mid - 1;
40
+ }
41
+ const page = items.slice(0, lo);
42
+ return { page, result: render(page), truncated: true };
43
+ }
44
+ //# sourceMappingURL=limits.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"limits.js","sourceRoot":"","sources":["../src/limits.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,sDAAsD;AACtD,MAAM,CAAC,MAAM,eAAe,GAAG,MAAM,CAAC;AAEtC;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,UAAU,CACxB,KAAU,EACV,MAAwB,EACxB,KAAK,GAAG,eAAe;IAEvB,MAAM,IAAI,GAAG,CAAC,CAAI,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;IACzD,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAC3B,IAAI,KAAK,CAAC,MAAM,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK;QAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;IACrG,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,uDAAuD;IACnE,IAAI,EAAE,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,oCAAoC;IAC/D,OAAO,EAAE,GAAG,EAAE,EAAE,CAAC;QACf,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;QACrC,IAAI,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,KAAK;YAAE,EAAE,GAAG,GAAG,CAAC;;YACpD,EAAE,GAAG,GAAG,GAAG,CAAC,CAAC;IACpB,CAAC;IACD,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAChC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;AACzD,CAAC"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Browser `Origin` policy for the MCP endpoint (Streamable HTTP §Security, and
3
+ * the fix list in #295, P0 item 1).
4
+ *
5
+ * Servers MUST validate `Origin` against DNS rebinding and answer 403 to an
6
+ * invalid one. The policy:
7
+ *
8
+ * - no `Origin` header allowed: every non-browser client (the SDKs, curl,
9
+ * Claude, Cursor) sends none;
10
+ * - a present `Origin` allowed only if its host is on the list, otherwise
11
+ * 403 before any MCP server is built;
12
+ * - CORS `Access-Control-Allow-Origin` echoes an allowed
13
+ * `Origin` (with `Vary: Origin`). It is never `*`.
14
+ *
15
+ * The list is hostnames. A localhost name matches over `http` or `https` on any
16
+ * port (the MCP Inspector runs at http://localhost:6274). Every other name
17
+ * matches only over `https` on the default port, exactly: no subdomains, no
18
+ * `http`, no `:8443`. The same rule applies to a list the caller supplies.
19
+ */
20
+ /** The first-party sites: this Worker, the site, the docs and the console. */
21
+ export declare const ALLOWED_ORIGIN_HOSTS: readonly string[];
22
+ /** The default list: the first-party sites and localhost. */
23
+ export declare const DEFAULT_ALLOWED_HOSTS: readonly string[];
24
+ /**
25
+ * The default list plus the extra origins in `MZIZI_ALLOWED_ORIGINS`
26
+ * (comma-separated `https://host` origins; case and a trailing slash are
27
+ * tolerated). An entry that is not an `https` origin with no path, port or
28
+ * credentials is dropped with a `console.warn`, so a typo cannot open the
29
+ * endpoint wider than named. The result is cached per value, so the Worker pays
30
+ * for the parse once per isolate, not once per request.
31
+ */
32
+ export declare function allowedHostsFromEnv(env: {
33
+ MZIZI_ALLOWED_ORIGINS?: string;
34
+ }): readonly string[];
35
+ /**
36
+ * True when `origin` may call the endpoint. `null` (no header at all) is
37
+ * allowed; a header that is present is judged, so an empty value and the opaque
38
+ * `"null"` are refused like any other unparseable origin.
39
+ */
40
+ export declare function isAllowedOrigin(origin: string | null, hosts?: readonly string[]): boolean;
41
+ /** The 403 for a present-but-unlisted `Origin` (a JSON-RPC error body, like the SDK's own). */
42
+ export declare function forbiddenOrigin(origin: string | null): Response;
43
+ /** A 403 for a present-but-unlisted `Origin`, or undefined when the request may proceed. */
44
+ export declare function originRejection(request: Request, hosts?: readonly string[]): Response | undefined;
45
+ /**
46
+ * The CORS headers for a request whose `Origin` is `origin`, already judged
47
+ * `allowed`: the origin echoed back, never `*`. No `Origin`, or one that is not
48
+ * allowed, gets no `Access-Control-Allow-Origin`; `Vary: Origin` is always
49
+ * present so a cache cannot hand one origin's answer to another. Merge `Vary`
50
+ * with `Headers.append`, not `set`.
51
+ */
52
+ export declare function corsHeadersFor(origin: string | null, allowed: boolean): Record<string, string>;
53
+ /** `corsHeadersFor`, judging the request's own `Origin` against `hosts`. */
54
+ export declare function corsHeaders(request: Request, hosts?: readonly string[]): Record<string, string>;
55
+ //# sourceMappingURL=origin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"origin.d.ts","sourceRoot":"","sources":["../src/origin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAOH,8EAA8E;AAC9E,eAAO,MAAM,oBAAoB,EAAE,SAAS,MAAM,EAMjD,CAAA;AAED,6DAA6D;AAC7D,eAAO,MAAM,qBAAqB,EAAE,SAAS,MAAM,EAA8C,CAAA;AAIjG;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE;IAAE,qBAAqB,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,MAAM,EAAE,CAsB9F;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,EAAE,KAAK,GAAE,SAAS,MAAM,EAA0B,GAAG,OAAO,CAahH;AAED,+FAA+F;AAC/F,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,QAAQ,CAK/D;AAED,4FAA4F;AAC5F,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,QAAQ,GAAG,SAAS,CAGjG;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAS9F;AAED,4EAA4E;AAC5E,wBAAgB,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAG/F"}
package/dist/origin.js ADDED
@@ -0,0 +1,127 @@
1
+ /**
2
+ * Browser `Origin` policy for the MCP endpoint (Streamable HTTP §Security, and
3
+ * the fix list in #295, P0 item 1).
4
+ *
5
+ * Servers MUST validate `Origin` against DNS rebinding and answer 403 to an
6
+ * invalid one. The policy:
7
+ *
8
+ * - no `Origin` header allowed: every non-browser client (the SDKs, curl,
9
+ * Claude, Cursor) sends none;
10
+ * - a present `Origin` allowed only if its host is on the list, otherwise
11
+ * 403 before any MCP server is built;
12
+ * - CORS `Access-Control-Allow-Origin` echoes an allowed
13
+ * `Origin` (with `Vary: Origin`). It is never `*`.
14
+ *
15
+ * The list is hostnames. A localhost name matches over `http` or `https` on any
16
+ * port (the MCP Inspector runs at http://localhost:6274). Every other name
17
+ * matches only over `https` on the default port, exactly: no subdomains, no
18
+ * `http`, no `:8443`. The same rule applies to a list the caller supplies.
19
+ */
20
+ import { localhostAllowedOrigins } from "@modelcontextprotocol/server";
21
+ /** Hostnames that count as local development. */
22
+ const LOCAL_HOSTS = localhostAllowedOrigins();
23
+ /** The first-party sites: this Worker, the site, the docs and the console. */
24
+ export const ALLOWED_ORIGIN_HOSTS = [
25
+ "mzizi.dev",
26
+ "www.mzizi.dev",
27
+ "docs.mzizi.dev",
28
+ "app.mzizi.dev",
29
+ "mcp.mzizi.dev",
30
+ ];
31
+ /** The default list: the first-party sites and localhost. */
32
+ export const DEFAULT_ALLOWED_HOSTS = [...ALLOWED_ORIGIN_HOSTS, ...LOCAL_HOSTS];
33
+ const hostsCache = new Map();
34
+ /**
35
+ * The default list plus the extra origins in `MZIZI_ALLOWED_ORIGINS`
36
+ * (comma-separated `https://host` origins; case and a trailing slash are
37
+ * tolerated). An entry that is not an `https` origin with no path, port or
38
+ * credentials is dropped with a `console.warn`, so a typo cannot open the
39
+ * endpoint wider than named. The result is cached per value, so the Worker pays
40
+ * for the parse once per isolate, not once per request.
41
+ */
42
+ export function allowedHostsFromEnv(env) {
43
+ const raw = env.MZIZI_ALLOWED_ORIGINS;
44
+ if (!raw)
45
+ return DEFAULT_ALLOWED_HOSTS;
46
+ const cached = hostsCache.get(raw);
47
+ if (cached)
48
+ return cached;
49
+ const extra = [];
50
+ for (const entry of raw.split(",")) {
51
+ const value = entry.trim().replace(/\/$/, "").toLowerCase();
52
+ if (!value)
53
+ continue;
54
+ let host;
55
+ try {
56
+ const url = new URL(value);
57
+ if (url.protocol === "https:" && url.origin === value && url.port === "")
58
+ host = url.hostname;
59
+ }
60
+ catch {
61
+ // Not an origin: dropped below.
62
+ }
63
+ if (host)
64
+ extra.push(host);
65
+ else
66
+ console.warn(`mzizi-mcp: MZIZI_ALLOWED_ORIGINS entry ignored (not a plain https origin): ${entry.trim()}`);
67
+ }
68
+ const hosts = [...DEFAULT_ALLOWED_HOSTS, ...extra];
69
+ hostsCache.set(raw, hosts);
70
+ return hosts;
71
+ }
72
+ /**
73
+ * True when `origin` may call the endpoint. `null` (no header at all) is
74
+ * allowed; a header that is present is judged, so an empty value and the opaque
75
+ * `"null"` are refused like any other unparseable origin.
76
+ */
77
+ export function isAllowedOrigin(origin, hosts = DEFAULT_ALLOWED_HOSTS) {
78
+ if (origin === null)
79
+ return true;
80
+ let url;
81
+ try {
82
+ url = new URL(origin);
83
+ }
84
+ catch {
85
+ return false;
86
+ }
87
+ // An Origin is scheme://host[:port] and nothing else.
88
+ if (url.origin !== origin)
89
+ return false;
90
+ if (!hosts.includes(url.hostname))
91
+ return false;
92
+ if (LOCAL_HOSTS.includes(url.hostname))
93
+ return url.protocol === "http:" || url.protocol === "https:";
94
+ return url.protocol === "https:" && url.port === "";
95
+ }
96
+ /** The 403 for a present-but-unlisted `Origin` (a JSON-RPC error body, like the SDK's own). */
97
+ export function forbiddenOrigin(origin) {
98
+ return Response.json({ jsonrpc: "2.0", id: null, error: { code: -32000, message: `Invalid Origin header: ${origin ?? ""}` } }, { status: 403, headers: { Vary: "Origin" } });
99
+ }
100
+ /** A 403 for a present-but-unlisted `Origin`, or undefined when the request may proceed. */
101
+ export function originRejection(request, hosts) {
102
+ const origin = request.headers.get("origin");
103
+ return isAllowedOrigin(origin, hosts) ? undefined : forbiddenOrigin(origin);
104
+ }
105
+ /**
106
+ * The CORS headers for a request whose `Origin` is `origin`, already judged
107
+ * `allowed`: the origin echoed back, never `*`. No `Origin`, or one that is not
108
+ * allowed, gets no `Access-Control-Allow-Origin`; `Vary: Origin` is always
109
+ * present so a cache cannot hand one origin's answer to another. Merge `Vary`
110
+ * with `Headers.append`, not `set`.
111
+ */
112
+ export function corsHeadersFor(origin, allowed) {
113
+ const headers = { Vary: "Origin" };
114
+ if (origin && allowed) {
115
+ headers["Access-Control-Allow-Origin"] = origin;
116
+ headers["Access-Control-Allow-Methods"] = "GET, POST, DELETE, OPTIONS";
117
+ headers["Access-Control-Allow-Headers"] =
118
+ "Content-Type, MCP-Protocol-Version, MCP-Session-Id, Mcp-Method, Mcp-Name, apikey";
119
+ }
120
+ return headers;
121
+ }
122
+ /** `corsHeadersFor`, judging the request's own `Origin` against `hosts`. */
123
+ export function corsHeaders(request, hosts) {
124
+ const origin = request.headers.get("origin");
125
+ return corsHeadersFor(origin, isAllowedOrigin(origin, hosts));
126
+ }
127
+ //# sourceMappingURL=origin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"origin.js","sourceRoot":"","sources":["../src/origin.ts"],"names":[],"mappings":"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"}
@@ -37,5 +37,5 @@ export declare function clientKey(request: Request): string;
37
37
  * The body is a JSON-RPC error so an MCP client can show it, and it names the
38
38
  * way past the limit: signing in.
39
39
  */
40
- export declare function limitAnonymous(limiter: RateLimiter | undefined, request: Request): Promise<Response | null>;
40
+ export declare function limitAnonymous(limiter: RateLimiter | undefined, request: Request, allowedHosts?: readonly string[]): Promise<Response | null>;
41
41
  //# sourceMappingURL=rate-limit.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"rate-limit.d.ts","sourceRoot":"","sources":["../src/rate-limit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAIH,sEAAsE;AACtE,MAAM,MAAM,WAAW,GAAG;IACxB,KAAK,CAAC,OAAO,EAAE;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;CAChE,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAElD;AAED;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,WAAW,GAAG,SAAS,EAChC,OAAO,EAAE,OAAO,GACf,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAuB1B"}
1
+ {"version":3,"file":"rate-limit.d.ts","sourceRoot":"","sources":["../src/rate-limit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAKH,sEAAsE;AACtE,MAAM,MAAM,WAAW,GAAG;IACxB,KAAK,CAAC,OAAO,EAAE;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;CAChE,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAElD;AAED;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,WAAW,GAAG,SAAS,EAChC,OAAO,EAAE,OAAO,EAChB,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,GAC/B,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAuB1B"}
@@ -16,6 +16,7 @@
16
16
  * free tier down with a missing binding, and the limit is a guard, not a gate.
17
17
  */
18
18
  import { ANONYMOUS_RATE_LIMIT, SIGN_IN_MCP_URL } from "./access.js";
19
+ import { corsHeaders } from "./origin.js";
19
20
  /**
20
21
  * The key for one client: the connecting IP Cloudflare reports.
21
22
  *
@@ -32,7 +33,7 @@ export function clientKey(request) {
32
33
  * The body is a JSON-RPC error so an MCP client can show it, and it names the
33
34
  * way past the limit: signing in.
34
35
  */
35
- export async function limitAnonymous(limiter, request) {
36
+ export async function limitAnonymous(limiter, request, allowedHosts) {
36
37
  if (!limiter)
37
38
  return null;
38
39
  const { success } = await limiter.limit({ key: clientKey(request) });
@@ -51,7 +52,7 @@ export async function limitAnonymous(limiter, request) {
51
52
  headers: {
52
53
  "Content-Type": "application/json",
53
54
  "Retry-After": String(periodSeconds),
54
- "Access-Control-Allow-Origin": "*",
55
+ ...corsHeaders(request, allowedHosts),
55
56
  },
56
57
  });
57
58
  }
@@ -1 +1 @@
1
- {"version":3,"file":"rate-limit.js","sourceRoot":"","sources":["../src/rate-limit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAOpE;;;;;;GAMG;AACH,MAAM,UAAU,SAAS,CAAC,OAAgB;IACxC,OAAO,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,IAAI,SAAS,CAAC;AAC9D,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,OAAgC,EAChC,OAAgB;IAEhB,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAC1B,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACrE,IAAI,OAAO;QAAE,OAAO,IAAI,CAAC;IACzB,MAAM,EAAE,KAAK,EAAE,aAAa,EAAE,GAAG,oBAAoB,CAAC;IACtD,OAAO,IAAI,QAAQ,CACjB,IAAI,CAAC,SAAS,CAAC;QACb,OAAO,EAAE,KAAK;QACd,EAAE,EAAE,IAAI;QACR,KAAK,EAAE;YACL,IAAI,EAAE,CAAC,KAAK;YACZ,OAAO,EAAE,iDAAiD,KAAK,QAAQ,aAAa,iEAAiE,eAAe,gBAAgB;SACrL;KACF,CAAC,EACF;QACE,MAAM,EAAE,GAAG;QACX,OAAO,EAAE;YACP,cAAc,EAAE,kBAAkB;YAClC,aAAa,EAAE,MAAM,CAAC,aAAa,CAAC;YACpC,6BAA6B,EAAE,GAAG;SACnC;KACF,CACF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"rate-limit.js","sourceRoot":"","sources":["../src/rate-limit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACpE,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAO1C;;;;;;GAMG;AACH,MAAM,UAAU,SAAS,CAAC,OAAgB;IACxC,OAAO,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,IAAI,SAAS,CAAC;AAC9D,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,OAAgC,EAChC,OAAgB,EAChB,YAAgC;IAEhC,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAC1B,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACrE,IAAI,OAAO;QAAE,OAAO,IAAI,CAAC;IACzB,MAAM,EAAE,KAAK,EAAE,aAAa,EAAE,GAAG,oBAAoB,CAAC;IACtD,OAAO,IAAI,QAAQ,CACjB,IAAI,CAAC,SAAS,CAAC;QACb,OAAO,EAAE,KAAK;QACd,EAAE,EAAE,IAAI;QACR,KAAK,EAAE;YACL,IAAI,EAAE,CAAC,KAAK;YACZ,OAAO,EAAE,iDAAiD,KAAK,QAAQ,aAAa,iEAAiE,eAAe,gBAAgB;SACrL;KACF,CAAC,EACF;QACE,MAAM,EAAE,GAAG;QACX,OAAO,EAAE;YACP,cAAc,EAAE,kBAAkB;YAClC,aAAa,EAAE,MAAM,CAAC,aAAa,CAAC;YACpC,GAAG,WAAW,CAAC,OAAO,EAAE,YAAY,CAAC;SACtC;KACF,CACF,CAAC;AACJ,CAAC"}
@@ -63,7 +63,7 @@ export type AstroImpl = {
63
63
  }>;
64
64
  };
65
65
  /**
66
- * A component's Mzizi Roots (Rust, Dioxus) implementation: the registry's
66
+ * A component's Mzizi Roots (Rust) implementation: the registry's
67
67
  * `/v1/rs/{name}` body, plus the `CONTRACT` clause block its source declares.
68
68
  */
69
69
  export type RustImpl = {
@@ -1 +1 @@
1
- {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,MAAM,MAAM,EAAE,CAAC,CAAC,IAAI;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,CAAC,CAAA;CAAE,CAAC;AAC1C,MAAM,MAAM,IAAI,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,WAAW,GAAG,SAAS,GAAG,SAAS,GAAG,UAAU,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAC5G,MAAM,MAAM,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;AAErC,yFAAyF;AACzF,MAAM,MAAM,WAAW,GAAG;IACxB,YAAY,EAAE;QAAE,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IACpE,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC3C,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC7C,cAAc,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACjD,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACxC,eAAe,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAClD,4FAA4F;IAC5F,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACvC,qDAAqD;IACrD,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC9C,mFAAmF;IACnF,YAAY,EAAE,MAAM,CAAC;IACrB,8FAA8F;IAC9F,KAAK,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CAC1C,CAAC;AAEF,uFAAuF;AACvF,MAAM,MAAM,SAAS,GAAG;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;IAChB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,oBAAoB,EAAE,MAAM,EAAE,CAAC;IAC/B,KAAK,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,QAAQ,CAAA;KAAE,CAAC,CAAC;CACpG,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,QAAQ,GAAG;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,wFAAwF;IACxF,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IACvD,KAAK,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/D,uFAAuF;IACvF,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;IAChC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,KAAK,YAAY,GAAG;IAAE,KAAK,EAAE,QAAQ,EAAE,CAAC;IAAC,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,CAAC;AAgBhE,MAAM,MAAM,SAAS,GAAG;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,mFAAmF;IACnF,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,qFAAqF;IACrF,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG;IACtB,IAAI,EAAE,WAAW,GAAG,YAAY,GAAG,gBAAgB,GAAG,SAAS,CAAC;IAChE,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,4FAA4F;IAC5F,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kFAAkF;IAClF,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAKF,MAAM,MAAM,QAAQ,GAAG,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC;AAEzD,wBAAgB,cAAc,CAAC,GAAG,EAAE,WAAW;;6BAtGR,MAAM;sBAAgB,MAAM;;wBA8HtC,MAAM,KAAG,MAAM,GAAG,SAAS;sBA8B7B,MAAM;sBAGN,MAAM,KAAG,MAAM,GAAG,SAAS;IAWlD;;;OAGG;mBACY,MAAM,GAAG,MAAM,CAAC,SAAS,CAAC;IAezC,qEAAqE;uBACnD,SAAS,GAAQ,EAAE,CAAC,YAAY,GAAG;QAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,CAAC;IAqCvF,4DAA4D;uBACzC,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC;IAY3C;;;;OAIG;kBACW,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC;IAWvC,wFAAwF;2BACjE,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC;IAM/C;;;;;;;;;OASG;+BACwB,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC;IAoCnD;;;;;OAKG;kBACW,MAAM,mBAAe,EAAE,CAAC;QAAE,IAAI,EAAE,SAAS,EAAE,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,CAAC;uBAkFxE,EAAE,CAAC,OAAO,CAAC;IAI9B,mFAAmF;eACxE,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC;gBAUvB,EAAE,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;wBAInB,EAAE,CAAC,OAAO,CAAC;2BAIR,EAAE,CAAC,OAAO,CAAC;0BAIZ,EAAE,CAAC,OAAO,CAAC;IAIjC,oGAAoG;4BAC5E,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC;IAYhD,kFAAkF;uBAC/D,EAAE,CAAC,OAAO,CAAC;wBAKV,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC;EAO/C;AAID;;;GAGG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,QAAQ,CAAC,CAGzD"}