@compilr-dev/sdk 0.23.2 → 0.24.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.
@@ -68,6 +68,8 @@ export interface TeamAgentUpdate {
68
68
  toolProfile?: TeamAgentConfig['toolProfile'];
69
69
  toolFilter?: string[];
70
70
  enabledSkills?: string[];
71
+ /** Which MCP servers this agent may reach. See `TeamAgent.mcpServers`. */
72
+ mcpServers?: string[];
71
73
  }
72
74
  /** What an edit did, and whether anyone needs telling. */
73
75
  export interface AgentUpdateResult {
@@ -185,6 +187,15 @@ export declare class TeamAgent {
185
187
  * from the profile name alone.
186
188
  */
187
189
  customGroups?: string[];
190
+ /**
191
+ * MCP servers this agent may reach. `undefined` = a pre-grants agent, which reaches all;
192
+ * `[]` = granted nothing. See `TeamAgentConfig.mcpServers`.
193
+ *
194
+ * The SDK holds the grant; the HOST enforces it, because the host owns the MCP connection and
195
+ * decides which tools an agent is built with. `grantsMcpServer()` is the shared predicate so
196
+ * the two cannot disagree about what `undefined` means.
197
+ */
198
+ mcpServers?: string[];
188
199
  /**
189
200
  * Enabled skills (empty = all skills)
190
201
  */
@@ -288,6 +299,15 @@ export declare class TeamAgent {
288
299
  * through after it is the same edit that would have been allowed before this guard existed.
289
300
  */
290
301
  private static readonly TURN_STALE_AFTER_MS;
302
+ /**
303
+ * Whether this agent may reach an MCP server.
304
+ *
305
+ * ⚠️ THE ONE PLACE `undefined` IS INTERPRETED. Hosts filter the tools they build an agent
306
+ * with, so each one would otherwise re-decide what "never asked" means — and a host that
307
+ * read it as "deny" would silently strip reach from every agent created before grants
308
+ * existed, which is the migration we explicitly chose not to do.
309
+ */
310
+ grantsMcpServer(server: string): boolean;
291
311
  /** Mark the start of a turn. Pair with `endTurn()` in a `finally`. */
292
312
  beginTurn(): void;
293
313
  /** Mark the end of a turn, however it ended — completed, aborted or thrown. */
@@ -334,7 +354,20 @@ export declare class TeamAgent {
334
354
  * @param agentFactory Factory function to create the agent
335
355
  * @param sharedContext Optional shared context to inject into system prompt
336
356
  */
337
- initialize(agentFactory: (config: Partial<AgentConfig>, systemPromptAddition?: string, useMinimalSystemPrompt?: boolean, noTools?: boolean, toolFilter?: string[], modelTier?: ModelTier) => Promise<Agent>, sharedContext?: SharedContextManager): Promise<void>;
357
+ initialize(agentFactory: (config: Partial<AgentConfig>, systemPromptAddition?: string, useMinimalSystemPrompt?: boolean, noTools?: boolean, toolFilter?: string[], modelTier?: ModelTier,
358
+ /**
359
+ * Which agent is being built.
360
+ *
361
+ * ⚠️ ADDED BECAUSE THE FACTORY COULD NOT TELL ITS AGENTS APART. Per-agent MCP grants are
362
+ * enforced by the HOST — it owns the connection and decides which tools an agent is
363
+ * constructed with — and it could not, because every parameter here described the
364
+ * configuration and none identified the agent. Desktop's episode recorder had already
365
+ * worked around the same gap by recording every team agent under the literal id
366
+ * 'team-agent'.
367
+ *
368
+ * Optional, so a host that ignores it behaves exactly as before.
369
+ */
370
+ teamAgent?: TeamAgent) => Promise<Agent>, sharedContext?: SharedContextManager): Promise<void>;
338
371
  /**
339
372
  * Set the agent instance directly
340
373
  * Used for the default agent when an agent is created before the team
@@ -203,6 +203,15 @@ export class TeamAgent {
203
203
  * from the profile name alone.
204
204
  */
205
205
  customGroups;
206
+ /**
207
+ * MCP servers this agent may reach. `undefined` = a pre-grants agent, which reaches all;
208
+ * `[]` = granted nothing. See `TeamAgentConfig.mcpServers`.
209
+ *
210
+ * The SDK holds the grant; the HOST enforces it, because the host owns the MCP connection and
211
+ * decides which tools an agent is built with. `grantsMcpServer()` is the shared predicate so
212
+ * the two cannot disagree about what `undefined` means.
213
+ */
214
+ mcpServers;
206
215
  /**
207
216
  * Enabled skills (empty = all skills)
208
217
  */
@@ -261,6 +270,7 @@ export class TeamAgent {
261
270
  this.toolFilter = config.toolFilter;
262
271
  this.toolProfile = config.toolProfile;
263
272
  this.customGroups = config.customGroups;
273
+ this.mcpServers = config.mcpServers;
264
274
  this.enabledSkills = config.enabledSkills;
265
275
  this.personality = config.personality;
266
276
  this.autoApproveHandoff = config.autoApproveHandoff;
@@ -353,6 +363,17 @@ export class TeamAgent {
353
363
  * through after it is the same edit that would have been allowed before this guard existed.
354
364
  */
355
365
  static TURN_STALE_AFTER_MS = 10 * 60 * 1000;
366
+ /**
367
+ * Whether this agent may reach an MCP server.
368
+ *
369
+ * ⚠️ THE ONE PLACE `undefined` IS INTERPRETED. Hosts filter the tools they build an agent
370
+ * with, so each one would otherwise re-decide what "never asked" means — and a host that
371
+ * read it as "deny" would silently strip reach from every agent created before grants
372
+ * existed, which is the migration we explicitly chose not to do.
373
+ */
374
+ grantsMcpServer(server) {
375
+ return this.mcpServers === undefined || this.mcpServers.includes(server);
376
+ }
356
377
  /** Mark the start of a turn. Pair with `endTurn()` in a `finally`. */
357
378
  beginTurn() {
358
379
  this.turnStartedAt = Date.now();
@@ -384,7 +405,9 @@ export class TeamAgent {
384
405
  (patch.personality !== undefined && patch.personality !== this.personality) ||
385
406
  (patch.toolProfile !== undefined && patch.toolProfile !== this.toolProfile) ||
386
407
  (patch.toolFilter !== undefined && !sameStrings(patch.toolFilter, this.toolFilter)) ||
387
- (patch.enabledSkills !== undefined && !sameStrings(patch.enabledSkills, this.enabledSkills));
408
+ (patch.enabledSkills !== undefined &&
409
+ !sameStrings(patch.enabledSkills, this.enabledSkills)) ||
410
+ (patch.mcpServers !== undefined && !sameStrings(patch.mcpServers, this.mcpServers));
388
411
  /*
389
412
  Delegated: `setModelTier` no-ops when the tier is unchanged and stashes for rebuild
390
413
  when it is not. Its `rebuilt` contribution is folded in below.
@@ -421,6 +444,8 @@ export class TeamAgent {
421
444
  this.systemPromptAddition = patch.systemPromptAddition;
422
445
  if (patch.personality !== undefined)
423
446
  this.personality = patch.personality;
447
+ if (patch.mcpServers !== undefined)
448
+ this.mcpServers = patch.mcpServers;
424
449
  /*
425
450
  ⚠️ THE PROFILE IS A LABEL; `toolFilter` IS THE ENFORCEMENT. `initialize()` passes
426
451
  `toolFilter` to the factory and never looks at `toolProfile`, so setting the profile
@@ -550,7 +575,8 @@ export class TeamAgent {
550
575
  }
551
576
  }
552
577
  this._agent = await agentFactory(this.agentConfig, finalSystemPromptAddition || undefined, this.useMinimalSystemPrompt, this.noTools, this.toolFilter, // Pass tool filter to factory
553
- this._modelTier // Pass model tier to factory
578
+ this._modelTier, // Pass model tier to factory
579
+ this // So the host can honour this agent's MCP grants and name it in logs
554
580
  );
555
581
  // Set the team roster as a pin (dynamically re-injected on every LLM call).
556
582
  // This ensures roster updates (agent added/removed) are always visible.
@@ -731,6 +757,7 @@ export class TeamAgent {
731
757
  toolFilter: this.toolFilter,
732
758
  toolProfile: this.toolProfile,
733
759
  customGroups: this.customGroups,
760
+ mcpServers: this.mcpServers,
734
761
  enabledSkills: this.enabledSkills,
735
762
  modelTier: this.modelTier,
736
763
  autoApproveHandoff: this.autoApproveHandoff,
@@ -787,6 +814,7 @@ export class TeamAgent {
787
814
  toolFilter,
788
815
  toolProfile: data.toolProfile,
789
816
  customGroups: data.customGroups,
817
+ mcpServers: data.mcpServers,
790
818
  enabledSkills: data.enabledSkills,
791
819
  modelTier: data.modelTier,
792
820
  autoApproveHandoff: data.autoApproveHandoff,
@@ -34,7 +34,9 @@ export interface AgentTeamConfig {
34
34
  * @param toolFilter - Limit which tools this agent can use
35
35
  * @param modelTier - Model tier for this agent (fast/balanced/powerful)
36
36
  */
37
- agentFactory: (config: Partial<AgentConfig>, systemPromptAddition?: string, useMinimalSystemPrompt?: boolean, noTools?: boolean, toolFilter?: string[], modelTier?: ModelTier) => Promise<Agent>;
37
+ agentFactory: (config: Partial<AgentConfig>, systemPromptAddition?: string, useMinimalSystemPrompt?: boolean, noTools?: boolean, toolFilter?: string[], modelTier?: ModelTier,
38
+ /** Which agent is being built — see TeamAgent.initialize. */
39
+ teamAgent?: TeamAgent) => Promise<Agent>;
38
40
  /**
39
41
  * Initial agents to add to the team (optional)
40
42
  * If not provided, starts with just the default agent
@@ -137,6 +137,16 @@ export interface TeamAgentConfig {
137
137
  toolProfile?: ToolProfile;
138
138
  /** Groups behind a `custom` profile — see TeamAgent.customGroups. */
139
139
  customGroups?: string[];
140
+ /**
141
+ * MCP servers this agent may reach, by server name.
142
+ *
143
+ * ⚠️ `undefined` AND `[]` MEAN DIFFERENT THINGS, DELIBERATELY. `undefined` is "never asked" —
144
+ * every agent serialized before per-agent grants existed, which reached every server, and
145
+ * still does. `[]` is "asked, and granted nothing", which is what a newly created agent gets.
146
+ * Collapsing them would either strip reach from agents that depend on it or hand every new
147
+ * agent the whole machine.
148
+ */
149
+ mcpServers?: string[];
140
150
  /**
141
151
  * Enabled skills for this agent
142
152
  * Empty array means all skills, non-empty means filtered
@@ -176,6 +186,8 @@ export interface SerializedTeamAgent {
176
186
  toolFilter?: string[];
177
187
  toolProfile?: ToolProfile;
178
188
  customGroups?: string[];
189
+ /** See TeamAgentConfig.mcpServers — undefined means a pre-grants agent, which reaches all. */
190
+ mcpServers?: string[];
179
191
  enabledSkills?: string[];
180
192
  modelTier?: ModelTier;
181
193
  autoApproveHandoff?: boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@compilr-dev/sdk",
3
- "version": "0.23.2",
3
+ "version": "0.24.0",
4
4
  "description": "Universal agent runtime for building AI-powered applications",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",