@agentforge-io/core 2.0.2 → 2.0.4

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.
@@ -68,6 +68,13 @@ class McpClientService {
68
68
  execute: async (input) => {
69
69
  return this.callTool(config.name, tool.name, input);
70
70
  },
71
+ // Carry the MCP origin through to the registry so /tools can label
72
+ // and group these distinctly from built-ins / connector tools.
73
+ mcpServerName: config.name,
74
+ // Propagate the owning tenant when the host wired one; lets the
75
+ // catalog endpoint scope MCP rows per workspace so deepwiki@tenantA
76
+ // doesn't leak into tenantB's tools picker.
77
+ ...(config.tenantId ? { tenantId: config.tenantId } : {}),
71
78
  };
72
79
  this.registry.register(wrapped);
73
80
  handles.push({
@@ -158,5 +158,9 @@ function toClientConfig(r) {
158
158
  transport: r.transport,
159
159
  url: r.url,
160
160
  headers: r.headers,
161
+ // Propagate the owning tenant so the registry can scope `/tools` by
162
+ // workspace; harmless on single-tenant deployments where it stays
163
+ // undefined.
164
+ tenantId: r.tenantId,
161
165
  };
162
166
  }
@@ -32,7 +32,15 @@ export declare class ToolRegistryService {
32
32
  * `execute` function (not serializable) and surfaces the per-tool agent
33
33
  * allowlist so a UI can show "this tool is only usable by agent X".
34
34
  */
35
- describe(): ToolDescription[];
35
+ /**
36
+ * Public catalog. Pass `tenantId` to scope tenant-tagged tools (MCP rows
37
+ * registered per-tenant) to that tenant; built-ins and untagged tools are
38
+ * always returned. Omit `tenantId` to keep the legacy behavior of
39
+ * returning everything (used by tests and single-tenant deployments).
40
+ */
41
+ describe(opts?: {
42
+ tenantId?: string;
43
+ }): ToolDescription[];
36
44
  }
37
45
  export interface ToolDescription {
38
46
  name: string;
@@ -48,4 +56,18 @@ export interface ToolDescription {
48
56
  connectorId?: string;
49
57
  /** Human-readable connector label paired with `connectorId`. */
50
58
  connectorName?: string;
59
+ /**
60
+ * Set when this tool was discovered from an MCP server. The tool's
61
+ * `name` is already prefixed `<server>__<tool>`, but the UI uses this
62
+ * field to group tools by their MCP origin and label them distinctly
63
+ * from built-ins / connector tools.
64
+ */
65
+ mcpServerName?: string;
66
+ /**
67
+ * Owning tenant for tenant-scoped tools (MCP servers registered per
68
+ * tenant). When the catalog endpoint is called with a tenant the
69
+ * registry filters by this field so workspaces don't see each other's
70
+ * MCP rows. Built-ins and untagged tools omit it.
71
+ */
72
+ tenantId?: string;
51
73
  }
@@ -89,12 +89,35 @@ class ToolRegistryService {
89
89
  * `execute` function (not serializable) and surfaces the per-tool agent
90
90
  * allowlist so a UI can show "this tool is only usable by agent X".
91
91
  */
92
- describe() {
93
- return Array.from(this.tools.values()).map((t) => ({
92
+ /**
93
+ * Public catalog. Pass `tenantId` to scope tenant-tagged tools (MCP rows
94
+ * registered per-tenant) to that tenant; built-ins and untagged tools are
95
+ * always returned. Omit `tenantId` to keep the legacy behavior of
96
+ * returning everything (used by tests and single-tenant deployments).
97
+ */
98
+ describe(opts) {
99
+ const callerTenant = opts?.tenantId;
100
+ return Array.from(this.tools.values())
101
+ .filter((t) => {
102
+ // Tools without a tenant tag are global (built-ins, untagged MCPs
103
+ // from older callers). Tools with a tenant tag only appear for the
104
+ // matching tenant; when no caller tenant was supplied we surface
105
+ // them all (backwards-compat).
106
+ if (!t.tenantId)
107
+ return true;
108
+ if (!callerTenant)
109
+ return true;
110
+ return t.tenantId === callerTenant;
111
+ })
112
+ .map((t) => ({
94
113
  name: t.name,
95
114
  description: t.description,
96
115
  inputSchema: t.inputSchema,
97
116
  agents: t.agents,
117
+ ...(t.connectorId ? { connectorId: t.connectorId } : {}),
118
+ ...(t.connectorName ? { connectorName: t.connectorName } : {}),
119
+ ...(t.mcpServerName ? { mcpServerName: t.mcpServerName } : {}),
120
+ ...(t.tenantId ? { tenantId: t.tenantId } : {}),
98
121
  }));
99
122
  }
100
123
  }
@@ -90,6 +90,18 @@ export interface AgentToolDefinition {
90
90
  execute: (input: Record<string, unknown>, context: ToolExecutionContext) => Promise<string>;
91
91
  /** Restrict to specific agents */
92
92
  agents?: string[];
93
+ /** OAuth connector this tool belongs to. Set by ConnectorRegistryService
94
+ * when materializing per-user toolbelts; left undefined for built-ins. */
95
+ connectorId?: string;
96
+ connectorName?: string;
97
+ /** MCP server this tool was discovered from. Set by McpClientService when
98
+ * wrapping a remote tool; left undefined for built-ins and connector tools. */
99
+ mcpServerName?: string;
100
+ /** Owning tenantId for tenant-scoped tools (MCP servers registered per
101
+ * tenant). Used by `/tools` to filter results to the caller's tenant so
102
+ * the catalog doesn't leak another workspace's rows. Built-ins leave
103
+ * this unset and remain globally visible. */
104
+ tenantId?: string;
93
105
  }
94
106
  export interface ToolExecutionContext {
95
107
  userId: string;
@@ -133,4 +133,11 @@ export interface McpServerConfig {
133
133
  * secrets via the host's SecretsService before passing them here.
134
134
  */
135
135
  headers?: Record<string, string>;
136
+ /**
137
+ * When the host stores MCP server records per-tenant, pass the owning
138
+ * tenantId here so the registry can scope `/tools` results to the caller
139
+ * and avoid leaking another workspace's catalog rows. Optional — leave
140
+ * unset for hosts with a single global MCP catalog.
141
+ */
142
+ tenantId?: string;
136
143
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentforge-io/core",
3
- "version": "2.0.2",
3
+ "version": "2.0.4",
4
4
  "description": "Framework-free AI runtime SDK. Owns: agent loop (Anthropic), conversations, tools, streaming, agent-job queue, SdkHooks. Identity, billing, infra (email/uploads/secrets) live in the host's modules — not here.",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",