@kya-os/mcp-i-core 1.6.2 → 1.8.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 +1 -1
- package/dist/conformance/index.d.ts +8 -0
- package/dist/conformance/index.js +13 -0
- package/dist/conformance/validate-level2.d.ts +193 -0
- package/dist/conformance/validate-level2.js +284 -0
- package/dist/delegation/outbound-proof.d.ts +3 -2
- package/dist/delegation/outbound-proof.js +3 -2
- package/dist/delegation/utils.d.ts +3 -1
- package/dist/index.d.ts +8 -63
- package/dist/index.js +14 -161
- package/dist/utils/base58.d.ts +4 -28
- package/dist/utils/base58.js +18 -98
- package/dist/utils/base64.d.ts +4 -29
- package/dist/utils/base64.js +18 -167
- package/dist/utils/did-helpers.d.ts +4 -165
- package/dist/utils/did-helpers.js +18 -217
- package/package.json +5 -7
package/README.md
CHANGED
|
@@ -151,7 +151,7 @@ import { MCPIRuntimeBaseV2 } from '@kya-os/mcp-i-core';
|
|
|
151
151
|
class MyPlatformRuntime extends MCPIRuntimeBaseV2 {
|
|
152
152
|
constructor() {
|
|
153
153
|
super({
|
|
154
|
-
cryptoProvider: new
|
|
154
|
+
cryptoProvider: new MyCryptoProvider(),
|
|
155
155
|
identityProvider: new MyIdentityProvider(),
|
|
156
156
|
storageProvider: new MyStorageProvider(),
|
|
157
157
|
nonceCacheProvider: new MyNonceCacheProvider(),
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP-I Conformance Level helpers.
|
|
3
|
+
*
|
|
4
|
+
* See docs/conformance-levels for the spec page (introduced in
|
|
5
|
+
* modelcontextprotocol-identity#46).
|
|
6
|
+
*/
|
|
7
|
+
export { validateLevel2, DEFAULT_TRUSTED_ISSUERS, type CapabilityName, type CapabilityAttestation, type CapabilityAttestationCredential, type Level2Capability, type ManifestCapabilities, type CapabilityVCSignatureVerifier, type CapabilityStatusListResolver, type ValidateLevel2Options, type ValidateLevel2Result, type InvalidCapability, } from './validate-level2.js';
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* MCP-I Conformance Level helpers.
|
|
4
|
+
*
|
|
5
|
+
* See docs/conformance-levels for the spec page (introduced in
|
|
6
|
+
* modelcontextprotocol-identity#46).
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.DEFAULT_TRUSTED_ISSUERS = exports.validateLevel2 = void 0;
|
|
10
|
+
var validate_level2_js_1 = require("./validate-level2.js");
|
|
11
|
+
Object.defineProperty(exports, "validateLevel2", { enumerable: true, get: function () { return validate_level2_js_1.validateLevel2; } });
|
|
12
|
+
Object.defineProperty(exports, "DEFAULT_TRUSTED_ISSUERS", { enumerable: true, get: function () { return validate_level2_js_1.DEFAULT_TRUSTED_ISSUERS; } });
|
|
13
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Level 2 Capability Attestation Validator
|
|
3
|
+
*
|
|
4
|
+
* Implements the Level 2 conformance behavior described in the MCP-I spec:
|
|
5
|
+
* https://github.com/modelcontextprotocol-identity/modelcontextprotocol-identity/pull/46
|
|
6
|
+
*
|
|
7
|
+
* For each declared capability in the agent manifest, verify at least one
|
|
8
|
+
* attached Verifiable Credential where ALL of the following hold:
|
|
9
|
+
* - VC signature verifies (delegated to a platform-specific verifier)
|
|
10
|
+
* - issuer DID is in the trusted issuer registry
|
|
11
|
+
* - credentialSubject.id matches the agent DID
|
|
12
|
+
* - credentialSubject.capability matches the declared capability name
|
|
13
|
+
* - validUntil is in the future (and validFrom is in the past, when present)
|
|
14
|
+
*
|
|
15
|
+
* Revocation (StatusList2021) is OPTIONAL for v1 and not enforced here.
|
|
16
|
+
*
|
|
17
|
+
* Capabilities that fail validation are NOT thrown — they are returned in the
|
|
18
|
+
* `invalid` array along with the reasons, so callers can surface diagnostics
|
|
19
|
+
* to UI without a hard failure.
|
|
20
|
+
*
|
|
21
|
+
* The legacy Level 1 `string[]` form is accepted as input: every entry is
|
|
22
|
+
* returned under `valid` along with a global warning so callers can surface
|
|
23
|
+
* the missing attestation context.
|
|
24
|
+
*/
|
|
25
|
+
/**
|
|
26
|
+
* Default trusted issuer registry.
|
|
27
|
+
*
|
|
28
|
+
* Matches the spec default: `did:web:knowthat.ai`. Callers MAY substitute or
|
|
29
|
+
* extend this allowlist via {@link ValidateLevel2Options.trustedIssuers}.
|
|
30
|
+
*/
|
|
31
|
+
export declare const DEFAULT_TRUSTED_ISSUERS: readonly string[];
|
|
32
|
+
/**
|
|
33
|
+
* Capability name as declared in the agent manifest (e.g. `payments.transfer`).
|
|
34
|
+
*/
|
|
35
|
+
export type CapabilityName = string;
|
|
36
|
+
/**
|
|
37
|
+
* Minimal shape of a `CapabilityAttestationCredential` per the spec.
|
|
38
|
+
*
|
|
39
|
+
* Only the fields the validator inspects are typed strictly — additional
|
|
40
|
+
* fields (`@context`, `type`, `proof`, etc.) are passed through.
|
|
41
|
+
*/
|
|
42
|
+
export interface CapabilityAttestationCredential {
|
|
43
|
+
'@context'?: string | string[];
|
|
44
|
+
type?: string | string[];
|
|
45
|
+
issuer: string | {
|
|
46
|
+
id: string;
|
|
47
|
+
};
|
|
48
|
+
validFrom?: string;
|
|
49
|
+
validUntil?: string;
|
|
50
|
+
credentialSubject: {
|
|
51
|
+
id: string;
|
|
52
|
+
capability: string;
|
|
53
|
+
scope?: Record<string, unknown>;
|
|
54
|
+
};
|
|
55
|
+
proof?: unknown;
|
|
56
|
+
[key: string]: unknown;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Single attestation entry attached to a Level 2 capability.
|
|
60
|
+
*
|
|
61
|
+
* The `vc` field MAY be a compact JWT string (per the spec example) OR a
|
|
62
|
+
* pre-parsed credential object (convenient for tests and callers that have
|
|
63
|
+
* already decoded the JWT).
|
|
64
|
+
*
|
|
65
|
+
* `issuer` and `type` are OPTIONAL envelope metadata hints — they are
|
|
66
|
+
* informational only and play NO role in trust evaluation. The validator
|
|
67
|
+
* derives the authoritative issuer from `vc.issuer` (the signed credential
|
|
68
|
+
* itself), so a wrong or attacker-supplied envelope `issuer` cannot grant
|
|
69
|
+
* trust. If you need to record the credential type, prefer `vc.type` inside
|
|
70
|
+
* the VC, which is covered by the signature.
|
|
71
|
+
*/
|
|
72
|
+
export interface CapabilityAttestation {
|
|
73
|
+
vc: string | CapabilityAttestationCredential;
|
|
74
|
+
/**
|
|
75
|
+
* Optional metadata hint. NOT consulted during validation — `vc.issuer` is
|
|
76
|
+
* authoritative for the trusted-issuer check.
|
|
77
|
+
*/
|
|
78
|
+
issuer?: string;
|
|
79
|
+
/**
|
|
80
|
+
* Optional metadata hint. NOT consulted during validation.
|
|
81
|
+
*/
|
|
82
|
+
type?: string;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Level 2 capability entry.
|
|
86
|
+
*/
|
|
87
|
+
export interface Level2Capability {
|
|
88
|
+
name: CapabilityName;
|
|
89
|
+
attestations: CapabilityAttestation[];
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Manifest capabilities — accepts either the legacy Level 1 string array or
|
|
93
|
+
* the Level 2 object array. Mixed entries within a single Level 2 array are
|
|
94
|
+
* tolerated (string entries are dropped with a per-capability warning).
|
|
95
|
+
*/
|
|
96
|
+
export type ManifestCapabilities = readonly CapabilityName[] | readonly (Level2Capability | CapabilityName)[];
|
|
97
|
+
/**
|
|
98
|
+
* Pluggable signature verifier for capability attestations.
|
|
99
|
+
*
|
|
100
|
+
* Cryptographic verification (Ed25519, ES256, etc.) is platform-specific, so
|
|
101
|
+
* the validator delegates the signature check. Implementations should resolve
|
|
102
|
+
* the issuer DID, locate the verification method, and verify the proof.
|
|
103
|
+
*
|
|
104
|
+
* If no verifier is supplied, the validator emits a single global warning and
|
|
105
|
+
* treats every signature as valid — useful for development but unsafe in
|
|
106
|
+
* production. This mirrors `DelegationCredentialVerifier`'s behavior when no
|
|
107
|
+
* `signatureVerifier` is provided.
|
|
108
|
+
*/
|
|
109
|
+
export type CapabilityVCSignatureVerifier = (vc: CapabilityAttestationCredential, rawJwt: string | undefined) => Promise<{
|
|
110
|
+
valid: boolean;
|
|
111
|
+
reason?: string;
|
|
112
|
+
}>;
|
|
113
|
+
/**
|
|
114
|
+
* Reserved hook for StatusList2021-based revocation checks.
|
|
115
|
+
*
|
|
116
|
+
* Not invoked in v1. Reserved so callers can pass a resolver today and have
|
|
117
|
+
* it activate transparently once revocation enforcement lands.
|
|
118
|
+
*/
|
|
119
|
+
export type CapabilityStatusListResolver = (vc: CapabilityAttestationCredential) => Promise<{
|
|
120
|
+
revoked: boolean;
|
|
121
|
+
reason?: string;
|
|
122
|
+
}>;
|
|
123
|
+
/**
|
|
124
|
+
* Validator options.
|
|
125
|
+
*/
|
|
126
|
+
export interface ValidateLevel2Options {
|
|
127
|
+
/**
|
|
128
|
+
* The agent DID being validated. `credentialSubject.id` on each VC MUST
|
|
129
|
+
* match this exactly.
|
|
130
|
+
*/
|
|
131
|
+
agentDid: string;
|
|
132
|
+
/**
|
|
133
|
+
* Trusted issuer DID allowlist. Defaults to {@link DEFAULT_TRUSTED_ISSUERS}.
|
|
134
|
+
* If supplied, replaces (does NOT merge with) the default — callers wanting
|
|
135
|
+
* to extend the default should spread it themselves.
|
|
136
|
+
*/
|
|
137
|
+
trustedIssuers?: readonly string[];
|
|
138
|
+
/**
|
|
139
|
+
* Platform-specific signature verifier. If omitted, signatures are accepted
|
|
140
|
+
* unverified and a global warning is emitted.
|
|
141
|
+
*/
|
|
142
|
+
signatureVerifier?: CapabilityVCSignatureVerifier;
|
|
143
|
+
/**
|
|
144
|
+
* StatusList2021 revocation hook. Reserved — not invoked in v1.
|
|
145
|
+
*
|
|
146
|
+
* TODO(v1.x): wire this into the per-attestation check loop once the
|
|
147
|
+
* StatusList2021 contract is finalized for capability attestations.
|
|
148
|
+
*/
|
|
149
|
+
statusListResolver?: CapabilityStatusListResolver;
|
|
150
|
+
/**
|
|
151
|
+
* Clock injection for tests. Defaults to `new Date()`.
|
|
152
|
+
*/
|
|
153
|
+
now?: () => Date;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Per-capability failure record.
|
|
157
|
+
*/
|
|
158
|
+
export interface InvalidCapability {
|
|
159
|
+
capability: CapabilityName;
|
|
160
|
+
reasons: string[];
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Validator result.
|
|
164
|
+
*
|
|
165
|
+
* - `valid` lists the capability names that passed validation.
|
|
166
|
+
* - `invalid` lists the capabilities that were declared but failed, with the
|
|
167
|
+
* accumulated reasons across every attached attestation.
|
|
168
|
+
* - `warnings` carries non-fatal diagnostics (e.g. "no signature verifier
|
|
169
|
+
* provided", or Level 1 input).
|
|
170
|
+
*/
|
|
171
|
+
export interface ValidateLevel2Result {
|
|
172
|
+
valid: CapabilityName[];
|
|
173
|
+
invalid: InvalidCapability[];
|
|
174
|
+
warnings: string[];
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Validate an MCP-I agent's declared capabilities at Level 2.
|
|
178
|
+
*
|
|
179
|
+
* @example
|
|
180
|
+
* ```ts
|
|
181
|
+
* const result = await validateLevel2(manifest.capabilities, {
|
|
182
|
+
* agentDid: 'did:web:securebank.example',
|
|
183
|
+
* trustedIssuers: ['did:web:knowthat.ai'],
|
|
184
|
+
* signatureVerifier: myEd25519Verifier,
|
|
185
|
+
* });
|
|
186
|
+
*
|
|
187
|
+
* console.log(result.valid); // ['payments.transfer']
|
|
188
|
+
* console.log(result.invalid); // [{ capability: 'accounts.read', reasons: [...] }]
|
|
189
|
+
* console.log(result.warnings); // []
|
|
190
|
+
* ```
|
|
191
|
+
*/
|
|
192
|
+
export declare function validateLevel2(capabilities: unknown, options: ValidateLevel2Options): Promise<ValidateLevel2Result>;
|
|
193
|
+
//# sourceMappingURL=validate-level2.d.ts.map
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Level 2 Capability Attestation Validator
|
|
4
|
+
*
|
|
5
|
+
* Implements the Level 2 conformance behavior described in the MCP-I spec:
|
|
6
|
+
* https://github.com/modelcontextprotocol-identity/modelcontextprotocol-identity/pull/46
|
|
7
|
+
*
|
|
8
|
+
* For each declared capability in the agent manifest, verify at least one
|
|
9
|
+
* attached Verifiable Credential where ALL of the following hold:
|
|
10
|
+
* - VC signature verifies (delegated to a platform-specific verifier)
|
|
11
|
+
* - issuer DID is in the trusted issuer registry
|
|
12
|
+
* - credentialSubject.id matches the agent DID
|
|
13
|
+
* - credentialSubject.capability matches the declared capability name
|
|
14
|
+
* - validUntil is in the future (and validFrom is in the past, when present)
|
|
15
|
+
*
|
|
16
|
+
* Revocation (StatusList2021) is OPTIONAL for v1 and not enforced here.
|
|
17
|
+
*
|
|
18
|
+
* Capabilities that fail validation are NOT thrown — they are returned in the
|
|
19
|
+
* `invalid` array along with the reasons, so callers can surface diagnostics
|
|
20
|
+
* to UI without a hard failure.
|
|
21
|
+
*
|
|
22
|
+
* The legacy Level 1 `string[]` form is accepted as input: every entry is
|
|
23
|
+
* returned under `valid` along with a global warning so callers can surface
|
|
24
|
+
* the missing attestation context.
|
|
25
|
+
*/
|
|
26
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
27
|
+
exports.DEFAULT_TRUSTED_ISSUERS = void 0;
|
|
28
|
+
exports.validateLevel2 = validateLevel2;
|
|
29
|
+
const utils_js_1 = require("../delegation/utils.js");
|
|
30
|
+
/**
|
|
31
|
+
* Default trusted issuer registry.
|
|
32
|
+
*
|
|
33
|
+
* Matches the spec default: `did:web:knowthat.ai`. Callers MAY substitute or
|
|
34
|
+
* extend this allowlist via {@link ValidateLevel2Options.trustedIssuers}.
|
|
35
|
+
*/
|
|
36
|
+
exports.DEFAULT_TRUSTED_ISSUERS = [
|
|
37
|
+
'did:web:knowthat.ai',
|
|
38
|
+
];
|
|
39
|
+
/**
|
|
40
|
+
* Validate an MCP-I agent's declared capabilities at Level 2.
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```ts
|
|
44
|
+
* const result = await validateLevel2(manifest.capabilities, {
|
|
45
|
+
* agentDid: 'did:web:securebank.example',
|
|
46
|
+
* trustedIssuers: ['did:web:knowthat.ai'],
|
|
47
|
+
* signatureVerifier: myEd25519Verifier,
|
|
48
|
+
* });
|
|
49
|
+
*
|
|
50
|
+
* console.log(result.valid); // ['payments.transfer']
|
|
51
|
+
* console.log(result.invalid); // [{ capability: 'accounts.read', reasons: [...] }]
|
|
52
|
+
* console.log(result.warnings); // []
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
async function validateLevel2(capabilities, options) {
|
|
56
|
+
const result = {
|
|
57
|
+
valid: [],
|
|
58
|
+
invalid: [],
|
|
59
|
+
warnings: [],
|
|
60
|
+
};
|
|
61
|
+
if (!Array.isArray(capabilities)) {
|
|
62
|
+
result.warnings.push('capabilities is not an array — no capabilities validated');
|
|
63
|
+
return result;
|
|
64
|
+
}
|
|
65
|
+
// Level 1 string[] passthrough: every entry is a bare capability name.
|
|
66
|
+
if (capabilities.length > 0 && capabilities.every((c) => typeof c === 'string')) {
|
|
67
|
+
result.valid.push(...capabilities);
|
|
68
|
+
result.warnings.push('Level 1 self-declared — no attestation verified');
|
|
69
|
+
return result;
|
|
70
|
+
}
|
|
71
|
+
const trustedIssuers = new Set(options.trustedIssuers ?? exports.DEFAULT_TRUSTED_ISSUERS);
|
|
72
|
+
const now = (options.now?.() ?? new Date()).getTime();
|
|
73
|
+
if (!options.signatureVerifier) {
|
|
74
|
+
result.warnings.push('No signatureVerifier provided — VC signatures accepted without cryptographic verification');
|
|
75
|
+
}
|
|
76
|
+
for (const entry of capabilities) {
|
|
77
|
+
// Mixed-array case: a bare string in a Level 2 array is unattested per
|
|
78
|
+
// spec ("MUST treat any capability supplied as a string … as unattested
|
|
79
|
+
// and therefore ignore it"). We surface it as invalid with a clear reason
|
|
80
|
+
// so callers can diagnose, rather than dropping silently.
|
|
81
|
+
if (typeof entry === 'string') {
|
|
82
|
+
result.invalid.push({
|
|
83
|
+
capability: entry,
|
|
84
|
+
reasons: ['capability declared as bare string with no attestations'],
|
|
85
|
+
});
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
if (!isLevel2Capability(entry)) {
|
|
89
|
+
// Entry has a name but malformed/missing attestations — report in invalid.
|
|
90
|
+
if (typeof entry === 'object' &&
|
|
91
|
+
entry !== null &&
|
|
92
|
+
typeof entry.name === 'string') {
|
|
93
|
+
result.invalid.push({
|
|
94
|
+
capability: entry.name,
|
|
95
|
+
reasons: ['capability has invalid or missing attestations array'],
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
result.warnings.push(`Skipping capability entry of unrecognized shape: ${safeStringify(entry)}`);
|
|
100
|
+
}
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
const capabilityResult = await validateCapability(entry, {
|
|
104
|
+
agentDid: options.agentDid,
|
|
105
|
+
trustedIssuers,
|
|
106
|
+
now,
|
|
107
|
+
signatureVerifier: options.signatureVerifier,
|
|
108
|
+
});
|
|
109
|
+
if (capabilityResult.valid) {
|
|
110
|
+
result.valid.push(entry.name);
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
result.invalid.push({
|
|
114
|
+
capability: entry.name,
|
|
115
|
+
reasons: capabilityResult.reasons,
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return result;
|
|
120
|
+
}
|
|
121
|
+
async function validateCapability(capability, ctx) {
|
|
122
|
+
const reasons = [];
|
|
123
|
+
if (!Array.isArray(capability.attestations) || capability.attestations.length === 0) {
|
|
124
|
+
return {
|
|
125
|
+
valid: false,
|
|
126
|
+
reasons: ['no attestations attached'],
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
for (let i = 0; i < capability.attestations.length; i++) {
|
|
130
|
+
const attestation = capability.attestations[i];
|
|
131
|
+
const attestationLabel = `attestation[${i}]`;
|
|
132
|
+
const parsed = decodeAttestationVC(attestation);
|
|
133
|
+
if (!parsed.ok) {
|
|
134
|
+
reasons.push(`${attestationLabel}: ${parsed.reason}`);
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
const { vc, rawJwt } = parsed;
|
|
138
|
+
const issuerDid = extractIssuerDid(vc);
|
|
139
|
+
if (!issuerDid) {
|
|
140
|
+
reasons.push(`${attestationLabel}: VC missing issuer`);
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
if (!ctx.trustedIssuers.has(issuerDid)) {
|
|
144
|
+
reasons.push(`${attestationLabel}: issuer ${issuerDid} not in trusted registry`);
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
if (vc.credentialSubject?.id !== ctx.agentDid) {
|
|
148
|
+
reasons.push(`${attestationLabel}: credentialSubject.id ${vc.credentialSubject?.id ?? '(missing)'} does not match agent DID ${ctx.agentDid}`);
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
if (vc.credentialSubject?.capability !== capability.name) {
|
|
152
|
+
reasons.push(`${attestationLabel}: credentialSubject.capability ${vc.credentialSubject?.capability ?? '(missing)'} does not match declared capability ${capability.name}`);
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
const validUntilMs = vc.validUntil ? Date.parse(vc.validUntil) : NaN;
|
|
156
|
+
if (!vc.validUntil || Number.isNaN(validUntilMs)) {
|
|
157
|
+
reasons.push(`${attestationLabel}: VC missing or unparseable validUntil`);
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
if (validUntilMs <= ctx.now) {
|
|
161
|
+
reasons.push(`${attestationLabel}: VC expired (validUntil ${vc.validUntil})`);
|
|
162
|
+
continue;
|
|
163
|
+
}
|
|
164
|
+
if (vc.validFrom) {
|
|
165
|
+
const validFromMs = Date.parse(vc.validFrom);
|
|
166
|
+
if (Number.isNaN(validFromMs)) {
|
|
167
|
+
reasons.push(`${attestationLabel}: unparseable validFrom`);
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
if (validFromMs > ctx.now) {
|
|
171
|
+
reasons.push(`${attestationLabel}: VC not yet valid (validFrom ${vc.validFrom})`);
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
if (ctx.signatureVerifier) {
|
|
176
|
+
let sig;
|
|
177
|
+
try {
|
|
178
|
+
sig = await ctx.signatureVerifier(vc, rawJwt);
|
|
179
|
+
}
|
|
180
|
+
catch (err) {
|
|
181
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
182
|
+
reasons.push(`${attestationLabel}: signature verifier threw: ${message}`);
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
if (!sig.valid) {
|
|
186
|
+
reasons.push(`${attestationLabel}: signature invalid${sig.reason ? ` (${sig.reason})` : ''}`);
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
// TODO(v1.x): when StatusList2021 hook lands, invoke
|
|
191
|
+
// ctx.statusListResolver here and reject revoked attestations. v1 skips
|
|
192
|
+
// revocation per the spec design doc.
|
|
193
|
+
return { valid: true, reasons: [] };
|
|
194
|
+
}
|
|
195
|
+
return { valid: false, reasons };
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Decode an attestation `vc` field (string JWT or object) into a credential.
|
|
199
|
+
*/
|
|
200
|
+
function decodeAttestationVC(attestation) {
|
|
201
|
+
if (attestation === null || typeof attestation !== 'object') {
|
|
202
|
+
return { ok: false, reason: 'attestation entry is not an object' };
|
|
203
|
+
}
|
|
204
|
+
const vc = attestation.vc;
|
|
205
|
+
if (typeof vc === 'string') {
|
|
206
|
+
const parsed = (0, utils_js_1.parseVCJWT)(vc);
|
|
207
|
+
if (!parsed) {
|
|
208
|
+
return { ok: false, reason: 'VC JWT could not be parsed' };
|
|
209
|
+
}
|
|
210
|
+
const inner = parsed.payload.vc;
|
|
211
|
+
if (!inner || typeof inner !== 'object') {
|
|
212
|
+
return { ok: false, reason: 'VC JWT payload missing vc claim' };
|
|
213
|
+
}
|
|
214
|
+
// Per W3C VC-JWT spec §6.3: promote JWT-level iss→vc.issuer and
|
|
215
|
+
// sub→vc.credentialSubject.id when absent from the embedded vc object so
|
|
216
|
+
// that externally-issued spec-compliant JWTs are not falsely rejected.
|
|
217
|
+
const merged = { ...inner };
|
|
218
|
+
if (!merged.issuer && typeof parsed.payload.iss === 'string') {
|
|
219
|
+
merged.issuer = parsed.payload.iss;
|
|
220
|
+
}
|
|
221
|
+
if (typeof parsed.payload.sub === 'string' &&
|
|
222
|
+
merged.credentialSubject &&
|
|
223
|
+
typeof merged.credentialSubject === 'object' &&
|
|
224
|
+
!merged.credentialSubject.id) {
|
|
225
|
+
merged.credentialSubject = {
|
|
226
|
+
...merged.credentialSubject,
|
|
227
|
+
id: parsed.payload.sub,
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
// Per W3C VC-JWT spec §6.3: also promote exp→validUntil and nbf→validFrom
|
|
231
|
+
// when absent from the embedded vc object, so externally-issued JWTs that
|
|
232
|
+
// carry validity only in the standard JWT claims are not falsely rejected.
|
|
233
|
+
// JWT exp/nbf are Unix seconds (NumericDate). Guard the conversion: an
|
|
234
|
+
// out-of-range claim yields an Invalid Date, which we leave unset (→ the VC
|
|
235
|
+
// fails closed at validation) rather than letting toISOString() throw a
|
|
236
|
+
// RangeError out of this otherwise-total decoder.
|
|
237
|
+
if (!merged.validUntil && typeof parsed.payload.exp === 'number') {
|
|
238
|
+
const d = new Date(parsed.payload.exp * 1000);
|
|
239
|
+
if (!Number.isNaN(d.getTime()))
|
|
240
|
+
merged.validUntil = d.toISOString();
|
|
241
|
+
}
|
|
242
|
+
if (!merged.validFrom && typeof parsed.payload.nbf === 'number') {
|
|
243
|
+
const d = new Date(parsed.payload.nbf * 1000);
|
|
244
|
+
if (!Number.isNaN(d.getTime()))
|
|
245
|
+
merged.validFrom = d.toISOString();
|
|
246
|
+
}
|
|
247
|
+
return {
|
|
248
|
+
ok: true,
|
|
249
|
+
vc: merged,
|
|
250
|
+
rawJwt: vc,
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
if (vc && typeof vc === 'object') {
|
|
254
|
+
return {
|
|
255
|
+
ok: true,
|
|
256
|
+
vc: vc,
|
|
257
|
+
rawJwt: undefined,
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
return { ok: false, reason: 'attestation.vc missing or invalid type' };
|
|
261
|
+
}
|
|
262
|
+
function extractIssuerDid(vc) {
|
|
263
|
+
if (typeof vc.issuer === 'string')
|
|
264
|
+
return vc.issuer;
|
|
265
|
+
if (vc.issuer && typeof vc.issuer === 'object' && typeof vc.issuer.id === 'string') {
|
|
266
|
+
return vc.issuer.id;
|
|
267
|
+
}
|
|
268
|
+
return undefined;
|
|
269
|
+
}
|
|
270
|
+
function isLevel2Capability(value) {
|
|
271
|
+
return (typeof value === 'object' &&
|
|
272
|
+
value !== null &&
|
|
273
|
+
typeof value.name === 'string' &&
|
|
274
|
+
Array.isArray(value.attestations));
|
|
275
|
+
}
|
|
276
|
+
function safeStringify(value) {
|
|
277
|
+
try {
|
|
278
|
+
return JSON.stringify(value);
|
|
279
|
+
}
|
|
280
|
+
catch {
|
|
281
|
+
return String(value);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
//# sourceMappingURL=validate-level2.js.map
|
|
@@ -6,9 +6,10 @@
|
|
|
6
6
|
* without trusting the MCP server.
|
|
7
7
|
*
|
|
8
8
|
* Wire format: signed compact EdDSA JWT (60s TTL, per-call jti)
|
|
9
|
-
* Header injection:
|
|
9
|
+
* Header injection: KYA-OS-Delegation-Chain, KYA-OS-Delegation-Proof, KYA-OS-Granted-Scopes,
|
|
10
|
+
* and KYA-OS-Delegation-Credential (the JWS-compact DelegationCredential VC) when present
|
|
10
11
|
*
|
|
11
|
-
* Related Spec: MCP-I §
|
|
12
|
+
* Related Spec: DIF MCP-I §8 — Outbound Delegation Propagation
|
|
12
13
|
*/
|
|
13
14
|
import type { DelegationRecord } from "@kya-os/contracts/delegation";
|
|
14
15
|
/**
|
|
@@ -7,9 +7,10 @@
|
|
|
7
7
|
* without trusting the MCP server.
|
|
8
8
|
*
|
|
9
9
|
* Wire format: signed compact EdDSA JWT (60s TTL, per-call jti)
|
|
10
|
-
* Header injection:
|
|
10
|
+
* Header injection: KYA-OS-Delegation-Chain, KYA-OS-Delegation-Proof, KYA-OS-Granted-Scopes,
|
|
11
|
+
* and KYA-OS-Delegation-Credential (the JWS-compact DelegationCredential VC) when present
|
|
11
12
|
*
|
|
12
|
-
* Related Spec: MCP-I §
|
|
13
|
+
* Related Spec: DIF MCP-I §8 — Outbound Delegation Propagation
|
|
13
14
|
*/
|
|
14
15
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
16
|
exports.buildDelegationProofJWT = buildDelegationProofJWT;
|
|
@@ -40,8 +40,10 @@ export interface VCJWTPayload {
|
|
|
40
40
|
sub?: string;
|
|
41
41
|
/** Audience (e.g., project ID the credential is scoped to). Per RFC 7519, can be string or array. */
|
|
42
42
|
aud?: string | string[];
|
|
43
|
-
/** Expiration time (from vc.expirationDate) */
|
|
43
|
+
/** Expiration time (from vc.expirationDate / validUntil) */
|
|
44
44
|
exp?: number;
|
|
45
|
+
/** Not-before time (RFC 7519 nbf; maps to vc.validFrom) */
|
|
46
|
+
nbf?: number;
|
|
45
47
|
/** Issued at time (from vc.issuanceDate) */
|
|
46
48
|
iat?: number;
|
|
47
49
|
/** JWT ID (from vc.id) */
|
package/dist/index.d.ts
CHANGED
|
@@ -1,53 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @kya-os/mcp-i-core
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Compatibility shim. The product-runtime layer has relocated to
|
|
5
|
+
* @kya-os/mcp-i-runtime; this package re-exports it so existing
|
|
6
|
+
* `@kya-os/mcp-i-core` importers keep resolving during the C4 drain window.
|
|
7
|
+
*
|
|
8
|
+
* Delegation (W3C VC) symbols remain sourced here — `src/delegation/**` is
|
|
9
|
+
* pinned by E3.5 (#2904) and is intentionally NOT relocated.
|
|
6
10
|
*/
|
|
7
|
-
export
|
|
8
|
-
export { MemoryStorageProvider, MemoryNonceCacheProvider, MemoryIdentityProvider, } from "./providers/memory";
|
|
9
|
-
export { MCPIRuntimeBase } from "./runtime/base";
|
|
10
|
-
export type { RuntimeWithAccessControl } from "./runtime/base";
|
|
11
|
-
export { CONSENT_UI_RESOURCE_URI } from "./runtime/ext-apps-constants";
|
|
12
|
-
export type { IAuditLogger } from "./runtime/audit-logger";
|
|
13
|
-
export * from "./utils";
|
|
14
|
-
export { ToolProtectionService } from "./services/tool-protection.service";
|
|
15
|
-
export { PolicyService } from "./services/policy.service";
|
|
16
|
-
export type { PolicyEvaluationContext, PolicyEvaluationResult, PolicyServiceConfig, } from "./services/policy.service";
|
|
17
|
-
export { CryptoService } from "./services/crypto.service";
|
|
18
|
-
export type { Ed25519JWK, ParsedJWS } from "./services/crypto.service";
|
|
19
|
-
export { ProofVerifier } from "./services/proof-verifier";
|
|
20
|
-
export type { ProofVerificationResult, ProofVerifierConfig, } from "./services/proof-verifier";
|
|
21
|
-
export { AccessControlApiService, authorizationMatches, } from "./services/access-control.service";
|
|
22
|
-
export type { AccessControlApiServiceConfig, AccessControlApiServiceMetrics, } from "./services/access-control.service";
|
|
23
|
-
export { SessionRegistrationService, createSessionRegistrationService, } from "./services/session-registration.service";
|
|
24
|
-
export type { SessionRegistrationServiceConfig, SessionRegistrationResult, } from "./services/session-registration.service";
|
|
25
|
-
export { OAuthConfigService } from "./services/oauth-config.service";
|
|
26
|
-
export type { OAuthConfigServiceConfig } from "./services/oauth-config.service";
|
|
27
|
-
export { OAuthService, defaultSecretResolver } from "./services/oauth-service";
|
|
28
|
-
export type { OAuthServiceConfig, SecretResolver } from "./services/oauth-service";
|
|
29
|
-
export { ToolContextBuilder } from "./services/tool-context-builder";
|
|
30
|
-
export type { ToolContextBuilderConfig } from "./services/tool-context-builder";
|
|
31
|
-
export { OAuthProviderRegistry } from "./services/oauth-provider-registry";
|
|
32
|
-
export { ProviderResolver, ConsentOnlyModeError, CredentialAuthModeError, } from "./services/provider-resolver";
|
|
33
|
-
export { ProviderValidator, ProviderValidationError, } from "./services/provider-validator";
|
|
34
|
-
export { OAuthTokenRetrievalService } from "./services/oauth-token-retrieval.service";
|
|
35
|
-
export type { OAuthTokenRetrievalServiceConfig } from "./services/oauth-token-retrieval.service";
|
|
36
|
-
export { BatchDelegationService } from "./services/batch-delegation.service";
|
|
37
|
-
export type { ToolGroup } from "./services/batch-delegation.service";
|
|
38
|
-
export { InMemoryOAuthConfigCache, NoOpOAuthConfigCache, } from "./cache/oauth-config-cache";
|
|
39
|
-
export type { OAuthConfigCache } from "./cache/oauth-config-cache";
|
|
40
|
-
export { createStorageProviders, StorageKeyHelpers, migrateLegacyKeys, } from "./services/storage.service";
|
|
41
|
-
export type { StorageServiceConfig, StorageProviders, } from "./services/storage.service";
|
|
42
|
-
export { ProofVerificationError, PROOF_VERIFICATION_ERROR_CODES, createProofVerificationError, } from "./services/errors";
|
|
43
|
-
export type { ProofVerificationErrorCode } from "./services/errors";
|
|
44
|
-
export { ToolProtectionCache, InMemoryToolProtectionCache, NoOpToolProtectionCache, } from "./cache/tool-protection-cache";
|
|
45
|
-
export type { ToolProtection, ToolProtectionConfig, ToolProtectionServiceConfig, } from "./types/tool-protection";
|
|
46
|
-
export { DelegationRequiredError } from "./types/tool-protection";
|
|
47
|
-
export { OAuthRequiredError } from "./types/oauth-required-error";
|
|
48
|
-
export type { OAuthRequiredErrorOptions } from "./types/oauth-required-error";
|
|
49
|
-
export { DelegationErrorFormatter, createDelegationErrorFormatter, } from "./services/delegation-error-formatter";
|
|
50
|
-
export type { DelegationErrorFormatOptions, DelegationErrorResult, ClientMessageTemplate, ClientMessagesConfig, } from "./services/delegation-error-formatter";
|
|
11
|
+
export * from "@kya-os/mcp-i-runtime";
|
|
51
12
|
export { DelegationCredentialIssuer, createDelegationIssuer, type IssueDelegationOptions, type VCSigningFunction, type IdentityProvider as DelegationIdentityProvider, } from "./delegation/vc-issuer";
|
|
52
13
|
export { DelegationCredentialVerifier, createDelegationVerifier, type DelegationVCVerificationResult, type VerifyDelegationVCOptions, type DIDResolver, type DIDDocument, type VerificationMethod, type StatusListResolver, type SignatureVerificationFunction, } from "./delegation/vc-verifier";
|
|
53
14
|
export { StatusList2021Manager, createStatusListManager, type StatusListStorageProvider, type StatusListIdentityProvider, } from "./delegation/statuslist-manager";
|
|
@@ -58,22 +19,6 @@ export { MemoryStatusListStorage } from "./delegation/storage/memory-statuslist-
|
|
|
58
19
|
export { MemoryDelegationGraphStorage } from "./delegation/storage/memory-graph-storage";
|
|
59
20
|
export { buildDelegationProofJWT, buildChainString, type DelegationProofOptions, type Ed25519PrivateJWK, } from "./delegation/outbound-proof";
|
|
60
21
|
export { createDidKeyResolver, isEd25519DidKey, extractPublicKeyFromDidKey, publicKeyToJwk, resolveDidKeySync, } from "./delegation/did-key-resolver";
|
|
61
|
-
export { base58Encode, base58Decode, isValidBase58 } from "./utils/base58";
|
|
62
|
-
export { SchemaVerifier, createSchemaVerifier, type SchemaMetadata, type FieldComplianceResult, type SchemaComplianceReport, type FullComplianceReport, } from "./compliance/schema-verifier";
|
|
63
|
-
export { SCHEMA_REGISTRY, getAllSchemas, getSchemasByCategory, getSchemaById, getCriticalSchemas, getSchemaStats, } from "./compliance/schema-registry";
|
|
64
22
|
export { canonicalizeJSON, createUnsignedVCJWT, completeVCJWT, parseVCJWT, type VCJWTHeader, type VCJWTPayload, type EncodeVCAsJWTOptions, } from "./delegation/utils";
|
|
65
|
-
export {
|
|
66
|
-
import type { HandshakeRequest, SessionContext, NonceCache, NonceCacheEntry, NonceCacheConfig, ProofMeta, DetachedProof, CanonicalHashes, AuditRecord } from "@kya-os/contracts";
|
|
67
|
-
export type { HandshakeRequest, SessionContext, NonceCache, NonceCacheEntry, NonceCacheConfig, ProofMeta, DetachedProof, CanonicalHashes, AuditRecord, };
|
|
68
|
-
export * from "./config";
|
|
69
|
-
export { fetchRemoteConfig, type RemoteConfigCache, type RemoteConfigOptions, getToolProtection, extractToolProtections, hasMergedToolProtections, getPolicy, extractPolicy, hasMergedPolicy, isPolicyEnabled, } from "./config/remote-config";
|
|
70
|
-
export { UserDidManager } from "./identity/user-did-manager";
|
|
71
|
-
export type { UserDidStorage, UserDidManagerConfig, UserKeyPair, OAuthIdentity, } from "./identity/user-did-manager";
|
|
72
|
-
export { IdpTokenResolver } from "./identity/idp-token-resolver";
|
|
73
|
-
export type { IdpTokenResolverConfig } from "./identity/idp-token-resolver";
|
|
74
|
-
export type { IIdpTokenStorage, TokenUsageMetadata, IdpTokensWithMetadata, } from "./identity/idp-token-storage.interface";
|
|
75
|
-
export { logger, createDefaultConsoleLogger, type Logger, type Level, } from "./logging";
|
|
76
|
-
export { ProofGenerator, createProofResponse, extractCanonicalData, type ProofAgentIdentity, type ToolRequest, type ToolResponse, type ProofOptions, } from "./proof";
|
|
77
|
-
export { SessionManager, createHandshakeRequest, validateHandshakeFormat, type SessionConfig, type HandshakeResult, } from "./session";
|
|
78
|
-
export { verifyOrHints, hasSensitiveScopes, MemoryResumeTokenStore, type AuthHandshakeConfig, type VerifyOrHintsResult, type AgentReputation, type ResumeTokenStore, type DelegationVerifier, type VerifyDelegationResult, } from "./auth";
|
|
23
|
+
export { validateLevel2, DEFAULT_TRUSTED_ISSUERS, type CapabilityName, type CapabilityAttestation, type CapabilityAttestationCredential, type Level2Capability, type ManifestCapabilities, type CapabilityVCSignatureVerifier, type CapabilityStatusListResolver, type ValidateLevel2Options, type ValidateLevel2Result, type InvalidCapability, } from "./conformance/index.js";
|
|
79
24
|
//# sourceMappingURL=index.d.ts.map
|