/** * Level 2 Capability Attestation Validator * * Implements the Level 2 conformance behavior described in the MCP-I spec: * https://github.com/modelcontextprotocol-identity/modelcontextprotocol-identity/pull/46 * * For each declared capability in the agent manifest, verify at least one * attached Verifiable Credential where ALL of the following hold: * - VC signature verifies (delegated to a platform-specific verifier) * - issuer DID is in the trusted issuer registry * - credentialSubject.id matches the agent DID * - credentialSubject.capability matches the declared capability name * - validUntil is in the future (and validFrom is in the past, when present) * * Revocation (StatusList2021) is OPTIONAL for v1 and not enforced here. * * Capabilities that fail validation are NOT thrown — they are returned in the * `invalid` array along with the reasons, so callers can surface diagnostics * to UI without a hard failure. * * The legacy Level 1 `string[]` form is accepted as input: every entry is * returned under `valid` along with a global warning so callers can surface * the missing attestation context. */ /** * Default trusted issuer registry. * * Matches the spec default: `did:web:knowthat.ai`. Callers MAY substitute or * extend this allowlist via {@link ValidateLevel2Options.trustedIssuers}. */ export declare const DEFAULT_TRUSTED_ISSUERS: readonly string[]; /** * Capability name as declared in the agent manifest (e.g. `payments.transfer`). */ export type CapabilityName = string; /** * Minimal shape of a `CapabilityAttestationCredential` per the spec. * * Only the fields the validator inspects are typed strictly — additional * fields (`@context`, `type`, `proof`, etc.) are passed through. */ export interface CapabilityAttestationCredential { '@context'?: string | string[]; type?: string | string[]; issuer: string | { id: string; }; validFrom?: string; validUntil?: string; credentialSubject: { id: string; capability: string; scope?: Record; }; proof?: unknown; [key: string]: unknown; } /** * Single attestation entry attached to a Level 2 capability. * * The `vc` field MAY be a compact JWT string (per the spec example) OR a * pre-parsed credential object (convenient for tests and callers that have * already decoded the JWT). * * `issuer` and `type` are OPTIONAL envelope metadata hints — they are * informational only and play NO role in trust evaluation. The validator * derives the authoritative issuer from `vc.issuer` (the signed credential * itself), so a wrong or attacker-supplied envelope `issuer` cannot grant * trust. If you need to record the credential type, prefer `vc.type` inside * the VC, which is covered by the signature. */ export interface CapabilityAttestation { vc: string | CapabilityAttestationCredential; /** * Optional metadata hint. NOT consulted during validation — `vc.issuer` is * authoritative for the trusted-issuer check. */ issuer?: string; /** * Optional metadata hint. NOT consulted during validation. */ type?: string; } /** * Level 2 capability entry. */ export interface Level2Capability { name: CapabilityName; attestations: CapabilityAttestation[]; } /** * Manifest capabilities — accepts either the legacy Level 1 string array or * the Level 2 object array. Mixed entries within a single Level 2 array are * tolerated (string entries are dropped with a per-capability warning). */ export type ManifestCapabilities = readonly CapabilityName[] | readonly (Level2Capability | CapabilityName)[]; /** * Pluggable signature verifier for capability attestations. * * Cryptographic verification (Ed25519, ES256, etc.) is platform-specific, so * the validator delegates the signature check. Implementations should resolve * the issuer DID, locate the verification method, and verify the proof. * * If no verifier is supplied, the validator emits a single global warning and * treats every signature as valid — useful for development but unsafe in * production. This mirrors `DelegationCredentialVerifier`'s behavior when no * `signatureVerifier` is provided. */ export type CapabilityVCSignatureVerifier = (vc: CapabilityAttestationCredential, rawJwt: string | undefined) => Promise<{ valid: boolean; reason?: string; }>; /** * Reserved hook for StatusList2021-based revocation checks. * * Not invoked in v1. Reserved so callers can pass a resolver today and have * it activate transparently once revocation enforcement lands. */ export type CapabilityStatusListResolver = (vc: CapabilityAttestationCredential) => Promise<{ revoked: boolean; reason?: string; }>; /** * Validator options. */ export interface ValidateLevel2Options { /** * The agent DID being validated. `credentialSubject.id` on each VC MUST * match this exactly. */ agentDid: string; /** * Trusted issuer DID allowlist. Defaults to {@link DEFAULT_TRUSTED_ISSUERS}. * If supplied, replaces (does NOT merge with) the default — callers wanting * to extend the default should spread it themselves. */ trustedIssuers?: readonly string[]; /** * Platform-specific signature verifier. If omitted, signatures are accepted * unverified and a global warning is emitted. */ signatureVerifier?: CapabilityVCSignatureVerifier; /** * StatusList2021 revocation hook. Reserved — not invoked in v1. * * TODO(v1.x): wire this into the per-attestation check loop once the * StatusList2021 contract is finalized for capability attestations. */ statusListResolver?: CapabilityStatusListResolver; /** * Clock injection for tests. Defaults to `new Date()`. */ now?: () => Date; } /** * Per-capability failure record. */ export interface InvalidCapability { capability: CapabilityName; reasons: string[]; } /** * Validator result. * * - `valid` lists the capability names that passed validation. * - `invalid` lists the capabilities that were declared but failed, with the * accumulated reasons across every attached attestation. * - `warnings` carries non-fatal diagnostics (e.g. "no signature verifier * provided", or Level 1 input). */ export interface ValidateLevel2Result { valid: CapabilityName[]; invalid: InvalidCapability[]; warnings: string[]; } /** * Verify an MCP-I agent's declared capability attestations (Level 2). * * Named for the action it performs — verifying capability ATTESTATIONS — rather * than the conformance level. {@link validateLevel2} remains exported as a * non-breaking `@deprecated` alias. * * @example * ```ts * const result = await verifyCapabilities(manifest.capabilities, { * agentDid: 'did:web:securebank.example', * trustedIssuers: ['did:web:knowthat.ai'], * signatureVerifier: myEd25519Verifier, * }); * * console.log(result.valid); // ['payments.transfer'] * console.log(result.invalid); // [{ capability: 'accounts.read', reasons: [...] }] * console.log(result.warnings); // [] * ``` */ export declare function verifyCapabilities(capabilities: unknown, options: ValidateLevel2Options): Promise; /** * @deprecated Renamed to {@link verifyCapabilities}. Retained as a non-breaking * alias — the two are referentially identical. Prefer `verifyCapabilities` in * new code; this alias will be removed in a future major. */ export declare const validateLevel2: typeof verifyCapabilities; //# sourceMappingURL=validate-level2.d.ts.map