@animalabs/agent-framework 0.23.3 → 0.24.1
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 +212 -42
- package/dist/src/agent.d.ts +65 -9
- package/dist/src/agent.d.ts.map +1 -1
- package/dist/src/agent.js +98 -12
- package/dist/src/agent.js.map +1 -1
- package/dist/src/api/server.d.ts.map +1 -1
- package/dist/src/api/server.js +14 -12
- package/dist/src/api/server.js.map +1 -1
- package/dist/src/clock-rows.d.ts +115 -0
- package/dist/src/clock-rows.d.ts.map +1 -0
- package/dist/src/clock-rows.js +222 -0
- package/dist/src/clock-rows.js.map +1 -0
- package/dist/src/code-execution/engine.d.ts +177 -0
- package/dist/src/code-execution/engine.d.ts.map +1 -0
- package/dist/src/code-execution/engine.js +494 -0
- package/dist/src/code-execution/engine.js.map +1 -0
- package/dist/src/code-execution/index.d.ts +5 -10
- package/dist/src/code-execution/index.d.ts.map +1 -1
- package/dist/src/code-execution/index.js +5 -9
- package/dist/src/code-execution/index.js.map +1 -1
- package/dist/src/code-execution/isolate/calls.d.ts +114 -0
- package/dist/src/code-execution/isolate/calls.d.ts.map +1 -0
- package/dist/src/code-execution/isolate/calls.js +145 -0
- package/dist/src/code-execution/isolate/calls.js.map +1 -0
- package/dist/src/code-execution/isolate/child-entry.d.ts +2 -0
- package/dist/src/code-execution/isolate/child-entry.d.ts.map +1 -0
- package/dist/src/code-execution/isolate/child-entry.js +5 -0
- package/dist/src/code-execution/isolate/child-entry.js.map +1 -0
- package/dist/src/code-execution/isolate/child-main.d.ts +26 -0
- package/dist/src/code-execution/isolate/child-main.d.ts.map +1 -0
- package/dist/src/code-execution/isolate/child-main.js +132 -0
- package/dist/src/code-execution/isolate/child-main.js.map +1 -0
- package/dist/src/code-execution/isolate/child.d.ts +44 -0
- package/dist/src/code-execution/isolate/child.d.ts.map +1 -0
- package/dist/src/code-execution/isolate/child.js +315 -0
- package/dist/src/code-execution/isolate/child.js.map +1 -0
- package/dist/src/code-execution/isolate/frames.d.ts +80 -0
- package/dist/src/code-execution/isolate/frames.d.ts.map +1 -0
- package/dist/src/code-execution/isolate/frames.js +210 -0
- package/dist/src/code-execution/isolate/frames.js.map +1 -0
- package/dist/src/code-execution/isolate/output.d.ts +68 -0
- package/dist/src/code-execution/isolate/output.d.ts.map +1 -0
- package/dist/src/code-execution/isolate/output.js +143 -0
- package/dist/src/code-execution/isolate/output.js.map +1 -0
- package/dist/src/code-execution/isolate/prelude.d.ts +109 -0
- package/dist/src/code-execution/isolate/prelude.d.ts.map +1 -0
- package/dist/src/code-execution/isolate/prelude.js +401 -0
- package/dist/src/code-execution/isolate/prelude.js.map +1 -0
- package/dist/src/code-execution/isolate/protocol.d.ts +151 -0
- package/dist/src/code-execution/isolate/protocol.d.ts.map +1 -0
- package/dist/src/code-execution/isolate/protocol.js +150 -0
- package/dist/src/code-execution/isolate/protocol.js.map +1 -0
- package/dist/src/code-execution/isolate/render.d.ts +57 -0
- package/dist/src/code-execution/isolate/render.d.ts.map +1 -0
- package/dist/src/code-execution/isolate/render.js +214 -0
- package/dist/src/code-execution/isolate/render.js.map +1 -0
- package/dist/src/code-execution/isolate/runner.d.ts +250 -0
- package/dist/src/code-execution/isolate/runner.d.ts.map +1 -0
- package/dist/src/code-execution/isolate/runner.js +854 -0
- package/dist/src/code-execution/isolate/runner.js.map +1 -0
- package/dist/src/code-execution/isolate/scripts.d.ts +175 -0
- package/dist/src/code-execution/isolate/scripts.d.ts.map +1 -0
- package/dist/src/code-execution/isolate/scripts.js +357 -0
- package/dist/src/code-execution/isolate/scripts.js.map +1 -0
- package/dist/src/code-execution/quickjs.wasm +0 -0
- package/dist/src/code-execution/tool-definition.d.ts +93 -43
- package/dist/src/code-execution/tool-definition.d.ts.map +1 -1
- package/dist/src/code-execution/tool-definition.js +176 -142
- package/dist/src/code-execution/tool-definition.js.map +1 -1
- package/dist/src/deadline-timer.d.ts +3 -0
- package/dist/src/deadline-timer.d.ts.map +1 -1
- package/dist/src/deadline-timer.js +1 -1
- package/dist/src/deadline-timer.js.map +1 -1
- package/dist/src/framework.d.ts +1120 -457
- package/dist/src/framework.d.ts.map +1 -1
- package/dist/src/framework.js +4635 -2505
- package/dist/src/framework.js.map +1 -1
- package/dist/src/gate/event-gate.d.ts +28 -4
- package/dist/src/gate/event-gate.d.ts.map +1 -1
- package/dist/src/gate/event-gate.js +89 -13
- package/dist/src/gate/event-gate.js.map +1 -1
- package/dist/src/held-writes.d.ts +16 -3
- package/dist/src/held-writes.d.ts.map +1 -1
- package/dist/src/held-writes.js +16 -3
- package/dist/src/held-writes.js.map +1 -1
- package/dist/src/index.d.ts +8 -6
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +10 -8
- package/dist/src/index.js.map +1 -1
- package/dist/src/mcpl/channel-registry.d.ts +483 -115
- package/dist/src/mcpl/channel-registry.d.ts.map +1 -1
- package/dist/src/mcpl/channel-registry.js +1735 -425
- package/dist/src/mcpl/channel-registry.js.map +1 -1
- package/dist/src/mcpl/conversation-router.d.ts +19 -39
- package/dist/src/mcpl/conversation-router.d.ts.map +1 -1
- package/dist/src/mcpl/conversation-router.js +27 -59
- package/dist/src/mcpl/conversation-router.js.map +1 -1
- package/dist/src/mcpl/convert-block.d.ts.map +1 -1
- package/dist/src/mcpl/convert-block.js +9 -5
- package/dist/src/mcpl/convert-block.js.map +1 -1
- package/dist/src/mcpl/inbound-source.d.ts +50 -0
- package/dist/src/mcpl/inbound-source.d.ts.map +1 -1
- package/dist/src/mcpl/inbound-source.js +130 -0
- package/dist/src/mcpl/inbound-source.js.map +1 -1
- package/dist/src/mcpl/index.d.ts +2 -1
- package/dist/src/mcpl/index.d.ts.map +1 -1
- package/dist/src/mcpl/index.js +3 -2
- package/dist/src/mcpl/index.js.map +1 -1
- package/dist/src/mcpl/log-value.d.ts +6 -0
- package/dist/src/mcpl/log-value.d.ts.map +1 -1
- package/dist/src/mcpl/log-value.js +8 -0
- package/dist/src/mcpl/log-value.js.map +1 -1
- package/dist/src/mcpl/modern-connection.d.ts +15 -6
- package/dist/src/mcpl/modern-connection.d.ts.map +1 -1
- package/dist/src/mcpl/modern-connection.js +168 -53
- package/dist/src/mcpl/modern-connection.js.map +1 -1
- package/dist/src/mcpl/prose-grammar.d.ts +4 -5
- package/dist/src/mcpl/prose-grammar.d.ts.map +1 -1
- package/dist/src/mcpl/prose-grammar.js +4 -5
- package/dist/src/mcpl/prose-grammar.js.map +1 -1
- package/dist/src/mcpl/protocol-family.d.ts +97 -10
- package/dist/src/mcpl/protocol-family.d.ts.map +1 -1
- package/dist/src/mcpl/protocol-family.js +174 -17
- package/dist/src/mcpl/protocol-family.js.map +1 -1
- package/dist/src/mcpl/push-coalescer.d.ts +132 -14
- package/dist/src/mcpl/push-coalescer.d.ts.map +1 -1
- package/dist/src/mcpl/push-coalescer.js +227 -50
- package/dist/src/mcpl/push-coalescer.js.map +1 -1
- package/dist/src/mcpl/push-handler.d.ts +9 -20
- package/dist/src/mcpl/push-handler.d.ts.map +1 -1
- package/dist/src/mcpl/push-handler.js +7 -49
- package/dist/src/mcpl/push-handler.js.map +1 -1
- package/dist/src/mcpl/reference-fetcher.d.ts +2 -2
- package/dist/src/mcpl/reference-fetcher.d.ts.map +1 -1
- package/dist/src/mcpl/reference-fetcher.js +4 -4
- package/dist/src/mcpl/reference-fetcher.js.map +1 -1
- package/dist/src/mcpl/server-connection.d.ts +50 -21
- package/dist/src/mcpl/server-connection.d.ts.map +1 -1
- package/dist/src/mcpl/server-connection.js +158 -74
- package/dist/src/mcpl/server-connection.js.map +1 -1
- package/dist/src/mcpl/tags.d.ts +24 -0
- package/dist/src/mcpl/tags.d.ts.map +1 -1
- package/dist/src/mcpl/tags.js +33 -0
- package/dist/src/mcpl/tags.js.map +1 -1
- package/dist/src/mcpl/tool-result-normalize.d.ts +2 -1
- package/dist/src/mcpl/tool-result-normalize.d.ts.map +1 -1
- package/dist/src/mcpl/tool-result-normalize.js.map +1 -1
- package/dist/src/mcpl/transport.d.ts +55 -7
- package/dist/src/mcpl/transport.d.ts.map +1 -1
- package/dist/src/mcpl/transport.js +163 -34
- package/dist/src/mcpl/transport.js.map +1 -1
- package/dist/src/mcpl/types.d.ts +22 -6
- package/dist/src/mcpl/types.d.ts.map +1 -1
- package/dist/src/mcpl/types.js.map +1 -1
- package/dist/src/module-registry.d.ts +4 -2
- package/dist/src/module-registry.d.ts.map +1 -1
- package/dist/src/module-registry.js +100 -13
- package/dist/src/module-registry.js.map +1 -1
- package/dist/src/modules/discord/index.d.ts.map +1 -1
- package/dist/src/modules/discord/index.js +8 -13
- package/dist/src/modules/discord/index.js.map +1 -1
- package/dist/src/modules/history/index.d.ts.map +1 -1
- package/dist/src/modules/history/index.js +27 -4
- package/dist/src/modules/history/index.js.map +1 -1
- package/dist/src/modules/history/semantic.d.ts +15 -3
- package/dist/src/modules/history/semantic.d.ts.map +1 -1
- package/dist/src/modules/history/semantic.js +27 -5
- package/dist/src/modules/history/semantic.js.map +1 -1
- package/dist/src/modules/index.d.ts +1 -1
- package/dist/src/modules/index.d.ts.map +1 -1
- package/dist/src/modules/index.js.map +1 -1
- package/dist/src/modules/unknown-tool.d.ts +4 -1
- package/dist/src/modules/unknown-tool.d.ts.map +1 -1
- package/dist/src/modules/unknown-tool.js +4 -1
- package/dist/src/modules/unknown-tool.js.map +1 -1
- package/dist/src/modules/workspace/branch-intent.d.ts +3 -1
- package/dist/src/modules/workspace/branch-intent.d.ts.map +1 -1
- package/dist/src/modules/workspace/branch-intent.js +3 -1
- package/dist/src/modules/workspace/branch-intent.js.map +1 -1
- package/dist/src/modules/workspace/edit-plan.d.ts +265 -0
- package/dist/src/modules/workspace/edit-plan.d.ts.map +1 -0
- package/dist/src/modules/workspace/edit-plan.js +794 -0
- package/dist/src/modules/workspace/edit-plan.js.map +1 -0
- package/dist/src/modules/workspace/edit-text.d.ts +117 -0
- package/dist/src/modules/workspace/edit-text.d.ts.map +1 -0
- package/dist/src/modules/workspace/edit-text.js +584 -0
- package/dist/src/modules/workspace/edit-text.js.map +1 -0
- package/dist/src/modules/workspace/effects.d.ts +5 -4
- package/dist/src/modules/workspace/effects.d.ts.map +1 -1
- package/dist/src/modules/workspace/effects.js +78 -25
- package/dist/src/modules/workspace/effects.js.map +1 -1
- package/dist/src/modules/workspace/index.d.ts +493 -62
- package/dist/src/modules/workspace/index.d.ts.map +1 -1
- package/dist/src/modules/workspace/index.js +2216 -652
- package/dist/src/modules/workspace/index.js.map +1 -1
- package/dist/src/modules/workspace/observe.d.ts +213 -38
- package/dist/src/modules/workspace/observe.d.ts.map +1 -1
- package/dist/src/modules/workspace/observe.js +416 -36
- package/dist/src/modules/workspace/observe.js.map +1 -1
- package/dist/src/modules/workspace/reconcile.d.ts.map +1 -1
- package/dist/src/modules/workspace/reconcile.js +15 -8
- package/dist/src/modules/workspace/reconcile.js.map +1 -1
- package/dist/src/modules/workspace/text.d.ts +32 -0
- package/dist/src/modules/workspace/text.d.ts.map +1 -0
- package/dist/src/modules/workspace/text.js +67 -0
- package/dist/src/modules/workspace/text.js.map +1 -0
- package/dist/src/modules/workspace/types.d.ts +210 -6
- package/dist/src/modules/workspace/types.d.ts.map +1 -1
- package/dist/src/modules/workspace/types.js.map +1 -1
- package/dist/src/modules/workspace/watcher.d.ts +3 -2
- package/dist/src/modules/workspace/watcher.d.ts.map +1 -1
- package/dist/src/modules/workspace/watcher.js.map +1 -1
- package/dist/src/operator-log.d.ts +52 -24
- package/dist/src/operator-log.d.ts.map +1 -1
- package/dist/src/operator-log.js.map +1 -1
- package/dist/src/recovery/discord-awareness-outbox.d.ts +496 -72
- package/dist/src/recovery/discord-awareness-outbox.d.ts.map +1 -1
- package/dist/src/recovery/discord-awareness-outbox.js +1196 -289
- package/dist/src/recovery/discord-awareness-outbox.js.map +1 -1
- package/dist/src/recovery/offline-branch.d.ts +26 -1
- package/dist/src/recovery/offline-branch.d.ts.map +1 -1
- package/dist/src/recovery/offline-branch.js +164 -39
- package/dist/src/recovery/offline-branch.js.map +1 -1
- package/dist/src/recovery/recover-cli.js +23 -4
- package/dist/src/recovery/recover-cli.js.map +1 -1
- package/dist/src/send-tools.d.ts +11 -0
- package/dist/src/send-tools.d.ts.map +1 -0
- package/dist/src/send-tools.js +11 -0
- package/dist/src/send-tools.js.map +1 -0
- package/dist/src/timezone.d.ts +4 -2
- package/dist/src/timezone.d.ts.map +1 -1
- package/dist/src/timezone.js +4 -2
- package/dist/src/timezone.js.map +1 -1
- package/dist/src/tool-image-ledger.d.ts +46 -7
- package/dist/src/tool-image-ledger.d.ts.map +1 -1
- package/dist/src/tool-image-ledger.js +60 -7
- package/dist/src/tool-image-ledger.js.map +1 -1
- package/dist/src/tool-result-guard.d.ts +14 -11
- package/dist/src/tool-result-guard.d.ts.map +1 -1
- package/dist/src/tool-result-guard.js +17 -14
- package/dist/src/tool-result-guard.js.map +1 -1
- package/dist/src/tool-result-history.d.ts +3 -2
- package/dist/src/tool-result-history.d.ts.map +1 -1
- package/dist/src/tool-result-history.js +3 -2
- package/dist/src/tool-result-history.js.map +1 -1
- package/dist/src/tune-out/coordinator.d.ts +21 -0
- package/dist/src/tune-out/coordinator.d.ts.map +1 -1
- package/dist/src/tune-out/coordinator.js +142 -40
- package/dist/src/tune-out/coordinator.js.map +1 -1
- package/dist/src/types/agent.d.ts +31 -6
- package/dist/src/types/agent.d.ts.map +1 -1
- package/dist/src/types/events.d.ts +66 -9
- package/dist/src/types/events.d.ts.map +1 -1
- package/dist/src/types/framework.d.ts +69 -62
- package/dist/src/types/framework.d.ts.map +1 -1
- package/dist/src/types/module.d.ts +40 -8
- package/dist/src/types/module.d.ts.map +1 -1
- package/dist/src/types/trace.d.ts +111 -10
- package/dist/src/types/trace.d.ts.map +1 -1
- package/dist/src/usage/types.d.ts +16 -0
- package/dist/src/usage/types.d.ts.map +1 -1
- package/dist/src/usage/usage-tracker.d.ts +14 -1
- package/dist/src/usage/usage-tracker.d.ts.map +1 -1
- package/dist/src/usage/usage-tracker.js +81 -41
- package/dist/src/usage/usage-tracker.js.map +1 -1
- package/package.json +6 -8
- package/src/agent.ts +99 -12
- package/src/api/server.ts +14 -12
- package/src/clock-rows.ts +302 -0
- package/src/code-execution/engine.ts +595 -0
- package/src/code-execution/index.ts +5 -17
- package/src/code-execution/isolate/calls.ts +199 -0
- package/src/code-execution/isolate/child-entry.ts +5 -0
- package/src/code-execution/isolate/child-main.ts +132 -0
- package/src/code-execution/isolate/child.ts +327 -0
- package/src/code-execution/isolate/frames.ts +209 -0
- package/src/code-execution/isolate/output.ts +161 -0
- package/src/code-execution/isolate/prelude.ts +409 -0
- package/src/code-execution/isolate/protocol.ts +240 -0
- package/src/code-execution/isolate/render.ts +230 -0
- package/src/code-execution/isolate/runner.ts +911 -0
- package/src/code-execution/isolate/scripts.ts +479 -0
- package/src/code-execution/quickjs.wasm +0 -0
- package/src/code-execution/quickjs.wasm.LICENSES +149 -0
- package/src/code-execution/tool-definition.ts +236 -167
- package/src/deadline-timer.ts +1 -1
- package/src/framework.ts +4978 -2671
- package/src/gate/event-gate.ts +79 -17
- package/src/held-writes.ts +17 -3
- package/src/index.ts +32 -22
- package/src/mcpl/channel-registry.ts +1892 -471
- package/src/mcpl/conversation-router.ts +26 -72
- package/src/mcpl/convert-block.ts +9 -5
- package/src/mcpl/inbound-source.ts +131 -0
- package/src/mcpl/index.ts +4 -2
- package/src/mcpl/log-value.ts +9 -0
- package/src/mcpl/modern-connection.ts +162 -53
- package/src/mcpl/prose-grammar.ts +4 -5
- package/src/mcpl/protocol-family.ts +200 -22
- package/src/mcpl/push-coalescer.ts +306 -62
- package/src/mcpl/push-handler.ts +12 -54
- package/src/mcpl/reference-fetcher.ts +4 -4
- package/src/mcpl/server-connection.ts +180 -79
- package/src/mcpl/tags.ts +36 -0
- package/src/mcpl/tool-result-normalize.ts +2 -1
- package/src/mcpl/transport.ts +162 -33
- package/src/mcpl/types.ts +23 -6
- package/src/module-registry.ts +92 -13
- package/src/modules/discord/index.ts +8 -13
- package/src/modules/history/index.ts +25 -3
- package/src/modules/history/semantic.ts +29 -6
- package/src/modules/index.ts +1 -0
- package/src/modules/unknown-tool.ts +4 -1
- package/src/modules/workspace/branch-intent.ts +3 -1
- package/src/modules/workspace/edit-plan.ts +954 -0
- package/src/modules/workspace/edit-text.ts +618 -0
- package/src/modules/workspace/effects.ts +70 -19
- package/src/modules/workspace/index.ts +2293 -650
- package/src/modules/workspace/observe.ts +465 -56
- package/src/modules/workspace/reconcile.ts +14 -7
- package/src/modules/workspace/text.ts +68 -0
- package/src/modules/workspace/types.ts +211 -6
- package/src/modules/workspace/watcher.ts +3 -2
- package/src/operator-log.ts +47 -19
- package/src/recovery/discord-awareness-outbox.ts +1500 -356
- package/src/recovery/offline-branch.ts +189 -55
- package/src/recovery/recover-cli.ts +25 -4
- package/src/send-tools.ts +11 -0
- package/src/timezone.ts +4 -2
- package/src/tool-image-ledger.ts +62 -8
- package/src/tool-result-guard.ts +18 -15
- package/src/tool-result-history.ts +3 -2
- package/src/tune-out/coordinator.ts +166 -45
- package/src/types/agent.ts +32 -6
- package/src/types/events.ts +66 -9
- package/src/types/framework.ts +69 -62
- package/src/types/module.ts +40 -8
- package/src/types/trace.ts +121 -15
- package/src/usage/types.ts +16 -0
- package/src/usage/usage-tracker.ts +86 -43
- package/dist/src/code-execution/py-runner.d.ts +0 -191
- package/dist/src/code-execution/py-runner.d.ts.map +0 -1
- package/dist/src/code-execution/py-runner.js +0 -655
- package/dist/src/code-execution/py-runner.js.map +0 -1
- package/dist/src/code-execution/runtime-py.d.ts +0 -50
- package/dist/src/code-execution/runtime-py.d.ts.map +0 -1
- package/dist/src/code-execution/runtime-py.js +0 -677
- package/dist/src/code-execution/runtime-py.js.map +0 -1
- package/dist/src/mcpl/prose-stream-router.d.ts +0 -88
- package/dist/src/mcpl/prose-stream-router.d.ts.map +0 -1
- package/dist/src/mcpl/prose-stream-router.js +0 -291
- package/dist/src/mcpl/prose-stream-router.js.map +0 -1
- package/src/code-execution/py-runner.ts +0 -791
- package/src/code-execution/runtime-py.ts +0 -677
- package/src/mcpl/prose-stream-router.ts +0 -268
|
@@ -26,6 +26,7 @@ import { DENY_BY_DEFAULT, capabilityPatternMatches } from './capability-grant.js
|
|
|
26
26
|
import { DEFAULT_EAGER_FETCH_MAX_BYTES, DEFAULT_MAX_TOTAL_BYTES } from './reference-fetcher.js';
|
|
27
27
|
import { DEFAULT_MAX_INPUT_BYTES } from './tool-lifecycle.js';
|
|
28
28
|
import type { McplServerConfig, ScopeConfig } from './types.js';
|
|
29
|
+
import { kindOf } from '../config-checks.js';
|
|
29
30
|
|
|
30
31
|
/** The one revision the legacy engine offers and accepts. */
|
|
31
32
|
export const LEGACY_MCP_PROTOCOL_VERSION = '2024-11-05';
|
|
@@ -126,8 +127,21 @@ export function redactUrl(url: string | undefined): string {
|
|
|
126
127
|
* strings (serverCredentialPatterns), so strings of different servers that
|
|
127
128
|
* overlap are both replaced whole. A credential neither the configuration
|
|
128
129
|
* holds nor a dial of it sent, such as another origin's, is outside it, and
|
|
129
|
-
* so are other encodings of the ones it holds. JSON-RPC
|
|
130
|
-
* error a host's own
|
|
130
|
+
* so are other encodings of the ones it holds. A JSON-RPC answer's result
|
|
131
|
+
* passes as it is. No error a host's own call gets, whether thrown, rejected
|
|
132
|
+
* with or in an error answer's data, carries one of the strings above,
|
|
133
|
+
* whoever wrote the words: a server's words are redacted, then bounded,
|
|
134
|
+
* where an error is built from them, the strings in an error answer's data
|
|
135
|
+
* are redacted ({@link redactedData}), and an error a library raised is
|
|
136
|
+
* handed on as its name and its redacted words alone ({@link maskedError}),
|
|
137
|
+
* with a stdio launch failure's code. A failed handshake's stderr tail
|
|
138
|
+
* is redacted from a longer window of the stream, so a credential of up to
|
|
139
|
+
* 14,336 characters that reaches into it is replaced whole
|
|
140
|
+
* (McplTransport.stderrTailRedacted). A close's or a
|
|
141
|
+
* cleanup's failure carries the transports' own words, a child's pid, its
|
|
142
|
+
* server's id and the wait it was given, and passes as built. A
|
|
143
|
+
* connection's events are the framework's records' inputs, and the records
|
|
144
|
+
* redact them.
|
|
131
145
|
*
|
|
132
146
|
* A configuration that can't be read, such as one whose `env` is a getter
|
|
133
147
|
* that throws, says nothing of which strings to replace, so the whole text
|
|
@@ -135,10 +149,26 @@ export function redactUrl(url: string | undefined): string {
|
|
|
135
149
|
* runs where a throw has nowhere to go, such as inside a transport's 'error'
|
|
136
150
|
* listener.
|
|
137
151
|
*/
|
|
138
|
-
export function redactServerText(text: unknown, config: Pick<McplServerConfig, 'url' | 'token' | 'env'>): string {
|
|
152
|
+
export function redactServerText(text: unknown, config: Pick<McplServerConfig, 'url' | 'token' | 'env' | 'tokenTransport'>): string {
|
|
139
153
|
return serverTextRedactor(config)(text);
|
|
140
154
|
}
|
|
141
155
|
|
|
156
|
+
/** A {@link serverTextRedactor}: a redaction of one configuration's
|
|
157
|
+
* credentials, which reads the configuration until a build succeeds. */
|
|
158
|
+
export interface ServerTextRedactor {
|
|
159
|
+
(text: unknown, from?: number): string;
|
|
160
|
+
/**
|
|
161
|
+
* This redaction for one piece of work, such as building one error from a
|
|
162
|
+
* server's words and data: its pattern built now if it isn't, so the
|
|
163
|
+
* configuration is read at most once for all the work's texts, and every
|
|
164
|
+
* text withheld if it can't be read.
|
|
165
|
+
*/
|
|
166
|
+
now(): Redaction;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/** The redaction of a configuration that can't be read. */
|
|
170
|
+
const withheld: Redaction = () => WITHHELD_TEXT;
|
|
171
|
+
|
|
142
172
|
/**
|
|
143
173
|
* {@link redactServerText} for one configuration, its strings found and its
|
|
144
174
|
* pattern built once, and again once a dial has sent something new
|
|
@@ -146,29 +176,108 @@ export function redactServerText(text: unknown, config: Pick<McplServerConfig, '
|
|
|
146
176
|
* line. A build that can't read the configuration withholds that call's
|
|
147
177
|
* text, and the next call builds again.
|
|
148
178
|
*/
|
|
149
|
-
export function serverTextRedactor(config: Pick<McplServerConfig, 'url' | 'token' | 'env'>):
|
|
179
|
+
export function serverTextRedactor(config: Pick<McplServerConfig, 'url' | 'token' | 'env' | 'tokenTransport'>): ServerTextRedactor {
|
|
150
180
|
let built = -1;
|
|
151
|
-
let redact!:
|
|
152
|
-
|
|
181
|
+
let redact!: Redaction;
|
|
182
|
+
const now = (): Redaction => {
|
|
153
183
|
const version = dialsSent.get(config)?.version ?? 0;
|
|
154
184
|
if (version !== built) {
|
|
155
185
|
let patterns: CredentialPattern[];
|
|
156
186
|
try {
|
|
157
187
|
patterns = serverCredentialPatterns(config);
|
|
158
188
|
} catch {
|
|
159
|
-
return
|
|
189
|
+
return withheld;
|
|
160
190
|
}
|
|
161
191
|
redact = credentialRedactor(patterns);
|
|
162
192
|
built = version;
|
|
163
193
|
}
|
|
164
|
-
return redact
|
|
194
|
+
return redact;
|
|
165
195
|
};
|
|
196
|
+
return Object.assign((text: unknown, from?: number) => now()(text, from), { now });
|
|
166
197
|
}
|
|
167
198
|
|
|
168
199
|
/** What a redaction gives in place of text when the configuration it
|
|
169
200
|
* redacts with can't be read ({@link redactServerText}). */
|
|
170
201
|
export const WITHHELD_TEXT = "[withheld: the server's configuration couldn't be read to redact this]";
|
|
171
202
|
|
|
203
|
+
/** What {@link redactedData} gives in place of data nested deeper than it
|
|
204
|
+
* walks. */
|
|
205
|
+
export const TOO_DEEP_TEXT = '[withheld: nested too deep to redact]';
|
|
206
|
+
|
|
207
|
+
/** How deep {@link redactedData} walks. A server's JSON can nest deeper than
|
|
208
|
+
* a recursive walk's stack holds (10,000 levels overflow it), and the walk
|
|
209
|
+
* runs where a throw would leave the request it answers unsettled. */
|
|
210
|
+
const REDACTED_DATA_DEPTH = 64;
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* The data a server's error answer carries beside its words, with every
|
|
214
|
+
* string in it, an object's keys included, redacted (`redact`, a server's
|
|
215
|
+
* {@link serverTextRedactor}, built once for the walk), so an error handed
|
|
216
|
+
* to a host carries no credential its configuration holds. Arrays and plain
|
|
217
|
+
* objects are walked, to a depth of 64; deeper data is
|
|
218
|
+
* {@link TOO_DEEP_TEXT}. A number goes as its redacted text if its digits,
|
|
219
|
+
* as JavaScript reads the number, hold a credential: a number with more
|
|
220
|
+
* significant digits than a double holds (about 15) has lost its last ones
|
|
221
|
+
* before anything sees it, so a credential sent as such a number isn't
|
|
222
|
+
* matched. A redacted key that comes out the same as another key is
|
|
223
|
+
* numbered, so every entry is kept under a name of its own, and a key the
|
|
224
|
+
* redaction leaves alone keeps its name. Any other value, null or a
|
|
225
|
+
* boolean, is kept as it is. With a configuration that can't be read, the
|
|
226
|
+
* data as a whole is {@link WITHHELD_TEXT}.
|
|
227
|
+
*/
|
|
228
|
+
export function redactedData(value: unknown, redactor: ServerTextRedactor | Redaction): unknown {
|
|
229
|
+
const redact = 'now' in redactor ? redactor.now() : redactor;
|
|
230
|
+
if (redact === withheld) return value === undefined ? undefined : WITHHELD_TEXT;
|
|
231
|
+
const walk = (item: unknown, depth: number): unknown => {
|
|
232
|
+
if (typeof item === 'string') return redact(item);
|
|
233
|
+
if (typeof item === 'number') {
|
|
234
|
+
const digits = String(item);
|
|
235
|
+
const redacted = redact(digits);
|
|
236
|
+
return redacted === digits ? item : redacted;
|
|
237
|
+
}
|
|
238
|
+
if (item === null || typeof item !== 'object') return item;
|
|
239
|
+
const walked = Array.isArray(item) || [Object.prototype, null].includes(Object.getPrototypeOf(item));
|
|
240
|
+
if (!walked) return item;
|
|
241
|
+
if (depth >= REDACTED_DATA_DEPTH) return TOO_DEEP_TEXT;
|
|
242
|
+
if (Array.isArray(item)) return item.map((entry) => walk(entry, depth + 1));
|
|
243
|
+
// A key the redaction leaves as it is keeps its name; a redacted one
|
|
244
|
+
// takes the first name no other key has, so no entry is lost or moved.
|
|
245
|
+
const entries = Object.entries(item);
|
|
246
|
+
const names = entries.map(([key]) => redact(key));
|
|
247
|
+
const taken = new Set(names.filter((name, n) => name === entries[n][0]));
|
|
248
|
+
// Each name's next number to try, so keys that redact alike don't search
|
|
249
|
+
// from 2 again: every number below it was taken, and stays taken.
|
|
250
|
+
const next = new Map<string, number>();
|
|
251
|
+
return Object.fromEntries(entries.map(([key, entry], n) => {
|
|
252
|
+
let name = names[n];
|
|
253
|
+
if (name !== key) {
|
|
254
|
+
const base = name;
|
|
255
|
+
let k = next.get(base) ?? 2;
|
|
256
|
+
while (taken.has(name)) name = `${base} (${k++})`;
|
|
257
|
+
next.set(base, k);
|
|
258
|
+
taken.add(name);
|
|
259
|
+
}
|
|
260
|
+
return [name, walk(entry, depth + 1)];
|
|
261
|
+
}));
|
|
262
|
+
};
|
|
263
|
+
return walk(value, 0);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* An error a library raised, as the framework hands it to a host: its name,
|
|
268
|
+
* which is its class's, as it is, and its words redacted (`redact`, a
|
|
269
|
+
* server's {@link serverTextRedactor}), and nothing else. A library's error
|
|
270
|
+
* can carry the url it dialed elsewhere than in its message (Bun's fetch
|
|
271
|
+
* errors keep it in `path`, its path and query included), or keep the raw
|
|
272
|
+
* error it wraps as its `cause`, so none of that is carried over.
|
|
273
|
+
*/
|
|
274
|
+
export function maskedError(error: unknown, redact: (text: unknown) => string): Error {
|
|
275
|
+
const masked = new Error(redact(error instanceof Error ? error.message : error));
|
|
276
|
+
// Not enumerable, as an error's own name is not.
|
|
277
|
+
if (error instanceof Error) Object.defineProperty(masked, 'name', { value: error.name, writable: true, configurable: true });
|
|
278
|
+
return masked;
|
|
279
|
+
}
|
|
280
|
+
|
|
172
281
|
/**
|
|
173
282
|
* What a configuration's dials sent that the configuration doesn't hold: the
|
|
174
283
|
* urls dialed with an access provider's token, and the provider's tokens,
|
|
@@ -208,10 +317,12 @@ export function noteDialSent(config: object, sent: { readonly url?: string; read
|
|
|
208
317
|
}
|
|
209
318
|
|
|
210
319
|
/**
|
|
211
|
-
* The url a dial sends. A WebSocket dial
|
|
212
|
-
* parameter, and setting it makes URLSearchParams
|
|
213
|
-
* again, form-encoded (a space as `+`), so the url as
|
|
214
|
-
* the url as configured.
|
|
320
|
+
* The url a dial sends. A WebSocket dial that sends its token in the query
|
|
321
|
+
* sets it as the `token` parameter, and setting it makes URLSearchParams
|
|
322
|
+
* write the whole query again, form-encoded (a space as `+`), so the url as
|
|
323
|
+
* sent can differ from the url as configured. A header-mode WebSocket dial,
|
|
324
|
+
* which is given no token here, and an http(s) dial send the url as
|
|
325
|
+
* configured.
|
|
215
326
|
*/
|
|
216
327
|
export function urlAsDialed(url: URL, token: string | null | undefined): URL {
|
|
217
328
|
const dialed = new URL(url);
|
|
@@ -232,7 +343,7 @@ export interface CredentialPattern {
|
|
|
232
343
|
* that begins inside another configuration's, or shares its start, can't
|
|
233
344
|
* leave any of that one in place.
|
|
234
345
|
*/
|
|
235
|
-
export function serverCredentialPatterns(config: Pick<McplServerConfig, 'url' | 'token' | 'env'>): CredentialPattern[] {
|
|
346
|
+
export function serverCredentialPatterns(config: Pick<McplServerConfig, 'url' | 'token' | 'env' | 'tokenTransport'>): CredentialPattern[] {
|
|
236
347
|
// Strings replaced wherever they occur (after an escape or inside a longer
|
|
237
348
|
// token too), and name=value pairs, replaced only where no letter or digit
|
|
238
349
|
// adjoins them, so a pair such as v=2 leaves dev=2 alone. A pair's value is
|
|
@@ -329,7 +440,7 @@ export function serverCredentialPatterns(config: Pick<McplServerConfig, 'url' |
|
|
|
329
440
|
const configuredUrl = config.url ?? '';
|
|
330
441
|
let url: URL | undefined;
|
|
331
442
|
try { url = new URL(configuredUrl); } catch { /* Still remove the static token. */ }
|
|
332
|
-
if (url) addUrl(urlAsDialed(url, config.token));
|
|
443
|
+
if (url) addUrl(urlAsDialed(url, config.tokenTransport === 'header' ? null : config.token));
|
|
333
444
|
// What the dials sent beyond that: urls dialed with an access provider's
|
|
334
445
|
// token, and its tokens sent in a header.
|
|
335
446
|
const sent = dialsSent.get(config);
|
|
@@ -367,6 +478,15 @@ export function serverCredentialPatterns(config: Pick<McplServerConfig, 'url' |
|
|
|
367
478
|
];
|
|
368
479
|
}
|
|
369
480
|
|
|
481
|
+
/**
|
|
482
|
+
* A redaction: `text` with the credentials it holds replaced, and only what
|
|
483
|
+
* lies from its `from`th code unit on (0 when left out). A credential that
|
|
484
|
+
* begins before `from` and reaches past it is matched whole and replaced
|
|
485
|
+
* whole, so a part of the text can be given redacted as the whole text has
|
|
486
|
+
* it.
|
|
487
|
+
*/
|
|
488
|
+
export type Redaction = (text: unknown, from?: number) => string;
|
|
489
|
+
|
|
370
490
|
/**
|
|
371
491
|
* Every place one of the given patterns matches becomes `redacted`,
|
|
372
492
|
* overlapping places included: the matches are found in the text as given,
|
|
@@ -374,13 +494,13 @@ export function serverCredentialPatterns(config: Pick<McplServerConfig, 'url' |
|
|
|
374
494
|
* replaced as one. So two strings that overlap, one's end being the other's
|
|
375
495
|
* start, are both replaced whole, and the replacement is never scanned.
|
|
376
496
|
*/
|
|
377
|
-
export function credentialRedactor(patterns: readonly CredentialPattern[]):
|
|
378
|
-
if (patterns.length === 0) return asText;
|
|
497
|
+
export function credentialRedactor(patterns: readonly CredentialPattern[]): Redaction {
|
|
498
|
+
if (patterns.length === 0) return (text, from = 0) => asText(text).slice(from);
|
|
379
499
|
// Longest first, so at each place the longest string that matches there is
|
|
380
500
|
// the match.
|
|
381
501
|
const sources = [...patterns].sort((a, b) => b.value.length - a.value.length).map(({ source }) => source);
|
|
382
502
|
const pattern = new RegExp([...new Set(sources)].join('|'), 'g');
|
|
383
|
-
return (text) => {
|
|
503
|
+
return (text, from = 0) => {
|
|
384
504
|
const input = asText(text);
|
|
385
505
|
const spans: Array<[start: number, end: number]> = [];
|
|
386
506
|
pattern.lastIndex = 0;
|
|
@@ -395,12 +515,13 @@ export function credentialRedactor(patterns: readonly CredentialPattern[]): (tex
|
|
|
395
515
|
pattern.lastIndex = start + 1;
|
|
396
516
|
}
|
|
397
517
|
let redacted = '';
|
|
398
|
-
let
|
|
518
|
+
let at = from;
|
|
399
519
|
for (const [start, end] of spans) {
|
|
400
|
-
|
|
401
|
-
|
|
520
|
+
if (end <= from) continue;
|
|
521
|
+
redacted += `${input.slice(at, start)}redacted`;
|
|
522
|
+
at = end;
|
|
402
523
|
}
|
|
403
|
-
return redacted + input.slice(
|
|
524
|
+
return redacted + input.slice(at);
|
|
404
525
|
};
|
|
405
526
|
}
|
|
406
527
|
|
|
@@ -583,6 +704,22 @@ export function serverConfigProblems(config: McplServerConfig): string[] {
|
|
|
583
704
|
);
|
|
584
705
|
}
|
|
585
706
|
}
|
|
707
|
+
if (config.tokenTransport !== undefined && config.tokenTransport !== null) {
|
|
708
|
+
if (binding.transport !== 'websocket') {
|
|
709
|
+
problems.push(
|
|
710
|
+
`MCP server "${config.id}": "tokenTransport" applies only to a ws(s):// server; an http(s):// server always sends its credential as a header, and a stdio server sends none`,
|
|
711
|
+
);
|
|
712
|
+
} else {
|
|
713
|
+
const problem = tokenTransportProblem(config, new URL(config.url!));
|
|
714
|
+
if (problem) problems.push(problem);
|
|
715
|
+
// A static token known now that no dial could send as configured.
|
|
716
|
+
else if (config.tokenTransport === 'header' && config.token && !headerCarries(config.token)) {
|
|
717
|
+
problems.push(
|
|
718
|
+
`MCP server "${config.id}": with tokenTransport 'header', "token" must be printable ASCII (U+0020 to U+007E) with no space at either end, which is all a header carries as configured`,
|
|
719
|
+
);
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
}
|
|
586
723
|
if (config.protocol !== undefined) {
|
|
587
724
|
if (config.protocol !== 'legacy' && config.protocol !== 'modern') {
|
|
588
725
|
problems.push(`MCP server "${config.id}": protocol must be 'legacy' or 'modern', got ${JSON.stringify(config.protocol)}`);
|
|
@@ -596,7 +733,7 @@ export function serverConfigProblems(config: McplServerConfig): string[] {
|
|
|
596
733
|
if (binding.family === 'modern') {
|
|
597
734
|
if (timeout !== undefined && !(Number.isInteger(timeout) && timeout >= 1 && timeout <= MAX_TIMER_MS)) {
|
|
598
735
|
problems.push(
|
|
599
|
-
`MCP server "${config.id}": requestTimeoutMs must be an integer from 1 to ${MAX_TIMER_MS} for a modern server (got ${
|
|
736
|
+
`MCP server "${config.id}": requestTimeoutMs must be an integer from 1 to ${MAX_TIMER_MS} for a modern server (got ${asText(timeout)}); every modern call has a deadline`,
|
|
600
737
|
);
|
|
601
738
|
}
|
|
602
739
|
for (const path of mcplPolicyGrants(config)) {
|
|
@@ -620,6 +757,47 @@ export function serverConfigProblems(config: McplServerConfig): string[] {
|
|
|
620
757
|
return problems;
|
|
621
758
|
}
|
|
622
759
|
|
|
760
|
+
/**
|
|
761
|
+
* What's wrong with a WebSocket server's `tokenTransport`, as a message, or
|
|
762
|
+
* undefined: a value that is neither mode, or `'header'` with a url that
|
|
763
|
+
* carries a `token` query parameter of its own, which would still put a
|
|
764
|
+
* credential in the url, or userinfo, whose Basic credential the Bearer
|
|
765
|
+
* header replaces whenever it carries a credential, since a request has one
|
|
766
|
+
* Authorization header. null counts as not set, as config-checks.ts has it.
|
|
767
|
+
* The refusal names the value's kind, never the value, which could be a
|
|
768
|
+
* credential pasted into the wrong field, and quotes nothing of the url.
|
|
769
|
+
*/
|
|
770
|
+
export function tokenTransportProblem(config: Pick<McplServerConfig, 'id' | 'tokenTransport'>, url: URL): string | undefined {
|
|
771
|
+
// A configuration read from JSON can hold anything here.
|
|
772
|
+
const mode: unknown = config.tokenTransport;
|
|
773
|
+
if (mode === undefined || mode === null || mode === 'query') return undefined;
|
|
774
|
+
if (mode !== 'header') {
|
|
775
|
+
return `MCP server "${config.id}": tokenTransport must be 'query' or 'header', not ${typeof mode === 'string' ? 'another string' : kindOf(mode)}`;
|
|
776
|
+
}
|
|
777
|
+
if (url.searchParams.has('token')) {
|
|
778
|
+
return `MCP server "${config.id}": with tokenTransport 'header' the url must not carry a "token" query parameter, which would still put a credential in it; give it as "token" or "accessProvider"`;
|
|
779
|
+
}
|
|
780
|
+
if (url.username || url.password) {
|
|
781
|
+
return `MCP server "${config.id}": with tokenTransport 'header' the url must not carry userinfo (user:password@), since the Bearer header replaces the userinfo's Basic credential whenever it carries a credential; leave out "tokenTransport" to send the userinfo as before, or give the credential as "token" or "accessProvider"`;
|
|
782
|
+
}
|
|
783
|
+
return undefined;
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
/**
|
|
787
|
+
* Whether a header-mode credential can go in an `Authorization: Bearer`
|
|
788
|
+
* header as it is: printable ASCII (U+0020 to U+007E), with no space at
|
|
789
|
+
* either end. Node and Bun send exactly those bytes, so the server checks the
|
|
790
|
+
* credential that was configured, and the redactor's patterns match whatever
|
|
791
|
+
* it echoes. Outside that set a header can't carry it as configured: a space
|
|
792
|
+
* at either end is dropped (by Bun before sending, by an HTTP parser on
|
|
793
|
+
* arrival), a control character can't go in a header, and a character past
|
|
794
|
+
* U+007E goes out as different bytes from Node and from Bun, or is refused
|
|
795
|
+
* when the socket is built.
|
|
796
|
+
*/
|
|
797
|
+
export function headerCarries(credential: string): boolean {
|
|
798
|
+
return /^[\x21-\x7e](?:[\x20-\x7e]*[\x21-\x7e])?$/.test(credential);
|
|
799
|
+
}
|
|
800
|
+
|
|
623
801
|
/** A host a connection to which never leaves this machine, as the WHATWG URL
|
|
624
802
|
* parser gives it. The unspecified addresses count: a connection to 0.0.0.0
|
|
625
803
|
* or [::] reaches this host. So do 127.0.0.0/8 written as an IPv4-mapped
|