@rudderhq/server 0.5.2-canary.2 → 0.6.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/dist/bootstrap/register-api-routes.d.ts.map +1 -1
- package/dist/bootstrap/register-api-routes.js +15 -0
- package/dist/bootstrap/register-api-routes.js.map +1 -1
- package/dist/bootstrap/types.d.ts +11 -0
- package/dist/bootstrap/types.d.ts.map +1 -1
- package/dist/bundled-plugins/plugin-linear/dist/worker.js +741 -7
- package/dist/bundled-plugins/plugin-linear/dist/worker.js.map +3 -3
- package/dist/config.d.ts +2 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +3 -0
- package/dist/config.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +28 -1
- package/dist/index.js.map +1 -1
- package/dist/local-runtime.d.ts +7 -0
- package/dist/local-runtime.d.ts.map +1 -1
- package/dist/local-runtime.js +15 -1
- package/dist/local-runtime.js.map +1 -1
- package/dist/middleware/auth.js +2 -2
- package/dist/middleware/auth.js.map +1 -1
- package/dist/middleware/error-handler.d.ts.map +1 -1
- package/dist/middleware/error-handler.js +3 -2
- package/dist/middleware/error-handler.js.map +1 -1
- package/dist/middleware/logger.d.ts +4 -0
- package/dist/middleware/logger.d.ts.map +1 -1
- package/dist/middleware/logger.js +82 -7
- package/dist/middleware/logger.js.map +1 -1
- package/dist/middleware/logger.test.js +94 -1
- package/dist/middleware/logger.test.js.map +1 -1
- package/dist/routes/chats.annotation-routes.d.ts +47 -0
- package/dist/routes/chats.annotation-routes.d.ts.map +1 -0
- package/dist/routes/chats.annotation-routes.js +164 -0
- package/dist/routes/chats.annotation-routes.js.map +1 -0
- package/dist/routes/chats.d.ts.map +1 -1
- package/dist/routes/chats.js +467 -165
- package/dist/routes/chats.js.map +1 -1
- package/dist/routes/chats.stream-routes.d.ts +1 -10
- package/dist/routes/chats.stream-routes.d.ts.map +1 -1
- package/dist/routes/chats.stream-routes.js +168 -110
- package/dist/routes/chats.stream-routes.js.map +1 -1
- package/dist/routes/chats.stream-support.d.ts +79 -0
- package/dist/routes/chats.stream-support.d.ts.map +1 -0
- package/dist/routes/chats.stream-support.js +121 -0
- package/dist/routes/chats.stream-support.js.map +1 -0
- package/dist/routes/issues.comments-attachments.d.ts.map +1 -1
- package/dist/routes/issues.comments-attachments.js +16 -2
- package/dist/routes/issues.comments-attachments.js.map +1 -1
- package/dist/routes/issues.d.ts.map +1 -1
- package/dist/routes/issues.js +21 -4
- package/dist/routes/issues.js.map +1 -1
- package/dist/routes/issues.mutations.d.ts.map +1 -1
- package/dist/routes/issues.mutations.js +20 -33
- package/dist/routes/issues.mutations.js.map +1 -1
- package/dist/routes/managed-mcp-agent-bindings.d.ts +15 -0
- package/dist/routes/managed-mcp-agent-bindings.d.ts.map +1 -0
- package/dist/routes/managed-mcp-agent-bindings.js +66 -0
- package/dist/routes/managed-mcp-agent-bindings.js.map +1 -0
- package/dist/routes/managed-mcp-connections.d.ts +8 -0
- package/dist/routes/managed-mcp-connections.d.ts.map +1 -0
- package/dist/routes/managed-mcp-connections.js +189 -0
- package/dist/routes/managed-mcp-connections.js.map +1 -0
- package/dist/routes/managed-mcp-runtime.d.ts +5 -0
- package/dist/routes/managed-mcp-runtime.d.ts.map +1 -0
- package/dist/routes/managed-mcp-runtime.js +148 -0
- package/dist/routes/managed-mcp-runtime.js.map +1 -0
- package/dist/routes/messenger.d.ts.map +1 -1
- package/dist/routes/messenger.js +1 -1
- package/dist/routes/messenger.js.map +1 -1
- package/dist/services/access.d.ts.map +1 -1
- package/dist/services/access.js +91 -12
- package/dist/services/access.js.map +1 -1
- package/dist/services/agent-run-context.d.ts +1 -0
- package/dist/services/agent-run-context.d.ts.map +1 -1
- package/dist/services/agent-run-context.js +5 -1
- package/dist/services/agent-run-context.js.map +1 -1
- package/dist/services/board-auth.d.ts +2 -2
- package/dist/services/chat-annotation-copy-lineage.d.ts +32 -0
- package/dist/services/chat-annotation-copy-lineage.d.ts.map +1 -0
- package/dist/services/chat-annotation-copy-lineage.js +110 -0
- package/dist/services/chat-annotation-copy-lineage.js.map +1 -0
- package/dist/services/chat-assistant.annotations.d.ts +16 -0
- package/dist/services/chat-assistant.annotations.d.ts.map +1 -0
- package/dist/services/chat-assistant.annotations.js +108 -0
- package/dist/services/chat-assistant.annotations.js.map +1 -0
- package/dist/services/chat-assistant.annotations.test.d.ts +2 -0
- package/dist/services/chat-assistant.annotations.test.d.ts.map +1 -0
- package/dist/services/chat-assistant.annotations.test.js +257 -0
- package/dist/services/chat-assistant.annotations.test.js.map +1 -0
- package/dist/services/chat-assistant.d.ts.map +1 -1
- package/dist/services/chat-assistant.helpers.d.ts +2 -3
- package/dist/services/chat-assistant.helpers.d.ts.map +1 -1
- package/dist/services/chat-assistant.helpers.js +37 -53
- package/dist/services/chat-assistant.helpers.js.map +1 -1
- package/dist/services/chat-assistant.js +61 -5
- package/dist/services/chat-assistant.js.map +1 -1
- package/dist/services/chat-generation-protocol.d.ts +8 -15
- package/dist/services/chat-generation-protocol.d.ts.map +1 -1
- package/dist/services/chat-generation-protocol.js +19 -59
- package/dist/services/chat-generation-protocol.js.map +1 -1
- package/dist/services/chat-generation-protocol.test.js +168 -6
- package/dist/services/chat-generation-protocol.test.js.map +1 -1
- package/dist/services/chat-generation-provenance.d.ts +14 -0
- package/dist/services/chat-generation-provenance.d.ts.map +1 -0
- package/dist/services/chat-generation-provenance.js +71 -0
- package/dist/services/chat-generation-provenance.js.map +1 -0
- package/dist/services/chat-inline-annotation-rendering.d.ts +2 -0
- package/dist/services/chat-inline-annotation-rendering.d.ts.map +1 -0
- package/dist/services/chat-inline-annotation-rendering.js +265 -0
- package/dist/services/chat-inline-annotation-rendering.js.map +1 -0
- package/dist/services/chat-inline-annotation-resolved-labels.d.ts +11 -0
- package/dist/services/chat-inline-annotation-resolved-labels.d.ts.map +1 -0
- package/dist/services/chat-inline-annotation-resolved-labels.js +490 -0
- package/dist/services/chat-inline-annotation-resolved-labels.js.map +1 -0
- package/dist/services/chat-inline-annotation-validation.d.ts +15 -0
- package/dist/services/chat-inline-annotation-validation.d.ts.map +1 -0
- package/dist/services/chat-inline-annotation-validation.js +430 -0
- package/dist/services/chat-inline-annotation-validation.js.map +1 -0
- package/dist/services/chat-inline-annotations.d.ts +18 -0
- package/dist/services/chat-inline-annotations.d.ts.map +1 -0
- package/dist/services/chat-inline-annotations.js +52 -0
- package/dist/services/chat-inline-annotations.js.map +1 -0
- package/dist/services/chat-inline-annotations.test.d.ts +2 -0
- package/dist/services/chat-inline-annotations.test.d.ts.map +1 -0
- package/dist/services/chat-inline-annotations.test.js +1306 -0
- package/dist/services/chat-inline-annotations.test.js.map +1 -0
- package/dist/services/chat-queued-message-materialization.d.ts +126 -0
- package/dist/services/chat-queued-message-materialization.d.ts.map +1 -0
- package/dist/services/chat-queued-message-materialization.js +327 -0
- package/dist/services/chat-queued-message-materialization.js.map +1 -0
- package/dist/services/chat-steer-messages.d.ts +3 -3
- package/dist/services/chat-steer-messages.d.ts.map +1 -1
- package/dist/services/chat-steer-messages.js +50 -80
- package/dist/services/chat-steer-messages.js.map +1 -1
- package/dist/services/chat-work-manifest.d.ts.map +1 -1
- package/dist/services/chat-work-manifest.js +5 -1
- package/dist/services/chat-work-manifest.js.map +1 -1
- package/dist/services/chats.annotation-persistence.d.ts +20 -0
- package/dist/services/chats.annotation-persistence.d.ts.map +1 -0
- package/dist/services/chats.annotation-persistence.js +206 -0
- package/dist/services/chats.annotation-persistence.js.map +1 -0
- package/dist/services/chats.d.ts +129 -96
- package/dist/services/chats.d.ts.map +1 -1
- package/dist/services/chats.helpers.d.ts +2 -2
- package/dist/services/chats.inline-visual-persistence.d.ts +3 -3
- package/dist/services/chats.inline-visual-persistence.d.ts.map +1 -1
- package/dist/services/chats.inline-visual-persistence.js +114 -54
- package/dist/services/chats.inline-visual-persistence.js.map +1 -1
- package/dist/services/chats.js +743 -252
- package/dist/services/chats.js.map +1 -1
- package/dist/services/finance.d.ts +1 -1
- package/dist/services/index.d.ts +8 -0
- package/dist/services/index.d.ts.map +1 -1
- package/dist/services/index.js +8 -0
- package/dist/services/index.js.map +1 -1
- package/dist/services/integrations/agent-integrations.d.ts +2 -2
- package/dist/services/integrations/custom-integrations.d.ts +3 -1
- package/dist/services/integrations/custom-integrations.d.ts.map +1 -1
- package/dist/services/integrations/custom-integrations.js +13 -2
- package/dist/services/integrations/custom-integrations.js.map +1 -1
- package/dist/services/issues.comments-attachments.d.ts +7 -1
- package/dist/services/issues.comments-attachments.d.ts.map +1 -1
- package/dist/services/issues.comments-attachments.js +13 -1
- package/dist/services/issues.comments-attachments.js.map +1 -1
- package/dist/services/issues.d.ts +6 -0
- package/dist/services/issues.d.ts.map +1 -1
- package/dist/services/issues.js +22 -3
- package/dist/services/issues.js.map +1 -1
- package/dist/services/knowledge-portability/organization-portability.core.d.ts +4 -1
- package/dist/services/knowledge-portability/organization-portability.core.d.ts.map +1 -1
- package/dist/services/knowledge-portability/organization-portability.core.js +17 -3
- package/dist/services/knowledge-portability/organization-portability.core.js.map +1 -1
- package/dist/services/knowledge-portability/organization-portability.export.d.ts.map +1 -1
- package/dist/services/knowledge-portability/organization-portability.export.js +2 -2
- package/dist/services/knowledge-portability/organization-portability.export.js.map +1 -1
- package/dist/services/knowledge-portability/organization-portability.import.d.ts.map +1 -1
- package/dist/services/knowledge-portability/organization-portability.import.js +13 -3
- package/dist/services/knowledge-portability/organization-portability.import.js.map +1 -1
- package/dist/services/knowledge-portability/organization-skills.catalog.d.ts +3 -0
- package/dist/services/knowledge-portability/organization-skills.catalog.d.ts.map +1 -1
- package/dist/services/knowledge-portability/organization-skills.catalog.js +54 -23
- package/dist/services/knowledge-portability/organization-skills.catalog.js.map +1 -1
- package/dist/services/knowledge-portability/organization-skills.d.ts.map +1 -1
- package/dist/services/knowledge-portability/organization-skills.js +627 -124
- package/dist/services/knowledge-portability/organization-skills.js.map +1 -1
- package/dist/services/knowledge-portability/organization-skills.sources.d.ts +1 -0
- package/dist/services/knowledge-portability/organization-skills.sources.d.ts.map +1 -1
- package/dist/services/knowledge-portability/organization-skills.sources.js +53 -10
- package/dist/services/knowledge-portability/organization-skills.sources.js.map +1 -1
- package/dist/services/mcp/authorizer-lock.d.ts +9 -0
- package/dist/services/mcp/authorizer-lock.d.ts.map +1 -0
- package/dist/services/mcp/authorizer-lock.js +15 -0
- package/dist/services/mcp/authorizer-lock.js.map +1 -0
- package/dist/services/mcp/managed-bindings.d.ts +17 -0
- package/dist/services/mcp/managed-bindings.d.ts.map +1 -0
- package/dist/services/mcp/managed-bindings.js +332 -0
- package/dist/services/mcp/managed-bindings.js.map +1 -0
- package/dist/services/mcp/managed-client.d.ts +64 -0
- package/dist/services/mcp/managed-client.d.ts.map +1 -0
- package/dist/services/mcp/managed-client.js +238 -0
- package/dist/services/mcp/managed-client.js.map +1 -0
- package/dist/services/mcp/managed-client.test.d.ts +2 -0
- package/dist/services/mcp/managed-client.test.d.ts.map +1 -0
- package/dist/services/mcp/managed-client.test.js +398 -0
- package/dist/services/mcp/managed-client.test.js.map +1 -0
- package/dist/services/mcp/managed-connections.d.ts +81 -0
- package/dist/services/mcp/managed-connections.d.ts.map +1 -0
- package/dist/services/mcp/managed-connections.js +920 -0
- package/dist/services/mcp/managed-connections.js.map +1 -0
- package/dist/services/mcp/managed-runtime.d.ts +134 -0
- package/dist/services/mcp/managed-runtime.d.ts.map +1 -0
- package/dist/services/mcp/managed-runtime.js +282 -0
- package/dist/services/mcp/managed-runtime.js.map +1 -0
- package/dist/services/mcp/oauth-provider.d.ts +48 -0
- package/dist/services/mcp/oauth-provider.d.ts.map +1 -0
- package/dist/services/mcp/oauth-provider.js +120 -0
- package/dist/services/mcp/oauth-provider.js.map +1 -0
- package/dist/services/mcp/oauth-scope.test.d.ts +2 -0
- package/dist/services/mcp/oauth-scope.test.d.ts.map +1 -0
- package/dist/services/mcp/oauth-scope.test.js +69 -0
- package/dist/services/mcp/oauth-scope.test.js.map +1 -0
- package/dist/services/mcp/oauth-session-gc.d.ts +14 -0
- package/dist/services/mcp/oauth-session-gc.d.ts.map +1 -0
- package/dist/services/mcp/oauth-session-gc.js +34 -0
- package/dist/services/mcp/oauth-session-gc.js.map +1 -0
- package/dist/services/mcp/oauth-session-gc.test.d.ts +2 -0
- package/dist/services/mcp/oauth-session-gc.test.d.ts.map +1 -0
- package/dist/services/mcp/oauth-session-gc.test.js +66 -0
- package/dist/services/mcp/oauth-session-gc.test.js.map +1 -0
- package/dist/services/mcp/oauth.d.ts +61 -0
- package/dist/services/mcp/oauth.d.ts.map +1 -0
- package/dist/services/mcp/oauth.js +1690 -0
- package/dist/services/mcp/oauth.js.map +1 -0
- package/dist/services/mcp/pinned-fetch.d.ts +15 -0
- package/dist/services/mcp/pinned-fetch.d.ts.map +1 -0
- package/dist/services/mcp/pinned-fetch.js +400 -0
- package/dist/services/mcp/pinned-fetch.js.map +1 -0
- package/dist/services/mcp/pinned-fetch.test.d.ts +2 -0
- package/dist/services/mcp/pinned-fetch.test.d.ts.map +1 -0
- package/dist/services/mcp/pinned-fetch.test.js +190 -0
- package/dist/services/mcp/pinned-fetch.test.js.map +1 -0
- package/dist/services/mcp/provider-registry.d.ts +77 -0
- package/dist/services/mcp/provider-registry.d.ts.map +1 -0
- package/dist/services/mcp/provider-registry.js +80 -0
- package/dist/services/mcp/provider-registry.js.map +1 -0
- package/dist/services/mcp/provider-registry.test.d.ts +2 -0
- package/dist/services/mcp/provider-registry.test.d.ts.map +1 -0
- package/dist/services/mcp/provider-registry.test.js +80 -0
- package/dist/services/mcp/provider-registry.test.js.map +1 -0
- package/dist/services/mcp/security-policy.d.ts +48 -0
- package/dist/services/mcp/security-policy.d.ts.map +1 -0
- package/dist/services/mcp/security-policy.js +344 -0
- package/dist/services/mcp/security-policy.js.map +1 -0
- package/dist/services/mcp/security-policy.test.d.ts +2 -0
- package/dist/services/mcp/security-policy.test.d.ts.map +1 -0
- package/dist/services/mcp/security-policy.test.js +226 -0
- package/dist/services/mcp/security-policy.test.js.map +1 -0
- package/dist/services/mcp/tool-discovery.d.ts +49 -0
- package/dist/services/mcp/tool-discovery.d.ts.map +1 -0
- package/dist/services/mcp/tool-discovery.js +198 -0
- package/dist/services/mcp/tool-discovery.js.map +1 -0
- package/dist/services/mcp/tool-discovery.test.d.ts +2 -0
- package/dist/services/mcp/tool-discovery.test.d.ts.map +1 -0
- package/dist/services/mcp/tool-discovery.test.js +168 -0
- package/dist/services/mcp/tool-discovery.test.js.map +1 -0
- package/dist/services/messenger.d.ts +1 -1
- package/dist/services/messenger.d.ts.map +1 -1
- package/dist/services/messenger.js +21 -3
- package/dist/services/messenger.js.map +1 -1
- package/dist/services/plugin-registry.d.ts +3 -3
- package/dist/services/runtime-kernel/heartbeat.core.d.ts +1 -1
- package/dist/services/runtime-kernel/heartbeat.core.d.ts.map +1 -1
- package/dist/services/runtime-kernel/heartbeat.core.js +30 -4
- package/dist/services/runtime-kernel/heartbeat.core.js.map +1 -1
- package/dist/services/runtime-kernel/heartbeat.wakeup.d.ts.map +1 -1
- package/dist/services/runtime-kernel/heartbeat.wakeup.js +38 -23
- package/dist/services/runtime-kernel/heartbeat.wakeup.js.map +1 -1
- package/dist/services/secrets.d.ts +64 -6
- package/dist/services/secrets.d.ts.map +1 -1
- package/dist/services/secrets.js +38 -15
- package/dist/services/secrets.js.map +1 -1
- package/dist/services/side-chats.d.ts +1 -1
- package/dist/services/side-chats.d.ts.map +1 -1
- package/dist/services/side-chats.js +56 -14
- package/dist/services/side-chats.js.map +1 -1
- package/dist/services/workspace-runtime.services.d.ts +2 -2
- package/dist/services/workspace-web-preview.js +1 -1
- package/package.json +16 -13
- package/resources/bundled-skills/rudder-docs/references/operating-practices.md +12 -5
- package/skills/rudder-docs/references/operating-practices.md +12 -5
- package/ui-dist/assets/LibraryLiveSurface-CKOthw54.js +1 -0
- package/ui-dist/assets/{abnfDiagram-VRR7QNED-KGtP7zoC.js → abnfDiagram-VRR7QNED-C6a_wMho.js} +1 -1
- package/ui-dist/assets/{arc-JjnKyiOb.js → arc-CP0En6KA.js} +1 -1
- package/ui-dist/assets/architectureDiagram-ZJ3FMSHR-AHfOdcaZ.js +36 -0
- package/ui-dist/assets/{blockDiagram-677ZJIJ3-D7YzMYrz.js → blockDiagram-677ZJIJ3-Bkl9lp63.js} +1 -1
- package/ui-dist/assets/{c4Diagram-LMCZKHZV-Dpf7UQxl.js → c4Diagram-LMCZKHZV-BpZareVt.js} +1 -1
- package/ui-dist/assets/channel-DqxL_Zcy.js +1 -0
- package/ui-dist/assets/{chunk-2Q5K7J3B-UJ3gsGlQ.js → chunk-2Q5K7J3B-BQAwVuXc.js} +1 -1
- package/ui-dist/assets/{chunk-32BRIVSS-BeHl2j2l.js → chunk-32BRIVSS-YkmfA08F.js} +1 -1
- package/ui-dist/assets/{chunk-5VM5RSS4-STE9fJd0.js → chunk-5VM5RSS4-DvvjwTnG.js} +1 -1
- package/ui-dist/assets/{chunk-EX3LRPZG-Bj8g8j4B.js → chunk-EX3LRPZG-TXD_Yhg5.js} +1 -1
- package/ui-dist/assets/{chunk-JWPE2WC7-0V4Pwta-.js → chunk-JWPE2WC7-CgMlj6XI.js} +1 -1
- package/ui-dist/assets/{chunk-MOJQB5TN-DNPn50gm.js → chunk-MOJQB5TN-BnJjU8Rc.js} +1 -1
- package/ui-dist/assets/{chunk-RYQCIY6F-Befmnv8r.js → chunk-RYQCIY6F-D9B64JKM.js} +1 -1
- package/ui-dist/assets/{chunk-V7JOEXUC-Boh8TjHj.js → chunk-V7JOEXUC-PS09QVpl.js} +1 -1
- package/ui-dist/assets/{chunk-VR4S4FIN-B_yEQSo3.js → chunk-VR4S4FIN-DQXb7pRS.js} +1 -1
- package/ui-dist/assets/{chunk-XXDRQBXY-Cf1GnUFx.js → chunk-XXDRQBXY-B1UdLiF2.js} +1 -1
- package/ui-dist/assets/classDiagram-OUVF2IWQ-DMwjzuJE.js +1 -0
- package/ui-dist/assets/classDiagram-v2-EOCWNBFH-DMwjzuJE.js +1 -0
- package/ui-dist/assets/cose-bilkent-JH36ORCC-lqqmMB3m.js +1 -0
- package/ui-dist/assets/{cynefin-VYW2F7L2-Dv1yELYC.js → cynefin-VYW2F7L2-C9hu0XqZ.js} +1 -1
- package/ui-dist/assets/{cynefinDiagram-TSTJHNR4-CeFwjFoZ.js → cynefinDiagram-TSTJHNR4-Uuhz4c-1.js} +1 -1
- package/ui-dist/assets/{dagre-VKFMJZFB-8idd_4sX.js → dagre-VKFMJZFB-ChDrQYse.js} +1 -1
- package/ui-dist/assets/{diagram-FQU43EPY-BBVua6hM.js → diagram-FQU43EPY-DLtjkVSN.js} +1 -1
- package/ui-dist/assets/{diagram-G47NLZAW-D1zLQZlp.js → diagram-G47NLZAW-DCvEm4D0.js} +1 -1
- package/ui-dist/assets/{diagram-NH7WQ7WH-DE_FTSNv.js → diagram-NH7WQ7WH-Dz5jlsPG.js} +1 -1
- package/ui-dist/assets/{diagram-OA4YK3LP-61VSKBEn.js → diagram-OA4YK3LP-BXmQLO-Q.js} +1 -1
- package/ui-dist/assets/{diagram-WEI45ONY-C-tED6BJ.js → diagram-WEI45ONY-JnMU3xrx.js} +1 -1
- package/ui-dist/assets/{ebnfDiagram-CCIWWBDH-BEB8WGt0.js → ebnfDiagram-CCIWWBDH-Kryuqj4r.js} +1 -1
- package/ui-dist/assets/{erDiagram-Q63AITRT-AN_jm1TZ.js → erDiagram-Q63AITRT-Bn7g2mSW.js} +1 -1
- package/ui-dist/assets/{flowDiagram-23GEKE2U-BwLC6tI7.js → flowDiagram-23GEKE2U-DcjqTK91.js} +4 -4
- package/ui-dist/assets/ganttDiagram-NO4QXBWP-BRkw9-GE.js +292 -0
- package/ui-dist/assets/{gitGraphDiagram-IHSO6WYX-D9HCL9rY.js → gitGraphDiagram-IHSO6WYX-Cexcp6kR.js} +1 -1
- package/ui-dist/assets/graph-Cu7OV4Oi.js +1 -0
- package/ui-dist/assets/{index-BQXnpwke.js → index-ASZMPBYm.js} +5 -5
- package/ui-dist/assets/{index-5OM32_rf.js → index-B17BqCTj.js} +1 -1
- package/ui-dist/assets/{index-Cf0gLy6a.js → index-B9MccU1g.js} +1 -1
- package/ui-dist/assets/{index-BoSJ4Rx1.js → index-BPqbtW_X.js} +1 -1
- package/ui-dist/assets/{index-CpIdZ4-7.js → index-C2HjDa98.js} +1 -1
- package/ui-dist/assets/index-CMPtpj0A.js +1 -0
- package/ui-dist/assets/{index-p0ZGU1_7.js → index-CZXgOYtk.js} +1 -1
- package/ui-dist/assets/{index-74cx3ESJ.js → index-CknAauOP.js} +1 -1
- package/ui-dist/assets/index-Cu1GuH0a.js +1 -0
- package/ui-dist/assets/index-D8PdEImm.css +1 -0
- package/ui-dist/assets/{index-DrVDiJhe.js → index-DB1YX9-p.js} +1 -1
- package/ui-dist/assets/{index-vHMnAQSb.js → index-DBxLZXK7.js} +624 -610
- package/ui-dist/assets/{index-CpEfk5zb.js → index-DOCVOD97.js} +1 -1
- package/ui-dist/assets/{index-DMuWG0YN.js → index-DUbakRAC.js} +1 -1
- package/ui-dist/assets/{index-AT8juaIi.js → index-Dbg1ZwO2.js} +1 -1
- package/ui-dist/assets/index-DwbLsoLt.js +1 -0
- package/ui-dist/assets/index-hCLSotmS.js +1 -0
- package/ui-dist/assets/index-jrhEFc-j.js +1 -0
- package/ui-dist/assets/index-kz8ueXgo.js +1 -0
- package/ui-dist/assets/{infoDiagram-FWYZ7A6U-CyO3CAA1.js → infoDiagram-FWYZ7A6U-DugVGI3K.js} +1 -1
- package/ui-dist/assets/{ishikawaDiagram-FXEZZL3T-BLLZuF1_.js → ishikawaDiagram-FXEZZL3T-CHy06Oev.js} +1 -1
- package/ui-dist/assets/{journeyDiagram-5HDEW3XC-CWzQocvE.js → journeyDiagram-5HDEW3XC-BI0w53rb.js} +1 -1
- package/ui-dist/assets/{kanban-definition-HUTT4EX6-Dz4SFU-I.js → kanban-definition-HUTT4EX6-v_bLwx7B.js} +1 -1
- package/ui-dist/assets/layout-Dwp1s_bo.js +1 -0
- package/ui-dist/assets/{linear-BlzDlAaL.js → linear-DAV4STLZ.js} +1 -1
- package/ui-dist/assets/map-Bs6QpaaQ.js +1 -0
- package/ui-dist/assets/{mermaid.core-BtCydd-w.js → mermaid.core-fVmaL47V.js} +4 -4
- package/ui-dist/assets/{mindmap-definition-LN4V7U3C-BeIkKRBx.js → mindmap-definition-LN4V7U3C-5dWD4dxm.js} +1 -1
- package/ui-dist/assets/{pegDiagram-2B236MQR-BZgpT4TN.js → pegDiagram-2B236MQR-DB2XsDPN.js} +1 -1
- package/ui-dist/assets/{pieDiagram-ENE6RG2P-BRFggcg2.js → pieDiagram-ENE6RG2P-Bc5teLCS.js} +1 -1
- package/ui-dist/assets/{quadrantDiagram-ABIIQ3AL-CibUo3gT.js → quadrantDiagram-ABIIQ3AL-BlfNdETt.js} +1 -1
- package/ui-dist/assets/{railroadDiagram-RFXS5EU6-DINJqhgn.js → railroadDiagram-RFXS5EU6-BbXywkq3.js} +1 -1
- package/ui-dist/assets/{requirementDiagram-TGXJPOKE-NegluQIe.js → requirementDiagram-TGXJPOKE-DU-CapdF.js} +1 -1
- package/ui-dist/assets/{sankeyDiagram-HTMAVEWB-Kq41yHAd.js → sankeyDiagram-HTMAVEWB-Ftvh3MqA.js} +1 -1
- package/ui-dist/assets/{sequenceDiagram-DBY2YBRQ-CngfEI4f.js → sequenceDiagram-DBY2YBRQ-CCtHt9V4.js} +1 -1
- package/ui-dist/assets/{sizeCapture-X5ZJPWSS-DUWRNlme.js → sizeCapture-X5ZJPWSS-x0jnIKHx.js} +1 -1
- package/ui-dist/assets/{stateDiagram-2N3HPSRC-BwHC_Fz4.js → stateDiagram-2N3HPSRC-2qCrydE7.js} +1 -1
- package/ui-dist/assets/stateDiagram-v2-6OUMAXLB-CvGRUgRf.js +1 -0
- package/ui-dist/assets/{swimlanes-5IMT3BWC-Cqp2rT1K.js → swimlanes-5IMT3BWC-6kqJq5Xf.js} +2 -2
- package/ui-dist/assets/swimlanesDiagram-G3AALYLV-EBa7-qSc.js +8 -0
- package/ui-dist/assets/{timeline-definition-FHXFAJF6-BG3GYPCu.js → timeline-definition-FHXFAJF6-BuRz8KHZ.js} +1 -1
- package/ui-dist/assets/{vennDiagram-L72KCM5P-D1IFU27N.js → vennDiagram-L72KCM5P-BKzMZ_Rv.js} +1 -1
- package/ui-dist/assets/{wardleyDiagram-EHGQE667-DboO2kYu.js → wardleyDiagram-EHGQE667-8uXlFtBV.js} +1 -1
- package/ui-dist/assets/{xychartDiagram-FW5EYKEG-vI2BGrXP.js → xychartDiagram-FW5EYKEG-CWKGlpF9.js} +1 -1
- package/ui-dist/index.html +2 -2
- package/ui-dist/assets/architectureDiagram-ZJ3FMSHR-DHyfFgK0.js +0 -36
- package/ui-dist/assets/channel-TMGI9Qt9.js +0 -1
- package/ui-dist/assets/classDiagram-OUVF2IWQ-r5zIpY6G.js +0 -1
- package/ui-dist/assets/classDiagram-v2-EOCWNBFH-r5zIpY6G.js +0 -1
- package/ui-dist/assets/cose-bilkent-JH36ORCC-fSNs9447.js +0 -1
- package/ui-dist/assets/ganttDiagram-NO4QXBWP-CJYhBF1C.js +0 -292
- package/ui-dist/assets/graph-DdBT9W3J.js +0 -1
- package/ui-dist/assets/index-6UIO-gg7.js +0 -1
- package/ui-dist/assets/index-BVkQVMFn.js +0 -1
- package/ui-dist/assets/index-BaAPxkqh.css +0 -1
- package/ui-dist/assets/index-CmCERTmS.js +0 -1
- package/ui-dist/assets/index-Cr4lUIaJ.js +0 -1
- package/ui-dist/assets/index-D0fAqlES.js +0 -1
- package/ui-dist/assets/index-DfNcAyZq.js +0 -1
- package/ui-dist/assets/layout-D3tY9q4Q.js +0 -1
- package/ui-dist/assets/map-Ctg1-a9N.js +0 -1
- package/ui-dist/assets/stateDiagram-v2-6OUMAXLB-C6P3NY96.js +0 -1
- package/ui-dist/assets/swimlanesDiagram-G3AALYLV-BNdDt62J.js +0 -8
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
import { Client, SdkError, SdkErrorCode, SdkHttpError, StreamableHTTPClientTransport, UnauthorizedError, } from "@modelcontextprotocol/client";
|
|
2
|
+
import { DEFAULT_INHERITED_ENV_VARS, StdioClientTransport, } from "@modelcontextprotocol/client/stdio";
|
|
3
|
+
import { createSecureMcpFetch } from "./pinned-fetch.js";
|
|
4
|
+
import { assertSafeMcpCredentialHeaders, assertSafeMcpHeaders, validateMcpStdioPolicy, } from "./security-policy.js";
|
|
5
|
+
export class ManagedMcpClientError extends Error {
|
|
6
|
+
code;
|
|
7
|
+
constructor(code, message) {
|
|
8
|
+
super(message);
|
|
9
|
+
this.name = "ManagedMcpClientError";
|
|
10
|
+
this.code = code;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export function resolveMcpHttpCredentials(input) {
|
|
14
|
+
assertSafeMcpCredentialHeaders(input.secretHeaders ?? {});
|
|
15
|
+
const encryptedAuthorization = Object.entries(input.secretHeaders ?? {})
|
|
16
|
+
.find(([name]) => name.toLowerCase() === "authorization");
|
|
17
|
+
const authorizationSources = [
|
|
18
|
+
Boolean(input.bearerToken),
|
|
19
|
+
Boolean(input.authorizationHeader),
|
|
20
|
+
Boolean(encryptedAuthorization),
|
|
21
|
+
Boolean(input.oauth),
|
|
22
|
+
].filter(Boolean).length;
|
|
23
|
+
if (authorizationSources > 1) {
|
|
24
|
+
throw new ManagedMcpClientError("mcp_conflicting_authorization", "Configure exactly one managed MCP Authorization source");
|
|
25
|
+
}
|
|
26
|
+
const headers = { ...(input.secretHeaders ?? {}) };
|
|
27
|
+
if (input.bearerToken)
|
|
28
|
+
headers.Authorization = `Bearer ${input.bearerToken}`;
|
|
29
|
+
if (input.authorizationHeader)
|
|
30
|
+
headers.Authorization = input.authorizationHeader;
|
|
31
|
+
return {
|
|
32
|
+
headers,
|
|
33
|
+
authProvider: input.oauth
|
|
34
|
+
? {
|
|
35
|
+
token: () => input.oauth.token(),
|
|
36
|
+
onUnauthorized: async () => input.oauth.refresh(),
|
|
37
|
+
}
|
|
38
|
+
: undefined,
|
|
39
|
+
onUnauthorizedFailure: input.oauth?.markNeedsReauth
|
|
40
|
+
? () => input.oauth.markNeedsReauth()
|
|
41
|
+
: undefined,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
function isStdioOutputBoundaryError(error) {
|
|
45
|
+
return error instanceof Error && /ReadBuffer exceeded maximum size/u.test(error.message);
|
|
46
|
+
}
|
|
47
|
+
function safeClientError(error, action) {
|
|
48
|
+
if (error instanceof ManagedMcpClientError)
|
|
49
|
+
return error;
|
|
50
|
+
if (error instanceof UnauthorizedError || (error instanceof SdkHttpError && error.status === 401)) {
|
|
51
|
+
return new ManagedMcpClientError("mcp_upstream_unauthorized", "Managed MCP authorization was rejected");
|
|
52
|
+
}
|
|
53
|
+
if (error instanceof SdkHttpError && error.status === 429) {
|
|
54
|
+
return new ManagedMcpClientError("mcp_upstream_rate_limited", "Managed MCP upstream rate limit was reached");
|
|
55
|
+
}
|
|
56
|
+
if (error instanceof SdkError && error.code === SdkErrorCode.RequestTimeout) {
|
|
57
|
+
return new ManagedMcpClientError(action === "call" ? "mcp_tool_timeout" : "mcp_startup_timeout", action === "call"
|
|
58
|
+
? "Managed MCP tool call timed out"
|
|
59
|
+
: "Managed MCP connection timed out");
|
|
60
|
+
}
|
|
61
|
+
return new ManagedMcpClientError(action === "call" ? "mcp_tool_failed" : "mcp_transport_failed", action === "call"
|
|
62
|
+
? "Managed MCP tool call failed"
|
|
63
|
+
: "Managed MCP transport failed");
|
|
64
|
+
}
|
|
65
|
+
function boundedResult(result, maxOutputBytes) {
|
|
66
|
+
let bytes;
|
|
67
|
+
try {
|
|
68
|
+
bytes = Buffer.byteLength(JSON.stringify(result), "utf8");
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
throw new ManagedMcpClientError("mcp_result_invalid", "Managed MCP tool result is not JSON serializable");
|
|
72
|
+
}
|
|
73
|
+
if (bytes > maxOutputBytes) {
|
|
74
|
+
throw new ManagedMcpClientError("mcp_result_too_large", "Managed MCP tool result exceeds the output limit");
|
|
75
|
+
}
|
|
76
|
+
return result;
|
|
77
|
+
}
|
|
78
|
+
async function prepareStdioLaunch(options) {
|
|
79
|
+
const environmentNames = new Set([
|
|
80
|
+
...Object.keys(options.staticEnv),
|
|
81
|
+
...Object.keys(options.secretEnv),
|
|
82
|
+
...options.forwardedEnv,
|
|
83
|
+
]);
|
|
84
|
+
const target = await validateMcpStdioPolicy({
|
|
85
|
+
command: options.command,
|
|
86
|
+
args: options.args,
|
|
87
|
+
cwd: options.cwd,
|
|
88
|
+
environmentNames: [...environmentNames],
|
|
89
|
+
}, options.deploymentPolicy);
|
|
90
|
+
const env = {
|
|
91
|
+
...options.staticEnv,
|
|
92
|
+
...options.secretEnv,
|
|
93
|
+
};
|
|
94
|
+
for (const name of options.forwardedEnv) {
|
|
95
|
+
const value = options.hostEnv[name];
|
|
96
|
+
if (value !== undefined)
|
|
97
|
+
env[name] = value;
|
|
98
|
+
}
|
|
99
|
+
if (options.deploymentPolicy.deploymentMode === "authenticated") {
|
|
100
|
+
for (const name of DEFAULT_INHERITED_ENV_VARS) {
|
|
101
|
+
if (!environmentNames.has(name))
|
|
102
|
+
env[name] = "";
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return { ...target, env };
|
|
106
|
+
}
|
|
107
|
+
export async function createManagedMcpClient(options) {
|
|
108
|
+
const sdkClient = new Client({ name: "rudder-managed-mcp", version: "1.0.0" }, { versionNegotiation: { mode: "legacy" } });
|
|
109
|
+
const maxOutputBytes = options.maxOutputBytes ?? 10 * 1024 * 1024;
|
|
110
|
+
let stderrBytes = 0;
|
|
111
|
+
let transport;
|
|
112
|
+
let stdioTransport = null;
|
|
113
|
+
let stdioOutputBoundaryExceeded = false;
|
|
114
|
+
let stdioClosedPromise = null;
|
|
115
|
+
let closePromise = null;
|
|
116
|
+
const closeSdkClient = () => {
|
|
117
|
+
if (closePromise)
|
|
118
|
+
return closePromise;
|
|
119
|
+
closePromise = (async () => {
|
|
120
|
+
try {
|
|
121
|
+
await sdkClient.close();
|
|
122
|
+
await stdioClosedPromise;
|
|
123
|
+
}
|
|
124
|
+
catch (error) {
|
|
125
|
+
closePromise = null;
|
|
126
|
+
throw error;
|
|
127
|
+
}
|
|
128
|
+
})();
|
|
129
|
+
return closePromise;
|
|
130
|
+
};
|
|
131
|
+
const mapClientError = async (error, action) => {
|
|
132
|
+
if (options.transport === "streamable_http"
|
|
133
|
+
&& (error instanceof UnauthorizedError
|
|
134
|
+
|| (error instanceof SdkHttpError && error.status === 401))) {
|
|
135
|
+
await options.credentials.onUnauthorizedFailure?.().catch(() => undefined);
|
|
136
|
+
}
|
|
137
|
+
return safeClientError(error, action);
|
|
138
|
+
};
|
|
139
|
+
if (options.transport === "streamable_http") {
|
|
140
|
+
assertSafeMcpHeaders(options.staticHeaders ?? {});
|
|
141
|
+
assertSafeMcpCredentialHeaders(options.credentials.headers);
|
|
142
|
+
const credentialAuthorization = Object.keys(options.credentials.headers)
|
|
143
|
+
.some((name) => name.toLowerCase() === "authorization");
|
|
144
|
+
if (credentialAuthorization && options.credentials.authProvider) {
|
|
145
|
+
throw new ManagedMcpClientError("mcp_conflicting_authorization", "Configure exactly one managed MCP Authorization source");
|
|
146
|
+
}
|
|
147
|
+
transport = new StreamableHTTPClientTransport(new URL(options.url), {
|
|
148
|
+
authProvider: options.credentials.authProvider,
|
|
149
|
+
requestInit: {
|
|
150
|
+
headers: {
|
|
151
|
+
...(options.staticHeaders ?? {}),
|
|
152
|
+
...options.credentials.headers,
|
|
153
|
+
},
|
|
154
|
+
},
|
|
155
|
+
fetch: createSecureMcpFetch({
|
|
156
|
+
...options.network,
|
|
157
|
+
maxResponseBytes: maxOutputBytes,
|
|
158
|
+
}),
|
|
159
|
+
onInsufficientScope: "throw",
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
const launch = await prepareStdioLaunch(options);
|
|
164
|
+
stdioTransport = new StdioClientTransport({
|
|
165
|
+
command: launch.command,
|
|
166
|
+
args: options.args,
|
|
167
|
+
cwd: launch.cwd,
|
|
168
|
+
env: launch.env,
|
|
169
|
+
stderr: "pipe",
|
|
170
|
+
maxBufferSize: maxOutputBytes,
|
|
171
|
+
});
|
|
172
|
+
transport = stdioTransport;
|
|
173
|
+
stdioTransport.stderr?.on("data", (chunk) => {
|
|
174
|
+
stderrBytes += Buffer.byteLength(chunk);
|
|
175
|
+
if (stderrBytes > maxOutputBytes) {
|
|
176
|
+
stdioOutputBoundaryExceeded = true;
|
|
177
|
+
void closeSdkClient().catch(() => undefined);
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
try {
|
|
182
|
+
await sdkClient.connect(transport, { timeout: options.startupTimeoutMs });
|
|
183
|
+
}
|
|
184
|
+
catch (error) {
|
|
185
|
+
await closeSdkClient().catch(() => undefined);
|
|
186
|
+
throw await mapClientError(error, "connect");
|
|
187
|
+
}
|
|
188
|
+
if (stdioTransport) {
|
|
189
|
+
let resolveStdioClosed = null;
|
|
190
|
+
stdioClosedPromise = new Promise((resolve) => {
|
|
191
|
+
resolveStdioClosed = resolve;
|
|
192
|
+
});
|
|
193
|
+
const clientCloseHandler = stdioTransport.onclose;
|
|
194
|
+
stdioTransport.onclose = () => {
|
|
195
|
+
try {
|
|
196
|
+
clientCloseHandler?.();
|
|
197
|
+
}
|
|
198
|
+
finally {
|
|
199
|
+
resolveStdioClosed?.();
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
const clientErrorHandler = stdioTransport.onerror;
|
|
203
|
+
stdioTransport.onerror = (error) => {
|
|
204
|
+
if (isStdioOutputBoundaryError(error)) {
|
|
205
|
+
stdioOutputBoundaryExceeded = true;
|
|
206
|
+
void closeSdkClient().catch(() => undefined);
|
|
207
|
+
}
|
|
208
|
+
clientErrorHandler?.(error);
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
return {
|
|
212
|
+
async discoverTools() {
|
|
213
|
+
try {
|
|
214
|
+
const result = await sdkClient.listTools(undefined, { timeout: options.startupTimeoutMs, cacheMode: "refresh" });
|
|
215
|
+
return result.tools;
|
|
216
|
+
}
|
|
217
|
+
catch (error) {
|
|
218
|
+
throw await mapClientError(error, "discover");
|
|
219
|
+
}
|
|
220
|
+
},
|
|
221
|
+
async callTool(name, args) {
|
|
222
|
+
try {
|
|
223
|
+
const result = await sdkClient.callTool({ name, arguments: args }, { timeout: options.toolTimeoutMs });
|
|
224
|
+
return boundedResult(result, maxOutputBytes);
|
|
225
|
+
}
|
|
226
|
+
catch (error) {
|
|
227
|
+
if (stdioOutputBoundaryExceeded) {
|
|
228
|
+
throw new ManagedMcpClientError("mcp_result_too_large", "Managed MCP tool result exceeds the output limit");
|
|
229
|
+
}
|
|
230
|
+
throw await mapClientError(error, "call");
|
|
231
|
+
}
|
|
232
|
+
},
|
|
233
|
+
async close() {
|
|
234
|
+
await closeSdkClient();
|
|
235
|
+
},
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
//# sourceMappingURL=managed-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"managed-client.js","sourceRoot":"","sources":["../../../src/services/mcp/managed-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"managed-client.test.d.ts","sourceRoot":"","sources":["../../../src/services/mcp/managed-client.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,398 @@
|
|
|
1
|
+
import { mkdir, mkdtemp, realpath, stat, symlink } from "node:fs/promises";
|
|
2
|
+
import { createServer } from "node:http";
|
|
3
|
+
import os from "node:os";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
import { afterEach, describe, expect, it } from "vitest";
|
|
7
|
+
import { createManagedMcpClient, resolveMcpHttpCredentials, } from "./managed-client.js";
|
|
8
|
+
async function readJson(req) {
|
|
9
|
+
const chunks = [];
|
|
10
|
+
for await (const chunk of req)
|
|
11
|
+
chunks.push(Buffer.from(chunk));
|
|
12
|
+
return JSON.parse(Buffer.concat(chunks).toString("utf8"));
|
|
13
|
+
}
|
|
14
|
+
function json(res, status, body) {
|
|
15
|
+
res.writeHead(status, { "content-type": "application/json" });
|
|
16
|
+
res.end(JSON.stringify(body));
|
|
17
|
+
}
|
|
18
|
+
async function startMockMcpServer(options = {}) {
|
|
19
|
+
const requests = [];
|
|
20
|
+
const server = createServer(async (req, res) => {
|
|
21
|
+
if (req.method === "GET") {
|
|
22
|
+
res.writeHead(405);
|
|
23
|
+
res.end();
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
if (req.method === "DELETE") {
|
|
27
|
+
res.writeHead(200);
|
|
28
|
+
res.end();
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
if (options.redirectOnce && req.url === "/redirect") {
|
|
32
|
+
res.writeHead(307, { location: "/mcp" });
|
|
33
|
+
res.end();
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
const message = await readJson(req);
|
|
37
|
+
const authorization = req.headers.authorization;
|
|
38
|
+
requests.push({ method: message.method, authorization });
|
|
39
|
+
const acceptedBearer = options.refreshBearer ?? options.requiredBearer;
|
|
40
|
+
if (options.alwaysUnauthorized
|
|
41
|
+
|| (acceptedBearer && authorization !== `Bearer ${acceptedBearer}`)) {
|
|
42
|
+
res.writeHead(401, { "www-authenticate": "Bearer" });
|
|
43
|
+
res.end();
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
if (options.rateLimitTools && message.method === "tools/list") {
|
|
47
|
+
res.writeHead(429, { "retry-after": "1" });
|
|
48
|
+
res.end();
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
if (message.method === "notifications/initialized") {
|
|
52
|
+
res.writeHead(202);
|
|
53
|
+
res.end();
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
if (message.method === "initialize") {
|
|
57
|
+
json(res, 200, {
|
|
58
|
+
jsonrpc: "2.0",
|
|
59
|
+
id: message.id,
|
|
60
|
+
result: {
|
|
61
|
+
protocolVersion: "2025-06-18",
|
|
62
|
+
capabilities: { tools: {} },
|
|
63
|
+
serverInfo: { name: "rudder-http-fixture", version: "1.0.0" },
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
if (message.method === "tools/list") {
|
|
69
|
+
json(res, 200, {
|
|
70
|
+
jsonrpc: "2.0",
|
|
71
|
+
id: message.id,
|
|
72
|
+
result: {
|
|
73
|
+
tools: [{
|
|
74
|
+
name: "echo",
|
|
75
|
+
description: "Echo an input",
|
|
76
|
+
inputSchema: {
|
|
77
|
+
type: "object",
|
|
78
|
+
properties: { value: { type: "string" } },
|
|
79
|
+
},
|
|
80
|
+
}],
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
if (message.method === "tools/call") {
|
|
86
|
+
json(res, 200, {
|
|
87
|
+
jsonrpc: "2.0",
|
|
88
|
+
id: message.id,
|
|
89
|
+
result: {
|
|
90
|
+
content: [{ type: "text", text: message.params.arguments.value }],
|
|
91
|
+
structuredContent: { echoed: message.params.arguments.value },
|
|
92
|
+
},
|
|
93
|
+
});
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
json(res, 404, {});
|
|
97
|
+
});
|
|
98
|
+
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
|
|
99
|
+
const address = server.address();
|
|
100
|
+
if (!address || typeof address === "string")
|
|
101
|
+
throw new Error("Missing fixture address");
|
|
102
|
+
return {
|
|
103
|
+
origin: `http://127.0.0.1:${address.port}`,
|
|
104
|
+
requests,
|
|
105
|
+
close: () => new Promise((resolve, reject) => {
|
|
106
|
+
server.close((error) => error ? reject(error) : resolve());
|
|
107
|
+
}),
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
const clients = [];
|
|
111
|
+
const servers = [];
|
|
112
|
+
afterEach(async () => {
|
|
113
|
+
await Promise.allSettled(clients.splice(0).map((client) => client.close()));
|
|
114
|
+
await Promise.allSettled(servers.splice(0).map((server) => server.close()));
|
|
115
|
+
});
|
|
116
|
+
describe("managed MCP Streamable HTTP client", () => {
|
|
117
|
+
it("performs initialize, tools/list, and tools/call without authentication", async () => {
|
|
118
|
+
const server = await startMockMcpServer();
|
|
119
|
+
servers.push(server);
|
|
120
|
+
const client = await createManagedMcpClient({
|
|
121
|
+
transport: "streamable_http",
|
|
122
|
+
url: `${server.origin}/mcp`,
|
|
123
|
+
network: { allowedOrigins: [server.origin] },
|
|
124
|
+
credentials: resolveMcpHttpCredentials({}),
|
|
125
|
+
startupTimeoutMs: 1_000,
|
|
126
|
+
toolTimeoutMs: 1_000,
|
|
127
|
+
});
|
|
128
|
+
clients.push(client);
|
|
129
|
+
await expect(client.discoverTools()).resolves.toEqual([
|
|
130
|
+
expect.objectContaining({ name: "echo" }),
|
|
131
|
+
]);
|
|
132
|
+
await expect(client.callTool("echo", { value: "hello" })).resolves.toMatchObject({
|
|
133
|
+
structuredContent: { echoed: "hello" },
|
|
134
|
+
});
|
|
135
|
+
expect(server.requests.map((request) => request.method)).toEqual([
|
|
136
|
+
"initialize",
|
|
137
|
+
"notifications/initialized",
|
|
138
|
+
"tools/list",
|
|
139
|
+
"tools/call",
|
|
140
|
+
]);
|
|
141
|
+
});
|
|
142
|
+
it("injects one Bearer source and refreshes at most once after 401", async () => {
|
|
143
|
+
const server = await startMockMcpServer({ refreshBearer: "fresh-token" });
|
|
144
|
+
servers.push(server);
|
|
145
|
+
let token = "expired-token";
|
|
146
|
+
let refreshes = 0;
|
|
147
|
+
const client = await createManagedMcpClient({
|
|
148
|
+
transport: "streamable_http",
|
|
149
|
+
url: `${server.origin}/mcp`,
|
|
150
|
+
network: { allowedOrigins: [server.origin] },
|
|
151
|
+
credentials: resolveMcpHttpCredentials({
|
|
152
|
+
oauth: {
|
|
153
|
+
token: async () => token,
|
|
154
|
+
refresh: async () => {
|
|
155
|
+
refreshes += 1;
|
|
156
|
+
token = "fresh-token";
|
|
157
|
+
},
|
|
158
|
+
},
|
|
159
|
+
}),
|
|
160
|
+
startupTimeoutMs: 1_000,
|
|
161
|
+
toolTimeoutMs: 1_000,
|
|
162
|
+
});
|
|
163
|
+
clients.push(client);
|
|
164
|
+
await expect(client.discoverTools()).resolves.toHaveLength(1);
|
|
165
|
+
expect(refreshes).toBe(1);
|
|
166
|
+
expect(server.requests.filter((request) => request.method === "initialize")).toHaveLength(2);
|
|
167
|
+
expect(server.requests.at(-1)?.authorization).toBe("Bearer fresh-token");
|
|
168
|
+
});
|
|
169
|
+
it("preserves the receiver for stateful OAuth credentials", async () => {
|
|
170
|
+
const oauth = {
|
|
171
|
+
currentToken: "stateful-token",
|
|
172
|
+
async token() {
|
|
173
|
+
return this.currentToken;
|
|
174
|
+
},
|
|
175
|
+
async refresh() { },
|
|
176
|
+
};
|
|
177
|
+
const credentials = resolveMcpHttpCredentials({ oauth });
|
|
178
|
+
await expect(credentials.authProvider?.token()).resolves.toBe("stateful-token");
|
|
179
|
+
});
|
|
180
|
+
it("refreshes only once and surfaces persistent upstream 401 responses", async () => {
|
|
181
|
+
const server = await startMockMcpServer({ alwaysUnauthorized: true });
|
|
182
|
+
servers.push(server);
|
|
183
|
+
let refreshes = 0;
|
|
184
|
+
let reauthorizationTransitions = 0;
|
|
185
|
+
await expect(createManagedMcpClient({
|
|
186
|
+
transport: "streamable_http",
|
|
187
|
+
url: `${server.origin}/mcp`,
|
|
188
|
+
network: { allowedOrigins: [server.origin] },
|
|
189
|
+
credentials: resolveMcpHttpCredentials({
|
|
190
|
+
oauth: {
|
|
191
|
+
token: async () => "always-rejected",
|
|
192
|
+
refresh: async () => {
|
|
193
|
+
refreshes += 1;
|
|
194
|
+
},
|
|
195
|
+
markNeedsReauth: async () => {
|
|
196
|
+
reauthorizationTransitions += 1;
|
|
197
|
+
},
|
|
198
|
+
},
|
|
199
|
+
}),
|
|
200
|
+
startupTimeoutMs: 1_000,
|
|
201
|
+
toolTimeoutMs: 1_000,
|
|
202
|
+
})).rejects.toMatchObject({ code: "mcp_upstream_unauthorized" });
|
|
203
|
+
expect(refreshes).toBe(1);
|
|
204
|
+
expect(reauthorizationTransitions).toBe(1);
|
|
205
|
+
expect(server.requests.filter((request) => request.method === "initialize")).toHaveLength(2);
|
|
206
|
+
});
|
|
207
|
+
it("follows only policy-validated redirects and surfaces rate limits safely", async () => {
|
|
208
|
+
const redirecting = await startMockMcpServer({ redirectOnce: true });
|
|
209
|
+
servers.push(redirecting);
|
|
210
|
+
const redirectedClient = await createManagedMcpClient({
|
|
211
|
+
transport: "streamable_http",
|
|
212
|
+
url: `${redirecting.origin}/redirect`,
|
|
213
|
+
network: { allowedOrigins: [redirecting.origin] },
|
|
214
|
+
credentials: resolveMcpHttpCredentials({ bearerToken: "redirect-secret" }),
|
|
215
|
+
startupTimeoutMs: 1_000,
|
|
216
|
+
toolTimeoutMs: 1_000,
|
|
217
|
+
});
|
|
218
|
+
clients.push(redirectedClient);
|
|
219
|
+
await expect(redirectedClient.discoverTools()).resolves.toHaveLength(1);
|
|
220
|
+
const limited = await startMockMcpServer({ rateLimitTools: true });
|
|
221
|
+
servers.push(limited);
|
|
222
|
+
const limitedClient = await createManagedMcpClient({
|
|
223
|
+
transport: "streamable_http",
|
|
224
|
+
url: `${limited.origin}/mcp`,
|
|
225
|
+
network: { allowedOrigins: [limited.origin] },
|
|
226
|
+
credentials: resolveMcpHttpCredentials({}),
|
|
227
|
+
startupTimeoutMs: 1_000,
|
|
228
|
+
toolTimeoutMs: 1_000,
|
|
229
|
+
});
|
|
230
|
+
clients.push(limitedClient);
|
|
231
|
+
await expect(limitedClient.discoverTools()).rejects.toMatchObject({
|
|
232
|
+
code: "mcp_upstream_rate_limited",
|
|
233
|
+
});
|
|
234
|
+
});
|
|
235
|
+
it("rejects conflicting Authorization sources without exposing their values", () => {
|
|
236
|
+
expect(() => resolveMcpHttpCredentials({
|
|
237
|
+
bearerToken: "first-secret",
|
|
238
|
+
authorizationHeader: "Bearer second-secret",
|
|
239
|
+
})).toThrowError(expect.not.stringMatching(/first-secret|second-secret/));
|
|
240
|
+
});
|
|
241
|
+
});
|
|
242
|
+
describe("managed MCP STDIO client", () => {
|
|
243
|
+
it("uses canonical authenticated paths, selects environment, and force-reaps a stubborn child", async () => {
|
|
244
|
+
const fixtureRoot = await mkdtemp(path.join(os.tmpdir(), "rudder-mcp-stdio-"));
|
|
245
|
+
const canonicalCwd = path.join(fixtureRoot, "canonical-cwd");
|
|
246
|
+
const cwdAlias = path.join(fixtureRoot, "cwd-alias");
|
|
247
|
+
const commandAlias = path.join(fixtureRoot, "node-alias");
|
|
248
|
+
await mkdir(canonicalCwd);
|
|
249
|
+
await symlink(canonicalCwd, cwdAlias, "dir");
|
|
250
|
+
await symlink(process.execPath, commandAlias, "file");
|
|
251
|
+
const touchedPath = path.join(canonicalCwd, "must-not-exist");
|
|
252
|
+
const shellText = `$(touch ${touchedPath})`;
|
|
253
|
+
const fixturePath = fileURLToPath(new URL("./__fixtures__/stdio-server.mjs", import.meta.url));
|
|
254
|
+
const client = await createManagedMcpClient({
|
|
255
|
+
transport: "stdio",
|
|
256
|
+
command: commandAlias,
|
|
257
|
+
args: [fixturePath, shellText],
|
|
258
|
+
cwd: cwdAlias,
|
|
259
|
+
staticEnv: {
|
|
260
|
+
STATIC_ENV: "static-value",
|
|
261
|
+
STUBBORN_MODE: "1",
|
|
262
|
+
},
|
|
263
|
+
forwardedEnv: ["FORWARDED_ENV"],
|
|
264
|
+
secretEnv: { SECRET_ENV: "secret-value" },
|
|
265
|
+
hostEnv: {
|
|
266
|
+
FORWARDED_ENV: "forwarded-value",
|
|
267
|
+
UNSELECTED_SECRET: "must-not-leak",
|
|
268
|
+
},
|
|
269
|
+
deploymentPolicy: {
|
|
270
|
+
deploymentMode: "authenticated",
|
|
271
|
+
stdioCommands: [[commandAlias, fixturePath, shellText]],
|
|
272
|
+
stdioWorkingDirectories: [cwdAlias],
|
|
273
|
+
stdioEnvironmentNames: [
|
|
274
|
+
"STATIC_ENV",
|
|
275
|
+
"STUBBORN_MODE",
|
|
276
|
+
"FORWARDED_ENV",
|
|
277
|
+
"SECRET_ENV",
|
|
278
|
+
],
|
|
279
|
+
},
|
|
280
|
+
startupTimeoutMs: 1_000,
|
|
281
|
+
toolTimeoutMs: 1_000,
|
|
282
|
+
maxOutputBytes: 128 * 1024,
|
|
283
|
+
});
|
|
284
|
+
clients.push(client);
|
|
285
|
+
const result = await client.callTool("inspect", {});
|
|
286
|
+
const details = result.structuredContent;
|
|
287
|
+
expect(details).toMatchObject({
|
|
288
|
+
argv0: await realpath(process.execPath),
|
|
289
|
+
cwd: await realpath(canonicalCwd),
|
|
290
|
+
extraArg: shellText,
|
|
291
|
+
staticEnv: "static-value",
|
|
292
|
+
forwardedEnv: "forwarded-value",
|
|
293
|
+
secretEnv: "secret-value",
|
|
294
|
+
unselectedEnv: null,
|
|
295
|
+
inheritedHome: null,
|
|
296
|
+
});
|
|
297
|
+
await expect(stat(touchedPath)).rejects.toMatchObject({ code: "ENOENT" });
|
|
298
|
+
const pid = details.pid;
|
|
299
|
+
const closeStartedAt = Date.now();
|
|
300
|
+
const firstClose = client.close();
|
|
301
|
+
let secondCloseObservedLiveChild = false;
|
|
302
|
+
const secondClose = client.close().then(() => {
|
|
303
|
+
try {
|
|
304
|
+
process.kill(pid, 0);
|
|
305
|
+
secondCloseObservedLiveChild = true;
|
|
306
|
+
}
|
|
307
|
+
catch {
|
|
308
|
+
secondCloseObservedLiveChild = false;
|
|
309
|
+
}
|
|
310
|
+
});
|
|
311
|
+
await Promise.all([firstClose, secondClose]);
|
|
312
|
+
clients.splice(clients.indexOf(client), 1);
|
|
313
|
+
expect(secondCloseObservedLiveChild).toBe(false);
|
|
314
|
+
expect(Date.now() - closeStartedAt).toBeLessThan(5_500);
|
|
315
|
+
expect(() => process.kill(pid, 0)).toThrow();
|
|
316
|
+
});
|
|
317
|
+
it("enforces tool timeout with redacted errors", async () => {
|
|
318
|
+
const fixturePath = fileURLToPath(new URL("./__fixtures__/stdio-server.mjs", import.meta.url));
|
|
319
|
+
const client = await createManagedMcpClient({
|
|
320
|
+
transport: "stdio",
|
|
321
|
+
command: process.execPath,
|
|
322
|
+
args: [fixturePath],
|
|
323
|
+
staticEnv: {},
|
|
324
|
+
forwardedEnv: [],
|
|
325
|
+
secretEnv: { SELECTED_ENV: "server-secret" },
|
|
326
|
+
hostEnv: {},
|
|
327
|
+
deploymentPolicy: {
|
|
328
|
+
deploymentMode: "local_trusted",
|
|
329
|
+
stdioCommands: [],
|
|
330
|
+
stdioWorkingDirectories: [],
|
|
331
|
+
stdioEnvironmentNames: [],
|
|
332
|
+
},
|
|
333
|
+
startupTimeoutMs: 1_000,
|
|
334
|
+
toolTimeoutMs: 25,
|
|
335
|
+
maxOutputBytes: 2_048,
|
|
336
|
+
});
|
|
337
|
+
clients.push(client);
|
|
338
|
+
await expect(client.callTool("sleep", { delayMs: 100 })).rejects.toMatchObject({
|
|
339
|
+
code: "mcp_tool_timeout",
|
|
340
|
+
});
|
|
341
|
+
});
|
|
342
|
+
it("returns a specific output-boundary error and reaps the child", async () => {
|
|
343
|
+
const fixturePath = fileURLToPath(new URL("./__fixtures__/stdio-server.mjs", import.meta.url));
|
|
344
|
+
const client = await createManagedMcpClient({
|
|
345
|
+
transport: "stdio",
|
|
346
|
+
command: process.execPath,
|
|
347
|
+
args: [fixturePath],
|
|
348
|
+
staticEnv: {},
|
|
349
|
+
forwardedEnv: [],
|
|
350
|
+
secretEnv: { SECRET_ENV: "server-secret" },
|
|
351
|
+
hostEnv: {},
|
|
352
|
+
deploymentPolicy: {
|
|
353
|
+
deploymentMode: "local_trusted",
|
|
354
|
+
stdioCommands: [],
|
|
355
|
+
stdioWorkingDirectories: [],
|
|
356
|
+
stdioEnvironmentNames: [],
|
|
357
|
+
},
|
|
358
|
+
startupTimeoutMs: 1_000,
|
|
359
|
+
toolTimeoutMs: 1_000,
|
|
360
|
+
maxOutputBytes: 2_048,
|
|
361
|
+
});
|
|
362
|
+
clients.push(client);
|
|
363
|
+
const inspected = await client.callTool("inspect", {});
|
|
364
|
+
const pid = inspected.structuredContent.pid;
|
|
365
|
+
const largeError = await client.callTool("large", { bytes: 8_192 }).then(() => null, (error) => error);
|
|
366
|
+
await client.close();
|
|
367
|
+
clients.splice(clients.indexOf(client), 1);
|
|
368
|
+
expect(largeError).toMatchObject({ code: "mcp_result_too_large" });
|
|
369
|
+
expect(JSON.stringify(largeError)).not.toContain("server-secret");
|
|
370
|
+
expect(() => process.kill(pid, 0)).toThrow();
|
|
371
|
+
});
|
|
372
|
+
it("rejects forged resolved credentials at the true client boundary", async () => {
|
|
373
|
+
const server = await startMockMcpServer();
|
|
374
|
+
servers.push(server);
|
|
375
|
+
const forgedCredentials = [
|
|
376
|
+
{
|
|
377
|
+
headers: { Authorization: "Bearer manual-secret" },
|
|
378
|
+
authProvider: { token: async () => "oauth-secret" },
|
|
379
|
+
},
|
|
380
|
+
{ headers: { Cookie: "cookie-secret" } },
|
|
381
|
+
{ headers: { Host: "host-secret" } },
|
|
382
|
+
{ headers: { "Proxy-Authorization": "proxy-secret" } },
|
|
383
|
+
];
|
|
384
|
+
for (const forged of forgedCredentials) {
|
|
385
|
+
await expect(createManagedMcpClient({
|
|
386
|
+
transport: "streamable_http",
|
|
387
|
+
url: `${server.origin}/mcp`,
|
|
388
|
+
network: { allowedOrigins: [server.origin] },
|
|
389
|
+
credentials: forged,
|
|
390
|
+
startupTimeoutMs: 1_000,
|
|
391
|
+
toolTimeoutMs: 1_000,
|
|
392
|
+
})).rejects.toSatisfy((error) => (!/manual-secret|oauth-secret|cookie-secret|host-secret|proxy-secret/u
|
|
393
|
+
.test(JSON.stringify(error))));
|
|
394
|
+
}
|
|
395
|
+
expect(server.requests).toHaveLength(0);
|
|
396
|
+
});
|
|
397
|
+
});
|
|
398
|
+
//# sourceMappingURL=managed-client.test.js.map
|