@mastra/code-sdk 1.8.4-alpha.6 → 1.9.0-alpha.7

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 (79) hide show
  1. package/README.md +190 -0
  2. package/dist/acp/agent.d.ts +30 -17
  3. package/dist/acp/agent.d.ts.map +1 -1
  4. package/dist/acp/agent.js +294 -103
  5. package/dist/acp/agent.js.map +1 -1
  6. package/dist/acp/errors.d.ts +3 -0
  7. package/dist/acp/errors.d.ts.map +1 -0
  8. package/dist/acp/errors.js +14 -0
  9. package/dist/acp/errors.js.map +1 -0
  10. package/dist/acp/event-mapper.d.ts +6 -1
  11. package/dist/acp/event-mapper.d.ts.map +1 -1
  12. package/dist/acp/event-mapper.js +116 -56
  13. package/dist/acp/event-mapper.js.map +1 -1
  14. package/dist/acp/index.d.ts +1 -4
  15. package/dist/acp/index.d.ts.map +1 -1
  16. package/dist/acp/index.js +6 -48
  17. package/dist/acp/index.js.map +1 -1
  18. package/dist/acp/runtime.d.ts +5 -0
  19. package/dist/acp/runtime.d.ts.map +1 -0
  20. package/dist/acp/runtime.js +80 -0
  21. package/dist/acp/runtime.js.map +1 -0
  22. package/dist/acp/server.d.ts +3 -6
  23. package/dist/acp/server.d.ts.map +1 -1
  24. package/dist/acp/server.js +22 -19
  25. package/dist/acp/server.js.map +1 -1
  26. package/dist/acp/skills.d.ts +6 -0
  27. package/dist/acp/skills.d.ts.map +1 -0
  28. package/dist/acp/skills.js +33 -0
  29. package/dist/acp/skills.js.map +1 -0
  30. package/dist/agents/model.js +1 -1
  31. package/dist/agents/prompts/agent-instructions.js +2 -2
  32. package/dist/agents/workspace.js +1 -1
  33. package/dist/analytics.js +2 -2
  34. package/dist/auth/providers/kimi-coding.js +1 -1
  35. package/dist/auth/storage.js +2 -2
  36. package/dist/clipboard/index.js +2 -2
  37. package/dist/headless/run-mc.d.ts.map +1 -1
  38. package/dist/headless/run-mc.js +14 -0
  39. package/dist/headless/run-mc.js.map +1 -1
  40. package/dist/hooks/config.js +1 -1
  41. package/dist/index.d.ts +2 -0
  42. package/dist/index.d.ts.map +1 -1
  43. package/dist/index.js +4 -4
  44. package/dist/index.js.map +1 -1
  45. package/dist/lsp/server.js +1 -1
  46. package/dist/lsp/workspace.js +1 -1
  47. package/dist/mcp/config.js +1 -1
  48. package/dist/mcp/manager.d.ts.map +1 -1
  49. package/dist/mcp/manager.js +2 -1
  50. package/dist/mcp/manager.js.map +1 -1
  51. package/dist/mcp/state.js +1 -1
  52. package/dist/mcp/types.d.ts +2 -0
  53. package/dist/mcp/types.d.ts.map +1 -1
  54. package/dist/onboarding/settings.js +3 -3
  55. package/dist/plugins/dependencies.js +1 -1
  56. package/dist/plugins/install.js +1 -1
  57. package/dist/plugins/loader.js +3 -3
  58. package/dist/plugins/manager.js +1 -1
  59. package/dist/plugins/manifest.js +1 -1
  60. package/dist/plugins/package-link.js +1 -1
  61. package/dist/plugins/paths.js +1 -1
  62. package/dist/plugins/registry.js +1 -1
  63. package/dist/plugins/scaffold.js +1 -1
  64. package/dist/process-memory-diagnostics.js +2 -2
  65. package/dist/providers/amazon-bedrock-gateway.js +1 -1
  66. package/dist/providers/openai-codex.js +1 -1
  67. package/dist/schema.js +1 -1
  68. package/dist/tools/request-sandbox-access.js +5 -4
  69. package/dist/tools/request-sandbox-access.js.map +1 -1
  70. package/dist/utils/debug-log.js +1 -1
  71. package/dist/utils/project.js +3 -3
  72. package/dist/utils/signals-pubsub.js +1 -1
  73. package/dist/utils/slash-command-loader.js +1 -1
  74. package/dist/utils/slash-command-processor.js +1 -1
  75. package/dist/utils/storage-maintenance.js +1 -1
  76. package/dist/utils/thread-lock.js +1 -1
  77. package/dist/utils/update-check.js +2 -2
  78. package/dist/workflows/register-primitives.js +1 -1
  79. package/package.json +15 -11
@@ -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 { MCPClient, MCPOAuthClientProvider } from '@mastra/mcp';\nimport type { 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\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 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] = { command: cfg.command, args: cfg.args, env: cfg.env, stderr: 'pipe' };\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 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 } else {\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 }\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":"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"}
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 { MCPClient, MCPOAuthClientProvider } from '@mastra/mcp';\nimport type { 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\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 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 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 } else {\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 }\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":"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"}
package/dist/mcp/state.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { getAppDataDir } from "../utils/project.js";
2
- import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "fs";
3
2
  import { dirname, join } from "path";
3
+ import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "fs";
4
4
  //#region src/mcp/state.ts
5
5
  /**
6
6
  * Persisted MCP disable state — mastracode-owned so user config files
@@ -11,6 +11,8 @@ export interface McpStdioServerConfig {
11
11
  command: string;
12
12
  /** Arguments for the command */
13
13
  args?: string[];
14
+ /** Working directory for the server process. Defaults to the parent process directory. */
15
+ cwd?: string;
14
16
  /** Environment variables to set for the server process */
15
17
  env?: Record<string, string>;
16
18
  }
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/mcp/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;GAGG;AACH,MAAM,WAAW,oBAAoB;IACnC,mDAAmD;IACnD,OAAO,EAAE,MAAM,CAAC;IAChB,gCAAgC;IAChC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,0DAA0D;IAC1D,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9B;AAED;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IAClC,gDAAgD;IAChD,GAAG,EAAE,MAAM,CAAC;IACZ,sDAAsD;IACtD,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,kEAAkE;IAClE,KAAK,CAAC,EAAE,kBAAkB,CAAC;CAC5B;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;;;OAOG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,uCAAuC;IACvC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,6CAA6C;IAC7C,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kDAAkD;IAClD,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;GAGG;AACH,MAAM,MAAM,eAAe,GAAG,oBAAoB,GAAG,mBAAmB,CAAC;AAEzE;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,oCAAoC;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,mDAAmD;IACnD,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;GAGG;AACH,MAAM,WAAW,SAAS;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IAC7C,cAAc,CAAC,EAAE,gBAAgB,EAAE,CAAC;CACrC;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,oCAAoC;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,gDAAgD;IAChD,SAAS,EAAE,OAAO,CAAC;IACnB,iDAAiD;IACjD,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,8CAA8C;IAC9C,SAAS,EAAE,MAAM,CAAC;IAClB,kCAAkC;IAClC,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,wCAAwC;IACxC,SAAS,EAAE,OAAO,GAAG,MAAM,CAAC;IAC5B,yCAAyC;IACzC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,6EAA6E;IAC7E,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;;OAIG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;OAIG;IACH,aAAa,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAC;IACrC,gGAAgG;IAChG,eAAe,CAAC,EAAE,SAAS,GAAG,UAAU,CAAC;IACzC,kGAAkG;IAClG,aAAa,CAAC,EAAE,SAAS,GAAG,UAAU,CAAC;IACvC,mGAAmG;IACnG,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/mcp/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;GAGG;AACH,MAAM,WAAW,oBAAoB;IACnC,mDAAmD;IACnD,OAAO,EAAE,MAAM,CAAC;IAChB,gCAAgC;IAChC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,0FAA0F;IAC1F,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,0DAA0D;IAC1D,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9B;AAED;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IAClC,gDAAgD;IAChD,GAAG,EAAE,MAAM,CAAC;IACZ,sDAAsD;IACtD,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,kEAAkE;IAClE,KAAK,CAAC,EAAE,kBAAkB,CAAC;CAC5B;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;;;OAOG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,uCAAuC;IACvC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,6CAA6C;IAC7C,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kDAAkD;IAClD,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;GAGG;AACH,MAAM,MAAM,eAAe,GAAG,oBAAoB,GAAG,mBAAmB,CAAC;AAEzE;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,oCAAoC;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,mDAAmD;IACnD,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;GAGG;AACH,MAAM,WAAW,SAAS;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IAC7C,cAAc,CAAC,EAAE,gBAAgB,EAAE,CAAC;CACrC;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,oCAAoC;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,gDAAgD;IAChD,SAAS,EAAE,OAAO,CAAC;IACnB,iDAAiD;IACjD,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,8CAA8C;IAC9C,SAAS,EAAE,MAAM,CAAC;IAClB,kCAAkC;IAClC,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,wCAAwC;IACxC,SAAS,EAAE,OAAO,GAAG,MAAM,CAAC;IAC5B,yCAAyC;IACzC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,6EAA6E;IAC7E,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;;OAIG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;OAIG;IACH,aAAa,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAC;IACrC,gGAAgG;IAChG,eAAe,CAAC,EAAE,SAAS,GAAG,UAAU,CAAC;IACzC,kGAAkG;IAClG,aAAa,CAAC,EAAE,SAAS,GAAG,UAAU,CAAC;IACvC,mGAAmG;IACnG,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B"}
@@ -1,13 +1,13 @@
1
+ import { THINKING_LEVEL_VALUES, isThinkingLevelSetting, resolveDefaultThinkingLevel as resolveDefaultThinkingLevel$1 } from "../thinking.js";
1
2
  import { getAppDataDir } from "../utils/project.js";
2
3
  import { AuthStorage, PROVIDER_DEFAULT_MODELS } from "../auth/storage.js";
3
4
  import { OPENAI_PREFIX, normalizeAnthropicModelId, remapOpenAIModelForCodexOAuth, stripMastraGatewayPrefix } from "../providers/model-ids.js";
4
- import { THINKING_LEVEL_VALUES, isThinkingLevelSetting, resolveDefaultThinkingLevel as resolveDefaultThinkingLevel$1 } from "../thinking.js";
5
5
  import { buildCodexStagehandFetch, createCodexMiddleware } from "../providers/openai-codex.js";
6
6
  import { DEFAULT_STT_PROVIDER, resolveSTTModel } from "../voice/stt-registry.js";
7
7
  import { pruneUnknownModePackFallbacks, pruneUnknownPackAccountPreferences } from "./packs.js";
8
- import { randomUUID } from "crypto";
9
- import { existsSync, mkdirSync, readFileSync, renameSync, rmSync, statSync, writeFileSync } from "fs";
10
8
  import { dirname, join } from "path";
9
+ import { existsSync, mkdirSync, readFileSync, renameSync, rmSync, statSync, writeFileSync } from "fs";
10
+ import { randomUUID } from "crypto";
11
11
  //#region src/onboarding/settings.ts
12
12
  /**
13
13
  * Persistent global settings stored in the app data directory as settings.json.
@@ -1,5 +1,5 @@
1
- import fs from "fs";
2
1
  import path from "path";
2
+ import fs from "fs";
3
3
  import { execa } from "execa";
4
4
  //#region src/plugins/dependencies.ts
5
5
  async function installPluginDependencies(pluginRoot, commandRoot = pluginRoot, options = {}) {
@@ -5,8 +5,8 @@ import { loadPluginRegistry, removePluginRecord, savePluginRegistry, setPluginRe
5
5
  import { loadPluginFromEntry } from "./loader.js";
6
6
  import { getSingleManifestPlugin } from "./manifest.js";
7
7
  import { ensureMastraCodePackageLink } from "./package-link.js";
8
- import fs from "fs";
9
8
  import path from "path";
9
+ import fs from "fs";
10
10
  import { execa } from "execa";
11
11
  //#region src/plugins/install.ts
12
12
  const ENTRY_CANDIDATES = ["src/index.ts", "index.ts"];
@@ -1,10 +1,10 @@
1
1
  import { getPluginRoot } from "./paths.js";
2
2
  import { loadPluginRegistry, mergePluginRegistries } from "./registry.js";
3
- import { isSignalProvider } from "@mastra/core/signals";
4
- import { createHash } from "crypto";
5
- import fs from "fs";
6
3
  import path from "path";
4
+ import fs from "fs";
7
5
  import { pathToFileURL } from "url";
6
+ import { createHash } from "crypto";
7
+ import { isSignalProvider } from "@mastra/core/signals";
8
8
  //#region src/plugins/loader.ts
9
9
  async function loadPlugins(options) {
10
10
  const records = mergePluginRegistries(options.globalRegistry ?? loadPluginRegistry(path.join(getPluginRoot("global", options), "plugins.json")), options.projectRegistry ?? loadPluginRegistry(path.join(getPluginRoot("project", options), "plugins.json")));
@@ -4,8 +4,8 @@ import { loadPluginRegistry, removePluginRecord, savePluginRegistry, setPluginRe
4
4
  import { collectActivePluginTools, isInsideDirectory, loadPlugins, resolvePluginEntryPath } from "./loader.js";
5
5
  import { ensureMastraCodePackageLink } from "./package-link.js";
6
6
  import { NON_INTERACTIVE_GIT_ENV, discoverLocalPlugins, installGithubPlugin, installLocalPlugin } from "./install.js";
7
- import fs from "fs";
8
7
  import path from "path";
8
+ import fs from "fs";
9
9
  import { execa } from "execa";
10
10
  //#region src/plugins/manager.ts
11
11
  const GITHUB_PLUGIN_POLL_INTERVAL_MS = 6e4;
@@ -1,5 +1,5 @@
1
- import fs from "fs";
2
1
  import path from "path";
2
+ import fs from "fs";
3
3
  //#region src/plugins/manifest.ts
4
4
  const PLUGIN_MANIFEST_FILE = ".mastracode-plugin.json";
5
5
  function loadPluginManifest(rootDir) {
@@ -1,5 +1,5 @@
1
- import fs from "fs";
2
1
  import path from "path";
2
+ import fs from "fs";
3
3
  import { fileURLToPath } from "url";
4
4
  //#region src/plugins/package-link.ts
5
5
  const MODULE_DIR = path.dirname(fileURLToPath(import.meta.url));
@@ -1,6 +1,6 @@
1
1
  import "../constants.js";
2
- import os from "os";
3
2
  import path from "path";
3
+ import os from "os";
4
4
  //#region src/plugins/paths.ts
5
5
  function getPluginRoot(scope, options) {
6
6
  const configDir = options.configDir ?? ".mastracode";
@@ -1,5 +1,5 @@
1
- import fs from "fs";
2
1
  import path from "path";
2
+ import fs from "fs";
3
3
  //#region src/plugins/registry.ts
4
4
  const EMPTY_PLUGIN_REGISTRY = {
5
5
  plugins: {},
@@ -1,8 +1,8 @@
1
1
  import "../constants.js";
2
2
  import { upsertPluginManifestEntry } from "./manifest.js";
3
3
  import { ensureMastraCodePackageLink } from "./package-link.js";
4
- import fs from "fs";
5
4
  import path from "path";
5
+ import fs from "fs";
6
6
  //#region src/plugins/scaffold.ts
7
7
  function resolveScaffoldTarget(target, options = {}) {
8
8
  if (isBarePluginName(target)) return path.join(options.projectRoot ?? process.cwd(), options.configDir ?? ".mastracode", "plugins", "sources", "local", target);
@@ -1,6 +1,6 @@
1
- import { randomUUID } from "crypto";
2
- import { homedir } from "os";
3
1
  import { join } from "path";
2
+ import { homedir } from "os";
3
+ import { randomUUID } from "crypto";
4
4
  import { appendFile, chmod, mkdir, rename, rm, writeFile } from "fs/promises";
5
5
  import { Session } from "inspector/promises";
6
6
  import { PerformanceObserver } from "perf_hooks";
@@ -1,6 +1,6 @@
1
1
  import { getBedrockModelCatalog } from "./amazon-bedrock.js";
2
- import { existsSync } from "fs";
3
2
  import path from "path";
3
+ import { existsSync } from "fs";
4
4
  import { MastraModelGateway } from "@mastra/core/llm";
5
5
  import { createAmazonBedrock } from "@ai-sdk/amazon-bedrock";
6
6
  import { fromNodeProviderChain } from "@aws-sdk/credential-providers";
@@ -1,6 +1,6 @@
1
+ import { supportsMaxReasoningEffort } from "../thinking.js";
1
2
  import { AuthStorage } from "../auth/storage.js";
2
3
  import { ProviderAuthRequiredError } from "../auth/provider-auth-error.js";
3
- import { supportsMaxReasoningEffort } from "../thinking.js";
4
4
  import { createOpenAI } from "@ai-sdk/openai";
5
5
  import { wrapLanguageModel } from "ai";
6
6
  //#region src/providers/openai-codex.ts
package/dist/schema.js CHANGED
@@ -1,5 +1,5 @@
1
- import { DEFAULT_CONFIG_DIR, DEFAULT_OM_MODEL_ID } from "./constants.js";
2
1
  import { THINKING_LEVEL_VALUES } from "./thinking.js";
2
+ import { DEFAULT_CONFIG_DIR, DEFAULT_OM_MODEL_ID } from "./constants.js";
3
3
  import { z } from "zod";
4
4
  //#region src/schema.ts
5
5
  const stateSchema = z.object({
@@ -1,9 +1,9 @@
1
1
  import { getAllowedPathsFromContext, isPathAllowed } from "./utils.js";
2
- import * as os$1 from "os";
3
2
  import * as path$1 from "path";
3
+ import * as os$1 from "os";
4
+ import { LocalFilesystem } from "@mastra/core/workspace";
4
5
  import { createTool } from "@mastra/core/tools";
5
6
  import { z } from "zod";
6
- import { LocalFilesystem } from "@mastra/core/workspace";
7
7
  //#region src/tools/request-sandbox-access.ts
8
8
  /**
9
9
  * request_access tool — requests permission to access a directory outside the project root.
@@ -30,9 +30,10 @@ const requestSandboxAccessTool = createTool({
30
30
  execute: async ({ path: requestedPath, reason }, context) => {
31
31
  try {
32
32
  const agentControllerCtx = context?.requestContext?.get("controller");
33
+ const projectRoot = agentControllerCtx?.getState()?.projectPath ?? process.cwd();
33
34
  const expanded = expandTilde(requestedPath);
34
- const absolutePath = path$1.isAbsolute(expanded) ? expanded : path$1.resolve(process.cwd(), expanded);
35
- if (isPathAllowed(absolutePath, process.cwd(), getAllowedPathsFromContext(context))) return {
35
+ const absolutePath = path$1.isAbsolute(expanded) ? expanded : path$1.resolve(projectRoot, expanded);
36
+ if (isPathAllowed(absolutePath, projectRoot, getAllowedPathsFromContext(context))) return {
36
37
  content: `Access already granted: "${absolutePath}" is within the project root or allowed paths.`,
37
38
  isError: false
38
39
  };
@@ -1 +1 @@
1
- {"version":3,"file":"request-sandbox-access.js","names":["os","path"],"sources":["../../src/tools/request-sandbox-access.ts"],"sourcesContent":["/**\n * request_access tool — requests permission to access a directory outside the project root.\n * The user can approve or deny the request via TUI dialog.\n */\n\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport type { AgentControllerRequestContext } from '@mastra/core/agent-controller';\nimport { createTool } from '@mastra/core/tools';\nimport { LocalFilesystem } from '@mastra/core/workspace';\nimport { z } from 'zod';\nimport type { MastraCodeState } from '../schema.js';\nimport { isPathAllowed, getAllowedPathsFromContext } from './utils.js';\n\nfunction expandTilde(p: string): string {\n if (p === '~') return os.homedir();\n if (p.startsWith('~/') || p.startsWith('~\\\\')) return path.join(os.homedir(), p.slice(2));\n return p;\n}\n\ntype RequestSandboxAccessInput = {\n path: string;\n reason: string;\n};\n\nconst requestSandboxAccessInputSchema = z.object({\n path: z.string().min(1).describe('The absolute path to the directory you need access to.'),\n reason: z.string().min(1).describe('Brief explanation of why you need access to this directory.'),\n});\n\nexport const requestSandboxAccessTool = createTool({\n id: 'request_access',\n description: `Request permission to access a directory outside the current project. Use this when you need to read or write files in a directory that is not within the project root. The user will be prompted to approve or deny the request.`,\n inputSchema: requestSandboxAccessInputSchema,\n suspendSchema: z.object({\n kind: z.literal('sandbox_access_request'),\n path: z.string(),\n reason: z.string(),\n }),\n resumeSchema: z.union([z.string(), z.array(z.string())]),\n execute: async ({ path: requestedPath, reason }: RequestSandboxAccessInput, context: any) => {\n try {\n const agentControllerCtx = context?.requestContext?.get('controller') as\n | AgentControllerRequestContext<MastraCodeState>\n | undefined;\n\n // Resolve to absolute path (expand ~ first since Node path APIs don't handle it)\n const expanded = expandTilde(requestedPath);\n const absolutePath = path.isAbsolute(expanded) ? expanded : path.resolve(process.cwd(), expanded);\n\n // Check if already allowed\n const projectRoot = process.cwd();\n const allowedPaths = getAllowedPathsFromContext(context);\n if (isPathAllowed(absolutePath, projectRoot, allowedPaths)) {\n return {\n content: `Access already granted: \"${absolutePath}\" is within the project root or allowed paths.`,\n isError: false,\n };\n }\n\n const suspend = context?.agent?.suspend ?? context?.suspend;\n const resumeData = context?.agent?.resumeData ?? context?.resumeData;\n\n // First pass: pause via the native tool-suspension primitive so the host can\n // prompt the user. The suspend payload carries the request details; the host\n // resumes with the user's answer as resume data.\n if (resumeData === undefined) {\n if (!suspend) {\n return {\n content: `Cannot request sandbox access: interactive context not available. The user should manually run /sandbox add ${absolutePath}`,\n isError: true,\n };\n }\n await suspend({ kind: 'sandbox_access_request', path: absolutePath, reason });\n return;\n }\n\n const answerText = Array.isArray(resumeData) ? resumeData.join(', ') : String(resumeData);\n const approved = answerText.toLowerCase().startsWith('y') || answerText.toLowerCase() === 'approve';\n if (approved) {\n // Persist to controller state first (and await it) so the value is\n // committed before the next tool call re-derives the workspace's\n // allowed paths from state. The workspace factory rebuilds the\n // filesystem allowlist from `sandboxAllowedPaths` on every call\n // (getDynamicWorkspace), so an unawaited setState would let that\n // rebuild clobber the in-turn widen below before the grant lands.\n const controllerState = agentControllerCtx?.getState();\n const currentAllowed = (controllerState?.sandboxAllowedPaths as string[] | undefined) ?? [];\n const nextAllowed = currentAllowed.includes(absolutePath) ? currentAllowed : [...currentAllowed, absolutePath];\n if (!currentAllowed.includes(absolutePath)) {\n await agentControllerCtx?.setState({\n sandboxAllowedPaths: nextAllowed,\n });\n }\n\n // Also update the live workspace filesystem immediately so tools in\n // the same turn (e.g. `view`) can access the path without waiting for\n // a fresh workspace build. The resolved workspace is carried on the\n // controller request context — the tool-execution context does not expose\n // it — so read the filesystem from there.\n const fs = agentControllerCtx?.workspace?.filesystem ?? context?.workspace?.filesystem;\n if (fs instanceof LocalFilesystem) {\n fs.setAllowedPaths((prev: readonly string[]) => [...prev, absolutePath]);\n }\n\n return {\n content: `Access granted: \"${absolutePath}\" has been added to allowed paths. You can now access files in this directory.`,\n isError: false,\n };\n } else {\n return {\n content: `Access denied: The user declined access to \"${absolutePath}\".`,\n isError: false,\n };\n }\n } catch (error) {\n const msg = error instanceof Error ? error.message : 'Unknown error';\n return {\n content: `Failed to request sandbox access: ${msg}`,\n isError: true,\n };\n }\n },\n} as any);\n"],"mappings":";;;;;;;;;;;AAcA,SAAS,YAAY,GAAmB;CACtC,IAAI,MAAM,KAAK,OAAOA,KAAG,QAAQ;CACjC,IAAI,EAAE,WAAW,IAAI,KAAK,EAAE,WAAW,KAAK,GAAG,OAAOC,OAAK,KAAKD,KAAG,QAAQ,GAAG,EAAE,MAAM,CAAC,CAAC;CACxF,OAAO;AACT;AAYA,MAAa,2BAA2B,WAAW;CACjD,IAAI;CACJ,aAAa;CACb,aARsC,EAAE,OAAO;EAC/C,MAAM,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,wDAAwD;EACzF,QAAQ,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,6DAA6D;CAClG,CAKe;CACb,eAAe,EAAE,OAAO;EACtB,MAAM,EAAE,QAAQ,wBAAwB;EACxC,MAAM,EAAE,OAAO;EACf,QAAQ,EAAE,OAAO;CACnB,CAAC;CACD,cAAc,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CACvD,SAAS,OAAO,EAAE,MAAM,eAAe,UAAqC,YAAiB;EAC3F,IAAI;GACF,MAAM,qBAAqB,SAAS,gBAAgB,IAAI,YAAY;GAKpE,MAAM,WAAW,YAAY,aAAa;GAC1C,MAAM,eAAeC,OAAK,WAAW,QAAQ,IAAI,WAAWA,OAAK,QAAQ,QAAQ,IAAI,GAAG,QAAQ;GAKhG,IAAI,cAAc,cAFE,QAAQ,IAEc,GADrB,2BAA2B,OACQ,CAAC,GACvD,OAAO;IACL,SAAS,4BAA4B,aAAa;IAClD,SAAS;GACX;GAGF,MAAM,UAAU,SAAS,OAAO,WAAW,SAAS;GACpD,MAAM,aAAa,SAAS,OAAO,cAAc,SAAS;GAK1D,IAAI,eAAe,KAAA,GAAW;IAC5B,IAAI,CAAC,SACH,OAAO;KACL,SAAS,+GAA+G;KACxH,SAAS;IACX;IAEF,MAAM,QAAQ;KAAE,MAAM;KAA0B,MAAM;KAAc;IAAO,CAAC;IAC5E;GACF;GAEA,MAAM,aAAa,MAAM,QAAQ,UAAU,IAAI,WAAW,KAAK,IAAI,IAAI,OAAO,UAAU;GAExF,IADiB,WAAW,YAAY,CAAC,CAAC,WAAW,GAAG,KAAK,WAAW,YAAY,MAAM,WAC5E;IAQZ,MAAM,kBADkB,oBAAoB,SAAS,EAAA,EACZ,uBAAgD,CAAC;IAC1F,MAAM,cAAc,eAAe,SAAS,YAAY,IAAI,iBAAiB,CAAC,GAAG,gBAAgB,YAAY;IAC7G,IAAI,CAAC,eAAe,SAAS,YAAY,GACvC,MAAM,oBAAoB,SAAS,EACjC,qBAAqB,YACvB,CAAC;IAQH,MAAM,KAAK,oBAAoB,WAAW,cAAc,SAAS,WAAW;IAC5E,IAAI,cAAc,iBAChB,GAAG,iBAAiB,SAA4B,CAAC,GAAG,MAAM,YAAY,CAAC;IAGzE,OAAO;KACL,SAAS,oBAAoB,aAAa;KAC1C,SAAS;IACX;GACF,OACE,OAAO;IACL,SAAS,+CAA+C,aAAa;IACrE,SAAS;GACX;EAEJ,SAAS,OAAO;GAEd,OAAO;IACL,SAAS,qCAFC,iBAAiB,QAAQ,MAAM,UAAU;IAGnD,SAAS;GACX;EACF;CACF;AACF,CAAQ"}
1
+ {"version":3,"file":"request-sandbox-access.js","names":["os","path"],"sources":["../../src/tools/request-sandbox-access.ts"],"sourcesContent":["/**\n * request_access tool — requests permission to access a directory outside the project root.\n * The user can approve or deny the request via TUI dialog.\n */\n\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport type { AgentControllerRequestContext } from '@mastra/core/agent-controller';\nimport { createTool } from '@mastra/core/tools';\nimport { LocalFilesystem } from '@mastra/core/workspace';\nimport { z } from 'zod';\nimport type { MastraCodeState } from '../schema.js';\nimport { isPathAllowed, getAllowedPathsFromContext } from './utils.js';\n\nfunction expandTilde(p: string): string {\n if (p === '~') return os.homedir();\n if (p.startsWith('~/') || p.startsWith('~\\\\')) return path.join(os.homedir(), p.slice(2));\n return p;\n}\n\ntype RequestSandboxAccessInput = {\n path: string;\n reason: string;\n};\n\nconst requestSandboxAccessInputSchema = z.object({\n path: z.string().min(1).describe('The absolute path to the directory you need access to.'),\n reason: z.string().min(1).describe('Brief explanation of why you need access to this directory.'),\n});\n\nexport const requestSandboxAccessTool = createTool({\n id: 'request_access',\n description: `Request permission to access a directory outside the current project. Use this when you need to read or write files in a directory that is not within the project root. The user will be prompted to approve or deny the request.`,\n inputSchema: requestSandboxAccessInputSchema,\n suspendSchema: z.object({\n kind: z.literal('sandbox_access_request'),\n path: z.string(),\n reason: z.string(),\n }),\n resumeSchema: z.union([z.string(), z.array(z.string())]),\n execute: async ({ path: requestedPath, reason }: RequestSandboxAccessInput, context: any) => {\n try {\n const agentControllerCtx = context?.requestContext?.get('controller') as\n | AgentControllerRequestContext<MastraCodeState>\n | undefined;\n\n // Resolve to absolute path (expand ~ first since Node path APIs don't handle it)\n const projectRoot = agentControllerCtx?.getState()?.projectPath ?? process.cwd();\n const expanded = expandTilde(requestedPath);\n const absolutePath = path.isAbsolute(expanded) ? expanded : path.resolve(projectRoot, expanded);\n\n // Check if already allowed\n const allowedPaths = getAllowedPathsFromContext(context);\n if (isPathAllowed(absolutePath, projectRoot, allowedPaths)) {\n return {\n content: `Access already granted: \"${absolutePath}\" is within the project root or allowed paths.`,\n isError: false,\n };\n }\n\n const suspend = context?.agent?.suspend ?? context?.suspend;\n const resumeData = context?.agent?.resumeData ?? context?.resumeData;\n\n // First pass: pause via the native tool-suspension primitive so the host can\n // prompt the user. The suspend payload carries the request details; the host\n // resumes with the user's answer as resume data.\n if (resumeData === undefined) {\n if (!suspend) {\n return {\n content: `Cannot request sandbox access: interactive context not available. The user should manually run /sandbox add ${absolutePath}`,\n isError: true,\n };\n }\n await suspend({ kind: 'sandbox_access_request', path: absolutePath, reason });\n return;\n }\n\n const answerText = Array.isArray(resumeData) ? resumeData.join(', ') : String(resumeData);\n const approved = answerText.toLowerCase().startsWith('y') || answerText.toLowerCase() === 'approve';\n if (approved) {\n // Persist to controller state first (and await it) so the value is\n // committed before the next tool call re-derives the workspace's\n // allowed paths from state. The workspace factory rebuilds the\n // filesystem allowlist from `sandboxAllowedPaths` on every call\n // (getDynamicWorkspace), so an unawaited setState would let that\n // rebuild clobber the in-turn widen below before the grant lands.\n const controllerState = agentControllerCtx?.getState();\n const currentAllowed = (controllerState?.sandboxAllowedPaths as string[] | undefined) ?? [];\n const nextAllowed = currentAllowed.includes(absolutePath) ? currentAllowed : [...currentAllowed, absolutePath];\n if (!currentAllowed.includes(absolutePath)) {\n await agentControllerCtx?.setState({\n sandboxAllowedPaths: nextAllowed,\n });\n }\n\n // Also update the live workspace filesystem immediately so tools in\n // the same turn (e.g. `view`) can access the path without waiting for\n // a fresh workspace build. The resolved workspace is carried on the\n // controller request context — the tool-execution context does not expose\n // it — so read the filesystem from there.\n const fs = agentControllerCtx?.workspace?.filesystem ?? context?.workspace?.filesystem;\n if (fs instanceof LocalFilesystem) {\n fs.setAllowedPaths((prev: readonly string[]) => [...prev, absolutePath]);\n }\n\n return {\n content: `Access granted: \"${absolutePath}\" has been added to allowed paths. You can now access files in this directory.`,\n isError: false,\n };\n } else {\n return {\n content: `Access denied: The user declined access to \"${absolutePath}\".`,\n isError: false,\n };\n }\n } catch (error) {\n const msg = error instanceof Error ? error.message : 'Unknown error';\n return {\n content: `Failed to request sandbox access: ${msg}`,\n isError: true,\n };\n }\n },\n} as any);\n"],"mappings":";;;;;;;;;;;AAcA,SAAS,YAAY,GAAmB;CACtC,IAAI,MAAM,KAAK,OAAOA,KAAG,QAAQ;CACjC,IAAI,EAAE,WAAW,IAAI,KAAK,EAAE,WAAW,KAAK,GAAG,OAAOC,OAAK,KAAKD,KAAG,QAAQ,GAAG,EAAE,MAAM,CAAC,CAAC;CACxF,OAAO;AACT;AAYA,MAAa,2BAA2B,WAAW;CACjD,IAAI;CACJ,aAAa;CACb,aARsC,EAAE,OAAO;EAC/C,MAAM,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,wDAAwD;EACzF,QAAQ,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,6DAA6D;CAClG,CAKe;CACb,eAAe,EAAE,OAAO;EACtB,MAAM,EAAE,QAAQ,wBAAwB;EACxC,MAAM,EAAE,OAAO;EACf,QAAQ,EAAE,OAAO;CACnB,CAAC;CACD,cAAc,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CACvD,SAAS,OAAO,EAAE,MAAM,eAAe,UAAqC,YAAiB;EAC3F,IAAI;GACF,MAAM,qBAAqB,SAAS,gBAAgB,IAAI,YAAY;GAKpE,MAAM,cAAc,oBAAoB,SAAS,CAAC,EAAE,eAAe,QAAQ,IAAI;GAC/E,MAAM,WAAW,YAAY,aAAa;GAC1C,MAAM,eAAeC,OAAK,WAAW,QAAQ,IAAI,WAAWA,OAAK,QAAQ,aAAa,QAAQ;GAI9F,IAAI,cAAc,cAAc,aADX,2BAA2B,OACQ,CAAC,GACvD,OAAO;IACL,SAAS,4BAA4B,aAAa;IAClD,SAAS;GACX;GAGF,MAAM,UAAU,SAAS,OAAO,WAAW,SAAS;GACpD,MAAM,aAAa,SAAS,OAAO,cAAc,SAAS;GAK1D,IAAI,eAAe,KAAA,GAAW;IAC5B,IAAI,CAAC,SACH,OAAO;KACL,SAAS,+GAA+G;KACxH,SAAS;IACX;IAEF,MAAM,QAAQ;KAAE,MAAM;KAA0B,MAAM;KAAc;IAAO,CAAC;IAC5E;GACF;GAEA,MAAM,aAAa,MAAM,QAAQ,UAAU,IAAI,WAAW,KAAK,IAAI,IAAI,OAAO,UAAU;GAExF,IADiB,WAAW,YAAY,CAAC,CAAC,WAAW,GAAG,KAAK,WAAW,YAAY,MAAM,WAC5E;IAQZ,MAAM,kBADkB,oBAAoB,SAAS,EAAA,EACZ,uBAAgD,CAAC;IAC1F,MAAM,cAAc,eAAe,SAAS,YAAY,IAAI,iBAAiB,CAAC,GAAG,gBAAgB,YAAY;IAC7G,IAAI,CAAC,eAAe,SAAS,YAAY,GACvC,MAAM,oBAAoB,SAAS,EACjC,qBAAqB,YACvB,CAAC;IAQH,MAAM,KAAK,oBAAoB,WAAW,cAAc,SAAS,WAAW;IAC5E,IAAI,cAAc,iBAChB,GAAG,iBAAiB,SAA4B,CAAC,GAAG,MAAM,YAAY,CAAC;IAGzE,OAAO;KACL,SAAS,oBAAoB,aAAa;KAC1C,SAAS;IACX;GACF,OACE,OAAO;IACL,SAAS,+CAA+C,aAAa;IACrE,SAAS;GACX;EAEJ,SAAS,OAAO;GAEd,OAAO;IACL,SAAS,qCAFC,iBAAiB,QAAQ,MAAM,UAAU;IAGnD,SAAS;GACX;EACF;CACF;AACF,CAAQ"}
@@ -1,6 +1,6 @@
1
1
  import { getAppDataDir } from "./project.js";
2
- import * as fs$1 from "fs";
3
2
  import * as path$1 from "path";
3
+ import * as fs$1 from "fs";
4
4
  //#region src/utils/debug-log.ts
5
5
  const MAX_LOG_SIZE = 5 * 1024 * 1024;
6
6
  const KEEP_SIZE = 4 * 1024 * 1024;
@@ -1,9 +1,9 @@
1
1
  import { DEFAULT_CONFIG_DIR } from "../constants.js";
2
- import { createHash } from "crypto";
3
- import fs from "fs";
4
- import os from "os";
5
2
  import path from "path";
6
3
  import { execFile, execSync } from "child_process";
4
+ import fs from "fs";
5
+ import os from "os";
6
+ import { createHash } from "crypto";
7
7
  //#region src/utils/project.ts
8
8
  /**
9
9
  * Project detection utilities
@@ -1,5 +1,5 @@
1
- import { createHash } from "crypto";
2
1
  import { join } from "path";
2
+ import { createHash } from "crypto";
3
3
  import { mkdir } from "fs/promises";
4
4
  import { PubSub, UnixSocketPubSub } from "@mastra/core/events";
5
5
  //#region src/utils/signals-pubsub.ts
@@ -1,7 +1,7 @@
1
1
  import { DEFAULT_CONFIG_DIR } from "../constants.js";
2
2
  import { isPathWithinRoot } from "./path-security.js";
3
- import { promises } from "fs";
4
3
  import * as path$1 from "path";
4
+ import { promises } from "fs";
5
5
  import { parse } from "yaml";
6
6
  //#region src/utils/slash-command-loader.ts
7
7
  /**
@@ -1,6 +1,6 @@
1
- import { promises } from "fs";
2
1
  import * as path$1 from "path";
3
2
  import { execSync } from "child_process";
3
+ import { promises } from "fs";
4
4
  //#region src/utils/slash-command-processor.ts
5
5
  /**
6
6
  * Process a slash command by replacing variables and executing shell commands
@@ -1,6 +1,6 @@
1
1
  import { getDatabasePath, getVectorDatabasePath } from "./project.js";
2
- import { closeSync, existsSync, openSync, readSync, renameSync, rmSync, statSync, statfsSync } from "fs";
3
2
  import { dirname } from "path";
3
+ import { closeSync, existsSync, openSync, readSync, renameSync, rmSync, statSync, statfsSync } from "fs";
4
4
  import Database from "libsql";
5
5
  //#region src/utils/storage-maintenance.ts
6
6
  /**
@@ -1,6 +1,6 @@
1
1
  import { getAppDataDir } from "./project.js";
2
- import * as fs$1 from "fs";
3
2
  import * as path$1 from "path";
3
+ import * as fs$1 from "fs";
4
4
  //#region src/utils/thread-lock.ts
5
5
  /**
6
6
  * Thread lock — ensures only one process writes to a thread at a time.
@@ -1,7 +1,7 @@
1
- import { readFileSync, realpathSync } from "fs";
2
- import { homedir } from "os";
3
1
  import { dirname, join, resolve, sep } from "path";
4
2
  import { execFile } from "child_process";
3
+ import { readFileSync, realpathSync } from "fs";
4
+ import { homedir } from "os";
5
5
  import { fileURLToPath } from "url";
6
6
  //#region src/utils/update-check.ts
7
7
  /**
@@ -3,8 +3,8 @@ import { createConfiguredWebTools } from "../tools/web-search.js";
3
3
  import { createMastraCodeWorkspaceTools } from "../agents/tool-availability.js";
4
4
  import { LazyNotificationsStorage } from "../agents/tools.js";
5
5
  import { workflowBuilderAgent } from "../agents/workflow-builder-agent.js";
6
- import { createNotificationInboxTool } from "@mastra/core/notifications";
7
6
  import { LocalFilesystem, LocalSandbox, Workspace, createWorkspaceTools } from "@mastra/core/workspace";
7
+ import { createNotificationInboxTool } from "@mastra/core/notifications";
8
8
  //#region src/workflows/register-primitives.ts
9
9
  async function registerWorkflowBuilderPrimitives(mastra, options) {
10
10
  const { projectPath, allowedPaths = [], codeAgent, mcpManager } = options;