@kya-os/mcp-i-cloudflare 1.15.1 → 1.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +42 -0
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +81 -51
- package/dist/agent.js.map +1 -1
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js +9 -12
- package/dist/app.js.map +1 -1
- package/dist/audit/deployment-binding.d.ts +12 -12
- package/dist/config.d.ts +28 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +16 -1
- package/dist/config.js.map +1 -1
- package/dist/constants/storage-keys.d.ts +9 -0
- package/dist/constants/storage-keys.d.ts.map +1 -1
- package/dist/constants/storage-keys.js +9 -0
- package/dist/constants/storage-keys.js.map +1 -1
- package/dist/constants.d.ts +6 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +6 -0
- package/dist/constants.js.map +1 -1
- package/dist/delegation-http/bearer-retry.d.ts +20 -4
- package/dist/delegation-http/bearer-retry.d.ts.map +1 -1
- package/dist/delegation-http/bearer-retry.js +58 -10
- package/dist/delegation-http/bearer-retry.js.map +1 -1
- package/dist/delegation-http/consent-anchor-bridge.d.ts.map +1 -1
- package/dist/delegation-http/consent-anchor-bridge.js +72 -13
- package/dist/delegation-http/consent-anchor-bridge.js.map +1 -1
- package/dist/delegation-http/native-oauth-state.d.ts +16 -0
- package/dist/delegation-http/native-oauth-state.d.ts.map +1 -1
- package/dist/delegation-http/native-oauth-state.js +24 -9
- package/dist/delegation-http/native-oauth-state.js.map +1 -1
- package/dist/delegation-http/native-oauth.d.ts.map +1 -1
- package/dist/delegation-http/native-oauth.js +26 -7
- package/dist/delegation-http/native-oauth.js.map +1 -1
- package/dist/delegation-http/oauth-recovery.d.ts +3 -0
- package/dist/delegation-http/oauth-recovery.d.ts.map +1 -0
- package/dist/delegation-http/oauth-recovery.js +39 -0
- package/dist/delegation-http/oauth-recovery.js.map +1 -0
- package/dist/delegation-http/remote-issuer.d.ts +15 -0
- package/dist/delegation-http/remote-issuer.d.ts.map +1 -1
- package/dist/delegation-http/remote-issuer.js +27 -8
- package/dist/delegation-http/remote-issuer.js.map +1 -1
- package/dist/helpers/env-mapper.d.ts.map +1 -1
- package/dist/helpers/env-mapper.js +28 -6
- package/dist/helpers/env-mapper.js.map +1 -1
- package/dist/index.d.ts +6 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -1
- package/dist/index.js.map +1 -1
- package/dist/proof-generator.d.ts +8 -7
- package/dist/proof-generator.d.ts.map +1 -1
- package/dist/proof-generator.js +32 -34
- package/dist/proof-generator.js.map +1 -1
- package/dist/runtime/oauth-handler.d.ts.map +1 -1
- package/dist/runtime/oauth-handler.js +43 -31
- package/dist/runtime/oauth-handler.js.map +1 -1
- package/dist/runtime/tool-activity.d.ts +31 -4
- package/dist/runtime/tool-activity.d.ts.map +1 -1
- package/dist/runtime/tool-activity.js +48 -0
- package/dist/runtime/tool-activity.js.map +1 -1
- package/dist/runtime.d.ts +31 -0
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +65 -0
- package/dist/runtime.js.map +1 -1
- package/dist/security/admission-refusal.d.ts +32 -0
- package/dist/security/admission-refusal.d.ts.map +1 -0
- package/dist/security/admission-refusal.js +97 -0
- package/dist/security/admission-refusal.js.map +1 -0
- package/dist/security/card-proof-support.d.ts +66 -0
- package/dist/security/card-proof-support.d.ts.map +1 -0
- package/dist/security/card-proof-support.js +121 -0
- package/dist/security/card-proof-support.js.map +1 -0
- package/dist/security/mcp-admission.d.ts +28 -2
- package/dist/security/mcp-admission.d.ts.map +1 -1
- package/dist/security/mcp-admission.js +129 -29
- package/dist/security/mcp-admission.js.map +1 -1
- package/dist/security/mcp-holder-admission.d.ts +12 -1
- package/dist/security/mcp-holder-admission.d.ts.map +1 -1
- package/dist/security/mcp-holder-admission.js +46 -8
- package/dist/security/mcp-holder-admission.js.map +1 -1
- package/dist/security/presented-delegation.d.ts +10 -0
- package/dist/security/presented-delegation.d.ts.map +1 -1
- package/dist/security/presented-delegation.js +23 -3
- package/dist/security/presented-delegation.js.map +1 -1
- package/dist/services/admin.service.d.ts.map +1 -1
- package/dist/services/admin.service.js +24 -9
- package/dist/services/admin.service.js.map +1 -1
- package/dist/services/approval-route.d.ts +48 -0
- package/dist/services/approval-route.d.ts.map +1 -0
- package/dist/services/approval-route.js +87 -0
- package/dist/services/approval-route.js.map +1 -0
- package/dist/services/consent-config.service.d.ts.map +1 -1
- package/dist/services/consent-config.service.js +20 -5
- package/dist/services/consent-config.service.js.map +1 -1
- package/dist/services/consent.service.d.ts +113 -5
- package/dist/services/consent.service.d.ts.map +1 -1
- package/dist/services/consent.service.js +745 -903
- package/dist/services/consent.service.js.map +1 -1
- package/dist/services/credential-auth.handler.d.ts +2 -0
- package/dist/services/credential-auth.handler.d.ts.map +1 -1
- package/dist/services/credential-auth.handler.js +19 -3
- package/dist/services/credential-auth.handler.js.map +1 -1
- package/dist/services/delegation-trust.d.ts +110 -0
- package/dist/services/delegation-trust.d.ts.map +1 -0
- package/dist/services/delegation-trust.js +368 -0
- package/dist/services/delegation-trust.js.map +1 -0
- package/dist/services/delegation.service.d.ts +53 -14
- package/dist/services/delegation.service.d.ts.map +1 -1
- package/dist/services/delegation.service.js +156 -69
- package/dist/services/delegation.service.js.map +1 -1
- package/dist/services/multipart-parser.d.ts +73 -0
- package/dist/services/multipart-parser.d.ts.map +1 -0
- package/dist/services/multipart-parser.js +116 -0
- package/dist/services/multipart-parser.js.map +1 -0
- package/dist/services/proof.service.d.ts +38 -0
- package/dist/services/proof.service.d.ts.map +1 -1
- package/dist/services/proof.service.js +41 -2
- package/dist/services/proof.service.js.map +1 -1
- package/dist/services/resource-audience.d.ts +53 -0
- package/dist/services/resource-audience.d.ts.map +1 -0
- package/dist/services/resource-audience.js +83 -0
- package/dist/services/resource-audience.js.map +1 -0
- package/dist/types.d.ts +18 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/checkpoint-project-id.d.ts +31 -0
- package/dist/utils/checkpoint-project-id.d.ts.map +1 -0
- package/dist/utils/checkpoint-project-id.js +35 -0
- package/dist/utils/checkpoint-project-id.js.map +1 -0
- package/dist/utils/oauth-profile.d.ts +7 -0
- package/dist/utils/oauth-profile.d.ts.map +1 -0
- package/dist/utils/oauth-profile.js +24 -0
- package/dist/utils/oauth-profile.js.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -314,6 +314,48 @@ OAuth callback handler for delegation flow.
|
|
|
314
314
|
|
|
315
315
|
## Security Features
|
|
316
316
|
|
|
317
|
+
### Delegation Credential Trust
|
|
318
|
+
|
|
319
|
+
`DelegationService` (stored delegations and the `Authorization: Bearer` retry)
|
|
320
|
+
accepts a delegation VC-JWT only if all of these hold, with or without
|
|
321
|
+
`CHECKPOINT_API_KEY`:
|
|
322
|
+
|
|
323
|
+
- **Pinned issuer.** `iss` is one of: the worker's own identity
|
|
324
|
+
(`MCP_IDENTITY_AGENT_DID`), the org DID in the native issuer binding
|
|
325
|
+
(`MCPI_NATIVE_HTTP_ISSUER_CONFIG`), a DID listed in
|
|
326
|
+
`KYA_OS_TRUSTED_DELEGATION_ISSUERS`, or the Checkpoint platform signer. The
|
|
327
|
+
platform signer is the did:key that the configured Checkpoint origin's
|
|
328
|
+
`/.well-known/did.json` (`CHECKPOINT_API_URL`, default `https://kya.vouched.id`)
|
|
329
|
+
lists in `alsoKnownAs` under its own assertion key. did:web issuers are
|
|
330
|
+
resolved with `@kya-os/mcp`'s did:web resolver, and the key is picked by the
|
|
331
|
+
JWT `kid` from the document's `assertionMethod`. An issuer is pinned before
|
|
332
|
+
its document is fetched. An untrusted or unresolvable issuer is refused.
|
|
333
|
+
- **Audience.** `aud` is exactly `did:web:<the request's Host>`, and that DID
|
|
334
|
+
is one of this worker's resources, listed in `KYA_OS_RESOURCE_DIDS` (a JSON
|
|
335
|
+
array, one `did:web:<host>` per host the worker is routed under, provisioned
|
|
336
|
+
by Checkpoint). A token for one host is refused at another, and a
|
|
337
|
+
multi-valued `aud` is refused. The host is the request URL the edge
|
|
338
|
+
delivered (Workers for Platforms dispatch forwards the original request), never
|
|
339
|
+
`X-Forwarded-Host`. Nothing else is accepted: not the org DID, the worker's
|
|
340
|
+
own DID or a project id, whoever the issuer and with or without an API key.
|
|
341
|
+
With `KYA_OS_RESOURCE_DIDS` unset, empty or malformed, every delegation is
|
|
342
|
+
refused.
|
|
343
|
+
- **Credential status.** A `credentialStatus` entry (Bitstring or StatusList2021,
|
|
344
|
+
revocation purpose) is read from its status list on every verification. A
|
|
345
|
+
revoked, unreachable or malformed entry is refused.
|
|
346
|
+
|
|
347
|
+
With `CHECKPOINT_API_KEY` set, every accepted credential is still confirmed with
|
|
348
|
+
Checkpoint and nothing is cached. Without it, legacy (non VC-JWT) tokens are
|
|
349
|
+
refused unless `KYA_OS_INSECURE_DEV_TOKENS=1` is set. That flag is for local
|
|
350
|
+
development only, logs a warning on every use, and is never cached. Only a
|
|
351
|
+
pinned issuer's status-less verdict is cached, for 60 seconds.
|
|
352
|
+
|
|
353
|
+
| Variable | Format | Purpose |
|
|
354
|
+
| ----------------------------------- | ---------------------------- | --------------------------------------------------------------------------------- |
|
|
355
|
+
| `KYA_OS_TRUSTED_DELEGATION_ISSUERS` | comma/space-separated DIDs | Extra pinned issuers (e.g. an org `did:web` on a worker without a native binding) |
|
|
356
|
+
| `KYA_OS_RESOURCE_DIDS` | JSON array of `did:web` DIDs | The worker's resources, one per routed host (required) |
|
|
357
|
+
| `KYA_OS_INSECURE_DEV_TOKENS` | `1` / `true` | Accept unchecked legacy tokens without an API key (development only) |
|
|
358
|
+
|
|
317
359
|
### CSRF Protection for OAuth Flows
|
|
318
360
|
|
|
319
361
|
The framework includes built-in CSRF (Cross-Site Request Forgery) protection for OAuth authorization flows. This prevents attackers from tricking users into authorizing unintended actions.
|
package/dist/agent.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtC,OAAO,KAAK,EACV,kBAAkB,EAClB,sBAAsB,EACtB,WAAW,EACZ,MAAM,2BAA2B,CAAC;AACnC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAM7C,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtC,OAAO,KAAK,EACV,kBAAkB,EAClB,sBAAsB,EACtB,WAAW,EACZ,MAAM,2BAA2B,CAAC;AACnC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAM7C,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,UAAU,CAAC;AAKxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAa9C,OAAO,KAAK,EACV,oBAAoB,EAErB,MAAM,0BAA0B,CAAC;AAGlC,OAAO,EAeL,KAAK,oBAAoB,EACzB,KAAK,uBAAuB,EAC7B,MAAM,uBAAuB,CAAC;AAa/B,OAAO,EAEL,KAAK,cAAc,EACpB,MAAM,8BAA8B,CAAC;AAStC,OAAO,EAEL,KAAK,iBAAiB,EACvB,MAAM,2BAA2B,CAAC;AAwBnC;;GAEG;AACH,MAAM,WAAW,qBACf,SAAQ,IAAI,CACV,aAAa,EACX,aAAa,GACb,eAAe,GACf,kBAAkB,GAClB,oBAAoB,GACpB,oBAAoB,GACpB,YAAY,CACf;IACD,CAAC,GAAG,EAAE,MAAM,GACR,WAAW,GACX,MAAM,GACN,kBAAkB,GAClB,sBAAsB,GACtB,SAAS,CAAC;IACd,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,aAAa,CAAC,EAAE,WAAW,CAAC;IAC5B,gBAAgB,CAAC,EAAE,WAAW,CAAC;IAC/B,kBAAkB,CAAC,EAAE,WAAW,CAAC;IACjC,kBAAkB,CAAC,EAAE,WAAW,CAAC;IACjC,UAAU,CAAC,EAAE,sBAAsB,CAAC;CACrC;AAmBD;;;;;;;;;;;;;;;GAeG;AACH,8BAAsB,mBAAoB,SAAQ,QAAQ;IAGxD,MAAM,EAGA,GAAG,CAAC;IAEV,SAAS,CAAC,WAAW,CAAC,EAAE,iBAAiB,CAAC;IAC1C,SAAS,CAAC,GAAG,EAAE,qBAAqB,CAAC;IACrC,SAAS,CAAC,gBAAgB,EAAE,iBAAiB,CAAC;IAC9C,OAAO,CAAC,QAAQ,CAAC,cAAc,CAA0B;IACzD,OAAO,CAAC,YAAY,CAA8C;IAClE,OAAO,CAAC,mBAAmB,CAAC,CAAS;IACrC,OAAO,CAAC,qBAAqB,CAAC,CAAuB;IACrD,OAAO,CAAC,wBAAwB,CAAC,CAAS;IAC1C,OAAO,CAAC,qBAAqB,CAAC,CAAS;IACvC,OAAO,CAAC,cAAc,CAAC,CAAgB;gBAGrC,KAAK,EAAE,kBAAkB,EACzB,GAAG,EAAE,qBAAqB,EAC1B,gBAAgB,GAAE,iBAA2C;IAkI/D;;;;OAIG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAkB9B;;;OAGG;YACW,uBAAuB;IA8GrC;;;;;;;;;OASG;YACW,wBAAwB;IA0BtC;;;;;;;;;;;;OAYG;YACW,wBAAwB;IA6GtC;;;OAGG;YACW,6BAA6B;IAmG3C;;OAEG;IACG,gBAAgB,IAAI,OAAO,CAC7B;QACE,UAAU,CAAC,EAAE;YACX,IAAI,CAAC,EAAE,MAAM,CAAC;YACd,OAAO,CAAC,EAAE,MAAM,CAAC;YACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;YAClB,MAAM,CAAC,EAAE,MAAM,CAAC;SACjB,CAAC;QACF,eAAe,CAAC,EAAE,MAAM,CAAC;QACzB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACvC,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,GACD,SAAS,CACZ;IAID;;OAEG;IACG,iBAAiB,IAAI,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC;IAI9D;;;OAGG;IACH,SAAS,CAAC,QAAQ,CAAC,YAAY,IAAI,MAAM;IAEzC;;;OAGG;IACH,SAAS,CAAC,eAAe,IAAI,MAAM;IAInC;;;OAGG;IACH,SAAS,CAAC,YAAY,IAAI,MAAM,GAAG,SAAS;IAI5C;;;;;;;;;;;;;;;;OAgBG;IACH,SAAS,CAAC,uBAAuB,IAAI,oBAAoB,GAAG,SAAS;IAIrE;;;OAGG;IACH,SAAS,CAAC,uBAAuB,CAAC,MAAM,EAAE,oBAAoB,GAAG,IAAI;IAIrE;;;;;;;;;;;;;OAaG;IACH,SAAS,CAAC,qBAAqB,IAAI,uBAAuB,GAAG,SAAS;IAItE;;;;;;;OAOG;IACH,SAAS,KAAK,qBAAqB,IAAI,OAAO,CAE7C;IAED;;;OAGG;IACH,SAAS,CAAC,QAAQ,CAAC,wBAAwB,CACzC,GAAG,EAAE,aAAa,GACjB,uBAAuB;IAE1B;;;OAGG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAyB3B;;;OAGG;IACH,SAAS,CAAC,QAAQ,CAAC,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI;IAExD;;;;;;;;;;OAUG;YACW,yBAAyB;IA4lBvC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA8BG;IACH,SAAS,CAAC,qBAAqB,CAAC,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7D,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,GAAG,EAAE,gDAAgD;IAC7D,OAAO,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,OAAO,CAAC,EAAE,oBAAoB,KAAK,OAAO,CAAC,GAAG,CAAC,GACrE,IAAI;IAkIP;;;;;;;;;;OAUG;cACa,oBAAoB,CAClC,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,OAAO,GAAG,OAAO,EAEjB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,KAAK,EACX,OAAO,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,OAAO,CAAC,EAAE,oBAAoB,KAAK,OAAO,CAAC,OAAO,CAAC,EAC1E,iBAAiB,CAAC,EAAE,MAAM,GACzB,OAAO,CAAC,OAAO,CAAC;IAk6BnB;;;;;;;;;OASG;YACW,gBAAgB;IA0jB9B;;;;;;;;;;;;;;;;;OAiBG;YACW,qBAAqB;IA8GnC;;;;;;;OAOG;YACW,6BAA6B;IA4D3C;;;;OAIG;IACH,OAAO,CAAC,qBAAqB;IAQ7B,aAAa,IAAI,MAAM;IAUvB;;;;;;;;;;;;OAYG;IACG,KAAK,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC;IAuvBhD;;;;;;;;;;;;;;;;OAgBG;IACG,wBAAwB,IAAI,OAAO,CAAC;QACxC,OAAO,EAAE,OAAO,CAAC;QACjB,YAAY,EAAE,OAAO,CAAC;QACtB,eAAe,EAAE,OAAO,CAAC;QACzB,SAAS,EAAE,MAAM,CAAC;QAClB,cAAc,EAAE,MAAM,EAAE,CAAC;QACzB,oBAAoB,CAAC,EAAE,OAAO,CAAC;QAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;IA2HF;;;;;;;;OAQG;cACa,wBAAwB,CAAC,IAAI,EAAE;QAC7C,SAAS,EAAE,MAAM,CAAC;QAClB,eAAe,EAAE,MAAM,CAAC;QACxB,YAAY,EAAE,MAAM,CAAC;QACrB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC;QAMjB,iBAAiB,CAAC,EAAE,MAAM,CAAC;KAC5B,GAAG,OAAO,CAAC,IAAI,CAAC;IAmCjB;;;;;;;;;;;;;;;;OAgBG;cACa,wBAAwB,CACtC,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,MAAM,EAChB,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CACN;QACE,eAAe,EAAE,MAAM,CAAC;QACxB,YAAY,EAAE,MAAM,CAAC;QACrB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC;QAEjB,iBAAiB,CAAC,EAAE,MAAM,CAAC;QAC3B,QAAQ,EAAE,MAAM,CAAC;KAClB,GACD,SAAS,CACZ;IA2HD;;;;;;;;;;;;OAYG;YACW,sBAAsB;IA0FpC;;;;;;;;;;;;;OAaG;YACW,wBAAwB;IAqEtC;;;;;;OAMG;YACW,qBAAqB;CA+DpC"}
|
package/dist/agent.js
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
import { McpAgent } from "agents/mcp";
|
|
9
9
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
10
10
|
import { AdmissionMcpServer, getMcpRequestHolder, getMcpPresentedDelegation, } from "./security/mcp-admission";
|
|
11
|
-
import { resolveHttpChallengeConfig } from "./config";
|
|
11
|
+
import { localToolProtectionConfig, resolveHttpChallengeConfig, } from "./config";
|
|
12
12
|
import { CloudflareRuntime } from "./runtime";
|
|
13
13
|
import { createCloudflareRuntime } from "./index";
|
|
14
14
|
import { mapPrefixedEnv } from "./helpers/env-mapper";
|
|
@@ -53,6 +53,20 @@ if (!_oauthRegistryLoaded) {
|
|
|
53
53
|
// Logger not yet configured at module init, use console.warn as fallback
|
|
54
54
|
console.warn("[MCPICloudflareAgent] OAuth service registry not loaded at module init - services may be unavailable");
|
|
55
55
|
}
|
|
56
|
+
function jsonSchemaPropertyToZod(prop) {
|
|
57
|
+
switch (prop.type) {
|
|
58
|
+
case "string":
|
|
59
|
+
return z.string();
|
|
60
|
+
case "number":
|
|
61
|
+
return z.number();
|
|
62
|
+
case "boolean":
|
|
63
|
+
return z.boolean();
|
|
64
|
+
case "array":
|
|
65
|
+
return z.array(z.any());
|
|
66
|
+
default:
|
|
67
|
+
return undefined;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
56
70
|
/**
|
|
57
71
|
* Base class for MCP agents with MCP-I features
|
|
58
72
|
*
|
|
@@ -117,7 +131,12 @@ export class MCPICloudflareAgent extends McpAgent {
|
|
|
117
131
|
// Load runtime configuration from subclass
|
|
118
132
|
const runtimeConfig = this.getRuntimeConfigInternal(mappedEnv);
|
|
119
133
|
if (runtimeConfig.requestAdmission) {
|
|
120
|
-
this.server = new AdmissionMcpServer({ name: agentName, version: agentVersion || "1.0.0" }, runtimeConfig.requestAdmission
|
|
134
|
+
this.server = new AdmissionMcpServer({ name: agentName, version: agentVersion || "1.0.0" }, runtimeConfig.requestAdmission, {
|
|
135
|
+
// Read at report time: mcpiRuntime is created further down.
|
|
136
|
+
reportRefusal: async (report) => {
|
|
137
|
+
await this.mcpiRuntime?.reportAdmissionRefusal(report);
|
|
138
|
+
},
|
|
139
|
+
});
|
|
121
140
|
}
|
|
122
141
|
const managedAudit = createCloudflareAuditRuntimeFromEnv(mappedEnv);
|
|
123
142
|
if (managedAudit !== undefined) {
|
|
@@ -148,17 +167,13 @@ export class MCPICloudflareAgent extends McpAgent {
|
|
|
148
167
|
"https://kya.vouched.id",
|
|
149
168
|
apiKey: mappedEnv.CHECKPOINT_API_KEY,
|
|
150
169
|
projectId: (runtimeConfig.toolProtection.checkpoint ??
|
|
151
|
-
runtimeConfig.toolProtection.agentShield)?.projectId ||
|
|
152
|
-
mappedEnv.CHECKPOINT_PROJECT_ID,
|
|
170
|
+
runtimeConfig.toolProtection.agentShield)?.projectId || mappedEnv.CHECKPOINT_PROJECT_ID,
|
|
153
171
|
cacheTtl: (runtimeConfig.toolProtection.checkpoint ??
|
|
154
172
|
runtimeConfig.toolProtection.agentShield)?.cacheTtl || 300000,
|
|
155
173
|
debug: runtimeConfig.environment === "development",
|
|
156
|
-
//
|
|
157
|
-
//
|
|
158
|
-
|
|
159
|
-
localConfig: runtimeConfig.toolProtection.localConfig
|
|
160
|
-
? { toolProtections: runtimeConfig.toolProtection.localConfig }
|
|
161
|
-
: undefined,
|
|
174
|
+
// The local maps, `localConfig` and `inline`, in the service's
|
|
175
|
+
// ToolProtectionConfig shape ({ toolProtections: ToolProtectionMap }).
|
|
176
|
+
localConfig: localToolProtectionConfig(runtimeConfig.toolProtection),
|
|
162
177
|
// Wrap offlineFallbackConfig the same way
|
|
163
178
|
offlineFallbackConfig: runtimeConfig.toolProtection
|
|
164
179
|
.offlineFallbackConfig
|
|
@@ -1018,6 +1033,9 @@ export class MCPICloudflareAgent extends McpAgent {
|
|
|
1018
1033
|
resume_token: args.resume_token,
|
|
1019
1034
|
termsAccepted: true,
|
|
1020
1035
|
approved: true,
|
|
1036
|
+
// The iframe's consent-only approval. /consent/approve refuses
|
|
1037
|
+
// a missing provider_type.
|
|
1038
|
+
provider_type: "none",
|
|
1021
1039
|
}),
|
|
1022
1040
|
});
|
|
1023
1041
|
if (!resp.ok) {
|
|
@@ -1202,45 +1220,43 @@ export class MCPICloudflareAgent extends McpAgent {
|
|
|
1202
1220
|
// MCP SDK expects Zod schema shape (Record<string, ZodType>), not JSON Schema
|
|
1203
1221
|
// Convert JSON Schema to Zod schema shape if needed
|
|
1204
1222
|
let zodSchemaShape = {};
|
|
1223
|
+
let acceptsExtraArguments = false;
|
|
1224
|
+
let extraArgumentsSchema;
|
|
1205
1225
|
if (schema && typeof schema === "object") {
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1226
|
+
const isZodInstance = "_def" in schema ||
|
|
1227
|
+
"_zod" in schema ||
|
|
1228
|
+
typeof schema.parse === "function";
|
|
1229
|
+
const isRawShape = isZodInstance ||
|
|
1230
|
+
Object.keys(schema).length === 0 ||
|
|
1231
|
+
Object.values(schema).some((value) => typeof value?.parse === "function");
|
|
1232
|
+
if (!isRawShape) {
|
|
1209
1233
|
const jsonSchema = schema;
|
|
1210
|
-
const
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
}
|
|
1225
|
-
}
|
|
1226
|
-
else if (prop.type === "boolean") {
|
|
1227
|
-
zodType = z.boolean();
|
|
1228
|
-
if (prop.description) {
|
|
1229
|
-
zodType = zodType.describe(prop.description);
|
|
1230
|
-
}
|
|
1231
|
-
}
|
|
1232
|
-
else if (prop.type === "array") {
|
|
1233
|
-
zodType = z.array(z.any());
|
|
1234
|
-
if (prop.description) {
|
|
1235
|
-
zodType = zodType.describe(prop.description);
|
|
1236
|
-
}
|
|
1234
|
+
const declaredType = [jsonSchema.type ?? "object"].flat();
|
|
1235
|
+
if (!declaredType.includes("object")) {
|
|
1236
|
+
throw new Error(`Tool "${name}" input schema must describe an object, received type ${declaredType.join(", ")}`);
|
|
1237
|
+
}
|
|
1238
|
+
const additional = jsonSchema.additionalProperties;
|
|
1239
|
+
const additionalSchema = additional !== null &&
|
|
1240
|
+
typeof additional === "object" &&
|
|
1241
|
+
Object.keys(additional).length > 0
|
|
1242
|
+
? additional
|
|
1243
|
+
: undefined;
|
|
1244
|
+
if (additionalSchema) {
|
|
1245
|
+
const converted = jsonSchemaPropertyToZod(additionalSchema);
|
|
1246
|
+
if (!converted) {
|
|
1247
|
+
throw new Error(`Tool "${name}" input schema declares additionalProperties that cannot be converted to a validator: ${JSON.stringify(additionalSchema)}`);
|
|
1237
1248
|
}
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1249
|
+
extraArgumentsSchema = converted;
|
|
1250
|
+
}
|
|
1251
|
+
acceptsExtraArguments =
|
|
1252
|
+
!additionalSchema &&
|
|
1253
|
+
additional !== false &&
|
|
1254
|
+
(additional != null || jsonSchema.properties == null);
|
|
1255
|
+
const requiredFields = new Set(jsonSchema.required || []);
|
|
1256
|
+
zodSchemaShape = Object.fromEntries(Object.entries(jsonSchema.properties ?? {}).map(([key, prop]) => {
|
|
1257
|
+
let zodType = jsonSchemaPropertyToZod(prop) ?? z.any();
|
|
1258
|
+
if (prop.description) {
|
|
1259
|
+
zodType = zodType.describe(prop.description);
|
|
1244
1260
|
}
|
|
1245
1261
|
// Make optional if not in required array
|
|
1246
1262
|
if (!requiredFields.has(key)) {
|
|
@@ -1268,7 +1284,11 @@ export class MCPICloudflareAgent extends McpAgent {
|
|
|
1268
1284
|
// so clients know this tool can render inline consent UI
|
|
1269
1285
|
const toolConfig = {
|
|
1270
1286
|
description,
|
|
1271
|
-
inputSchema:
|
|
1287
|
+
inputSchema: extraArgumentsSchema
|
|
1288
|
+
? z.object(zodSchemaShape).catchall(extraArgumentsSchema)
|
|
1289
|
+
: acceptsExtraArguments
|
|
1290
|
+
? z.object(zodSchemaShape).passthrough()
|
|
1291
|
+
: zodSchemaShape,
|
|
1272
1292
|
};
|
|
1273
1293
|
if (this._consentUIResourceUri) {
|
|
1274
1294
|
// Include BOTH new nested format AND legacy flat format for maximum client compatibility
|
|
@@ -1453,7 +1473,8 @@ export class MCPICloudflareAgent extends McpAgent {
|
|
|
1453
1473
|
// stored type) → fail-safe re-challenge on typed tools.
|
|
1454
1474
|
let delegationAuthorizationType;
|
|
1455
1475
|
try {
|
|
1456
|
-
const agentDid = getMcpRequestHolder()?.did ??
|
|
1476
|
+
const agentDid = getMcpRequestHolder()?.did ??
|
|
1477
|
+
(await this.mcpiRuntime.getIdentity()).did;
|
|
1457
1478
|
logger.debug("[MCPICloudflareAgent] 🔍 Starting delegation lookup (DO storage):", {
|
|
1458
1479
|
sessionId: sessionId.slice(0, 20) + "...",
|
|
1459
1480
|
agentDid: agentDid.slice(0, 20) + "...",
|
|
@@ -1566,7 +1587,8 @@ export class MCPICloudflareAgent extends McpAgent {
|
|
|
1566
1587
|
const session = {
|
|
1567
1588
|
id: sessionId,
|
|
1568
1589
|
audience: "https://kya.vouched.id",
|
|
1569
|
-
agentDid: getMcpRequestHolder()?.did ??
|
|
1590
|
+
agentDid: getMcpRequestHolder()?.did ??
|
|
1591
|
+
(await this.mcpiRuntime.getIdentity()).did,
|
|
1570
1592
|
// Trusted per-request proof result; never a client-supplied DID label.
|
|
1571
1593
|
verifiedInvokerDid: getMcpRequestHolder()?.did,
|
|
1572
1594
|
agentName: this.getAgentName() || mappedEnv.MCP_SERVER_NAME || "Unknown Agent", // Human-readable agent name for Checkpoint dashboard
|
|
@@ -2028,7 +2050,15 @@ export class MCPICloudflareAgent extends McpAgent {
|
|
|
2028
2050
|
try {
|
|
2029
2051
|
// Retrieve password auth token - getToken handles scope hashing internally
|
|
2030
2052
|
const storedToken = await idpTokenStorage.getToken(userDid, provider, protection.requiredScopes || []);
|
|
2031
|
-
|
|
2053
|
+
// SECURITY (defence in depth): a presented delegation must satisfy
|
|
2054
|
+
// the tool's required type before the user's stored credential token
|
|
2055
|
+
// is handed to the tool, the same rule as the delegation-only path
|
|
2056
|
+
// below. Otherwise a delegation minted under the user's DID without
|
|
2057
|
+
// their sign-in would unlock their token. Not presenting a
|
|
2058
|
+
// delegation keeps the existing behaviour.
|
|
2059
|
+
const presentedDelegationAllowed = !delegationToken ||
|
|
2060
|
+
authTypeSatisfies(delegationAuthorizationType, protection.authorization?.type ?? "password");
|
|
2061
|
+
if (storedToken && presentedDelegationAllowed) {
|
|
2032
2062
|
// Build headers based on token usage metadata
|
|
2033
2063
|
const tokenWithMeta = storedToken;
|
|
2034
2064
|
const idpHeaders = {};
|
|
@@ -2068,7 +2098,7 @@ export class MCPICloudflareAgent extends McpAgent {
|
|
|
2068
2098
|
return context;
|
|
2069
2099
|
}
|
|
2070
2100
|
else {
|
|
2071
|
-
// No password auth token
|
|
2101
|
+
// No usable password auth token - check if delegation exists
|
|
2072
2102
|
// If delegation exists, tool can still execute without credential token
|
|
2073
2103
|
//
|
|
2074
2104
|
// SECURITY (consent-approve auth-gate, Task B3): the delegation only
|