@arizeai/phoenix-cli 1.9.1 → 1.10.1

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 (50) hide show
  1. package/README.md +28 -0
  2. package/build/commands/auth.d.ts.map +1 -1
  3. package/build/commands/auth.js +13 -1
  4. package/build/commands/auth.js.map +1 -1
  5. package/build/commands/formatSetup.d.ts +6 -0
  6. package/build/commands/formatSetup.d.ts.map +1 -1
  7. package/build/commands/formatSetup.js +22 -0
  8. package/build/commands/formatSetup.js.map +1 -1
  9. package/build/commands/setup.d.ts.map +1 -1
  10. package/build/commands/setup.js +10 -38
  11. package/build/commands/setup.js.map +1 -1
  12. package/build/commands/setupErrors.d.ts +10 -0
  13. package/build/commands/setupErrors.d.ts.map +1 -0
  14. package/build/commands/setupErrors.js +54 -0
  15. package/build/commands/setupErrors.js.map +1 -0
  16. package/build/commands/setupMcp.d.ts +15 -0
  17. package/build/commands/setupMcp.d.ts.map +1 -0
  18. package/build/commands/setupMcp.js +141 -0
  19. package/build/commands/setupMcp.js.map +1 -0
  20. package/build/oauth.d.ts +31 -0
  21. package/build/oauth.d.ts.map +1 -1
  22. package/build/oauth.js +53 -1
  23. package/build/oauth.js.map +1 -1
  24. package/build/setup/agents/registry.d.ts +4 -0
  25. package/build/setup/agents/registry.d.ts.map +1 -1
  26. package/build/setup/agents/registry.js +7 -3
  27. package/build/setup/agents/registry.js.map +1 -1
  28. package/build/setup/deps/oauthLogin.d.ts.map +1 -1
  29. package/build/setup/deps/oauthLogin.js +6 -14
  30. package/build/setup/deps/oauthLogin.js.map +1 -1
  31. package/build/setup/mcp/agents.d.ts +91 -0
  32. package/build/setup/mcp/agents.d.ts.map +1 -0
  33. package/build/setup/mcp/agents.js +265 -0
  34. package/build/setup/mcp/agents.js.map +1 -0
  35. package/build/setup/mcp/install.d.ts +34 -0
  36. package/build/setup/mcp/install.d.ts.map +1 -0
  37. package/build/setup/mcp/install.js +76 -0
  38. package/build/setup/mcp/install.js.map +1 -0
  39. package/build/setup/mcp/runSetupMcp.d.ts +68 -0
  40. package/build/setup/mcp/runSetupMcp.d.ts.map +1 -0
  41. package/build/setup/mcp/runSetupMcp.js +235 -0
  42. package/build/setup/mcp/runSetupMcp.js.map +1 -0
  43. package/build/setup/steps/offerDocsMcp.d.ts.map +1 -1
  44. package/build/setup/steps/offerDocsMcp.js +3 -2
  45. package/build/setup/steps/offerDocsMcp.js.map +1 -1
  46. package/build/setup/util/mcpConfig.d.ts +12 -5
  47. package/build/setup/util/mcpConfig.d.ts.map +1 -1
  48. package/build/setup/util/mcpConfig.js +6 -4
  49. package/build/setup/util/mcpConfig.js.map +1 -1
  50. package/package.json +1 -1
@@ -0,0 +1,265 @@
1
+ /**
2
+ * The coding agents `px setup mcp` can register the Phoenix remote MCP server
3
+ * with, and how each one is configured per scope.
4
+ *
5
+ * Separate from the launch-focused instrumentation registry in
6
+ * `../agents/registry.ts`: MCP configuration has no launch, two scopes, and six
7
+ * agents (including VS Code and Gemini), so it gets its own registry rather than
8
+ * adding unused fields to that one.
9
+ *
10
+ * Each agent declares a per-scope {@link McpInstallAction}: `cli` runs the
11
+ * agent's own `mcp add` (so the format can't drift from the agent's schema);
12
+ * `file` merges into a config file. The file shapes mirror
13
+ * `docs/phoenix/integrations/remote-mcp.mdx`.
14
+ */
15
+ import * as path from "node:path";
16
+ /** The name the Phoenix MCP server is registered under in every agent config. */
17
+ export const PHOENIX_MCP_SERVER_NAME = "phoenix";
18
+ // ---------------------------------------------------------------------------
19
+ // Header helpers
20
+ // ---------------------------------------------------------------------------
21
+ /** `--header "Name: value"` pairs, for agents whose CLI takes raw headers. */
22
+ function headerFlags(headers) {
23
+ return headers.flatMap((header) => [
24
+ "--header",
25
+ `${header.name}: ${header.value}`,
26
+ ]);
27
+ }
28
+ /**
29
+ * A spreadable `{ headers }` fragment — present only when there are headers, so
30
+ * a URL-only (OAuth) config carries no empty `headers` key. Spread it into a
31
+ * server entry: `{ url, ...headersField(headers) }`.
32
+ */
33
+ function headersField(headers) {
34
+ if (headers.length === 0) {
35
+ return {};
36
+ }
37
+ return {
38
+ headers: Object.fromEntries(headers.map((header) => [header.name, header.value])),
39
+ };
40
+ }
41
+ /** An `Authorization` value that is exactly `Bearer $VAR` or `Bearer ${VAR}`. */
42
+ const BEARER_ENV_VAR_PATTERN = /^Bearer\s+(?:\$([A-Za-z_][A-Za-z0-9_]*)|\$\{([A-Za-z_][A-Za-z0-9_]*)\})$/;
43
+ /**
44
+ * The one header Codex's `mcp add` can persist — the first `Authorization`
45
+ * header whose value is env-var-shaped — and the env-var name it references.
46
+ * Codex stores only `--bearer-token-env-var`; a literal token has no
47
+ * translation, so it is never honored.
48
+ */
49
+ function honoredBearerHeader(headers) {
50
+ for (const header of headers) {
51
+ if (header.name.toLowerCase() !== "authorization") {
52
+ continue;
53
+ }
54
+ const match = header.value.match(BEARER_ENV_VAR_PATTERN);
55
+ const envVar = match?.[1] ?? match?.[2];
56
+ if (envVar) {
57
+ return { header, envVar };
58
+ }
59
+ }
60
+ return undefined;
61
+ }
62
+ // ---------------------------------------------------------------------------
63
+ // Per-agent install builders
64
+ // ---------------------------------------------------------------------------
65
+ /**
66
+ * Claude Code and Gemini share one `mcp add` shape — both take
67
+ * `--scope user|project` and raw `--header`s; only the scope flag differs.
68
+ */
69
+ function httpCliAdd(binary, scopeFlag, { verify }) {
70
+ return {
71
+ kind: "cli",
72
+ binary,
73
+ addArgs: (url, headers) => [
74
+ "mcp",
75
+ "add",
76
+ "--scope",
77
+ scopeFlag,
78
+ "--transport",
79
+ "http",
80
+ ...headerFlags(headers),
81
+ PHOENIX_MCP_SERVER_NAME,
82
+ url,
83
+ ],
84
+ removeArgs: [
85
+ "mcp",
86
+ "remove",
87
+ "--scope",
88
+ scopeFlag,
89
+ PHOENIX_MCP_SERVER_NAME,
90
+ ],
91
+ ...(verify ? { verifyArgs: ["mcp", "get", PHOENIX_MCP_SERVER_NAME] } : {}),
92
+ };
93
+ }
94
+ // ---------------------------------------------------------------------------
95
+ // File-config fragments
96
+ // ---------------------------------------------------------------------------
97
+ const OPENCODE_DEFAULTS = { $schema: "https://opencode.ai/config.json" };
98
+ function cursorPatch(url, headers) {
99
+ return {
100
+ mcpServers: {
101
+ [PHOENIX_MCP_SERVER_NAME]: {
102
+ url,
103
+ ...headersField(headers),
104
+ },
105
+ },
106
+ };
107
+ }
108
+ function opencodePatch(url, headers) {
109
+ return {
110
+ mcp: {
111
+ [PHOENIX_MCP_SERVER_NAME]: {
112
+ type: "remote",
113
+ url,
114
+ enabled: true,
115
+ ...headersField(headers),
116
+ },
117
+ },
118
+ };
119
+ }
120
+ // ---------------------------------------------------------------------------
121
+ // Registry
122
+ // ---------------------------------------------------------------------------
123
+ export const MCP_AGENTS = [
124
+ {
125
+ id: "claude",
126
+ label: "Claude Code",
127
+ binary: "claude",
128
+ install: {
129
+ // `--scope user` is user-wide; `--scope project` writes the shared
130
+ // `.mcp.json` at the repo root (the "repo" scope a --local install means).
131
+ global: httpCliAdd("claude", "user", { verify: true }),
132
+ local: httpCliAdd("claude", "project", { verify: true }),
133
+ },
134
+ },
135
+ {
136
+ id: "codex",
137
+ label: "Codex",
138
+ binary: "codex",
139
+ install: {
140
+ // Codex reads one global `~/.codex/config.toml`; there is no repo-scoped
141
+ // config, so only `global` is offered. `codex mcp add` writes the TOML
142
+ // itself, so we never format TOML by hand.
143
+ global: {
144
+ kind: "cli",
145
+ binary: "codex",
146
+ addArgs: (url, headers) => {
147
+ const envVar = honoredBearerHeader(headers)?.envVar;
148
+ return [
149
+ "mcp",
150
+ "add",
151
+ PHOENIX_MCP_SERVER_NAME,
152
+ "--url",
153
+ url,
154
+ ...(envVar ? ["--bearer-token-env-var", envVar] : []),
155
+ ];
156
+ },
157
+ removeArgs: ["mcp", "remove", PHOENIX_MCP_SERVER_NAME],
158
+ verifyArgs: ["mcp", "get", PHOENIX_MCP_SERVER_NAME],
159
+ droppedHeaders: (headers) => {
160
+ // Codex persists only the bearer env var derived from the honored
161
+ // Authorization header; every other header — including a second
162
+ // Authorization header, or one whose value isn't `Bearer ${VAR}` —
163
+ // is discarded by `codex mcp add`, so report those as un-storable.
164
+ const honored = honoredBearerHeader(headers)?.header;
165
+ return headers.filter((header) => header !== honored);
166
+ },
167
+ },
168
+ },
169
+ },
170
+ {
171
+ id: "gemini",
172
+ label: "Gemini CLI",
173
+ binary: "gemini",
174
+ install: {
175
+ // Gemini's `mcp add` mirrors Claude's flags but ships no `get`, so there
176
+ // is no read-back — the add's exit code is trusted.
177
+ global: httpCliAdd("gemini", "user", { verify: false }),
178
+ local: httpCliAdd("gemini", "project", { verify: false }),
179
+ },
180
+ },
181
+ {
182
+ id: "cursor",
183
+ label: "Cursor",
184
+ binary: "cursor-agent",
185
+ install: {
186
+ global: {
187
+ kind: "file",
188
+ path: (ctx) => path.join(ctx.home, ".cursor", "mcp.json"),
189
+ displayPath: () => "~/.cursor/mcp.json",
190
+ patch: cursorPatch,
191
+ },
192
+ local: {
193
+ kind: "file",
194
+ path: (ctx) => path.join(ctx.cwd, ".cursor", "mcp.json"),
195
+ displayPath: () => ".cursor/mcp.json",
196
+ patch: cursorPatch,
197
+ },
198
+ },
199
+ },
200
+ {
201
+ id: "opencode",
202
+ label: "OpenCode",
203
+ binary: "opencode",
204
+ install: {
205
+ global: {
206
+ kind: "file",
207
+ path: (ctx) => path.join(ctx.home, ".config", "opencode", "opencode.json"),
208
+ displayPath: () => "~/.config/opencode/opencode.json",
209
+ createDefaults: OPENCODE_DEFAULTS,
210
+ patch: opencodePatch,
211
+ },
212
+ local: {
213
+ kind: "file",
214
+ path: (ctx) => path.join(ctx.cwd, "opencode.json"),
215
+ displayPath: () => "opencode.json",
216
+ createDefaults: OPENCODE_DEFAULTS,
217
+ patch: opencodePatch,
218
+ },
219
+ },
220
+ },
221
+ {
222
+ id: "vscode",
223
+ label: "VS Code",
224
+ binary: "code",
225
+ install: {
226
+ // Global: the user-profile `mcp.json` path is platform-specific, so we
227
+ // let the `code` CLI write it rather than guessing the location.
228
+ global: {
229
+ kind: "cli",
230
+ binary: "code",
231
+ addArgs: (url, headers) => [
232
+ "--add-mcp",
233
+ JSON.stringify({
234
+ name: PHOENIX_MCP_SERVER_NAME,
235
+ type: "http",
236
+ url,
237
+ ...headersField(headers),
238
+ }),
239
+ ],
240
+ },
241
+ // Local: the documented workspace file.
242
+ local: {
243
+ kind: "file",
244
+ path: (ctx) => path.join(ctx.cwd, ".vscode", "mcp.json"),
245
+ displayPath: () => ".vscode/mcp.json",
246
+ patch: (url, headers) => ({
247
+ servers: {
248
+ [PHOENIX_MCP_SERVER_NAME]: {
249
+ type: "http",
250
+ url,
251
+ ...headersField(headers),
252
+ },
253
+ },
254
+ }),
255
+ },
256
+ },
257
+ },
258
+ ];
259
+ /** The agent with this id, or undefined when the id is unknown. */
260
+ export function getMcpAgent(id) {
261
+ return MCP_AGENTS.find((agent) => agent.id === id);
262
+ }
263
+ /** Every id `--agent` accepts, for help text and error messages. */
264
+ export const MCP_AGENT_IDS = MCP_AGENTS.map((agent) => agent.id);
265
+ //# sourceMappingURL=agents.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agents.js","sourceRoot":"","sources":["../../../src/setup/mcp/agents.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Execute one MCP install action — run the agent's `mcp add`, or merge the
3
+ * server entry into its config file.
4
+ *
5
+ * The CLI path adds first, and only remove-then-retries when the add is refused
6
+ * *and* the agent's own listing already shows an entry under our name — removing
7
+ * before the add is known to work could destroy a registration a failed retry
8
+ * can't restore. The `verifyArgs` read-back guards against drift: an add whose
9
+ * flags changed meaning while still exiting 0 shows up as a missing entry.
10
+ *
11
+ * Never throws when an install simply didn't take — returns a `failed` result
12
+ * with a reason for the caller to handle.
13
+ */
14
+ import type { SetupDeps } from "../deps/index.js";
15
+ import type { McpHeader, McpInstallAction, McpInstallContext } from "./agents.js";
16
+ export type McpInstallOutcome = "configured" | "failed";
17
+ export interface McpInstallResult {
18
+ outcome: McpInstallOutcome;
19
+ /** The config file written (repo-relative or `~/…`), for file-based installs. */
20
+ file?: string;
21
+ /** Why the install failed, when it did. */
22
+ reason?: string;
23
+ }
24
+ export interface RunMcpInstallArgs {
25
+ action: McpInstallAction;
26
+ /** The Phoenix MCP URL (endpoint + `/mcp`). */
27
+ url: string;
28
+ /** Headers for the API-key bearer fallback; empty for OAuth. */
29
+ headers: McpHeader[];
30
+ /** Home and repo-root the file paths resolve against. */
31
+ installContext: McpInstallContext;
32
+ }
33
+ export declare function runMcpInstall(deps: Pick<SetupDeps, "processes">, { action, url, headers, installContext }: RunMcpInstallArgs): Promise<McpInstallResult>;
34
+ //# sourceMappingURL=install.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../../src/setup/mcp/install.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAEzC,OAAO,KAAK,EAAE,SAAS,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAE/E,MAAM,MAAM,iBAAiB,GAAG,YAAY,GAAG,QAAQ,CAAC;AAExD,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,iBAAiB,CAAC;IAC3B,iFAAiF;IACjF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,2CAA2C;IAC3C,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAKD,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,gBAAgB,CAAC;IACzB,+CAA+C;IAC/C,GAAG,EAAE,MAAM,CAAC;IACZ,gEAAgE;IAChE,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB,yDAAyD;IACzD,cAAc,EAAE,iBAAiB,CAAC;CACnC;AAED,wBAAsB,aAAa,CACjC,IAAI,EAAE,IAAI,CAAC,SAAS,EAAE,WAAW,CAAC,EAClC,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,cAAc,EAAE,EAAE,iBAAiB,GAC1D,OAAO,CAAC,gBAAgB,CAAC,CAW3B"}
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Execute one MCP install action — run the agent's `mcp add`, or merge the
3
+ * server entry into its config file.
4
+ *
5
+ * The CLI path adds first, and only remove-then-retries when the add is refused
6
+ * *and* the agent's own listing already shows an entry under our name — removing
7
+ * before the add is known to work could destroy a registration a failed retry
8
+ * can't restore. The `verifyArgs` read-back guards against drift: an add whose
9
+ * flags changed meaning while still exiting 0 shows up as a missing entry.
10
+ *
11
+ * Never throws when an install simply didn't take — returns a `failed` result
12
+ * with a reason for the caller to handle.
13
+ */
14
+ import { writeMcpConfig } from "../util/mcpConfig.js";
15
+ /** Registering a server is one config write; a slow CLI start is still fine. */
16
+ const CLI_INSTALL_TIMEOUT_MS = 30_000;
17
+ export async function runMcpInstall(deps, { action, url, headers, installContext }) {
18
+ try {
19
+ return action.kind === "cli"
20
+ ? await runCliInstall(deps, action, { url, headers, installContext })
21
+ : runFileInstall(action, { url, headers, installContext });
22
+ }
23
+ catch (error) {
24
+ return {
25
+ outcome: "failed",
26
+ reason: error instanceof Error ? error.message : String(error),
27
+ };
28
+ }
29
+ }
30
+ async function runCliInstall(deps, action, { url, headers, installContext, }) {
31
+ // Every exec runs in the install context's cwd — the repo root for a local
32
+ // install, so a `--scope project` add lands the config in this repo, not
33
+ // wherever px happened to be launched from.
34
+ const exec = (args) => deps.processes.exec({
35
+ command: action.binary,
36
+ args,
37
+ cwd: installContext.cwd,
38
+ timeoutMs: CLI_INSTALL_TIMEOUT_MS,
39
+ });
40
+ const fail = (reason) => ({
41
+ outcome: "failed",
42
+ reason,
43
+ });
44
+ let added = await exec(action.addArgs(url, headers));
45
+ // Retry through remove only when we can both confirm an entry exists and
46
+ // remove it — otherwise a refused add is just reported.
47
+ if (added.exitCode !== 0 &&
48
+ action.removeArgs &&
49
+ action.verifyArgs &&
50
+ (await exec(action.verifyArgs)).exitCode === 0) {
51
+ await exec(action.removeArgs);
52
+ added = await exec(action.addArgs(url, headers));
53
+ }
54
+ if (added.exitCode !== 0) {
55
+ return fail(added.stderr.trim() || `exit code ${added.exitCode}`);
56
+ }
57
+ // Trust the add's exit code only when the agent has no listing to read back
58
+ // from; otherwise confirm the entry actually registered.
59
+ if (action.verifyArgs) {
60
+ const verified = await exec(action.verifyArgs);
61
+ if (verified.exitCode !== 0) {
62
+ return fail("the server did not show up in the agent's MCP list");
63
+ }
64
+ }
65
+ return { outcome: "configured" };
66
+ }
67
+ function runFileInstall(action, { url, headers, installContext, }) {
68
+ writeMcpConfig({
69
+ filePath: action.path(installContext),
70
+ displayPath: action.displayPath(installContext),
71
+ patch: action.patch(url, headers),
72
+ ...(action.createDefaults ? { createDefaults: action.createDefaults } : {}),
73
+ });
74
+ return { outcome: "configured", file: action.displayPath(installContext) };
75
+ }
76
+ //# sourceMappingURL=install.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install.js","sourceRoot":"","sources":["../../../src/setup/mcp/install.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,68 @@
1
+ /**
2
+ * `px setup mcp` — register the Phoenix remote MCP server (`<base-url>/mcp`)
3
+ * with a coding agent's config. This module receives the already-resolved
4
+ * endpoint from the command layer.
5
+ *
6
+ * Auth defaults to OAuth (URL-only config; the agent handles browser login on
7
+ * first use). `--header` adds an API-key bearer fallback for headless clients,
8
+ * applied per agent (see {@link ./agents}).
9
+ *
10
+ * Without `--agent` the command prompts for scope then agent, after confirming
11
+ * the endpoint. A headless run requires `--agent` and defaults to global scope.
12
+ */
13
+ import type { SetupDeps } from "../deps/index.js";
14
+ import { type McpAgentId, type McpHeader, type McpScope } from "./agents.js";
15
+ /** What a run did, in the shape the summary and `--format json` print. */
16
+ export interface McpSetupReport {
17
+ /** The Phoenix base URL the server was pointed at (no trailing `/mcp`). */
18
+ endpoint: string;
19
+ /** The full MCP URL written into the agent config. */
20
+ url: string;
21
+ serverName: string;
22
+ agent: McpAgentId;
23
+ scope: McpScope;
24
+ /** `oauth` when URL-only; `header` when a bearer/custom header was written. */
25
+ auth: "oauth" | "header";
26
+ /** The config file written, for file-based agents (repo-relative or `~/…`). */
27
+ file?: string;
28
+ }
29
+ export interface McpSetupInputs {
30
+ /** Resolved Phoenix base URL (normalized, no trailing slash). */
31
+ endpoint: string;
32
+ /** True when `--endpoint` pinned it — skips the interactive confirm prompt. */
33
+ endpointExplicit: boolean;
34
+ /** Pinned agent, or undefined to detect + prompt. */
35
+ agent?: McpAgentId;
36
+ /** Pinned scope, or undefined (interactive prompts; headless defaults global). */
37
+ scope?: McpScope;
38
+ /** Headers for the bearer fallback; empty means OAuth (URL only). */
39
+ headers: McpHeader[];
40
+ headless: boolean;
41
+ }
42
+ export declare const COPY: {
43
+ readonly endpointPrompt: "Phoenix endpoint";
44
+ readonly endpointInvalid: "Enter a full http:// or https:// URL (e.g. http://localhost:6006).";
45
+ readonly endpointUnusable: (value: string) => string;
46
+ readonly usingEndpoint: (url: string) => string;
47
+ readonly scopePrompt: "Where should the MCP server be configured?";
48
+ readonly scopeGlobalLabel: "Global";
49
+ readonly scopeGlobalHint: "available across all your projects";
50
+ readonly scopeLocalLabel: "This repo";
51
+ readonly scopeLocalHint: "written into this project's config, checked in with it";
52
+ readonly agentPrompt: "Which coding agent?";
53
+ readonly detectedHint: "detected";
54
+ readonly headlessNeedsAgent: `--agent is required with --no-input. Pass one of: ${string}.`;
55
+ readonly localNeedsRepo: "--local must run inside a git repository. Re-run from your project, or use --global.";
56
+ readonly globalOnly: (agentLabel: string) => string;
57
+ readonly globalOnlyHeadless: (agentLabel: string) => string;
58
+ readonly homeUnknown: (agentLabel: string) => string;
59
+ readonly scopeUnsupported: (agentLabel: string, scope: McpScope) => string;
60
+ readonly headersUnsupported: (agentLabel: string, dropped: McpHeader[]) => string;
61
+ readonly configuredCli: (agentLabel: string) => string;
62
+ readonly configuredFile: (agentLabel: string, file: string) => string;
63
+ readonly installFailed: (agentLabel: string, reason: string) => string;
64
+ readonly nextStepOAuth: (agentLabel: string) => string;
65
+ readonly nextStepHeader: "The server is configured with your bearer header — no browser login needed.";
66
+ };
67
+ export declare function runSetupMcp(deps: Pick<SetupDeps, "context" | "prompter" | "processes">, inputs: McpSetupInputs): Promise<McpSetupReport>;
68
+ //# sourceMappingURL=runSetupMcp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runSetupMcp.d.ts","sourceRoot":"","sources":["../../../src/setup/mcp/runSetupMcp.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAQH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAEzC,OAAO,EAML,KAAK,UAAU,EACf,KAAK,SAAS,EACd,KAAK,QAAQ,EACd,MAAM,UAAU,CAAC;AAGlB,0EAA0E;AAC1E,MAAM,WAAW,cAAc;IAC7B,2EAA2E;IAC3E,QAAQ,EAAE,MAAM,CAAC;IACjB,sDAAsD;IACtD,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,UAAU,CAAC;IAClB,KAAK,EAAE,QAAQ,CAAC;IAChB,+EAA+E;IAC/E,IAAI,EAAE,OAAO,GAAG,QAAQ,CAAC;IACzB,+EAA+E;IAC/E,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,cAAc;IAC7B,iEAAiE;IACjE,QAAQ,EAAE,MAAM,CAAC;IACjB,+EAA+E;IAC/E,gBAAgB,EAAE,OAAO,CAAC;IAC1B,qDAAqD;IACrD,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,kFAAkF;IAClF,KAAK,CAAC,EAAE,QAAQ,CAAC;IACjB,qEAAqE;IACrE,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,eAAO,MAAM,IAAI;aACf,cAAc,EAAE,kBAAkB;aAClC,eAAe,EACb,oEAAoE;aACtE,gBAAgB,UAAU,MAAM;aAGhC,aAAa,QAAQ,MAAM;aAE3B,WAAW,EAAE,4CAA4C;aACzD,gBAAgB,EAAE,QAAQ;aAC1B,eAAe,EAAE,oCAAoC;aACrD,eAAe,EAAE,WAAW;aAC5B,cAAc,EAAE,wDAAwD;aACxE,WAAW,EAAE,qBAAqB;aAClC,YAAY,EAAE,UAAU;aACxB,kBAAkB;aAClB,cAAc,EACZ,sFAAsF;aACxF,UAAU,eAAe,MAAM;aAE/B,kBAAkB,eAAe,MAAM;aAEvC,WAAW,eAAe,MAAM;aAGhC,gBAAgB,eAAe,MAAM,SAAS,QAAQ;aAEtD,kBAAkB,eAAe,MAAM,WAAW,SAAS,EAAE;aAK7D,aAAa,eAAe,MAAM;aAElC,cAAc,eAAe,MAAM,QAAQ,MAAM;aAEjD,aAAa,eAAe,MAAM,UAAU,MAAM;aAElD,aAAa,eAAe,MAAM;aAElC,cAAc,EACZ,6EAA6E;CACvE,CAAC;AAMX,wBAAsB,WAAW,CAC/B,IAAI,EAAE,IAAI,CAAC,SAAS,EAAE,SAAS,GAAG,UAAU,GAAG,WAAW,CAAC,EAC3D,MAAM,EAAE,cAAc,GACrB,OAAO,CAAC,cAAc,CAAC,CA8EzB"}