@particle-academy/agent-integrations 0.43.0 → 0.45.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.
- package/README.md +32 -0
- package/dist/bridges/artboard.d.cts +3 -3
- package/dist/bridges/artboard.d.ts +3 -3
- package/dist/bridges/catalog.d.cts +3 -3
- package/dist/bridges/catalog.d.ts +3 -3
- package/dist/bridges/charts.d.cts +3 -3
- package/dist/bridges/charts.d.ts +3 -3
- package/dist/bridges/cms.d.cts +3 -3
- package/dist/bridges/cms.d.ts +3 -3
- package/dist/bridges/code.d.cts +3 -3
- package/dist/bridges/code.d.ts +3 -3
- package/dist/bridges/doc.d.cts +3 -3
- package/dist/bridges/doc.d.ts +3 -3
- package/dist/bridges/features.d.cts +3 -3
- package/dist/bridges/features.d.ts +3 -3
- package/dist/bridges/files.d.cts +3 -3
- package/dist/bridges/files.d.ts +3 -3
- package/dist/bridges/flow.d.cts +3 -3
- package/dist/bridges/flow.d.ts +3 -3
- package/dist/bridges/forms.d.cts +3 -3
- package/dist/bridges/forms.d.ts +3 -3
- package/dist/bridges/git.d.cts +3 -3
- package/dist/bridges/git.d.ts +3 -3
- package/dist/bridges/grid.d.cts +3 -3
- package/dist/bridges/grid.d.ts +3 -3
- package/dist/bridges/map.d.cts +3 -3
- package/dist/bridges/map.d.ts +3 -3
- package/dist/bridges/passkeys.d.cts +3 -3
- package/dist/bridges/passkeys.d.ts +3 -3
- package/dist/bridges/scene.d.cts +3 -3
- package/dist/bridges/scene.d.ts +3 -3
- package/dist/bridges/screens.d.cts +3 -3
- package/dist/bridges/screens.d.ts +3 -3
- package/dist/bridges/sheets.d.cts +3 -3
- package/dist/bridges/sheets.d.ts +3 -3
- package/dist/bridges/slides.d.cts +3 -3
- package/dist/bridges/slides.d.ts +3 -3
- package/dist/bridges/terminal.d.cts +3 -3
- package/dist/bridges/terminal.d.ts +3 -3
- package/dist/bridges/tui.d.cts +2 -2
- package/dist/bridges/tui.d.ts +2 -2
- package/dist/bridges/whiteboard.d.cts +3 -3
- package/dist/bridges/whiteboard.d.ts +3 -3
- package/dist/bridges-artboard.cjs.map +1 -1
- package/dist/bridges-artboard.js +2 -2
- package/dist/bridges-catalog.cjs.map +1 -1
- package/dist/bridges-catalog.js +3 -3
- package/dist/bridges-charts.cjs.map +1 -1
- package/dist/bridges-charts.js +3 -3
- package/dist/bridges-cms.cjs.map +1 -1
- package/dist/bridges-cms.js +4 -4
- package/dist/bridges-code.cjs.map +1 -1
- package/dist/bridges-code.js +3 -3
- package/dist/bridges-doc.cjs.map +1 -1
- package/dist/bridges-doc.js +3 -3
- package/dist/bridges-features.cjs.map +1 -1
- package/dist/bridges-features.js +3 -3
- package/dist/bridges-files.cjs.map +1 -1
- package/dist/bridges-files.js +3 -3
- package/dist/bridges-flow.cjs.map +1 -1
- package/dist/bridges-flow.js +2 -2
- package/dist/bridges-forms.cjs.map +1 -1
- package/dist/bridges-forms.js +3 -3
- package/dist/bridges-git.cjs.map +1 -1
- package/dist/bridges-git.js +3 -3
- package/dist/bridges-grid.cjs.map +1 -1
- package/dist/bridges-grid.js +3 -3
- package/dist/bridges-map.cjs.map +1 -1
- package/dist/bridges-map.js +3 -3
- package/dist/bridges-passkeys.cjs.map +1 -1
- package/dist/bridges-passkeys.js +3 -3
- package/dist/bridges-scene.cjs.map +1 -1
- package/dist/bridges-scene.js +3 -3
- package/dist/bridges-screens.cjs.map +1 -1
- package/dist/bridges-screens.js +3 -3
- package/dist/bridges-sheets.cjs.map +1 -1
- package/dist/bridges-sheets.js +3 -3
- package/dist/bridges-slides.cjs.map +1 -1
- package/dist/bridges-slides.js +3 -3
- package/dist/bridges-terminal.cjs.map +1 -1
- package/dist/bridges-terminal.js +3 -3
- package/dist/bridges-tui.cjs.map +1 -1
- package/dist/bridges-tui.js +2 -2
- package/dist/bridges-whiteboard.cjs.map +1 -1
- package/dist/bridges-whiteboard.js +3 -3
- package/dist/{chunk-5W6YOXLT.js → chunk-36MKPTVD.js} +4 -4
- package/dist/{chunk-5W6YOXLT.js.map → chunk-36MKPTVD.js.map} +1 -1
- package/dist/{chunk-SXVRIIXW.js → chunk-3HVYUMQF.js} +4 -4
- package/dist/{chunk-SXVRIIXW.js.map → chunk-3HVYUMQF.js.map} +1 -1
- package/dist/{chunk-MZ74LLDS.js → chunk-3UUF5KKZ.js} +4 -4
- package/dist/{chunk-MZ74LLDS.js.map → chunk-3UUF5KKZ.js.map} +1 -1
- package/dist/{chunk-WEXMZMJH.js → chunk-3WVXAB3D.js} +3 -3
- package/dist/{chunk-WEXMZMJH.js.map → chunk-3WVXAB3D.js.map} +1 -1
- package/dist/{chunk-Z4L2GOAK.js → chunk-5ZWNCHZS.js} +4 -4
- package/dist/{chunk-Z4L2GOAK.js.map → chunk-5ZWNCHZS.js.map} +1 -1
- package/dist/{chunk-TEB5U6Y5.js → chunk-7NVATRLE.js} +4 -4
- package/dist/{chunk-TEB5U6Y5.js.map → chunk-7NVATRLE.js.map} +1 -1
- package/dist/{chunk-PUMQDV67.js → chunk-AXWMWYH5.js} +4 -4
- package/dist/{chunk-PUMQDV67.js.map → chunk-AXWMWYH5.js.map} +1 -1
- package/dist/{chunk-NKAH67JK.js → chunk-CS3CHGYC.js} +4 -4
- package/dist/{chunk-NKAH67JK.js.map → chunk-CS3CHGYC.js.map} +1 -1
- package/dist/{chunk-QJYRWEXD.js → chunk-CZV3WUW5.js} +35 -8
- package/dist/chunk-CZV3WUW5.js.map +1 -0
- package/dist/{chunk-PCFRBVKS.js → chunk-FCXSR7I5.js} +4 -4
- package/dist/{chunk-PCFRBVKS.js.map → chunk-FCXSR7I5.js.map} +1 -1
- package/dist/{chunk-NIFPRC7P.js → chunk-GVTBMJU6.js} +4 -4
- package/dist/{chunk-NIFPRC7P.js.map → chunk-GVTBMJU6.js.map} +1 -1
- package/dist/{chunk-E2I3YVKC.js → chunk-JLHVQWOV.js} +3 -3
- package/dist/{chunk-E2I3YVKC.js.map → chunk-JLHVQWOV.js.map} +1 -1
- package/dist/{chunk-2LSU3NFO.js → chunk-LQB42OSA.js} +4 -4
- package/dist/{chunk-2LSU3NFO.js.map → chunk-LQB42OSA.js.map} +1 -1
- package/dist/{chunk-VJD3Y7E5.js → chunk-MIDZWKIF.js} +4 -4
- package/dist/{chunk-VJD3Y7E5.js.map → chunk-MIDZWKIF.js.map} +1 -1
- package/dist/{chunk-QOANLXSW.js → chunk-OZBUPO4K.js} +110 -8
- package/dist/chunk-OZBUPO4K.js.map +1 -0
- package/dist/{chunk-LOD77NCD.js → chunk-PWYEW6NL.js} +4 -4
- package/dist/{chunk-LOD77NCD.js.map → chunk-PWYEW6NL.js.map} +1 -1
- package/dist/{chunk-HVDHT7DM.js → chunk-R4XXOGQH.js} +3 -3
- package/dist/{chunk-HVDHT7DM.js.map → chunk-R4XXOGQH.js.map} +1 -1
- package/dist/{chunk-7LLMILTM.js → chunk-RVMM4BHK.js} +4 -4
- package/dist/{chunk-7LLMILTM.js.map → chunk-RVMM4BHK.js.map} +1 -1
- package/dist/{chunk-NIXOY473.js → chunk-SWWJUOCY.js} +3 -3
- package/dist/{chunk-NIXOY473.js.map → chunk-SWWJUOCY.js.map} +1 -1
- package/dist/{chunk-EIBV76IB.js → chunk-VFWFT3OK.js} +4 -4
- package/dist/{chunk-EIBV76IB.js.map → chunk-VFWFT3OK.js.map} +1 -1
- package/dist/{chunk-2Q4EGZHJ.js → chunk-VMRUW4B4.js} +4 -4
- package/dist/{chunk-2Q4EGZHJ.js.map → chunk-VMRUW4B4.js.map} +1 -1
- package/dist/{chunk-GT63LSPJ.js → chunk-VOCUGTZB.js} +4 -4
- package/dist/{chunk-GT63LSPJ.js.map → chunk-VOCUGTZB.js.map} +1 -1
- package/dist/{chunk-N5VOPV64.js → chunk-Z5NL5D4J.js} +4 -4
- package/dist/{chunk-N5VOPV64.js.map → chunk-Z5NL5D4J.js.map} +1 -1
- package/dist/components-shared-whiteboard.cjs +33 -6
- package/dist/components-shared-whiteboard.cjs.map +1 -1
- package/dist/components-shared-whiteboard.js +3 -3
- package/dist/index.cjs +33 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -7
- package/dist/index.d.ts +7 -7
- package/dist/index.js +27 -27
- package/dist/mcp/index.d.cts +5 -5
- package/dist/mcp/index.d.ts +5 -5
- package/dist/mcp/stdio.d.cts +94 -0
- package/dist/mcp/stdio.d.ts +94 -0
- package/dist/mcp-stdio.cjs +120 -0
- package/dist/mcp-stdio.cjs.map +1 -0
- package/dist/mcp-stdio.js +117 -0
- package/dist/mcp-stdio.js.map +1 -0
- package/dist/mcp.cjs +33 -6
- package/dist/mcp.cjs.map +1 -1
- package/dist/mcp.js +1 -1
- package/dist/presence/index.d.cts +1 -1
- package/dist/presence/index.d.ts +1 -1
- package/dist/relay-server/index.d.cts +44 -2
- package/dist/relay-server/index.d.ts +44 -2
- package/dist/relay-server-cli.cjs +108 -6
- package/dist/relay-server-cli.cjs.map +1 -1
- package/dist/relay-server-cli.js +1 -1
- package/dist/relay-server.cjs +108 -6
- package/dist/relay-server.cjs.map +1 -1
- package/dist/relay-server.js +1 -1
- package/dist/{server-BJNF7pQe.d.cts → server-BIcA3ZtK.d.cts} +32 -3
- package/dist/{server-Dt97UxuD.d.ts → server-DnUyeavY.d.ts} +32 -3
- package/dist/sharing/index.d.cts +3 -3
- package/dist/sharing/index.d.ts +3 -3
- package/dist/sheets-adapter.d.cts +3 -3
- package/dist/sheets-adapter.d.ts +3 -3
- package/dist/{tool-host-BpEBqf5u.d.cts → tool-host-LVBgCN5m.d.cts} +1 -1
- package/dist/{tool-host-xY5F-eqG.d.ts → tool-host-Wo0pkY83.d.ts} +1 -1
- package/dist/{types-DSwsNTBG.d.ts → types-BxNRKSVd.d.ts} +1 -1
- package/dist/{types-C58ZXs4K.d.cts → types-C2DtnHIn.d.cts} +25 -1
- package/dist/{types-C58ZXs4K.d.ts → types-C2DtnHIn.d.ts} +25 -1
- package/dist/{types-C4NaIW6B.d.cts → types-EcElKOlk.d.cts} +1 -1
- package/dist/undo/index.d.cts +2 -2
- package/dist/undo/index.d.ts +2 -2
- package/dist/undo.cjs.map +1 -1
- package/dist/undo.js +3 -3
- package/docs/relay-protocol.md +33 -0
- package/package.json +13 -2
- package/dist/chunk-QJYRWEXD.js.map +0 -1
- package/dist/chunk-QOANLXSW.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/relay-server/core.ts","../src/relay-server/node.ts"],"names":["randomBytes","next","createHash","timingSafeEqual","URL","ok"],"mappings":"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","file":"relay-server.cjs","sourcesContent":["import { createHash, randomBytes, timingSafeEqual } from \"node:crypto\";\n\n/**\n * RelayBroker — pure logic for the SSE+POST tunnel described in\n * docs/relay-protocol.md, hostable in any Node-compatible runtime\n * (Node, Bun, Deno-with-Node-compat, Cloudflare Workers via the Web\n * standards subset). No HTTP framework opinions; this class just\n * stores sessions, validates tokens, enqueues frames, and produces\n * SSE event payloads ready to flush.\n *\n * const broker = new RelayBroker();\n * const reg = broker.register(\"session-id\", \"token\"); // ok / error\n * broker.inbox(\"session-id\", \"token\", '{\"jsonrpc\":\"2.0\",…}'); // enqueue inbound\n * const sub = broker.subscribe(\"session-id\", \"token\", \"inbound\");\n * for await (const payload of sub.frames()) yield encodeSse(payload);\n *\n * Storage is an in-memory Map by default — fine for a single relay\n * process. To run multiple instances behind a load balancer, swap\n * `MemoryStore` for a Redis-backed equivalent (same Store interface).\n */\n\nexport type Direction = \"inbound\" | \"outbound\";\n\nexport type Session = {\n id: string;\n /** SHA-256 hex of the original token. Compared with timing-safe equals. */\n tokenHash: string;\n /** Last touched (ms since epoch). Used for TTL cleanup. */\n lastSeen: number;\n};\n\nexport type Subscriber = {\n id: string;\n direction: Direction;\n queue: string[];\n resolveNext: ((frame: string | null) => void) | null;\n};\n\nexport type RelayBrokerOptions = {\n /** Sessions auto-expire after this many ms of inactivity. Default 4h. */\n ttlMs?: number;\n /** Cleanup tick interval in ms. Default 60 000. */\n reapIntervalMs?: number;\n /** Bring-your-own storage layer (redis, etc.). Defaults to in-memory. */\n store?: Store;\n};\n\nexport interface Store {\n putSession(s: Session): void;\n getSession(id: string): Session | undefined;\n deleteSession(id: string): void;\n /** Used by the reap tick — return ids whose lastSeen < cutoff. */\n expiredSessionIds(cutoff: number): string[];\n}\n\nclass MemoryStore implements Store {\n private sessions = new Map<string, Session>();\n putSession(s: Session) { this.sessions.set(s.id, s); }\n getSession(id: string) { return this.sessions.get(id); }\n deleteSession(id: string) { this.sessions.delete(id); }\n expiredSessionIds(cutoff: number) {\n const out: string[] = [];\n for (const [id, s] of this.sessions) if (s.lastSeen < cutoff) out.push(id);\n return out;\n }\n}\n\nconst SESSION_ID_PATTERN = /^[A-Za-z0-9_-]{4,64}$/;\n\nexport class RelayBroker {\n private readonly ttlMs: number;\n private readonly store: Store;\n /** Per-session, per-direction subscriber list. */\n private subs: Map<string, Map<string, Map<string, Subscriber>>> = new Map();\n private reaper?: ReturnType<typeof setInterval>;\n\n constructor(opts: RelayBrokerOptions = {}) {\n this.ttlMs = opts.ttlMs ?? 4 * 60 * 60 * 1000; // 4h\n this.store = opts.store ?? new MemoryStore();\n const tick = opts.reapIntervalMs ?? 60_000;\n if (tick > 0) {\n this.reaper = setInterval(() => this.reap(), tick);\n // Don't keep the process alive just for the reaper.\n if (typeof (this.reaper as { unref?: () => void }).unref === \"function\") {\n (this.reaper as { unref: () => void }).unref();\n }\n }\n }\n\n dispose() {\n if (this.reaper) clearInterval(this.reaper);\n this.subs.clear();\n }\n\n /** Register a session id + token. Idempotent — same id+token re-registers,\n * different token fails. */\n register(id: string, token: string): { ok: true } | { ok: false; reason: string } {\n if (!SESSION_ID_PATTERN.test(id)) return { ok: false, reason: \"invalid_session_id\" };\n if (typeof token !== \"string\" || token.length < 16 || token.length > 128) {\n return { ok: false, reason: \"invalid_token\" };\n }\n const existing = this.store.getSession(id);\n const hash = sha256Hex(token);\n if (existing) {\n if (!timingSafeEqualHex(existing.tokenHash, hash)) return { ok: false, reason: \"session_taken\" };\n existing.lastSeen = Date.now();\n this.store.putSession(existing);\n return { ok: true };\n }\n this.store.putSession({ id, tokenHash: hash, lastSeen: Date.now() });\n return { ok: true };\n }\n\n unregister(id: string, token: string): boolean {\n if (!this.validate(id, token)) return false;\n this.store.deleteSession(id);\n this.subs.delete(id);\n return true;\n }\n\n /**\n * Validate an authenticated touch, saying WHY when it fails.\n *\n * `session_gone` and `invalid_token` are different facts and a client acts on\n * them differently. A gone session means the page has closed or the TTL has\n * elapsed — the NORMAL end of a relay lifecycle, since the browser is the\n * server and no state persists across restarts. A bad token means the caller\n * is wrong.\n *\n * They were collapsed into one boolean and reported as `invalid_token`, so an\n * agent holding a perfectly good token against a closed page was told its\n * credentials were wrong. Not a missing signal — an actively misleading one,\n * which sends the reader to debug an auth path that was never the problem.\n *\n * Missing credentials stay `invalid_token`: a request that never named a\n * session has not discovered a dead one.\n *\n * The reason is deliberately NOT widened to cover a wrong token on a live\n * session — answering `session_gone` there would tell an unauthenticated\n * caller which sessions exist.\n *\n * Requested by the Prism harness while designing a non-Node relay client.\n */\n check(id: string, token: string): { ok: true } | { ok: false; reason: \"invalid_token\" | \"session_gone\" } {\n if (!id || !token) return { ok: false, reason: \"invalid_token\" };\n\n const s = this.store.getSession(id);\n if (!s) return { ok: false, reason: \"session_gone\" };\n\n if (!timingSafeEqualHex(s.tokenHash, sha256Hex(token))) {\n return { ok: false, reason: \"invalid_token\" };\n }\n\n s.lastSeen = Date.now();\n this.store.putSession(s);\n return { ok: true };\n }\n\n /**\n * Validate an authenticated touch and slide the TTL forward.\n *\n * Kept as-is for existing callers; `check()` is the one that says why.\n */\n validate(id: string, token: string): boolean {\n return this.check(id, token).ok;\n }\n\n /** Drop a session — the page closed, or a test needs it gone. */\n dropSession(id: string): void {\n this.store.deleteSession(id);\n this.subs.delete(id);\n }\n\n /** Push a frame onto the inbound queue (external agent → browser). */\n inbox(id: string, token: string, payload: string): boolean {\n if (!this.validate(id, token)) return false;\n if (!this.isFrame(payload)) return false;\n this.fanOut(id, \"inbound\", payload);\n return true;\n }\n\n /** Push a frame onto the outbound queue (browser server → external agents). */\n outbox(id: string, token: string, payload: string): boolean {\n if (!this.validate(id, token)) return false;\n if (!this.isFrame(payload)) return false;\n this.fanOut(id, \"outbound\", payload);\n return true;\n }\n\n /**\n * Subscribe to a session's queue for one direction. Returns an iterable\n * the caller (an HTTP handler) pumps as SSE.\n */\n subscribe(id: string, token: string, direction: Direction): SubscribeResult {\n if (!this.validate(id, token)) return { ok: false, reason: \"invalid_token\" };\n const subscriberId = randomBytes(8).toString(\"hex\");\n const subscriber: Subscriber = { id: subscriberId, direction, queue: [], resolveNext: null };\n this.getDirSubs(id, direction).set(subscriberId, subscriber);\n\n // Notify the inbound side (= browser) that an outbound subscriber\n // (= external agent) just connected.\n if (direction === \"outbound\") {\n this.fanOut(\n id,\n \"inbound\",\n JSON.stringify({\n jsonrpc: \"2.0\",\n method: \"notifications/peer_joined\",\n params: { subscriberId, ts: Date.now() },\n }),\n );\n }\n\n const unsubscribe = () => {\n this.getDirSubs(id, direction).delete(subscriberId);\n if (direction === \"outbound\") {\n this.fanOut(\n id,\n \"inbound\",\n JSON.stringify({\n jsonrpc: \"2.0\",\n method: \"notifications/peer_left\",\n params: { subscriberId, ts: Date.now() },\n }),\n );\n }\n };\n\n /** Async generator the HTTP handler drains. Yields raw frame payloads;\n * the handler is responsible for SSE framing (`event: mcp\\ndata: …`). */\n const frames = async function* (this: Subscriber): AsyncGenerator<string, void, void> {\n while (true) {\n if (this.queue.length > 0) {\n const next = this.queue.shift();\n if (next !== undefined) yield next;\n continue;\n }\n const next = await new Promise<string | null>((resolve) => {\n this.resolveNext = resolve;\n });\n this.resolveNext = null;\n if (next === null) return;\n yield next;\n }\n }.bind(subscriber);\n\n return {\n ok: true,\n subscriberId,\n frames: frames(),\n unsubscribe: () => {\n // Wake the generator and let it return cleanly.\n subscriber.resolveNext?.(null);\n unsubscribe();\n },\n };\n }\n\n // ────────────────────────────────────────────────────────────── internals\n\n private getDirSubs(sessionId: string, direction: Direction): Map<string, Subscriber> {\n let bySession = this.subs.get(sessionId);\n if (!bySession) {\n bySession = new Map();\n this.subs.set(sessionId, bySession);\n }\n let byDir = bySession.get(direction);\n if (!byDir) {\n byDir = new Map();\n bySession.set(direction, byDir);\n }\n return byDir;\n }\n\n private fanOut(sessionId: string, direction: Direction, payload: string) {\n const dir = this.subs.get(sessionId)?.get(direction);\n if (!dir) return;\n for (const sub of dir.values()) {\n sub.queue.push(payload);\n sub.resolveNext?.(sub.queue.shift() ?? null);\n }\n }\n\n /**\n * Validate that a peer-supplied payload is a well-formed JSON-RPC 2.0 frame\n * (or batch) before it is fanned out. Previously this was a substring match on\n * `\"jsonrpc\"`, which let any token holder inject spoofed frames — a forged\n * `notifications/peer_joined` / `peer_left` (broker-reserved presence control),\n * a fake `notifications/agent_activity {source:\"user\"}` (\"human took control\"),\n * or a forged response with a matching id. We now parse + shape-check, and\n * reject the broker-reserved control methods (the broker emits those itself,\n * never a peer).\n */\n private isFrame(payload: string): boolean {\n if (payload.length === 0) return false;\n let parsed: unknown;\n try {\n parsed = JSON.parse(payload);\n } catch {\n return false;\n }\n const frames = Array.isArray(parsed) ? parsed : [parsed];\n return frames.length > 0 && frames.every((f) => this.isValidFrame(f));\n }\n\n private isValidFrame(f: unknown): boolean {\n if (!f || typeof f !== \"object\" || Array.isArray(f)) return false;\n const o = f as Record<string, unknown>;\n if (o.jsonrpc !== \"2.0\") return false;\n const method = typeof o.method === \"string\" ? o.method : undefined;\n // Broker-reserved control frames may never arrive from a peer.\n if (method === \"notifications/peer_joined\" || method === \"notifications/peer_left\") return false;\n if (method !== undefined) return true; // request or notification\n // Response: needs an id and exactly one of result / error.\n const hasResult = \"result\" in o;\n const hasError = \"error\" in o;\n return \"id\" in o && hasResult !== hasError;\n }\n\n private reap() {\n const cutoff = Date.now() - this.ttlMs;\n for (const id of this.store.expiredSessionIds(cutoff)) {\n const dirs = this.subs.get(id);\n if (dirs) {\n for (const dir of dirs.values()) {\n for (const sub of dir.values()) sub.resolveNext?.(null);\n }\n }\n this.subs.delete(id);\n this.store.deleteSession(id);\n }\n }\n}\n\nexport type SubscribeResult =\n | { ok: false; reason: string }\n | {\n ok: true;\n subscriberId: string;\n frames: AsyncGenerator<string, void, void>;\n unsubscribe: () => void;\n };\n\nfunction sha256Hex(input: string): string {\n return createHash(\"sha256\").update(input).digest(\"hex\");\n}\n\nfunction timingSafeEqualHex(a: string, b: string): boolean {\n if (a.length !== b.length) return false;\n return timingSafeEqual(Buffer.from(a, \"hex\"), Buffer.from(b, \"hex\"));\n}\n","import type { IncomingMessage, ServerResponse } from \"node:http\";\nimport { URL } from \"node:url\";\nimport { RelayBroker, type RelayBrokerOptions } from \"./core\";\n\n/**\n * Node HTTP adapter for {@link RelayBroker}. Returns a single request\n * handler plus per-route handlers, so you can either drop it into\n * `http.createServer(...)` directly or mount the individual handlers\n * onto your existing Node HTTP framework (Express, Hono w/ node-adapter,\n * native http).\n *\n * const relay = createNodeRelay({ pathPrefix: \"/mcp-relay\" });\n * http.createServer(relay.handler).listen(8787);\n *\n * // Or piecemeal:\n * app.post(\"/mcp-relay/register\", relay.register);\n * app.post(\"/mcp-relay/:s/inbox\", relay.inbox);\n * app.post(\"/mcp-relay/:s/outbox\", relay.outbox);\n * app.get (\"/mcp-relay/:s/events\", relay.events);\n * app.post(\"/mcp-relay/:s/unregister\", relay.unregister);\n */\n\nexport type NodeRelayOptions = RelayBrokerOptions & {\n /** URL path prefix (without trailing slash). Default `\"\"` — handlers\n * expect paths like `/register`, `/{id}/inbox`, etc. directly. */\n pathPrefix?: string;\n /** Comma-separated origins (or `*`) for CORS. Default `*` — relays\n * are typically called cross-origin from the demo host. */\n corsAllowOrigin?: string;\n /**\n * Strict browser-origin allow-list. When set, only these Origins get a\n * matching `Access-Control-Allow-Origin` (the request's own Origin is\n * reflected, never `*`), which blunts DNS-rebinding + hostile cross-origin\n * pages from reading relay responses. Recommended for any browser-facing\n * deployment. When unset, `corsAllowOrigin` (default `*`) is used and the\n * session token is the only auth — pair that with a loopback bind.\n */\n allowedOrigins?: string[];\n};\n\nexport type NodeHandler = (req: IncomingMessage, res: ServerResponse) => unknown | Promise<unknown>;\n\nexport type NodeRelay = {\n broker: RelayBroker;\n /** Single-handler shape — routes internally based on method + URL. */\n handler: NodeHandler;\n /** Per-route handlers. Each handler ignores the URL prefix and\n * acts on the path remainder, so you can mount them under any\n * prefix in your existing app. */\n register: NodeHandler;\n inbox: NodeHandler;\n outbox: NodeHandler;\n events: NodeHandler;\n unregister: NodeHandler;\n};\n\nexport function createNodeRelay(opts: NodeRelayOptions = {}): NodeRelay {\n const broker = new RelayBroker(opts);\n const prefix = (opts.pathPrefix ?? \"\").replace(/\\/$/, \"\");\n const cors = opts.corsAllowOrigin ?? \"*\";\n\n const allowedOrigins = opts.allowedOrigins;\n\n function setCorsHeaders(res: ServerResponse, req?: IncomingMessage) {\n if (allowedOrigins && allowedOrigins.length) {\n // Strict mode: reflect the request Origin only when it's allow-listed;\n // otherwise emit an origin that no browser will match.\n const origin = req?.headers.origin;\n res.setHeader(\"access-control-allow-origin\", origin && allowedOrigins.includes(origin) ? origin : \"null\");\n res.setHeader(\"vary\", \"origin\");\n } else {\n res.setHeader(\"access-control-allow-origin\", cors);\n }\n res.setHeader(\"access-control-allow-methods\", \"GET, POST, OPTIONS\");\n // `authorization` is forward-compat for a header-borne session token.\n res.setHeader(\"access-control-allow-headers\", \"content-type, x-csrf-token, accept, authorization\");\n res.setHeader(\"access-control-max-age\", \"86400\");\n }\n\n function readBody(req: IncomingMessage): Promise<string> {\n return new Promise((resolve, reject) => {\n const chunks: Buffer[] = [];\n let bytes = 0;\n req.on(\"data\", (chunk: Buffer) => {\n bytes += chunk.length;\n // Cap individual frames at 256 KB — protect against runaway payloads.\n if (bytes > 256 * 1024) {\n reject(new Error(\"payload_too_large\"));\n req.destroy();\n return;\n }\n chunks.push(chunk);\n });\n req.on(\"end\", () => resolve(Buffer.concat(chunks).toString(\"utf8\")));\n req.on(\"error\", reject);\n });\n }\n\n function json(res: ServerResponse, status: number, body: unknown): void {\n res.statusCode = status;\n res.setHeader(\"content-type\", \"application/json\");\n res.end(JSON.stringify(body));\n }\n\n function getQuery(req: IncomingMessage): URLSearchParams {\n const host = req.headers.host || \"x\";\n const u = new URL(req.url || \"/\", `http://${host}`);\n return u.searchParams;\n }\n\n function getPathname(req: IncomingMessage): string {\n const host = req.headers.host || \"x\";\n const u = new URL(req.url || \"/\", `http://${host}`);\n return u.pathname;\n }\n\n const register: NodeHandler = async (req, res) => {\n setCorsHeaders(res, req);\n if (req.method === \"OPTIONS\") { res.statusCode = 204; return res.end(); }\n if (req.method !== \"POST\") return json(res, 405, { error: \"method_not_allowed\" });\n let body: string;\n try { body = await readBody(req); } catch (e) {\n return json(res, 413, { error: e instanceof Error ? e.message : \"payload_error\" });\n }\n let parsed: unknown;\n try { parsed = JSON.parse(body); } catch { return json(res, 400, { error: \"invalid_json\" }); }\n const { session, token } = (parsed ?? {}) as { session?: string; token?: string };\n if (typeof session !== \"string\" || typeof token !== \"string\") {\n return json(res, 400, { error: \"missing_fields\" });\n }\n const result = broker.register(session, token);\n if (!result.ok) return json(res, 401, { error: result.reason });\n return json(res, 200, { ok: true });\n };\n\n /** Handler for endpoints with a `{session}` segment. The path matcher\n * caller passes the session id explicitly so this works mounted under\n * any route shape. */\n function makeSessionHandler(\n direction: Direction | \"unregister\",\n ): NodeHandler {\n return async (req, res) => {\n setCorsHeaders(res, req);\n if (req.method === \"OPTIONS\") { res.statusCode = 204; return res.end(); }\n if (req.method !== \"POST\") return json(res, 405, { error: \"method_not_allowed\" });\n const session = extractSession(req, prefix);\n if (!session) return json(res, 400, { error: \"missing_session\" });\n const token = getQuery(req).get(\"token\") ?? \"\";\n\n if (direction === \"unregister\") {\n // Unregistering a session that is already gone is a SUCCESS, not an\n // auth failure. The caller wanted it gone and it is gone; reporting\n // `invalid_token` for a correct token would make a clean shutdown look\n // like a broken one, and a client retrying it would loop.\n const state = broker.check(session, token);\n if (!state.ok && state.reason === \"session_gone\") {\n return json(res, 200, { ok: true, alreadyGone: true });\n }\n\n const ok = broker.unregister(session, token);\n return json(res, ok ? 200 : 401, ok ? { ok: true } : { error: \"invalid_token\" });\n }\n\n let body: string;\n try { body = await readBody(req); } catch (e) {\n return json(res, 413, { error: e instanceof Error ? e.message : \"payload_error\" });\n }\n // A GONE SESSION IS REPORTED AS ITSELF, with 410, before the frame is\n // even considered.\n //\n // Every failure here used to come back as `401 invalid_token_or_frame`,\n // so an agent whose page had simply closed was told its credentials or\n // its JSON were wrong. A relay session ending is the NORMAL end of a\n // lifecycle -- the browser is the server and nothing persists -- so it is\n // the one outcome a server-side client must be able to recognise.\n //\n // 410 Gone rather than 404: the session existed and is now over, which is\n // exactly what the status means, and it distinguishes \"this is finished\"\n // from \"you have the wrong URL\".\n const auth = broker.check(session, token);\n if (!auth.ok && auth.reason === \"session_gone\") {\n return json(res, 410, { error: \"session_gone\" });\n }\n\n const ok = direction === \"inbound\"\n ? broker.inbox(session, token, body)\n : broker.outbox(session, token, body);\n return json(res, ok ? 200 : 401, ok ? { ok: true } : { error: \"invalid_token_or_frame\" });\n };\n }\n\n const inbox = makeSessionHandler(\"inbound\");\n const outbox = makeSessionHandler(\"outbound\");\n const unregister = makeSessionHandler(\"unregister\");\n\n const events: NodeHandler = async (req, res) => {\n setCorsHeaders(res, req);\n if (req.method === \"OPTIONS\") { res.statusCode = 204; return res.end(); }\n if (req.method !== \"GET\") return json(res, 405, { error: \"method_not_allowed\" });\n const session = extractSession(req, prefix);\n if (!session) return json(res, 400, { error: \"missing_session\" });\n const q = getQuery(req);\n const token = q.get(\"token\") ?? \"\";\n const direction = q.get(\"direction\") === \"outbound\" ? \"outbound\" : \"inbound\";\n\n const sub = broker.subscribe(session, token, direction);\n if (!sub.ok) {\n res.statusCode = 401;\n res.setHeader(\"content-type\", \"text/event-stream\");\n res.write(`event: error\\ndata: ${sub.reason}\\n\\n`);\n return res.end();\n }\n\n res.statusCode = 200;\n res.setHeader(\"content-type\", \"text/event-stream\");\n res.setHeader(\"cache-control\", \"no-cache\");\n res.setHeader(\"connection\", \"keep-alive\");\n res.setHeader(\"x-accel-buffering\", \"no\");\n res.write(\"retry: 2000\\n\\n\");\n flush(res);\n\n let heartbeat: ReturnType<typeof setInterval> | null = setInterval(() => {\n res.write(\": keepalive\\n\\n\");\n flush(res);\n }, 15_000);\n if (heartbeat && typeof (heartbeat as { unref?: () => void }).unref === \"function\") {\n (heartbeat as { unref: () => void }).unref();\n }\n\n const cleanup = () => {\n if (heartbeat) { clearInterval(heartbeat); heartbeat = null; }\n sub.unsubscribe();\n };\n req.on(\"close\", cleanup);\n req.on(\"error\", cleanup);\n\n try {\n for await (const frame of sub.frames) {\n res.write(`event: mcp\\ndata: ${frame}\\n\\n`);\n flush(res);\n }\n } catch {\n /* stream ended */\n } finally {\n cleanup();\n res.end();\n }\n };\n\n /**\n * Single handler — routes based on method + path. Useful for mounting\n * via `http.createServer(relay.handler)` without an Express layer.\n */\n const handler: NodeHandler = async (req, res) => {\n const pathname = getPathname(req);\n if (!pathname.startsWith(prefix + \"/\")) {\n return json(res, 404, { error: \"not_found\" });\n }\n const rest = pathname.slice(prefix.length); // \"/register\", \"/<id>/inbox\", etc.\n if (rest === \"/register\") return register(req, res);\n const m = /^\\/([A-Za-z0-9_-]{4,64})\\/(inbox|outbox|events|unregister)$/.exec(rest);\n if (!m) return json(res, 404, { error: \"not_found\" });\n const route = m[2];\n if (route === \"inbox\") return inbox(req, res);\n if (route === \"outbox\") return outbox(req, res);\n if (route === \"events\") return events(req, res);\n if (route === \"unregister\") return unregister(req, res);\n return json(res, 404, { error: \"not_found\" });\n };\n\n return { broker, handler, register, inbox, outbox, events, unregister };\n}\n\nfunction extractSession(req: IncomingMessage, prefix: string): string | null {\n const host = req.headers.host || \"x\";\n const u = new URL(req.url || \"/\", `http://${host}`);\n const path = u.pathname;\n if (prefix && !path.startsWith(prefix + \"/\")) return null;\n const rest = prefix ? path.slice(prefix.length) : path;\n const m = /^\\/([A-Za-z0-9_-]{4,64})\\//.exec(rest);\n return m ? m[1] : null;\n}\n\nfunction flush(res: ServerResponse) {\n // Node doesn't expose explicit flush, but write returns false when buffered;\n // explicit flushHeaders + write is enough for SSE in practice.\n const r = res as { flush?: () => void };\n r.flush?.();\n}\n\ntype Direction = \"inbound\" | \"outbound\";\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/relay-server/core.ts","../src/relay-server/node.ts"],"names":["randomBytes","next","createHash","timingSafeEqual","URL","ok"],"mappings":"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","file":"relay-server.cjs","sourcesContent":["import { createHash, randomBytes, timingSafeEqual } from \"node:crypto\";\n\n/**\n * RelayBroker — pure logic for the SSE+POST tunnel described in\n * docs/relay-protocol.md, hostable in any Node-compatible runtime\n * (Node, Bun, Deno-with-Node-compat, Cloudflare Workers via the Web\n * standards subset). No HTTP framework opinions; this class just\n * stores sessions, validates tokens, enqueues frames, and produces\n * SSE event payloads ready to flush.\n *\n * const broker = new RelayBroker();\n * const reg = broker.register(\"session-id\", \"token\"); // ok / error\n * broker.inbox(\"session-id\", \"token\", '{\"jsonrpc\":\"2.0\",…}'); // enqueue inbound\n * const sub = broker.subscribe(\"session-id\", \"token\", \"inbound\");\n * for await (const payload of sub.frames()) yield encodeSse(payload);\n *\n * Storage is an in-memory Map by default — fine for a single relay\n * process. To run multiple instances behind a load balancer, swap\n * `MemoryStore` for a Redis-backed equivalent (same Store interface).\n */\n\nexport type Direction = \"inbound\" | \"outbound\";\n\nexport type Session = {\n id: string;\n /** SHA-256 hex of the original token. Compared with timing-safe equals. */\n tokenHash: string;\n /** Last touched (ms since epoch). Used for TTL cleanup. */\n lastSeen: number;\n};\n\nexport type Subscriber = {\n id: string;\n direction: Direction;\n queue: string[];\n resolveNext: ((frame: string | null) => void) | null;\n /**\n * The caller-supplied client label, when one was given.\n *\n * Used to route a RESPONSE back to whoever asked. Without it the broker\n * cannot tell two holders of one bearer token apart, and every reply goes to\n * every subscriber -- so a second token holder passively receives the results\n * of everyone else's tool calls without making one.\n */\n client?: string;\n};\n\nexport type RelayBrokerOptions = {\n /** Sessions auto-expire after this many ms of inactivity. Default 4h. */\n ttlMs?: number;\n /** Cleanup tick interval in ms. Default 60 000. */\n reapIntervalMs?: number;\n /** Bring-your-own storage layer (redis, etc.). Defaults to in-memory. */\n store?: Store;\n};\n\nexport interface Store {\n putSession(s: Session): void;\n getSession(id: string): Session | undefined;\n deleteSession(id: string): void;\n /** Used by the reap tick — return ids whose lastSeen < cutoff. */\n expiredSessionIds(cutoff: number): string[];\n}\n\nclass MemoryStore implements Store {\n private sessions = new Map<string, Session>();\n putSession(s: Session) { this.sessions.set(s.id, s); }\n getSession(id: string) { return this.sessions.get(id); }\n deleteSession(id: string) { this.sessions.delete(id); }\n expiredSessionIds(cutoff: number) {\n const out: string[] = [];\n for (const [id, s] of this.sessions) if (s.lastSeen < cutoff) out.push(id);\n return out;\n }\n}\n\nconst SESSION_ID_PATTERN = /^[A-Za-z0-9_-]{4,64}$/;\n\nexport class RelayBroker {\n private readonly ttlMs: number;\n private readonly store: Store;\n /** Per-session, per-direction subscriber list. */\n private subs: Map<string, Map<string, Map<string, Subscriber>>> = new Map();\n\n /** Per-session map of JSON-RPC request id -> the client that asked. */\n private callers: Map<string, Map<string, string>> = new Map();\n private reaper?: ReturnType<typeof setInterval>;\n\n constructor(opts: RelayBrokerOptions = {}) {\n this.ttlMs = opts.ttlMs ?? 4 * 60 * 60 * 1000; // 4h\n this.store = opts.store ?? new MemoryStore();\n const tick = opts.reapIntervalMs ?? 60_000;\n if (tick > 0) {\n this.reaper = setInterval(() => this.reap(), tick);\n // Don't keep the process alive just for the reaper.\n if (typeof (this.reaper as { unref?: () => void }).unref === \"function\") {\n (this.reaper as { unref: () => void }).unref();\n }\n }\n }\n\n dispose() {\n if (this.reaper) clearInterval(this.reaper);\n this.subs.clear();\n this.callers.clear();\n }\n\n /** Register a session id + token. Idempotent — same id+token re-registers,\n * different token fails. */\n register(id: string, token: string): { ok: true } | { ok: false; reason: string } {\n if (!SESSION_ID_PATTERN.test(id)) return { ok: false, reason: \"invalid_session_id\" };\n if (typeof token !== \"string\" || token.length < 16 || token.length > 128) {\n return { ok: false, reason: \"invalid_token\" };\n }\n const existing = this.store.getSession(id);\n const hash = sha256Hex(token);\n if (existing) {\n if (!timingSafeEqualHex(existing.tokenHash, hash)) return { ok: false, reason: \"session_taken\" };\n existing.lastSeen = Date.now();\n this.store.putSession(existing);\n return { ok: true };\n }\n this.store.putSession({ id, tokenHash: hash, lastSeen: Date.now() });\n return { ok: true };\n }\n\n unregister(id: string, token: string): boolean {\n if (!this.validate(id, token)) return false;\n this.store.deleteSession(id);\n this.subs.delete(id);\n this.callers.delete(id);\n return true;\n }\n\n /**\n * Validate an authenticated touch, saying WHY when it fails.\n *\n * `session_gone` and `invalid_token` are different facts and a client acts on\n * them differently. A gone session means the page has closed or the TTL has\n * elapsed — the NORMAL end of a relay lifecycle, since the browser is the\n * server and no state persists across restarts. A bad token means the caller\n * is wrong.\n *\n * They were collapsed into one boolean and reported as `invalid_token`, so an\n * agent holding a perfectly good token against a closed page was told its\n * credentials were wrong. Not a missing signal — an actively misleading one,\n * which sends the reader to debug an auth path that was never the problem.\n *\n * Missing credentials stay `invalid_token`: a request that never named a\n * session has not discovered a dead one.\n *\n * The reason is deliberately NOT widened to cover a wrong token on a live\n * session — answering `session_gone` there would tell an unauthenticated\n * caller which sessions exist.\n *\n * Requested by the Prism harness while designing a non-Node relay client.\n */\n check(id: string, token: string): { ok: true } | { ok: false; reason: \"invalid_token\" | \"session_gone\" } {\n if (!id || !token) return { ok: false, reason: \"invalid_token\" };\n\n const s = this.store.getSession(id);\n if (!s) return { ok: false, reason: \"session_gone\" };\n\n if (!timingSafeEqualHex(s.tokenHash, sha256Hex(token))) {\n return { ok: false, reason: \"invalid_token\" };\n }\n\n s.lastSeen = Date.now();\n this.store.putSession(s);\n return { ok: true };\n }\n\n /**\n * Validate an authenticated touch and slide the TTL forward.\n *\n * Kept as-is for existing callers; `check()` is the one that says why.\n */\n validate(id: string, token: string): boolean {\n return this.check(id, token).ok;\n }\n\n /** Drop a session — the page closed, or a test needs it gone. */\n dropSession(id: string): void {\n this.store.deleteSession(id);\n this.subs.delete(id);\n this.callers.delete(id);\n }\n\n /** Push a frame onto the inbound queue (external agent → browser). */\n inbox(id: string, token: string, payload: string, opts: { client?: string } = {}): boolean {\n if (!this.validate(id, token)) return false;\n if (!this.isFrame(payload)) return false;\n\n // Remember WHO asked, so the reply can go back to them alone.\n if (opts.client !== undefined) {\n this.rememberCaller(id, payload, opts.client);\n }\n\n this.fanOut(id, \"inbound\", payload);\n return true;\n }\n\n /** Push a frame onto the outbound queue (browser server → external agents). */\n outbox(id: string, token: string, payload: string): boolean {\n if (!this.validate(id, token)) return false;\n if (!this.isFrame(payload)) return false;\n\n // A RESPONSE goes to the caller. A NOTIFICATION goes to everyone.\n //\n // `relay-protocol.md` has always said \"tool-call replies go back on the\n // transport that originated the call\"; the relay broadcast them instead.\n // Combined with a bearer token that carries no per-agent identity, that\n // meant a second token holder passively received the results of everyone\n // else's calls -- turning a share link from \"you may act here\" into \"you\n // may watch everyone acting here\", which nobody chose.\n //\n // Notifications stay broadcast: presence, activity and server-pushed state\n // answer nobody and are meant for every attached client. Narrowing those\n // would break the collaboration this exists to serve.\n const target = this.callerFor(id, payload);\n\n if (target === null) {\n this.fanOut(id, \"outbound\", payload);\n return true;\n }\n\n this.fanOutTo(id, \"outbound\", payload, target);\n return true;\n }\n\n /**\n * Subscribe to a session's queue for one direction. Returns an iterable\n * the caller (an HTTP handler) pumps as SSE.\n */\n subscribe(id: string, token: string, direction: Direction, opts: { client?: string } = {}): SubscribeResult {\n if (!this.validate(id, token)) return { ok: false, reason: \"invalid_token\" };\n const subscriberId = randomBytes(8).toString(\"hex\");\n const subscriber: Subscriber = {\n id: subscriberId,\n direction,\n queue: [],\n resolveNext: null,\n client: opts.client,\n };\n this.getDirSubs(id, direction).set(subscriberId, subscriber);\n\n // Notify the inbound side (= browser) that an outbound subscriber\n // (= external agent) just connected.\n if (direction === \"outbound\") {\n this.fanOut(\n id,\n \"inbound\",\n JSON.stringify({\n jsonrpc: \"2.0\",\n method: \"notifications/peer_joined\",\n params: { subscriberId, ts: Date.now() },\n }),\n );\n }\n\n const unsubscribe = () => {\n this.getDirSubs(id, direction).delete(subscriberId);\n if (direction === \"outbound\") {\n this.fanOut(\n id,\n \"inbound\",\n JSON.stringify({\n jsonrpc: \"2.0\",\n method: \"notifications/peer_left\",\n params: { subscriberId, ts: Date.now() },\n }),\n );\n }\n };\n\n /** Async generator the HTTP handler drains. Yields raw frame payloads;\n * the handler is responsible for SSE framing (`event: mcp\\ndata: …`). */\n const frames = async function* (this: Subscriber): AsyncGenerator<string, void, void> {\n while (true) {\n if (this.queue.length > 0) {\n const next = this.queue.shift();\n if (next !== undefined) yield next;\n continue;\n }\n const next = await new Promise<string | null>((resolve) => {\n this.resolveNext = resolve;\n });\n this.resolveNext = null;\n if (next === null) return;\n yield next;\n }\n }.bind(subscriber);\n\n return {\n ok: true,\n subscriberId,\n frames: frames(),\n unsubscribe: () => {\n // Wake the generator and let it return cleanly.\n subscriber.resolveNext?.(null);\n unsubscribe();\n },\n };\n }\n\n // ────────────────────────────────────────────────────────────── internals\n\n private getDirSubs(sessionId: string, direction: Direction): Map<string, Subscriber> {\n let bySession = this.subs.get(sessionId);\n if (!bySession) {\n bySession = new Map();\n this.subs.set(sessionId, bySession);\n }\n let byDir = bySession.get(direction);\n if (!byDir) {\n byDir = new Map();\n bySession.set(direction, byDir);\n }\n return byDir;\n }\n\n /**\n * Record which client asked, keyed by JSON-RPC id.\n *\n * Only for REQUESTS — a frame with both an `id` and a `method`. A\n * notification answers nobody and a response is not a question.\n */\n private rememberCaller(sessionId: string, payload: string, client: string): void {\n const frame = this.parseFrame(payload);\n if (!frame || frame.id === undefined || frame.id === null || typeof frame.method !== \"string\") {\n return;\n }\n\n let byId = this.callers.get(sessionId);\n if (!byId) {\n byId = new Map();\n this.callers.set(sessionId, byId);\n }\n\n // BOUNDED. A session that asks for hours must not grow this without limit,\n // and an unanswered request would otherwise sit here forever. Oldest out\n // first; losing the oldest correlation degrades to \"delivered to nobody\",\n // which fails closed rather than open.\n if (byId.size >= 1000) {\n const oldest = byId.keys().next();\n if (!oldest.done) byId.delete(oldest.value);\n }\n\n byId.set(String(frame.id), client);\n }\n\n /**\n * The client a RESPONSE belongs to, or `null` when the frame is a broadcast.\n *\n * Returns the empty string for a response whose id nobody is recorded as\n * having asked — routed to NOBODY rather than to everyone. Broadcasting an\n * uncorrelated reply \"just in case\" is precisely the leak being closed.\n */\n private callerFor(sessionId: string, payload: string): string | null {\n const frame = this.parseFrame(payload);\n\n // Not a response: no id, or it carries a method (a request/notification).\n if (!frame || frame.id === undefined || frame.id === null || typeof frame.method === \"string\") {\n return null;\n }\n\n // LEGACY MODE is decided by whether any subscriber IDENTIFIED ITSELF, not\n // by whether a correlation happens to have been recorded yet.\n //\n // Keying on the correlation map was wrong in a way a test caught: a\n // labelled client that has subscribed but not yet asked leaves the map\n // empty, and an unsolicited response would then broadcast to everyone --\n // the leak reopening in the window before the first call.\n //\n // If nobody labelled themselves, every client is legacy and broadcast is\n // the only thing that can work; narrowing would break them in silence.\n if (!this.anyIdentifiedSubscriber(sessionId)) {\n return null;\n }\n\n const byId = this.callers.get(sessionId);\n const key = String(frame.id);\n const client = byId?.get(key);\n\n // CONSUMED. Correlation is not a standing subscription: leaving it would\n // let a replayed frame with the same id be delivered again, and would make\n // the map a slow leak on a long session.\n byId?.delete(key);\n\n return client ?? \"\";\n }\n\n /**\n * Has any subscriber on this session told the broker who it is?\n *\n * The discriminator between a scoped session and a legacy one. Checked across\n * BOTH directions: the page subscribes inbound and rarely labels itself, so\n * asking only about the outbound side would misread a scoped session whose\n * agents have not yet attached.\n */\n private anyIdentifiedSubscriber(sessionId: string): boolean {\n const dirs = this.subs.get(sessionId);\n if (!dirs) return false;\n\n for (const dir of dirs.values()) {\n for (const sub of dir.values()) {\n if (sub.client !== undefined) return true;\n }\n }\n\n return false;\n }\n\n private parseFrame(payload: string): { id?: unknown; method?: unknown } | null {\n try {\n const parsed: unknown = JSON.parse(payload);\n return parsed && typeof parsed === \"object\" ? (parsed as { id?: unknown; method?: unknown }) : null;\n } catch {\n return null;\n }\n }\n\n /** Deliver to the subscribers of one client only. */\n private fanOutTo(sessionId: string, direction: Direction, payload: string, client: string) {\n const dir = this.subs.get(sessionId)?.get(direction);\n if (!dir) return;\n\n for (const sub of dir.values()) {\n if (sub.client !== client) continue;\n sub.queue.push(payload);\n sub.resolveNext?.(sub.queue.shift() ?? null);\n }\n }\n\n private fanOut(sessionId: string, direction: Direction, payload: string) {\n const dir = this.subs.get(sessionId)?.get(direction);\n if (!dir) return;\n for (const sub of dir.values()) {\n sub.queue.push(payload);\n sub.resolveNext?.(sub.queue.shift() ?? null);\n }\n }\n\n /**\n * Validate that a peer-supplied payload is a well-formed JSON-RPC 2.0 frame\n * (or batch) before it is fanned out. Previously this was a substring match on\n * `\"jsonrpc\"`, which let any token holder inject spoofed frames — a forged\n * `notifications/peer_joined` / `peer_left` (broker-reserved presence control),\n * a fake `notifications/agent_activity {source:\"user\"}` (\"human took control\"),\n * or a forged response with a matching id. We now parse + shape-check, and\n * reject the broker-reserved control methods (the broker emits those itself,\n * never a peer).\n */\n private isFrame(payload: string): boolean {\n if (payload.length === 0) return false;\n let parsed: unknown;\n try {\n parsed = JSON.parse(payload);\n } catch {\n return false;\n }\n const frames = Array.isArray(parsed) ? parsed : [parsed];\n return frames.length > 0 && frames.every((f) => this.isValidFrame(f));\n }\n\n private isValidFrame(f: unknown): boolean {\n if (!f || typeof f !== \"object\" || Array.isArray(f)) return false;\n const o = f as Record<string, unknown>;\n if (o.jsonrpc !== \"2.0\") return false;\n const method = typeof o.method === \"string\" ? o.method : undefined;\n // Broker-reserved control frames may never arrive from a peer.\n if (method === \"notifications/peer_joined\" || method === \"notifications/peer_left\") return false;\n if (method !== undefined) return true; // request or notification\n // Response: needs an id and exactly one of result / error.\n const hasResult = \"result\" in o;\n const hasError = \"error\" in o;\n return \"id\" in o && hasResult !== hasError;\n }\n\n private reap() {\n const cutoff = Date.now() - this.ttlMs;\n for (const id of this.store.expiredSessionIds(cutoff)) {\n const dirs = this.subs.get(id);\n if (dirs) {\n for (const dir of dirs.values()) {\n for (const sub of dir.values()) sub.resolveNext?.(null);\n }\n }\n this.subs.delete(id);\n this.callers.delete(id);\n this.store.deleteSession(id);\n }\n }\n}\n\nexport type SubscribeResult =\n | { ok: false; reason: string }\n | {\n ok: true;\n subscriberId: string;\n frames: AsyncGenerator<string, void, void>;\n unsubscribe: () => void;\n };\n\nfunction sha256Hex(input: string): string {\n return createHash(\"sha256\").update(input).digest(\"hex\");\n}\n\nfunction timingSafeEqualHex(a: string, b: string): boolean {\n if (a.length !== b.length) return false;\n return timingSafeEqual(Buffer.from(a, \"hex\"), Buffer.from(b, \"hex\"));\n}\n","import type { IncomingMessage, ServerResponse } from \"node:http\";\nimport { URL } from \"node:url\";\nimport { RelayBroker, type RelayBrokerOptions } from \"./core\";\n\n/**\n * Node HTTP adapter for {@link RelayBroker}. Returns a single request\n * handler plus per-route handlers, so you can either drop it into\n * `http.createServer(...)` directly or mount the individual handlers\n * onto your existing Node HTTP framework (Express, Hono w/ node-adapter,\n * native http).\n *\n * const relay = createNodeRelay({ pathPrefix: \"/mcp-relay\" });\n * http.createServer(relay.handler).listen(8787);\n *\n * // Or piecemeal:\n * app.post(\"/mcp-relay/register\", relay.register);\n * app.post(\"/mcp-relay/:s/inbox\", relay.inbox);\n * app.post(\"/mcp-relay/:s/outbox\", relay.outbox);\n * app.get (\"/mcp-relay/:s/events\", relay.events);\n * app.post(\"/mcp-relay/:s/unregister\", relay.unregister);\n */\n\nexport type NodeRelayOptions = RelayBrokerOptions & {\n /** URL path prefix (without trailing slash). Default `\"\"` — handlers\n * expect paths like `/register`, `/{id}/inbox`, etc. directly. */\n pathPrefix?: string;\n /** Comma-separated origins (or `*`) for CORS. Default `*` — relays\n * are typically called cross-origin from the demo host. */\n corsAllowOrigin?: string;\n /**\n * Strict browser-origin allow-list. When set, only these Origins get a\n * matching `Access-Control-Allow-Origin` (the request's own Origin is\n * reflected, never `*`), which blunts DNS-rebinding + hostile cross-origin\n * pages from reading relay responses. Recommended for any browser-facing\n * deployment. When unset, `corsAllowOrigin` (default `*`) is used and the\n * session token is the only auth — pair that with a loopback bind.\n */\n allowedOrigins?: string[];\n};\n\nexport type NodeHandler = (req: IncomingMessage, res: ServerResponse) => unknown | Promise<unknown>;\n\nexport type NodeRelay = {\n broker: RelayBroker;\n /** Single-handler shape — routes internally based on method + URL. */\n handler: NodeHandler;\n /** Per-route handlers. Each handler ignores the URL prefix and\n * acts on the path remainder, so you can mount them under any\n * prefix in your existing app. */\n register: NodeHandler;\n inbox: NodeHandler;\n outbox: NodeHandler;\n events: NodeHandler;\n unregister: NodeHandler;\n};\n\nexport function createNodeRelay(opts: NodeRelayOptions = {}): NodeRelay {\n const broker = new RelayBroker(opts);\n const prefix = (opts.pathPrefix ?? \"\").replace(/\\/$/, \"\");\n const cors = opts.corsAllowOrigin ?? \"*\";\n\n const allowedOrigins = opts.allowedOrigins;\n\n function setCorsHeaders(res: ServerResponse, req?: IncomingMessage) {\n if (allowedOrigins && allowedOrigins.length) {\n // Strict mode: reflect the request Origin only when it's allow-listed;\n // otherwise emit an origin that no browser will match.\n const origin = req?.headers.origin;\n res.setHeader(\"access-control-allow-origin\", origin && allowedOrigins.includes(origin) ? origin : \"null\");\n res.setHeader(\"vary\", \"origin\");\n } else {\n res.setHeader(\"access-control-allow-origin\", cors);\n }\n res.setHeader(\"access-control-allow-methods\", \"GET, POST, OPTIONS\");\n // `authorization` is forward-compat for a header-borne session token.\n res.setHeader(\"access-control-allow-headers\", \"content-type, x-csrf-token, accept, authorization\");\n res.setHeader(\"access-control-max-age\", \"86400\");\n }\n\n function readBody(req: IncomingMessage): Promise<string> {\n return new Promise((resolve, reject) => {\n const chunks: Buffer[] = [];\n let bytes = 0;\n req.on(\"data\", (chunk: Buffer) => {\n bytes += chunk.length;\n // Cap individual frames at 256 KB — protect against runaway payloads.\n if (bytes > 256 * 1024) {\n reject(new Error(\"payload_too_large\"));\n req.destroy();\n return;\n }\n chunks.push(chunk);\n });\n req.on(\"end\", () => resolve(Buffer.concat(chunks).toString(\"utf8\")));\n req.on(\"error\", reject);\n });\n }\n\n function json(res: ServerResponse, status: number, body: unknown): void {\n res.statusCode = status;\n res.setHeader(\"content-type\", \"application/json\");\n res.end(JSON.stringify(body));\n }\n\n function getQuery(req: IncomingMessage): URLSearchParams {\n const host = req.headers.host || \"x\";\n const u = new URL(req.url || \"/\", `http://${host}`);\n return u.searchParams;\n }\n\n function getPathname(req: IncomingMessage): string {\n const host = req.headers.host || \"x\";\n const u = new URL(req.url || \"/\", `http://${host}`);\n return u.pathname;\n }\n\n const register: NodeHandler = async (req, res) => {\n setCorsHeaders(res, req);\n if (req.method === \"OPTIONS\") { res.statusCode = 204; return res.end(); }\n if (req.method !== \"POST\") return json(res, 405, { error: \"method_not_allowed\" });\n let body: string;\n try { body = await readBody(req); } catch (e) {\n return json(res, 413, { error: e instanceof Error ? e.message : \"payload_error\" });\n }\n let parsed: unknown;\n try { parsed = JSON.parse(body); } catch { return json(res, 400, { error: \"invalid_json\" }); }\n const { session, token } = (parsed ?? {}) as { session?: string; token?: string };\n if (typeof session !== \"string\" || typeof token !== \"string\") {\n return json(res, 400, { error: \"missing_fields\" });\n }\n const result = broker.register(session, token);\n if (!result.ok) return json(res, 401, { error: result.reason });\n return json(res, 200, { ok: true });\n };\n\n /** Handler for endpoints with a `{session}` segment. The path matcher\n * caller passes the session id explicitly so this works mounted under\n * any route shape. */\n function makeSessionHandler(\n direction: Direction | \"unregister\",\n ): NodeHandler {\n return async (req, res) => {\n setCorsHeaders(res, req);\n if (req.method === \"OPTIONS\") { res.statusCode = 204; return res.end(); }\n if (req.method !== \"POST\") return json(res, 405, { error: \"method_not_allowed\" });\n const session = extractSession(req, prefix);\n if (!session) return json(res, 400, { error: \"missing_session\" });\n const token = getQuery(req).get(\"token\") ?? \"\";\n\n if (direction === \"unregister\") {\n // Unregistering a session that is already gone is a SUCCESS, not an\n // auth failure. The caller wanted it gone and it is gone; reporting\n // `invalid_token` for a correct token would make a clean shutdown look\n // like a broken one, and a client retrying it would loop.\n const state = broker.check(session, token);\n if (!state.ok && state.reason === \"session_gone\") {\n return json(res, 200, { ok: true, alreadyGone: true });\n }\n\n const ok = broker.unregister(session, token);\n return json(res, ok ? 200 : 401, ok ? { ok: true } : { error: \"invalid_token\" });\n }\n\n let body: string;\n try { body = await readBody(req); } catch (e) {\n return json(res, 413, { error: e instanceof Error ? e.message : \"payload_error\" });\n }\n // A GONE SESSION IS REPORTED AS ITSELF, with 410, before the frame is\n // even considered.\n //\n // Every failure here used to come back as `401 invalid_token_or_frame`,\n // so an agent whose page had simply closed was told its credentials or\n // its JSON were wrong. A relay session ending is the NORMAL end of a\n // lifecycle -- the browser is the server and nothing persists -- so it is\n // the one outcome a server-side client must be able to recognise.\n //\n // 410 Gone rather than 404: the session existed and is now over, which is\n // exactly what the status means, and it distinguishes \"this is finished\"\n // from \"you have the wrong URL\".\n const auth = broker.check(session, token);\n if (!auth.ok && auth.reason === \"session_gone\") {\n return json(res, 410, { error: \"session_gone\" });\n }\n\n // `client` identifies WHICH agent is calling, so its reply can be routed\n // back to it alone. Optional: a client that sends none gets the legacy\n // broadcast, which is the only thing that can work for it.\n const client = getQuery(req).get(\"client\") ?? undefined;\n\n const ok = direction === \"inbound\"\n ? broker.inbox(session, token, body, { client })\n : broker.outbox(session, token, body);\n return json(res, ok ? 200 : 401, ok ? { ok: true } : { error: \"invalid_token_or_frame\" });\n };\n }\n\n const inbox = makeSessionHandler(\"inbound\");\n const outbox = makeSessionHandler(\"outbound\");\n const unregister = makeSessionHandler(\"unregister\");\n\n const events: NodeHandler = async (req, res) => {\n setCorsHeaders(res, req);\n if (req.method === \"OPTIONS\") { res.statusCode = 204; return res.end(); }\n if (req.method !== \"GET\") return json(res, 405, { error: \"method_not_allowed\" });\n const session = extractSession(req, prefix);\n if (!session) return json(res, 400, { error: \"missing_session\" });\n const q = getQuery(req);\n const token = q.get(\"token\") ?? \"\";\n const direction = q.get(\"direction\") === \"outbound\" ? \"outbound\" : \"inbound\";\n\n // The SAME `client` the agent posts under, so a reply can find its way\n // back. An agent that subscribes with a label and posts without one (or\n // vice versa) simply does not correlate and its replies go nowhere -- which\n // fails closed, and is the right way round for a leak fix.\n const sub = broker.subscribe(session, token, direction, {\n client: getQuery(req).get(\"client\") ?? undefined,\n });\n if (!sub.ok) {\n res.statusCode = 401;\n res.setHeader(\"content-type\", \"text/event-stream\");\n res.write(`event: error\\ndata: ${sub.reason}\\n\\n`);\n return res.end();\n }\n\n res.statusCode = 200;\n res.setHeader(\"content-type\", \"text/event-stream\");\n res.setHeader(\"cache-control\", \"no-cache\");\n res.setHeader(\"connection\", \"keep-alive\");\n res.setHeader(\"x-accel-buffering\", \"no\");\n res.write(\"retry: 2000\\n\\n\");\n flush(res);\n\n let heartbeat: ReturnType<typeof setInterval> | null = setInterval(() => {\n res.write(\": keepalive\\n\\n\");\n flush(res);\n }, 15_000);\n if (heartbeat && typeof (heartbeat as { unref?: () => void }).unref === \"function\") {\n (heartbeat as { unref: () => void }).unref();\n }\n\n const cleanup = () => {\n if (heartbeat) { clearInterval(heartbeat); heartbeat = null; }\n sub.unsubscribe();\n };\n req.on(\"close\", cleanup);\n req.on(\"error\", cleanup);\n\n try {\n for await (const frame of sub.frames) {\n res.write(`event: mcp\\ndata: ${frame}\\n\\n`);\n flush(res);\n }\n } catch {\n /* stream ended */\n } finally {\n cleanup();\n res.end();\n }\n };\n\n /**\n * Single handler — routes based on method + path. Useful for mounting\n * via `http.createServer(relay.handler)` without an Express layer.\n */\n const handler: NodeHandler = async (req, res) => {\n const pathname = getPathname(req);\n if (!pathname.startsWith(prefix + \"/\")) {\n return json(res, 404, { error: \"not_found\" });\n }\n const rest = pathname.slice(prefix.length); // \"/register\", \"/<id>/inbox\", etc.\n if (rest === \"/register\") return register(req, res);\n const m = /^\\/([A-Za-z0-9_-]{4,64})\\/(inbox|outbox|events|unregister)$/.exec(rest);\n if (!m) return json(res, 404, { error: \"not_found\" });\n const route = m[2];\n if (route === \"inbox\") return inbox(req, res);\n if (route === \"outbox\") return outbox(req, res);\n if (route === \"events\") return events(req, res);\n if (route === \"unregister\") return unregister(req, res);\n return json(res, 404, { error: \"not_found\" });\n };\n\n return { broker, handler, register, inbox, outbox, events, unregister };\n}\n\nfunction extractSession(req: IncomingMessage, prefix: string): string | null {\n const host = req.headers.host || \"x\";\n const u = new URL(req.url || \"/\", `http://${host}`);\n const path = u.pathname;\n if (prefix && !path.startsWith(prefix + \"/\")) return null;\n const rest = prefix ? path.slice(prefix.length) : path;\n const m = /^\\/([A-Za-z0-9_-]{4,64})\\//.exec(rest);\n return m ? m[1] : null;\n}\n\nfunction flush(res: ServerResponse) {\n // Node doesn't expose explicit flush, but write returns false when buffered;\n // explicit flushHeaders + write is enough for SSE in practice.\n const r = res as { flush?: () => void };\n r.flush?.();\n}\n\ntype Direction = \"inbound\" | \"outbound\";\n"]}
|
package/dist/relay-server.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { S as ServerInfo,
|
|
2
|
-
import { a as ToolRegistry } from './tool-host-
|
|
1
|
+
import { S as ServerInfo, c as ServerCapabilities, a as JsonRpcMessage, C as CallToolResult } from './types-C2DtnHIn.cjs';
|
|
2
|
+
import { a as ToolRegistry } from './tool-host-LVBgCN5m.cjs';
|
|
3
3
|
|
|
4
4
|
type McpServerOptions = {
|
|
5
5
|
info: ServerInfo;
|
|
@@ -7,6 +7,18 @@ type McpServerOptions = {
|
|
|
7
7
|
capabilities?: ServerCapabilities;
|
|
8
8
|
/** Free-text instructions surfaced to clients during initialize. */
|
|
9
9
|
instructions?: string;
|
|
10
|
+
/**
|
|
11
|
+
* The protocol revisions this server speaks, NEWEST FIRST.
|
|
12
|
+
*
|
|
13
|
+
* `initialize` echoes the client's requested revision when it is in this
|
|
14
|
+
* list, and answers the first entry otherwise — the spec's rule, which leaves
|
|
15
|
+
* the client to decide whether it can live with the answer.
|
|
16
|
+
*
|
|
17
|
+
* Defaults to `[MCP_PROTOCOL_VERSION]`: one revision, answered whatever the
|
|
18
|
+
* client asks, which is exactly what this server did before the option
|
|
19
|
+
* existed. Only list a revision the tools you register are correct under.
|
|
20
|
+
*/
|
|
21
|
+
protocolVersions?: readonly string[];
|
|
10
22
|
};
|
|
11
23
|
type Transport = {
|
|
12
24
|
/** Called by the server when it has a message to deliver to the client. */
|
|
@@ -30,10 +42,15 @@ type Transport = {
|
|
|
30
42
|
*/
|
|
31
43
|
declare class MicroMcpServer extends ToolRegistry {
|
|
32
44
|
private transports;
|
|
33
|
-
|
|
45
|
+
/**
|
|
46
|
+
* Transports owed a `tools/list_changed` at the end of this tick. Empty when
|
|
47
|
+
* none is scheduled. See {@link scheduleListChangedNotification}.
|
|
48
|
+
*/
|
|
49
|
+
private listChangedOwed;
|
|
34
50
|
readonly info: ServerInfo;
|
|
35
51
|
readonly capabilities: ServerCapabilities;
|
|
36
52
|
readonly instructions?: string;
|
|
53
|
+
readonly protocolVersions: readonly string[];
|
|
37
54
|
constructor(options: McpServerOptions);
|
|
38
55
|
attach(transport: Transport): () => void;
|
|
39
56
|
detach(transport: Transport): void;
|
|
@@ -45,6 +62,18 @@ declare class MicroMcpServer extends ToolRegistry {
|
|
|
45
62
|
*/
|
|
46
63
|
receive(transport: Transport, message: JsonRpcMessage): Promise<void>;
|
|
47
64
|
private handle;
|
|
65
|
+
/** The revision to answer `initialize` with: the one asked for if spoken, else the newest. */
|
|
66
|
+
private negotiate;
|
|
67
|
+
/**
|
|
68
|
+
* Tell the transports that SAW the old tool list that it changed.
|
|
69
|
+
*
|
|
70
|
+
* Changes in one tick coalesce into one notification. The recipients are the
|
|
71
|
+
* transports attached at the moment of a change, not at the moment the
|
|
72
|
+
* notification goes out: a transport attached afterwards never had the old
|
|
73
|
+
* list, so "your list is stale" is noise to it — and on stdio, where a host
|
|
74
|
+
* builds the server and attaches stdin/stdout in the same tick, it was the
|
|
75
|
+
* first frame a client received, before it had even sent `initialize`.
|
|
76
|
+
*/
|
|
48
77
|
private scheduleListChangedNotification;
|
|
49
78
|
/** Send an application notification to every client, or one attached transport. */
|
|
50
79
|
notify(message: JsonRpcMessage, transport?: Transport): void;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { S as ServerInfo,
|
|
2
|
-
import { a as ToolRegistry } from './tool-host-
|
|
1
|
+
import { S as ServerInfo, c as ServerCapabilities, a as JsonRpcMessage, C as CallToolResult } from './types-C2DtnHIn.js';
|
|
2
|
+
import { a as ToolRegistry } from './tool-host-Wo0pkY83.js';
|
|
3
3
|
|
|
4
4
|
type McpServerOptions = {
|
|
5
5
|
info: ServerInfo;
|
|
@@ -7,6 +7,18 @@ type McpServerOptions = {
|
|
|
7
7
|
capabilities?: ServerCapabilities;
|
|
8
8
|
/** Free-text instructions surfaced to clients during initialize. */
|
|
9
9
|
instructions?: string;
|
|
10
|
+
/**
|
|
11
|
+
* The protocol revisions this server speaks, NEWEST FIRST.
|
|
12
|
+
*
|
|
13
|
+
* `initialize` echoes the client's requested revision when it is in this
|
|
14
|
+
* list, and answers the first entry otherwise — the spec's rule, which leaves
|
|
15
|
+
* the client to decide whether it can live with the answer.
|
|
16
|
+
*
|
|
17
|
+
* Defaults to `[MCP_PROTOCOL_VERSION]`: one revision, answered whatever the
|
|
18
|
+
* client asks, which is exactly what this server did before the option
|
|
19
|
+
* existed. Only list a revision the tools you register are correct under.
|
|
20
|
+
*/
|
|
21
|
+
protocolVersions?: readonly string[];
|
|
10
22
|
};
|
|
11
23
|
type Transport = {
|
|
12
24
|
/** Called by the server when it has a message to deliver to the client. */
|
|
@@ -30,10 +42,15 @@ type Transport = {
|
|
|
30
42
|
*/
|
|
31
43
|
declare class MicroMcpServer extends ToolRegistry {
|
|
32
44
|
private transports;
|
|
33
|
-
|
|
45
|
+
/**
|
|
46
|
+
* Transports owed a `tools/list_changed` at the end of this tick. Empty when
|
|
47
|
+
* none is scheduled. See {@link scheduleListChangedNotification}.
|
|
48
|
+
*/
|
|
49
|
+
private listChangedOwed;
|
|
34
50
|
readonly info: ServerInfo;
|
|
35
51
|
readonly capabilities: ServerCapabilities;
|
|
36
52
|
readonly instructions?: string;
|
|
53
|
+
readonly protocolVersions: readonly string[];
|
|
37
54
|
constructor(options: McpServerOptions);
|
|
38
55
|
attach(transport: Transport): () => void;
|
|
39
56
|
detach(transport: Transport): void;
|
|
@@ -45,6 +62,18 @@ declare class MicroMcpServer extends ToolRegistry {
|
|
|
45
62
|
*/
|
|
46
63
|
receive(transport: Transport, message: JsonRpcMessage): Promise<void>;
|
|
47
64
|
private handle;
|
|
65
|
+
/** The revision to answer `initialize` with: the one asked for if spoken, else the newest. */
|
|
66
|
+
private negotiate;
|
|
67
|
+
/**
|
|
68
|
+
* Tell the transports that SAW the old tool list that it changed.
|
|
69
|
+
*
|
|
70
|
+
* Changes in one tick coalesce into one notification. The recipients are the
|
|
71
|
+
* transports attached at the moment of a change, not at the moment the
|
|
72
|
+
* notification goes out: a transport attached afterwards never had the old
|
|
73
|
+
* list, so "your list is stale" is noise to it — and on stdio, where a host
|
|
74
|
+
* builds the server and attaches stdin/stdout in the same tick, it was the
|
|
75
|
+
* first frame a client received, before it had even sent `initialize`.
|
|
76
|
+
*/
|
|
48
77
|
private scheduleListChangedNotification;
|
|
49
78
|
/** Send an application notification to every client, or one attached transport. */
|
|
50
79
|
notify(message: JsonRpcMessage, transport?: Transport): void;
|
package/dist/sharing/index.d.cts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
export { S as SessionDescriptor, b as buildShareConfig, a as buildShareUrl, e as constantTimeEqual, c as createSessionDescriptor, d as describeSession, r as readSessionFromUrl } from '../token-BZ8doMam.cjs';
|
|
2
|
-
import {
|
|
3
|
-
import { T as Transport, M as MicroMcpServer } from '../server-
|
|
2
|
+
import { a as JsonRpcMessage } from '../types-C2DtnHIn.cjs';
|
|
3
|
+
import { T as Transport, M as MicroMcpServer } from '../server-BIcA3ZtK.cjs';
|
|
4
4
|
import { AutoActivityEvent } from '@particle-academy/fancy-auto-common';
|
|
5
|
-
import '../tool-host-
|
|
5
|
+
import '../tool-host-LVBgCN5m.cjs';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* SseRelayTransport — bridges the in-page MicroMcpServer to a host-app
|
package/dist/sharing/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
export { S as SessionDescriptor, b as buildShareConfig, a as buildShareUrl, e as constantTimeEqual, c as createSessionDescriptor, d as describeSession, r as readSessionFromUrl } from '../token-BZ8doMam.js';
|
|
2
|
-
import {
|
|
3
|
-
import { T as Transport, M as MicroMcpServer } from '../server-
|
|
2
|
+
import { a as JsonRpcMessage } from '../types-C2DtnHIn.js';
|
|
3
|
+
import { T as Transport, M as MicroMcpServer } from '../server-DnUyeavY.js';
|
|
4
4
|
import { AutoActivityEvent } from '@particle-academy/fancy-auto-common';
|
|
5
|
-
import '../tool-host-
|
|
5
|
+
import '../tool-host-Wo0pkY83.js';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* SseRelayTransport — bridges the in-page MicroMcpServer to a host-app
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { SheetsBridgeAdapter } from './bridges/sheets.cjs';
|
|
2
|
-
import './tool-host-
|
|
3
|
-
import './types-
|
|
4
|
-
import './types-
|
|
2
|
+
import './tool-host-LVBgCN5m.cjs';
|
|
3
|
+
import './types-C2DtnHIn.cjs';
|
|
4
|
+
import './types-EcElKOlk.cjs';
|
|
5
5
|
import '@particle-academy/fancy-sheets';
|
|
6
6
|
|
|
7
7
|
/**
|
package/dist/sheets-adapter.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { SheetsBridgeAdapter } from './bridges/sheets.js';
|
|
2
|
-
import './tool-host-
|
|
3
|
-
import './types-
|
|
4
|
-
import './types-
|
|
2
|
+
import './tool-host-Wo0pkY83.js';
|
|
3
|
+
import './types-C2DtnHIn.js';
|
|
4
|
+
import './types-BxNRKSVd.js';
|
|
5
5
|
import '@particle-academy/fancy-sheets';
|
|
6
6
|
|
|
7
7
|
/**
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { T as ToolDefinition,
|
|
1
|
+
import { T as ToolDefinition, b as ToolHandler, R as RegisteredTool, J as JsonObject, C as CallToolResult } from './types-C2DtnHIn.cjs';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* ToolHost — the minimal surface a bridge needs to register its tools.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { T as ToolDefinition,
|
|
1
|
+
import { T as ToolDefinition, b as ToolHandler, R as RegisteredTool, J as JsonObject, C as CallToolResult } from './types-C2DtnHIn.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* ToolHost — the minimal surface a bridge needs to register its tools.
|
|
@@ -69,16 +69,40 @@ type InitializeResult = {
|
|
|
69
69
|
instructions?: string;
|
|
70
70
|
};
|
|
71
71
|
type ToolInputSchema = {
|
|
72
|
+
/** The JSON Schema dialect, when a server states it (e.g. draft-07). */
|
|
73
|
+
$schema?: string;
|
|
72
74
|
type: "object";
|
|
73
75
|
properties?: Record<string, JsonValue>;
|
|
74
76
|
required?: string[];
|
|
75
77
|
additionalProperties?: boolean;
|
|
76
78
|
};
|
|
79
|
+
/** Behaviour hints a client may use when presenting or gating a tool. */
|
|
80
|
+
type ToolAnnotations = {
|
|
81
|
+
title?: string;
|
|
82
|
+
readOnlyHint?: boolean;
|
|
83
|
+
destructiveHint?: boolean;
|
|
84
|
+
idempotentHint?: boolean;
|
|
85
|
+
openWorldHint?: boolean;
|
|
86
|
+
};
|
|
87
|
+
/**
|
|
88
|
+
* A tool as `tools/list` reports it. Every field is passed to the client
|
|
89
|
+
* verbatim, so the optional ones below are the spec's, not extensions.
|
|
90
|
+
*/
|
|
77
91
|
type ToolDefinition = {
|
|
78
92
|
name: string;
|
|
79
93
|
title?: string;
|
|
80
94
|
description?: string;
|
|
81
95
|
inputSchema: ToolInputSchema;
|
|
96
|
+
/** JSON Schema for `structuredContent`, when the tool returns it. */
|
|
97
|
+
outputSchema?: ToolInputSchema;
|
|
98
|
+
annotations?: ToolAnnotations;
|
|
99
|
+
/** 2025-11-25: whether the tool may run as a task. */
|
|
100
|
+
execution?: {
|
|
101
|
+
taskSupport?: "forbidden" | "optional" | "required";
|
|
102
|
+
};
|
|
103
|
+
_meta?: {
|
|
104
|
+
[key: string]: JsonValue;
|
|
105
|
+
};
|
|
82
106
|
};
|
|
83
107
|
type ContentBlock = {
|
|
84
108
|
type: "text";
|
|
@@ -113,4 +137,4 @@ type RegisteredTool = {
|
|
|
113
137
|
};
|
|
114
138
|
declare const MCP_PROTOCOL_VERSION = "2025-06-18";
|
|
115
139
|
|
|
116
|
-
export { type CallToolResult as C, type InitializeResult as I, type JsonObject as J, MCP_PROTOCOL_VERSION as M, type RegisteredTool as R, type ServerInfo as S, type ToolDefinition as T, type
|
|
140
|
+
export { type CallToolResult as C, type InitializeResult as I, type JsonObject as J, MCP_PROTOCOL_VERSION as M, type RegisteredTool as R, type ServerInfo as S, type ToolDefinition as T, type JsonRpcMessage as a, type ToolHandler as b, type ServerCapabilities as c, type ContentBlock as d, type JsonRpcNotification as e, type JsonRpcRequest as f, type JsonValue as g, type ToolCallContext as h, JSONRPC_INTERNAL_ERROR as i, JSONRPC_INVALID_PARAMS as j, JSONRPC_INVALID_REQUEST as k, JSONRPC_METHOD_NOT_FOUND as l, JSONRPC_PARSE_ERROR as m, type JsonRpcError as n, type JsonRpcId as o, type JsonRpcSuccess as p, type ToolAnnotations as q, type ToolInputSchema as r };
|
|
@@ -69,16 +69,40 @@ type InitializeResult = {
|
|
|
69
69
|
instructions?: string;
|
|
70
70
|
};
|
|
71
71
|
type ToolInputSchema = {
|
|
72
|
+
/** The JSON Schema dialect, when a server states it (e.g. draft-07). */
|
|
73
|
+
$schema?: string;
|
|
72
74
|
type: "object";
|
|
73
75
|
properties?: Record<string, JsonValue>;
|
|
74
76
|
required?: string[];
|
|
75
77
|
additionalProperties?: boolean;
|
|
76
78
|
};
|
|
79
|
+
/** Behaviour hints a client may use when presenting or gating a tool. */
|
|
80
|
+
type ToolAnnotations = {
|
|
81
|
+
title?: string;
|
|
82
|
+
readOnlyHint?: boolean;
|
|
83
|
+
destructiveHint?: boolean;
|
|
84
|
+
idempotentHint?: boolean;
|
|
85
|
+
openWorldHint?: boolean;
|
|
86
|
+
};
|
|
87
|
+
/**
|
|
88
|
+
* A tool as `tools/list` reports it. Every field is passed to the client
|
|
89
|
+
* verbatim, so the optional ones below are the spec's, not extensions.
|
|
90
|
+
*/
|
|
77
91
|
type ToolDefinition = {
|
|
78
92
|
name: string;
|
|
79
93
|
title?: string;
|
|
80
94
|
description?: string;
|
|
81
95
|
inputSchema: ToolInputSchema;
|
|
96
|
+
/** JSON Schema for `structuredContent`, when the tool returns it. */
|
|
97
|
+
outputSchema?: ToolInputSchema;
|
|
98
|
+
annotations?: ToolAnnotations;
|
|
99
|
+
/** 2025-11-25: whether the tool may run as a task. */
|
|
100
|
+
execution?: {
|
|
101
|
+
taskSupport?: "forbidden" | "optional" | "required";
|
|
102
|
+
};
|
|
103
|
+
_meta?: {
|
|
104
|
+
[key: string]: JsonValue;
|
|
105
|
+
};
|
|
82
106
|
};
|
|
83
107
|
type ContentBlock = {
|
|
84
108
|
type: "text";
|
|
@@ -113,4 +137,4 @@ type RegisteredTool = {
|
|
|
113
137
|
};
|
|
114
138
|
declare const MCP_PROTOCOL_VERSION = "2025-06-18";
|
|
115
139
|
|
|
116
|
-
export { type CallToolResult as C, type InitializeResult as I, type JsonObject as J, MCP_PROTOCOL_VERSION as M, type RegisteredTool as R, type ServerInfo as S, type ToolDefinition as T, type
|
|
140
|
+
export { type CallToolResult as C, type InitializeResult as I, type JsonObject as J, MCP_PROTOCOL_VERSION as M, type RegisteredTool as R, type ServerInfo as S, type ToolDefinition as T, type JsonRpcMessage as a, type ToolHandler as b, type ServerCapabilities as c, type ContentBlock as d, type JsonRpcNotification as e, type JsonRpcRequest as f, type JsonValue as g, type ToolCallContext as h, JSONRPC_INTERNAL_ERROR as i, JSONRPC_INVALID_PARAMS as j, JSONRPC_INVALID_REQUEST as k, JSONRPC_METHOD_NOT_FOUND as l, JSONRPC_PARSE_ERROR as m, type JsonRpcError as n, type JsonRpcId as o, type JsonRpcSuccess as p, type ToolAnnotations as q, type ToolInputSchema as r };
|
package/dist/undo/index.d.cts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as _particle_academy_fancy_auto_common from '@particle-academy/fancy-auto-common';
|
|
2
2
|
export { UndoEntry, clearStack, pushUndoEntry, readHistory, redoOne, resetAllUndoStacks, undoOne } from '@particle-academy/fancy-auto-common';
|
|
3
|
-
import { T as ToolHost } from '../tool-host-
|
|
4
|
-
import '../types-
|
|
3
|
+
import { T as ToolHost } from '../tool-host-LVBgCN5m.cjs';
|
|
4
|
+
import '../types-C2DtnHIn.cjs';
|
|
5
5
|
|
|
6
6
|
type UndoToolsOptions = {
|
|
7
7
|
/** Default agent id when the caller doesn't pass one. */
|
package/dist/undo/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as _particle_academy_fancy_auto_common from '@particle-academy/fancy-auto-common';
|
|
2
2
|
export { UndoEntry, clearStack, pushUndoEntry, readHistory, redoOne, resetAllUndoStacks, undoOne } from '@particle-academy/fancy-auto-common';
|
|
3
|
-
import { T as ToolHost } from '../tool-host-
|
|
4
|
-
import '../types-
|
|
3
|
+
import { T as ToolHost } from '../tool-host-Wo0pkY83.js';
|
|
4
|
+
import '../types-C2DtnHIn.js';
|
|
5
5
|
|
|
6
6
|
type UndoToolsOptions = {
|
|
7
7
|
/** Default agent id when the caller doesn't pass one. */
|