@mastra/code-sdk 1.17.0-alpha.2 → 1.18.0-alpha.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 (37) hide show
  1. package/dist/agents/instructions.d.ts +2 -10
  2. package/dist/agents/instructions.d.ts.map +1 -1
  3. package/dist/agents/instructions.js +2 -4
  4. package/dist/agents/instructions.js.map +1 -1
  5. package/dist/agents/memory.d.ts +1 -17
  6. package/dist/agents/memory.d.ts.map +1 -1
  7. package/dist/agents/memory.js +6 -55
  8. package/dist/agents/memory.js.map +1 -1
  9. package/dist/agents/prompts/index.d.ts +0 -2
  10. package/dist/agents/prompts/index.d.ts.map +1 -1
  11. package/dist/agents/prompts/index.js +0 -1
  12. package/dist/agents/prompts/index.js.map +1 -1
  13. package/dist/agents/prompts/tool-guidance.d.ts +0 -2
  14. package/dist/agents/prompts/tool-guidance.d.ts.map +1 -1
  15. package/dist/agents/prompts/tool-guidance.js +0 -30
  16. package/dist/agents/prompts/tool-guidance.js.map +1 -1
  17. package/dist/index.d.ts +15 -2
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +28 -16
  20. package/dist/index.js.map +1 -1
  21. package/dist/knowledge-inspector.d.ts +26 -10
  22. package/dist/knowledge-inspector.d.ts.map +1 -1
  23. package/dist/knowledge-inspector.js +266 -241
  24. package/dist/knowledge-inspector.js.map +1 -1
  25. package/dist/knowledge-scope.d.ts +21 -23
  26. package/dist/knowledge-scope.d.ts.map +1 -1
  27. package/dist/knowledge-scope.js +49 -33
  28. package/dist/knowledge-scope.js.map +1 -1
  29. package/dist/mcp/manager.d.ts +3 -1
  30. package/dist/mcp/manager.d.ts.map +1 -1
  31. package/dist/mcp/manager.js +139 -104
  32. package/dist/mcp/manager.js.map +1 -1
  33. package/dist/onboarding/settings.d.ts +2 -0
  34. package/dist/onboarding/settings.d.ts.map +1 -1
  35. package/dist/onboarding/settings.js +3 -1
  36. package/dist/onboarding/settings.js.map +1 -1
  37. package/package.json +15 -15
@@ -10,6 +10,8 @@ import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "
10
10
  * Created once at startup, provides tools from connected MCP servers.
11
11
  */
12
12
  const MASTRACODE_MCP_TIMEOUT_MS = 6048e5;
13
+ /** How long a server gets to connect and list its tools before it is reported as failed. */
14
+ const DEFAULT_MCP_DISCOVERY_TIMEOUT_MS = 6e4;
13
15
  function getTransport(cfg) {
14
16
  return "url" in cfg ? "http" : "stdio";
15
17
  }
@@ -93,7 +95,8 @@ function loadedMcpModule() {
93
95
  * Create an MCP manager that wraps MCPClient with config-file discovery
94
96
  * and per-server status tracking.
95
97
  */
96
- function createMcpManager(projectDir, configDirName = DEFAULT_CONFIG_DIR, extraServers, externalDiscovery) {
98
+ function createMcpManager(projectDir, configDirName = DEFAULT_CONFIG_DIR, extraServers, externalDiscovery, options) {
99
+ const discoveryTimeoutMs = options?.discoveryTimeoutMs ?? DEFAULT_MCP_DISCOVERY_TIMEOUT_MS;
97
100
  /** Merge programmatic servers into a base config (highest priority). */
98
101
  const applyExtraServers = (base) => {
99
102
  if (!extraServers || Object.keys(extraServers).length === 0) return base;
@@ -129,6 +132,13 @@ function createMcpManager(projectDir, configDirName = DEFAULT_CONFIG_DIR, extraS
129
132
  let serverStatuses = /* @__PURE__ */ new Map();
130
133
  let stderrLogs = /* @__PURE__ */ new Map();
131
134
  let initialized = false;
135
+ /**
136
+ * The latest connect attempt per server. A discovery result is only applied while its
137
+ * attempt is still the latest and its client is still the live one, so a slow or late
138
+ * result never overwrites a newer reconnect, a reload, or a server being disabled.
139
+ */
140
+ let connectAttempts = /* @__PURE__ */ new Map();
141
+ const isCurrent = (name, attempt, attemptClient) => connectAttempts.get(name) === attempt && client === attemptClient;
132
142
  /** Per-server handlers that receive the OAuth authorization URL during authenticateServer(). */
133
143
  const authUrlHandlers = /* @__PURE__ */ new Map();
134
144
  /**
@@ -155,11 +165,14 @@ function createMcpManager(projectDir, configDirName = DEFAULT_CONFIG_DIR, extraS
155
165
  globalKillSwitch: globalDisableState.allDisabled
156
166
  });
157
167
  const MAX_STDERR_LINES = 200;
168
+ /** Streams already being buffered, so capturing a server again never doubles its lines. */
169
+ const capturedStderr = /* @__PURE__ */ new WeakSet();
158
170
  /** Hook into a server's stderr stream and buffer its output. */
159
171
  function captureStderr(serverName) {
160
172
  if (!client || typeof client.getServerStderr !== "function") return;
161
173
  const stream = client.getServerStderr(serverName);
162
- if (!stream) return;
174
+ if (!stream || capturedStderr.has(stream)) return;
175
+ capturedStderr.add(stream);
163
176
  let buffer = "";
164
177
  const lines = stderrLogs.get(serverName) ?? [];
165
178
  stderrLogs.set(serverName, lines);
@@ -241,6 +254,53 @@ function createMcpManager(projectDir, configDirName = DEFAULT_CONFIG_DIR, extraS
241
254
  });
242
255
  }
243
256
  }
257
+ const discoveryTimeoutError = () => `Timed out after ${discoveryTimeoutMs / 1e3}s waiting for the server to connect and list its tools`;
258
+ function outcomeOf(result) {
259
+ if (result.error === void 0) return { tools: result.value };
260
+ const { MCP_DISCOVERY_TIMEOUT_CODE } = loadedMcpModule();
261
+ return { error: result.error.code === MCP_DISCOVERY_TIMEOUT_CODE ? discoveryTimeoutError() : result.error.message };
262
+ }
263
+ /**
264
+ * Drop the tools a server registered earlier.
265
+ *
266
+ * Only the exact tool names that server reported are removed. Matching on the
267
+ * `${name}_` prefix would also delete the tools of a server whose name starts
268
+ * with this one, e.g. `foo` would drop `foo_bar_ping` from `foo_bar`.
269
+ */
270
+ function removeServerTools(name) {
271
+ for (const key of serverStatuses.get(name)?.toolNames ?? []) delete tools[key];
272
+ }
273
+ /** Replace a server's tools and status with one discovery outcome. */
274
+ function applyServerResult(name, cfg, outcome) {
275
+ removeServerTools(name);
276
+ const transport = getTransport(cfg);
277
+ const serverTools = outcome.tools ?? {};
278
+ const toolNames = Object.keys(serverTools).map((t) => `${name}_${t}`);
279
+ let status;
280
+ if (outcome.error === void 0 && toolNames.length > 0) {
281
+ for (const [toolName, toolConfig] of Object.entries(serverTools)) tools[`${name}_${toolName}`] = toolConfig;
282
+ status = {
283
+ name,
284
+ connected: true,
285
+ toolCount: toolNames.length,
286
+ toolNames,
287
+ transport
288
+ };
289
+ } else {
290
+ const error = outcome.error ?? "Failed to connect";
291
+ status = {
292
+ name,
293
+ connected: false,
294
+ toolCount: 0,
295
+ toolNames: [],
296
+ transport,
297
+ error,
298
+ ...serverNeedsAuth(name, cfg, error) ? { needsAuth: true } : {}
299
+ };
300
+ }
301
+ serverStatuses.set(name, status);
302
+ return status;
303
+ }
244
304
  async function connectAndCollectTools() {
245
305
  setDisabledStatuses();
246
306
  const servers = Object.fromEntries(Object.entries(config.mcpServers ?? {}).filter(([name]) => !isDisabled(name)));
@@ -256,52 +316,39 @@ function createMcpManager(projectDir, configDirName = DEFAULT_CONFIG_DIR, extraS
256
316
  });
257
317
  const { MCPClient } = await loadMcpModule();
258
318
  serverDefs = buildServerDefs(servers);
259
- client = new MCPClient({
319
+ const attemptClient = new MCPClient({
260
320
  id: "mastra-code-mcp",
261
321
  servers: serverDefs,
262
322
  timeout: MASTRACODE_MCP_TIMEOUT_MS
263
323
  });
324
+ client = attemptClient;
325
+ const attempts = new Map(serverNames.map((name) => [name, {}]));
326
+ for (const [name, attempt] of attempts) connectAttempts.set(name, attempt);
327
+ const record = (name, outcome) => {
328
+ if (!isCurrent(name, attempts.get(name), attemptClient)) return false;
329
+ captureStderr(name);
330
+ applyServerResult(name, servers[name], outcome);
331
+ return true;
332
+ };
333
+ const timedOut = [];
264
334
  try {
265
- const { toolsets, errors } = await client.listToolsetsWithErrors();
266
- const typedToolsets = toolsets;
267
- for (const [serverName, serverTools] of Object.entries(typedToolsets)) for (const [toolName, toolConfig] of Object.entries(serverTools)) tools[`${serverName}_${toolName}`] = toolConfig;
268
- for (const name of serverNames) {
269
- const serverTools = typedToolsets[name];
270
- if (serverTools && Object.keys(serverTools).length > 0) {
271
- const toolNames = Object.keys(serverTools).map((t) => `${name}_${t}`);
272
- serverStatuses.set(name, {
273
- name,
274
- connected: true,
275
- toolCount: toolNames.length,
276
- toolNames,
277
- transport: getTransport(servers[name])
278
- });
279
- } else {
280
- const error = errors[name] ?? "Failed to connect";
281
- serverStatuses.set(name, {
282
- name,
283
- connected: false,
284
- toolCount: 0,
285
- toolNames: [],
286
- transport: getTransport(servers[name]),
287
- error,
288
- ...serverNeedsAuth(name, servers[name], error) ? { needsAuth: true } : {}
289
- });
335
+ await attemptClient.listToolsetsWithErrors({
336
+ perServerTimeoutMs: discoveryTimeoutMs,
337
+ onServerSettled: (name, result) => {
338
+ if (!attempts.has(name)) return;
339
+ if (result.error?.code === loadedMcpModule().MCP_DISCOVERY_TIMEOUT_CODE) timedOut.push(name);
340
+ record(name, outcomeOf(result));
290
341
  }
291
- }
292
- for (const name of serverNames) captureStderr(name);
342
+ });
293
343
  } catch (error) {
294
344
  const errMsg = error instanceof Error ? error.message : String(error);
295
- for (const name of serverNames) serverStatuses.set(name, {
296
- name,
297
- connected: false,
298
- toolCount: 0,
299
- toolNames: [],
300
- transport: getTransport(servers[name]),
301
- error: errMsg,
302
- ...serverNeedsAuth(name, servers[name], errMsg) ? { needsAuth: true } : {}
303
- });
345
+ for (const name of serverNames) if (serverStatuses.get(name)?.connecting) record(name, { error: errMsg });
304
346
  }
347
+ for (const name of serverNames) if (serverStatuses.get(name)?.connecting) record(name, { error: "Failed to connect" });
348
+ if (timedOut.length > 0) attemptClient.listToolsetsWithErrors({
349
+ serverNames: timedOut,
350
+ onServerSettled: (name, result) => record(name, outcomeOf(result))
351
+ }).catch(() => {});
305
352
  }
306
353
  /**
307
354
  * Whether a failed HTTP server is blocked on OAuth authorization.
@@ -320,11 +367,17 @@ function createMcpManager(projectDir, configDirName = DEFAULT_CONFIG_DIR, extraS
320
367
  /**
321
368
  * Runs a single-server connect action (reconnect or authenticate), then
322
369
  * refreshes that server's tools and status from the client.
370
+ *
371
+ * With `deadlineMs`, the whole operation shares one deadline: the server is
372
+ * reported as failed when it passes, and its result is still applied if it
373
+ * arrives later. A call that a newer reconnect, reload, or disable replaced
374
+ * leaves the stored status alone and returns a copy of it.
323
375
  */
324
- async function connectSingleServer(name, cfg, connect) {
325
- const transport = getTransport(cfg);
326
- const prefix = `${name}_`;
327
- for (const key of Object.keys(tools)) if (key.startsWith(prefix)) delete tools[key];
376
+ async function connectSingleServer(name, cfg, connect, deadlineMs) {
377
+ const attemptClient = client;
378
+ const attempt = {};
379
+ connectAttempts.set(name, attempt);
380
+ removeServerTools(name);
328
381
  stderrLogs.delete(name);
329
382
  serverStatuses.set(name, {
330
383
  name,
@@ -332,70 +385,49 @@ function createMcpManager(projectDir, configDirName = DEFAULT_CONFIG_DIR, extraS
332
385
  connecting: true,
333
386
  toolCount: 0,
334
387
  toolNames: [],
335
- transport
388
+ transport: getTransport(cfg)
336
389
  });
337
- try {
338
- await connect();
339
- captureStderr(name);
340
- const { toolsets, errors } = await client.listToolsetsWithErrors();
341
- const serverTools = toolsets[name];
342
- const serverError = errors[name];
343
- if (serverError) {
344
- const status = {
345
- name,
346
- connected: false,
347
- toolCount: 0,
348
- toolNames: [],
349
- transport,
350
- error: serverError,
351
- ...serverNeedsAuth(name, cfg, serverError) ? { needsAuth: true } : {}
352
- };
353
- serverStatuses.set(name, status);
354
- return status;
355
- } else if (serverTools && Object.keys(serverTools).length > 0) {
356
- const toolNames = Object.keys(serverTools).map((t) => `${name}_${t}`);
357
- for (const [toolName, toolConfig] of Object.entries(serverTools)) tools[`${name}_${toolName}`] = toolConfig;
358
- const status = {
359
- name,
360
- connected: true,
361
- toolCount: toolNames.length,
362
- toolNames,
363
- transport
364
- };
365
- serverStatuses.set(name, status);
366
- return status;
367
- }
368
- const status = {
369
- name,
370
- connected: false,
371
- toolCount: 0,
372
- toolNames: [],
373
- transport,
374
- error: "Failed to connect"
375
- };
376
- serverStatuses.set(name, status);
377
- return status;
378
- } catch (error) {
379
- const errMsg = error instanceof Error ? error.message : String(error);
380
- const status = {
381
- name,
382
- connected: false,
383
- toolCount: 0,
384
- toolNames: [],
385
- transport,
386
- error: errMsg,
387
- ...serverNeedsAuth(name, cfg, errMsg) ? { needsAuth: true } : {}
388
- };
389
- serverStatuses.set(name, status);
390
- return status;
391
- }
390
+ const work = (async () => {
391
+ await connect(attemptClient);
392
+ if (isCurrent(name, attempt, attemptClient)) captureStderr(name);
393
+ let outcome = { error: "Failed to connect" };
394
+ await attemptClient.listToolsetsWithErrors({
395
+ serverNames: [name],
396
+ onServerSettled: (_, result) => {
397
+ outcome = outcomeOf(result);
398
+ }
399
+ });
400
+ return outcome;
401
+ })().catch((error) => ({ error: error instanceof Error ? error.message : String(error) }));
402
+ const record = (outcome) => isCurrent(name, attempt, attemptClient) ? applyServerResult(name, cfg, outcome) : void 0;
403
+ const superseded = () => ({ ...serverStatuses.get(name) ?? {
404
+ name,
405
+ connected: false,
406
+ toolCount: 0,
407
+ toolNames: [],
408
+ transport: getTransport(cfg),
409
+ error: "Superseded by a newer connection attempt"
410
+ } });
411
+ if (deadlineMs === void 0) return record(await work) ?? superseded();
412
+ let timer;
413
+ const deadline = new Promise((resolve) => {
414
+ timer = setTimeout(() => resolve("timeout"), deadlineMs);
415
+ timer.unref?.();
416
+ });
417
+ const first = await Promise.race([work, deadline]);
418
+ clearTimeout(timer);
419
+ if (first !== "timeout") return record(first) ?? superseded();
420
+ work.then(record);
421
+ return record({ error: discoveryTimeoutError() }) ?? superseded();
392
422
  }
393
423
  async function disconnect() {
424
+ connectAttempts = /* @__PURE__ */ new Map();
394
425
  if (client) {
426
+ const closing = client;
427
+ client = null;
395
428
  try {
396
- await client.disconnect();
429
+ await closing.disconnect();
397
430
  } catch {}
398
- client = null;
399
431
  }
400
432
  }
401
433
  /** Tear down all connections and reconnect every enabled server. */
@@ -551,7 +583,7 @@ function createMcpManager(projectDir, configDirName = DEFAULT_CONFIG_DIR, extraS
551
583
  transport: getTransport(cfg),
552
584
  error: "MCP client not initialized"
553
585
  };
554
- return connectSingleServer(name, cfg, () => client.reconnectServer(name));
586
+ return connectSingleServer(name, cfg, (c) => c.reconnectServer(name), discoveryTimeoutMs);
555
587
  },
556
588
  async authenticateServer(name, options) {
557
589
  const cfg = config.mcpServers?.[name];
@@ -605,7 +637,8 @@ function createMcpManager(projectDir, configDirName = DEFAULT_CONFIG_DIR, extraS
605
637
  authenticatingServers.add(name);
606
638
  cancelledAuthServers.delete(name);
607
639
  try {
608
- const result = await connectSingleServer(name, cfg, () => client.authenticate(name, options?.timeoutMs === void 0 ? void 0 : { timeoutMs: options.timeoutMs }));
640
+ const result = await connectSingleServer(name, cfg, (c) => c.authenticate(name, options?.timeoutMs === void 0 ? void 0 : { timeoutMs: options.timeoutMs }));
641
+ if (serverStatuses.get(name) !== result) return result;
609
642
  const finalStatus = cancelledAuthServers.has(name) && !result.connected ? {
610
643
  ...result,
611
644
  cancelled: true
@@ -627,7 +660,9 @@ function createMcpManager(projectDir, configDirName = DEFAULT_CONFIG_DIR, extraS
627
660
  },
628
661
  disconnect,
629
662
  getTools() {
630
- return { ...tools };
663
+ const ordered = {};
664
+ for (const name of Object.keys(config.mcpServers ?? {})) for (const key of serverStatuses.get(name)?.toolNames ?? []) if (key in tools) ordered[key] = tools[key];
665
+ return ordered;
631
666
  },
632
667
  hasServers() {
633
668
  const hasConfigured = config.mcpServers !== void 0 && Object.keys(config.mcpServers).length > 0;
@@ -1 +1 @@
1
- {"version":3,"file":"manager.js","names":[],"sources":["../../src/mcp/manager.ts"],"sourcesContent":["/**\n * MCP manager — orchestrates MCP server connections using MCPClient directly.\n * Created once at startup, provides tools from connected MCP servers.\n */\n\nimport { existsSync, mkdirSync, readFileSync, writeFileSync, renameSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport type { MCPClient, MastraMCPServerDefinition, OAuthClientInformation, OAuthStorage } from '@mastra/mcp';\nimport { DEFAULT_CONFIG_DIR } from '../constants.js';\nimport { getAppDataDir } from '../utils/project.js';\nimport {\n DEFAULT_OAUTH_REDIRECT_URL,\n MASTRA_CODE_CLIENT_METADATA_URL,\n loadMcpConfig,\n getProjectMcpPath,\n getGlobalMcpPath,\n getClaudeSettingsPath,\n resolveOAuthRedirectUrl,\n} from './config.js';\nimport type { ExternalMcpDiscoveryOptions } from './config.js';\nimport {\n loadGlobalDisableState,\n loadProjectServerOverrides,\n saveGlobalDisableState,\n saveProjectServerOverrides,\n} from './state.js';\nimport type { McpProjectServerOverride } from './state.js';\nimport type {\n McpConfig,\n McpHttpOAuthConfig,\n McpHttpServerConfig,\n McpServerConfig,\n McpServerStatus,\n McpSkippedServer,\n} from './types.js';\n\nconst MASTRACODE_MCP_TIMEOUT_MS = 7 * 24 * 60 * 60 * 1000; // 7 days\n\n/** Summary of MCP initialization result. */\nexport interface McpInitResult {\n connected: McpServerStatus[];\n failed: McpServerStatus[];\n skipped: McpSkippedServer[];\n totalTools: number;\n}\n\n/** Public interface for the MCP manager returned by createMcpManager(). */\nexport interface McpManager {\n /** Connect to all configured MCP servers and collect their tools. */\n init(): Promise<void>;\n /** Start init in the background. Returns a promise that resolves with status when done. */\n initInBackground(): Promise<McpInitResult>;\n /** Disconnect all servers, reload config from disk, reconnect. */\n reload(): Promise<void>;\n /** Reconnect a single server by name. Returns updated status. */\n reconnectServer(name: string): Promise<McpServerStatus>;\n /**\n * Run the OAuth authorization-code flow for an HTTP server, then reconnect it.\n * Servers without an `oauth` config are provisioned with a zero-config default\n * that identifies Mastra Code by its Client ID Metadata Document. The\n * authorization URL is surfaced through\n * `onAuthorizationUrl` for the caller to open in a browser.\n *\n * Resolves with the resulting {@link McpServerStatus}: a connected status on\n * success, or a status carrying an `error` message on failure (including\n * cancellation) — it does not reject. Inspect the returned status rather than\n * relying on a thrown error.\n */\n authenticateServer(\n name: string,\n options?: { onAuthorizationUrl?: (url: string) => void; timeoutMs?: number },\n ): Promise<McpServerStatus>;\n /**\n * Cancel a pending {@link authenticateServer} flow for a server (e.g. the\n * user closed the browser without completing consent). The pending\n * authenticate call rejects and the server returns to the `needsAuth` state\n * so it can be retried. Returns `true` if a flow was cancelled.\n */\n cancelServerAuthentication(name: string): Promise<boolean>;\n /**\n * Disable or enable a single server by name. The change is persisted (in\n * mastracode's app data, not the user's config files) and survives restarts.\n * With `global: true`, this changes the default for every project. Otherwise\n * it records an explicit project override, which can override a global\n * per-server disable. The global all-MCP kill switch remains absolute.\n * Connections are rebuilt, so other servers reconnect — same behavior as\n * {@link reload}. Returns the server's resulting status.\n */\n setServerDisabled(name: string, disabled: boolean, options?: { global?: boolean }): Promise<McpServerStatus>;\n /** Clear a server's explicit project override so it inherits the global default. */\n inheritServer(name: string): Promise<McpServerStatus>;\n /**\n * Disable or enable all servers at once. Project scope records an explicit\n * override for every currently configured server. Global scope sets/clears a\n * persisted all-MCP kill switch (and, when enabling, also clears globally\n * disabled server names). Persisted like {@link setServerDisabled}.\n */\n setAllDisabled(disabled: boolean, options?: { global?: boolean }): Promise<void>;\n /** Clear every explicit project override so all servers inherit global defaults. */\n inheritAllServers(): Promise<void>;\n /** Names of configured servers that are currently disabled (any scope). */\n getDisabledServers(): string[];\n /** Whether all MCP is disabled globally (across every project). */\n isAllDisabledGlobally(): boolean;\n /** Disconnect from all MCP servers and clean up. */\n disconnect(): Promise<void>;\n /** Get all tools from connected MCP servers (namespaced as serverName_toolName). */\n getTools(): Record<string, any>;\n /** Check if any MCP servers are configured (or skipped). */\n hasServers(): boolean;\n /** Get status of all servers. */\n getServerStatuses(): McpServerStatus[];\n /** Get servers that were skipped during config loading. */\n getSkippedServers(): McpSkippedServer[];\n /** Get config file paths for display. */\n getConfigPaths(): { project: string; global: string; claude: string };\n /** Get the merged config. */\n getConfig(): McpConfig;\n /** Get captured stderr logs for a server. */\n getServerLogs(name: string): string[];\n}\n\nfunction getTransport(cfg: McpServerConfig): 'stdio' | 'http' {\n return 'url' in cfg ? 'http' : 'stdio';\n}\n\nclass FileOAuthStorage implements OAuthStorage {\n constructor(private filePath: string) {}\n\n get(key: string): string | undefined {\n return this.read()[key];\n }\n\n set(key: string, value: string): void {\n const data = this.read();\n data[key] = value;\n this.write(data);\n }\n\n delete(key: string): void {\n const data = this.read();\n delete data[key];\n this.write(data);\n }\n\n private read(): Record<string, string> {\n if (!existsSync(this.filePath)) return {};\n try {\n return JSON.parse(readFileSync(this.filePath, 'utf-8')) as Record<string, string>;\n } catch {\n return {};\n }\n }\n\n private write(data: Record<string, string>): void {\n const dir = dirname(this.filePath);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true, mode: 0o700 });\n }\n const tmpPath = `${this.filePath}.tmp`;\n writeFileSync(tmpPath, JSON.stringify(data, null, 2), { encoding: 'utf-8', mode: 0o600 });\n renameSync(tmpPath, this.filePath);\n }\n}\n\n/**\n * Zero-config OAuth defaults for servers with a bare `url` entry. The client\n * identifies itself by Mastra Code's Client ID Metadata Document URL, so no\n * `clientId` is needed.\n */\nconst DEFAULT_OAUTH_CONFIG: McpHttpOAuthConfig = { redirectUrl: DEFAULT_OAUTH_REDIRECT_URL };\n\nfunction getOAuthStoragePath(projectDir: string, name: string, cfg: McpHttpServerConfig): string {\n // The fingerprint always uses the resolved redirect URL so a bare `url`\n // entry keeps the same token file before and after zero-config provisioning.\n const key = JSON.stringify({\n projectDir,\n name,\n url: cfg.url,\n redirectUrl: resolveOAuthRedirectUrl(cfg.oauth),\n clientId: cfg.oauth?.clientId,\n scopes: cfg.oauth?.scopes ?? [],\n });\n return join(getAppDataDir(), 'mcp-oauth', `${getStorageKeyFingerprint(key)}.json`);\n}\n\nfunction getStorageKeyFingerprint(value: string): string {\n let fingerprint = 0xcbf29ce484222325n;\n for (let i = 0; i < value.length; i += 1) {\n fingerprint ^= BigInt(value.charCodeAt(i));\n fingerprint = BigInt.asUintN(64, fingerprint * 0x100000001b3n);\n }\n return fingerprint.toString(16).padStart(16, '0');\n}\n\ntype McpModule = typeof import('@mastra/mcp');\nlet mcpModule: McpModule | undefined;\n\n/** `@mastra/mcp` and the MCP SDK (~12 MB) load with the first server that connects, not with every session. */\nasync function loadMcpModule(): Promise<McpModule> {\n mcpModule ??= await import('@mastra/mcp');\n return mcpModule;\n}\n\n/** For code that only runs once a client exists, so the module is already loaded. */\nfunction loadedMcpModule(): McpModule {\n if (!mcpModule) throw new Error('@mastra/mcp is not loaded yet');\n return mcpModule;\n}\n\n/**\n * Create an MCP manager that wraps MCPClient with config-file discovery\n * and per-server status tracking.\n */\nexport function createMcpManager(\n projectDir: string,\n configDirName = DEFAULT_CONFIG_DIR,\n extraServers?: Record<string, McpServerConfig>,\n externalDiscovery?: ExternalMcpDiscoveryOptions,\n): McpManager {\n /** Merge programmatic servers into a base config (highest priority). */\n const applyExtraServers = (base: McpConfig): McpConfig => {\n if (!extraServers || Object.keys(extraServers).length === 0) return base;\n return { ...base, mcpServers: { ...base.mcpServers, ...extraServers } };\n };\n\n let config = applyExtraServers(loadMcpConfig(projectDir, configDirName, externalDiscovery));\n let projectServerOverrides = new Map<string, McpProjectServerOverride>(\n Object.entries(loadProjectServerOverrides(projectDir)),\n );\n let globalDisableState = loadGlobalDisableState();\n let globallyDisabledServers = new Set(globalDisableState.disabledServers);\n\n /** Whether a server is disabled after applying the kill switch, project override, and global default. */\n const isDisabled = (name: string): boolean => {\n if (globalDisableState.allDisabled) return true;\n const projectOverride = projectServerOverrides.get(name);\n if (projectOverride) return projectOverride === 'disabled';\n return globallyDisabledServers.has(name);\n };\n\n /** Which scope currently disables a server. The global kill switch remains absolute. */\n const disabledScopeOf = (name: string): 'project' | 'global' | undefined => {\n if (globalDisableState.allDisabled) return 'global';\n const projectOverride = projectServerOverrides.get(name);\n if (projectOverride === 'disabled') return 'project';\n if (!projectOverride && globallyDisabledServers.has(name)) return 'global';\n return undefined;\n };\n let client: MCPClient | null = null;\n let serverDefs: Record<string, MastraMCPServerDefinition> = {};\n let tools: Record<string, any> = {};\n let serverStatuses = new Map<string, McpServerStatus>();\n let stderrLogs = new Map<string, string[]>();\n let initialized = false;\n\n /** Per-server handlers that receive the OAuth authorization URL during authenticateServer(). */\n const authUrlHandlers = new Map<string, (url: string) => void>();\n\n /**\n * Servers with an OAuth authorization flow currently in flight. Owned by the\n * manager (not the TUI) so the state survives a `/mcp` selector being closed\n * and reopened — the reopened selector reads it back off the server status and\n * can still offer \"Cancel authentication\".\n */\n const authenticatingServers = new Set<string>();\n\n /**\n * Servers whose in-flight authentication was cancelled by the caller. Set by\n * cancelServerAuthentication() so the resolving authenticateServer() call can\n * mark its failed status as a deliberate cancel rather than a genuine failure.\n * This lives on the manager (not the TUI selector) so the signal survives the\n * selector being closed and reopened mid-flow.\n */\n const cancelledAuthServers = new Set<string>();\n\n /** Overlay manager-owned state onto a status snapshot. */\n const withManagerState = (status: McpServerStatus): McpServerStatus => ({\n ...status,\n ...(authenticatingServers.has(status.name) ? { authenticating: true } : {}),\n ...(projectServerOverrides.has(status.name) ? { projectOverride: projectServerOverrides.get(status.name) } : {}),\n globalDefault: globallyDisabledServers.has(status.name) ? 'disabled' : 'enabled',\n globalKillSwitch: globalDisableState.allDisabled,\n });\n\n const MAX_STDERR_LINES = 200;\n\n /** Hook into a server's stderr stream and buffer its output. */\n function captureStderr(serverName: string): void {\n if (!client || typeof client.getServerStderr !== 'function') return;\n const stream = client.getServerStderr(serverName);\n if (!stream) return;\n\n let buffer = '';\n const lines = stderrLogs.get(serverName) ?? [];\n stderrLogs.set(serverName, lines);\n\n stream.on('data', (chunk: Buffer) => {\n buffer += chunk.toString();\n const parts = buffer.split('\\n');\n // Last element is incomplete line (or empty if ended with \\n)\n buffer = parts.pop()!;\n for (const line of parts) {\n if (line.trim()) {\n lines.push(line);\n if (lines.length > MAX_STDERR_LINES) {\n lines.shift();\n }\n }\n }\n });\n\n stream.on('end', () => {\n if (buffer.trim()) {\n lines.push(buffer);\n if (lines.length > MAX_STDERR_LINES) {\n lines.shift();\n }\n }\n });\n }\n\n function createOAuthProvider(name: string, cfg: McpHttpServerConfig) {\n // Bare `url` entries get no eager provider — auth is provisioned lazily\n // when the user authenticates — unless a previous session already stored\n // OAuth state for this server, in which case the provider is needed to\n // attach the persisted tokens on connect.\n const oauth =\n cfg.oauth ?? (existsSync(getOAuthStoragePath(projectDir, name, cfg)) ? DEFAULT_OAUTH_CONFIG : undefined);\n if (!oauth) return undefined;\n\n // redirectUrl is optional in the user-supplied config; resolve the stable\n // default (or the `callbackPort` shorthand, for programmatically registered\n // servers that bypass config parsing) so provider metadata always carries\n // a concrete URL.\n const redirectUrl = resolveOAuthRedirectUrl(oauth);\n\n // Without a pre-registered clientId the client is identified by Mastra\n // Code's Client ID Metadata Document: the document URL is the client_id and\n // the authorization server fetches it, so nothing is registered per server.\n const clientInformation = oauth.clientId\n ? ({\n client_id: oauth.clientId,\n ...(oauth.clientSecret ? { client_secret: oauth.clientSecret } : {}),\n } satisfies OAuthClientInformation)\n : undefined;\n const clientMetadataUrl = clientInformation ? undefined : MASTRA_CODE_CLIENT_METADATA_URL;\n\n const { MCPOAuthClientProvider } = loadedMcpModule();\n return new MCPOAuthClientProvider({\n redirectUrl,\n clientMetadata: {\n ...(clientMetadataUrl ? { client_id: clientMetadataUrl } : {}),\n redirect_uris: [redirectUrl],\n client_name: oauth.clientName ?? (clientMetadataUrl ? 'Mastra Code' : `Mastra Code MCP ${name}`),\n grant_types: ['authorization_code', 'refresh_token'],\n response_types: ['code'],\n ...(oauth.scopes?.length ? { scope: oauth.scopes.join(' ') } : {}),\n },\n clientInformation,\n clientMetadataUrl,\n storage: new FileOAuthStorage(getOAuthStoragePath(projectDir, name, cfg)),\n onRedirectToAuthorization: url => {\n authUrlHandlers.get(name)?.(url.toString());\n },\n });\n }\n\n function buildServerDefs(servers: Record<string, McpServerConfig>): Record<string, MastraMCPServerDefinition> {\n const defs: Record<string, MastraMCPServerDefinition> = {};\n for (const [name, cfg] of Object.entries(servers)) {\n if ('url' in cfg) {\n const httpCfg = cfg as McpHttpServerConfig;\n defs[name] = {\n url: new URL(httpCfg.url),\n requestInit: httpCfg.headers ? { headers: httpCfg.headers } : undefined,\n authProvider: createOAuthProvider(name, httpCfg),\n };\n } else {\n defs[name] = {\n command: cfg.command,\n args: cfg.args,\n env: cfg.env,\n ...(cfg.cwd ? { cwd: cfg.cwd } : {}),\n stderr: 'pipe',\n };\n }\n }\n return defs;\n }\n\n /** Seed a `disabled` status for every disabled server so it stays visible. */\n function setDisabledStatuses(): void {\n for (const [name, cfg] of Object.entries(config.mcpServers ?? {})) {\n const scope = disabledScopeOf(name);\n if (!scope) continue;\n serverStatuses.set(name, {\n name,\n connected: false,\n toolCount: 0,\n toolNames: [],\n transport: getTransport(cfg),\n disabled: true,\n disabledScope: scope,\n });\n }\n }\n\n async function connectAndCollectTools(): Promise<void> {\n setDisabledStatuses();\n\n const servers = Object.fromEntries(Object.entries(config.mcpServers ?? {}).filter(([name]) => !isDisabled(name)));\n if (Object.keys(servers).length === 0) {\n return;\n }\n\n // Pre-populate statuses as \"connecting\" so callers can see in-progress state\n const serverNames = Object.keys(servers);\n for (const name of serverNames) {\n serverStatuses.set(name, {\n name,\n connected: false,\n connecting: true,\n toolCount: 0,\n toolNames: [],\n transport: getTransport(servers[name]!),\n });\n }\n\n const { MCPClient } = await loadMcpModule();\n serverDefs = buildServerDefs(servers);\n client = new MCPClient({\n id: 'mastra-code-mcp',\n servers: serverDefs,\n timeout: MASTRACODE_MCP_TIMEOUT_MS,\n });\n\n // Use listToolsetsWithErrors() to get tools grouped by server name,\n // plus per-server error messages for servers that failed to connect.\n\n try {\n const { toolsets, errors } = await client.listToolsetsWithErrors();\n const typedToolsets = toolsets as Record<string, Record<string, any>>;\n\n // Flatten toolsets into the namespaced tools map (serverName_toolName)\n for (const [serverName, serverTools] of Object.entries(typedToolsets)) {\n for (const [toolName, toolConfig] of Object.entries(serverTools)) {\n tools[`${serverName}_${toolName}`] = toolConfig;\n }\n }\n\n for (const name of serverNames) {\n const serverTools = typedToolsets[name];\n if (serverTools && Object.keys(serverTools).length > 0) {\n const toolNames = Object.keys(serverTools).map(t => `${name}_${t}`);\n serverStatuses.set(name, {\n name,\n connected: true,\n toolCount: toolNames.length,\n toolNames,\n transport: getTransport(servers[name]!),\n });\n } else {\n // Server failed — use the real error from listToolsetsWithErrors()\n const error = errors[name] ?? 'Failed to connect';\n serverStatuses.set(name, {\n name,\n connected: false,\n toolCount: 0,\n toolNames: [],\n transport: getTransport(servers[name]!),\n error,\n ...(serverNeedsAuth(name, servers[name]!, error) ? { needsAuth: true } : {}),\n });\n }\n }\n\n // Capture stderr from all stdio servers (connected or failed)\n for (const name of serverNames) {\n captureStderr(name);\n }\n } catch (error) {\n const errMsg = error instanceof Error ? error.message : String(error);\n\n for (const name of serverNames) {\n serverStatuses.set(name, {\n name,\n connected: false,\n toolCount: 0,\n toolNames: [],\n transport: getTransport(servers[name]!),\n error: errMsg,\n ...(serverNeedsAuth(name, servers[name]!, errMsg) ? { needsAuth: true } : {}),\n });\n }\n }\n }\n\n /**\n * Whether a failed HTTP server is blocked on OAuth authorization.\n *\n * Provider-backed servers report the exact state tracked by `@mastra/mcp`.\n * Bare `url` entries carry no provider until the user authenticates, so the\n * signal is a 401 in the connect error — surfaced either as the status text\n * or as the RFC 6750 `invalid_token` bearer error code in the response body.\n */\n function serverNeedsAuth(name: string, cfg: McpServerConfig, error?: string): boolean {\n if (getTransport(cfg) !== 'http') return false;\n if (client?.getServerAuthState?.(name) === 'needs-auth') return true;\n if (serverDefs[name]?.authProvider) return false;\n return error !== undefined && /\\b401\\b|unauthorized|invalid_token/i.test(error);\n }\n\n /**\n * Runs a single-server connect action (reconnect or authenticate), then\n * refreshes that server's tools and status from the client.\n */\n async function connectSingleServer(\n name: string,\n cfg: McpServerConfig,\n connect: () => Promise<unknown>,\n ): Promise<McpServerStatus> {\n const transport = getTransport(cfg);\n\n // Remove old tools for this server\n const prefix = `${name}_`;\n for (const key of Object.keys(tools)) {\n if (key.startsWith(prefix)) {\n delete tools[key];\n }\n }\n\n // Clear old logs and mark as connecting\n stderrLogs.delete(name);\n serverStatuses.set(name, {\n name,\n connected: false,\n connecting: true,\n toolCount: 0,\n toolNames: [],\n transport,\n });\n\n try {\n await connect();\n\n // Recapture stderr for the reconnected server\n captureStderr(name);\n\n // Fetch updated toolsets to get this server's tools\n const { toolsets, errors } = await client!.listToolsetsWithErrors();\n const serverTools = toolsets[name];\n const serverError = errors[name];\n\n if (serverError) {\n const status: McpServerStatus = {\n name,\n connected: false,\n toolCount: 0,\n toolNames: [],\n transport,\n error: serverError,\n ...(serverNeedsAuth(name, cfg, serverError) ? { needsAuth: true } : {}),\n };\n serverStatuses.set(name, status);\n return status;\n } else if (serverTools && Object.keys(serverTools).length > 0) {\n const toolNames = Object.keys(serverTools).map(t => `${name}_${t}`);\n for (const [toolName, toolConfig] of Object.entries(serverTools)) {\n tools[`${name}_${toolName}`] = toolConfig;\n }\n const status: McpServerStatus = {\n name,\n connected: true,\n toolCount: toolNames.length,\n toolNames,\n transport,\n };\n serverStatuses.set(name, status);\n return status;\n }\n const status: McpServerStatus = {\n name,\n connected: false,\n toolCount: 0,\n toolNames: [],\n transport,\n error: 'Failed to connect',\n };\n serverStatuses.set(name, status);\n return status;\n } catch (error) {\n const errMsg = error instanceof Error ? error.message : String(error);\n const status: McpServerStatus = {\n name,\n connected: false,\n toolCount: 0,\n toolNames: [],\n transport,\n error: errMsg,\n ...(serverNeedsAuth(name, cfg, errMsg) ? { needsAuth: true } : {}),\n };\n serverStatuses.set(name, status);\n return status;\n }\n }\n\n async function disconnect(): Promise<void> {\n if (client) {\n try {\n await client.disconnect();\n } catch {\n // Ignore disconnect errors\n }\n client = null;\n }\n }\n\n /** Tear down all connections and reconnect every enabled server. */\n async function rebuildConnections(): Promise<void> {\n await disconnect();\n tools = {};\n serverStatuses = new Map();\n stderrLogs = new Map();\n initialized = false;\n await connectAndCollectTools();\n initialized = true;\n }\n\n function disabledStatus(name: string): McpServerStatus {\n const cfg = config.mcpServers?.[name];\n return {\n name,\n connected: false,\n toolCount: 0,\n toolNames: [],\n transport: cfg ? getTransport(cfg) : 'stdio',\n disabled: true,\n disabledScope: disabledScopeOf(name),\n };\n }\n\n // Read-merge-write persistence: re-read the persisted state and apply this\n // operation's delta on top, then adopt the merged result in memory. This\n // way a concurrent mastracode process's changes (e.g. another window\n // flipping the global kill switch) are never clobbered by this manager's\n // construction-time snapshot.\n function persistProjectDelta(mutate: (overrides: Map<string, McpProjectServerOverride>) => void): void {\n const fresh = new Map<string, McpProjectServerOverride>(Object.entries(loadProjectServerOverrides(projectDir)));\n mutate(fresh);\n projectServerOverrides = fresh;\n saveProjectServerOverrides(projectDir, Object.fromEntries(fresh));\n }\n\n function persistGlobalDelta(mutate: (state: { allDisabled: boolean; disabledServers: Set<string> }) => void): void {\n const onDisk = loadGlobalDisableState();\n const fresh = { allDisabled: onDisk.allDisabled, disabledServers: new Set(onDisk.disabledServers) };\n mutate(fresh);\n globallyDisabledServers = fresh.disabledServers;\n globalDisableState = { allDisabled: fresh.allDisabled, disabledServers: Array.from(fresh.disabledServers) };\n saveGlobalDisableState(globalDisableState);\n }\n\n return {\n async init() {\n if (initialized) return;\n await connectAndCollectTools();\n initialized = true;\n },\n\n async initInBackground(): Promise<McpInitResult> {\n await this.init();\n const statuses = Array.from(serverStatuses.values(), withManagerState);\n const connected = statuses.filter(s => s.connected);\n const failed = statuses.filter(s => !s.connected && !s.disabled);\n return {\n connected,\n failed,\n skipped: [...(config.skippedServers ?? [])],\n totalTools: connected.reduce((sum, s) => sum + s.toolCount, 0),\n };\n },\n\n async reload() {\n config = applyExtraServers(loadMcpConfig(projectDir, configDirName, externalDiscovery));\n projectServerOverrides = new Map(Object.entries(loadProjectServerOverrides(projectDir)));\n globalDisableState = loadGlobalDisableState();\n globallyDisabledServers = new Set(globalDisableState.disabledServers);\n await rebuildConnections();\n },\n\n async setServerDisabled(name: string, disabled: boolean, options?: { global?: boolean }): Promise<McpServerStatus> {\n if (!config.mcpServers?.[name]) {\n return {\n name,\n connected: false,\n toolCount: 0,\n toolNames: [],\n transport: 'stdio',\n error: `Server \"${name}\" not found in config`,\n };\n }\n\n const wasEffectivelyDisabled = isDisabled(name);\n\n if (options?.global) {\n persistGlobalDelta(state => {\n if (disabled) {\n state.disabledServers.add(name);\n } else {\n state.disabledServers.delete(name);\n }\n });\n } else {\n persistProjectDelta(overrides => {\n overrides.set(name, disabled ? 'disabled' : 'enabled');\n });\n }\n\n // Only rebuild connections when the server's effective state actually\n // flipped. State changes that only alter an inherited default or an\n // override beneath the global kill switch leave connections alone.\n if (isDisabled(name) !== wasEffectivelyDisabled) {\n await rebuildConnections();\n return withManagerState(serverStatuses.get(name) ?? disabledStatus(name));\n }\n return withManagerState(\n isDisabled(name) ? disabledStatus(name) : (serverStatuses.get(name) ?? disabledStatus(name)),\n );\n },\n\n async inheritServer(name: string): Promise<McpServerStatus> {\n if (!config.mcpServers?.[name]) {\n return {\n name,\n connected: false,\n toolCount: 0,\n toolNames: [],\n transport: 'stdio',\n error: `Server \"${name}\" not found in config`,\n };\n }\n\n const wasEffectivelyDisabled = isDisabled(name);\n persistProjectDelta(overrides => {\n overrides.delete(name);\n });\n if (isDisabled(name) !== wasEffectivelyDisabled) {\n await rebuildConnections();\n }\n return withManagerState(\n isDisabled(name) ? disabledStatus(name) : (serverStatuses.get(name) ?? disabledStatus(name)),\n );\n },\n\n async setAllDisabled(disabled: boolean, options?: { global?: boolean }): Promise<void> {\n const configuredNames = Object.keys(config.mcpServers ?? {});\n const effectiveBefore = configuredNames.filter(name => isDisabled(name)).join(',');\n if (options?.global) {\n persistGlobalDelta(state => {\n state.allDisabled = disabled;\n if (!disabled) {\n // Enabling globally also clears globally disabled server names so\n // \"/mcp enable all --global\" fully restores global defaults.\n state.disabledServers.clear();\n }\n });\n } else {\n persistProjectDelta(overrides => {\n for (const name of configuredNames) {\n overrides.set(name, disabled ? 'disabled' : 'enabled');\n }\n });\n }\n const effectiveAfter = configuredNames.filter(name => isDisabled(name)).join(',');\n if (effectiveAfter !== effectiveBefore) {\n await rebuildConnections();\n }\n },\n\n async inheritAllServers(): Promise<void> {\n const configuredNames = Object.keys(config.mcpServers ?? {});\n const effectiveBefore = configuredNames.filter(name => isDisabled(name)).join(',');\n persistProjectDelta(overrides => {\n overrides.clear();\n });\n const effectiveAfter = configuredNames.filter(name => isDisabled(name)).join(',');\n if (effectiveAfter !== effectiveBefore) {\n await rebuildConnections();\n }\n },\n\n getDisabledServers() {\n return Object.keys(config.mcpServers ?? {})\n .filter(name => isDisabled(name))\n .sort();\n },\n\n isAllDisabledGlobally() {\n return globalDisableState.allDisabled;\n },\n\n async reconnectServer(name: string): Promise<McpServerStatus> {\n if (isDisabled(name)) {\n return { ...disabledStatus(name), error: `Server \"${name}\" is disabled — enable it first` };\n }\n const cfg = config.mcpServers?.[name];\n if (!cfg) {\n return {\n name,\n connected: false,\n toolCount: 0,\n toolNames: [],\n transport: 'stdio',\n error: `Server \"${name}\" not found in config`,\n };\n }\n\n if (!client) {\n return {\n name,\n connected: false,\n toolCount: 0,\n toolNames: [],\n transport: getTransport(cfg),\n error: 'MCP client not initialized',\n };\n }\n\n // Use MCPClient's per-server reconnect\n return connectSingleServer(name, cfg, () => client!.reconnectServer(name));\n },\n\n async authenticateServer(\n name: string,\n options?: { onAuthorizationUrl?: (url: string) => void; timeoutMs?: number },\n ): Promise<McpServerStatus> {\n const cfg = config.mcpServers?.[name];\n if (!cfg) {\n return {\n name,\n connected: false,\n toolCount: 0,\n toolNames: [],\n transport: 'stdio',\n error: `Server \"${name}\" not found in config`,\n };\n }\n\n if (isDisabled(name)) {\n return { ...disabledStatus(name), error: `Server \"${name}\" is disabled — enable it first` };\n }\n\n if (!client) {\n return {\n name,\n connected: false,\n toolCount: 0,\n toolNames: [],\n transport: getTransport(cfg),\n error: 'MCP client not initialized',\n };\n }\n\n if (getTransport(cfg) !== 'http') {\n return {\n name,\n connected: false,\n toolCount: 0,\n toolNames: [],\n transport: 'stdio',\n error: `Server \"${name}\" uses stdio transport, which does not support OAuth`,\n };\n }\n\n // Zero-config provisioning: a bare `url` entry gets a provider with the\n // default redirect URL the first time the user authenticates. The Client\n // ID Metadata Document takes care of the client identity.\n //\n // NOTE: `serverDefs[name]` is the same object reference the MCPClient was\n // constructed with, and connectHttp reads `authProvider` live off it at\n // connect time, so mutating it here reaches the already-created client.\n // If MCPClient ever defensively copies its server config, zero-config auth\n // would need an explicit \"set this server's provider\" API instead.\n const def = serverDefs[name];\n if (def?.url && !def.authProvider) {\n def.authProvider = createOAuthProvider(name, { ...(cfg as McpHttpServerConfig), oauth: DEFAULT_OAUTH_CONFIG });\n }\n\n // Reject a concurrent second attempt for the same server. authUrlHandlers\n // has a single slot per server, so a second call with an onAuthorizationUrl\n // would overwrite the first caller's handler (which then never sees the\n // URL) and its finally would delete the handler out from under the other\n // in-flight call. Gate on authenticatingServers rather than authUrlHandlers\n // so callers without a URL handler are caught too. The underlying\n // client.authenticate already coalesces same-server calls into one flow.\n if (authenticatingServers.has(name)) {\n const current = serverStatuses.get(name);\n return {\n name,\n connected: current?.connected ?? false,\n connecting: current?.connecting,\n needsAuth: current?.needsAuth,\n toolCount: current?.toolCount ?? 0,\n toolNames: current?.toolNames ?? [],\n transport: current?.transport ?? getTransport(cfg),\n error: `Authentication for \"${name}\" is already in progress`,\n };\n }\n\n if (options?.onAuthorizationUrl) {\n authUrlHandlers.set(name, options.onAuthorizationUrl);\n }\n authenticatingServers.add(name);\n cancelledAuthServers.delete(name);\n try {\n const result = await connectSingleServer(name, cfg, () =>\n client!.authenticate(name, options?.timeoutMs === undefined ? undefined : { timeoutMs: options.timeoutMs }),\n );\n // A cancelled flow resolves with a failed status; mark it so callers can\n // distinguish a deliberate cancel from a genuine authentication failure.\n // Write the marker back to the durable status map (not just the returned\n // value) so a selector reopened after cancellation still sees it.\n const finalStatus =\n cancelledAuthServers.has(name) && !result.connected ? { ...result, cancelled: true } : result;\n serverStatuses.set(name, finalStatus);\n return finalStatus;\n } finally {\n authUrlHandlers.delete(name);\n authenticatingServers.delete(name);\n cancelledAuthServers.delete(name);\n }\n },\n\n async cancelServerAuthentication(name: string): Promise<boolean> {\n if (!client) {\n return false;\n }\n // Record the intent before aborting so the resolving authenticateServer()\n // call can tag its failed status as cancelled rather than failed.\n cancelledAuthServers.add(name);\n const cancelled = await client.cancelAuthentication(name);\n if (!cancelled) {\n cancelledAuthServers.delete(name);\n }\n return cancelled;\n },\n\n disconnect,\n\n getTools() {\n return { ...tools };\n },\n\n hasServers() {\n const hasConfigured = config.mcpServers !== undefined && Object.keys(config.mcpServers).length > 0;\n const hasSkipped = config.skippedServers !== undefined && config.skippedServers.length > 0;\n return hasConfigured || hasSkipped;\n },\n\n getServerStatuses() {\n return Array.from(serverStatuses.values(), withManagerState);\n },\n\n getSkippedServers() {\n return [...(config.skippedServers ?? [])];\n },\n\n getConfigPaths() {\n return {\n project: getProjectMcpPath(projectDir, configDirName),\n global: getGlobalMcpPath(configDirName),\n claude: getClaudeSettingsPath(projectDir),\n };\n },\n\n getConfig() {\n return config;\n },\n\n getServerLogs(name: string) {\n return [...(stderrLogs.get(name) ?? [])];\n },\n };\n}\n"],"mappings":";;;;;;;;;;;AAoCA,MAAM,4BAA4B;AAsFlC,SAAS,aAAa,KAAwC;CAC5D,OAAO,SAAS,MAAM,SAAS;AACjC;AAEA,IAAM,mBAAN,MAA+C;CACzB;CAApB,YAAY,UAA0B;EAAlB,KAAA,WAAA;CAAmB;CAEvC,IAAI,KAAiC;EACnC,OAAO,KAAK,KAAK,CAAC,CAAC;CACrB;CAEA,IAAI,KAAa,OAAqB;EACpC,MAAM,OAAO,KAAK,KAAK;EACvB,KAAK,OAAO;EACZ,KAAK,MAAM,IAAI;CACjB;CAEA,OAAO,KAAmB;EACxB,MAAM,OAAO,KAAK,KAAK;EACvB,OAAO,KAAK;EACZ,KAAK,MAAM,IAAI;CACjB;CAEA,OAAuC;EACrC,IAAI,CAAC,WAAW,KAAK,QAAQ,GAAG,OAAO,CAAC;EACxC,IAAI;GACF,OAAO,KAAK,MAAM,aAAa,KAAK,UAAU,OAAO,CAAC;EACxD,QAAQ;GACN,OAAO,CAAC;EACV;CACF;CAEA,MAAc,MAAoC;EAChD,MAAM,MAAM,QAAQ,KAAK,QAAQ;EACjC,IAAI,CAAC,WAAW,GAAG,GACjB,UAAU,KAAK;GAAE,WAAW;GAAM,MAAM;EAAM,CAAC;EAEjD,MAAM,UAAU,GAAG,KAAK,SAAS;EACjC,cAAc,SAAS,KAAK,UAAU,MAAM,MAAM,CAAC,GAAG;GAAE,UAAU;GAAS,MAAM;EAAM,CAAC;EACxF,WAAW,SAAS,KAAK,QAAQ;CACnC;AACF;;;;;;AAOA,MAAM,uBAA2C,EAAE,aAAa,2BAA2B;AAE3F,SAAS,oBAAoB,YAAoB,MAAc,KAAkC;CAG/F,MAAM,MAAM,KAAK,UAAU;EACzB;EACA;EACA,KAAK,IAAI;EACT,aAAa,wBAAwB,IAAI,KAAK;EAC9C,UAAU,IAAI,OAAO;EACrB,QAAQ,IAAI,OAAO,UAAU,CAAC;CAChC,CAAC;CACD,OAAO,KAAK,cAAc,GAAG,aAAa,GAAG,yBAAyB,GAAG,EAAE,MAAM;AACnF;AAEA,SAAS,yBAAyB,OAAuB;CACvD,IAAI,cAAc;CAClB,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK,GAAG;EACxC,eAAe,OAAO,MAAM,WAAW,CAAC,CAAC;EACzC,cAAc,OAAO,QAAQ,IAAI,cAAc,cAAc;CAC/D;CACA,OAAO,YAAY,SAAS,EAAE,CAAC,CAAC,SAAS,IAAI,GAAG;AAClD;AAGA,IAAI;;AAGJ,eAAe,gBAAoC;CACjD,cAAc,MAAM,OAAO;CAC3B,OAAO;AACT;;AAGA,SAAS,kBAA6B;CACpC,IAAI,CAAC,WAAW,MAAM,IAAI,MAAM,+BAA+B;CAC/D,OAAO;AACT;;;;;AAMA,SAAgB,iBACd,YACA,gBAAgB,oBAChB,cACA,mBACY;;CAEZ,MAAM,qBAAqB,SAA+B;EACxD,IAAI,CAAC,gBAAgB,OAAO,KAAK,YAAY,CAAC,CAAC,WAAW,GAAG,OAAO;EACpE,OAAO;GAAE,GAAG;GAAM,YAAY;IAAE,GAAG,KAAK;IAAY,GAAG;GAAa;EAAE;CACxE;CAEA,IAAI,SAAS,kBAAkB,cAAc,YAAY,eAAe,iBAAiB,CAAC;CAC1F,IAAI,yBAAyB,IAAI,IAC/B,OAAO,QAAQ,2BAA2B,UAAU,CAAC,CACvD;CACA,IAAI,qBAAqB,uBAAuB;CAChD,IAAI,0BAA0B,IAAI,IAAI,mBAAmB,eAAe;;CAGxE,MAAM,cAAc,SAA0B;EAC5C,IAAI,mBAAmB,aAAa,OAAO;EAC3C,MAAM,kBAAkB,uBAAuB,IAAI,IAAI;EACvD,IAAI,iBAAiB,OAAO,oBAAoB;EAChD,OAAO,wBAAwB,IAAI,IAAI;CACzC;;CAGA,MAAM,mBAAmB,SAAmD;EAC1E,IAAI,mBAAmB,aAAa,OAAO;EAC3C,MAAM,kBAAkB,uBAAuB,IAAI,IAAI;EACvD,IAAI,oBAAoB,YAAY,OAAO;EAC3C,IAAI,CAAC,mBAAmB,wBAAwB,IAAI,IAAI,GAAG,OAAO;CAEpE;CACA,IAAI,SAA2B;CAC/B,IAAI,aAAwD,CAAC;CAC7D,IAAI,QAA6B,CAAC;CAClC,IAAI,iCAAiB,IAAI,IAA6B;CACtD,IAAI,6BAAa,IAAI,IAAsB;CAC3C,IAAI,cAAc;;CAGlB,MAAM,kCAAkB,IAAI,IAAmC;;;;;;;CAQ/D,MAAM,wCAAwB,IAAI,IAAY;;;;;;;;CAS9C,MAAM,uCAAuB,IAAI,IAAY;;CAG7C,MAAM,oBAAoB,YAA8C;EACtE,GAAG;EACH,GAAI,sBAAsB,IAAI,OAAO,IAAI,IAAI,EAAE,gBAAgB,KAAK,IAAI,CAAC;EACzE,GAAI,uBAAuB,IAAI,OAAO,IAAI,IAAI,EAAE,iBAAiB,uBAAuB,IAAI,OAAO,IAAI,EAAE,IAAI,CAAC;EAC9G,eAAe,wBAAwB,IAAI,OAAO,IAAI,IAAI,aAAa;EACvE,kBAAkB,mBAAmB;CACvC;CAEA,MAAM,mBAAmB;;CAGzB,SAAS,cAAc,YAA0B;EAC/C,IAAI,CAAC,UAAU,OAAO,OAAO,oBAAoB,YAAY;EAC7D,MAAM,SAAS,OAAO,gBAAgB,UAAU;EAChD,IAAI,CAAC,QAAQ;EAEb,IAAI,SAAS;EACb,MAAM,QAAQ,WAAW,IAAI,UAAU,KAAK,CAAC;EAC7C,WAAW,IAAI,YAAY,KAAK;EAEhC,OAAO,GAAG,SAAS,UAAkB;GACnC,UAAU,MAAM,SAAS;GACzB,MAAM,QAAQ,OAAO,MAAM,IAAI;GAE/B,SAAS,MAAM,IAAI;GACnB,KAAK,MAAM,QAAQ,OACjB,IAAI,KAAK,KAAK,GAAG;IACf,MAAM,KAAK,IAAI;IACf,IAAI,MAAM,SAAS,kBACjB,MAAM,MAAM;GAEhB;EAEJ,CAAC;EAED,OAAO,GAAG,aAAa;GACrB,IAAI,OAAO,KAAK,GAAG;IACjB,MAAM,KAAK,MAAM;IACjB,IAAI,MAAM,SAAS,kBACjB,MAAM,MAAM;GAEhB;EACF,CAAC;CACH;CAEA,SAAS,oBAAoB,MAAc,KAA0B;EAKnE,MAAM,QACJ,IAAI,UAAU,WAAW,oBAAoB,YAAY,MAAM,GAAG,CAAC,IAAI,uBAAuB,KAAA;EAChG,IAAI,CAAC,OAAO,OAAO,KAAA;EAMnB,MAAM,cAAc,wBAAwB,KAAK;EAKjD,MAAM,oBAAoB,MAAM,WAC3B;GACC,WAAW,MAAM;GACjB,GAAI,MAAM,eAAe,EAAE,eAAe,MAAM,aAAa,IAAI,CAAC;EACpE,IACA,KAAA;EACJ,MAAM,oBAAoB,oBAAoB,KAAA,IAAY;EAE1D,MAAM,EAAE,2BAA2B,gBAAgB;EACnD,OAAO,IAAI,uBAAuB;GAChC;GACA,gBAAgB;IACd,GAAI,oBAAoB,EAAE,WAAW,kBAAkB,IAAI,CAAC;IAC5D,eAAe,CAAC,WAAW;IAC3B,aAAa,MAAM,eAAe,oBAAoB,gBAAgB,mBAAmB;IACzF,aAAa,CAAC,sBAAsB,eAAe;IACnD,gBAAgB,CAAC,MAAM;IACvB,GAAI,MAAM,QAAQ,SAAS,EAAE,OAAO,MAAM,OAAO,KAAK,GAAG,EAAE,IAAI,CAAC;GAClE;GACA;GACA;GACA,SAAS,IAAI,iBAAiB,oBAAoB,YAAY,MAAM,GAAG,CAAC;GACxE,4BAA2B,QAAO;IAChC,gBAAgB,IAAI,IAAI,CAAC,GAAG,IAAI,SAAS,CAAC;GAC5C;EACF,CAAC;CACH;CAEA,SAAS,gBAAgB,SAAqF;EAC5G,MAAM,OAAkD,CAAC;EACzD,KAAK,MAAM,CAAC,MAAM,QAAQ,OAAO,QAAQ,OAAO,GAC9C,IAAI,SAAS,KAAK;GAChB,MAAM,UAAU;GAChB,KAAK,QAAQ;IACX,KAAK,IAAI,IAAI,QAAQ,GAAG;IACxB,aAAa,QAAQ,UAAU,EAAE,SAAS,QAAQ,QAAQ,IAAI,KAAA;IAC9D,cAAc,oBAAoB,MAAM,OAAO;GACjD;EACF,OACE,KAAK,QAAQ;GACX,SAAS,IAAI;GACb,MAAM,IAAI;GACV,KAAK,IAAI;GACT,GAAI,IAAI,MAAM,EAAE,KAAK,IAAI,IAAI,IAAI,CAAC;GAClC,QAAQ;EACV;EAGJ,OAAO;CACT;;CAGA,SAAS,sBAA4B;EACnC,KAAK,MAAM,CAAC,MAAM,QAAQ,OAAO,QAAQ,OAAO,cAAc,CAAC,CAAC,GAAG;GACjE,MAAM,QAAQ,gBAAgB,IAAI;GAClC,IAAI,CAAC,OAAO;GACZ,eAAe,IAAI,MAAM;IACvB;IACA,WAAW;IACX,WAAW;IACX,WAAW,CAAC;IACZ,WAAW,aAAa,GAAG;IAC3B,UAAU;IACV,eAAe;GACjB,CAAC;EACH;CACF;CAEA,eAAe,yBAAwC;EACrD,oBAAoB;EAEpB,MAAM,UAAU,OAAO,YAAY,OAAO,QAAQ,OAAO,cAAc,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,WAAW,IAAI,CAAC,CAAC;EAChH,IAAI,OAAO,KAAK,OAAO,CAAC,CAAC,WAAW,GAClC;EAIF,MAAM,cAAc,OAAO,KAAK,OAAO;EACvC,KAAK,MAAM,QAAQ,aACjB,eAAe,IAAI,MAAM;GACvB;GACA,WAAW;GACX,YAAY;GACZ,WAAW;GACX,WAAW,CAAC;GACZ,WAAW,aAAa,QAAQ,KAAM;EACxC,CAAC;EAGH,MAAM,EAAE,cAAc,MAAM,cAAc;EAC1C,aAAa,gBAAgB,OAAO;EACpC,SAAS,IAAI,UAAU;GACrB,IAAI;GACJ,SAAS;GACT,SAAS;EACX,CAAC;EAKD,IAAI;GACF,MAAM,EAAE,UAAU,WAAW,MAAM,OAAO,uBAAuB;GACjE,MAAM,gBAAgB;GAGtB,KAAK,MAAM,CAAC,YAAY,gBAAgB,OAAO,QAAQ,aAAa,GAClE,KAAK,MAAM,CAAC,UAAU,eAAe,OAAO,QAAQ,WAAW,GAC7D,MAAM,GAAG,WAAW,GAAG,cAAc;GAIzC,KAAK,MAAM,QAAQ,aAAa;IAC9B,MAAM,cAAc,cAAc;IAClC,IAAI,eAAe,OAAO,KAAK,WAAW,CAAC,CAAC,SAAS,GAAG;KACtD,MAAM,YAAY,OAAO,KAAK,WAAW,CAAC,CAAC,KAAI,MAAK,GAAG,KAAK,GAAG,GAAG;KAClE,eAAe,IAAI,MAAM;MACvB;MACA,WAAW;MACX,WAAW,UAAU;MACrB;MACA,WAAW,aAAa,QAAQ,KAAM;KACxC,CAAC;IACH,OAAO;KAEL,MAAM,QAAQ,OAAO,SAAS;KAC9B,eAAe,IAAI,MAAM;MACvB;MACA,WAAW;MACX,WAAW;MACX,WAAW,CAAC;MACZ,WAAW,aAAa,QAAQ,KAAM;MACtC;MACA,GAAI,gBAAgB,MAAM,QAAQ,OAAQ,KAAK,IAAI,EAAE,WAAW,KAAK,IAAI,CAAC;KAC5E,CAAC;IACH;GACF;GAGA,KAAK,MAAM,QAAQ,aACjB,cAAc,IAAI;EAEtB,SAAS,OAAO;GACd,MAAM,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;GAEpE,KAAK,MAAM,QAAQ,aACjB,eAAe,IAAI,MAAM;IACvB;IACA,WAAW;IACX,WAAW;IACX,WAAW,CAAC;IACZ,WAAW,aAAa,QAAQ,KAAM;IACtC,OAAO;IACP,GAAI,gBAAgB,MAAM,QAAQ,OAAQ,MAAM,IAAI,EAAE,WAAW,KAAK,IAAI,CAAC;GAC7E,CAAC;EAEL;CACF;;;;;;;;;CAUA,SAAS,gBAAgB,MAAc,KAAsB,OAAyB;EACpF,IAAI,aAAa,GAAG,MAAM,QAAQ,OAAO;EACzC,IAAI,QAAQ,qBAAqB,IAAI,MAAM,cAAc,OAAO;EAChE,IAAI,WAAW,KAAK,EAAE,cAAc,OAAO;EAC3C,OAAO,UAAU,KAAA,KAAa,sCAAsC,KAAK,KAAK;CAChF;;;;;CAMA,eAAe,oBACb,MACA,KACA,SAC0B;EAC1B,MAAM,YAAY,aAAa,GAAG;EAGlC,MAAM,SAAS,GAAG,KAAK;EACvB,KAAK,MAAM,OAAO,OAAO,KAAK,KAAK,GACjC,IAAI,IAAI,WAAW,MAAM,GACvB,OAAO,MAAM;EAKjB,WAAW,OAAO,IAAI;EACtB,eAAe,IAAI,MAAM;GACvB;GACA,WAAW;GACX,YAAY;GACZ,WAAW;GACX,WAAW,CAAC;GACZ;EACF,CAAC;EAED,IAAI;GACF,MAAM,QAAQ;GAGd,cAAc,IAAI;GAGlB,MAAM,EAAE,UAAU,WAAW,MAAM,OAAQ,uBAAuB;GAClE,MAAM,cAAc,SAAS;GAC7B,MAAM,cAAc,OAAO;GAE3B,IAAI,aAAa;IACf,MAAM,SAA0B;KAC9B;KACA,WAAW;KACX,WAAW;KACX,WAAW,CAAC;KACZ;KACA,OAAO;KACP,GAAI,gBAAgB,MAAM,KAAK,WAAW,IAAI,EAAE,WAAW,KAAK,IAAI,CAAC;IACvE;IACA,eAAe,IAAI,MAAM,MAAM;IAC/B,OAAO;GACT,OAAO,IAAI,eAAe,OAAO,KAAK,WAAW,CAAC,CAAC,SAAS,GAAG;IAC7D,MAAM,YAAY,OAAO,KAAK,WAAW,CAAC,CAAC,KAAI,MAAK,GAAG,KAAK,GAAG,GAAG;IAClE,KAAK,MAAM,CAAC,UAAU,eAAe,OAAO,QAAQ,WAAW,GAC7D,MAAM,GAAG,KAAK,GAAG,cAAc;IAEjC,MAAM,SAA0B;KAC9B;KACA,WAAW;KACX,WAAW,UAAU;KACrB;KACA;IACF;IACA,eAAe,IAAI,MAAM,MAAM;IAC/B,OAAO;GACT;GACA,MAAM,SAA0B;IAC9B;IACA,WAAW;IACX,WAAW;IACX,WAAW,CAAC;IACZ;IACA,OAAO;GACT;GACA,eAAe,IAAI,MAAM,MAAM;GAC/B,OAAO;EACT,SAAS,OAAO;GACd,MAAM,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;GACpE,MAAM,SAA0B;IAC9B;IACA,WAAW;IACX,WAAW;IACX,WAAW,CAAC;IACZ;IACA,OAAO;IACP,GAAI,gBAAgB,MAAM,KAAK,MAAM,IAAI,EAAE,WAAW,KAAK,IAAI,CAAC;GAClE;GACA,eAAe,IAAI,MAAM,MAAM;GAC/B,OAAO;EACT;CACF;CAEA,eAAe,aAA4B;EACzC,IAAI,QAAQ;GACV,IAAI;IACF,MAAM,OAAO,WAAW;GAC1B,QAAQ,CAER;GACA,SAAS;EACX;CACF;;CAGA,eAAe,qBAAoC;EACjD,MAAM,WAAW;EACjB,QAAQ,CAAC;EACT,iCAAiB,IAAI,IAAI;EACzB,6BAAa,IAAI,IAAI;EACrB,cAAc;EACd,MAAM,uBAAuB;EAC7B,cAAc;CAChB;CAEA,SAAS,eAAe,MAA+B;EACrD,MAAM,MAAM,OAAO,aAAa;EAChC,OAAO;GACL;GACA,WAAW;GACX,WAAW;GACX,WAAW,CAAC;GACZ,WAAW,MAAM,aAAa,GAAG,IAAI;GACrC,UAAU;GACV,eAAe,gBAAgB,IAAI;EACrC;CACF;CAOA,SAAS,oBAAoB,QAA0E;EACrG,MAAM,QAAQ,IAAI,IAAsC,OAAO,QAAQ,2BAA2B,UAAU,CAAC,CAAC;EAC9G,OAAO,KAAK;EACZ,yBAAyB;EACzB,2BAA2B,YAAY,OAAO,YAAY,KAAK,CAAC;CAClE;CAEA,SAAS,mBAAmB,QAAuF;EACjH,MAAM,SAAS,uBAAuB;EACtC,MAAM,QAAQ;GAAE,aAAa,OAAO;GAAa,iBAAiB,IAAI,IAAI,OAAO,eAAe;EAAE;EAClG,OAAO,KAAK;EACZ,0BAA0B,MAAM;EAChC,qBAAqB;GAAE,aAAa,MAAM;GAAa,iBAAiB,MAAM,KAAK,MAAM,eAAe;EAAE;EAC1G,uBAAuB,kBAAkB;CAC3C;CAEA,OAAO;EACL,MAAM,OAAO;GACX,IAAI,aAAa;GACjB,MAAM,uBAAuB;GAC7B,cAAc;EAChB;EAEA,MAAM,mBAA2C;GAC/C,MAAM,KAAK,KAAK;GAChB,MAAM,WAAW,MAAM,KAAK,eAAe,OAAO,GAAG,gBAAgB;GACrE,MAAM,YAAY,SAAS,QAAO,MAAK,EAAE,SAAS;GAElD,OAAO;IACL;IACA,QAHa,SAAS,QAAO,MAAK,CAAC,EAAE,aAAa,CAAC,EAAE,QAGhD;IACL,SAAS,CAAC,GAAI,OAAO,kBAAkB,CAAC,CAAE;IAC1C,YAAY,UAAU,QAAQ,KAAK,MAAM,MAAM,EAAE,WAAW,CAAC;GAC/D;EACF;EAEA,MAAM,SAAS;GACb,SAAS,kBAAkB,cAAc,YAAY,eAAe,iBAAiB,CAAC;GACtF,yBAAyB,IAAI,IAAI,OAAO,QAAQ,2BAA2B,UAAU,CAAC,CAAC;GACvF,qBAAqB,uBAAuB;GAC5C,0BAA0B,IAAI,IAAI,mBAAmB,eAAe;GACpE,MAAM,mBAAmB;EAC3B;EAEA,MAAM,kBAAkB,MAAc,UAAmB,SAA0D;GACjH,IAAI,CAAC,OAAO,aAAa,OACvB,OAAO;IACL;IACA,WAAW;IACX,WAAW;IACX,WAAW,CAAC;IACZ,WAAW;IACX,OAAO,WAAW,KAAK;GACzB;GAGF,MAAM,yBAAyB,WAAW,IAAI;GAE9C,IAAI,SAAS,QACX,oBAAmB,UAAS;IAC1B,IAAI,UACF,MAAM,gBAAgB,IAAI,IAAI;SAE9B,MAAM,gBAAgB,OAAO,IAAI;GAErC,CAAC;QAED,qBAAoB,cAAa;IAC/B,UAAU,IAAI,MAAM,WAAW,aAAa,SAAS;GACvD,CAAC;GAMH,IAAI,WAAW,IAAI,MAAM,wBAAwB;IAC/C,MAAM,mBAAmB;IACzB,OAAO,iBAAiB,eAAe,IAAI,IAAI,KAAK,eAAe,IAAI,CAAC;GAC1E;GACA,OAAO,iBACL,WAAW,IAAI,IAAI,eAAe,IAAI,IAAK,eAAe,IAAI,IAAI,KAAK,eAAe,IAAI,CAC5F;EACF;EAEA,MAAM,cAAc,MAAwC;GAC1D,IAAI,CAAC,OAAO,aAAa,OACvB,OAAO;IACL;IACA,WAAW;IACX,WAAW;IACX,WAAW,CAAC;IACZ,WAAW;IACX,OAAO,WAAW,KAAK;GACzB;GAGF,MAAM,yBAAyB,WAAW,IAAI;GAC9C,qBAAoB,cAAa;IAC/B,UAAU,OAAO,IAAI;GACvB,CAAC;GACD,IAAI,WAAW,IAAI,MAAM,wBACvB,MAAM,mBAAmB;GAE3B,OAAO,iBACL,WAAW,IAAI,IAAI,eAAe,IAAI,IAAK,eAAe,IAAI,IAAI,KAAK,eAAe,IAAI,CAC5F;EACF;EAEA,MAAM,eAAe,UAAmB,SAA+C;GACrF,MAAM,kBAAkB,OAAO,KAAK,OAAO,cAAc,CAAC,CAAC;GAC3D,MAAM,kBAAkB,gBAAgB,QAAO,SAAQ,WAAW,IAAI,CAAC,CAAC,CAAC,KAAK,GAAG;GACjF,IAAI,SAAS,QACX,oBAAmB,UAAS;IAC1B,MAAM,cAAc;IACpB,IAAI,CAAC,UAGH,MAAM,gBAAgB,MAAM;GAEhC,CAAC;QAED,qBAAoB,cAAa;IAC/B,KAAK,MAAM,QAAQ,iBACjB,UAAU,IAAI,MAAM,WAAW,aAAa,SAAS;GAEzD,CAAC;GAGH,IADuB,gBAAgB,QAAO,SAAQ,WAAW,IAAI,CAAC,CAAC,CAAC,KAAK,GAC5D,MAAM,iBACrB,MAAM,mBAAmB;EAE7B;EAEA,MAAM,oBAAmC;GACvC,MAAM,kBAAkB,OAAO,KAAK,OAAO,cAAc,CAAC,CAAC;GAC3D,MAAM,kBAAkB,gBAAgB,QAAO,SAAQ,WAAW,IAAI,CAAC,CAAC,CAAC,KAAK,GAAG;GACjF,qBAAoB,cAAa;IAC/B,UAAU,MAAM;GAClB,CAAC;GAED,IADuB,gBAAgB,QAAO,SAAQ,WAAW,IAAI,CAAC,CAAC,CAAC,KAAK,GAC5D,MAAM,iBACrB,MAAM,mBAAmB;EAE7B;EAEA,qBAAqB;GACnB,OAAO,OAAO,KAAK,OAAO,cAAc,CAAC,CAAC,CAAC,CACxC,QAAO,SAAQ,WAAW,IAAI,CAAC,CAAC,CAChC,KAAK;EACV;EAEA,wBAAwB;GACtB,OAAO,mBAAmB;EAC5B;EAEA,MAAM,gBAAgB,MAAwC;GAC5D,IAAI,WAAW,IAAI,GACjB,OAAO;IAAE,GAAG,eAAe,IAAI;IAAG,OAAO,WAAW,KAAK;GAAiC;GAE5F,MAAM,MAAM,OAAO,aAAa;GAChC,IAAI,CAAC,KACH,OAAO;IACL;IACA,WAAW;IACX,WAAW;IACX,WAAW,CAAC;IACZ,WAAW;IACX,OAAO,WAAW,KAAK;GACzB;GAGF,IAAI,CAAC,QACH,OAAO;IACL;IACA,WAAW;IACX,WAAW;IACX,WAAW,CAAC;IACZ,WAAW,aAAa,GAAG;IAC3B,OAAO;GACT;GAIF,OAAO,oBAAoB,MAAM,WAAW,OAAQ,gBAAgB,IAAI,CAAC;EAC3E;EAEA,MAAM,mBACJ,MACA,SAC0B;GAC1B,MAAM,MAAM,OAAO,aAAa;GAChC,IAAI,CAAC,KACH,OAAO;IACL;IACA,WAAW;IACX,WAAW;IACX,WAAW,CAAC;IACZ,WAAW;IACX,OAAO,WAAW,KAAK;GACzB;GAGF,IAAI,WAAW,IAAI,GACjB,OAAO;IAAE,GAAG,eAAe,IAAI;IAAG,OAAO,WAAW,KAAK;GAAiC;GAG5F,IAAI,CAAC,QACH,OAAO;IACL;IACA,WAAW;IACX,WAAW;IACX,WAAW,CAAC;IACZ,WAAW,aAAa,GAAG;IAC3B,OAAO;GACT;GAGF,IAAI,aAAa,GAAG,MAAM,QACxB,OAAO;IACL;IACA,WAAW;IACX,WAAW;IACX,WAAW,CAAC;IACZ,WAAW;IACX,OAAO,WAAW,KAAK;GACzB;GAYF,MAAM,MAAM,WAAW;GACvB,IAAI,KAAK,OAAO,CAAC,IAAI,cACnB,IAAI,eAAe,oBAAoB,MAAM;IAAE,GAAI;IAA6B,OAAO;GAAqB,CAAC;GAU/G,IAAI,sBAAsB,IAAI,IAAI,GAAG;IACnC,MAAM,UAAU,eAAe,IAAI,IAAI;IACvC,OAAO;KACL;KACA,WAAW,SAAS,aAAa;KACjC,YAAY,SAAS;KACrB,WAAW,SAAS;KACpB,WAAW,SAAS,aAAa;KACjC,WAAW,SAAS,aAAa,CAAC;KAClC,WAAW,SAAS,aAAa,aAAa,GAAG;KACjD,OAAO,uBAAuB,KAAK;IACrC;GACF;GAEA,IAAI,SAAS,oBACX,gBAAgB,IAAI,MAAM,QAAQ,kBAAkB;GAEtD,sBAAsB,IAAI,IAAI;GAC9B,qBAAqB,OAAO,IAAI;GAChC,IAAI;IACF,MAAM,SAAS,MAAM,oBAAoB,MAAM,WAC7C,OAAQ,aAAa,MAAM,SAAS,cAAc,KAAA,IAAY,KAAA,IAAY,EAAE,WAAW,QAAQ,UAAU,CAAC,CAC5G;IAKA,MAAM,cACJ,qBAAqB,IAAI,IAAI,KAAK,CAAC,OAAO,YAAY;KAAE,GAAG;KAAQ,WAAW;IAAK,IAAI;IACzF,eAAe,IAAI,MAAM,WAAW;IACpC,OAAO;GACT,UAAU;IACR,gBAAgB,OAAO,IAAI;IAC3B,sBAAsB,OAAO,IAAI;IACjC,qBAAqB,OAAO,IAAI;GAClC;EACF;EAEA,MAAM,2BAA2B,MAAgC;GAC/D,IAAI,CAAC,QACH,OAAO;GAIT,qBAAqB,IAAI,IAAI;GAC7B,MAAM,YAAY,MAAM,OAAO,qBAAqB,IAAI;GACxD,IAAI,CAAC,WACH,qBAAqB,OAAO,IAAI;GAElC,OAAO;EACT;EAEA;EAEA,WAAW;GACT,OAAO,EAAE,GAAG,MAAM;EACpB;EAEA,aAAa;GACX,MAAM,gBAAgB,OAAO,eAAe,KAAA,KAAa,OAAO,KAAK,OAAO,UAAU,CAAC,CAAC,SAAS;GACjG,MAAM,aAAa,OAAO,mBAAmB,KAAA,KAAa,OAAO,eAAe,SAAS;GACzF,OAAO,iBAAiB;EAC1B;EAEA,oBAAoB;GAClB,OAAO,MAAM,KAAK,eAAe,OAAO,GAAG,gBAAgB;EAC7D;EAEA,oBAAoB;GAClB,OAAO,CAAC,GAAI,OAAO,kBAAkB,CAAC,CAAE;EAC1C;EAEA,iBAAiB;GACf,OAAO;IACL,SAAS,kBAAkB,YAAY,aAAa;IACpD,QAAQ,iBAAiB,aAAa;IACtC,QAAQ,sBAAsB,UAAU;GAC1C;EACF;EAEA,YAAY;GACV,OAAO;EACT;EAEA,cAAc,MAAc;GAC1B,OAAO,CAAC,GAAI,WAAW,IAAI,IAAI,KAAK,CAAC,CAAE;EACzC;CACF;AACF"}
1
+ {"version":3,"file":"manager.js","names":[],"sources":["../../src/mcp/manager.ts"],"sourcesContent":["/**\n * MCP manager — orchestrates MCP server connections using MCPClient directly.\n * Created once at startup, provides tools from connected MCP servers.\n */\n\nimport { existsSync, mkdirSync, readFileSync, writeFileSync, renameSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport type {\n MCPClient,\n MCPServerSettledResult,\n MastraMCPServerDefinition,\n OAuthClientInformation,\n OAuthStorage,\n} from '@mastra/mcp';\nimport { DEFAULT_CONFIG_DIR } from '../constants.js';\nimport { getAppDataDir } from '../utils/project.js';\nimport {\n DEFAULT_OAUTH_REDIRECT_URL,\n MASTRA_CODE_CLIENT_METADATA_URL,\n loadMcpConfig,\n getProjectMcpPath,\n getGlobalMcpPath,\n getClaudeSettingsPath,\n resolveOAuthRedirectUrl,\n} from './config.js';\nimport type { ExternalMcpDiscoveryOptions } from './config.js';\nimport {\n loadGlobalDisableState,\n loadProjectServerOverrides,\n saveGlobalDisableState,\n saveProjectServerOverrides,\n} from './state.js';\nimport type { McpProjectServerOverride } from './state.js';\nimport type {\n McpConfig,\n McpHttpOAuthConfig,\n McpHttpServerConfig,\n McpServerConfig,\n McpServerStatus,\n McpSkippedServer,\n} from './types.js';\n\nconst MASTRACODE_MCP_TIMEOUT_MS = 7 * 24 * 60 * 60 * 1000; // 7 days\n/** How long a server gets to connect and list its tools before it is reported as failed. */\nconst DEFAULT_MCP_DISCOVERY_TIMEOUT_MS = 60_000;\n\n/** Summary of MCP initialization result. */\nexport interface McpInitResult {\n connected: McpServerStatus[];\n failed: McpServerStatus[];\n skipped: McpSkippedServer[];\n totalTools: number;\n}\n\n/** Public interface for the MCP manager returned by createMcpManager(). */\nexport interface McpManager {\n /** Connect to all configured MCP servers and collect their tools. */\n init(): Promise<void>;\n /** Start init in the background. Returns a promise that resolves with status when done. */\n initInBackground(): Promise<McpInitResult>;\n /** Disconnect all servers, reload config from disk, reconnect. */\n reload(): Promise<void>;\n /** Reconnect a single server by name. Returns updated status. */\n reconnectServer(name: string): Promise<McpServerStatus>;\n /**\n * Run the OAuth authorization-code flow for an HTTP server, then reconnect it.\n * Servers without an `oauth` config are provisioned with a zero-config default\n * that identifies Mastra Code by its Client ID Metadata Document. The\n * authorization URL is surfaced through\n * `onAuthorizationUrl` for the caller to open in a browser.\n *\n * Resolves with the resulting {@link McpServerStatus}: a connected status on\n * success, or a status carrying an `error` message on failure (including\n * cancellation) — it does not reject. Inspect the returned status rather than\n * relying on a thrown error.\n */\n authenticateServer(\n name: string,\n options?: { onAuthorizationUrl?: (url: string) => void; timeoutMs?: number },\n ): Promise<McpServerStatus>;\n /**\n * Cancel a pending {@link authenticateServer} flow for a server (e.g. the\n * user closed the browser without completing consent). The pending\n * authenticate call rejects and the server returns to the `needsAuth` state\n * so it can be retried. Returns `true` if a flow was cancelled.\n */\n cancelServerAuthentication(name: string): Promise<boolean>;\n /**\n * Disable or enable a single server by name. The change is persisted (in\n * mastracode's app data, not the user's config files) and survives restarts.\n * With `global: true`, this changes the default for every project. Otherwise\n * it records an explicit project override, which can override a global\n * per-server disable. The global all-MCP kill switch remains absolute.\n * Connections are rebuilt, so other servers reconnect — same behavior as\n * {@link reload}. Returns the server's resulting status.\n */\n setServerDisabled(name: string, disabled: boolean, options?: { global?: boolean }): Promise<McpServerStatus>;\n /** Clear a server's explicit project override so it inherits the global default. */\n inheritServer(name: string): Promise<McpServerStatus>;\n /**\n * Disable or enable all servers at once. Project scope records an explicit\n * override for every currently configured server. Global scope sets/clears a\n * persisted all-MCP kill switch (and, when enabling, also clears globally\n * disabled server names). Persisted like {@link setServerDisabled}.\n */\n setAllDisabled(disabled: boolean, options?: { global?: boolean }): Promise<void>;\n /** Clear every explicit project override so all servers inherit global defaults. */\n inheritAllServers(): Promise<void>;\n /** Names of configured servers that are currently disabled (any scope). */\n getDisabledServers(): string[];\n /** Whether all MCP is disabled globally (across every project). */\n isAllDisabledGlobally(): boolean;\n /** Disconnect from all MCP servers and clean up. */\n disconnect(): Promise<void>;\n /** Get all tools from connected MCP servers (namespaced as serverName_toolName). */\n getTools(): Record<string, any>;\n /** Check if any MCP servers are configured (or skipped). */\n hasServers(): boolean;\n /** Get status of all servers. */\n getServerStatuses(): McpServerStatus[];\n /** Get servers that were skipped during config loading. */\n getSkippedServers(): McpSkippedServer[];\n /** Get config file paths for display. */\n getConfigPaths(): { project: string; global: string; claude: string };\n /** Get the merged config. */\n getConfig(): McpConfig;\n /** Get captured stderr logs for a server. */\n getServerLogs(name: string): string[];\n}\n\nfunction getTransport(cfg: McpServerConfig): 'stdio' | 'http' {\n return 'url' in cfg ? 'http' : 'stdio';\n}\n\nclass FileOAuthStorage implements OAuthStorage {\n constructor(private filePath: string) {}\n\n get(key: string): string | undefined {\n return this.read()[key];\n }\n\n set(key: string, value: string): void {\n const data = this.read();\n data[key] = value;\n this.write(data);\n }\n\n delete(key: string): void {\n const data = this.read();\n delete data[key];\n this.write(data);\n }\n\n private read(): Record<string, string> {\n if (!existsSync(this.filePath)) return {};\n try {\n return JSON.parse(readFileSync(this.filePath, 'utf-8')) as Record<string, string>;\n } catch {\n return {};\n }\n }\n\n private write(data: Record<string, string>): void {\n const dir = dirname(this.filePath);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true, mode: 0o700 });\n }\n const tmpPath = `${this.filePath}.tmp`;\n writeFileSync(tmpPath, JSON.stringify(data, null, 2), { encoding: 'utf-8', mode: 0o600 });\n renameSync(tmpPath, this.filePath);\n }\n}\n\n/**\n * Zero-config OAuth defaults for servers with a bare `url` entry. The client\n * identifies itself by Mastra Code's Client ID Metadata Document URL, so no\n * `clientId` is needed.\n */\nconst DEFAULT_OAUTH_CONFIG: McpHttpOAuthConfig = { redirectUrl: DEFAULT_OAUTH_REDIRECT_URL };\n\nfunction getOAuthStoragePath(projectDir: string, name: string, cfg: McpHttpServerConfig): string {\n // The fingerprint always uses the resolved redirect URL so a bare `url`\n // entry keeps the same token file before and after zero-config provisioning.\n const key = JSON.stringify({\n projectDir,\n name,\n url: cfg.url,\n redirectUrl: resolveOAuthRedirectUrl(cfg.oauth),\n clientId: cfg.oauth?.clientId,\n scopes: cfg.oauth?.scopes ?? [],\n });\n return join(getAppDataDir(), 'mcp-oauth', `${getStorageKeyFingerprint(key)}.json`);\n}\n\nfunction getStorageKeyFingerprint(value: string): string {\n let fingerprint = 0xcbf29ce484222325n;\n for (let i = 0; i < value.length; i += 1) {\n fingerprint ^= BigInt(value.charCodeAt(i));\n fingerprint = BigInt.asUintN(64, fingerprint * 0x100000001b3n);\n }\n return fingerprint.toString(16).padStart(16, '0');\n}\n\ntype McpModule = typeof import('@mastra/mcp');\nlet mcpModule: McpModule | undefined;\n\n/** `@mastra/mcp` and the MCP SDK (~12 MB) load with the first server that connects, not with every session. */\nasync function loadMcpModule(): Promise<McpModule> {\n mcpModule ??= await import('@mastra/mcp');\n return mcpModule;\n}\n\n/** For code that only runs once a client exists, so the module is already loaded. */\nfunction loadedMcpModule(): McpModule {\n if (!mcpModule) throw new Error('@mastra/mcp is not loaded yet');\n return mcpModule;\n}\n\n/**\n * Create an MCP manager that wraps MCPClient with config-file discovery\n * and per-server status tracking.\n */\nexport function createMcpManager(\n projectDir: string,\n configDirName = DEFAULT_CONFIG_DIR,\n extraServers?: Record<string, McpServerConfig>,\n externalDiscovery?: ExternalMcpDiscoveryOptions,\n options?: { discoveryTimeoutMs?: number },\n): McpManager {\n const discoveryTimeoutMs = options?.discoveryTimeoutMs ?? DEFAULT_MCP_DISCOVERY_TIMEOUT_MS;\n /** Merge programmatic servers into a base config (highest priority). */\n const applyExtraServers = (base: McpConfig): McpConfig => {\n if (!extraServers || Object.keys(extraServers).length === 0) return base;\n return { ...base, mcpServers: { ...base.mcpServers, ...extraServers } };\n };\n\n let config = applyExtraServers(loadMcpConfig(projectDir, configDirName, externalDiscovery));\n let projectServerOverrides = new Map<string, McpProjectServerOverride>(\n Object.entries(loadProjectServerOverrides(projectDir)),\n );\n let globalDisableState = loadGlobalDisableState();\n let globallyDisabledServers = new Set(globalDisableState.disabledServers);\n\n /** Whether a server is disabled after applying the kill switch, project override, and global default. */\n const isDisabled = (name: string): boolean => {\n if (globalDisableState.allDisabled) return true;\n const projectOverride = projectServerOverrides.get(name);\n if (projectOverride) return projectOverride === 'disabled';\n return globallyDisabledServers.has(name);\n };\n\n /** Which scope currently disables a server. The global kill switch remains absolute. */\n const disabledScopeOf = (name: string): 'project' | 'global' | undefined => {\n if (globalDisableState.allDisabled) return 'global';\n const projectOverride = projectServerOverrides.get(name);\n if (projectOverride === 'disabled') return 'project';\n if (!projectOverride && globallyDisabledServers.has(name)) return 'global';\n return undefined;\n };\n let client: MCPClient | null = null;\n let serverDefs: Record<string, MastraMCPServerDefinition> = {};\n let tools: Record<string, any> = {};\n let serverStatuses = new Map<string, McpServerStatus>();\n let stderrLogs = new Map<string, string[]>();\n let initialized = false;\n\n /**\n * The latest connect attempt per server. A discovery result is only applied while its\n * attempt is still the latest and its client is still the live one, so a slow or late\n * result never overwrites a newer reconnect, a reload, or a server being disabled.\n */\n let connectAttempts = new Map<string, object>();\n const isCurrent = (name: string, attempt: object, attemptClient: MCPClient): boolean =>\n connectAttempts.get(name) === attempt && client === attemptClient;\n\n /** Per-server handlers that receive the OAuth authorization URL during authenticateServer(). */\n const authUrlHandlers = new Map<string, (url: string) => void>();\n\n /**\n * Servers with an OAuth authorization flow currently in flight. Owned by the\n * manager (not the TUI) so the state survives a `/mcp` selector being closed\n * and reopened — the reopened selector reads it back off the server status and\n * can still offer \"Cancel authentication\".\n */\n const authenticatingServers = new Set<string>();\n\n /**\n * Servers whose in-flight authentication was cancelled by the caller. Set by\n * cancelServerAuthentication() so the resolving authenticateServer() call can\n * mark its failed status as a deliberate cancel rather than a genuine failure.\n * This lives on the manager (not the TUI selector) so the signal survives the\n * selector being closed and reopened mid-flow.\n */\n const cancelledAuthServers = new Set<string>();\n\n /** Overlay manager-owned state onto a status snapshot. */\n const withManagerState = (status: McpServerStatus): McpServerStatus => ({\n ...status,\n ...(authenticatingServers.has(status.name) ? { authenticating: true } : {}),\n ...(projectServerOverrides.has(status.name) ? { projectOverride: projectServerOverrides.get(status.name) } : {}),\n globalDefault: globallyDisabledServers.has(status.name) ? 'disabled' : 'enabled',\n globalKillSwitch: globalDisableState.allDisabled,\n });\n\n const MAX_STDERR_LINES = 200;\n /** Streams already being buffered, so capturing a server again never doubles its lines. */\n const capturedStderr = new WeakSet<object>();\n\n /** Hook into a server's stderr stream and buffer its output. */\n function captureStderr(serverName: string): void {\n if (!client || typeof client.getServerStderr !== 'function') return;\n const stream = client.getServerStderr(serverName);\n if (!stream || capturedStderr.has(stream)) return;\n capturedStderr.add(stream);\n\n let buffer = '';\n const lines = stderrLogs.get(serverName) ?? [];\n stderrLogs.set(serverName, lines);\n\n stream.on('data', (chunk: Buffer) => {\n buffer += chunk.toString();\n const parts = buffer.split('\\n');\n // Last element is incomplete line (or empty if ended with \\n)\n buffer = parts.pop()!;\n for (const line of parts) {\n if (line.trim()) {\n lines.push(line);\n if (lines.length > MAX_STDERR_LINES) {\n lines.shift();\n }\n }\n }\n });\n\n stream.on('end', () => {\n if (buffer.trim()) {\n lines.push(buffer);\n if (lines.length > MAX_STDERR_LINES) {\n lines.shift();\n }\n }\n });\n }\n\n function createOAuthProvider(name: string, cfg: McpHttpServerConfig) {\n // Bare `url` entries get no eager provider — auth is provisioned lazily\n // when the user authenticates — unless a previous session already stored\n // OAuth state for this server, in which case the provider is needed to\n // attach the persisted tokens on connect.\n const oauth =\n cfg.oauth ?? (existsSync(getOAuthStoragePath(projectDir, name, cfg)) ? DEFAULT_OAUTH_CONFIG : undefined);\n if (!oauth) return undefined;\n\n // redirectUrl is optional in the user-supplied config; resolve the stable\n // default (or the `callbackPort` shorthand, for programmatically registered\n // servers that bypass config parsing) so provider metadata always carries\n // a concrete URL.\n const redirectUrl = resolveOAuthRedirectUrl(oauth);\n\n // Without a pre-registered clientId the client is identified by Mastra\n // Code's Client ID Metadata Document: the document URL is the client_id and\n // the authorization server fetches it, so nothing is registered per server.\n const clientInformation = oauth.clientId\n ? ({\n client_id: oauth.clientId,\n ...(oauth.clientSecret ? { client_secret: oauth.clientSecret } : {}),\n } satisfies OAuthClientInformation)\n : undefined;\n const clientMetadataUrl = clientInformation ? undefined : MASTRA_CODE_CLIENT_METADATA_URL;\n\n const { MCPOAuthClientProvider } = loadedMcpModule();\n return new MCPOAuthClientProvider({\n redirectUrl,\n clientMetadata: {\n ...(clientMetadataUrl ? { client_id: clientMetadataUrl } : {}),\n redirect_uris: [redirectUrl],\n client_name: oauth.clientName ?? (clientMetadataUrl ? 'Mastra Code' : `Mastra Code MCP ${name}`),\n grant_types: ['authorization_code', 'refresh_token'],\n response_types: ['code'],\n ...(oauth.scopes?.length ? { scope: oauth.scopes.join(' ') } : {}),\n },\n clientInformation,\n clientMetadataUrl,\n storage: new FileOAuthStorage(getOAuthStoragePath(projectDir, name, cfg)),\n onRedirectToAuthorization: url => {\n authUrlHandlers.get(name)?.(url.toString());\n },\n });\n }\n\n function buildServerDefs(servers: Record<string, McpServerConfig>): Record<string, MastraMCPServerDefinition> {\n const defs: Record<string, MastraMCPServerDefinition> = {};\n for (const [name, cfg] of Object.entries(servers)) {\n if ('url' in cfg) {\n const httpCfg = cfg as McpHttpServerConfig;\n defs[name] = {\n url: new URL(httpCfg.url),\n requestInit: httpCfg.headers ? { headers: httpCfg.headers } : undefined,\n authProvider: createOAuthProvider(name, httpCfg),\n };\n } else {\n defs[name] = {\n command: cfg.command,\n args: cfg.args,\n env: cfg.env,\n ...(cfg.cwd ? { cwd: cfg.cwd } : {}),\n stderr: 'pipe',\n };\n }\n }\n return defs;\n }\n\n /** Seed a `disabled` status for every disabled server so it stays visible. */\n function setDisabledStatuses(): void {\n for (const [name, cfg] of Object.entries(config.mcpServers ?? {})) {\n const scope = disabledScopeOf(name);\n if (!scope) continue;\n serverStatuses.set(name, {\n name,\n connected: false,\n toolCount: 0,\n toolNames: [],\n transport: getTransport(cfg),\n disabled: true,\n disabledScope: scope,\n });\n }\n }\n\n /** What one server's discovery produced: its tools, or why it has none. */\n type ServerOutcome = { tools: Record<string, any>; error?: undefined } | { tools?: undefined; error: string };\n\n const discoveryTimeoutError = () =>\n `Timed out after ${discoveryTimeoutMs / 1000}s waiting for the server to connect and list its tools`;\n\n function outcomeOf(result: MCPServerSettledResult<Record<string, any>>): ServerOutcome {\n if (result.error === undefined) return { tools: result.value };\n const { MCP_DISCOVERY_TIMEOUT_CODE } = loadedMcpModule();\n return { error: result.error.code === MCP_DISCOVERY_TIMEOUT_CODE ? discoveryTimeoutError() : result.error.message };\n }\n\n /**\n * Drop the tools a server registered earlier.\n *\n * Only the exact tool names that server reported are removed. Matching on the\n * `${name}_` prefix would also delete the tools of a server whose name starts\n * with this one, e.g. `foo` would drop `foo_bar_ping` from `foo_bar`.\n */\n function removeServerTools(name: string): void {\n for (const key of serverStatuses.get(name)?.toolNames ?? []) {\n delete tools[key];\n }\n }\n\n /** Replace a server's tools and status with one discovery outcome. */\n function applyServerResult(name: string, cfg: McpServerConfig, outcome: ServerOutcome): McpServerStatus {\n removeServerTools(name);\n\n const transport = getTransport(cfg);\n const serverTools = outcome.tools ?? {};\n const toolNames = Object.keys(serverTools).map(t => `${name}_${t}`);\n let status: McpServerStatus;\n if (outcome.error === undefined && toolNames.length > 0) {\n for (const [toolName, toolConfig] of Object.entries(serverTools)) {\n tools[`${name}_${toolName}`] = toolConfig;\n }\n status = { name, connected: true, toolCount: toolNames.length, toolNames, transport };\n } else {\n const error = outcome.error ?? 'Failed to connect';\n status = {\n name,\n connected: false,\n toolCount: 0,\n toolNames: [],\n transport,\n error,\n ...(serverNeedsAuth(name, cfg, error) ? { needsAuth: true } : {}),\n };\n }\n serverStatuses.set(name, status);\n return status;\n }\n\n async function connectAndCollectTools(): Promise<void> {\n setDisabledStatuses();\n\n const servers = Object.fromEntries(Object.entries(config.mcpServers ?? {}).filter(([name]) => !isDisabled(name)));\n if (Object.keys(servers).length === 0) {\n return;\n }\n\n // Pre-populate statuses as \"connecting\" so callers can see in-progress state\n const serverNames = Object.keys(servers);\n for (const name of serverNames) {\n serverStatuses.set(name, {\n name,\n connected: false,\n connecting: true,\n toolCount: 0,\n toolNames: [],\n transport: getTransport(servers[name]!),\n });\n }\n\n const { MCPClient } = await loadMcpModule();\n serverDefs = buildServerDefs(servers);\n const attemptClient = new MCPClient({\n id: 'mastra-code-mcp',\n servers: serverDefs,\n timeout: MASTRACODE_MCP_TIMEOUT_MS,\n });\n client = attemptClient;\n\n const attempts = new Map(serverNames.map(name => [name, {}]));\n for (const [name, attempt] of attempts) connectAttempts.set(name, attempt);\n\n const record = (name: string, outcome: ServerOutcome): boolean => {\n if (!isCurrent(name, attempts.get(name)!, attemptClient)) return false;\n captureStderr(name);\n applyServerResult(name, servers[name]!, outcome);\n return true;\n };\n\n // Each server reports as soon as it settles, so one stalled server cannot hold\n // back the status and tools of the others.\n const timedOut: string[] = [];\n try {\n await attemptClient.listToolsetsWithErrors({\n perServerTimeoutMs: discoveryTimeoutMs,\n onServerSettled: (name, result) => {\n if (!attempts.has(name)) return;\n if (result.error?.code === loadedMcpModule().MCP_DISCOVERY_TIMEOUT_CODE) timedOut.push(name);\n record(name, outcomeOf(result));\n },\n });\n } catch (error) {\n const errMsg = error instanceof Error ? error.message : String(error);\n for (const name of serverNames) {\n if (serverStatuses.get(name)?.connecting) record(name, { error: errMsg });\n }\n }\n for (const name of serverNames) {\n if (serverStatuses.get(name)?.connecting) record(name, { error: 'Failed to connect' });\n }\n\n // A timed-out server's connect keeps running (a cold `npx` install can take a\n // while). Discover those servers again without a cap so they still connect once ready.\n if (timedOut.length > 0) {\n void attemptClient\n .listToolsetsWithErrors({\n serverNames: timedOut,\n onServerSettled: (name, result) => record(name, outcomeOf(result)),\n })\n .catch(() => {});\n }\n }\n\n /**\n * Whether a failed HTTP server is blocked on OAuth authorization.\n *\n * Provider-backed servers report the exact state tracked by `@mastra/mcp`.\n * Bare `url` entries carry no provider until the user authenticates, so the\n * signal is a 401 in the connect error — surfaced either as the status text\n * or as the RFC 6750 `invalid_token` bearer error code in the response body.\n */\n function serverNeedsAuth(name: string, cfg: McpServerConfig, error?: string): boolean {\n if (getTransport(cfg) !== 'http') return false;\n if (client?.getServerAuthState?.(name) === 'needs-auth') return true;\n if (serverDefs[name]?.authProvider) return false;\n return error !== undefined && /\\b401\\b|unauthorized|invalid_token/i.test(error);\n }\n\n /**\n * Runs a single-server connect action (reconnect or authenticate), then\n * refreshes that server's tools and status from the client.\n *\n * With `deadlineMs`, the whole operation shares one deadline: the server is\n * reported as failed when it passes, and its result is still applied if it\n * arrives later. A call that a newer reconnect, reload, or disable replaced\n * leaves the stored status alone and returns a copy of it.\n */\n async function connectSingleServer(\n name: string,\n cfg: McpServerConfig,\n connect: (client: MCPClient) => Promise<unknown>,\n deadlineMs?: number,\n ): Promise<McpServerStatus> {\n const attemptClient = client!;\n const attempt = {};\n connectAttempts.set(name, attempt);\n\n // Remove old tools for this server\n removeServerTools(name);\n\n // Clear old logs and mark as connecting\n stderrLogs.delete(name);\n serverStatuses.set(name, {\n name,\n connected: false,\n connecting: true,\n toolCount: 0,\n toolNames: [],\n transport: getTransport(cfg),\n });\n\n const work = (async (): Promise<ServerOutcome> => {\n await connect(attemptClient);\n if (isCurrent(name, attempt, attemptClient)) captureStderr(name);\n\n let outcome: ServerOutcome = { error: 'Failed to connect' };\n await attemptClient.listToolsetsWithErrors({\n serverNames: [name],\n onServerSettled: (_, result) => {\n outcome = outcomeOf(result);\n },\n });\n return outcome;\n })().catch((error): ServerOutcome => ({ error: error instanceof Error ? error.message : String(error) }));\n\n const record = (outcome: ServerOutcome): McpServerStatus | undefined =>\n isCurrent(name, attempt, attemptClient) ? applyServerResult(name, cfg, outcome) : undefined;\n const superseded = (): McpServerStatus => ({\n ...(serverStatuses.get(name) ?? {\n name,\n connected: false,\n toolCount: 0,\n toolNames: [],\n transport: getTransport(cfg),\n error: 'Superseded by a newer connection attempt',\n }),\n });\n\n if (deadlineMs === undefined) {\n return record(await work) ?? superseded();\n }\n\n let timer: NodeJS.Timeout | undefined;\n const deadline = new Promise<'timeout'>(resolve => {\n timer = setTimeout(() => resolve('timeout'), deadlineMs);\n timer.unref?.();\n });\n const first = await Promise.race([work, deadline]);\n clearTimeout(timer);\n if (first !== 'timeout') {\n return record(first) ?? superseded();\n }\n void work.then(record);\n return record({ error: discoveryTimeoutError() }) ?? superseded();\n }\n\n async function disconnect(): Promise<void> {\n connectAttempts = new Map();\n if (client) {\n const closing = client;\n client = null;\n try {\n await closing.disconnect();\n } catch {\n // Ignore disconnect errors\n }\n }\n }\n\n /** Tear down all connections and reconnect every enabled server. */\n async function rebuildConnections(): Promise<void> {\n await disconnect();\n tools = {};\n serverStatuses = new Map();\n stderrLogs = new Map();\n initialized = false;\n await connectAndCollectTools();\n initialized = true;\n }\n\n function disabledStatus(name: string): McpServerStatus {\n const cfg = config.mcpServers?.[name];\n return {\n name,\n connected: false,\n toolCount: 0,\n toolNames: [],\n transport: cfg ? getTransport(cfg) : 'stdio',\n disabled: true,\n disabledScope: disabledScopeOf(name),\n };\n }\n\n // Read-merge-write persistence: re-read the persisted state and apply this\n // operation's delta on top, then adopt the merged result in memory. This\n // way a concurrent mastracode process's changes (e.g. another window\n // flipping the global kill switch) are never clobbered by this manager's\n // construction-time snapshot.\n function persistProjectDelta(mutate: (overrides: Map<string, McpProjectServerOverride>) => void): void {\n const fresh = new Map<string, McpProjectServerOverride>(Object.entries(loadProjectServerOverrides(projectDir)));\n mutate(fresh);\n projectServerOverrides = fresh;\n saveProjectServerOverrides(projectDir, Object.fromEntries(fresh));\n }\n\n function persistGlobalDelta(mutate: (state: { allDisabled: boolean; disabledServers: Set<string> }) => void): void {\n const onDisk = loadGlobalDisableState();\n const fresh = { allDisabled: onDisk.allDisabled, disabledServers: new Set(onDisk.disabledServers) };\n mutate(fresh);\n globallyDisabledServers = fresh.disabledServers;\n globalDisableState = { allDisabled: fresh.allDisabled, disabledServers: Array.from(fresh.disabledServers) };\n saveGlobalDisableState(globalDisableState);\n }\n\n return {\n async init() {\n if (initialized) return;\n await connectAndCollectTools();\n initialized = true;\n },\n\n async initInBackground(): Promise<McpInitResult> {\n await this.init();\n const statuses = Array.from(serverStatuses.values(), withManagerState);\n const connected = statuses.filter(s => s.connected);\n const failed = statuses.filter(s => !s.connected && !s.disabled);\n return {\n connected,\n failed,\n skipped: [...(config.skippedServers ?? [])],\n totalTools: connected.reduce((sum, s) => sum + s.toolCount, 0),\n };\n },\n\n async reload() {\n config = applyExtraServers(loadMcpConfig(projectDir, configDirName, externalDiscovery));\n projectServerOverrides = new Map(Object.entries(loadProjectServerOverrides(projectDir)));\n globalDisableState = loadGlobalDisableState();\n globallyDisabledServers = new Set(globalDisableState.disabledServers);\n await rebuildConnections();\n },\n\n async setServerDisabled(name: string, disabled: boolean, options?: { global?: boolean }): Promise<McpServerStatus> {\n if (!config.mcpServers?.[name]) {\n return {\n name,\n connected: false,\n toolCount: 0,\n toolNames: [],\n transport: 'stdio',\n error: `Server \"${name}\" not found in config`,\n };\n }\n\n const wasEffectivelyDisabled = isDisabled(name);\n\n if (options?.global) {\n persistGlobalDelta(state => {\n if (disabled) {\n state.disabledServers.add(name);\n } else {\n state.disabledServers.delete(name);\n }\n });\n } else {\n persistProjectDelta(overrides => {\n overrides.set(name, disabled ? 'disabled' : 'enabled');\n });\n }\n\n // Only rebuild connections when the server's effective state actually\n // flipped. State changes that only alter an inherited default or an\n // override beneath the global kill switch leave connections alone.\n if (isDisabled(name) !== wasEffectivelyDisabled) {\n await rebuildConnections();\n return withManagerState(serverStatuses.get(name) ?? disabledStatus(name));\n }\n return withManagerState(\n isDisabled(name) ? disabledStatus(name) : (serverStatuses.get(name) ?? disabledStatus(name)),\n );\n },\n\n async inheritServer(name: string): Promise<McpServerStatus> {\n if (!config.mcpServers?.[name]) {\n return {\n name,\n connected: false,\n toolCount: 0,\n toolNames: [],\n transport: 'stdio',\n error: `Server \"${name}\" not found in config`,\n };\n }\n\n const wasEffectivelyDisabled = isDisabled(name);\n persistProjectDelta(overrides => {\n overrides.delete(name);\n });\n if (isDisabled(name) !== wasEffectivelyDisabled) {\n await rebuildConnections();\n }\n return withManagerState(\n isDisabled(name) ? disabledStatus(name) : (serverStatuses.get(name) ?? disabledStatus(name)),\n );\n },\n\n async setAllDisabled(disabled: boolean, options?: { global?: boolean }): Promise<void> {\n const configuredNames = Object.keys(config.mcpServers ?? {});\n const effectiveBefore = configuredNames.filter(name => isDisabled(name)).join(',');\n if (options?.global) {\n persistGlobalDelta(state => {\n state.allDisabled = disabled;\n if (!disabled) {\n // Enabling globally also clears globally disabled server names so\n // \"/mcp enable all --global\" fully restores global defaults.\n state.disabledServers.clear();\n }\n });\n } else {\n persistProjectDelta(overrides => {\n for (const name of configuredNames) {\n overrides.set(name, disabled ? 'disabled' : 'enabled');\n }\n });\n }\n const effectiveAfter = configuredNames.filter(name => isDisabled(name)).join(',');\n if (effectiveAfter !== effectiveBefore) {\n await rebuildConnections();\n }\n },\n\n async inheritAllServers(): Promise<void> {\n const configuredNames = Object.keys(config.mcpServers ?? {});\n const effectiveBefore = configuredNames.filter(name => isDisabled(name)).join(',');\n persistProjectDelta(overrides => {\n overrides.clear();\n });\n const effectiveAfter = configuredNames.filter(name => isDisabled(name)).join(',');\n if (effectiveAfter !== effectiveBefore) {\n await rebuildConnections();\n }\n },\n\n getDisabledServers() {\n return Object.keys(config.mcpServers ?? {})\n .filter(name => isDisabled(name))\n .sort();\n },\n\n isAllDisabledGlobally() {\n return globalDisableState.allDisabled;\n },\n\n async reconnectServer(name: string): Promise<McpServerStatus> {\n if (isDisabled(name)) {\n return { ...disabledStatus(name), error: `Server \"${name}\" is disabled — enable it first` };\n }\n const cfg = config.mcpServers?.[name];\n if (!cfg) {\n return {\n name,\n connected: false,\n toolCount: 0,\n toolNames: [],\n transport: 'stdio',\n error: `Server \"${name}\" not found in config`,\n };\n }\n\n if (!client) {\n return {\n name,\n connected: false,\n toolCount: 0,\n toolNames: [],\n transport: getTransport(cfg),\n error: 'MCP client not initialized',\n };\n }\n\n // Use MCPClient's per-server reconnect, bounded by the same discovery timeout as startup\n return connectSingleServer(name, cfg, c => c.reconnectServer(name), discoveryTimeoutMs);\n },\n\n async authenticateServer(\n name: string,\n options?: { onAuthorizationUrl?: (url: string) => void; timeoutMs?: number },\n ): Promise<McpServerStatus> {\n const cfg = config.mcpServers?.[name];\n if (!cfg) {\n return {\n name,\n connected: false,\n toolCount: 0,\n toolNames: [],\n transport: 'stdio',\n error: `Server \"${name}\" not found in config`,\n };\n }\n\n if (isDisabled(name)) {\n return { ...disabledStatus(name), error: `Server \"${name}\" is disabled — enable it first` };\n }\n\n if (!client) {\n return {\n name,\n connected: false,\n toolCount: 0,\n toolNames: [],\n transport: getTransport(cfg),\n error: 'MCP client not initialized',\n };\n }\n\n if (getTransport(cfg) !== 'http') {\n return {\n name,\n connected: false,\n toolCount: 0,\n toolNames: [],\n transport: 'stdio',\n error: `Server \"${name}\" uses stdio transport, which does not support OAuth`,\n };\n }\n\n // Zero-config provisioning: a bare `url` entry gets a provider with the\n // default redirect URL the first time the user authenticates. The Client\n // ID Metadata Document takes care of the client identity.\n //\n // NOTE: `serverDefs[name]` is the same object reference the MCPClient was\n // constructed with, and connectHttp reads `authProvider` live off it at\n // connect time, so mutating it here reaches the already-created client.\n // If MCPClient ever defensively copies its server config, zero-config auth\n // would need an explicit \"set this server's provider\" API instead.\n const def = serverDefs[name];\n if (def?.url && !def.authProvider) {\n def.authProvider = createOAuthProvider(name, { ...(cfg as McpHttpServerConfig), oauth: DEFAULT_OAUTH_CONFIG });\n }\n\n // Reject a concurrent second attempt for the same server. authUrlHandlers\n // has a single slot per server, so a second call with an onAuthorizationUrl\n // would overwrite the first caller's handler (which then never sees the\n // URL) and its finally would delete the handler out from under the other\n // in-flight call. Gate on authenticatingServers rather than authUrlHandlers\n // so callers without a URL handler are caught too. The underlying\n // client.authenticate already coalesces same-server calls into one flow.\n if (authenticatingServers.has(name)) {\n const current = serverStatuses.get(name);\n return {\n name,\n connected: current?.connected ?? false,\n connecting: current?.connecting,\n needsAuth: current?.needsAuth,\n toolCount: current?.toolCount ?? 0,\n toolNames: current?.toolNames ?? [],\n transport: current?.transport ?? getTransport(cfg),\n error: `Authentication for \"${name}\" is already in progress`,\n };\n }\n\n if (options?.onAuthorizationUrl) {\n authUrlHandlers.set(name, options.onAuthorizationUrl);\n }\n authenticatingServers.add(name);\n cancelledAuthServers.delete(name);\n try {\n const result = await connectSingleServer(name, cfg, c =>\n c.authenticate(name, options?.timeoutMs === undefined ? undefined : { timeoutMs: options.timeoutMs }),\n );\n // A newer reconnect, reload, or disable replaced this attempt; leave its status alone.\n if (serverStatuses.get(name) !== result) return result;\n // A cancelled flow resolves with a failed status; mark it so callers can\n // distinguish a deliberate cancel from a genuine authentication failure.\n // Write the marker back to the durable status map (not just the returned\n // value) so a selector reopened after cancellation still sees it.\n const finalStatus =\n cancelledAuthServers.has(name) && !result.connected ? { ...result, cancelled: true } : result;\n serverStatuses.set(name, finalStatus);\n return finalStatus;\n } finally {\n authUrlHandlers.delete(name);\n authenticatingServers.delete(name);\n cancelledAuthServers.delete(name);\n }\n },\n\n async cancelServerAuthentication(name: string): Promise<boolean> {\n if (!client) {\n return false;\n }\n // Record the intent before aborting so the resolving authenticateServer()\n // call can tag its failed status as cancelled rather than failed.\n cancelledAuthServers.add(name);\n const cancelled = await client.cancelAuthentication(name);\n if (!cancelled) {\n cancelledAuthServers.delete(name);\n }\n return cancelled;\n },\n\n disconnect,\n\n getTools() {\n // Servers settle in any order; return tools in config order so the model sees a stable tool list.\n const ordered: Record<string, any> = {};\n for (const name of Object.keys(config.mcpServers ?? {})) {\n for (const key of serverStatuses.get(name)?.toolNames ?? []) {\n if (key in tools) ordered[key] = tools[key];\n }\n }\n return ordered;\n },\n\n hasServers() {\n const hasConfigured = config.mcpServers !== undefined && Object.keys(config.mcpServers).length > 0;\n const hasSkipped = config.skippedServers !== undefined && config.skippedServers.length > 0;\n return hasConfigured || hasSkipped;\n },\n\n getServerStatuses() {\n return Array.from(serverStatuses.values(), withManagerState);\n },\n\n getSkippedServers() {\n return [...(config.skippedServers ?? [])];\n },\n\n getConfigPaths() {\n return {\n project: getProjectMcpPath(projectDir, configDirName),\n global: getGlobalMcpPath(configDirName),\n claude: getClaudeSettingsPath(projectDir),\n };\n },\n\n getConfig() {\n return config;\n },\n\n getServerLogs(name: string) {\n return [...(stderrLogs.get(name) ?? [])];\n },\n };\n}\n"],"mappings":"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"}
@@ -340,6 +340,8 @@ export interface SignalSettings {
340
340
  experimentalCrossAgentSignals: boolean;
341
341
  /** Experimental: give the agent tools to create and manage `/schedules` schedules on its thread. */
342
342
  experimentalScheduleTools: boolean;
343
+ /** Experimental: give the agent Knowledge (search, read, write, pin) on Mastra Code's own storage. */
344
+ experimentalKnowledge: boolean;
343
345
  /** Poll interval for GitHub PR subscriptions. */
344
346
  githubPollIntervalMs: number;
345
347
  }