@zackbart/connecta 0.34.1 → 0.36.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/CHANGELOG.md +418 -0
- package/README.md +65 -105
- package/SECURITY.md +3 -2
- package/bin/connecta.mjs +41 -16
- package/bin/version.mjs +1 -1
- package/dist/access-tokens.d.ts +2 -1
- package/dist/access-tokens.js +66 -30
- package/dist/activity.d.ts +1 -1
- package/dist/activity.js +2 -0
- package/dist/agent-config.d.ts +23 -0
- package/dist/agent-config.js +59 -0
- package/dist/agent-description.js +16 -0
- package/dist/agent-identity.js +4 -4
- package/dist/agent-observation.js +39 -0
- package/dist/auth/clerk-sdk/client.d.ts +2 -0
- package/dist/auth/clerk-sdk/generated.js +554 -563
- package/dist/auth/clerk-transport.js +70 -3
- package/dist/auth/clerk.d.ts +13 -0
- package/dist/auth/clerk.js +653 -246
- package/dist/auth/cloudflare-access.js +46 -42
- package/dist/auth/downstream-client-metadata.js +2 -2
- package/dist/auth/downstream-oauth.js +2044 -1161
- package/dist/auth/downstream-revocation.js +88 -88
- package/dist/auth/native-call.js +20 -0
- package/dist/auth/native.js +184 -0
- package/dist/auth/oauth-start-reset.js +11 -5
- package/dist/auth/oauth-token-response.js +121 -102
- package/dist/auth/oauth-v2-migration.js +97 -78
- package/dist/auth/renewable-grant.js +10 -0
- package/dist/auth/static-oauth.js +751 -281
- package/dist/auth/vercel-agent.js +266 -0
- package/dist/auth-admission.js +204 -0
- package/dist/auth-elicitation.js +350 -241
- package/dist/authorization-handoff.js +164 -90
- package/dist/call-admission-context.js +3 -10
- package/dist/call-admission.js +2 -0
- package/dist/call-classification.js +9 -0
- package/dist/call-recovery.js +32 -13
- package/dist/canonical-json.js +8 -0
- package/dist/catalog-cache.js +369 -213
- package/dist/catalog-service.js +659 -530
- package/dist/catalog.js +5 -1
- package/dist/concurrency.js +0 -25
- package/dist/config-defaults.d.ts +1 -0
- package/dist/config-defaults.js +1 -0
- package/dist/config-schema.d.ts +3 -1
- package/dist/config-schema.js +13 -3
- package/dist/config.d.ts +40 -6
- package/dist/config.js +40 -26
- package/dist/connector-caller.d.ts +4 -0
- package/dist/connector-caller.js +17 -4
- package/dist/connectors/api-connector.d.ts +29 -7
- package/dist/connectors/api-connector.js +145 -57
- package/dist/connectors/guarded-fetch.d.ts +51 -17
- package/dist/connectors/guarded-fetch.js +215 -121
- package/dist/connectors/negotiation-cache.js +20 -10
- package/dist/connectors/remote-mcp.d.ts +10 -30
- package/dist/connectors/remote-mcp.js +955 -563
- package/dist/d1.js +10 -243
- package/dist/derived-context.js +5 -0
- package/dist/describe-config.d.ts +3 -1
- package/dist/describe-config.js +2 -0
- package/dist/downstream-input.js +347 -260
- package/dist/errors.d.ts +87 -6
- package/dist/errors.js +114 -4
- package/dist/execute.js +87 -50
- package/dist/executor-admission.js +3 -0
- package/dist/executors/quickjs.js +163 -112
- package/dist/guarded-transport.js +50 -0
- package/dist/guest-runtime.js +1 -1
- package/dist/http/client.js +439 -0
- package/dist/http/errors.js +558 -0
- package/dist/http/fields.js +49 -0
- package/dist/http/hatch-paging.js +318 -0
- package/dist/http/hatch.js +1279 -0
- package/dist/http/json-schema.js +267 -0
- package/dist/http/node-transport.js +241 -0
- package/dist/http/oauth.js +162 -0
- package/dist/http/paging.js +227 -0
- package/dist/http/provider.js +221 -0
- package/dist/http/safety.js +82 -0
- package/dist/http/services.js +79 -0
- package/dist/http/tools.js +379 -0
- package/dist/http/vendor-index.js +138 -0
- package/dist/http/vendor.js +448 -0
- package/dist/http/write-request.js +66 -0
- package/dist/http-policy.d.ts +11 -0
- package/dist/http-policy.js +45 -0
- package/dist/inbound-credential.js +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +4 -0
- package/dist/invocation-auth.js +30 -19
- package/dist/invocation.js +218 -85
- package/dist/mcp-result.js +0 -4
- package/dist/membership.d.ts +4 -0
- package/dist/meta-output.js +1 -1
- package/dist/meta-tools.js +531 -406
- package/dist/native-recovery.js +52 -0
- package/dist/native-tools.js +382 -0
- package/dist/node.d.ts +4 -3
- package/dist/node.js +45 -8
- package/dist/oauth-handoff.js +177 -104
- package/dist/oauth-partition.js +6 -20
- package/dist/oauth-sealing.js +6 -7
- package/dist/operation-vocabulary.js +101 -0
- package/dist/operator-record.d.ts +2 -2
- package/dist/operator-record.js +17 -4
- package/dist/operator-ui/contract.d.ts +8 -3
- package/dist/operator-ui/generated.js +4 -4
- package/dist/operator-ui/model.d.ts +2 -3
- package/dist/program-writes.js +47 -26
- package/dist/provider-call-facts.d.ts +115 -0
- package/dist/provider-call-facts.js +182 -0
- package/dist/provider-call.d.ts +112 -0
- package/dist/provider-call.js +271 -0
- package/dist/provider.d.ts +65 -31
- package/dist/provider.js +116 -39
- package/dist/providers/_shared/google/hatch.js +91 -0
- package/dist/providers/_shared/google/kit.js +427 -0
- package/dist/providers/_shared/google/result-size.js +15 -2
- package/dist/providers/_shared/google/service-account.d.ts +2 -1
- package/dist/providers/_shared/google/service-account.js +8 -4
- package/dist/providers/_shared/google/workspace.d.ts +6 -210
- package/dist/providers/_shared/google/workspace.js +6 -425
- package/dist/providers/_shared/rest/compact-index.js +86 -0
- package/dist/providers/_shared/rest/kit.js +146 -0
- package/dist/providers/_shared/rest/operation-index.js +230 -14
- package/dist/providers/_shared/rest/response-media.js +11 -0
- package/dist/providers/_shared/rest/value-safety.js +353 -195
- package/dist/providers/_shared/sensitive-fields.js +27 -0
- package/dist/providers/breeze/api.js +584 -0
- package/dist/providers/breeze/index.d.ts +1 -3
- package/dist/providers/breeze/index.js +67 -1420
- package/dist/providers/breeze/openapi.generated.js +60 -0
- package/dist/providers/breeze/skill.generated.js +2 -6
- package/dist/providers/breeze/tools.js +696 -0
- package/dist/providers/ccb/api.js +496 -0
- package/dist/providers/ccb/index.d.ts +15 -37
- package/dist/providers/ccb/index.js +77 -1702
- package/dist/providers/ccb/lib/constants.d.ts +34 -0
- package/dist/providers/ccb/lib/constants.js +74 -0
- package/dist/providers/ccb/lib/guide.js +9 -0
- package/dist/providers/ccb/lib/verdicts.js +387 -0
- package/dist/providers/ccb/openapi.generated.js +397 -0
- package/dist/providers/ccb/safety.js +295 -0
- package/dist/providers/ccb/skill.generated.js +2 -6
- package/dist/providers/ccb/tools.js +853 -0
- package/dist/providers/cloudflare/api.js +1066 -0
- package/dist/providers/cloudflare/index.d.ts +5 -22
- package/dist/providers/cloudflare/index.js +79 -197
- package/dist/providers/cloudflare/lib/config.d.ts +16 -0
- package/dist/providers/cloudflare/lib/config.js +2 -0
- package/dist/providers/cloudflare/lib/discovery.js +29 -0
- package/dist/providers/cloudflare/{graphql.js → lib/graphql.js} +1 -1
- package/dist/providers/cloudflare/lib/hatch.js +103 -0
- package/dist/providers/cloudflare/lib/path-bounds.js +28 -0
- package/dist/providers/cloudflare/lib/response-media.js +75 -0
- package/dist/providers/cloudflare/openapi.generated.js +4 -3
- package/dist/providers/cloudflare/{value-safety.js → safety.js} +487 -0
- package/dist/providers/cloudflare/skill.generated.js +2 -10
- package/dist/providers/cloudflare/tools.js +360 -0
- package/dist/providers/docs/api.js +51 -0
- package/dist/providers/docs/index.d.ts +1 -12
- package/dist/providers/docs/index.js +53 -1165
- package/dist/providers/docs/lib/constants.d.ts +18 -0
- package/dist/providers/docs/lib/constants.js +18 -0
- package/dist/providers/docs/lib/discovery.js +26 -0
- package/dist/providers/docs/lib/requests.js +48 -0
- package/dist/providers/docs/lib/schemas.js +168 -0
- package/dist/providers/docs/openapi.generated.js +16 -0
- package/dist/providers/docs/safety.js +54 -0
- package/dist/providers/docs/skill.generated.js +2 -6
- package/dist/providers/docs/tools.js +801 -0
- package/dist/providers/drive/api.js +177 -0
- package/dist/providers/drive/index.d.ts +1 -12
- package/dist/providers/drive/index.js +38 -1448
- package/dist/providers/drive/lib/constants.d.ts +6 -0
- package/dist/providers/drive/lib/constants.js +6 -0
- package/dist/providers/drive/lib/contracts.js +532 -0
- package/dist/providers/drive/lib/hatch.js +197 -0
- package/dist/providers/drive/openapi.generated.js +77 -0
- package/dist/providers/drive/safety.js +90 -0
- package/dist/providers/drive/skill.generated.js +2 -6
- package/dist/providers/drive/tools.js +1290 -0
- package/dist/providers/forms/api.js +71 -0
- package/dist/providers/forms/index.d.ts +1 -12
- package/dist/providers/forms/index.js +49 -1145
- package/dist/providers/forms/lib/constants.d.ts +14 -0
- package/dist/providers/forms/lib/constants.js +19 -0
- package/dist/providers/forms/lib/hatch.js +72 -0
- package/dist/providers/forms/openapi.generated.js +23 -0
- package/dist/providers/forms/safety.js +34 -0
- package/dist/providers/forms/skill.generated.js +2 -8
- package/dist/providers/forms/tools.js +1023 -0
- package/dist/providers/github/api.js +150 -0
- package/dist/providers/github/index.d.ts +4 -5
- package/dist/providers/github/index.js +30 -87
- package/dist/providers/github/{auth.d.ts → lib/auth.d.ts} +5 -3
- package/dist/providers/github/{auth.js → lib/auth.js} +40 -43
- package/dist/providers/github/lib/discovery.js +132 -0
- package/dist/providers/github/lib/operations.js +58 -0
- package/dist/providers/github/{scope.d.ts → lib/scope.d.ts} +2 -0
- package/dist/providers/github/{scope.js → lib/scope.js} +25 -1
- package/dist/providers/github/openapi.generated.js +1216 -0
- package/dist/providers/github/safety.js +216 -0
- package/dist/providers/github/skill.generated.js +2 -5
- package/dist/providers/github/tools.js +506 -0
- package/dist/providers/gmail/api.js +114 -0
- package/dist/providers/gmail/index.d.ts +1 -12
- package/dist/providers/gmail/index.js +73 -1621
- package/dist/providers/gmail/lib/constants.d.ts +13 -0
- package/dist/providers/gmail/lib/constants.js +16 -0
- package/dist/providers/gmail/lib/index.js +173 -0
- package/dist/providers/gmail/lib/schemas.js +176 -0
- package/dist/providers/gmail/lib/threading.js +120 -0
- package/dist/providers/gmail/openapi.generated.js +92 -0
- package/dist/providers/gmail/safety.js +21 -0
- package/dist/providers/gmail/skill.generated.js +2 -6
- package/dist/providers/gmail/tools.js +1435 -0
- package/dist/providers/overflow/api.js +1008 -0
- package/dist/providers/overflow/index.d.ts +1 -17
- package/dist/providers/overflow/index.js +60 -1488
- package/dist/providers/overflow/skill.generated.js +2 -5
- package/dist/providers/overflow/tools.js +873 -0
- package/dist/providers/planning-center/api.js +467 -0
- package/dist/providers/planning-center/index.d.ts +4 -35
- package/dist/providers/planning-center/index.js +69 -2445
- package/dist/providers/planning-center/lib/constants.d.ts +58 -0
- package/dist/providers/planning-center/lib/constants.js +83 -0
- package/dist/providers/planning-center/lib/discovery.js +40 -0
- package/dist/providers/planning-center/lib/guide.js +39 -0
- package/dist/providers/planning-center/lib/json-api.js +83 -0
- package/dist/providers/planning-center/lib/verdicts.js +1758 -0
- package/dist/providers/planning-center/openapi.generated.js +1764 -0
- package/dist/providers/planning-center/safety.js +188 -0
- package/dist/providers/planning-center/skill.generated.js +2 -27
- package/dist/providers/planning-center/tools.js +1010 -0
- package/dist/providers/quickbooks/api.js +299 -0
- package/dist/providers/quickbooks/index.d.ts +13 -0
- package/dist/providers/quickbooks/index.js +93 -0
- package/dist/providers/quickbooks/lib/query.js +118 -0
- package/dist/providers/quickbooks/lib/writes.js +168 -0
- package/dist/providers/quickbooks/safety.js +222 -0
- package/dist/providers/quickbooks/skill.generated.js +5 -0
- package/dist/providers/quickbooks/tools.js +117 -0
- package/dist/providers/sheets/api.js +133 -0
- package/dist/providers/sheets/index.d.ts +4 -16
- package/dist/providers/sheets/index.js +61 -1172
- package/dist/providers/sheets/lib/constants.d.ts +14 -0
- package/dist/providers/sheets/lib/constants.js +14 -0
- package/dist/providers/sheets/lib/hatch.js +163 -0
- package/dist/providers/sheets/lib/requests.js +105 -0
- package/dist/providers/sheets/lib/schemas.js +138 -0
- package/dist/providers/sheets/openapi.generated.js +30 -0
- package/dist/providers/sheets/safety.js +27 -0
- package/dist/providers/sheets/skill.generated.js +2 -7
- package/dist/providers/sheets/tools.js +733 -0
- package/dist/providers/slides/api.js +147 -0
- package/dist/providers/slides/index.d.ts +2 -10
- package/dist/providers/slides/index.js +48 -2555
- package/dist/providers/slides/lib/constants.d.ts +11 -0
- package/dist/providers/slides/lib/constants.js +11 -0
- package/dist/providers/slides/lib/requests.js +60 -0
- package/dist/providers/slides/lib/schemas.js +565 -0
- package/dist/providers/slides/openapi.generated.js +18 -0
- package/dist/providers/slides/skill.generated.js +2 -6
- package/dist/providers/slides/tools.js +1968 -0
- package/dist/providers/stripe/api.js +401 -0
- package/dist/providers/stripe/index.d.ts +5 -27
- package/dist/providers/stripe/index.js +74 -210
- package/dist/providers/stripe/lib/config.d.ts +4 -0
- package/dist/providers/stripe/lib/config.js +2 -0
- package/dist/providers/stripe/openapi.generated.js +4 -3
- package/dist/providers/stripe/{value-safety.js → safety.js} +5 -5
- package/dist/providers/stripe/skill.generated.js +2 -11
- package/dist/providers/stripe/tools.js +77 -0
- package/dist/providers/tithely/api.js +531 -0
- package/dist/providers/tithely/index.d.ts +17 -0
- package/dist/providers/tithely/index.js +86 -965
- package/dist/providers/tithely/skill.generated.js +2 -5
- package/dist/providers/tithely/tools.js +426 -0
- package/dist/providers/vercel/api.js +551 -0
- package/dist/providers/vercel/index.d.ts +9 -25
- package/dist/providers/vercel/index.js +65 -260
- package/dist/providers/vercel/lib/config.d.ts +2 -0
- package/dist/providers/vercel/lib/config.js +2 -0
- package/dist/providers/vercel/lib/index.js +117 -0
- package/dist/providers/vercel/lib/logs.js +100 -0
- package/dist/providers/vercel/lib/pin.js +270 -0
- package/dist/providers/vercel/openapi.generated.js +10 -5
- package/dist/providers/vercel/{value-safety.js → safety.js} +247 -38
- package/dist/providers/vercel/skill.generated.js +2 -7
- package/dist/providers/vercel/tools.js +642 -0
- package/dist/redaction-identity.js +47 -0
- package/dist/redaction-marker.js +125 -0
- package/dist/registry.d.ts +21 -15
- package/dist/registry.js +409 -376
- package/dist/routes/access-tokens.js +1 -1
- package/dist/routes/actor-labels.js +1 -1
- package/dist/routes/connect.js +1 -1
- package/dist/routes/dispatch.js +103 -0
- package/dist/routes/mcp.js +170 -79
- package/dist/routes/oauth.js +6 -1
- package/dist/routes/operator.js +2 -2
- package/dist/routes/shared.d.ts +5 -4
- package/dist/routes/shared.js +244 -177
- package/dist/routes/skills.js +10 -8
- package/dist/routes/ui-config.js +27 -3
- package/dist/routes/ui-data.js +21 -20
- package/dist/routes/ui.js +1 -1
- package/dist/runtime/call-admission.js +0 -26
- package/dist/runtime/call-entry.js +30 -0
- package/dist/runtime/call.js +552 -0
- package/dist/runtime/connector-scope.js +7 -0
- package/dist/runtime/credential-probe.js +34 -0
- package/dist/runtime/executor.js +40 -0
- package/dist/runtime/native-storage.js +63 -0
- package/dist/runtime/registry.js +27 -0
- package/dist/runtime/request-scope.js +72 -0
- package/dist/runtime/run.js +15 -7
- package/dist/runtime/shared-read.js +34 -5
- package/dist/runtime/storage.js +34 -21
- package/dist/sent-secrets.d.ts +194 -37
- package/dist/sent-secrets.js +1743 -340
- package/dist/server.js +5 -56
- package/dist/skills.js +322 -223
- package/dist/sqlite.js +15 -14
- package/dist/storage/d1-copy.js +255 -0
- package/dist/storage/d1-driver.js +15 -0
- package/dist/storage/keys.js +28 -0
- package/dist/storage/sql-driver.js +88 -0
- package/dist/storage/sql-native.js +544 -0
- package/dist/storage/sql-schema.d.ts +6 -0
- package/dist/storage/sql-schema.js +15 -0
- package/dist/storage/sql.d.ts +14 -20
- package/dist/storage/sql.js +29 -535
- package/dist/timeout.js +0 -26
- package/dist/tool-safety.js +20 -10
- package/dist/types.d.ts +9 -109
- package/dist/ui.d.ts +1 -1
- package/dist/ui.js +0 -1
- package/dist/upward.js +3 -0
- package/dist/usage-guide.js +3 -1
- package/dist/validate.d.ts +4 -2
- package/dist/validate.js +86 -9
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/worker.js +312 -292
- package/dist/workspace-subject.js +5 -1
- package/dist/write-outcome.js +454 -34
- package/documentation/README.md +28 -7
- package/documentation/architecture.md +2409 -255
- package/documentation/auth.md +867 -114
- package/documentation/code-mode.md +49 -16
- package/documentation/deploying.md +164 -20
- package/documentation/hosted-mcp-migration.md +460 -0
- package/documentation/integrating.md +129 -144
- package/documentation/meta-tools.md +409 -32
- package/documentation/operating.md +27 -3
- package/documentation/operator-tests.md +3 -0
- package/documentation/operator-ui.md +84 -48
- package/documentation/provider-auth-migration.md +16 -63
- package/documentation/provider-migration-0.29.md +10 -5
- package/documentation/provider-migration-0.35.md +975 -0
- package/documentation/providers.md +1347 -0
- package/examples/worker/AGENTS.md +23 -9
- package/examples/worker/README.md +254 -135
- package/examples/worker/alchemy.run.ts +116 -0
- package/examples/worker/gitignore +10 -0
- package/examples/worker/src/connecta.config.ts +23 -21
- package/examples/worker/wrangler.jsonc +14 -5
- package/guides/connecting-agents.md +157 -0
- package/guides/how-it-works.md +156 -0
- package/guides/safety-and-trust.md +153 -0
- package/package.json +30 -50
- package/templates/node/.env.example +3 -0
- package/templates/node/README.md +22 -2
- package/templates/node/docker-compose.yml +1 -0
- package/templates/node/package.json +3 -2
- package/templates/node/src/connecta.config.ts +8 -0
- package/dist/catalog-drift.d.ts +0 -138
- package/dist/catalog-drift.js +0 -578
- package/dist/operator-ui/agents.d.ts +0 -74
- package/dist/operator-ui/agents.js +0 -104
- package/dist/operator-ui/config-summary.js +0 -565
- package/dist/operator-ui/connection-map.js +0 -376
- package/dist/operator-ui/endpoints.js +0 -221
- package/dist/operator-ui/fix-prompts.d.ts +0 -18
- package/dist/operator-ui/fix-prompts.js +0 -87
- package/dist/operator-ui/health.js +0 -52
- package/dist/operator-ui/member-page.js +0 -97
- package/dist/operator-ui/overview.js +0 -123
- package/dist/operator-ui/setup-commands.js +0 -51
- package/dist/operator-ui/view.d.ts +0 -401
- package/dist/operator-ui/view.js +0 -705
- package/dist/providers/_shared/request-token.js +0 -83
- package/dist/providers/_shared/rest/dispatch.js +0 -41
- package/dist/providers/_shared/rest/operation-index.d.ts +0 -133
- package/dist/providers/_shared/rest/tools.d.ts +0 -141
- package/dist/providers/_shared/rest/tools.js +0 -569
- package/dist/providers/_shared/rest/value-safety.d.ts +0 -201
- package/dist/providers/basecamp/index.d.ts +0 -45
- package/dist/providers/basecamp/index.js +0 -997
- package/dist/providers/basecamp/skill.generated.js +0 -9
- package/dist/providers/cloudflare/rest.d.ts +0 -37
- package/dist/providers/cloudflare/rest.js +0 -1097
- package/dist/providers/github/hosted.js +0 -218
- package/dist/providers/github/rest.js +0 -321
- package/dist/providers/infisical/index.d.ts +0 -7
- package/dist/providers/infisical/index.js +0 -713
- package/dist/providers/infisical/skill.generated.js +0 -8
- package/dist/providers/intercom/index.d.ts +0 -24
- package/dist/providers/intercom/index.js +0 -121
- package/dist/providers/intercom/skill.generated.js +0 -8
- package/dist/providers/linear/index.d.ts +0 -55
- package/dist/providers/linear/index.js +0 -537
- package/dist/providers/linear/skill.generated.js +0 -8
- package/dist/providers/mixpanel/index.d.ts +0 -59
- package/dist/providers/mixpanel/index.js +0 -472
- package/dist/providers/mixpanel/operations.js +0 -20
- package/dist/providers/mixpanel/rest.js +0 -603
- package/dist/providers/mixpanel/skill.generated.js +0 -10
- package/dist/providers/mixpanel/value-safety.js +0 -16
- package/dist/providers/notion/index.d.ts +0 -67
- package/dist/providers/notion/index.js +0 -368
- package/dist/providers/notion/openapi.generated.js +0 -75
- package/dist/providers/notion/rest.d.ts +0 -24
- package/dist/providers/notion/rest.js +0 -1226
- package/dist/providers/notion/skill.generated.js +0 -11
- package/dist/providers/notion/value-safety.js +0 -56
- package/dist/providers/revenuecat/index.d.ts +0 -51
- package/dist/providers/revenuecat/index.js +0 -697
- package/dist/providers/revenuecat/skill.generated.js +0 -11
- package/dist/providers/stripe/rest.d.ts +0 -14
- package/dist/providers/stripe/rest.js +0 -402
- package/dist/providers/vercel/rest.d.ts +0 -20
- package/dist/providers/vercel/rest.js +0 -1020
- package/dist/providers/wispr-flow/index.d.ts +0 -14
- package/dist/providers/wispr-flow/index.js +0 -117
- package/dist/providers/wispr-flow/skill.generated.js +0 -8
- /package/dist/providers/github/{key.js → lib/key.js} +0 -0
|
@@ -64,7 +64,7 @@ export async function routeAccessTokens(context, manager) {
|
|
|
64
64
|
if (mutating && !isSameOrigin(request, baseUrl)) {
|
|
65
65
|
return privateJson({ error: "same-origin request required" }, { status: 403 });
|
|
66
66
|
}
|
|
67
|
-
const admin = await authorizeUiIdentity(request, baseUrl, opts.config.auth, "access token management", context.runtimeContext);
|
|
67
|
+
const admin = await authorizeUiIdentity(request, baseUrl, opts.config.auth, "access token management", context.runtimeContext, opts.config.logger);
|
|
68
68
|
if (!admin.ok)
|
|
69
69
|
return admin.response;
|
|
70
70
|
// Interactive maintainers alone manage agent tokens (#837); anyone else
|
|
@@ -75,7 +75,7 @@ function labelLookups(actors, auth) {
|
|
|
75
75
|
export function resolveActorLabels(actors, auth) {
|
|
76
76
|
return Effect.suspend(() => {
|
|
77
77
|
const labels = new Map();
|
|
78
|
-
const resolve = ({ key, id, provider }) => Effect.tryPromise(() => Promise.resolve(provider.activityActorLabel(id))).pipe(Effect.map(cleanActorLabel), Effect.orElseSucceed(() => undefined), Effect.map((label) => {
|
|
78
|
+
const resolve = ({ key, id, provider }) => Effect.tryPromise((signal) => Promise.resolve(provider.activityActorLabel(id, signal))).pipe(Effect.map(cleanActorLabel), Effect.orElseSucceed(() => undefined), Effect.map((label) => {
|
|
79
79
|
if (label)
|
|
80
80
|
labels.set(key, label);
|
|
81
81
|
}));
|
package/dist/routes/connect.js
CHANGED
|
@@ -84,7 +84,7 @@ async function connect(context) {
|
|
|
84
84
|
headers: { Location: target.href, "Cache-Control": "no-store", "Referrer-Policy": "no-referrer" },
|
|
85
85
|
});
|
|
86
86
|
};
|
|
87
|
-
const authz = await authorizeUiIdentity(request, baseUrl, opts.config.auth, "OAuth connection", runtimeContext);
|
|
87
|
+
const authz = await authorizeUiIdentity(request, baseUrl, opts.config.auth, "OAuth connection", runtimeContext, opts.config.logger);
|
|
88
88
|
if (!authz.ok) {
|
|
89
89
|
// Access sign-in is enforced at the edge. Clerk needs its own sign-in page.
|
|
90
90
|
// The sign-in page returns to this link, which then sends a maintainer on
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { Context, Effect, Scheduler } from "effect";
|
|
2
|
+
import * as HttpRouter from "effect/http/HttpRouter";
|
|
3
|
+
import * as HttpServerError from "effect/http/HttpServerError";
|
|
4
|
+
import * as HttpServerRequest from "effect/http/HttpServerRequest";
|
|
5
|
+
import * as HttpServerResponse from "effect/http/HttpServerResponse";
|
|
6
|
+
import { notFoundResponse } from "../branding.js";
|
|
7
|
+
import { isAgentPath } from "./agent-path.js";
|
|
8
|
+
import { MCP_CORS_HEADERS } from "./mcp.js";
|
|
9
|
+
import { routeConnect } from "./connect.js";
|
|
10
|
+
import { routeOAuthCallback } from "./oauth.js";
|
|
11
|
+
import { routeOAuthClientMetadata } from "./oauth-client-metadata.js";
|
|
12
|
+
// Only execution provides this service. Registration never sees request state.
|
|
13
|
+
class CurrentRoute extends Context.Service()("connecta/CurrentRoute") {
|
|
14
|
+
}
|
|
15
|
+
/** Private, request-free route tables, owned by one fetch handler. */
|
|
16
|
+
export function createRouteDispatcher(mcp, metadata, health) {
|
|
17
|
+
let tables;
|
|
18
|
+
const missing = (context) => notFoundResponse(context.request, context.opts.config);
|
|
19
|
+
const fallback = (context) => Effect.gen(function* () {
|
|
20
|
+
if (context.request.method === "OPTIONS") {
|
|
21
|
+
return ((yield* mcp(context)) ??
|
|
22
|
+
(yield* metadata(context.request, context.baseUrl)) ??
|
|
23
|
+
new Response(null, { status: 204, headers: MCP_CORS_HEADERS }));
|
|
24
|
+
}
|
|
25
|
+
return (yield* mcp(context)) ?? missing(context);
|
|
26
|
+
});
|
|
27
|
+
const afterUi = (program) => (context) => Effect.gen(function* () {
|
|
28
|
+
const ui = context.opts.config.ui;
|
|
29
|
+
const response = ui ? yield* Effect.promise(() => ui.handle(context)) : null;
|
|
30
|
+
return response ?? (yield* program(context));
|
|
31
|
+
});
|
|
32
|
+
const optional = (program) => (context) => Effect.flatMap(program(context), (response) => (response ? Effect.succeed(response) : fallback(context)));
|
|
33
|
+
const agentProgram = (context) => Effect.map(mcp(context), (response) => response ?? missing(context));
|
|
34
|
+
const wrap = (program) => Effect.flatMap(CurrentRoute, (current) => {
|
|
35
|
+
current.entered = true;
|
|
36
|
+
return Effect.map(Effect.suspend(() => program(current.context)), HttpServerResponse.raw);
|
|
37
|
+
});
|
|
38
|
+
// make/addAll/asHttpEffect are entirely synchronous for these fixed tables.
|
|
39
|
+
// Bound only their registration/publication so concurrent first edges cannot
|
|
40
|
+
// yield halfway through and build duplicate tables. No callbacks or I/O here.
|
|
41
|
+
const initialize = Effect.suspend(() => {
|
|
42
|
+
if (tables)
|
|
43
|
+
return Effect.succeed(tables);
|
|
44
|
+
return Effect.gen(function* () {
|
|
45
|
+
const human = yield* HttpRouter.make;
|
|
46
|
+
const agent = yield* HttpRouter.make;
|
|
47
|
+
const humanRoutes = [
|
|
48
|
+
HttpRouter.route("*", "/oauth/client-metadata/*", wrap((context) => {
|
|
49
|
+
const response = routeOAuthClientMetadata(context);
|
|
50
|
+
return response ? Effect.succeed(response) : afterUi(fallback)(context);
|
|
51
|
+
})),
|
|
52
|
+
HttpRouter.route("*", "/connect/*", wrap(afterUi(optional(routeConnect)))),
|
|
53
|
+
HttpRouter.route("*", "/oauth/callback/*", wrap(afterUi(optional(routeOAuthCallback)))),
|
|
54
|
+
HttpRouter.route("*", "/.well-known/*", wrap(afterUi((context) => {
|
|
55
|
+
if (!context.path.startsWith("/.well-known/"))
|
|
56
|
+
return fallback(context);
|
|
57
|
+
return Effect.gen(function* () {
|
|
58
|
+
return ((yield* mcp(context)) ??
|
|
59
|
+
(yield* metadata(context.request, context.baseUrl)) ??
|
|
60
|
+
(context.request.method === "OPTIONS"
|
|
61
|
+
? new Response(null, { status: 204, headers: MCP_CORS_HEADERS })
|
|
62
|
+
: missing(context)));
|
|
63
|
+
});
|
|
64
|
+
}))),
|
|
65
|
+
HttpRouter.route("*", "/health", wrap(afterUi((context) => context.path === "/health" && context.request.method !== "OPTIONS"
|
|
66
|
+
? Effect.promise(health)
|
|
67
|
+
: fallback(context)))),
|
|
68
|
+
HttpRouter.route("*", "/mcp/*", wrap(afterUi(fallback))),
|
|
69
|
+
];
|
|
70
|
+
// addAll's Request markers describe execution dependencies, not services
|
|
71
|
+
// used during registration. CurrentRoute is supplied below on every call;
|
|
72
|
+
// the error marker is handled by the existing edge, never by registration.
|
|
73
|
+
yield* human.addAll(humanRoutes);
|
|
74
|
+
yield* agent.addAll([HttpRouter.route("*", "*", wrap(agentProgram))]);
|
|
75
|
+
tables = { human: human.asHttpEffect(), agent: agent.asHttpEffect() };
|
|
76
|
+
return tables;
|
|
77
|
+
});
|
|
78
|
+
}).pipe(Effect.provideService(HttpRouter.RouterConfig, {
|
|
79
|
+
ignoreDuplicateSlashes: false,
|
|
80
|
+
ignoreTrailingSlash: false,
|
|
81
|
+
caseSensitive: true,
|
|
82
|
+
}), Effect.provideService(Scheduler.PreventSchedulerYield, true), Effect.uninterruptible);
|
|
83
|
+
return (context) => Effect.gen(function* () {
|
|
84
|
+
const routers = yield* initialize;
|
|
85
|
+
const current = { context, entered: false };
|
|
86
|
+
const agent = isAgentPath(context.path);
|
|
87
|
+
// Dispatch only selects paths. Methods, body and headers belong to the
|
|
88
|
+
// original request in CurrentRoute; a GET projection also covers arbitrary
|
|
89
|
+
// extension methods outside FindMyWay's finite wildcard-method list.
|
|
90
|
+
// Escape '%' once so the matcher cannot decode raw prefixes or reject an
|
|
91
|
+
// invalid escape in an otherwise owned suffix; ';' is its query delimiter.
|
|
92
|
+
const request = HttpServerRequest.fromWeb(new Request(context.url)).modify({
|
|
93
|
+
url: context.path.replaceAll("%", "%25").replaceAll(";", "%3B"),
|
|
94
|
+
});
|
|
95
|
+
return yield* Effect.scoped(agent ? routers.agent : routers.human).pipe(Effect.provideService(CurrentRoute, current), Effect.provideService(HttpServerRequest.HttpServerRequest, request), Effect.map(HttpServerResponse.toWeb), Effect.catch((error) => !current.entered &&
|
|
96
|
+
HttpServerError.isHttpServerError(error) &&
|
|
97
|
+
error.reason instanceof HttpServerError.RouteNotFound
|
|
98
|
+
? agent
|
|
99
|
+
? agentProgram(context)
|
|
100
|
+
: afterUi(fallback)(context)
|
|
101
|
+
: Effect.fail(error)));
|
|
102
|
+
});
|
|
103
|
+
}
|
package/dist/routes/mcp.js
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
|
+
import { upwardStep } from "../upward.js";
|
|
2
|
+
import { authCall, authInvoke, authFlow, authMethod } from "../auth/native.js";
|
|
3
|
+
import { registryProgram } from "../runtime/registry.js";
|
|
4
|
+
import { requestOwner, RequestScope } from "../runtime/request-scope.js";
|
|
5
|
+
import { observeAgentAdmission } from "../agent-observation.js";
|
|
1
6
|
import { bindActivityRequest } from "../activity-request.js";
|
|
2
|
-
import {
|
|
7
|
+
import { closeScope } from "../runtime/connector-scope.js";
|
|
3
8
|
import { executeLimits } from "../config.js";
|
|
4
9
|
import { oauthConnectUrl, oauthConnectLink, oauthConnectLinkProgress, closeOAuthConnectLinks, claimAuthRetry, oauthConnectUnavailable, } from "../oauth-handoff.js";
|
|
5
10
|
import { AuthElicitation } from "../auth-elicitation.js";
|
|
@@ -9,6 +14,7 @@ import { registerExecuteTool } from "../execute.js";
|
|
|
9
14
|
import { ExecutorAdmissionError } from "../executor-admission.js";
|
|
10
15
|
import { registerMetaTools } from "../meta-tools.js";
|
|
11
16
|
import { endpointInstructions } from "../skills.js";
|
|
17
|
+
import { NATIVE_TOOLS_LIST_TTL_MS, NativeSurface, nativeRequestHint } from "../native-tools.js";
|
|
12
18
|
import { registerSkills } from "./skills.js";
|
|
13
19
|
import { failureRecord, logFailure } from "../operator-record.js";
|
|
14
20
|
import { redactAgentOutput, sentSecretsForRequest } from "../sent-secrets.js";
|
|
@@ -16,12 +22,9 @@ import { detach } from "../runtime/run.js";
|
|
|
16
22
|
import { agentEndpointPool, isAgentPath } from "./agent-path.js";
|
|
17
23
|
import { admitsMaintainer, agentPool, authorize, authorizeAgent, mayManageConnector, memberPool, } from "./shared.js";
|
|
18
24
|
/**
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* the platform's request limit on Workers. The host owns that decision, as it
|
|
23
|
-
* did before the SDK had an opinion, so the SDK is told to have none. Its
|
|
24
|
-
* option must be finite.
|
|
25
|
+
* Core checks admission.requests.maxBodyBytes after authentication and endpoint
|
|
26
|
+
* admission, before any SDK/body-hint reader. The SDK's separate 4 MiB default
|
|
27
|
+
* must not shadow a configured larger bound. Its option must be finite.
|
|
25
28
|
*/
|
|
26
29
|
const SDK_BODY_BOUND = { maxRequestBodySize: Number.MAX_SAFE_INTEGER };
|
|
27
30
|
// Identity, not a status/header a custom auth response could imitate.
|
|
@@ -33,12 +36,12 @@ const deadlineResponses = new WeakSet();
|
|
|
33
36
|
*/
|
|
34
37
|
export const MAX_LISTEN_CLASSIFICATION_BYTES = 64 * 1024;
|
|
35
38
|
/**
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
39
|
+
* Check an authenticated, endpoint-admitted body while streaming. The clone
|
|
40
|
+
* preserves the SDK's body and protocol validation. Only a listen candidate
|
|
41
|
+
* needs decoding/classification; other bodies retain no second text copy.
|
|
42
|
+
* Cancel both tee branches past the bound or when the request ends.
|
|
40
43
|
*/
|
|
41
|
-
async function
|
|
44
|
+
async function inspectRequestBody(request, signal, maxBytes, listen) {
|
|
42
45
|
const reader = request.clone().body?.getReader();
|
|
43
46
|
if (!reader)
|
|
44
47
|
return "other";
|
|
@@ -50,7 +53,7 @@ async function classifyListen(request, signal) {
|
|
|
50
53
|
if (signal.aborted)
|
|
51
54
|
onAbort();
|
|
52
55
|
try {
|
|
53
|
-
const decoder = new TextDecoder();
|
|
56
|
+
const decoder = listen ? new TextDecoder() : undefined;
|
|
54
57
|
let text = "";
|
|
55
58
|
let bytes = 0;
|
|
56
59
|
for (;;) {
|
|
@@ -58,15 +61,18 @@ async function classifyListen(request, signal) {
|
|
|
58
61
|
if (done)
|
|
59
62
|
break;
|
|
60
63
|
bytes += value.byteLength;
|
|
61
|
-
if (bytes >
|
|
64
|
+
if (bytes > maxBytes) {
|
|
62
65
|
void reader.cancel().catch(() => { });
|
|
63
66
|
void request.body?.cancel().catch(() => { });
|
|
64
67
|
return "too_large";
|
|
65
68
|
}
|
|
66
|
-
|
|
69
|
+
if (decoder)
|
|
70
|
+
text += decoder.decode(value, { stream: true });
|
|
67
71
|
}
|
|
68
72
|
if (signal.aborted)
|
|
69
73
|
return "aborted";
|
|
74
|
+
if (!decoder)
|
|
75
|
+
return "other";
|
|
70
76
|
const protocolVersion = request.headers.get("MCP-Protocol-Version");
|
|
71
77
|
const method = request.headers.get("Mcp-Method");
|
|
72
78
|
const route = classifyInboundRequest({
|
|
@@ -319,7 +325,9 @@ function serveMcp(request, requestSignal, requestScope, opts, baseUrl, actor, re
|
|
|
319
325
|
// The modern handler tears its own down after the exchange; the legacy
|
|
320
326
|
// transport never does, and neither may stay wired to an ended request.
|
|
321
327
|
const servers = [];
|
|
322
|
-
|
|
328
|
+
// A native pool lists its downstream tools directly (pools.<name>.surface).
|
|
329
|
+
const native = pool !== undefined ? opts.pools.get(pool)?.native : undefined;
|
|
330
|
+
const createServer = authMethod((hint) => authFlow(function* () {
|
|
323
331
|
const authElicitation = new AuthElicitation({
|
|
324
332
|
vault: opts.config.vault,
|
|
325
333
|
publicUrl: opts.config.publicUrl,
|
|
@@ -327,10 +335,18 @@ function serveMcp(request, requestSignal, requestScope, opts, baseUrl, actor, re
|
|
|
327
335
|
principal: principalKey,
|
|
328
336
|
registry,
|
|
329
337
|
canManage: canManageAuth,
|
|
330
|
-
connectLink: (id, force, after) => oauthConnectLink
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
338
|
+
connectLink: authMethod((id, force, after) => authCall(oauthConnectLink, [
|
|
339
|
+
opts,
|
|
340
|
+
opts.config.publicUrl ?? baseUrl,
|
|
341
|
+
id,
|
|
342
|
+
principalKey,
|
|
343
|
+
force,
|
|
344
|
+
Boolean(opts.config.vault?.seal && opts.config.vault.open),
|
|
345
|
+
after,
|
|
346
|
+
])),
|
|
347
|
+
linkProgress: authMethod((id, nonce) => authCall(oauthConnectLinkProgress, [opts, baseUrl, id, nonce])),
|
|
348
|
+
closeLinks: authMethod((id, nonces) => authCall(closeOAuthConnectLinks, [opts, baseUrl, id, nonces])),
|
|
349
|
+
claimRetry: authMethod((id, nonce) => authCall(claimAuthRetry, [opts, baseUrl, id, nonce])),
|
|
334
350
|
unavailable: oauthConnectUnavailable(opts),
|
|
335
351
|
credentialUi: Boolean(opts.config.ui && opts.config.vault),
|
|
336
352
|
requestSignal,
|
|
@@ -344,17 +360,18 @@ function serveMcp(request, requestSignal, requestScope, opts, baseUrl, actor, re
|
|
|
344
360
|
// Instructions differ per endpoint only by the admitted pool's
|
|
345
361
|
// description. Every cache hint below is private, so a client keeps
|
|
346
362
|
// what it learned per endpoint URL and never shares it across them.
|
|
347
|
-
instructions: endpointInstructions(pool !== undefined ? opts.pools.get(pool)?.description : undefined),
|
|
363
|
+
instructions: endpointInstructions(pool !== undefined ? opts.pools.get(pool)?.description : undefined, native),
|
|
348
364
|
inputRequired: { legacyShim: false },
|
|
349
365
|
requestState: { verify: (state, context) => authElicitation.verify(state, context) },
|
|
350
366
|
cacheHints: {
|
|
351
367
|
"server/discover": { ttlMs: 3_600_000, cacheScope: "private" },
|
|
352
368
|
"tools/list": {
|
|
353
|
-
ttlMs: 3_600_000,
|
|
369
|
+
ttlMs: native ? NATIVE_TOOLS_LIST_TTL_MS : 3_600_000,
|
|
354
370
|
cacheScope: "private",
|
|
355
371
|
},
|
|
356
372
|
},
|
|
357
373
|
});
|
|
374
|
+
servers.push(server);
|
|
358
375
|
const activity = opts.config.activity?.store
|
|
359
376
|
? {
|
|
360
377
|
sink: opts.config.activity?.store,
|
|
@@ -378,14 +395,16 @@ function serveMcp(request, requestSignal, requestScope, opts, baseUrl, actor, re
|
|
|
378
395
|
probeTimeoutMs: opts.config.discovery.probeTimeoutMs,
|
|
379
396
|
...(runtimeContext?.waitUntil ? { defer: runtimeContext.waitUntil.bind(runtimeContext) } : {}),
|
|
380
397
|
});
|
|
381
|
-
|
|
398
|
+
const diagnostics = native ? { ...native, catalogErrors: [] } : undefined;
|
|
399
|
+
const nativeRoute = registerMetaTools(server, registry, {
|
|
400
|
+
native: diagnostics,
|
|
382
401
|
authElicitation,
|
|
383
402
|
client,
|
|
384
403
|
baseUrl,
|
|
385
404
|
requestScope,
|
|
386
405
|
readOnly,
|
|
387
406
|
canManageAuth,
|
|
388
|
-
oauthConnectUrl: (id, force) => oauthConnectUrl
|
|
407
|
+
oauthConnectUrl: authMethod((id, force) => authCall(oauthConnectUrl, [opts, baseUrl, id, principalKey, force])),
|
|
389
408
|
oauthConnectUnavailable: oauthConnectUnavailable(opts),
|
|
390
409
|
credentialHandoffUrl: opts.config.ui?.credentialHandoffUrl(baseUrl),
|
|
391
410
|
...(activity ? { activity } : {}),
|
|
@@ -395,39 +414,62 @@ function serveMcp(request, requestSignal, requestScope, opts, baseUrl, actor, re
|
|
|
395
414
|
requestSignal,
|
|
396
415
|
...(runtimeContext?.waitUntil ? { defer: runtimeContext.waitUntil.bind(runtimeContext) } : {}),
|
|
397
416
|
});
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
417
|
+
if (!native || native.executeCode) {
|
|
418
|
+
registerExecuteTool(server, registry, {
|
|
419
|
+
authElicitation,
|
|
420
|
+
client,
|
|
421
|
+
baseUrl,
|
|
422
|
+
requestScope,
|
|
423
|
+
executor: opts.executor,
|
|
424
|
+
defaultToolTimeoutMs: opts.config.calls.defaultTimeoutMs ?? opts.config.execute.hostCallTimeoutMs,
|
|
425
|
+
logger: opts.config.logger,
|
|
426
|
+
...(activity ? { activity } : {}),
|
|
427
|
+
requestSignal,
|
|
428
|
+
...(runtimeContext?.waitUntil ? { defer: runtimeContext.waitUntil.bind(runtimeContext) } : {}),
|
|
429
|
+
...executeLimits(opts.config),
|
|
430
|
+
readOnly,
|
|
431
|
+
native: native !== undefined,
|
|
432
|
+
});
|
|
433
|
+
}
|
|
434
|
+
if (native && nativeRoute && hint) {
|
|
435
|
+
yield* upwardStep(authInvoke(new NativeSurface(registry, {
|
|
436
|
+
baseUrl,
|
|
437
|
+
executeCode: native.executeCode,
|
|
438
|
+
route: nativeRoute,
|
|
439
|
+
bind: (context) => authElicitation.bind(context),
|
|
440
|
+
catalogErrors: diagnostics.catalogErrors,
|
|
441
|
+
logger: opts.config.logger,
|
|
442
|
+
requestScope,
|
|
443
|
+
requestSignal,
|
|
444
|
+
probeTimeoutMs: opts.config.discovery.probeTimeoutMs,
|
|
445
|
+
discoveryConcurrency: opts.config.discovery.concurrency,
|
|
446
|
+
readOnly,
|
|
447
|
+
...(runtimeContext?.waitUntil ? { defer: runtimeContext.waitUntil.bind(runtimeContext) } : {}),
|
|
448
|
+
}), "register", [server, hint]));
|
|
449
|
+
}
|
|
413
450
|
return server;
|
|
414
|
-
};
|
|
415
|
-
const exchange =
|
|
451
|
+
}));
|
|
452
|
+
const exchange = authFlow(function* () {
|
|
416
453
|
// The v2 entry's built-in legacy fallback streams 2025 results as SSE.
|
|
417
454
|
// Connecta's established wire contract is JSON, so retain the documented
|
|
418
455
|
// user-land legacy branch with the same transport setting while the modern
|
|
419
456
|
// branch uses the fetch-native handler.
|
|
420
|
-
if (!(
|
|
421
|
-
const response =
|
|
457
|
+
if (!(yield* upwardStep(authCall(isLegacyRequest, [request, undefined, SDK_BODY_BOUND])))) {
|
|
458
|
+
const response = yield* upwardStep(authInvoke(createMcpHandler(authMethod(() => authFlow(function* () {
|
|
459
|
+
const hint = native
|
|
460
|
+
? yield* upwardStep(authCall(nativeRequestHint, [request, true]))
|
|
461
|
+
: undefined;
|
|
462
|
+
return yield* upwardStep(authCall(createServer, [hint]));
|
|
463
|
+
})), {
|
|
422
464
|
...SDK_BODY_BOUND,
|
|
423
465
|
legacy: "reject",
|
|
424
466
|
// Keep the SDK's validation and prevent it from opening an SSE stream.
|
|
425
467
|
// Its capacity error below becomes our permanent unsupported method.
|
|
426
468
|
maxSubscriptions: 0,
|
|
427
469
|
onerror: (error) => logFailure(opts.config.logger, "MCP handler error", failureRecord({}, error), "error"),
|
|
428
|
-
})
|
|
470
|
+
}), "fetch", [request]));
|
|
429
471
|
if (request.headers.get("Mcp-Method") === "subscriptions/listen" && response.status === 200) {
|
|
430
|
-
const body =
|
|
472
|
+
const body = yield* upwardStep(authInvoke(response.clone(), "json", []));
|
|
431
473
|
if (isJSONRPCErrorResponse(body) &&
|
|
432
474
|
body.error.code === -32603 &&
|
|
433
475
|
body.error.message === "Subscription limit reached") {
|
|
@@ -441,24 +483,27 @@ function serveMcp(request, requestSignal, requestScope, opts, baseUrl, actor, re
|
|
|
441
483
|
return response;
|
|
442
484
|
}
|
|
443
485
|
// Fresh server + transport per legacy request, stateless and JSON-shaped.
|
|
444
|
-
const
|
|
486
|
+
const hint = native
|
|
487
|
+
? yield* upwardStep(authCall(nativeRequestHint, [request, false]))
|
|
488
|
+
: undefined;
|
|
489
|
+
const server = yield* upwardStep(authCall(createServer, [hint]));
|
|
445
490
|
const transport = new WebStandardStreamableHTTPServerTransport({
|
|
446
491
|
...SDK_BODY_BOUND,
|
|
447
492
|
enableJsonResponse: true,
|
|
448
493
|
});
|
|
449
|
-
|
|
450
|
-
return transport
|
|
451
|
-
};
|
|
494
|
+
yield* upwardStep(authInvoke(server, "connect", [transport]));
|
|
495
|
+
return yield* upwardStep(authInvoke(transport, "handleRequest", [request]));
|
|
496
|
+
});
|
|
452
497
|
return Effect.addFinalizer(() => Effect.sync(() => {
|
|
453
498
|
for (const server of servers)
|
|
454
499
|
void server.close().catch(() => { });
|
|
455
|
-
})).pipe(Effect.andThen(
|
|
456
|
-
const response =
|
|
500
|
+
})).pipe(Effect.andThen(authFlow(function* () {
|
|
501
|
+
const response = yield* upwardStep(exchange);
|
|
457
502
|
// Both SDK transports serialize here. This also covers SDK-generated
|
|
458
503
|
// JSON-RPC errors and allowed HTTP 4xx text, outside tool result shaping.
|
|
459
504
|
if (!response.body)
|
|
460
505
|
return response;
|
|
461
|
-
const body =
|
|
506
|
+
const body = yield* upwardStep(authInvoke(response, "text", []));
|
|
462
507
|
let text;
|
|
463
508
|
if (response.headers.get("Content-Type")?.includes("application/json")) {
|
|
464
509
|
// Structured redaction also joins text blocks before a secret split
|
|
@@ -596,6 +641,7 @@ export function createMcpRoute(opts) {
|
|
|
596
641
|
let deadlineTimer;
|
|
597
642
|
return scopedToBody(Effect.gen(function* () {
|
|
598
643
|
yield* Effect.addFinalizer(() => Effect.sync(() => {
|
|
644
|
+
requestOwner(requestScope).close();
|
|
599
645
|
if (!localAbort.signal.aborted) {
|
|
600
646
|
localAbort.abort(request.signal.reason ?? new Error("MCP request ended."));
|
|
601
647
|
}
|
|
@@ -654,9 +700,23 @@ export function createMcpRoute(opts) {
|
|
|
654
700
|
// shares it, to save only the lookups an abandoned authorization
|
|
655
701
|
// finishes on its own.
|
|
656
702
|
// Agent endpoints consult only the `cta_` adapter; human endpoints refuse `cta_`.
|
|
657
|
-
const admit = () => agentEndpoint
|
|
658
|
-
? authorizeAgent
|
|
659
|
-
|
|
703
|
+
const admit = authMethod(() => agentEndpoint
|
|
704
|
+
? authCall(authorizeAgent, [
|
|
705
|
+
localRequest,
|
|
706
|
+
baseUrl,
|
|
707
|
+
opts.config.auth,
|
|
708
|
+
opts.config.logger,
|
|
709
|
+
runtimeContext?.waitUntil.bind(runtimeContext),
|
|
710
|
+
])
|
|
711
|
+
: authCall(authorize, [
|
|
712
|
+
localRequest,
|
|
713
|
+
baseUrl,
|
|
714
|
+
opts.config.auth,
|
|
715
|
+
runtimeContext,
|
|
716
|
+
true,
|
|
717
|
+
false,
|
|
718
|
+
opts.config.logger,
|
|
719
|
+
]));
|
|
660
720
|
// Plain /mcp admits maintainers and serves the whole catalog; a pool
|
|
661
721
|
// admits its members, people at /mcp/<pool> and agents at
|
|
662
722
|
// /agent/<pool>, and serves exactly its tools (INV-4).
|
|
@@ -680,7 +740,7 @@ export function createMcpRoute(opts) {
|
|
|
680
740
|
: undefined;
|
|
681
741
|
};
|
|
682
742
|
const handled = Effect.gen(function* () {
|
|
683
|
-
const authz = yield*
|
|
743
|
+
const authz = yield* authCall(admit, []);
|
|
684
744
|
if (!authz.ok) {
|
|
685
745
|
const response = authz.response;
|
|
686
746
|
// Preserve the auth adapter's challenge and status. The MCP host must
|
|
@@ -726,8 +786,15 @@ export function createMcpRoute(opts) {
|
|
|
726
786
|
return notFound();
|
|
727
787
|
}
|
|
728
788
|
const { access, readOnly, poolOwner } = scope;
|
|
729
|
-
|
|
730
|
-
|
|
789
|
+
// Admission, not completed-call activity. This fact carries no live
|
|
790
|
+
// identity or credential and never changes the admission verdict.
|
|
791
|
+
if (agentEndpoint && authz.identity.agent && opts.config.agents.includes(authz.identity.agent)) {
|
|
792
|
+
yield* observeAgentAdmission(opts.config.storage, authz.identity.agent, new Date().toISOString(), opts.config.discovery.probeTimeoutMs);
|
|
793
|
+
}
|
|
794
|
+
{
|
|
795
|
+
const maxBodyBytes = opts.config.admission.requests.maxBodyBytes;
|
|
796
|
+
const bound = listenHeader ? Math.min(maxBodyBytes, MAX_LISTEN_CLASSIFICATION_BYTES) : maxBodyBytes;
|
|
797
|
+
const verdict = yield* Effect.promise(() => inspectRequestBody(localRequest, localAbort.signal, bound, listenHeader));
|
|
731
798
|
// The deadline timer aborts a stalled read; its body is already cancelled.
|
|
732
799
|
if (verdict === "aborted") {
|
|
733
800
|
return cors(mcpRefusal(sentSecrets, 504, -33003, "MCP request lifetime exceeded."));
|
|
@@ -735,7 +802,7 @@ export function createMcpRoute(opts) {
|
|
|
735
802
|
if (verdict === "too_large") {
|
|
736
803
|
return cors(mcpRefusal(sentSecrets, 413, -33006, "MCP request body too large."));
|
|
737
804
|
}
|
|
738
|
-
if (verdict === "other") {
|
|
805
|
+
if (listenHeader && verdict === "other") {
|
|
739
806
|
const late = yield* Effect.result(admitted(opts.requestAdmission, request.signal));
|
|
740
807
|
if (Result.isFailure(late))
|
|
741
808
|
return yield* refuseAdmission(late.failure);
|
|
@@ -762,13 +829,15 @@ export function createMcpRoute(opts) {
|
|
|
762
829
|
...(authz.principalKey ? { principalKey: authz.principalKey } : {}),
|
|
763
830
|
endpoint: new URL(request.url).pathname,
|
|
764
831
|
origin: request.headers.get("Origin"),
|
|
765
|
-
currentResultAccess:
|
|
832
|
+
currentResultAccess: authMethod((dependencies, classification, signal) => authFlow(function* () {
|
|
766
833
|
signal?.throwIfAborted();
|
|
767
|
-
const current =
|
|
834
|
+
const current = yield* upwardStep(authCall(admit, []));
|
|
768
835
|
if (!current.ok) {
|
|
769
|
-
|
|
836
|
+
yield* upwardStep(authCall(() => current.response.body?.cancel().catch(() => { }), []));
|
|
837
|
+
signal?.throwIfAborted();
|
|
770
838
|
return false;
|
|
771
839
|
}
|
|
840
|
+
signal?.throwIfAborted();
|
|
772
841
|
if (current.subjectKey !== authz.subjectKey || current.principalKey !== authz.principalKey)
|
|
773
842
|
return false;
|
|
774
843
|
// Paging re-admits the caller at this endpoint, as a new request would.
|
|
@@ -784,27 +853,49 @@ export function createMcpRoute(opts) {
|
|
|
784
853
|
});
|
|
785
854
|
if (classification === "write" && currentReadOnly)
|
|
786
855
|
return false;
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
// Skill and resource content requires a whole grant; catalog metadata requires visibility.
|
|
790
|
-
if (!address.includes("."))
|
|
791
|
-
return Boolean(access === "catalog" ? view.getConnector(address) : view.getResourceConnector(address));
|
|
792
|
-
const resolved = view.resolveAddress(address);
|
|
793
|
-
if (!resolved)
|
|
794
|
-
return false;
|
|
856
|
+
// Both admission and catalogs belong to this pass only. A second
|
|
857
|
+
// pass after reading the page must observe revocation afresh.
|
|
795
858
|
const requestScope = {};
|
|
859
|
+
const catalogs = new Map();
|
|
796
860
|
try {
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
861
|
+
for (const dependency of dependencies) {
|
|
862
|
+
signal?.throwIfAborted();
|
|
863
|
+
if (dependency.classification === "write" && currentReadOnly)
|
|
864
|
+
return false;
|
|
865
|
+
// Skill and resource content requires a whole grant; catalog metadata requires visibility.
|
|
866
|
+
if (dependency.tool === undefined) {
|
|
867
|
+
if (!(dependency.access === "catalog"
|
|
868
|
+
? view.getConnector(dependency.connector)
|
|
869
|
+
: view.getResourceConnector(dependency.connector)))
|
|
870
|
+
return false;
|
|
871
|
+
continue;
|
|
872
|
+
}
|
|
873
|
+
const resolved = view.resolveAddress(`${dependency.connector}.${dependency.tool}`);
|
|
874
|
+
if (!resolved)
|
|
875
|
+
return false;
|
|
876
|
+
let catalog = catalogs.get(resolved.connector.id);
|
|
877
|
+
if (!catalog) {
|
|
878
|
+
// Track even a failed load so its scope is always closed.
|
|
879
|
+
catalog = { connector: resolved.connector, tools: [] };
|
|
880
|
+
catalogs.set(resolved.connector.id, catalog);
|
|
881
|
+
catalog.tools = yield* upwardStep(registryProgram(view, "getTools", resolved.connector.id, baseUrl, requestScope, signal ? { signal } : {}));
|
|
882
|
+
}
|
|
883
|
+
signal?.throwIfAborted();
|
|
884
|
+
const tool = catalog.tools.find((tool) => tool.name === resolved.toolName);
|
|
885
|
+
if (!(tool &&
|
|
886
|
+
(dependency.access === "catalog" ||
|
|
887
|
+
(dependency.classification === "read" && tool.classification === "read") ||
|
|
888
|
+
!currentReadOnly)))
|
|
889
|
+
return false;
|
|
890
|
+
}
|
|
891
|
+
return true;
|
|
803
892
|
}
|
|
804
893
|
finally {
|
|
805
|
-
|
|
894
|
+
for (const [id, { connector }] of catalogs) {
|
|
895
|
+
yield* upwardStep(closeScope(connector, view.contextFor(id, baseUrl, requestScope), runtimeContext?.waitUntil?.bind(runtimeContext)));
|
|
896
|
+
}
|
|
806
897
|
}
|
|
807
|
-
},
|
|
898
|
+
})),
|
|
808
899
|
caller: callerFor(authz.identity, poolOwner),
|
|
809
900
|
});
|
|
810
901
|
}
|
|
@@ -833,7 +924,7 @@ export function createMcpRoute(opts) {
|
|
|
833
924
|
return Option.isSome(bounded)
|
|
834
925
|
? bounded.value
|
|
835
926
|
: cors(mcpRefusal(sentSecrets, 504, -33003, "MCP request lifetime exceeded."));
|
|
836
|
-
}), localAbort.signal);
|
|
927
|
+
}).pipe(Effect.provideService(RequestScope, requestOwner(requestScope))), localAbort.signal);
|
|
837
928
|
}
|
|
838
929
|
return { handle: routeMcp, rejectOrigin };
|
|
839
930
|
}
|
package/dist/routes/oauth.js
CHANGED
|
@@ -167,8 +167,10 @@ async function finishOAuthCallback(context) {
|
|
|
167
167
|
}
|
|
168
168
|
try {
|
|
169
169
|
const expectedPrincipalKey = callbackTarget?.principalKey;
|
|
170
|
-
const browserIdentity = await authorizeUiIdentity(context.request, baseUrl, opts.config.auth, "OAuth callback", context.runtimeContext);
|
|
170
|
+
const browserIdentity = await authorizeUiIdentity(context.request, baseUrl, opts.config.auth, "OAuth callback", context.runtimeContext, opts.config.logger);
|
|
171
171
|
if (!browserIdentity.ok) {
|
|
172
|
+
if (browserIdentity.response.status === 503)
|
|
173
|
+
return browserIdentity.response;
|
|
172
174
|
if (browserIdentity.response.status === 401 && authorizationCredential(context.request).kind !== "absent")
|
|
173
175
|
return browserIdentity.response;
|
|
174
176
|
// A Clerk browser handshake refreshes its session and returns to this
|
|
@@ -215,6 +217,9 @@ async function finishOAuthCallback(context) {
|
|
|
215
217
|
if (["state", "iss", "code", "error"].some((name) => url.searchParams.getAll(name).length > 1))
|
|
216
218
|
return refused();
|
|
217
219
|
try {
|
|
220
|
+
if (connector.verifyCallbackParameters &&
|
|
221
|
+
!(await connector.verifyCallbackParameters(url.searchParams, connectorContext)))
|
|
222
|
+
return refused();
|
|
218
223
|
const issuer = url.searchParams.get("iss");
|
|
219
224
|
if (connector.verifyCallbackIssuer) {
|
|
220
225
|
if (!(await connector.verifyCallbackIssuer(issuer, connectorContext)))
|
package/dist/routes/operator.js
CHANGED
|
@@ -41,11 +41,11 @@ function admitted(result) {
|
|
|
41
41
|
}
|
|
42
42
|
/** Any configured caller. The gate's refusal, challenge headers and all, is the answer. */
|
|
43
43
|
export function authorized({ request, baseUrl, opts, runtimeContext }, partitionIdentity = true) {
|
|
44
|
-
return Effect.suspend(() => admitted(authorize(request, baseUrl, opts.config.auth, runtimeContext, partitionIdentity)));
|
|
44
|
+
return Effect.suspend(() => admitted(authorize(request, baseUrl, opts.config.auth, runtimeContext, partitionIdentity, false, opts.config.logger)));
|
|
45
45
|
}
|
|
46
46
|
/** A signed-in person, for a route that changes how a connector authenticates. */
|
|
47
47
|
export function authorizedPerson({ request, baseUrl, opts, runtimeContext }, purpose) {
|
|
48
|
-
return Effect.suspend(() => admitted(authorizeUiIdentity(request, baseUrl, opts.config.auth, purpose, runtimeContext)));
|
|
48
|
+
return Effect.suspend(() => admitted(authorizeUiIdentity(request, baseUrl, opts.config.auth, purpose, runtimeContext, opts.config.logger)));
|
|
49
49
|
}
|
|
50
50
|
/** The partition an identity carries into a registry view of the given connectors. */
|
|
51
51
|
export function scopeFor(authz, connectorIds = "all") {
|