@slashfi/agents-sdk 0.34.0 → 0.35.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.
Files changed (91) hide show
  1. package/README.md +2 -1
  2. package/dist/agent-definitions/auth.d.ts +3 -3
  3. package/dist/agent-definitions/auth.d.ts.map +1 -1
  4. package/dist/agent-definitions/auth.js +10 -4
  5. package/dist/agent-definitions/auth.js.map +1 -1
  6. package/dist/agent-definitions/config.d.ts.map +1 -1
  7. package/dist/agent-definitions/config.js.map +1 -1
  8. package/dist/agent-definitions/integrations.d.ts +12 -3
  9. package/dist/agent-definitions/integrations.d.ts.map +1 -1
  10. package/dist/agent-definitions/integrations.js +35 -16
  11. package/dist/agent-definitions/integrations.js.map +1 -1
  12. package/dist/agent-definitions/remote-registry.d.ts.map +1 -1
  13. package/dist/agent-definitions/remote-registry.js +17 -22
  14. package/dist/agent-definitions/remote-registry.js.map +1 -1
  15. package/dist/agent-definitions/users.d.ts.map +1 -1
  16. package/dist/agent-definitions/users.js.map +1 -1
  17. package/dist/auth-governance.js.map +1 -1
  18. package/dist/call-agent-schema.d.ts +128 -135
  19. package/dist/call-agent-schema.d.ts.map +1 -1
  20. package/dist/call-agent-schema.js +35 -5
  21. package/dist/call-agent-schema.js.map +1 -1
  22. package/dist/cjs/agent-definitions/auth.js +10 -4
  23. package/dist/cjs/agent-definitions/auth.js.map +1 -1
  24. package/dist/cjs/agent-definitions/config.js.map +1 -1
  25. package/dist/cjs/agent-definitions/integrations.js +35 -16
  26. package/dist/cjs/agent-definitions/integrations.js.map +1 -1
  27. package/dist/cjs/agent-definitions/remote-registry.js +17 -22
  28. package/dist/cjs/agent-definitions/remote-registry.js.map +1 -1
  29. package/dist/cjs/agent-definitions/users.js.map +1 -1
  30. package/dist/cjs/auth-governance.js.map +1 -1
  31. package/dist/cjs/call-agent-schema.js +35 -5
  32. package/dist/cjs/call-agent-schema.js.map +1 -1
  33. package/dist/cjs/define.js.map +1 -1
  34. package/dist/cjs/index.js +6 -2
  35. package/dist/cjs/index.js.map +1 -1
  36. package/dist/cjs/key-manager.js.map +1 -1
  37. package/dist/cjs/registry-consumer.js +60 -15
  38. package/dist/cjs/registry-consumer.js.map +1 -1
  39. package/dist/cjs/registry.js +3 -1
  40. package/dist/cjs/registry.js.map +1 -1
  41. package/dist/cjs/server.js +70 -121
  42. package/dist/cjs/server.js.map +1 -1
  43. package/dist/cjs/types.js +13 -0
  44. package/dist/cjs/types.js.map +1 -1
  45. package/dist/cjs/validate.js +2 -2
  46. package/dist/cjs/validate.js.map +1 -1
  47. package/dist/define.d.ts.map +1 -1
  48. package/dist/define.js.map +1 -1
  49. package/dist/index.d.ts +2 -1
  50. package/dist/index.d.ts.map +1 -1
  51. package/dist/index.js +1 -0
  52. package/dist/index.js.map +1 -1
  53. package/dist/key-manager.d.ts.map +1 -1
  54. package/dist/key-manager.js +1 -1
  55. package/dist/key-manager.js.map +1 -1
  56. package/dist/registry-consumer.d.ts +8 -8
  57. package/dist/registry-consumer.d.ts.map +1 -1
  58. package/dist/registry-consumer.js +60 -15
  59. package/dist/registry-consumer.js.map +1 -1
  60. package/dist/registry.d.ts.map +1 -1
  61. package/dist/registry.js +3 -1
  62. package/dist/registry.js.map +1 -1
  63. package/dist/server.d.ts +1 -1
  64. package/dist/server.d.ts.map +1 -1
  65. package/dist/server.js +63 -114
  66. package/dist/server.js.map +1 -1
  67. package/dist/types.d.ts +38 -0
  68. package/dist/types.d.ts.map +1 -1
  69. package/dist/types.js +10 -1
  70. package/dist/types.js.map +1 -1
  71. package/dist/validate.d.ts +15 -15
  72. package/dist/validate.js +2 -2
  73. package/dist/validate.js.map +1 -1
  74. package/package.json +1 -1
  75. package/src/agent-definitions/auth.ts +31 -14
  76. package/src/agent-definitions/config.ts +4 -4
  77. package/src/agent-definitions/integrations.ts +119 -63
  78. package/src/agent-definitions/remote-registry.ts +65 -38
  79. package/src/agent-definitions/users.ts +36 -3
  80. package/src/auth-governance.ts +2 -2
  81. package/src/call-agent-schema.test.ts +4 -1
  82. package/src/call-agent-schema.ts +39 -5
  83. package/src/consumer.test.ts +4 -1
  84. package/src/define.ts +18 -12
  85. package/src/index.ts +11 -0
  86. package/src/key-manager.ts +9 -2
  87. package/src/registry-consumer.ts +85 -24
  88. package/src/registry.ts +3 -1
  89. package/src/server.ts +122 -153
  90. package/src/types.ts +62 -0
  91. package/src/validate.ts +2 -2
@@ -28,7 +28,23 @@ import {
28
28
  generateCollectionToken,
29
29
  pendingCollections,
30
30
  } from "../secret-collection.js";
31
- import type { AgentDefinition, ToolContext, ToolDefinition } from "../types.js";
31
+ import type {
32
+ AgentDefinition,
33
+ CallAgentRequest,
34
+ CallAgentResponse,
35
+ JsonSchema,
36
+ ToolContext,
37
+ ToolDefinition,
38
+ } from "../types.js";
39
+
40
+ /** Unwrap `execute_tool` payload from a registry response. */
41
+ function executeToolResult(
42
+ r: CallAgentResponse | undefined,
43
+ ): unknown | undefined {
44
+ if (!r || r.success === false) return undefined;
45
+ if ("result" in r) return r.result;
46
+ return undefined;
47
+ }
32
48
 
33
49
  // ============================================
34
50
  // OAuth Config Types
@@ -73,6 +89,9 @@ export interface IntegrationOAuthConfig {
73
89
  refreshGrantType?: string;
74
90
  refreshBodyParams?: string[];
75
91
  refreshHeaders?: Record<string, string>;
92
+
93
+ /** OAuth client id (plain string or secret: ref) */
94
+ clientId?: string;
76
95
  }
77
96
 
78
97
  // ============================================
@@ -106,7 +125,14 @@ export interface ProviderConfig {
106
125
  * Agent path that handles this integration type.
107
126
  * @integrations dispatches setup/connect/call to that agent's integrationMethods.
108
127
  */
109
- agentPath: string;
128
+ agentPath?: string;
129
+ /**
130
+ * @internal Secret store ids for credentials encrypted by @integrations.
131
+ */
132
+ _clientIdSecretId?: string;
133
+ _clientSecretSecretId?: string;
134
+ /** Client id as plain string or secret: ref (when not using _clientIdSecretId) */
135
+ clientId?: string;
110
136
  /**
111
137
  * Scope of the integration:
112
138
  * - 'user': per-user tokens (Slack, Notion, Linear)
@@ -515,7 +541,7 @@ export interface IntegrationsAgentOptions {
515
541
  /** Registry instance for calling other agents' internal tools */
516
542
  registry?: {
517
543
  list?(): AgentDefinition[];
518
- call(request: any): Promise<any>;
544
+ call(request: CallAgentRequest): Promise<CallAgentResponse>;
519
545
  };
520
546
 
521
547
  /** Secret store for storing/resolving client credentials and tokens */
@@ -668,29 +694,32 @@ export function createIntegrationsAgent(
668
694
  },
669
695
  required: ["id", "name", "type", "api"],
670
696
  },
671
- execute: async (input: any, _ctx: ToolContext) => {
697
+ execute: async (input: Record<string, unknown>, _ctx: ToolContext) => {
672
698
  const config: ProviderConfig = {
673
- id: input.id,
674
- name: input.name,
675
- agentPath: input.agentPath,
676
- scope: input.scope,
677
- docs: input.docs,
678
- auth: input.auth,
679
- api: input.api,
699
+ id: input.id as string,
700
+ name: input.name as string,
701
+ agentPath: input.agentPath as string | undefined,
702
+ scope: input.scope as "user" | "tenant" | undefined,
703
+ docs: input.docs as ProviderConfig["docs"],
704
+ auth: input.auth as ProviderConfig["auth"],
705
+ api: input.api as ProviderConfig["api"],
680
706
  };
681
707
  // Store client credentials encrypted and save secret IDs
682
708
  const result: Record<string, unknown> = { success: true };
683
709
  if (input.clientId) {
684
- const secretId = await secretStore.store(input.clientId, SYSTEM_OWNER);
685
- (config as any)._clientIdSecretId = secretId;
710
+ const secretId = await secretStore.store(
711
+ input.clientId as string,
712
+ SYSTEM_OWNER,
713
+ );
714
+ config._clientIdSecretId = secretId;
686
715
  result.clientIdStored = true;
687
716
  }
688
717
  if (input.clientSecret) {
689
718
  const secretId = await secretStore.store(
690
- input.clientSecret,
719
+ input.clientSecret as string,
691
720
  SYSTEM_OWNER,
692
721
  );
693
- (config as any)._clientSecretSecretId = secretId;
722
+ config._clientSecretSecretId = secretId;
694
723
  result.clientSecretStored = true;
695
724
  }
696
725
 
@@ -703,10 +732,11 @@ export function createIntegrationsAgent(
703
732
  action: "execute_tool",
704
733
  path: config.agentPath,
705
734
  tool: "setup_integration",
706
- params: input.config ?? input,
735
+ params: (input.config ?? input) as Record<string, unknown>,
707
736
  callerType: "system",
708
737
  });
709
- result.setupResult = (setupResult as any)?.result ?? setupResult;
738
+ result.setupResult =
739
+ executeToolResult(setupResult) ?? setupResult;
710
740
  } catch (err) {
711
741
  result.setupError = err instanceof Error ? err.message : String(err);
712
742
  }
@@ -857,7 +887,7 @@ export function createIntegrationsAgent(
857
887
  const agents = options.registry.list?.() ?? [];
858
888
  for (const agent of agents) {
859
889
  const hasListTool = agent.tools?.some(
860
- (t: any) => t.name === "list_integrations",
890
+ (t: ToolDefinition) => t.name === "list_integrations",
861
891
  );
862
892
  if (hasListTool && agent.config?.integration) {
863
893
  const meta = {
@@ -878,9 +908,15 @@ export function createIntegrationsAgent(
878
908
  callerType: "system",
879
909
  })
880
910
  : null;
881
- const result = (callResult as any)?.result ??
882
- callResult ?? { success: false };
883
- if (result.success && result.data) {
911
+ const raw =
912
+ executeToolResult(callResult ?? undefined) ??
913
+ callResult ??
914
+ { success: false };
915
+ const result = raw as {
916
+ success?: boolean;
917
+ data?: unknown;
918
+ };
919
+ if (result.success && result.data != null) {
884
920
  // Flatten: if data has an array field, each item becomes an integration
885
921
  const items = Array.isArray(result.data)
886
922
  ? result.data
@@ -982,7 +1018,7 @@ export function createIntegrationsAgent(
982
1018
  params: { ...input, registryId: config.id },
983
1019
  callerType: "system",
984
1020
  });
985
- return (connectResult as any)?.result ?? connectResult;
1021
+ return executeToolResult(connectResult) ?? connectResult;
986
1022
  }
987
1023
 
988
1024
  if (!config.auth)
@@ -998,26 +1034,26 @@ export function createIntegrationsAgent(
998
1034
  // Check both _clientIdSecretId (from setup_integration direct) and
999
1035
  // clientId field as secret:ref (from collect_secrets flow)
1000
1036
  let clientId: string | null = null;
1001
- const cidSecretId = (config as any)._clientIdSecretId;
1037
+ const cidSecretId = config._clientIdSecretId;
1002
1038
  if (cidSecretId && secretStore) {
1003
1039
  clientId = await secretStore.resolve(cidSecretId, SYSTEM_OWNER);
1004
1040
  }
1005
1041
  // Also check if auth config has clientId as a secret:ref
1006
1042
  if (
1007
1043
  !clientId &&
1008
- (oauth as any).clientId &&
1009
- typeof (oauth as any).clientId === "string"
1044
+ oauth.clientId &&
1045
+ typeof oauth.clientId === "string"
1010
1046
  ) {
1011
- if ((oauth as any).clientId.startsWith("secret:") && secretStore) {
1012
- const refId = (oauth as any).clientId.slice("secret:".length);
1047
+ if (oauth.clientId.startsWith("secret:") && secretStore) {
1048
+ const refId = oauth.clientId.slice("secret:".length);
1013
1049
  clientId = await secretStore.resolve(refId, SYSTEM_OWNER);
1014
- } else if (!(oauth as any).clientId.startsWith("secret:")) {
1015
- clientId = (oauth as any).clientId;
1050
+ } else if (!oauth.clientId.startsWith("secret:")) {
1051
+ clientId = oauth.clientId;
1016
1052
  }
1017
1053
  }
1018
1054
  // Check top-level config too
1019
- if (!clientId && (config as any).clientId) {
1020
- const cid = (config as any).clientId;
1055
+ if (!clientId && config.clientId) {
1056
+ const cid = config.clientId;
1021
1057
  if (
1022
1058
  typeof cid === "string" &&
1023
1059
  cid.startsWith("secret:") &&
@@ -1112,14 +1148,17 @@ export function createIntegrationsAgent(
1112
1148
  },
1113
1149
  required: ["provider", "type"],
1114
1150
  },
1115
- execute: async (input: any, ctx: ToolContext) => {
1116
- const config = await store.getProvider(input.provider);
1151
+ execute: async (input: Record<string, unknown>, ctx: ToolContext) => {
1152
+ const config = await store.getProvider(input.provider as string);
1117
1153
  if (!config) return { error: `Provider '${input.provider}' not found` };
1118
1154
 
1119
1155
  const userId = ctx.callerId;
1120
1156
 
1121
1157
  // Get access token
1122
- const connection = await store.getConnection(userId, input.provider);
1158
+ const connection = await store.getConnection(
1159
+ userId,
1160
+ input.provider as string,
1161
+ );
1123
1162
  if (!connection) {
1124
1163
  return {
1125
1164
  error: `Not connected to '${input.provider}'. Use connect_integration first.`,
@@ -1135,8 +1174,8 @@ export function createIntegrationsAgent(
1135
1174
  connection.refreshToken
1136
1175
  ) {
1137
1176
  try {
1138
- const rCidId = (config as any)._clientIdSecretId;
1139
- const rCsecId = (config as any)._clientSecretSecretId;
1177
+ const rCidId = config._clientIdSecretId;
1178
+ const rCsecId = config._clientSecretSecretId;
1140
1179
  if (!rCidId || !rCsecId) {
1141
1180
  throw new Error(
1142
1181
  "No client credentials stored. Re-run setup_integration with clientId/clientSecret.",
@@ -1181,12 +1220,12 @@ export function createIntegrationsAgent(
1181
1220
  return executeRestCall(
1182
1221
  config,
1183
1222
  {
1184
- provider: input.provider,
1223
+ provider: input.provider as string,
1185
1224
  type: "rest",
1186
- method: input.method ?? "GET",
1187
- path: input.path ?? "/",
1188
- body: input.body,
1189
- query: input.query,
1225
+ method: (input.method as RestCallInput["method"]) ?? "GET",
1226
+ path: (input.path as string) ?? "/",
1227
+ body: input.body as Record<string, unknown> | undefined,
1228
+ query: input.query as Record<string, string> | undefined,
1190
1229
  },
1191
1230
  accessToken,
1192
1231
  );
@@ -1195,10 +1234,12 @@ export function createIntegrationsAgent(
1195
1234
  return executeGraphqlCall(
1196
1235
  config,
1197
1236
  {
1198
- provider: input.provider,
1237
+ provider: input.provider as string,
1199
1238
  type: "graphql",
1200
- query: input.graphqlQuery ?? input.query ?? "",
1201
- variables: input.variables,
1239
+ query: String(input.graphqlQuery ?? ""),
1240
+ variables: input.variables as
1241
+ | Record<string, unknown>
1242
+ | undefined,
1202
1243
  },
1203
1244
  accessToken,
1204
1245
  );
@@ -1249,7 +1290,7 @@ export function createIntegrationsAgent(
1249
1290
  params: { ...input, registryId: config.id },
1250
1291
  callerType: "system",
1251
1292
  });
1252
- return (connectResult as any)?.result ?? connectResult;
1293
+ return executeToolResult(connectResult) ?? connectResult;
1253
1294
  }
1254
1295
 
1255
1296
  if (!config.auth)
@@ -1266,8 +1307,8 @@ export function createIntegrationsAgent(
1266
1307
  }
1267
1308
 
1268
1309
  // Resolve client credentials from secret store via config
1269
- const cbCidId = (config as any)._clientIdSecretId;
1270
- const cbCsecId = (config as any)._clientSecretSecretId;
1310
+ const cbCidId = config._clientIdSecretId;
1311
+ const cbCsecId = config._clientSecretSecretId;
1271
1312
  if (!cbCidId || !cbCsecId) {
1272
1313
  return { error: "No client credentials stored for this provider." };
1273
1314
  }
@@ -1390,7 +1431,7 @@ export function createIntegrationsAgent(
1390
1431
  // Fetch tool schema from registry
1391
1432
  let toolSchema: {
1392
1433
  name: string;
1393
- inputSchema?: any;
1434
+ inputSchema?: JsonSchema;
1394
1435
  description?: string;
1395
1436
  } | null = null;
1396
1437
  const registryUrl = input.registry;
@@ -1414,10 +1455,14 @@ export function createIntegrationsAgent(
1414
1455
  },
1415
1456
  }),
1416
1457
  });
1417
- const data = (await res.json()) as any;
1418
- const parsed = JSON.parse(data?.result?.content?.[0]?.text ?? "{}");
1458
+ const data = (await res.json()) as Record<string, unknown>;
1459
+ const resultBlock = data.result as
1460
+ | { content?: Array<{ text?: string }> }
1461
+ | undefined;
1462
+ const parsed = JSON.parse(resultBlock?.content?.[0]?.text ?? "{}");
1419
1463
  const tools = parsed?.tools ?? parsed?.result?.tools ?? [];
1420
- toolSchema = tools.find((t: any) => t.name === input.tool) ?? null;
1464
+ toolSchema =
1465
+ tools.find((t: { name: string }) => t.name === input.tool) ?? null;
1421
1466
 
1422
1467
  if (!toolSchema?.inputSchema) {
1423
1468
  return { error: `Tool '${input.tool}' not found on '${input.agent}'` };
@@ -1437,15 +1482,24 @@ export function createIntegrationsAgent(
1437
1482
  required: boolean;
1438
1483
  }> = [];
1439
1484
 
1440
- for (const [name, def] of Object.entries(properties) as [string, any][]) {
1485
+ for (const [name, def] of Object.entries(properties) as [
1486
+ string,
1487
+ Record<string, unknown>,
1488
+ ][]) {
1441
1489
  const isSecret = def.secret === true;
1442
1490
  const isRequired = requiredFields.has(name);
1443
1491
  const isProvided = name in providedParams;
1444
1492
  if (isSecret || (isRequired && !isProvided)) {
1445
1493
  fields.push({
1446
1494
  name,
1447
- type: def.type ?? "string",
1448
- description: def.description ?? name,
1495
+ type:
1496
+ typeof def.type === "string"
1497
+ ? def.type
1498
+ : Array.isArray(def.type)
1499
+ ? def.type.join("|")
1500
+ : "string",
1501
+ description:
1502
+ typeof def.description === "string" ? def.description : name,
1449
1503
  secret: isSecret,
1450
1504
  required: isRequired,
1451
1505
  });
@@ -1502,11 +1556,11 @@ export function createIntegrationsAgent(
1502
1556
  inputSchema: { type: "object" as const, properties: {} },
1503
1557
  execute: async () => {
1504
1558
  const agents = options.registry?.list?.() ?? [];
1505
- const results: any[] = [];
1559
+ const results: unknown[] = [];
1506
1560
  if (options.registry) {
1507
1561
  for (const agent of agents) {
1508
1562
  const hasDiscoverTool = agent.tools?.some(
1509
- (t: any) => t.name === "discover_integrations",
1563
+ (t: ToolDefinition) => t.name === "discover_integrations",
1510
1564
  );
1511
1565
  if (hasDiscoverTool) {
1512
1566
  try {
@@ -1518,8 +1572,9 @@ export function createIntegrationsAgent(
1518
1572
  callerId: "@integrations",
1519
1573
  callerType: "system",
1520
1574
  });
1521
- if (res?.result && Array.isArray(res.result)) {
1522
- results.push(...res.result);
1575
+ const payload = executeToolResult(res);
1576
+ if (payload && Array.isArray(payload)) {
1577
+ results.push(...payload);
1523
1578
  }
1524
1579
  } catch {}
1525
1580
  }
@@ -1542,14 +1597,14 @@ export function createIntegrationsAgent(
1542
1597
  },
1543
1598
  execute: async (input: { agent_path?: string }) => {
1544
1599
  const agents = options.registry?.list?.() ?? [];
1545
- const results: any[] = [];
1600
+ const results: unknown[] = [];
1546
1601
  if (options.registry) {
1547
1602
  const targetAgents = input.agent_path
1548
- ? agents.filter((a: any) => a.path === input.agent_path)
1603
+ ? agents.filter((a: AgentDefinition) => a.path === input.agent_path)
1549
1604
  : agents;
1550
1605
  for (const agent of targetAgents) {
1551
1606
  const hasListTool = agent.tools?.some(
1552
- (t: any) => t.name === "list_integrations",
1607
+ (t: ToolDefinition) => t.name === "list_integrations",
1553
1608
  );
1554
1609
  if (hasListTool) {
1555
1610
  try {
@@ -1561,8 +1616,9 @@ export function createIntegrationsAgent(
1561
1616
  callerId: "@integrations",
1562
1617
  callerType: "system",
1563
1618
  });
1564
- if (res?.result && Array.isArray(res.result)) {
1565
- results.push(...res.result);
1619
+ const payload = executeToolResult(res);
1620
+ if (payload && Array.isArray(payload)) {
1621
+ results.push(...payload);
1566
1622
  }
1567
1623
  } catch {}
1568
1624
  }
@@ -27,9 +27,9 @@
27
27
  import { defineAgent, defineTool } from "../define.js";
28
28
  import type {
29
29
  AgentDefinition,
30
- IntegrationMethodContext,
31
30
  IntegrationMethodResult,
32
31
  ToolContext,
32
+ ToolDefinition,
33
33
  } from "../types.js";
34
34
  import type { SecretStore } from "./secrets.js";
35
35
 
@@ -53,6 +53,39 @@ interface RegistryConnection {
53
53
 
54
54
  const ENTITY_TYPE = "remote-registry-connections";
55
55
 
56
+ /** JSON-RPC response for MCP `tools/call` over HTTP. */
57
+ interface McpToolsCallRpcBody {
58
+ result?: {
59
+ content?: Array<{ type: string; text?: string }>;
60
+ };
61
+ error?: { message: string };
62
+ }
63
+
64
+ interface ProxyCallToolInput {
65
+ registryId: string;
66
+ action: string;
67
+ path: string;
68
+ tool: string;
69
+ params?: Record<string, unknown>;
70
+ }
71
+
72
+ interface AddConnectionToolInput {
73
+ id: string;
74
+ name?: string;
75
+ url: string;
76
+ remoteTenantId?: string;
77
+ }
78
+
79
+ /** Typical fields from POST /oauth/token JSON body. */
80
+ interface OAuthTokenJsonBody {
81
+ access_token?: string;
82
+ tenant_id?: string;
83
+ user_id?: string;
84
+ error?: string;
85
+ error_description?: string;
86
+ authorize_url?: string;
87
+ }
88
+
56
89
  export function createRemoteRegistryAgent(
57
90
  options: RemoteRegistryAgentOptions,
58
91
  ): AgentDefinition {
@@ -122,7 +155,7 @@ export function createRemoteRegistryAgent(
122
155
  url: string,
123
156
  jwt: string,
124
157
  request: Record<string, unknown>,
125
- ): Promise<any> {
158
+ ): Promise<unknown> {
126
159
  const res = await globalThis.fetch(url, {
127
160
  method: "POST",
128
161
  headers: {
@@ -136,7 +169,7 @@ export function createRemoteRegistryAgent(
136
169
  params: { name: "call_agent", arguments: { request } },
137
170
  }),
138
171
  });
139
- const rpc = (await res.json()) as any;
172
+ const rpc = (await res.json()) as McpToolsCallRpcBody;
140
173
  const text = rpc.result?.content?.[0]?.text;
141
174
  if (!text) return rpc.result;
142
175
  const parsed = JSON.parse(text);
@@ -167,7 +200,7 @@ export function createRemoteRegistryAgent(
167
200
  tool: string;
168
201
  params?: Record<string, unknown>;
169
202
  },
170
- ): Promise<any> {
203
+ ): Promise<unknown> {
171
204
  const conn = await loadConnection(ownerId, registryId);
172
205
  if (!conn) {
173
206
  throw new Error(
@@ -202,7 +235,7 @@ export function createRemoteRegistryAgent(
202
235
  },
203
236
  required: ["registryId", "action", "path", "tool"],
204
237
  },
205
- execute: async (input: any, _ctx: ToolContext) => {
238
+ execute: async (input: ProxyCallToolInput, _ctx: ToolContext) => {
206
239
  return proxyCall("system", input.registryId, {
207
240
  action: input.action,
208
241
  path: input.path,
@@ -230,7 +263,7 @@ export function createRemoteRegistryAgent(
230
263
  },
231
264
  required: ["id", "url"],
232
265
  },
233
- execute: async (input: any, _ctx: ToolContext) => {
266
+ execute: async (input: AddConnectionToolInput, _ctx: ToolContext) => {
234
267
  const conn: RegistryConnection = {
235
268
  id: input.id,
236
269
  name: input.name ?? input.id,
@@ -248,7 +281,7 @@ export function createRemoteRegistryAgent(
248
281
  description: "List all connected remote registries.",
249
282
  visibility: "public" as const,
250
283
  inputSchema: { type: "object" as const, properties: {} },
251
- execute: async (_input: any, _ctx: ToolContext) => {
284
+ execute: async (_input: Record<string, unknown>, _ctx: ToolContext) => {
252
285
  const all = await loadAllConnections("system");
253
286
  return {
254
287
  connections: Object.values(all).map((c) => ({
@@ -264,7 +297,7 @@ export function createRemoteRegistryAgent(
264
297
  // Extract setup/connect as standalone functions to avoid circular reference
265
298
  const setupFn = async (
266
299
  params: Record<string, unknown>,
267
- _ctx: IntegrationMethodContext,
300
+ _ctx: ToolContext,
268
301
  ): Promise<IntegrationMethodResult> => {
269
302
  console.log(
270
303
  "[remote-registry] setupFn called with:",
@@ -294,7 +327,7 @@ export function createRemoteRegistryAgent(
294
327
  redirect_uri: params.redirect_uri ?? "",
295
328
  }),
296
329
  });
297
- const tokenData = (await tokenRes.json()) as any;
330
+ const tokenData = (await tokenRes.json()) as OAuthTokenJsonBody;
298
331
  if (!tokenData.access_token && !tokenData.tenant_id) {
299
332
  return {
300
333
  success: false,
@@ -319,23 +352,16 @@ export function createRemoteRegistryAgent(
319
352
  };
320
353
  }
321
354
 
322
- // Phase 1: Discover JWKS, establish trust, then request OIDC
323
- const configUrl = `${baseUrl}/.well-known/configuration`;
324
- console.log("[setupFn] fetching config:", configUrl);
325
- const configRes = await globalThis.fetch(configUrl);
326
- console.log("[setupFn] config status:", configRes.status);
327
- if (!configRes.ok)
355
+ // Phase 1: Verify JWKS at origin, establish trust, then request OIDC
356
+ const jwksUri = `${new URL(baseUrl).origin}/.well-known/jwks.json`;
357
+ console.log("[setupFn] fetching JWKS:", jwksUri);
358
+ const jwksRes = await globalThis.fetch(jwksUri);
359
+ console.log("[setupFn] JWKS status:", jwksRes.status);
360
+ if (!jwksRes.ok)
328
361
  return {
329
362
  success: false,
330
- error: `Failed to discover registry at ${configUrl}`,
363
+ error: `JWKS not reachable at ${jwksUri}`,
331
364
  };
332
- const remoteConfig = (await configRes.json()) as any;
333
- if (remoteConfig.jwks_uri) {
334
- console.log("[setupFn] fetching JWKS:", remoteConfig.jwks_uri);
335
- const jwksRes = await globalThis.fetch(remoteConfig.jwks_uri);
336
- console.log("[setupFn] JWKS status:", jwksRes.status);
337
- if (!jwksRes.ok) return { success: false, error: "JWKS not reachable" };
338
- }
339
365
  if (addTrustedIssuer) {
340
366
  console.log("[setupFn] adding trusted issuer:", baseUrl);
341
367
  await addTrustedIssuer(baseUrl);
@@ -361,7 +387,7 @@ export function createRemoteRegistryAgent(
361
387
  }),
362
388
  });
363
389
  console.log("[setupFn] token status:", tokenRes.status);
364
- const tokenData = (await tokenRes.json()) as any;
390
+ const tokenData = (await tokenRes.json()) as OAuthTokenJsonBody;
365
391
  console.log(
366
392
  "[setupFn] tokenData:",
367
393
  JSON.stringify(tokenData).substring(0, 300),
@@ -414,7 +440,7 @@ export function createRemoteRegistryAgent(
414
440
 
415
441
  const connectFn = async (
416
442
  params: Record<string, unknown>,
417
- ctx: IntegrationMethodContext,
443
+ ctx: ToolContext,
418
444
  ): Promise<IntegrationMethodResult> => {
419
445
  const registryId = params.registryId as string;
420
446
  const redirectUri = (params.redirectUri as string) ?? "";
@@ -443,7 +469,7 @@ export function createRemoteRegistryAgent(
443
469
  redirect_uri: redirectUri,
444
470
  }),
445
471
  });
446
- const tokenData = (await tokenRes.json()) as any;
472
+ const tokenData = (await tokenRes.json()) as OAuthTokenJsonBody;
447
473
  if (tokenData.access_token)
448
474
  return {
449
475
  success: true,
@@ -498,27 +524,28 @@ export function createRemoteRegistryAgent(
498
524
  category: "infrastructure",
499
525
  description:
500
526
  "Connect to a remote agent registry via JWKS trust exchange.",
501
- setup: (params, ctx) => setupFn(params, ctx as any),
502
- connect: (params, ctx) => connectFn(params, ctx as any),
527
+ setup: (params, ctx) => setupFn(params, ctx),
528
+ connect: (params, ctx) => connectFn(params, ctx),
503
529
  async discover(params) {
504
530
  const url = (params.url as string) ?? "";
505
531
  try {
506
- const res = await globalThis.fetch(
507
- `${url.replace(/\/$/, "")}/.well-known/configuration`,
508
- );
509
- if (!res.ok)
532
+ const base = url.replace(/\/$/, "");
533
+ const origin = new URL(base).origin;
534
+ const jwksUri = `${origin}/.well-known/jwks.json`;
535
+ const res = await globalThis.fetch(jwksUri);
536
+ if (!res.ok) {
510
537
  return {
511
538
  success: false,
512
- error: `No configuration endpoint at ${url}`,
539
+ error: `JWKS not reachable at ${jwksUri}`,
513
540
  };
514
- const config = (await res.json()) as any;
541
+ }
515
542
  return {
516
543
  success: true,
517
544
  data: {
518
545
  url,
519
- issuer: config.issuer,
520
- grantTypes: config.supported_grant_types,
521
- jwksUri: config.jwks_uri,
546
+ issuer: origin,
547
+ grantTypes: ["client_credentials", "jwt_exchange"],
548
+ jwksUri,
522
549
  },
523
550
  };
524
551
  } catch (err) {
@@ -558,6 +585,6 @@ export function createRemoteRegistryAgent(
558
585
  return { success: true, data: conn };
559
586
  },
560
587
  },
561
- tools: [proxyTool, listTool, addConnectionTool] as any[],
588
+ tools: [proxyTool, listTool, addConnectionTool] as ToolDefinition<ToolContext>[],
562
589
  });
563
590
  }
@@ -230,6 +230,39 @@ export interface UsersAgentOptions {
230
230
  store: UserStore;
231
231
  }
232
232
 
233
+ interface CreateUserToolInput {
234
+ id?: string;
235
+ tenantId: string;
236
+ email?: string;
237
+ name?: string;
238
+ avatarUrl?: string;
239
+ metadata?: Record<string, unknown>;
240
+ externalRef?: { issuer: string; userId: string };
241
+ }
242
+
243
+ interface UpdateUserToolInput {
244
+ userId: string;
245
+ email?: string;
246
+ name?: string;
247
+ avatarUrl?: string;
248
+ metadata?: Record<string, unknown>;
249
+ }
250
+
251
+ interface LinkIdentityToolInput {
252
+ userId: string;
253
+ provider: string;
254
+ providerUserId: string;
255
+ email?: string;
256
+ name?: string;
257
+ avatarUrl?: string;
258
+ accessToken?: string;
259
+ refreshToken?: string;
260
+ expiresAt?: number;
261
+ tokenType?: string;
262
+ scopes?: string[];
263
+ metadata?: Record<string, unknown>;
264
+ }
265
+
233
266
  export function createUsersAgent(options: UsersAgentOptions): AgentDefinition {
234
267
  const { store } = options;
235
268
 
@@ -268,7 +301,7 @@ export function createUsersAgent(options: UsersAgentOptions): AgentDefinition {
268
301
  },
269
302
  required: ["tenantId"],
270
303
  },
271
- execute: async (input: any, __ctx: ToolContext) => {
304
+ execute: async (input: CreateUserToolInput, __ctx: ToolContext) => {
272
305
  // If externalRef provided, check if identity already exists
273
306
  if (input.externalRef) {
274
307
  const existing = await store.findIdentityByProviderUserId(
@@ -365,7 +398,7 @@ export function createUsersAgent(options: UsersAgentOptions): AgentDefinition {
365
398
  },
366
399
  required: ["userId"],
367
400
  },
368
- execute: async (input: any, __ctx: ToolContext) => {
401
+ execute: async (input: UpdateUserToolInput, __ctx: ToolContext) => {
369
402
  const { userId, ...updates } = input;
370
403
  const user = await store.updateUser(userId, updates);
371
404
  if (!user) return { error: `User '${userId}' not found` };
@@ -416,7 +449,7 @@ export function createUsersAgent(options: UsersAgentOptions): AgentDefinition {
416
449
  },
417
450
  required: ["userId", "provider", "providerUserId"],
418
451
  },
419
- execute: async (input: any, __ctx: ToolContext) => {
452
+ execute: async (input: LinkIdentityToolInput, __ctx: ToolContext) => {
420
453
  // Check if identity already exists
421
454
  const existing = await store.getIdentityByProvider(
422
455
  input.userId,