@slashfi/agents-sdk 0.25.0 → 0.25.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/src/server.ts CHANGED
@@ -4,7 +4,7 @@
4
4
  * Minimal JSON-RPC server implementing the MCP protocol for agent interaction.
5
5
  * Handles only core SDK concerns:
6
6
  * - MCP protocol (initialize, tools/list, tools/call)
7
- * - Agent registry routing (call_agent, list_agents)
7
+ * - Agent registry routing (call_agent, list_agents, search_agent_tools)
8
8
  * - Auth resolution (Bearer tokens, root key, JWT)
9
9
  * - OAuth2 token exchange (client_credentials)
10
10
  * - Health check
@@ -30,6 +30,7 @@ import {
30
30
  type SecretStore,
31
31
  processSecretParams,
32
32
  } from "./agent-definitions/secrets.js";
33
+ import { type BM25Document, createBM25Index } from "./bm25.js";
33
34
  import { verifyJwt } from "./jwt.js";
34
35
  import type { SigningKey } from "./jwt.js";
35
36
  import {
@@ -442,6 +443,32 @@ function getToolDefinitions() {
442
443
  properties: {},
443
444
  },
444
445
  },
446
+ {
447
+ name: "search_agent_tools",
448
+ description:
449
+ "Search across all registered agent tools using natural language. Returns tools ranked by relevance using BM25 scoring.",
450
+ inputSchema: {
451
+ type: "object",
452
+ properties: {
453
+ query: {
454
+ type: "string",
455
+ description:
456
+ "Natural language search query (e.g. 'send a message', 'database query')",
457
+ },
458
+ agents: {
459
+ type: "array",
460
+ items: { type: "string" },
461
+ description:
462
+ "Optional list of agent paths to search within (e.g. ['@notifications', '@db']). Searches all agents if omitted.",
463
+ },
464
+ limit: {
465
+ type: "number",
466
+ description: "Maximum number of results to return (default: 10)",
467
+ },
468
+ },
469
+ required: ["query"],
470
+ },
471
+ },
445
472
  ];
446
473
  }
447
474
 
@@ -609,6 +636,104 @@ export function createAgentServer(
609
636
  });
610
637
  }
611
638
 
639
+ case "search_agent_tools": {
640
+ const { query, agents: agentFilter, limit: resultLimit } = args as {
641
+ query: string;
642
+ agents?: string[];
643
+ limit?: number;
644
+ };
645
+
646
+ const agents = registry.list();
647
+ const visible = agents.filter((agent) => {
648
+ if (!canSeeAgent(agent, auth)) return false;
649
+ if (agentFilter && agentFilter.length > 0) {
650
+ return agentFilter.includes(agent.path);
651
+ }
652
+ return true;
653
+ });
654
+
655
+ // Build search documents from all visible tools
656
+ const documents: (BM25Document & {
657
+ agentPath: string;
658
+ toolName: string;
659
+ description: string;
660
+ agentName?: string;
661
+ agentDescription?: string;
662
+ })[] = [];
663
+
664
+ for (const agent of visible) {
665
+ const visibleTools = agent.tools.filter((t) => {
666
+ const tv = t.visibility ?? "internal";
667
+ if (auth?.isRoot) return true;
668
+ if (tv === "public") return true;
669
+ if (
670
+ tv === "authenticated" &&
671
+ auth?.callerId &&
672
+ auth.callerId !== "anonymous"
673
+ )
674
+ return true;
675
+ if (tv === "internal" && auth) return true;
676
+ return false;
677
+ });
678
+
679
+ for (const tool of visibleTools) {
680
+ // Build searchable text from tool name, description, agent context, and schema
681
+ const parts = [
682
+ tool.name,
683
+ tool.description,
684
+ agent.config?.name ?? "",
685
+ agent.config?.description ?? "",
686
+ agent.path,
687
+ ];
688
+
689
+ // Include property names and descriptions from input schema
690
+ const schema = tool.inputSchema as any;
691
+ if (schema?.properties) {
692
+ for (const [key, prop] of Object.entries(schema.properties)) {
693
+ parts.push(key);
694
+ if ((prop as any)?.description) {
695
+ parts.push((prop as any).description);
696
+ }
697
+ }
698
+ }
699
+
700
+ documents.push({
701
+ id: `${agent.path}/${tool.name}`,
702
+ text: parts.join(" "),
703
+ agentPath: agent.path,
704
+ toolName: tool.name,
705
+ description: tool.description,
706
+ agentName: agent.config?.name,
707
+ agentDescription: agent.config?.description,
708
+ });
709
+ }
710
+ }
711
+
712
+ const index = createBM25Index(documents);
713
+ const results = index.search(query, resultLimit ?? 10);
714
+
715
+ // Map results back to tool details
716
+ const docMap = new Map(documents.map((d) => [d.id, d]));
717
+ const matches = results.map((r) => {
718
+ const doc = docMap.get(r.id)!;
719
+ return {
720
+ agentPath: doc.agentPath,
721
+ tool: doc.toolName,
722
+ description: doc.description,
723
+ agentName: doc.agentName,
724
+ agentDescription: doc.agentDescription,
725
+ score: r.score,
726
+ };
727
+ });
728
+
729
+ return mcpResult({
730
+ success: true,
731
+ query,
732
+ results: matches,
733
+ total: matches.length,
734
+ });
735
+ }
736
+
612
737
  default:
613
738
  throw new Error(`Unknown tool: ${toolName}`);
614
739
  }