@slashfi/agents-sdk 0.35.0 → 0.36.1

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/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAqzBH,2EAA2E;AAC3E,MAAM,UAAU,wBAAwB,CACtC,CAAoB;IAEpB,OAAO,CAAC,CAAC,OAAO,KAAK,KAAK,CAAC;AAC7B,CAAC;AA8BD,MAAM,UAAU,4BAA4B,CAC1C,CAA0B;IAE1B,OAAO,CAAC,CAAC,OAAO,KAAK,IAAI,CAAC;AAC5B,CAAC;AAED,MAAM,UAAU,4BAA4B,CAC1C,CAA0B;IAE1B,OAAO,CAAC,CAAC,OAAO,KAAK,KAAK,IAAI,WAAW,IAAI,CAAC,IAAI,CAAC,CAAC,SAAS,KAAK,IAAI,CAAC;AACzE,CAAC"}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AA2zBH,2EAA2E;AAC3E,MAAM,UAAU,wBAAwB,CACtC,CAAoB;IAEpB,OAAO,CAAC,CAAC,OAAO,KAAK,KAAK,CAAC;AAC7B,CAAC;AA8BD,MAAM,UAAU,4BAA4B,CAC1C,CAA0B;IAE1B,OAAO,CAAC,CAAC,OAAO,KAAK,IAAI,CAAC;AAC5B,CAAC;AAED,MAAM,UAAU,4BAA4B,CAC1C,CAA0B;IAE1B,OAAO,CAAC,CAAC,OAAO,KAAK,KAAK,IAAI,WAAW,IAAI,CAAC,IAAI,CAAC,CAAC,SAAS,KAAK,IAAI,CAAC;AACzE,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@slashfi/agents-sdk",
3
- "version": "0.35.0",
3
+ "version": "0.36.1",
4
4
  "author": "Slash Financial",
5
5
  "repository": {
6
6
  "type": "git",
package/src/events.ts CHANGED
@@ -10,7 +10,7 @@
10
10
  * Filtering happens in the callback, not the API.
11
11
  */
12
12
 
13
- import type { CallAgentRequest, CallAgentResponse } from "./types.js";
13
+ import type { AgentDefinition, CallAgentRequest, CallAgentResponse } from "./types.js";
14
14
  // =============================================================================
15
15
  // Event Types
16
16
  // =============================================================================
@@ -24,7 +24,8 @@ export type SystemEventType =
24
24
  | "tool/error"
25
25
  | "step"
26
26
  | "invoke"
27
- | "call";
27
+ | "tools/call/call_agent"
28
+ | "tools/call/list_agents";
28
29
 
29
30
  /**
30
31
  * Augmentable map for custom event types. Consumers extend this
@@ -124,12 +125,28 @@ export interface InvokeEvent extends BaseEvent {
124
125
  }
125
126
 
126
127
  /**
127
- * Event emitted when a call_agent request is received.
128
- * Call `resolve(response)` to short-circuit the default handler.
129
- * If no listener resolves, the default call handler runs.
128
+ * Event emitted when the `call_agent` MCP tool is invoked.
129
+ * Replaces the legacy `call` event with a namespaced type.
130
+ *
131
+ * Call `next()` to run the default call handler (optionally with a modified request).
132
+ * Call `resolve(response)` to short-circuit with a custom response.
133
+ * If neither is called, the default handler runs.
134
+ *
135
+ * @example
136
+ * ```ts
137
+ * registry.on('tools/call/call_agent', async (event) => {
138
+ * // Proxy to a remote registry
139
+ * if (isRemoteAgent(event.request.path)) {
140
+ * const result = await proxyToRemote(event.request);
141
+ * event.resolve(result);
142
+ * return;
143
+ * }
144
+ * // Fall through to default handler
145
+ * });
146
+ * ```
130
147
  */
131
- export interface CallEvent extends BaseEvent {
132
- type: "call";
148
+ export interface CallAgentToolCallEvent extends BaseEvent {
149
+ type: "tools/call/call_agent";
133
150
  /** The incoming call_agent request */
134
151
  request: CallAgentRequest;
135
152
  /** Run the default call handler and return its result.
@@ -139,6 +156,61 @@ export interface CallEvent extends BaseEvent {
139
156
  resolve(response: CallAgentResponse): void;
140
157
  }
141
158
 
159
+ /**
160
+ * Result shape for list_agents responses.
161
+ */
162
+ export interface ListAgentsResult {
163
+ success: true;
164
+ total: number;
165
+ nextCursor?: string;
166
+ agents: Array<{
167
+ path: string;
168
+ name?: string;
169
+ description?: string;
170
+ supportedActions?: string[];
171
+ integration?: unknown;
172
+ security?: { type: string };
173
+ resources?: Array<{ uri: string; name?: string; mimeType?: string }>;
174
+ tools: string[];
175
+ }>;
176
+ }
177
+
178
+ /**
179
+ * Event emitted when the `list_agents` MCP tool is invoked.
180
+ *
181
+ * Gives hosts a chance to inject additional agents (e.g., from remote registries
182
+ * or consumer config) before BM25 search and pagination run.
183
+ *
184
+ * Call `next(additionalAgents?)` to continue default behavior with optional
185
+ * extra agents merged into the base set.
186
+ * Call `resolve(result)` to short-circuit with a fully formed response.
187
+ * If neither is called, the default handler runs with the base agents.
188
+ *
189
+ * @example
190
+ * ```ts
191
+ * registry.on('tools/call/list_agents', async (event) => {
192
+ * const remoteAgents = await fetchRemoteAgents();
193
+ * await event.next(remoteAgents);
194
+ * });
195
+ * ```
196
+ */
197
+ export interface ListAgentsToolCallEvent extends BaseEvent {
198
+ type: "tools/call/list_agents";
199
+ /** Agents from the local registry (before search/pagination) */
200
+ baseAgents: AgentDefinition[];
201
+ /** Search query, if provided */
202
+ query?: string;
203
+ /** Requested page size */
204
+ limit?: number;
205
+ /** Pagination cursor */
206
+ cursor?: string;
207
+ /** Continue with default BM25/pagination behavior.
208
+ * Pass additional agents to merge into the base set. */
209
+ next(additionalAgents?: AgentDefinition[]): Promise<ListAgentsResult>;
210
+ /** Short-circuit with a complete response (same shape as list_agents output) */
211
+ resolve(result: ListAgentsResult): void;
212
+ }
213
+
142
214
  /**
143
215
  * Union of all built-in event types.
144
216
  */
@@ -148,7 +220,8 @@ export type AgentEvent =
148
220
  | ToolErrorEvent
149
221
  | StepEvent
150
222
  | InvokeEvent
151
- | CallEvent;
223
+ | CallAgentToolCallEvent
224
+ | ListAgentsToolCallEvent;
152
225
 
153
226
  /**
154
227
  * Map from system event type string to event interface.
@@ -159,7 +232,8 @@ export interface SystemEventMap {
159
232
  "tool/error": ToolErrorEvent;
160
233
  step: StepEvent;
161
234
  invoke: InvokeEvent;
162
- call: CallEvent;
235
+ "tools/call/call_agent": CallAgentToolCallEvent;
236
+ "tools/call/list_agents": ListAgentsToolCallEvent;
163
237
  }
164
238
 
165
239
  /**
@@ -0,0 +1,439 @@
1
+ /**
2
+ * Tests for tools/call/call_agent and tools/call/list_agents hooks.
3
+ *
4
+ * These go through the full production path:
5
+ * HTTP POST → JSON-RPC → MCP tools/call → handleToolCall → registry hooks
6
+ *
7
+ * Mirrors how atlas-os uses these hooks to intercept and route requests.
8
+ */
9
+
10
+ import { afterAll, beforeAll, describe, expect, test } from "bun:test";
11
+ import {
12
+ createAgentRegistry,
13
+ createAgentServer,
14
+ defineAgent,
15
+ defineTool,
16
+ } from "./index";
17
+ import type {
18
+ AgentDefinition,
19
+ AgentServer,
20
+ CallAgentToolCallEvent,
21
+ ListAgentsToolCallEvent,
22
+ } from "./index";
23
+
24
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
25
+ // Test agents
26
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
27
+
28
+ const echoAgent = defineAgent({
29
+ path: "@echo",
30
+ entrypoint: "Echo agent",
31
+ config: { name: "Echo", description: "Echoes input back" },
32
+ visibility: "public" as const,
33
+ tools: [
34
+ defineTool({
35
+ name: "echo",
36
+ description: "Echo the input",
37
+ inputSchema: {
38
+ type: "object",
39
+ properties: { message: { type: "string" } },
40
+ required: ["message"],
41
+ },
42
+ execute: async (input: { message: string }) => ({
43
+ echoed: input.message,
44
+ }),
45
+ }),
46
+ ],
47
+ });
48
+
49
+ const mathAgent = defineAgent({
50
+ path: "@math",
51
+ entrypoint: "Math agent",
52
+ config: { name: "Math", description: "Does math" },
53
+ visibility: "public" as const,
54
+ tools: [
55
+ defineTool({
56
+ name: "add",
57
+ description: "Add two numbers",
58
+ inputSchema: {
59
+ type: "object",
60
+ properties: {
61
+ a: { type: "number" },
62
+ b: { type: "number" },
63
+ },
64
+ required: ["a", "b"],
65
+ },
66
+ execute: async (input: { a: number; b: number }) => ({
67
+ result: input.a + input.b,
68
+ }),
69
+ }),
70
+ ],
71
+ });
72
+
73
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
74
+ // Helper: MCP JSON-RPC call through HTTP
75
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
76
+
77
+ let nextId = 1;
78
+ async function mcpCall(
79
+ baseUrl: string,
80
+ toolName: string,
81
+ args: Record<string, unknown>,
82
+ ) {
83
+ const res = await fetch(baseUrl, {
84
+ method: "POST",
85
+ headers: { "Content-Type": "application/json" },
86
+ body: JSON.stringify({
87
+ jsonrpc: "2.0",
88
+ id: nextId++,
89
+ method: "tools/call",
90
+ params: { name: toolName, arguments: args },
91
+ }),
92
+ });
93
+
94
+ const json = (await res.json()) as {
95
+ result?: { content?: Array<{ text: string }> };
96
+ };
97
+ const text = json.result?.content?.[0]?.text;
98
+ return text ? JSON.parse(text) : json;
99
+ }
100
+
101
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
102
+ // tools/call/call_agent tests
103
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
104
+
105
+ describe("tools/call/call_agent hook", () => {
106
+ const PORT = 19870;
107
+
108
+ test("resolve() short-circuits the default handler", async () => {
109
+ // This mirrors atlas-os: intercept call_agent, route externally, resolve()
110
+ const registry = createAgentRegistry({ defaultVisibility: "public" });
111
+ registry.register(echoAgent);
112
+
113
+ registry.on("tools/call/call_agent", async (event) => {
114
+ event.resolve({
115
+ success: true,
116
+ result: { intercepted: true, originalPath: event.request.path },
117
+ });
118
+ });
119
+
120
+ const server = createAgentServer(registry, { port: PORT });
121
+ await server.start();
122
+
123
+ const result = await mcpCall(`http://localhost:${PORT}`, "call_agent", {
124
+ action: "execute_tool",
125
+ path: "@echo",
126
+ tool: "echo",
127
+ params: { message: "hello" },
128
+ });
129
+
130
+ expect(result.success).toBe(true);
131
+ expect(result.result.intercepted).toBe(true);
132
+ expect(result.result.originalPath).toBe("@echo");
133
+ await server.stop();
134
+ });
135
+
136
+ test("next() runs default handler and hook observes", async () => {
137
+ const registry = createAgentRegistry({ defaultVisibility: "public" });
138
+ registry.register(echoAgent);
139
+
140
+ let hookSawRequest = false;
141
+ registry.on("tools/call/call_agent", async (event) => {
142
+ hookSawRequest = true;
143
+ await event.next();
144
+ });
145
+
146
+ const server = createAgentServer(registry, { port: PORT + 1 });
147
+ await server.start();
148
+
149
+ const result = await mcpCall(`http://localhost:${PORT + 1}`, "call_agent", {
150
+ action: "execute_tool",
151
+ path: "@echo",
152
+ tool: "echo",
153
+ params: { message: "passthrough" },
154
+ });
155
+
156
+ expect(hookSawRequest).toBe(true);
157
+ expect(result.success).toBe(true);
158
+ expect(result.result.echoed).toBe("passthrough");
159
+ await server.stop();
160
+ });
161
+
162
+ test("next() with modified request reroutes the call", async () => {
163
+ const registry = createAgentRegistry({ defaultVisibility: "public" });
164
+ registry.register(echoAgent);
165
+ registry.register(mathAgent);
166
+
167
+ registry.on("tools/call/call_agent", async (event) => {
168
+ if (event.request.action === "execute_tool" && event.request.path === "@echo") {
169
+ await event.next({
170
+ ...event.request,
171
+ path: "@math",
172
+ tool: "add",
173
+ params: { a: 10, b: 20 },
174
+ });
175
+ }
176
+ });
177
+
178
+ const server = createAgentServer(registry, { port: PORT + 2 });
179
+ await server.start();
180
+
181
+ const result = await mcpCall(`http://localhost:${PORT + 2}`, "call_agent", {
182
+ action: "execute_tool",
183
+ path: "@echo",
184
+ tool: "echo",
185
+ params: { message: "this gets rerouted" },
186
+ });
187
+
188
+ expect(result.success).toBe(true);
189
+ expect(result.result.result).toBe(30);
190
+ await server.stop();
191
+ });
192
+
193
+ test("no listener = default behavior unchanged", async () => {
194
+ const registry = createAgentRegistry({ defaultVisibility: "public" });
195
+ registry.register(echoAgent);
196
+
197
+ const server = createAgentServer(registry, { port: PORT + 3 });
198
+ await server.start();
199
+
200
+ const result = await mcpCall(`http://localhost:${PORT + 3}`, "call_agent", {
201
+ action: "execute_tool",
202
+ path: "@echo",
203
+ tool: "echo",
204
+ params: { message: "no hook" },
205
+ });
206
+
207
+ expect(result.success).toBe(true);
208
+ expect(result.result.echoed).toBe("no hook");
209
+ await server.stop();
210
+ });
211
+
212
+ test("resolve() with error response", async () => {
213
+ const registry = createAgentRegistry({ defaultVisibility: "public" });
214
+ registry.register(echoAgent);
215
+
216
+ registry.on("tools/call/call_agent", async (event) => {
217
+ event.resolve({
218
+ success: false,
219
+ error: "Agent not available in remote registry",
220
+ code: "AGENT_NOT_FOUND",
221
+ });
222
+ });
223
+
224
+ const server = createAgentServer(registry, { port: PORT + 4 });
225
+ await server.start();
226
+
227
+ const result = await mcpCall(`http://localhost:${PORT + 4}`, "call_agent", {
228
+ action: "execute_tool",
229
+ path: "@nonexistent",
230
+ tool: "foo",
231
+ params: {},
232
+ });
233
+
234
+ expect(result.success).toBe(false);
235
+ expect(result.error).toBe("Agent not available in remote registry");
236
+ await server.stop();
237
+ });
238
+ });
239
+
240
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
241
+ // tools/call/list_agents tests
242
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
243
+
244
+ describe("tools/call/list_agents hook", () => {
245
+ const PORT = 19880;
246
+
247
+ test("next() with additional agents merges into listing", async () => {
248
+ const registry = createAgentRegistry({ defaultVisibility: "public" });
249
+ registry.register(echoAgent);
250
+
251
+ const remoteAgent = defineAgent({
252
+ path: "@remote-db",
253
+ entrypoint: "Remote database agent",
254
+ config: { name: "RemoteDB", description: "Query remote databases" },
255
+ visibility: "public" as const,
256
+ tools: [
257
+ defineTool({
258
+ name: "query",
259
+ description: "Run a SQL query",
260
+ inputSchema: { type: "object", properties: { sql: { type: "string" } } },
261
+ execute: async () => ({ rows: [] }),
262
+ }),
263
+ ],
264
+ });
265
+
266
+ registry.on("tools/call/list_agents", async (event) => {
267
+ await event.next([remoteAgent]);
268
+ });
269
+
270
+ const server = createAgentServer(registry, { port: PORT });
271
+ await server.start();
272
+
273
+ const result = await mcpCall(`http://localhost:${PORT}`, "list_agents", {});
274
+
275
+ expect(result.success).toBe(true);
276
+ const paths = result.agents.map((a: { path: string }) => a.path);
277
+ expect(paths).toContain("@echo");
278
+ expect(paths).toContain("@remote-db");
279
+ expect(result.total).toBe(2);
280
+ await server.stop();
281
+ });
282
+
283
+ test("injected agents appear in BM25 search results", async () => {
284
+ const registry = createAgentRegistry({ defaultVisibility: "public" });
285
+ registry.register(echoAgent);
286
+
287
+ const remoteAgent = defineAgent({
288
+ path: "@snowflake",
289
+ entrypoint: "Snowflake analytics",
290
+ config: { name: "Snowflake", description: "Analytics data warehouse queries" },
291
+ visibility: "public" as const,
292
+ tools: [
293
+ defineTool({
294
+ name: "run_query",
295
+ description: "Run an analytics query on Snowflake",
296
+ inputSchema: { type: "object", properties: { sql: { type: "string" } } },
297
+ execute: async () => ({ rows: [] }),
298
+ }),
299
+ ],
300
+ });
301
+
302
+ registry.on("tools/call/list_agents", async (event) => {
303
+ await event.next([remoteAgent]);
304
+ });
305
+
306
+ const server = createAgentServer(registry, { port: PORT + 1 });
307
+ await server.start();
308
+
309
+ const result = await mcpCall(`http://localhost:${PORT + 1}`, "list_agents", {
310
+ query: "analytics warehouse",
311
+ });
312
+
313
+ expect(result.success).toBe(true);
314
+ const paths = result.agents.map((a: { path: string }) => a.path);
315
+ expect(paths).toContain("@snowflake");
316
+ await server.stop();
317
+ });
318
+
319
+ test("resolve() fully replaces the response", async () => {
320
+ const registry = createAgentRegistry({ defaultVisibility: "public" });
321
+ registry.register(echoAgent);
322
+ registry.register(mathAgent);
323
+
324
+ registry.on("tools/call/list_agents", async (event) => {
325
+ event.resolve({
326
+ success: true,
327
+ total: 1,
328
+ agents: [
329
+ {
330
+ path: "@custom-only",
331
+ name: "Custom",
332
+ description: "Only this one",
333
+ tools: ["do_stuff"],
334
+ },
335
+ ],
336
+ });
337
+ });
338
+
339
+ const server = createAgentServer(registry, { port: PORT + 2 });
340
+ await server.start();
341
+
342
+ const result = await mcpCall(`http://localhost:${PORT + 2}`, "list_agents", {});
343
+
344
+ expect(result.success).toBe(true);
345
+ expect(result.agents.length).toBe(1);
346
+ expect(result.agents[0].path).toBe("@custom-only");
347
+ const paths = result.agents.map((a: { path: string }) => a.path);
348
+ expect(paths).not.toContain("@echo");
349
+ expect(paths).not.toContain("@math");
350
+ await server.stop();
351
+ });
352
+
353
+ test("no listener = default behavior unchanged", async () => {
354
+ const registry = createAgentRegistry({ defaultVisibility: "public" });
355
+ registry.register(echoAgent);
356
+ registry.register(mathAgent);
357
+
358
+ const server = createAgentServer(registry, { port: PORT + 3 });
359
+ await server.start();
360
+
361
+ const result = await mcpCall(`http://localhost:${PORT + 3}`, "list_agents", {});
362
+
363
+ expect(result.success).toBe(true);
364
+ expect(result.total).toBe(2);
365
+ const paths = result.agents.map((a: { path: string }) => a.path);
366
+ expect(paths).toContain("@echo");
367
+ expect(paths).toContain("@math");
368
+ await server.stop();
369
+ });
370
+
371
+ test("deduplicates by path — injected agent overrides local", async () => {
372
+ const registry = createAgentRegistry({ defaultVisibility: "public" });
373
+ registry.register(echoAgent);
374
+
375
+ const overrideEcho = defineAgent({
376
+ path: "@echo",
377
+ entrypoint: "Overridden echo",
378
+ config: { name: "Echo Override", description: "This replaced the original" },
379
+ visibility: "public" as const,
380
+ tools: [
381
+ defineTool({
382
+ name: "echo",
383
+ description: "Overridden echo tool",
384
+ inputSchema: { type: "object", properties: { message: { type: "string" } } },
385
+ execute: async () => ({ overridden: true }),
386
+ }),
387
+ ],
388
+ });
389
+
390
+ registry.on("tools/call/list_agents", async (event) => {
391
+ await event.next([overrideEcho]);
392
+ });
393
+
394
+ const server = createAgentServer(registry, { port: PORT + 4 });
395
+ await server.start();
396
+
397
+ const result = await mcpCall(`http://localhost:${PORT + 4}`, "list_agents", {});
398
+
399
+ expect(result.success).toBe(true);
400
+ expect(result.total).toBe(1);
401
+ expect(result.agents[0].description).toBe("This replaced the original");
402
+ await server.stop();
403
+ });
404
+
405
+ test("event carries query/limit/cursor params", async () => {
406
+ const registry = createAgentRegistry({ defaultVisibility: "public" });
407
+ registry.register(echoAgent);
408
+
409
+ let capturedEvent: {
410
+ query?: string;
411
+ limit?: number;
412
+ cursor?: string;
413
+ baseAgentCount: number;
414
+ } | null = null;
415
+
416
+ registry.on("tools/call/list_agents", async (event) => {
417
+ capturedEvent = {
418
+ query: event.query,
419
+ limit: event.limit,
420
+ cursor: event.cursor,
421
+ baseAgentCount: event.baseAgents.length,
422
+ };
423
+ });
424
+
425
+ const server = createAgentServer(registry, { port: PORT + 5 });
426
+ await server.start();
427
+
428
+ await mcpCall(`http://localhost:${PORT + 5}`, "list_agents", {
429
+ query: "echo",
430
+ limit: 5,
431
+ });
432
+
433
+ expect(capturedEvent).not.toBeNull();
434
+ expect(capturedEvent!.query).toBe("echo");
435
+ expect(capturedEvent!.limit).toBe(5);
436
+ expect(capturedEvent!.baseAgentCount).toBe(1);
437
+ await server.stop();
438
+ });
439
+ });
package/src/index.ts CHANGED
@@ -135,7 +135,9 @@ export type {
135
135
  ToolErrorEvent,
136
136
  StepEvent,
137
137
  InvokeEvent,
138
- CallEvent,
138
+ CallAgentToolCallEvent,
139
+ ListAgentsToolCallEvent,
140
+ ListAgentsResult,
139
141
  EventMap,
140
142
  SystemEventMap,
141
143
  ListenerEntry,
@@ -902,13 +902,20 @@ export async function createRegistryConsumer(
902
902
  action: "describe_tools",
903
903
  path: agentPath,
904
904
  tools: undefined,
905
- })) as { tools?: unknown[]; description?: string } | null;
905
+ })) as {
906
+ tools?: unknown[];
907
+ description?: string;
908
+ security?: SecuritySchemeSummary;
909
+ resources?: Array<{ uri: string; name?: string; mimeType?: string }>;
910
+ } | null;
906
911
  if (!data) return null;
907
912
  return {
908
913
  path: agentPath,
909
914
  publisher: registry.publisher,
910
915
  tools: data.tools,
911
916
  description: data.description,
917
+ security: data.security,
918
+ resources: data.resources,
912
919
  } as AgentListing;
913
920
  }),
914
921
  );