@kya-os/mcp-i-cloudflare 1.7.61 → 1.7.62
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/dist/agent.d.ts +38 -3
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +165 -119
- package/dist/agent.js.map +1 -1
- package/dist/services/consent.service.d.ts +15 -2
- package/dist/services/consent.service.d.ts.map +1 -1
- package/dist/services/consent.service.js +99 -96
- package/dist/services/consent.service.js.map +1 -1
- package/dist/types.d.ts +3 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/agent.d.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* Users only need to extend this class and register their tools.
|
|
7
7
|
*/
|
|
8
8
|
import { McpAgent } from "agents/mcp";
|
|
9
|
-
import type { DurableObjectState } from "@cloudflare/workers-types";
|
|
9
|
+
import type { DurableObjectState, DurableObjectNamespace, KVNamespace } from "@cloudflare/workers-types";
|
|
10
10
|
import type { CloudflareEnv } from "./types";
|
|
11
11
|
import type { CloudflareRuntimeConfig } from "./config";
|
|
12
12
|
import { CloudflareRuntime } from "./runtime";
|
|
@@ -16,8 +16,8 @@ import { type IProviderRegistry } from "@kya-os/provider-registry";
|
|
|
16
16
|
/**
|
|
17
17
|
* Extended CloudflareEnv with prefixed KV bindings for multi-agent deployments
|
|
18
18
|
*/
|
|
19
|
-
export interface PrefixedCloudflareEnv extends Omit<CloudflareEnv, "NONCE_CACHE" | "PROOF_ARCHIVE" | "IDENTITY_STORAGE" | "DELEGATION_STORAGE" | "TOOL_PROTECTION_KV"> {
|
|
20
|
-
[key: string]: KVNamespace | string | DurableObjectState | undefined;
|
|
19
|
+
export interface PrefixedCloudflareEnv extends Omit<CloudflareEnv, "NONCE_CACHE" | "PROOF_ARCHIVE" | "IDENTITY_STORAGE" | "DELEGATION_STORAGE" | "TOOL_PROTECTION_KV" | "MCP_OBJECT"> {
|
|
20
|
+
[key: string]: KVNamespace | string | DurableObjectState | DurableObjectNamespace | undefined;
|
|
21
21
|
DO_ROUTING_STRATEGY?: string;
|
|
22
22
|
DO_SHARD_COUNT?: string;
|
|
23
23
|
NONCE_CACHE?: KVNamespace;
|
|
@@ -287,6 +287,41 @@ export declare abstract class MCPICloudflareAgent extends McpAgent {
|
|
|
287
287
|
consentConfigCleared?: boolean;
|
|
288
288
|
error?: string;
|
|
289
289
|
}>;
|
|
290
|
+
/**
|
|
291
|
+
* Store delegation data to DO internal storage
|
|
292
|
+
*
|
|
293
|
+
* Uses multiple storage keys for efficient lookup:
|
|
294
|
+
* - `delegation:session:${sessionId}` - Primary key for session-based lookup
|
|
295
|
+
* - `delegation:user:${userDid}:agent:${agentDid}` - Secondary key for user-based lookup
|
|
296
|
+
*
|
|
297
|
+
* @param data - Delegation data to store
|
|
298
|
+
*/
|
|
299
|
+
protected storeDelegationToStorage(data: {
|
|
300
|
+
sessionId: string;
|
|
301
|
+
delegationToken: string;
|
|
302
|
+
delegationId: string;
|
|
303
|
+
userDid?: string;
|
|
304
|
+
agentDid: string;
|
|
305
|
+
}): Promise<void>;
|
|
306
|
+
/**
|
|
307
|
+
* Retrieve delegation from DO internal storage
|
|
308
|
+
*
|
|
309
|
+
* Looks up in priority order:
|
|
310
|
+
* 1. Session key (primary)
|
|
311
|
+
* 2. User+agent key (if userDid available)
|
|
312
|
+
*
|
|
313
|
+
* @param sessionId - Session ID
|
|
314
|
+
* @param userDid - Optional user DID for secondary lookup
|
|
315
|
+
* @param agentDid - Agent DID for secondary lookup
|
|
316
|
+
* @returns Delegation data or undefined if not found
|
|
317
|
+
*/
|
|
318
|
+
protected getDelegationFromStorage(sessionId: string, userDid?: string, agentDid?: string): Promise<{
|
|
319
|
+
delegationToken: string;
|
|
320
|
+
delegationId: string;
|
|
321
|
+
userDid?: string;
|
|
322
|
+
agentDid: string;
|
|
323
|
+
storedAt: number;
|
|
324
|
+
} | undefined>;
|
|
290
325
|
/**
|
|
291
326
|
* Handle MCP-I handshake JSON-RPC request
|
|
292
327
|
*
|
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,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"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"}
|
package/dist/agent.js
CHANGED
|
@@ -738,137 +738,69 @@ export class MCPICloudflareAgent extends McpAgent {
|
|
|
738
738
|
serverUrl: serverUrl?.slice(0, 50) || "undefined",
|
|
739
739
|
});
|
|
740
740
|
}
|
|
741
|
-
// ✅ Look up delegation token from
|
|
741
|
+
// ✅ Look up delegation token from DO storage (strongly consistent)
|
|
742
|
+
// Using DO internal storage eliminates KV eventual consistency issues.
|
|
743
|
+
// No retry mechanism needed - storage and retrieval happen on the same DO instance.
|
|
742
744
|
let delegationToken;
|
|
743
|
-
let delegationId;
|
|
744
|
-
let userDid;
|
|
745
|
-
let clientDid;
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
// PRIORITY 0: Get userDid from BOTH identity key and session key
|
|
756
|
-
// Due to KV key separation (see initializeSessionStorage), userDid may be in either:
|
|
757
|
-
// - session:identity:${sessionId} → NEW location for identity data
|
|
758
|
-
// - session:${sessionId} → OLD location (backward compat) + delegation data
|
|
745
|
+
let delegationId;
|
|
746
|
+
let userDid;
|
|
747
|
+
let clientDid;
|
|
748
|
+
try {
|
|
749
|
+
const agentDid = (await this.mcpiRuntime.getIdentity()).did;
|
|
750
|
+
logger.debug("[MCPICloudflareAgent] 🔍 Starting delegation lookup (DO storage):", {
|
|
751
|
+
sessionId: sessionId.slice(0, 20) + "...",
|
|
752
|
+
agentDid: agentDid.slice(0, 20) + "...",
|
|
753
|
+
});
|
|
754
|
+
// Get userDid and clientDid from KV session data (still needed for identity context)
|
|
755
|
+
const delegationStorage = mappedEnv.DELEGATION_STORAGE;
|
|
756
|
+
if (delegationStorage) {
|
|
759
757
|
const identityKey = STORAGE_KEYS.sessionIdentity(sessionId);
|
|
760
758
|
const sessionKey = STORAGE_KEYS.session(sessionId);
|
|
761
|
-
|
|
762
|
-
const
|
|
763
|
-
// Then check session key (backward compat + delegation data)
|
|
764
|
-
const sessionData = (await delegationStorage.get(sessionKey, "json"));
|
|
765
|
-
// Prefer identity key, fallback to session key
|
|
759
|
+
const identityData = await delegationStorage.get(identityKey, "json");
|
|
760
|
+
const sessionData = await delegationStorage.get(sessionKey, "json");
|
|
766
761
|
userDid = identityData?.userDid || sessionData?.userDid;
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
762
|
+
clientDid = sessionData?.clientDid;
|
|
763
|
+
}
|
|
764
|
+
// Look up delegation from DO storage (strongly consistent - no retries needed)
|
|
765
|
+
const doData = await this.getDelegationFromStorage(sessionId, userDid, agentDid);
|
|
766
|
+
if (doData) {
|
|
767
|
+
delegationToken = doData.delegationToken;
|
|
768
|
+
delegationId = doData.delegationId;
|
|
769
|
+
// Prefer userDid from DO storage if available
|
|
770
|
+
if (doData.userDid) {
|
|
771
|
+
userDid = doData.userDid;
|
|
774
772
|
}
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
key: userAgentKey,
|
|
794
|
-
userDid: userDid.slice(0, 20) + "...",
|
|
795
|
-
agentDid: agentDid.slice(0, 20) + "...",
|
|
796
|
-
});
|
|
797
|
-
}
|
|
798
|
-
const userAgentToken = await delegationStorage.get(userAgentKey, "text");
|
|
799
|
-
if (kvRetry === 0 || userAgentToken) {
|
|
800
|
-
logger.debug("[MCPICloudflareAgent] 🔍 PRIORITY 1: User+agent scoped lookup result:", {
|
|
801
|
-
found: !!userAgentToken,
|
|
802
|
-
tokenLength: userAgentToken?.length || 0,
|
|
803
|
-
...(kvRetry > 0 && { kvRetry }),
|
|
804
|
-
});
|
|
805
|
-
}
|
|
806
|
-
if (userAgentToken) {
|
|
807
|
-
delegationToken = userAgentToken;
|
|
808
|
-
tokenSource = "user+agent-key";
|
|
809
|
-
if (kvRetry > 0) {
|
|
810
|
-
logger.info(`[MCPICloudflareAgent] ✅ Delegation found after ${kvRetry} KV retry(s) - eventual consistency resolved`);
|
|
811
|
-
}
|
|
812
|
-
break;
|
|
813
|
-
}
|
|
814
|
-
}
|
|
815
|
-
// PRIORITY 2: Session-scoped token (if session ID persists)
|
|
816
|
-
if (!delegationToken) {
|
|
817
|
-
if (kvRetry === 0) {
|
|
818
|
-
logger.debug("[MCPICloudflareAgent] 🔍 PRIORITY 2: Checking session-scoped key:", {
|
|
819
|
-
key: sessionKey,
|
|
820
|
-
sessionId: sessionId.slice(0, 20) + "...",
|
|
821
|
-
});
|
|
822
|
-
}
|
|
823
|
-
const sessionTokenData = (await delegationStorage.get(sessionKey, "json"));
|
|
824
|
-
if (kvRetry === 0 || sessionTokenData?.delegationToken) {
|
|
825
|
-
logger.debug("[MCPICloudflareAgent] 🔍 PRIORITY 2: Session-scoped lookup result:", {
|
|
826
|
-
found: !!sessionTokenData,
|
|
827
|
-
hasDelegationToken: !!sessionTokenData?.delegationToken,
|
|
828
|
-
hasDelegationId: !!sessionTokenData?.delegationId,
|
|
829
|
-
tokenLength: sessionTokenData?.delegationToken?.length || 0,
|
|
830
|
-
...(kvRetry > 0 && { kvRetry }),
|
|
831
|
-
});
|
|
832
|
-
}
|
|
833
|
-
if (sessionTokenData?.delegationToken) {
|
|
834
|
-
delegationToken = sessionTokenData.delegationToken;
|
|
835
|
-
tokenSource = "session-key";
|
|
836
|
-
// Extract delegationId if not already set
|
|
837
|
-
if (!delegationId && sessionTokenData.delegationId) {
|
|
838
|
-
delegationId = sessionTokenData.delegationId;
|
|
839
|
-
}
|
|
840
|
-
if (kvRetry > 0) {
|
|
841
|
-
logger.info(`[MCPICloudflareAgent] ✅ Delegation found after ${kvRetry} KV retry(s) - eventual consistency resolved`);
|
|
842
|
-
}
|
|
843
|
-
break;
|
|
844
|
-
}
|
|
773
|
+
logger.debug("[MCPICloudflareAgent] ✅ Delegation found in DO storage:", {
|
|
774
|
+
sessionId: sessionId.slice(0, 20) + "...",
|
|
775
|
+
delegationId,
|
|
776
|
+
hasUserDid: !!userDid,
|
|
777
|
+
});
|
|
778
|
+
}
|
|
779
|
+
else {
|
|
780
|
+
// Fallback: Check KV for backward compatibility with existing delegations
|
|
781
|
+
// This handles delegations created before the DO storage migration
|
|
782
|
+
if (delegationStorage && userDid) {
|
|
783
|
+
const userAgentKey = STORAGE_KEYS.delegation(userDid, agentDid);
|
|
784
|
+
const kvToken = await delegationStorage.get(userAgentKey, "text");
|
|
785
|
+
if (kvToken) {
|
|
786
|
+
delegationToken = kvToken;
|
|
787
|
+
logger.debug("[MCPICloudflareAgent] ✅ Delegation found in KV (legacy):", {
|
|
788
|
+
sessionId: sessionId.slice(0, 20) + "...",
|
|
789
|
+
source: "kv-fallback",
|
|
790
|
+
});
|
|
845
791
|
}
|
|
846
792
|
}
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
// Delegations are now strictly session-scoped or user+agent scoped.
|
|
850
|
-
// See: Security fix for cross-user delegation leakage
|
|
851
|
-
if (delegationToken) {
|
|
852
|
-
logger.debug("[MCPICloudflareAgent] ✅ Delegation token retrieved:", {
|
|
853
|
-
sessionId: sessionId.slice(0, 20) + "...",
|
|
854
|
-
tokenLength: delegationToken.length,
|
|
855
|
-
source: tokenSource,
|
|
856
|
-
});
|
|
857
|
-
}
|
|
858
|
-
else {
|
|
859
|
-
// NOTE: This is informational - delegation is only required for protected tools
|
|
860
|
-
// If the tool doesn't require delegation, this message can be ignored
|
|
861
|
-
// The proper fix for KV consistency is passing userDid through redirect params
|
|
862
|
-
logger.debug("[MCPICloudflareAgent] ℹ️ No delegation token found (normal if tool doesn't require delegation):", {
|
|
793
|
+
if (!delegationToken) {
|
|
794
|
+
logger.debug("[MCPICloudflareAgent] ℹ️ No delegation found:", {
|
|
863
795
|
sessionId: sessionId.slice(0, 20) + "...",
|
|
864
796
|
hasUserDid: !!userDid,
|
|
865
|
-
note: "Delegation only required for tools
|
|
797
|
+
note: "Delegation only required for tools with 'requiresDelegation: true'",
|
|
866
798
|
});
|
|
867
799
|
}
|
|
868
800
|
}
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
801
|
+
}
|
|
802
|
+
catch (error) {
|
|
803
|
+
logger.warn("[MCPICloudflareAgent] Failed to retrieve delegation:", error);
|
|
872
804
|
}
|
|
873
805
|
// ✅ FIX: Extract userDid from delegation token if not available from session storage
|
|
874
806
|
// This handles KV eventual consistency issues where session cache is stale but delegation exists
|
|
@@ -1798,6 +1730,33 @@ export class MCPICloudflareAgent extends McpAgent {
|
|
|
1798
1730
|
}), { status: 500, headers: { "Content-Type": "application/json" } });
|
|
1799
1731
|
}
|
|
1800
1732
|
}
|
|
1733
|
+
// Handle internal delegation storage request
|
|
1734
|
+
// This is called by consent.service.ts to store delegation tokens directly in DO storage.
|
|
1735
|
+
// Using DO storage instead of KV eliminates eventual consistency issues since
|
|
1736
|
+
// both storage and retrieval happen on the same DO instance (strongly consistent).
|
|
1737
|
+
if (url.pathname === "/_internal/delegation/store" && request.method === "POST") {
|
|
1738
|
+
logger.info("[MCPICloudflareAgent] Handling internal delegation store request");
|
|
1739
|
+
try {
|
|
1740
|
+
const body = await request.json();
|
|
1741
|
+
if (!body.sessionId || !body.delegationToken || !body.delegationId || !body.agentDid) {
|
|
1742
|
+
return new Response(JSON.stringify({ success: false, error: "Missing required fields" }), { status: 400, headers: { "Content-Type": "application/json" } });
|
|
1743
|
+
}
|
|
1744
|
+
await this.storeDelegationToStorage(body);
|
|
1745
|
+
logger.info("[MCPICloudflareAgent] ✅ Delegation stored to DO storage:", {
|
|
1746
|
+
sessionId: body.sessionId.slice(0, 20) + "...",
|
|
1747
|
+
delegationId: body.delegationId,
|
|
1748
|
+
hasUserDid: !!body.userDid,
|
|
1749
|
+
});
|
|
1750
|
+
return new Response(JSON.stringify({ success: true }), { status: 200, headers: { "Content-Type": "application/json" } });
|
|
1751
|
+
}
|
|
1752
|
+
catch (error) {
|
|
1753
|
+
logger.error("[MCPICloudflareAgent] Delegation store request failed:", error);
|
|
1754
|
+
return new Response(JSON.stringify({
|
|
1755
|
+
success: false,
|
|
1756
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1757
|
+
}), { status: 500, headers: { "Content-Type": "application/json" } });
|
|
1758
|
+
}
|
|
1759
|
+
}
|
|
1801
1760
|
// Handle internal cache-clear request
|
|
1802
1761
|
if (url.pathname === "/_do/cache-clear" && request.method === "POST") {
|
|
1803
1762
|
logger.info("[MCPICloudflareAgent] Handling internal cache-clear request");
|
|
@@ -1936,6 +1895,93 @@ export class MCPICloudflareAgent extends McpAgent {
|
|
|
1936
1895
|
};
|
|
1937
1896
|
}
|
|
1938
1897
|
}
|
|
1898
|
+
// ============================================================================
|
|
1899
|
+
// DO-BASED DELEGATION STORAGE
|
|
1900
|
+
// ============================================================================
|
|
1901
|
+
// These methods provide strongly consistent delegation storage using the
|
|
1902
|
+
// Durable Object's internal storage (this.ctx.storage). This eliminates the
|
|
1903
|
+
// eventual consistency issues with KV that require retry mechanisms.
|
|
1904
|
+
//
|
|
1905
|
+
// Flow:
|
|
1906
|
+
// 1. Consent service (Worker) calls /_internal/delegation/store via DO stub
|
|
1907
|
+
// 2. DO stores delegation in this.ctx.storage keyed by sessionId
|
|
1908
|
+
// 3. Tool execution reads from this.ctx.storage (same DO = strongly consistent)
|
|
1909
|
+
// ============================================================================
|
|
1910
|
+
/**
|
|
1911
|
+
* Store delegation data to DO internal storage
|
|
1912
|
+
*
|
|
1913
|
+
* Uses multiple storage keys for efficient lookup:
|
|
1914
|
+
* - `delegation:session:${sessionId}` - Primary key for session-based lookup
|
|
1915
|
+
* - `delegation:user:${userDid}:agent:${agentDid}` - Secondary key for user-based lookup
|
|
1916
|
+
*
|
|
1917
|
+
* @param data - Delegation data to store
|
|
1918
|
+
*/
|
|
1919
|
+
async storeDelegationToStorage(data) {
|
|
1920
|
+
const { sessionId, delegationToken, delegationId, userDid, agentDid } = data;
|
|
1921
|
+
const storageData = {
|
|
1922
|
+
delegationToken,
|
|
1923
|
+
delegationId,
|
|
1924
|
+
userDid,
|
|
1925
|
+
agentDid,
|
|
1926
|
+
storedAt: Date.now(),
|
|
1927
|
+
};
|
|
1928
|
+
// Store with session key (primary for tool execution)
|
|
1929
|
+
const sessionKey = `delegation:session:${sessionId}`;
|
|
1930
|
+
await this.ctx.storage.put(sessionKey, storageData);
|
|
1931
|
+
// Store with user+agent key (for persistence across sessions)
|
|
1932
|
+
if (userDid) {
|
|
1933
|
+
const userAgentKey = `delegation:user:${userDid}:agent:${agentDid}`;
|
|
1934
|
+
await this.ctx.storage.put(userAgentKey, storageData);
|
|
1935
|
+
}
|
|
1936
|
+
logger.debug("[MCPICloudflareAgent] Delegation stored to DO storage:", {
|
|
1937
|
+
sessionKey,
|
|
1938
|
+
hasUserAgentKey: !!userDid,
|
|
1939
|
+
delegationId,
|
|
1940
|
+
});
|
|
1941
|
+
}
|
|
1942
|
+
/**
|
|
1943
|
+
* Retrieve delegation from DO internal storage
|
|
1944
|
+
*
|
|
1945
|
+
* Looks up in priority order:
|
|
1946
|
+
* 1. Session key (primary)
|
|
1947
|
+
* 2. User+agent key (if userDid available)
|
|
1948
|
+
*
|
|
1949
|
+
* @param sessionId - Session ID
|
|
1950
|
+
* @param userDid - Optional user DID for secondary lookup
|
|
1951
|
+
* @param agentDid - Agent DID for secondary lookup
|
|
1952
|
+
* @returns Delegation data or undefined if not found
|
|
1953
|
+
*/
|
|
1954
|
+
async getDelegationFromStorage(sessionId, userDid, agentDid) {
|
|
1955
|
+
// Try session key first
|
|
1956
|
+
const sessionKey = `delegation:session:${sessionId}`;
|
|
1957
|
+
const sessionData = await this.ctx.storage.get(sessionKey);
|
|
1958
|
+
if (sessionData) {
|
|
1959
|
+
logger.debug("[MCPICloudflareAgent] Delegation found via session key:", {
|
|
1960
|
+
sessionId: sessionId.slice(0, 20) + "...",
|
|
1961
|
+
delegationId: sessionData.delegationId,
|
|
1962
|
+
});
|
|
1963
|
+
return sessionData;
|
|
1964
|
+
}
|
|
1965
|
+
// Try user+agent key if we have userDid
|
|
1966
|
+
if (userDid && agentDid) {
|
|
1967
|
+
const userAgentKey = `delegation:user:${userDid}:agent:${agentDid}`;
|
|
1968
|
+
const userAgentData = await this.ctx.storage.get(userAgentKey);
|
|
1969
|
+
if (userAgentData) {
|
|
1970
|
+
logger.debug("[MCPICloudflareAgent] Delegation found via user+agent key:", {
|
|
1971
|
+
userDid: userDid.slice(0, 20) + "...",
|
|
1972
|
+
agentDid: agentDid.slice(0, 20) + "...",
|
|
1973
|
+
delegationId: userAgentData.delegationId,
|
|
1974
|
+
});
|
|
1975
|
+
return userAgentData;
|
|
1976
|
+
}
|
|
1977
|
+
}
|
|
1978
|
+
logger.debug("[MCPICloudflareAgent] No delegation found in DO storage:", {
|
|
1979
|
+
sessionId: sessionId.slice(0, 20) + "...",
|
|
1980
|
+
hasUserDid: !!userDid,
|
|
1981
|
+
hasAgentDid: !!agentDid,
|
|
1982
|
+
});
|
|
1983
|
+
return undefined;
|
|
1984
|
+
}
|
|
1939
1985
|
/**
|
|
1940
1986
|
* Handle MCP-I handshake JSON-RPC request
|
|
1941
1987
|
*
|