@mastra/code-sdk 1.0.3-alpha.0 → 1.1.0-alpha.2
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.
- package/CHANGELOG.md +49 -0
- package/dist/acp/agent.js +155 -167
- package/dist/acp/agent.js.map +1 -1
- package/dist/acp/event-mapper.js +193 -168
- package/dist/acp/event-mapper.js.map +1 -1
- package/dist/acp/index.js +60 -49
- package/dist/acp/index.js.map +1 -1
- package/dist/acp/server.js +31 -30
- package/dist/acp/server.js.map +1 -1
- package/dist/acp.js +1 -4
- package/dist/agents/credential-resolver.js +40 -29
- package/dist/agents/credential-resolver.js.map +1 -1
- package/dist/agents/custom-provider-source.js +16 -9
- package/dist/agents/custom-provider-source.js.map +1 -1
- package/dist/agents/instructions.js +27 -36
- package/dist/agents/instructions.js.map +1 -1
- package/dist/agents/mastracode-gateway.js +355 -428
- package/dist/agents/mastracode-gateway.js.map +1 -1
- package/dist/agents/memory.js +87 -78
- package/dist/agents/memory.js.map +1 -1
- package/dist/agents/model.js +114 -119
- package/dist/agents/model.js.map +1 -1
- package/dist/agents/modes/build.js +12 -13
- package/dist/agents/modes/build.js.map +1 -1
- package/dist/agents/modes/explore.js +14 -13
- package/dist/agents/modes/explore.js.map +1 -1
- package/dist/agents/modes/plan.js +14 -15
- package/dist/agents/modes/plan.js.map +1 -1
- package/dist/agents/prompts/agent-instructions.js +78 -69
- package/dist/agents/prompts/agent-instructions.js.map +1 -1
- package/dist/agents/prompts/build.js +19 -16
- package/dist/agents/prompts/build.js.map +1 -1
- package/dist/agents/prompts/fast.js +8 -4
- package/dist/agents/prompts/fast.js.map +1 -1
- package/dist/agents/prompts/index.js +48 -47
- package/dist/agents/prompts/index.js.map +1 -1
- package/dist/agents/prompts/model.js +6 -5
- package/dist/agents/prompts/model.js.map +1 -1
- package/dist/agents/prompts/plan.js +20 -16
- package/dist/agents/prompts/plan.js.map +1 -1
- package/dist/agents/prompts/tool-guidance.js +77 -109
- package/dist/agents/prompts/tool-guidance.js.map +1 -1
- package/dist/agents/sandbox-filesystem.js +245 -259
- package/dist/agents/sandbox-filesystem.js.map +1 -1
- package/dist/agents/sandbox-reattach.js +9 -11
- package/dist/agents/sandbox-reattach.js.map +1 -1
- package/dist/agents/thread-caveman-state.js +92 -81
- package/dist/agents/thread-caveman-state.js.map +1 -1
- package/dist/agents/tool-availability.js +62 -80
- package/dist/agents/tool-availability.js.map +1 -1
- package/dist/agents/tools.js +99 -139
- package/dist/agents/tools.js.map +1 -1
- package/dist/agents/workspace.js +232 -225
- package/dist/agents/workspace.js.map +1 -1
- package/dist/analytics.js +139 -128
- package/dist/analytics.js.map +1 -1
- package/dist/auth/authorization-input.js +39 -25
- package/dist/auth/authorization-input.js.map +1 -1
- package/dist/auth/device-code.js +112 -80
- package/dist/auth/device-code.js.map +1 -1
- package/dist/auth/index.js +2 -9
- package/dist/auth/pkce.js +27 -16
- package/dist/auth/pkce.js.map +1 -1
- package/dist/auth/providers/anthropic.js +107 -93
- package/dist/auth/providers/anthropic.js.map +1 -1
- package/dist/auth/providers/github-copilot.js +304 -293
- package/dist/auth/providers/github-copilot.js.map +1 -1
- package/dist/auth/providers/openai-codex.js +442 -460
- package/dist/auth/providers/openai-codex.js.map +1 -1
- package/dist/auth/providers/xai.js +179 -145
- package/dist/auth/providers/xai.js.map +1 -1
- package/dist/auth/storage.js +182 -175
- package/dist/auth/storage.js.map +1 -1
- package/dist/auth/types.js +1 -1
- package/dist/clipboard/index.js +206 -172
- package/dist/clipboard/index.js.map +1 -1
- package/dist/constants.js +11 -16
- package/dist/constants.js.map +1 -1
- package/dist/error-classification.js +19 -11
- package/dist/error-classification.js.map +1 -1
- package/dist/evals/context-builder.js +145 -104
- package/dist/evals/context-builder.js.map +1 -1
- package/dist/evals/index.js +4 -7
- package/dist/evals/scorers/classify-command.js +62 -41
- package/dist/evals/scorers/classify-command.js.map +1 -1
- package/dist/evals/scorers/efficiency.js +239 -181
- package/dist/evals/scorers/efficiency.js.map +1 -1
- package/dist/evals/scorers/extract-tools.js +51 -47
- package/dist/evals/scorers/extract-tools.js.map +1 -1
- package/dist/evals/scorers/index.js +1 -5
- package/dist/evals/scorers/outcome.js +321 -212
- package/dist/evals/scorers/outcome.js.map +1 -1
- package/dist/goal-manager.js +266 -261
- package/dist/goal-manager.js.map +1 -1
- package/dist/goal-signal.js +14 -13
- package/dist/goal-signal.js.map +1 -1
- package/dist/headless/cli.js +153 -154
- package/dist/headless/cli.js.map +1 -1
- package/dist/headless/flags.js +180 -178
- package/dist/headless/flags.js.map +1 -1
- package/dist/headless/format.js +72 -71
- package/dist/headless/format.js.map +1 -1
- package/dist/headless/index.js +5 -31
- package/dist/headless/policy.js +35 -31
- package/dist/headless/policy.js.map +1 -1
- package/dist/headless/run-mc.js +332 -334
- package/dist/headless/run-mc.js.map +1 -1
- package/dist/headless/types.js +16 -7
- package/dist/headless/types.js.map +1 -1
- package/dist/hooks/config.js +56 -61
- package/dist/hooks/config.js.map +1 -1
- package/dist/hooks/executor.js +118 -116
- package/dist/hooks/executor.js.map +1 -1
- package/dist/hooks/index.js +4 -15
- package/dist/hooks/manager.js +221 -280
- package/dist/hooks/manager.js.map +1 -1
- package/dist/hooks/types.js +5 -4
- package/dist/hooks/types.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +632 -712
- package/dist/index.js.map +1 -1
- package/dist/ipc/ipc-reporter.js +19 -22
- package/dist/ipc/ipc-reporter.js.map +1 -1
- package/dist/lsp/client.js +248 -306
- package/dist/lsp/client.js.map +1 -1
- package/dist/lsp/index.js +1 -6
- package/dist/lsp/language.js +39 -43
- package/dist/lsp/language.js.map +1 -1
- package/dist/lsp/manager.js +78 -93
- package/dist/lsp/manager.js.map +1 -1
- package/dist/lsp/server.js +151 -120
- package/dist/lsp/server.js.map +1 -1
- package/dist/lsp/workspace.js +50 -47
- package/dist/lsp/workspace.js.map +1 -1
- package/dist/mcp/config.js +210 -199
- package/dist/mcp/config.js.map +1 -1
- package/dist/mcp/index.js +2 -9
- package/dist/mcp/manager.js +482 -475
- package/dist/mcp/manager.js.map +1 -1
- package/dist/mcp/types.js +1 -1
- package/dist/onboarding/custom-packs.js +14 -17
- package/dist/onboarding/custom-packs.js.map +1 -1
- package/dist/onboarding/custom-providers.js +22 -20
- package/dist/onboarding/custom-providers.js.map +1 -1
- package/dist/onboarding/index.d.ts +1 -1
- package/dist/onboarding/index.d.ts.map +1 -1
- package/dist/onboarding/index.js +3 -21
- package/dist/onboarding/om-settings.d.ts +5 -0
- package/dist/onboarding/om-settings.d.ts.map +1 -1
- package/dist/onboarding/om-settings.js +41 -20
- package/dist/onboarding/om-settings.js.map +1 -1
- package/dist/onboarding/packs.d.ts +4 -6
- package/dist/onboarding/packs.d.ts.map +1 -1
- package/dist/onboarding/packs.js +154 -105
- package/dist/onboarding/packs.js.map +1 -1
- package/dist/onboarding/settings.js +575 -517
- package/dist/onboarding/settings.js.map +1 -1
- package/dist/permissions.js +112 -99
- package/dist/permissions.js.map +1 -1
- package/dist/plugin.js +21 -23
- package/dist/plugin.js.map +1 -1
- package/dist/plugins/dependencies.js +64 -87
- package/dist/plugins/dependencies.js.map +1 -1
- package/dist/plugins/install.js +159 -169
- package/dist/plugins/install.js.map +1 -1
- package/dist/plugins/loader.js +170 -185
- package/dist/plugins/loader.js.map +1 -1
- package/dist/plugins/manager.js +374 -380
- package/dist/plugins/manager.js.map +1 -1
- package/dist/plugins/manifest.js +38 -63
- package/dist/plugins/manifest.js.map +1 -1
- package/dist/plugins/package-link.js +48 -64
- package/dist/plugins/package-link.js.map +1 -1
- package/dist/plugins/paths.js +18 -19
- package/dist/plugins/paths.js.map +1 -1
- package/dist/plugins/registry.js +97 -81
- package/dist/plugins/registry.js.map +1 -1
- package/dist/plugins/scaffold.js +62 -98
- package/dist/plugins/scaffold.js.map +1 -1
- package/dist/plugins/types.js +1 -1
- package/dist/processors/plan-rejection-abort.js +45 -44
- package/dist/processors/plan-rejection-abort.js.map +1 -1
- package/dist/providers/amazon-bedrock-gateway.js +134 -125
- package/dist/providers/amazon-bedrock-gateway.js.map +1 -1
- package/dist/providers/amazon-bedrock.js +68 -47
- package/dist/providers/amazon-bedrock.js.map +1 -1
- package/dist/providers/claude-max.js +153 -133
- package/dist/providers/claude-max.js.map +1 -1
- package/dist/providers/github-copilot.js +232 -230
- package/dist/providers/github-copilot.js.map +1 -1
- package/dist/providers/openai-codex.js +271 -260
- package/dist/providers/openai-codex.js.map +1 -1
- package/dist/providers/xai.js +57 -50
- package/dist/providers/xai.js.map +1 -1
- package/dist/schema.js +91 -89
- package/dist/schema.js.map +1 -1
- package/dist/theme-palette.js +18 -14
- package/dist/theme-palette.js.map +1 -1
- package/dist/tool-names.js +46 -37
- package/dist/tool-names.js.map +1 -1
- package/dist/tools/index.js +2 -8
- package/dist/tools/request-sandbox-access.js +71 -80
- package/dist/tools/request-sandbox-access.js.map +1 -1
- package/dist/tools/utils.js +26 -16
- package/dist/tools/utils.js.map +1 -1
- package/dist/tools/web-search.js +51 -55
- package/dist/tools/web-search.js.map +1 -1
- package/dist/utils/binaries.js +65 -61
- package/dist/utils/binaries.js.map +1 -1
- package/dist/utils/debug-log.js +51 -47
- package/dist/utils/debug-log.js.map +1 -1
- package/dist/utils/errors.js +157 -192
- package/dist/utils/errors.js.map +1 -1
- package/dist/utils/gateway-sync.js +49 -37
- package/dist/utils/gateway-sync.js.map +1 -1
- package/dist/utils/path-security.js +7 -6
- package/dist/utils/path-security.js.map +1 -1
- package/dist/utils/plan-diff.js +58 -39
- package/dist/utils/plan-diff.js.map +1 -1
- package/dist/utils/plans.js +92 -74
- package/dist/utils/plans.js.map +1 -1
- package/dist/utils/project.js +318 -256
- package/dist/utils/project.js.map +1 -1
- package/dist/utils/signals-pubsub.js +117 -99
- package/dist/utils/signals-pubsub.js.map +1 -1
- package/dist/utils/slash-command-loader.js +118 -154
- package/dist/utils/slash-command-loader.js.map +1 -1
- package/dist/utils/slash-command-processor.js +92 -83
- package/dist/utils/slash-command-processor.js.map +1 -1
- package/dist/utils/stdin-pipe.js +87 -63
- package/dist/utils/stdin-pipe.js.map +1 -1
- package/dist/utils/storage-factory.js +104 -84
- package/dist/utils/storage-factory.js.map +1 -1
- package/dist/utils/storage-maintenance.js +249 -211
- package/dist/utils/storage-maintenance.js.map +1 -1
- package/dist/utils/thread-lock.js +96 -92
- package/dist/utils/thread-lock.js.map +1 -1
- package/dist/utils/token-estimator.js +12 -12
- package/dist/utils/token-estimator.js.map +1 -1
- package/dist/utils/update-check.d.ts +1 -1
- package/dist/utils/update-check.js +341 -259
- package/dist/utils/update-check.js.map +1 -1
- package/dist/voice/stt-registry.js +131 -113
- package/dist/voice/stt-registry.js.map +1 -1
- package/package.json +11 -11
- package/dist/acp.js.map +0 -1
- package/dist/auth/index.js.map +0 -1
- package/dist/auth/types.js.map +0 -1
- package/dist/evals/index.js.map +0 -1
- package/dist/evals/scorers/index.js.map +0 -1
- package/dist/headless/index.js.map +0 -1
- package/dist/hooks/index.js.map +0 -1
- package/dist/lsp/index.js.map +0 -1
- package/dist/mcp/index.js.map +0 -1
- package/dist/mcp/types.js.map +0 -1
- package/dist/onboarding/index.js.map +0 -1
- package/dist/plugins/types.js.map +0 -1
- package/dist/tools/index.js.map +0 -1
package/dist/mcp/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/mcp/config.ts"],"sourcesContent":["/**\n * MCP server configuration loading from filesystem.\n * Loads from:\n * 1. .claude/settings.local.json (Claude Code compat — lowest priority)\n * 2. ~/.mastracode/mcp.json (global)\n * 3. .mcp.json (project root — Claude Code compatible)\n * 4. .mastracode/mcp.json (project — highest priority)\n *\n * Higher-priority configs override lower ones by server name. The project root\n * `.mcp.json` is read so a project that already keeps MCP servers there for\n * Claude Code does not need to duplicate them under `.mastracode/`.\n */\n\nimport * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport { DEFAULT_CONFIG_DIR } from '../constants.js';\nimport type { McpConfig, McpHttpOAuthConfig, McpServerConfig, McpSkippedServer } from './types.js';\n\n/**\n * Default OAuth redirect URL for servers that do not configure one.\n * Port 1458 is stable across sessions so persisted tokens keep the same\n * storage fingerprint; it sits clear of the ports the Codex login flow\n * reserves (1455/1457). When 1458 is busy the callback server falls back\n * to the next sequential port, which stays covered by the client\n * registration (see `@mastra/mcp`'s `getCallbackUrlCandidates`).\n */\nexport const DEFAULT_OAUTH_REDIRECT_URL = 'http://127.0.0.1:1458/oauth/callback';\n\n// Matches the entire 127.0.0.0/8 range in dotted-quad form. `URL` normalizes\n// IPv4 hosts to four octets (so `127.1` becomes `127.0.0.1`), so anchoring the\n// pattern is enough — and it rejects lookalikes like `127.evil.com` that a\n// `startsWith('127.')` check would wrongly accept.\nconst LOOPBACK_IPV4 = /^127\\.(?:\\d{1,3})\\.(?:\\d{1,3})\\.(?:\\d{1,3})$/;\n\nfunction isLoopbackHostname(hostname: string): boolean {\n return hostname === 'localhost' || hostname === '[::1]' || hostname === '::1' || LOOPBACK_IPV4.test(hostname);\n}\n\n/**\n * Resolve the effective OAuth redirect URL for a server config.\n *\n * `callbackPort` (the Claude Code / Codex convention) takes precedence and\n * synthesizes `http://localhost:<port>/callback`. Config-file entries are\n * normalized by `parseOAuthConfig` (which also enforces that `callbackPort`\n * and `redirectUrl` are mutually exclusive), but programmatically registered\n * servers bypass the parser, so every consumer of the redirect URL must\n * resolve it through this helper rather than reading `redirectUrl` directly.\n */\nexport function resolveOAuthRedirectUrl(oauth: McpHttpOAuthConfig | undefined): string {\n if (oauth?.callbackPort !== undefined) {\n return `http://localhost:${oauth.callbackPort}/callback`;\n }\n return oauth?.redirectUrl ?? DEFAULT_OAUTH_REDIRECT_URL;\n}\n\nexport function loadMcpConfig(projectDir: string, configDirName = DEFAULT_CONFIG_DIR): McpConfig {\n const claudeConfig = loadClaudeSettings(projectDir);\n const globalConfig = loadSingleConfig(getGlobalMcpPath(configDirName));\n const rootConfig = loadSingleConfig(getRootMcpPath(projectDir));\n const projectConfig = loadSingleConfig(getProjectMcpPath(projectDir, configDirName));\n\n return mergeConfigs(claudeConfig, globalConfig, rootConfig, projectConfig);\n}\n\nexport function getProjectMcpPath(projectDir: string, configDirName = DEFAULT_CONFIG_DIR): string {\n return path.join(projectDir, configDirName, 'mcp.json');\n}\n\nexport function getRootMcpPath(projectDir: string): string {\n return path.join(projectDir, '.mcp.json');\n}\n\nexport function getGlobalMcpPath(configDirName = DEFAULT_CONFIG_DIR): string {\n return path.join(os.homedir(), configDirName, 'mcp.json');\n}\n\nexport function getClaudeSettingsPath(projectDir: string): string {\n return path.join(projectDir, '.claude', 'settings.local.json');\n}\n\nfunction loadSingleConfig(filePath: string): McpConfig {\n try {\n if (!fs.existsSync(filePath)) return {};\n const raw = fs.readFileSync(filePath, 'utf-8');\n return validateConfig(JSON.parse(raw));\n } catch {\n return {};\n }\n}\n\nfunction loadClaudeSettings(projectDir: string): McpConfig {\n try {\n const filePath = getClaudeSettingsPath(projectDir);\n if (!fs.existsSync(filePath)) return {};\n const raw = fs.readFileSync(filePath, 'utf-8');\n const parsed = JSON.parse(raw);\n // Claude Code stores mcpServers at the top level of settings\n if (parsed?.mcpServers && typeof parsed.mcpServers === 'object') {\n return validateConfig({ mcpServers: parsed.mcpServers });\n }\n return {};\n } catch {\n return {};\n }\n}\n\n/**\n * Expand `${VAR}` and `${VAR:-default}` references in a string from the\n * environment, matching how Claude Code resolves values in `.mcp.json`.\n * A referenced variable that is unset or empty falls back to its default,\n * or to an empty string when no default is given.\n */\nexport function expandEnvVars(value: string, env: NodeJS.ProcessEnv = process.env): string {\n return value.replace(\n /\\$\\{([A-Za-z_][A-Za-z0-9_]*)(?::-([^}]*))?\\}|\\$([A-Za-z_][A-Za-z0-9_]*)/g,\n (_match, bracedName, fallback, bareName) => {\n const name = bracedName ?? bareName;\n const resolved = env[name];\n if (resolved !== undefined && resolved !== '') return resolved;\n return fallback ?? '';\n },\n );\n}\n\n/**\n * Expand `${VAR}` and `$VAR` references in every string-valued HTTP header so that\n * secrets like API keys can be referenced from the environment instead of\n * being hardcoded in `mcp.json`.\n */\nfunction expandHeaderEnvVars(headers: Record<string, unknown>): Record<string, string> {\n const expanded: Record<string, string> = {};\n for (const [key, value] of Object.entries(headers)) {\n if (typeof value === 'string') expanded[key] = expandEnvVars(value);\n }\n return expanded;\n}\n\n/**\n * Expand `${VAR}` and `$VAR` references in every string-valued environment\n * variable passed to a stdio server, so that secrets can be referenced from the\n * host environment instead of being hardcoded in `mcp.json`.\n */\nfunction expandEnvValues(env: Record<string, unknown>): Record<string, string> {\n const expanded: Record<string, string> = {};\n for (const [key, value] of Object.entries(env)) {\n if (typeof value === 'string') expanded[key] = expandEnvVars(value);\n }\n return expanded;\n}\n\n/**\n * Classify a raw server entry as stdio, http, or skip (with reason).\n */\nexport function classifyServerEntry(raw: unknown): { kind: 'stdio' | 'http' | 'skip'; reason?: string } {\n if (!raw || typeof raw !== 'object') {\n return { kind: 'skip', reason: 'Invalid entry: expected an object' };\n }\n\n const obj = raw as Record<string, unknown>;\n const hasCommand = typeof obj.command === 'string';\n const hasUrl = typeof obj.url === 'string';\n\n if (hasCommand && hasUrl) {\n return { kind: 'skip', reason: 'Cannot specify both \"command\" and \"url\"' };\n }\n\n if (hasCommand) {\n return { kind: 'stdio' };\n }\n\n if (hasUrl) {\n try {\n new URL(expandEnvVars(obj.url as string));\n } catch {\n return { kind: 'skip', reason: `Invalid URL: \"${obj.url}\"` };\n }\n return { kind: 'http' };\n }\n\n return { kind: 'skip', reason: 'Missing required field: \"command\" (stdio) or \"url\" (http)' };\n}\n\nexport function validateConfig(raw: unknown): McpConfig {\n if (!raw || typeof raw !== 'object') return {};\n const obj = raw as Record<string, unknown>;\n\n if (!obj.mcpServers || typeof obj.mcpServers !== 'object') return {};\n\n const servers: Record<string, McpServerConfig> = {};\n const skippedServers: McpSkippedServer[] = [];\n const rawServers = obj.mcpServers as Record<string, unknown>;\n\n for (const [name, entry] of Object.entries(rawServers)) {\n const classification = classifyServerEntry(entry);\n\n if (classification.kind === 'stdio') {\n const e = entry as Record<string, unknown>;\n servers[name] = {\n command: e.command as string,\n args: Array.isArray(e.args) ? (e.args as string[]) : undefined,\n env:\n typeof e.env === 'object' && e.env !== null ? expandEnvValues(e.env as Record<string, unknown>) : undefined,\n };\n } else if (classification.kind === 'http') {\n const e = entry as Record<string, unknown>;\n const oauthResult = parseOAuthConfig(e.oauth);\n if (oauthResult.reason) {\n skippedServers.push({ name, reason: oauthResult.reason });\n continue;\n }\n servers[name] = {\n url: expandEnvVars(e.url as string),\n headers:\n typeof e.headers === 'object' && e.headers !== null\n ? expandHeaderEnvVars(e.headers as Record<string, unknown>)\n : undefined,\n oauth: oauthResult.config,\n };\n } else {\n skippedServers.push({ name, reason: classification.reason! });\n }\n }\n\n const result: McpConfig = {};\n if (Object.keys(servers).length > 0) {\n result.mcpServers = servers;\n }\n if (skippedServers.length > 0) {\n result.skippedServers = skippedServers;\n }\n return result;\n}\n\nfunction parseOAuthConfig(raw: unknown): { config?: McpHttpOAuthConfig; reason?: string } {\n if (raw === undefined) return {};\n if (!raw || typeof raw !== 'object') {\n return { reason: 'Invalid OAuth config: expected an object' };\n }\n\n const obj = raw as Record<string, unknown>;\n if (obj.redirectUrl !== undefined && typeof obj.redirectUrl !== 'string') {\n return { reason: 'Invalid OAuth config: \"redirectUrl\" must be a string' };\n }\n // `callbackPort` is a shorthand for a loopback redirect URL. It synthesizes\n // `http://localhost:<port>/callback` — the convention Claude Code and Codex\n // emit — so those clients' config (e.g. Slack's official MCP plugin config)\n // can be pasted verbatim. `redirectUrl` stays as the full-control escape\n // hatch (any loopback host/path). The two are mutually exclusive to avoid\n // an ambiguous redirect.\n let callbackPortRedirectUrl: string | undefined;\n if (obj.callbackPort !== undefined) {\n if (obj.redirectUrl !== undefined) {\n return { reason: 'Invalid OAuth config: set either \"redirectUrl\" or \"callbackPort\", not both' };\n }\n if (\n typeof obj.callbackPort !== 'number' ||\n !Number.isInteger(obj.callbackPort) ||\n obj.callbackPort < 1 ||\n obj.callbackPort > 65535\n ) {\n return { reason: 'Invalid OAuth config: \"callbackPort\" must be an integer between 1 and 65535' };\n }\n callbackPortRedirectUrl = resolveOAuthRedirectUrl({ callbackPort: obj.callbackPort });\n }\n\n const rawRedirectUrl = callbackPortRedirectUrl ?? obj.redirectUrl ?? DEFAULT_OAUTH_REDIRECT_URL;\n try {\n const redirectUrl = new URL(rawRedirectUrl);\n const isLoopback = isLoopbackHostname(redirectUrl.hostname);\n if (redirectUrl.protocol !== 'https:' && !(redirectUrl.protocol === 'http:' && isLoopback)) {\n return { reason: 'Invalid OAuth redirectUrl: must use HTTPS unless it is a loopback HTTP URL' };\n }\n } catch {\n return { reason: `Invalid OAuth redirectUrl: \"${rawRedirectUrl}\"` };\n }\n\n if (obj.scopes !== undefined && (!Array.isArray(obj.scopes) || obj.scopes.some(scope => typeof scope !== 'string'))) {\n return { reason: 'Invalid OAuth config: \"scopes\" must be an array of strings' };\n }\n\n return {\n config: {\n redirectUrl: rawRedirectUrl,\n clientName: typeof obj.clientName === 'string' ? obj.clientName : undefined,\n scopes: obj.scopes as string[] | undefined,\n clientId: typeof obj.clientId === 'string' ? obj.clientId : undefined,\n clientSecret: typeof obj.clientSecret === 'string' ? obj.clientSecret : undefined,\n },\n };\n}\n\n/**\n * Merge configs: claude (lowest priority) < global < project (highest).\n * Later configs override earlier by server name.\n * Skipped entries are accumulated, but if a higher-priority config provides\n * a valid entry for a skipped name, the skip is removed.\n */\nfunction mergeConfigs(...configs: McpConfig[]): McpConfig {\n const merged: Record<string, McpServerConfig> = {};\n const allSkipped: McpSkippedServer[] = [];\n\n for (const config of configs) {\n if (config.mcpServers) {\n for (const [name, server] of Object.entries(config.mcpServers)) {\n merged[name] = server;\n }\n }\n if (config.skippedServers) {\n allSkipped.push(...config.skippedServers);\n }\n }\n\n // Remove skipped entries that were resolved by a valid config at any priority\n const validNames = new Set(Object.keys(merged));\n const filteredSkipped = allSkipped.filter(s => !validNames.has(s.name));\n\n // Deduplicate skipped entries by name (keep last occurrence — highest priority reason)\n const skippedMap = new Map<string, McpSkippedServer>();\n for (const s of filteredSkipped) {\n skippedMap.set(s.name, s);\n }\n\n const result: McpConfig = {};\n if (Object.keys(merged).length > 0) {\n result.mcpServers = merged;\n }\n if (skippedMap.size > 0) {\n result.skippedServers = Array.from(skippedMap.values());\n }\n return result;\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"file":"config.js","names":["path","os","fs"],"sources":["../../src/mcp/config.ts"],"sourcesContent":["/**\n * MCP server configuration loading from filesystem.\n * Loads from:\n * 1. .claude/settings.local.json (Claude Code compat — lowest priority)\n * 2. ~/.mastracode/mcp.json (global)\n * 3. .mcp.json (project root — Claude Code compatible)\n * 4. .mastracode/mcp.json (project — highest priority)\n *\n * Higher-priority configs override lower ones by server name. The project root\n * `.mcp.json` is read so a project that already keeps MCP servers there for\n * Claude Code does not need to duplicate them under `.mastracode/`.\n */\n\nimport * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport { DEFAULT_CONFIG_DIR } from '../constants.js';\nimport type { McpConfig, McpHttpOAuthConfig, McpServerConfig, McpSkippedServer } from './types.js';\n\n/**\n * Default OAuth redirect URL for servers that do not configure one.\n * Port 1458 is stable across sessions so persisted tokens keep the same\n * storage fingerprint; it sits clear of the ports the Codex login flow\n * reserves (1455/1457). When 1458 is busy the callback server falls back\n * to the next sequential port, which stays covered by the client\n * registration (see `@mastra/mcp`'s `getCallbackUrlCandidates`).\n */\nexport const DEFAULT_OAUTH_REDIRECT_URL = 'http://127.0.0.1:1458/oauth/callback';\n\n// Matches the entire 127.0.0.0/8 range in dotted-quad form. `URL` normalizes\n// IPv4 hosts to four octets (so `127.1` becomes `127.0.0.1`), so anchoring the\n// pattern is enough — and it rejects lookalikes like `127.evil.com` that a\n// `startsWith('127.')` check would wrongly accept.\nconst LOOPBACK_IPV4 = /^127\\.(?:\\d{1,3})\\.(?:\\d{1,3})\\.(?:\\d{1,3})$/;\n\nfunction isLoopbackHostname(hostname: string): boolean {\n return hostname === 'localhost' || hostname === '[::1]' || hostname === '::1' || LOOPBACK_IPV4.test(hostname);\n}\n\n/**\n * Resolve the effective OAuth redirect URL for a server config.\n *\n * `callbackPort` (the Claude Code / Codex convention) takes precedence and\n * synthesizes `http://localhost:<port>/callback`. Config-file entries are\n * normalized by `parseOAuthConfig` (which also enforces that `callbackPort`\n * and `redirectUrl` are mutually exclusive), but programmatically registered\n * servers bypass the parser, so every consumer of the redirect URL must\n * resolve it through this helper rather than reading `redirectUrl` directly.\n */\nexport function resolveOAuthRedirectUrl(oauth: McpHttpOAuthConfig | undefined): string {\n if (oauth?.callbackPort !== undefined) {\n return `http://localhost:${oauth.callbackPort}/callback`;\n }\n return oauth?.redirectUrl ?? DEFAULT_OAUTH_REDIRECT_URL;\n}\n\nexport function loadMcpConfig(projectDir: string, configDirName = DEFAULT_CONFIG_DIR): McpConfig {\n const claudeConfig = loadClaudeSettings(projectDir);\n const globalConfig = loadSingleConfig(getGlobalMcpPath(configDirName));\n const rootConfig = loadSingleConfig(getRootMcpPath(projectDir));\n const projectConfig = loadSingleConfig(getProjectMcpPath(projectDir, configDirName));\n\n return mergeConfigs(claudeConfig, globalConfig, rootConfig, projectConfig);\n}\n\nexport function getProjectMcpPath(projectDir: string, configDirName = DEFAULT_CONFIG_DIR): string {\n return path.join(projectDir, configDirName, 'mcp.json');\n}\n\nexport function getRootMcpPath(projectDir: string): string {\n return path.join(projectDir, '.mcp.json');\n}\n\nexport function getGlobalMcpPath(configDirName = DEFAULT_CONFIG_DIR): string {\n return path.join(os.homedir(), configDirName, 'mcp.json');\n}\n\nexport function getClaudeSettingsPath(projectDir: string): string {\n return path.join(projectDir, '.claude', 'settings.local.json');\n}\n\nfunction loadSingleConfig(filePath: string): McpConfig {\n try {\n if (!fs.existsSync(filePath)) return {};\n const raw = fs.readFileSync(filePath, 'utf-8');\n return validateConfig(JSON.parse(raw));\n } catch {\n return {};\n }\n}\n\nfunction loadClaudeSettings(projectDir: string): McpConfig {\n try {\n const filePath = getClaudeSettingsPath(projectDir);\n if (!fs.existsSync(filePath)) return {};\n const raw = fs.readFileSync(filePath, 'utf-8');\n const parsed = JSON.parse(raw);\n // Claude Code stores mcpServers at the top level of settings\n if (parsed?.mcpServers && typeof parsed.mcpServers === 'object') {\n return validateConfig({ mcpServers: parsed.mcpServers });\n }\n return {};\n } catch {\n return {};\n }\n}\n\n/**\n * Expand `${VAR}` and `${VAR:-default}` references in a string from the\n * environment, matching how Claude Code resolves values in `.mcp.json`.\n * A referenced variable that is unset or empty falls back to its default,\n * or to an empty string when no default is given.\n */\nexport function expandEnvVars(value: string, env: NodeJS.ProcessEnv = process.env): string {\n return value.replace(\n /\\$\\{([A-Za-z_][A-Za-z0-9_]*)(?::-([^}]*))?\\}|\\$([A-Za-z_][A-Za-z0-9_]*)/g,\n (_match, bracedName, fallback, bareName) => {\n const name = bracedName ?? bareName;\n const resolved = env[name];\n if (resolved !== undefined && resolved !== '') return resolved;\n return fallback ?? '';\n },\n );\n}\n\n/**\n * Expand `${VAR}` and `$VAR` references in every string-valued HTTP header so that\n * secrets like API keys can be referenced from the environment instead of\n * being hardcoded in `mcp.json`.\n */\nfunction expandHeaderEnvVars(headers: Record<string, unknown>): Record<string, string> {\n const expanded: Record<string, string> = {};\n for (const [key, value] of Object.entries(headers)) {\n if (typeof value === 'string') expanded[key] = expandEnvVars(value);\n }\n return expanded;\n}\n\n/**\n * Expand `${VAR}` and `$VAR` references in every string-valued environment\n * variable passed to a stdio server, so that secrets can be referenced from the\n * host environment instead of being hardcoded in `mcp.json`.\n */\nfunction expandEnvValues(env: Record<string, unknown>): Record<string, string> {\n const expanded: Record<string, string> = {};\n for (const [key, value] of Object.entries(env)) {\n if (typeof value === 'string') expanded[key] = expandEnvVars(value);\n }\n return expanded;\n}\n\n/**\n * Classify a raw server entry as stdio, http, or skip (with reason).\n */\nexport function classifyServerEntry(raw: unknown): { kind: 'stdio' | 'http' | 'skip'; reason?: string } {\n if (!raw || typeof raw !== 'object') {\n return { kind: 'skip', reason: 'Invalid entry: expected an object' };\n }\n\n const obj = raw as Record<string, unknown>;\n const hasCommand = typeof obj.command === 'string';\n const hasUrl = typeof obj.url === 'string';\n\n if (hasCommand && hasUrl) {\n return { kind: 'skip', reason: 'Cannot specify both \"command\" and \"url\"' };\n }\n\n if (hasCommand) {\n return { kind: 'stdio' };\n }\n\n if (hasUrl) {\n try {\n new URL(expandEnvVars(obj.url as string));\n } catch {\n return { kind: 'skip', reason: `Invalid URL: \"${obj.url}\"` };\n }\n return { kind: 'http' };\n }\n\n return { kind: 'skip', reason: 'Missing required field: \"command\" (stdio) or \"url\" (http)' };\n}\n\nexport function validateConfig(raw: unknown): McpConfig {\n if (!raw || typeof raw !== 'object') return {};\n const obj = raw as Record<string, unknown>;\n\n if (!obj.mcpServers || typeof obj.mcpServers !== 'object') return {};\n\n const servers: Record<string, McpServerConfig> = {};\n const skippedServers: McpSkippedServer[] = [];\n const rawServers = obj.mcpServers as Record<string, unknown>;\n\n for (const [name, entry] of Object.entries(rawServers)) {\n const classification = classifyServerEntry(entry);\n\n if (classification.kind === 'stdio') {\n const e = entry as Record<string, unknown>;\n servers[name] = {\n command: e.command as string,\n args: Array.isArray(e.args) ? (e.args as string[]) : undefined,\n env:\n typeof e.env === 'object' && e.env !== null ? expandEnvValues(e.env as Record<string, unknown>) : undefined,\n };\n } else if (classification.kind === 'http') {\n const e = entry as Record<string, unknown>;\n const oauthResult = parseOAuthConfig(e.oauth);\n if (oauthResult.reason) {\n skippedServers.push({ name, reason: oauthResult.reason });\n continue;\n }\n servers[name] = {\n url: expandEnvVars(e.url as string),\n headers:\n typeof e.headers === 'object' && e.headers !== null\n ? expandHeaderEnvVars(e.headers as Record<string, unknown>)\n : undefined,\n oauth: oauthResult.config,\n };\n } else {\n skippedServers.push({ name, reason: classification.reason! });\n }\n }\n\n const result: McpConfig = {};\n if (Object.keys(servers).length > 0) {\n result.mcpServers = servers;\n }\n if (skippedServers.length > 0) {\n result.skippedServers = skippedServers;\n }\n return result;\n}\n\nfunction parseOAuthConfig(raw: unknown): { config?: McpHttpOAuthConfig; reason?: string } {\n if (raw === undefined) return {};\n if (!raw || typeof raw !== 'object') {\n return { reason: 'Invalid OAuth config: expected an object' };\n }\n\n const obj = raw as Record<string, unknown>;\n if (obj.redirectUrl !== undefined && typeof obj.redirectUrl !== 'string') {\n return { reason: 'Invalid OAuth config: \"redirectUrl\" must be a string' };\n }\n // `callbackPort` is a shorthand for a loopback redirect URL. It synthesizes\n // `http://localhost:<port>/callback` — the convention Claude Code and Codex\n // emit — so those clients' config (e.g. Slack's official MCP plugin config)\n // can be pasted verbatim. `redirectUrl` stays as the full-control escape\n // hatch (any loopback host/path). The two are mutually exclusive to avoid\n // an ambiguous redirect.\n let callbackPortRedirectUrl: string | undefined;\n if (obj.callbackPort !== undefined) {\n if (obj.redirectUrl !== undefined) {\n return { reason: 'Invalid OAuth config: set either \"redirectUrl\" or \"callbackPort\", not both' };\n }\n if (\n typeof obj.callbackPort !== 'number' ||\n !Number.isInteger(obj.callbackPort) ||\n obj.callbackPort < 1 ||\n obj.callbackPort > 65535\n ) {\n return { reason: 'Invalid OAuth config: \"callbackPort\" must be an integer between 1 and 65535' };\n }\n callbackPortRedirectUrl = resolveOAuthRedirectUrl({ callbackPort: obj.callbackPort });\n }\n\n const rawRedirectUrl = callbackPortRedirectUrl ?? obj.redirectUrl ?? DEFAULT_OAUTH_REDIRECT_URL;\n try {\n const redirectUrl = new URL(rawRedirectUrl);\n const isLoopback = isLoopbackHostname(redirectUrl.hostname);\n if (redirectUrl.protocol !== 'https:' && !(redirectUrl.protocol === 'http:' && isLoopback)) {\n return { reason: 'Invalid OAuth redirectUrl: must use HTTPS unless it is a loopback HTTP URL' };\n }\n } catch {\n return { reason: `Invalid OAuth redirectUrl: \"${rawRedirectUrl}\"` };\n }\n\n if (obj.scopes !== undefined && (!Array.isArray(obj.scopes) || obj.scopes.some(scope => typeof scope !== 'string'))) {\n return { reason: 'Invalid OAuth config: \"scopes\" must be an array of strings' };\n }\n\n return {\n config: {\n redirectUrl: rawRedirectUrl,\n clientName: typeof obj.clientName === 'string' ? obj.clientName : undefined,\n scopes: obj.scopes as string[] | undefined,\n clientId: typeof obj.clientId === 'string' ? obj.clientId : undefined,\n clientSecret: typeof obj.clientSecret === 'string' ? obj.clientSecret : undefined,\n },\n };\n}\n\n/**\n * Merge configs: claude (lowest priority) < global < project (highest).\n * Later configs override earlier by server name.\n * Skipped entries are accumulated, but if a higher-priority config provides\n * a valid entry for a skipped name, the skip is removed.\n */\nfunction mergeConfigs(...configs: McpConfig[]): McpConfig {\n const merged: Record<string, McpServerConfig> = {};\n const allSkipped: McpSkippedServer[] = [];\n\n for (const config of configs) {\n if (config.mcpServers) {\n for (const [name, server] of Object.entries(config.mcpServers)) {\n merged[name] = server;\n }\n }\n if (config.skippedServers) {\n allSkipped.push(...config.skippedServers);\n }\n }\n\n // Remove skipped entries that were resolved by a valid config at any priority\n const validNames = new Set(Object.keys(merged));\n const filteredSkipped = allSkipped.filter(s => !validNames.has(s.name));\n\n // Deduplicate skipped entries by name (keep last occurrence — highest priority reason)\n const skippedMap = new Map<string, McpSkippedServer>();\n for (const s of filteredSkipped) {\n skippedMap.set(s.name, s);\n }\n\n const result: McpConfig = {};\n if (Object.keys(merged).length > 0) {\n result.mcpServers = merged;\n }\n if (skippedMap.size > 0) {\n result.skippedServers = Array.from(skippedMap.values());\n }\n return result;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AA2BA,MAAa,6BAA6B;AAM1C,MAAM,gBAAgB;AAEtB,SAAS,mBAAmB,UAA2B;CACrD,OAAO,aAAa,eAAe,aAAa,WAAW,aAAa,SAAS,cAAc,KAAK,QAAQ;AAC9G;;;;;;;;;;;AAYA,SAAgB,wBAAwB,OAA+C;CACrF,IAAI,OAAO,iBAAiB,KAAA,GAC1B,OAAO,oBAAoB,MAAM,aAAa;CAEhD,OAAO,OAAO,eAAA;AAChB;AAEA,SAAgB,cAAc,YAAoB,gBAAgB,oBAA+B;CAM/F,OAAO,aALc,mBAAmB,UAKT,GAJV,iBAAiB,iBAAiB,aAAa,CAIvB,GAH1B,iBAAiB,eAAe,UAAU,CAGJ,GAFnC,iBAAiB,kBAAkB,YAAY,aAAa,CAEV,CAAC;AAC3E;AAEA,SAAgB,kBAAkB,YAAoB,gBAAgB,oBAA4B;CAChG,OAAOA,OAAK,KAAK,YAAY,eAAe,UAAU;AACxD;AAEA,SAAgB,eAAe,YAA4B;CACzD,OAAOA,OAAK,KAAK,YAAY,WAAW;AAC1C;AAEA,SAAgB,iBAAiB,gBAAgB,oBAA4B;CAC3E,OAAOA,OAAK,KAAKC,KAAG,QAAQ,GAAG,eAAe,UAAU;AAC1D;AAEA,SAAgB,sBAAsB,YAA4B;CAChE,OAAOD,OAAK,KAAK,YAAY,WAAW,qBAAqB;AAC/D;AAEA,SAAS,iBAAiB,UAA6B;CACrD,IAAI;EACF,IAAI,CAACE,KAAG,WAAW,QAAQ,GAAG,OAAO,CAAC;EACtC,MAAM,MAAMA,KAAG,aAAa,UAAU,OAAO;EAC7C,OAAO,eAAe,KAAK,MAAM,GAAG,CAAC;CACvC,QAAQ;EACN,OAAO,CAAC;CACV;AACF;AAEA,SAAS,mBAAmB,YAA+B;CACzD,IAAI;EACF,MAAM,WAAW,sBAAsB,UAAU;EACjD,IAAI,CAACA,KAAG,WAAW,QAAQ,GAAG,OAAO,CAAC;EACtC,MAAM,MAAMA,KAAG,aAAa,UAAU,OAAO;EAC7C,MAAM,SAAS,KAAK,MAAM,GAAG;EAE7B,IAAI,QAAQ,cAAc,OAAO,OAAO,eAAe,UACrD,OAAO,eAAe,EAAE,YAAY,OAAO,WAAW,CAAC;EAEzD,OAAO,CAAC;CACV,QAAQ;EACN,OAAO,CAAC;CACV;AACF;;;;;;;AAQA,SAAgB,cAAc,OAAe,MAAyB,QAAQ,KAAa;CACzF,OAAO,MAAM,QACX,6EACC,QAAQ,YAAY,UAAU,aAAa;EAE1C,MAAM,WAAW,IADJ,cAAc;EAE3B,IAAI,aAAa,KAAA,KAAa,aAAa,IAAI,OAAO;EACtD,OAAO,YAAY;CACrB,CACF;AACF;;;;;;AAOA,SAAS,oBAAoB,SAA0D;CACrF,MAAM,WAAmC,CAAC;CAC1C,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,OAAO,GAC/C,IAAI,OAAO,UAAU,UAAU,SAAS,OAAO,cAAc,KAAK;CAEpE,OAAO;AACT;;;;;;AAOA,SAAS,gBAAgB,KAAsD;CAC7E,MAAM,WAAmC,CAAC;CAC1C,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,GAAG,GAC3C,IAAI,OAAO,UAAU,UAAU,SAAS,OAAO,cAAc,KAAK;CAEpE,OAAO;AACT;;;;AAKA,SAAgB,oBAAoB,KAAoE;CACtG,IAAI,CAAC,OAAO,OAAO,QAAQ,UACzB,OAAO;EAAE,MAAM;EAAQ,QAAQ;CAAoC;CAGrE,MAAM,MAAM;CACZ,MAAM,aAAa,OAAO,IAAI,YAAY;CAC1C,MAAM,SAAS,OAAO,IAAI,QAAQ;CAElC,IAAI,cAAc,QAChB,OAAO;EAAE,MAAM;EAAQ,QAAQ;CAA0C;CAG3E,IAAI,YACF,OAAO,EAAE,MAAM,QAAQ;CAGzB,IAAI,QAAQ;EACV,IAAI;GACF,IAAI,IAAI,cAAc,IAAI,GAAa,CAAC;EAC1C,QAAQ;GACN,OAAO;IAAE,MAAM;IAAQ,QAAQ,iBAAiB,IAAI,IAAI;GAAG;EAC7D;EACA,OAAO,EAAE,MAAM,OAAO;CACxB;CAEA,OAAO;EAAE,MAAM;EAAQ,QAAQ;CAA4D;AAC7F;AAEA,SAAgB,eAAe,KAAyB;CACtD,IAAI,CAAC,OAAO,OAAO,QAAQ,UAAU,OAAO,CAAC;CAC7C,MAAM,MAAM;CAEZ,IAAI,CAAC,IAAI,cAAc,OAAO,IAAI,eAAe,UAAU,OAAO,CAAC;CAEnE,MAAM,UAA2C,CAAC;CAClD,MAAM,iBAAqC,CAAC;CAC5C,MAAM,aAAa,IAAI;CAEvB,KAAK,MAAM,CAAC,MAAM,UAAU,OAAO,QAAQ,UAAU,GAAG;EACtD,MAAM,iBAAiB,oBAAoB,KAAK;EAEhD,IAAI,eAAe,SAAS,SAAS;GACnC,MAAM,IAAI;GACV,QAAQ,QAAQ;IACd,SAAS,EAAE;IACX,MAAM,MAAM,QAAQ,EAAE,IAAI,IAAK,EAAE,OAAoB,KAAA;IACrD,KACE,OAAO,EAAE,QAAQ,YAAY,EAAE,QAAQ,OAAO,gBAAgB,EAAE,GAA8B,IAAI,KAAA;GACtG;EACF,OAAO,IAAI,eAAe,SAAS,QAAQ;GACzC,MAAM,IAAI;GACV,MAAM,cAAc,iBAAiB,EAAE,KAAK;GAC5C,IAAI,YAAY,QAAQ;IACtB,eAAe,KAAK;KAAE;KAAM,QAAQ,YAAY;IAAO,CAAC;IACxD;GACF;GACA,QAAQ,QAAQ;IACd,KAAK,cAAc,EAAE,GAAa;IAClC,SACE,OAAO,EAAE,YAAY,YAAY,EAAE,YAAY,OAC3C,oBAAoB,EAAE,OAAkC,IACxD,KAAA;IACN,OAAO,YAAY;GACrB;EACF,OACE,eAAe,KAAK;GAAE;GAAM,QAAQ,eAAe;EAAQ,CAAC;CAEhE;CAEA,MAAM,SAAoB,CAAC;CAC3B,IAAI,OAAO,KAAK,OAAO,CAAC,CAAC,SAAS,GAChC,OAAO,aAAa;CAEtB,IAAI,eAAe,SAAS,GAC1B,OAAO,iBAAiB;CAE1B,OAAO;AACT;AAEA,SAAS,iBAAiB,KAAgE;CACxF,IAAI,QAAQ,KAAA,GAAW,OAAO,CAAC;CAC/B,IAAI,CAAC,OAAO,OAAO,QAAQ,UACzB,OAAO,EAAE,QAAQ,2CAA2C;CAG9D,MAAM,MAAM;CACZ,IAAI,IAAI,gBAAgB,KAAA,KAAa,OAAO,IAAI,gBAAgB,UAC9D,OAAO,EAAE,QAAQ,yDAAuD;CAQ1E,IAAI;CACJ,IAAI,IAAI,iBAAiB,KAAA,GAAW;EAClC,IAAI,IAAI,gBAAgB,KAAA,GACtB,OAAO,EAAE,QAAQ,iFAA6E;EAEhG,IACE,OAAO,IAAI,iBAAiB,YAC5B,CAAC,OAAO,UAAU,IAAI,YAAY,KAClC,IAAI,eAAe,KACnB,IAAI,eAAe,OAEnB,OAAO,EAAE,QAAQ,gFAA8E;EAEjG,0BAA0B,wBAAwB,EAAE,cAAc,IAAI,aAAa,CAAC;CACtF;CAEA,MAAM,iBAAiB,2BAA2B,IAAI,eAAA;CACtD,IAAI;EACF,MAAM,cAAc,IAAI,IAAI,cAAc;EAC1C,MAAM,aAAa,mBAAmB,YAAY,QAAQ;EAC1D,IAAI,YAAY,aAAa,YAAY,EAAE,YAAY,aAAa,WAAW,aAC7E,OAAO,EAAE,QAAQ,6EAA6E;CAElG,QAAQ;EACN,OAAO,EAAE,QAAQ,+BAA+B,eAAe,GAAG;CACpE;CAEA,IAAI,IAAI,WAAW,KAAA,MAAc,CAAC,MAAM,QAAQ,IAAI,MAAM,KAAK,IAAI,OAAO,MAAK,UAAS,OAAO,UAAU,QAAQ,IAC/G,OAAO,EAAE,QAAQ,+DAA6D;CAGhF,OAAO,EACL,QAAQ;EACN,aAAa;EACb,YAAY,OAAO,IAAI,eAAe,WAAW,IAAI,aAAa,KAAA;EAClE,QAAQ,IAAI;EACZ,UAAU,OAAO,IAAI,aAAa,WAAW,IAAI,WAAW,KAAA;EAC5D,cAAc,OAAO,IAAI,iBAAiB,WAAW,IAAI,eAAe,KAAA;CAC1E,EACF;AACF;;;;;;;AAQA,SAAS,aAAa,GAAG,SAAiC;CACxD,MAAM,SAA0C,CAAC;CACjD,MAAM,aAAiC,CAAC;CAExC,KAAK,MAAM,UAAU,SAAS;EAC5B,IAAI,OAAO,YACT,KAAK,MAAM,CAAC,MAAM,WAAW,OAAO,QAAQ,OAAO,UAAU,GAC3D,OAAO,QAAQ;EAGnB,IAAI,OAAO,gBACT,WAAW,KAAK,GAAG,OAAO,cAAc;CAE5C;CAGA,MAAM,aAAa,IAAI,IAAI,OAAO,KAAK,MAAM,CAAC;CAC9C,MAAM,kBAAkB,WAAW,QAAO,MAAK,CAAC,WAAW,IAAI,EAAE,IAAI,CAAC;CAGtE,MAAM,6BAAa,IAAI,IAA8B;CACrD,KAAK,MAAM,KAAK,iBACd,WAAW,IAAI,EAAE,MAAM,CAAC;CAG1B,MAAM,SAAoB,CAAC;CAC3B,IAAI,OAAO,KAAK,MAAM,CAAC,CAAC,SAAS,GAC/B,OAAO,aAAa;CAEtB,IAAI,WAAW,OAAO,GACpB,OAAO,iBAAiB,MAAM,KAAK,WAAW,OAAO,CAAC;CAExD,OAAO;AACT"}
|
package/dist/mcp/index.js
CHANGED
|
@@ -1,10 +1,3 @@
|
|
|
1
|
+
import { getClaudeSettingsPath, getGlobalMcpPath, getProjectMcpPath, loadMcpConfig } from "./config.js";
|
|
1
2
|
import { createMcpManager } from "./manager.js";
|
|
2
|
-
|
|
3
|
-
export {
|
|
4
|
-
createMcpManager,
|
|
5
|
-
getClaudeSettingsPath,
|
|
6
|
-
getGlobalMcpPath,
|
|
7
|
-
getProjectMcpPath,
|
|
8
|
-
loadMcpConfig
|
|
9
|
-
};
|
|
10
|
-
//# sourceMappingURL=index.js.map
|
|
3
|
+
export { createMcpManager, getClaudeSettingsPath, getGlobalMcpPath, getProjectMcpPath, loadMcpConfig };
|