@kya-os/mcp-i 1.5.0 → 1.5.2

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.
@@ -42,6 +42,8 @@ export interface AgentReputation {
42
42
  export interface AuthHandshakeConfig {
43
43
  /** Delegation verifier instance */
44
44
  delegationVerifier: DelegationVerifier;
45
+ /** Resume token store (REQUIRED to persist tokens across calls) */
46
+ resumeTokenStore: ResumeTokenStore;
45
47
  /** KTA API configuration (optional, for reputation checks) */
46
48
  kta?: {
47
49
  apiUrl: string;
@@ -120,9 +120,12 @@ async function verifyOrHints(agentDid, scopes, config, resumeToken) {
120
120
  }
121
121
  catch (error) {
122
122
  console.error('[AuthHandshake] Delegation verification failed:', error);
123
+ const errorMessage = `Delegation verification error: ${error instanceof Error ? error.message : 'Unknown error'}`;
124
+ const authError = await buildNeedsAuthorizationError(agentDid, scopes, config, errorMessage);
123
125
  return {
124
126
  authorized: false,
125
- reason: `Delegation verification error: ${error instanceof Error ? error.message : 'Unknown error'}`,
127
+ authError,
128
+ reason: errorMessage,
126
129
  };
127
130
  }
128
131
  // Step 3: If delegation exists and valid, authorize immediately
@@ -202,9 +205,8 @@ async function fetchAgentReputation(agentDid, ktaConfig) {
202
205
  * @returns NeedsAuthorizationError
203
206
  */
204
207
  async function buildNeedsAuthorizationError(agentDid, scopes, config, message) {
205
- // Generate resume token (simple implementation - use proper store in production)
206
- const resumeTokenStore = new MemoryResumeTokenStore(config.bouncer.resumeTokenTtl || 600_000);
207
- const resumeToken = await resumeTokenStore.create(agentDid, scopes, {
208
+ // Use the persistent resume token store from config
209
+ const resumeToken = await config.resumeTokenStore.create(agentDid, scopes, {
208
210
  requestedAt: Date.now(),
209
211
  });
210
212
  const expiresAt = Date.now() + (config.bouncer.resumeTokenTtl || 600_000);
@@ -100,10 +100,9 @@ class CloudflareKVDelegationVerifier {
100
100
  if (this.debug) {
101
101
  console.log(`[KV] Cache MISS for ${agentDid}, querying KV...`);
102
102
  }
103
- // Try to find delegation by agent DID lookup key
104
- const lookupKey = `agent:${agentDid}:scopes:${scopesKey}`;
105
- const delegationId = await this.kv.get(lookupKey, 'text');
106
- if (!delegationId) {
103
+ // List all delegations for this agent (to support subset scope matching)
104
+ const listResult = await this.kv.list({ prefix: `agent:${agentDid}:scopes:` });
105
+ if (!listResult.keys || listResult.keys.length === 0) {
107
106
  const result = {
108
107
  valid: false,
109
108
  reason: 'No delegation found for agent',
@@ -116,17 +115,37 @@ class CloudflareKVDelegationVerifier {
116
115
  }
117
116
  return result;
118
117
  }
119
- // Fetch full delegation record
120
- const delegation = await this.get(delegationId);
121
- if (!delegation) {
118
+ // Try each delegation to find one that matches the requested scopes
119
+ let matchingDelegation = null;
120
+ for (const key of listResult.keys) {
121
+ const delegationId = await this.kv.get(key.name, 'text');
122
+ if (!delegationId)
123
+ continue;
124
+ const delegation = await this.get(delegationId);
125
+ if (!delegation)
126
+ continue;
127
+ // Check if this delegation has the required scopes
128
+ const delegationScopes = (0, delegation_verifier_1.extractScopes)(delegation);
129
+ const scopesMatch = (0, delegation_verifier_1.checkScopes)(delegationScopes, scopes);
130
+ if (scopesMatch) {
131
+ // Found a matching delegation!
132
+ matchingDelegation = delegation;
133
+ break;
134
+ }
135
+ }
136
+ if (!matchingDelegation) {
122
137
  const result = {
123
138
  valid: false,
124
- reason: 'Delegation not found',
139
+ reason: 'No delegation found with required scopes',
125
140
  cached: false,
126
141
  };
127
142
  this.cache.set(cacheKey, result, this.cacheTtl / 2);
143
+ if (this.debug) {
144
+ console.log(`[KV] No matching delegation found (${Date.now() - startTime}ms)`);
145
+ }
128
146
  return result;
129
147
  }
148
+ const delegation = matchingDelegation;
130
149
  // Validate delegation
131
150
  const validation = (0, delegation_verifier_1.validateDelegation)(delegation);
132
151
  if (!validation.valid) {
@@ -82,6 +82,7 @@ export declare class MCPIRuntime {
82
82
  private debugManager?;
83
83
  private demoManager?;
84
84
  private delegationVerifier?;
85
+ private resumeTokenStore;
85
86
  private config;
86
87
  private cachedIdentity?;
87
88
  constructor(config?: MCPIRuntimeConfig);
@@ -28,6 +28,7 @@ class MCPIRuntime {
28
28
  debugManager;
29
29
  demoManager;
30
30
  delegationVerifier; // NEW - Phase 1
31
+ resumeTokenStore; // NEW - Phase 1
31
32
  config;
32
33
  cachedIdentity;
33
34
  constructor(config = {}) {
@@ -41,6 +42,9 @@ class MCPIRuntime {
41
42
  this.sessionManager = new session_1.SessionManager(config.session);
42
43
  // Initialize audit logger
43
44
  this.auditLogger = new audit_1.AuditLogger(config.audit);
45
+ // Initialize resume token store (NEW - Phase 1)
46
+ // Use in-memory store by default (sufficient for most use cases)
47
+ this.resumeTokenStore = new auth_handshake_1.MemoryResumeTokenStore(config.delegation?.authorization?.resumeTokenTtl || 600_000);
44
48
  // Initialize delegation verifier (NEW - Phase 1)
45
49
  if (config.delegation?.enabled && config.delegation?.verifier) {
46
50
  this.delegationVerifier = (0, delegation_verifier_1.createDelegationVerifier)(config.delegation.verifier);
@@ -113,6 +117,7 @@ class MCPIRuntime {
113
117
  // Build auth handshake config
114
118
  const authConfig = {
115
119
  delegationVerifier: this.delegationVerifier,
120
+ resumeTokenStore: this.resumeTokenStore,
116
121
  kta: this.config.delegation.authorization?.kta,
117
122
  bouncer: {
118
123
  authorizationUrl: this.config.delegation.authorization?.authorizationUrl ||
@@ -127,6 +132,9 @@ class MCPIRuntime {
127
132
  const verifyResult = await (0, auth_handshake_1.verifyOrHints)(options.agentDid, requiredScopes, authConfig);
128
133
  // If not authorized, return needs_authorization error
129
134
  if (!verifyResult.authorized) {
135
+ if (!verifyResult.authError) {
136
+ throw new Error('Authorization failed but no authError was provided');
137
+ }
130
138
  return verifyResult.authError;
131
139
  }
132
140
  // If authorized, log the delegation ID for audit trail
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kya-os/mcp-i",
3
- "version": "1.5.0",
3
+ "version": "1.5.2",
4
4
  "description": "The TypeScript MCP framework with identity features built-in",
5
5
  "type": "commonjs",
6
6
  "main": "dist/index.js",