@kya-os/mcp-i-core 1.3.7-canary.clientinfo.20251126041014 → 1.3.8-canary.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/.turbo/turbo-build.log +1 -1
- package/.turbo/turbo-test$colon$coverage.log +2913 -2246
- package/.turbo/turbo-test.log +1207 -2842
- package/coverage/coverage-final.json +57 -56
- package/dist/__tests__/utils/mock-providers.d.ts +2 -1
- package/dist/__tests__/utils/mock-providers.d.ts.map +1 -1
- package/dist/__tests__/utils/mock-providers.js.map +1 -1
- package/dist/config/remote-config.d.ts +51 -0
- package/dist/config/remote-config.d.ts.map +1 -1
- package/dist/config/remote-config.js +74 -0
- package/dist/config/remote-config.js.map +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +4 -1
- package/dist/config.js.map +1 -1
- package/dist/services/session-registration.service.d.ts.map +1 -1
- package/dist/services/session-registration.service.js +10 -66
- package/dist/services/session-registration.service.js.map +1 -1
- package/dist/services/tool-protection.service.d.ts +4 -1
- package/dist/services/tool-protection.service.d.ts.map +1 -1
- package/dist/services/tool-protection.service.js +31 -16
- package/dist/services/tool-protection.service.js.map +1 -1
- package/package.json +2 -2
- package/src/__tests__/integration/full-flow.test.ts +23 -10
- package/src/__tests__/services/agentshield-integration.test.ts +10 -3
- package/src/__tests__/services/tool-protection-merged-config.test.ts +485 -0
- package/src/__tests__/services/tool-protection.service.test.ts +18 -11
- package/src/config/__tests__/merged-config.spec.ts +445 -0
- package/src/config/remote-config.ts +90 -0
- package/src/config.ts +3 -0
- package/src/services/session-registration.service.ts +26 -92
- package/src/services/tool-protection.service.ts +76 -48
|
@@ -112,43 +112,6 @@ export class SessionRegistrationService {
|
|
|
112
112
|
url,
|
|
113
113
|
});
|
|
114
114
|
|
|
115
|
-
// ✅ EMPIRICAL PROOF: Prepare request headers with correct auth format
|
|
116
|
-
const requestHeaders = {
|
|
117
|
-
"Content-Type": "application/json",
|
|
118
|
-
"X-AgentShield-Key": this.config.apiKey, // Fixed: Use X-AgentShield-Key instead of Authorization: Bearer
|
|
119
|
-
};
|
|
120
|
-
|
|
121
|
-
// ✅ EMPIRICAL PROOF: Log exact request details (sanitized for security)
|
|
122
|
-
const sanitizedHeaders = {
|
|
123
|
-
...requestHeaders,
|
|
124
|
-
"X-AgentShield-Key": `${this.config.apiKey.slice(0, 8)}...${this.config.apiKey.slice(-4)}`, // Show first 8 and last 4 chars
|
|
125
|
-
};
|
|
126
|
-
|
|
127
|
-
const sanitizedBody = {
|
|
128
|
-
session_id: request.session_id,
|
|
129
|
-
agent_did: request.agent_did,
|
|
130
|
-
project_id: request.project_id,
|
|
131
|
-
created_at: request.created_at,
|
|
132
|
-
client_info: request.client_info,
|
|
133
|
-
client_identity: request.client_identity,
|
|
134
|
-
server_did: request.server_did,
|
|
135
|
-
ttl_minutes: request.ttl_minutes,
|
|
136
|
-
};
|
|
137
|
-
|
|
138
|
-
this.config.logger(
|
|
139
|
-
"[SessionRegistration] 🔍 EMPIRICAL DEBUG - Request details",
|
|
140
|
-
{
|
|
141
|
-
url,
|
|
142
|
-
method: "POST",
|
|
143
|
-
headers: sanitizedHeaders,
|
|
144
|
-
headerKeys: Object.keys(requestHeaders),
|
|
145
|
-
authHeaderPresent: !!requestHeaders["X-AgentShield-Key"],
|
|
146
|
-
authHeaderName: "X-AgentShield-Key",
|
|
147
|
-
body: sanitizedBody,
|
|
148
|
-
bodySize: JSON.stringify(request).length,
|
|
149
|
-
}
|
|
150
|
-
);
|
|
151
|
-
|
|
152
115
|
// Make the request with timeout
|
|
153
116
|
const controller = new AbortController();
|
|
154
117
|
const timeoutId = setTimeout(
|
|
@@ -159,75 +122,47 @@ export class SessionRegistrationService {
|
|
|
159
122
|
try {
|
|
160
123
|
const response = await this.config.fetchProvider.fetch(url, {
|
|
161
124
|
method: "POST",
|
|
162
|
-
headers:
|
|
125
|
+
headers: {
|
|
126
|
+
"Content-Type": "application/json",
|
|
127
|
+
Authorization: `Bearer ${this.config.apiKey}`,
|
|
128
|
+
},
|
|
163
129
|
body: JSON.stringify(request),
|
|
164
130
|
signal: controller.signal,
|
|
165
131
|
});
|
|
166
132
|
|
|
167
133
|
clearTimeout(timeoutId);
|
|
168
134
|
|
|
169
|
-
// ✅ EMPIRICAL PROOF: Capture exact response details
|
|
170
|
-
const responseHeaders: Record<string, string> = {};
|
|
171
|
-
response.headers.forEach((value, key) => {
|
|
172
|
-
responseHeaders[key] = value;
|
|
173
|
-
});
|
|
174
|
-
|
|
175
|
-
const responseText = await response
|
|
176
|
-
.text()
|
|
177
|
-
.catch(() => "Failed to read response");
|
|
178
|
-
let responseBody: unknown;
|
|
179
|
-
try {
|
|
180
|
-
responseBody = JSON.parse(responseText);
|
|
181
|
-
} catch {
|
|
182
|
-
responseBody = responseText;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
// ✅ EMPIRICAL PROOF: Log exact response details
|
|
186
|
-
this.config.logger(
|
|
187
|
-
"[SessionRegistration] 🔍 EMPIRICAL DEBUG - Response details",
|
|
188
|
-
{
|
|
189
|
-
status: response.status,
|
|
190
|
-
statusText: response.statusText,
|
|
191
|
-
ok: response.ok,
|
|
192
|
-
headers: responseHeaders,
|
|
193
|
-
body: responseBody,
|
|
194
|
-
bodyLength: responseText.length,
|
|
195
|
-
clientName: request.client_info.name,
|
|
196
|
-
}
|
|
197
|
-
);
|
|
198
|
-
|
|
199
135
|
if (!response.ok) {
|
|
200
136
|
// Log error but don't throw - this is fire-and-forget
|
|
137
|
+
const errorText = await response.text().catch(() => "Unknown error");
|
|
201
138
|
this.config.logger("[SessionRegistration] Registration failed", {
|
|
202
139
|
sessionId,
|
|
203
140
|
status: response.status,
|
|
204
|
-
error:
|
|
205
|
-
// ✅ EMPIRICAL PROOF: Include full response details
|
|
206
|
-
responseHeaders,
|
|
207
|
-
responseBody,
|
|
208
|
-
clientName: request.client_info.name,
|
|
141
|
+
error: errorText,
|
|
209
142
|
});
|
|
210
143
|
return {
|
|
211
144
|
success: false,
|
|
212
145
|
sessionId,
|
|
213
|
-
error: `HTTP ${response.status}: ${
|
|
146
|
+
error: `HTTP ${response.status}: ${errorText}`,
|
|
214
147
|
};
|
|
215
148
|
}
|
|
216
149
|
|
|
217
|
-
// Parse response
|
|
218
|
-
const responseData =
|
|
219
|
-
|
|
220
|
-
|
|
150
|
+
// Parse response
|
|
151
|
+
const responseData = (await response.json()) as {
|
|
152
|
+
data?: RegisterSessionResponse;
|
|
153
|
+
} & RegisterSessionResponse;
|
|
221
154
|
const parseResult = registerSessionResponseSchema.safeParse(
|
|
222
|
-
|
|
223
|
-
responseData
|
|
155
|
+
responseData.data || responseData
|
|
224
156
|
);
|
|
225
157
|
|
|
226
158
|
if (!parseResult.success) {
|
|
227
|
-
this.config.logger(
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
159
|
+
this.config.logger(
|
|
160
|
+
"[SessionRegistration] Invalid response format",
|
|
161
|
+
{
|
|
162
|
+
sessionId,
|
|
163
|
+
response: responseData,
|
|
164
|
+
}
|
|
165
|
+
);
|
|
231
166
|
// Still consider it a success if we got a 200 OK
|
|
232
167
|
return { success: true, sessionId };
|
|
233
168
|
}
|
|
@@ -252,7 +187,8 @@ export class SessionRegistrationService {
|
|
|
252
187
|
}
|
|
253
188
|
|
|
254
189
|
// Log any other error
|
|
255
|
-
const errorMsg =
|
|
190
|
+
const errorMsg =
|
|
191
|
+
error instanceof Error ? error.message : "Unknown error";
|
|
256
192
|
this.config.logger("[SessionRegistration] Unexpected error", {
|
|
257
193
|
sessionId,
|
|
258
194
|
error: errorMsg,
|
|
@@ -274,13 +210,10 @@ export class SessionRegistrationService {
|
|
|
274
210
|
this.registerSession(request).catch((error) => {
|
|
275
211
|
// This should never happen since registerSession catches all errors,
|
|
276
212
|
// but just in case
|
|
277
|
-
this.config.logger(
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
error: error instanceof Error ? error.message : "Unknown error",
|
|
282
|
-
}
|
|
283
|
-
);
|
|
213
|
+
this.config.logger("[SessionRegistration] Background registration failed", {
|
|
214
|
+
sessionId: request.session_id,
|
|
215
|
+
error: error instanceof Error ? error.message : "Unknown error",
|
|
216
|
+
});
|
|
284
217
|
});
|
|
285
218
|
}
|
|
286
219
|
}
|
|
@@ -315,3 +248,4 @@ export function createSessionRegistrationService(options: {
|
|
|
315
248
|
logger: options.logger,
|
|
316
249
|
});
|
|
317
250
|
}
|
|
251
|
+
|
|
@@ -87,34 +87,56 @@ import type {
|
|
|
87
87
|
import type { ToolProtectionCache } from "../cache/tool-protection-cache.js";
|
|
88
88
|
import { InMemoryToolProtectionCache } from "../cache/tool-protection-cache.js";
|
|
89
89
|
|
|
90
|
+
/**
|
|
91
|
+
* Tool protection data structure in API responses
|
|
92
|
+
*/
|
|
93
|
+
interface ToolProtectionData {
|
|
94
|
+
requiresDelegation?: boolean;
|
|
95
|
+
requires_delegation?: boolean;
|
|
96
|
+
requiredScopes?: string[];
|
|
97
|
+
required_scopes?: string[];
|
|
98
|
+
scopes?: string[];
|
|
99
|
+
riskLevel?: string;
|
|
100
|
+
risk_level?: string;
|
|
101
|
+
oauthProvider?: string;
|
|
102
|
+
oauth_provider?: string;
|
|
103
|
+
authorization?: {
|
|
104
|
+
type: string;
|
|
105
|
+
provider?: string;
|
|
106
|
+
issuer?: string;
|
|
107
|
+
credentialType?: string;
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
90
111
|
/**
|
|
91
112
|
* Response from AgentShield API bouncer endpoints
|
|
92
113
|
*
|
|
93
114
|
* Supports multiple endpoint formats:
|
|
94
|
-
* 1.
|
|
95
|
-
* 2.
|
|
96
|
-
* 3.
|
|
115
|
+
* 1. Merged config (/projects/{projectId}/config): { data: { config: { toolProtection: { tools: {...} } } } }
|
|
116
|
+
* 2. Legacy tool-protections endpoint: { data: { toolProtections: { [toolName]: {...} } } }
|
|
117
|
+
* 3. Old config endpoint (/config?agent_did=...): { data: { tools: [{ name: string, ... }] } }
|
|
118
|
+
* 4. Legacy format: { data: { tools: { [toolName]: {...} } } }
|
|
97
119
|
*/
|
|
98
120
|
interface BouncerConfigApiResponse {
|
|
99
121
|
success: boolean;
|
|
100
122
|
data: {
|
|
101
123
|
agent_did?: string;
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
//
|
|
124
|
+
|
|
125
|
+
// NEW: Merged config format (v1.6.0+) - preferred format
|
|
126
|
+
// The entire config is returned with tools embedded at config.toolProtection.tools
|
|
127
|
+
config?: {
|
|
128
|
+
toolProtection?: {
|
|
129
|
+
source?: string;
|
|
130
|
+
tools?: Record<string, ToolProtectionData>;
|
|
131
|
+
};
|
|
132
|
+
// Other config fields we don't need to parse
|
|
133
|
+
[key: string]: unknown;
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
// DEPRECATED: Top-level toolProtections (backward compatibility during transition)
|
|
137
|
+
toolProtections?: Record<string, ToolProtectionData>;
|
|
138
|
+
|
|
139
|
+
// Legacy endpoint formats
|
|
118
140
|
tools?:
|
|
119
141
|
| Array<{
|
|
120
142
|
name: string;
|
|
@@ -122,20 +144,10 @@ interface BouncerConfigApiResponse {
|
|
|
122
144
|
requires_delegation?: boolean;
|
|
123
145
|
scopes?: string[];
|
|
124
146
|
required_scopes?: string[];
|
|
125
|
-
oauthProvider?: string;
|
|
126
|
-
oauth_provider?: string;
|
|
147
|
+
oauthProvider?: string;
|
|
148
|
+
oauth_provider?: string;
|
|
127
149
|
}>
|
|
128
|
-
| Record<
|
|
129
|
-
string,
|
|
130
|
-
{
|
|
131
|
-
requiresDelegation?: boolean;
|
|
132
|
-
requires_delegation?: boolean;
|
|
133
|
-
scopes?: string[];
|
|
134
|
-
required_scopes?: string[];
|
|
135
|
-
oauthProvider?: string; // Phase 2: Tool-specific OAuth provider
|
|
136
|
-
oauth_provider?: string; // Phase 2: snake_case variant
|
|
137
|
-
}
|
|
138
|
-
>;
|
|
150
|
+
| Record<string, ToolProtectionData>;
|
|
139
151
|
reputation_threshold?: number;
|
|
140
152
|
denied_agents?: string[];
|
|
141
153
|
};
|
|
@@ -271,7 +283,7 @@ export class ToolProtectionService {
|
|
|
271
283
|
projectId: this.config.projectId || "none",
|
|
272
284
|
apiUrl: this.config.apiUrl,
|
|
273
285
|
endpoint: this.config.projectId
|
|
274
|
-
? `/api/v1/bouncer/projects/${this.config.projectId}/
|
|
286
|
+
? `/api/v1/bouncer/projects/${this.config.projectId}/config`
|
|
275
287
|
: `/api/v1/bouncer/config?agent_did=${agentDid}`,
|
|
276
288
|
});
|
|
277
289
|
}
|
|
@@ -665,7 +677,10 @@ export class ToolProtectionService {
|
|
|
665
677
|
|
|
666
678
|
/**
|
|
667
679
|
* Fetch tool protection config from AgentShield API
|
|
668
|
-
*
|
|
680
|
+
*
|
|
681
|
+
* Uses the merged /config endpoint which returns tool protections embedded
|
|
682
|
+
* at config.toolProtection.tools. Falls back to legacy formats for backward
|
|
683
|
+
* compatibility.
|
|
669
684
|
*
|
|
670
685
|
* @param agentDid DID of the agent to fetch config for
|
|
671
686
|
* @param options Optional fetch options
|
|
@@ -675,17 +690,17 @@ export class ToolProtectionService {
|
|
|
675
690
|
agentDid: string,
|
|
676
691
|
options?: { bypassCDNCache?: boolean }
|
|
677
692
|
): Promise<BouncerConfigApiResponse> {
|
|
678
|
-
//
|
|
679
|
-
//
|
|
693
|
+
// Use the merged /config endpoint which includes embedded tool protections
|
|
694
|
+
// This endpoint returns config.toolProtection.tools with all tool rules
|
|
680
695
|
let url: string;
|
|
681
|
-
let
|
|
696
|
+
let useMergedEndpoint = false;
|
|
682
697
|
|
|
683
698
|
if (this.config.projectId) {
|
|
684
|
-
// ✅
|
|
685
|
-
url = `${this.config.apiUrl}/api/v1/bouncer/projects/${encodeURIComponent(this.config.projectId)}/
|
|
686
|
-
|
|
699
|
+
// ✅ MERGED CONFIG ENDPOINT: Returns config with embedded toolProtection.tools
|
|
700
|
+
url = `${this.config.apiUrl}/api/v1/bouncer/projects/${encodeURIComponent(this.config.projectId)}/config`;
|
|
701
|
+
useMergedEndpoint = true;
|
|
687
702
|
} else {
|
|
688
|
-
// ⚠️
|
|
703
|
+
// ⚠️ LEGACY ENDPOINT: Agent-scoped, returns tools array (backward compatibility)
|
|
689
704
|
url = `${this.config.apiUrl}/api/v1/bouncer/config?agent_did=${encodeURIComponent(agentDid)}`;
|
|
690
705
|
}
|
|
691
706
|
|
|
@@ -712,9 +727,9 @@ export class ToolProtectionService {
|
|
|
712
727
|
|
|
713
728
|
if (this.config.debug) {
|
|
714
729
|
console.log("[ToolProtectionService] Fetching from API:", url, {
|
|
715
|
-
method:
|
|
716
|
-
? "projects/{projectId}/
|
|
717
|
-
: "config?agent_did (
|
|
730
|
+
method: useMergedEndpoint
|
|
731
|
+
? "projects/{projectId}/config (merged)"
|
|
732
|
+
: "config?agent_did (legacy)",
|
|
718
733
|
projectId: this.config.projectId || "none",
|
|
719
734
|
apiKeyPresent: !!this.config.apiKey,
|
|
720
735
|
apiKeyLength,
|
|
@@ -736,19 +751,19 @@ export class ToolProtectionService {
|
|
|
736
751
|
);
|
|
737
752
|
}
|
|
738
753
|
|
|
739
|
-
// Build headers -
|
|
754
|
+
// Build headers - merged endpoint uses X-API-Key, legacy uses Authorization Bearer
|
|
740
755
|
const headers: Record<string, string> = {
|
|
741
756
|
"Content-Type": "application/json",
|
|
742
757
|
};
|
|
743
758
|
|
|
744
|
-
if (
|
|
745
|
-
// ✅
|
|
759
|
+
if (useMergedEndpoint) {
|
|
760
|
+
// ✅ Merged config endpoint headers
|
|
746
761
|
headers["X-API-Key"] = this.config.apiKey;
|
|
747
762
|
if (this.config.projectId) {
|
|
748
763
|
headers["X-Project-Id"] = this.config.projectId;
|
|
749
764
|
}
|
|
750
765
|
} else {
|
|
751
|
-
// ⚠️
|
|
766
|
+
// ⚠️ Legacy endpoint headers (backward compatibility)
|
|
752
767
|
headers["Authorization"] = `Bearer ${this.config.apiKey}`;
|
|
753
768
|
}
|
|
754
769
|
|
|
@@ -786,6 +801,19 @@ export class ToolProtectionService {
|
|
|
786
801
|
throw new Error("API returned success: false");
|
|
787
802
|
}
|
|
788
803
|
|
|
804
|
+
// Transform merged config format to normalized format
|
|
805
|
+
// If response contains config.toolProtection.tools, extract them to data.toolProtections
|
|
806
|
+
if (useMergedEndpoint && data.data.config?.toolProtection?.tools) {
|
|
807
|
+
// Extract embedded tools to the standard toolProtections field
|
|
808
|
+
data.data.toolProtections = data.data.config.toolProtection.tools;
|
|
809
|
+
if (this.config.debug) {
|
|
810
|
+
console.log("[ToolProtectionService] Extracted tools from merged config", {
|
|
811
|
+
toolCount: Object.keys(data.data.toolProtections).length,
|
|
812
|
+
tools: Object.keys(data.data.toolProtections),
|
|
813
|
+
});
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
|
|
789
817
|
return data;
|
|
790
818
|
}
|
|
791
819
|
|