@bastani/atomic 0.9.25-alpha.3 → 0.9.25-alpha.5

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 (184) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/dist/builtin/intercom/package.json +1 -1
  3. package/dist/builtin/mcp/CHANGELOG.md +30 -0
  4. package/dist/builtin/mcp/OAUTH.md +59 -269
  5. package/dist/builtin/mcp/README.md +58 -345
  6. package/dist/builtin/mcp/index.bundle.mjs +4 -28073
  7. package/dist/builtin/mcp/native-client-licenses/LICENSES/modelcontextprotocol-typescript-sdk.txt +21 -0
  8. package/dist/builtin/mcp/native-client-licenses/NOTICE +30 -0
  9. package/dist/builtin/mcp/package.json +4 -25
  10. package/dist/builtin/subagents/package.json +1 -1
  11. package/dist/builtin/web-access/package.json +1 -1
  12. package/dist/builtin/workflows/CHANGELOG.md +6 -0
  13. package/dist/builtin/workflows/package.json +1 -1
  14. package/dist/builtin/workflows/src/extension/index.bundle.mjs +18 -3
  15. package/dist/cli/args.d.ts.map +1 -1
  16. package/dist/cli/args.js +2 -1
  17. package/dist/cli/args.js.map +1 -1
  18. package/dist/core/agent-session-extension-bindings.d.ts.map +1 -1
  19. package/dist/core/agent-session-extension-bindings.js +87 -5
  20. package/dist/core/agent-session-extension-bindings.js.map +1 -1
  21. package/dist/core/agent-session-tool-registry.d.ts.map +1 -1
  22. package/dist/core/agent-session-tool-registry.js +6 -3
  23. package/dist/core/agent-session-tool-registry.js.map +1 -1
  24. package/dist/core/extensions/context-types.d.ts +3 -1
  25. package/dist/core/extensions/context-types.d.ts.map +1 -1
  26. package/dist/core/extensions/context-types.js.map +1 -1
  27. package/dist/core/extensions/loader-api.d.ts.map +1 -1
  28. package/dist/core/extensions/loader-api.js +4 -0
  29. package/dist/core/extensions/loader-api.js.map +1 -1
  30. package/dist/core/extensions/loader-virtual-modules.d.ts.map +1 -1
  31. package/dist/core/extensions/loader-virtual-modules.js +3 -0
  32. package/dist/core/extensions/loader-virtual-modules.js.map +1 -1
  33. package/dist/core/mcp-child-policy.d.ts +11 -0
  34. package/dist/core/mcp-child-policy.d.ts.map +1 -0
  35. package/dist/core/mcp-child-policy.js +31 -0
  36. package/dist/core/mcp-child-policy.js.map +1 -0
  37. package/dist/core/mcp-servers.d.ts +32 -26
  38. package/dist/core/mcp-servers.d.ts.map +1 -1
  39. package/dist/core/mcp-servers.js +148 -1
  40. package/dist/core/mcp-servers.js.map +1 -1
  41. package/dist/core/package-manager-manifest.js.map +1 -1
  42. package/dist/core/package-manager-mcp-servers.js +1 -1
  43. package/dist/core/package-manager-mcp-servers.js.map +1 -1
  44. package/dist/core/sdk.js +10 -1
  45. package/dist/core/sdk.js.map +1 -1
  46. package/dist/core/tools/truncate.d.ts +8 -0
  47. package/dist/core/tools/truncate.d.ts.map +1 -1
  48. package/dist/core/tools/truncate.js +24 -0
  49. package/dist/core/tools/truncate.js.map +1 -1
  50. package/dist/extensions/mcp/cli.d.ts +21 -0
  51. package/dist/extensions/mcp/cli.d.ts.map +1 -0
  52. package/dist/extensions/mcp/cli.js +500 -0
  53. package/dist/extensions/mcp/cli.js.map +1 -0
  54. package/dist/extensions/mcp/cli.lazy.d.ts +3 -0
  55. package/dist/extensions/mcp/cli.lazy.d.ts.map +1 -0
  56. package/dist/extensions/mcp/cli.lazy.js +3 -0
  57. package/dist/extensions/mcp/cli.lazy.js.map +1 -0
  58. package/dist/extensions/mcp/client/auth-provider.d.ts +15 -0
  59. package/dist/extensions/mcp/client/auth-provider.d.ts.map +1 -0
  60. package/dist/extensions/mcp/client/auth-provider.js +2 -0
  61. package/dist/extensions/mcp/client/auth-provider.js.map +1 -0
  62. package/dist/extensions/mcp/client/client.d.ts +89 -0
  63. package/dist/extensions/mcp/client/client.d.ts.map +1 -0
  64. package/dist/extensions/mcp/client/client.js +457 -0
  65. package/dist/extensions/mcp/client/client.js.map +1 -0
  66. package/dist/extensions/mcp/client/index.d.ts +9 -0
  67. package/dist/extensions/mcp/client/index.d.ts.map +1 -0
  68. package/dist/extensions/mcp/client/index.js +7 -0
  69. package/dist/extensions/mcp/client/index.js.map +1 -0
  70. package/dist/extensions/mcp/client/oauth/callback.d.ts +42 -0
  71. package/dist/extensions/mcp/client/oauth/callback.d.ts.map +1 -0
  72. package/dist/extensions/mcp/client/oauth/callback.js +106 -0
  73. package/dist/extensions/mcp/client/oauth/callback.js.map +1 -0
  74. package/dist/extensions/mcp/client/oauth/discovery.d.ts +27 -0
  75. package/dist/extensions/mcp/client/oauth/discovery.d.ts.map +1 -0
  76. package/dist/extensions/mcp/client/oauth/discovery.js +153 -0
  77. package/dist/extensions/mcp/client/oauth/discovery.js.map +1 -0
  78. package/dist/extensions/mcp/client/oauth/errors.d.ts +24 -0
  79. package/dist/extensions/mcp/client/oauth/errors.d.ts.map +1 -0
  80. package/dist/extensions/mcp/client/oauth/errors.js +46 -0
  81. package/dist/extensions/mcp/client/oauth/errors.js.map +1 -0
  82. package/dist/extensions/mcp/client/oauth/flow.d.ts +82 -0
  83. package/dist/extensions/mcp/client/oauth/flow.d.ts.map +1 -0
  84. package/dist/extensions/mcp/client/oauth/flow.js +292 -0
  85. package/dist/extensions/mcp/client/oauth/flow.js.map +1 -0
  86. package/dist/extensions/mcp/client/oauth/index.d.ts +7 -0
  87. package/dist/extensions/mcp/client/oauth/index.d.ts.map +1 -0
  88. package/dist/extensions/mcp/client/oauth/index.js +6 -0
  89. package/dist/extensions/mcp/client/oauth/index.js.map +1 -0
  90. package/dist/extensions/mcp/client/oauth/provider.d.ts +59 -0
  91. package/dist/extensions/mcp/client/oauth/provider.d.ts.map +1 -0
  92. package/dist/extensions/mcp/client/oauth/provider.js +116 -0
  93. package/dist/extensions/mcp/client/oauth/provider.js.map +1 -0
  94. package/dist/extensions/mcp/client/oauth/types.d.ts +77 -0
  95. package/dist/extensions/mcp/client/oauth/types.d.ts.map +1 -0
  96. package/dist/extensions/mcp/client/oauth/types.js +109 -0
  97. package/dist/extensions/mcp/client/oauth/types.js.map +1 -0
  98. package/dist/extensions/mcp/client/protocol/content.d.ts +82 -0
  99. package/dist/extensions/mcp/client/protocol/content.d.ts.map +1 -0
  100. package/dist/extensions/mcp/client/protocol/content.js +41 -0
  101. package/dist/extensions/mcp/client/protocol/content.js.map +1 -0
  102. package/dist/extensions/mcp/client/protocol/jsonrpc.d.ts +59 -0
  103. package/dist/extensions/mcp/client/protocol/jsonrpc.d.ts.map +1 -0
  104. package/dist/extensions/mcp/client/protocol/jsonrpc.js +67 -0
  105. package/dist/extensions/mcp/client/protocol/jsonrpc.js.map +1 -0
  106. package/dist/extensions/mcp/client/protocol/types.d.ts +123 -0
  107. package/dist/extensions/mcp/client/protocol/types.d.ts.map +1 -0
  108. package/dist/extensions/mcp/client/protocol/types.js +7 -0
  109. package/dist/extensions/mcp/client/protocol/types.js.map +1 -0
  110. package/dist/extensions/mcp/client/testing/index.d.ts +2 -0
  111. package/dist/extensions/mcp/client/testing/index.d.ts.map +1 -0
  112. package/dist/extensions/mcp/client/testing/index.js +2 -0
  113. package/dist/extensions/mcp/client/testing/index.js.map +1 -0
  114. package/dist/extensions/mcp/client/transports/in-memory.d.ts +19 -0
  115. package/dist/extensions/mcp/client/transports/in-memory.d.ts.map +1 -0
  116. package/dist/extensions/mcp/client/transports/in-memory.js +50 -0
  117. package/dist/extensions/mcp/client/transports/in-memory.js.map +1 -0
  118. package/dist/extensions/mcp/client/transports/stdio.d.ts +32 -0
  119. package/dist/extensions/mcp/client/transports/stdio.d.ts.map +1 -0
  120. package/dist/extensions/mcp/client/transports/stdio.js +201 -0
  121. package/dist/extensions/mcp/client/transports/stdio.js.map +1 -0
  122. package/dist/extensions/mcp/client/transports/streamable-http.d.ts +96 -0
  123. package/dist/extensions/mcp/client/transports/streamable-http.d.ts.map +1 -0
  124. package/dist/extensions/mcp/client/transports/streamable-http.js +456 -0
  125. package/dist/extensions/mcp/client/transports/streamable-http.js.map +1 -0
  126. package/dist/extensions/mcp/client/transports/transport.d.ts +28 -0
  127. package/dist/extensions/mcp/client/transports/transport.d.ts.map +1 -0
  128. package/dist/extensions/mcp/client/transports/transport.js +38 -0
  129. package/dist/extensions/mcp/client/transports/transport.js.map +1 -0
  130. package/dist/extensions/mcp/config.d.ts +72 -0
  131. package/dist/extensions/mcp/config.d.ts.map +1 -0
  132. package/dist/extensions/mcp/config.js +158 -0
  133. package/dist/extensions/mcp/config.js.map +1 -0
  134. package/dist/extensions/mcp/index.d.ts +76 -0
  135. package/dist/extensions/mcp/index.d.ts.map +1 -0
  136. package/dist/extensions/mcp/index.js +1119 -0
  137. package/dist/extensions/mcp/index.js.map +1 -0
  138. package/dist/extensions/mcp/log.d.ts +16 -0
  139. package/dist/extensions/mcp/log.d.ts.map +1 -0
  140. package/dist/extensions/mcp/log.js +66 -0
  141. package/dist/extensions/mcp/log.js.map +1 -0
  142. package/dist/extensions/mcp/oauth.d.ts +103 -0
  143. package/dist/extensions/mcp/oauth.d.ts.map +1 -0
  144. package/dist/extensions/mcp/oauth.js +382 -0
  145. package/dist/extensions/mcp/oauth.js.map +1 -0
  146. package/dist/extensions/mcp/resources.d.ts +43 -0
  147. package/dist/extensions/mcp/resources.d.ts.map +1 -0
  148. package/dist/extensions/mcp/resources.js +262 -0
  149. package/dist/extensions/mcp/resources.js.map +1 -0
  150. package/dist/extensions/mcp/runtime.d.ts +104 -0
  151. package/dist/extensions/mcp/runtime.d.ts.map +1 -0
  152. package/dist/extensions/mcp/runtime.js +546 -0
  153. package/dist/extensions/mcp/runtime.js.map +1 -0
  154. package/dist/extensions/mcp/runtime.lazy.d.ts +3 -0
  155. package/dist/extensions/mcp/runtime.lazy.d.ts.map +1 -0
  156. package/dist/extensions/mcp/runtime.lazy.js +3 -0
  157. package/dist/extensions/mcp/runtime.lazy.js.map +1 -0
  158. package/dist/extensions/mcp/tools.d.ts +84 -0
  159. package/dist/extensions/mcp/tools.d.ts.map +1 -0
  160. package/dist/extensions/mcp/tools.js +251 -0
  161. package/dist/extensions/mcp/tools.js.map +1 -0
  162. package/dist/extensions/mcp/ui.d.ts +60 -0
  163. package/dist/extensions/mcp/ui.d.ts.map +1 -0
  164. package/dist/extensions/mcp/ui.js +175 -0
  165. package/dist/extensions/mcp/ui.js.map +1 -0
  166. package/dist/index.d.ts +5 -1
  167. package/dist/index.d.ts.map +1 -1
  168. package/dist/index.js +5 -0
  169. package/dist/index.js.map +1 -1
  170. package/dist/main.d.ts.map +1 -1
  171. package/dist/main.js +7 -0
  172. package/dist/main.js.map +1 -1
  173. package/dist/modes/interactive/interactive-slash-commands.js +23 -8
  174. package/dist/modes/interactive/interactive-slash-commands.js.map +1 -1
  175. package/docs/extensions/api-reference.md +3 -3
  176. package/docs/extensions.md +8 -8
  177. package/docs/mcp-servers.md +153 -79
  178. package/docs/packages/authoring.md +2 -2
  179. package/docs/sdk.md +1 -1
  180. package/docs/sessions.md +1 -1
  181. package/npm-shrinkwrap.json +32 -32
  182. package/package.json +3 -3
  183. package/dist/builtin/mcp/app-bridge.bundle.js +0 -67
  184. package/dist/builtin/mcp/xdg-open +0 -1267
@@ -0,0 +1,500 @@
1
+ /**
2
+ * `pi mcp`: add, remove, and check MCP servers and sign in to them outside a session. Agents run it
3
+ * through bash to configure servers, verify an `mcp.json` they wrote, and start an OAuth sign-in;
4
+ * the user only approves access in the browser. Running sessions pick up new credentials on their
5
+ * next turn.
6
+ */
7
+ import { existsSync } from "node:fs";
8
+ import { join } from "node:path";
9
+ import { createInterface } from "node:readline/promises";
10
+ import chalk from "chalk";
11
+ import { APP_NAME, CONFIG_DIR_NAME } from "../../config.js";
12
+ import { validateMcpServerConfig } from "../../core/mcp-servers.js";
13
+ import { ProjectTrustStore } from "../../core/trust-manager.js";
14
+ import { openBrowser } from "../../utils/open-browser.js";
15
+ import { addMcpServerConfig, getMcpToolExposure, loadMcpConfig, removeMcpServerConfig, } from "./config.js";
16
+ import { createDefaultTransport, McpOAuthCredentialStore, McpServerConnection, McpServerLog, McpSignInCancelledError, signInMcpServer, } from "./runtime.js";
17
+ const HELP = `${chalk.bold("Usage:")}
18
+ ${APP_NAME} mcp add <server> [options] -- <command> [args...]
19
+ ${APP_NAME} mcp add <server> [options] --url <url>
20
+ ${APP_NAME} mcp remove <server> [-l]
21
+ ${APP_NAME} mcp list [--json]
22
+ ${APP_NAME} mcp login <server> [--timeout <seconds>]
23
+ ${APP_NAME} mcp logout <server>
24
+
25
+ Configure and check MCP servers and sign in to OAuth servers without starting a session.
26
+ Reads ~/${CONFIG_DIR_NAME}/agent/mcp.json and, in trusted projects, ${CONFIG_DIR_NAME}/mcp.json.
27
+
28
+ Commands:
29
+ add <server> Add or replace a server in mcp.json
30
+ remove <server> Remove a server from mcp.json
31
+ list Show state, tools, and errors (exits 1 on failure)
32
+ login <server> Sign in through the browser
33
+ logout <server> Delete the stored OAuth credentials
34
+
35
+ Options for add and remove:
36
+ -l, --local Use ${CONFIG_DIR_NAME}/mcp.json in the current project instead of the global file
37
+
38
+ Options for add:
39
+ --url <url> Streamable HTTP server URL (instead of a command)
40
+ --env <KEY=VALUE> Environment variable for a stdio server (repeatable)
41
+ --cwd <dir> Working directory for a stdio server
42
+ --header <KEY=VALUE> HTTP header (repeatable)
43
+ --bearer-token-env-var <NAME>
44
+ Send "Authorization: Bearer \${NAME}"
45
+ --oauth-client-id <id> Pre-registered OAuth client id
46
+ --oauth-client-secret <secret>
47
+ OAuth client secret (may be \${NAME} or !command)
48
+ --oauth-callback-port <port>
49
+ Fixed OAuth callback port
50
+ --oauth-client-name <name>
51
+ Client name sent when registering with the OAuth server
52
+ --exposure <mode> codemode (default), deferred, direct, or hidden
53
+ --description <text> What the server offers, shown in the system prompt
54
+
55
+ Other options:
56
+ --json Print the list as JSON
57
+ --timeout <seconds> How long login waits for the browser (default: 300)`;
58
+ const HELP_HINT = chalk.dim(`Use "${APP_NAME} mcp --help" for usage.`);
59
+ const DEFAULT_LOGIN_TIMEOUT_SECONDS = 300;
60
+ function errorMessage(error) {
61
+ return error instanceof Error ? error.message : String(error);
62
+ }
63
+ function describeTransport(entry) {
64
+ const { config } = entry;
65
+ return "url" in config ? config.url : [config.command, ...(config.args ?? [])].join(" ");
66
+ }
67
+ function createConnection(entry, options, credentials) {
68
+ return new McpServerConnection({
69
+ entry,
70
+ cwd: options.cwd,
71
+ createTransport: createDefaultTransport,
72
+ credentials,
73
+ log: new McpServerLog(join(options.agentDir, "mcp.log")),
74
+ onTools: () => { },
75
+ });
76
+ }
77
+ /** Short spellings of options. `-l`/`--local` match `pi install`. */
78
+ const OPTION_ALIASES = new Map([["-l", "--local"]]);
79
+ /**
80
+ * Parse `--name value` options; returns undefined and reports unknown ones. `--` ends the options,
81
+ * as does reaching `maxPositionals` positional arguments: the remaining arguments are positional,
82
+ * so a command's own options (`add <server> <command> --flag`) are passed through.
83
+ */
84
+ function parseOptions(args, known, error, maxPositionals = Number.POSITIVE_INFINITY) {
85
+ const positional = [];
86
+ const values = new Map();
87
+ const lists = new Map();
88
+ for (let index = 0; index < args.length; index++) {
89
+ const arg = OPTION_ALIASES.get(args[index]) ?? args[index];
90
+ if (arg === "--" || positional.length >= maxPositionals) {
91
+ positional.push(...args.slice(arg === "--" ? index + 1 : index));
92
+ break;
93
+ }
94
+ if (!arg.startsWith("--")) {
95
+ positional.push(arg);
96
+ continue;
97
+ }
98
+ const name = arg.slice(2);
99
+ const kind = known[name];
100
+ if (!kind) {
101
+ error(`Unknown option ${arg}.\n${HELP_HINT}`);
102
+ return undefined;
103
+ }
104
+ if (kind === "flag") {
105
+ values.set(name, true);
106
+ continue;
107
+ }
108
+ const value = args[++index];
109
+ if (value === undefined) {
110
+ error(`${arg} needs a value.`);
111
+ return undefined;
112
+ }
113
+ if (kind === "list")
114
+ lists.set(name, [...(lists.get(name) ?? []), value]);
115
+ else
116
+ values.set(name, value);
117
+ }
118
+ return { positional, values, lists };
119
+ }
120
+ /** Run `pi mcp <args>` and return the exit code. */
121
+ export async function runMcpCommand(args, options) {
122
+ const log = options.log ?? ((line) => console.log(line));
123
+ const error = options.error ?? ((line) => console.error(line));
124
+ const [command, ...rest] = args;
125
+ if (command === undefined || command === "help" || args.includes("--help") || args.includes("-h")) {
126
+ log(HELP);
127
+ return 0;
128
+ }
129
+ const projectConfig = join(options.cwd, CONFIG_DIR_NAME, "mcp.json");
130
+ if (command === "add" || command === "remove") {
131
+ return command === "add"
132
+ ? add(rest, projectConfig, options, log, error)
133
+ : remove(rest, projectConfig, options, log, error);
134
+ }
135
+ const projectTrusted = new ProjectTrustStore(options.agentDir).get(options.cwd) === true;
136
+ const loaded = loadMcpConfig({ agentDir: options.agentDir, cwd: options.cwd, projectTrusted });
137
+ const untrustedNote = !projectTrusted && existsSync(projectConfig)
138
+ ? `${projectConfig} is ignored because the project is not trusted. Start ${APP_NAME} in the project to trust it.`
139
+ : undefined;
140
+ const credentials = options.credentials ?? new McpOAuthCredentialStore();
141
+ switch (command) {
142
+ case "list": {
143
+ const parsed = parseOptions(rest, { json: "flag" }, error);
144
+ if (!parsed)
145
+ return 1;
146
+ if (parsed.positional.length > 0) {
147
+ error(`Usage: ${APP_NAME} mcp list [--json]\n${HELP_HINT}`);
148
+ return 1;
149
+ }
150
+ return list(loaded, parsed.values.has("json"), untrustedNote, options, credentials, log);
151
+ }
152
+ case "login":
153
+ case "logout": {
154
+ const parsed = parseOptions(rest, command === "login" ? { timeout: "value" } : {}, error);
155
+ if (!parsed)
156
+ return 1;
157
+ const [name, ...extra] = parsed.positional;
158
+ if (!name || extra.length > 0) {
159
+ error(`Usage: ${APP_NAME} mcp ${command} <server>\n${HELP_HINT}`);
160
+ return 1;
161
+ }
162
+ const entry = loaded.servers.find((server) => server.name === name);
163
+ if (!entry) {
164
+ error(`No MCP server named "${name}".${untrustedNote ? ` ${untrustedNote}` : ""} Configured: ${loaded.servers.map((server) => server.name).join(", ") || "none"}.`);
165
+ return 1;
166
+ }
167
+ const connection = createConnection(entry, options, credentials);
168
+ const url = connection.oauthUrl;
169
+ if (!url) {
170
+ error(`MCP server "${name}" does not use OAuth. Only HTTP servers without an Authorization header do.`);
171
+ return 1;
172
+ }
173
+ if (command === "logout") {
174
+ const removed = await credentials.removeAsync(url);
175
+ log(removed ? `Signed out of MCP server "${name}".` : `No stored credentials for MCP server "${name}".`);
176
+ return 0;
177
+ }
178
+ const timeout = Number(parsed.values.get("timeout") ?? DEFAULT_LOGIN_TIMEOUT_SECONDS);
179
+ if (!Number.isFinite(timeout) || timeout <= 0) {
180
+ error("--timeout must be a positive number of seconds.");
181
+ return 1;
182
+ }
183
+ try {
184
+ return await login(entry, connection, url, timeout * 1000, options, credentials, log, error);
185
+ }
186
+ finally {
187
+ await connection.close();
188
+ }
189
+ }
190
+ default:
191
+ error(`Unknown mcp command "${command}".\n${HELP_HINT}`);
192
+ return 1;
193
+ }
194
+ }
195
+ /** Parse `KEY=VALUE` pairs of a repeatable option into a record. */
196
+ function parsePairs(option, pairs, error) {
197
+ if (!pairs)
198
+ return {};
199
+ const record = {};
200
+ for (const pair of pairs) {
201
+ const separator = pair.indexOf("=");
202
+ if (separator <= 0) {
203
+ error(`--${option} expects KEY=VALUE, got "${pair}".`);
204
+ return undefined;
205
+ }
206
+ record[pair.slice(0, separator)] = pair.slice(separator + 1);
207
+ }
208
+ return record;
209
+ }
210
+ function add(args, projectConfig, options, log, error) {
211
+ const usage = `Usage: ${APP_NAME} mcp add <server> [options] (--url <url> | -- <command> [args...])\n${HELP_HINT}`;
212
+ const parsed = parseOptions(args, {
213
+ local: "flag",
214
+ url: "value",
215
+ env: "list",
216
+ cwd: "value",
217
+ header: "list",
218
+ "bearer-token-env-var": "value",
219
+ "oauth-client-id": "value",
220
+ "oauth-client-secret": "value",
221
+ "oauth-callback-port": "value",
222
+ "oauth-client-name": "value",
223
+ exposure: "value",
224
+ description: "value",
225
+ }, error, 2);
226
+ if (!parsed)
227
+ return 1;
228
+ const { positional, values, lists } = parsed;
229
+ const [name, ...command] = positional;
230
+ const url = values.get("url");
231
+ if (!name || (url === undefined) === (command.length === 0)) {
232
+ error(usage);
233
+ return 1;
234
+ }
235
+ const value = (option) => {
236
+ const found = values.get(option);
237
+ return typeof found === "string" ? found : undefined;
238
+ };
239
+ const exposure = value("exposure");
240
+ const httpOnly = [
241
+ "header",
242
+ "bearer-token-env-var",
243
+ "oauth-client-id",
244
+ "oauth-client-secret",
245
+ "oauth-callback-port",
246
+ "oauth-client-name",
247
+ ];
248
+ const stdioOnly = ["env", "cwd"];
249
+ const misplaced = (url === undefined ? httpOnly : stdioOnly).find((option) => values.has(option) || lists.has(option));
250
+ if (misplaced) {
251
+ error(`--${misplaced} only applies to ${url === undefined ? "HTTP servers (--url)" : "stdio servers"}.`);
252
+ return 1;
253
+ }
254
+ let config;
255
+ if (typeof url === "string") {
256
+ const headers = parsePairs("header", lists.get("header"), error);
257
+ if (!headers)
258
+ return 1;
259
+ const bearer = value("bearer-token-env-var");
260
+ if (bearer !== undefined)
261
+ headers.Authorization = `Bearer \${${bearer}}`;
262
+ const port = value("oauth-callback-port");
263
+ const oauth = {
264
+ ...(value("oauth-client-id") === undefined ? {} : { clientId: value("oauth-client-id") }),
265
+ ...(value("oauth-client-secret") === undefined ? {} : { clientSecret: value("oauth-client-secret") }),
266
+ ...(port === undefined ? {} : { callbackPort: Number(port) }),
267
+ ...(value("oauth-client-name") === undefined ? {} : { clientName: value("oauth-client-name") }),
268
+ };
269
+ config = {
270
+ url,
271
+ ...(Object.keys(headers).length > 0 ? { headers } : {}),
272
+ ...(Object.keys(oauth).length > 0 ? { oauth } : {}),
273
+ };
274
+ }
275
+ else {
276
+ const env = parsePairs("env", lists.get("env"), error);
277
+ if (!env)
278
+ return 1;
279
+ const [executable, ...commandArgs] = command;
280
+ config = {
281
+ command: executable,
282
+ ...(commandArgs.length > 0 ? { args: commandArgs } : {}),
283
+ ...(Object.keys(env).length > 0 ? { env } : {}),
284
+ ...(value("cwd") === undefined ? {} : { cwd: value("cwd") }),
285
+ };
286
+ }
287
+ if (exposure !== undefined)
288
+ config.exposure = exposure;
289
+ const description = value("description");
290
+ if (description !== undefined)
291
+ config.description = description;
292
+ const validated = validateMcpServerConfig(name, config);
293
+ if (typeof validated === "string") {
294
+ error(validated);
295
+ return 1;
296
+ }
297
+ const project = values.has("local");
298
+ const path = project ? projectConfig : join(options.agentDir, "mcp.json");
299
+ const scope = project ? "project" : "global";
300
+ let replaced;
301
+ try {
302
+ replaced = addMcpServerConfig(path, name, validated);
303
+ }
304
+ catch (addError) {
305
+ error(`Could not update ${path}: ${errorMessage(addError)}`);
306
+ return 1;
307
+ }
308
+ log(`${replaced ? "Replaced" : "Added"} ${scope} MCP server "${name}" in ${path}.`);
309
+ if (project && new ProjectTrustStore(options.agentDir).get(options.cwd) !== true) {
310
+ log(`The project is not trusted, so ${path} is ignored until you start ${APP_NAME} in the project and trust it.`);
311
+ }
312
+ // HTTP servers without an Authorization header may use OAuth.
313
+ const mayNeedSignIn = "url" in validated &&
314
+ !Object.keys(validated.headers ?? {}).some((header) => header.toLowerCase() === "authorization");
315
+ log(`Check it with: ${APP_NAME} mcp list${mayNeedSignIn ? `. If it requires sign-in: ${APP_NAME} mcp login ${name}` : ""}`);
316
+ return 0;
317
+ }
318
+ function remove(args, projectConfig, options, log, error) {
319
+ const parsed = parseOptions(args, { local: "flag" }, error);
320
+ if (!parsed)
321
+ return 1;
322
+ const [name, ...extra] = parsed.positional;
323
+ if (!name || extra.length > 0) {
324
+ error(`Usage: ${APP_NAME} mcp remove <server> [-l]\n${HELP_HINT}`);
325
+ return 1;
326
+ }
327
+ const project = parsed.values.has("local");
328
+ const globalConfig = join(options.agentDir, "mcp.json");
329
+ const path = project ? projectConfig : globalConfig;
330
+ const scope = project ? "project" : "global";
331
+ let removed;
332
+ try {
333
+ removed = removeMcpServerConfig(path, name);
334
+ }
335
+ catch (removeError) {
336
+ error(`Could not update ${path}: ${errorMessage(removeError)}`);
337
+ return 1;
338
+ }
339
+ if (removed) {
340
+ log(`Removed ${scope} MCP server "${name}" from ${path}.`);
341
+ return 0;
342
+ }
343
+ const other = loadMcpConfig({ agentDir: options.agentDir, cwd: options.cwd, projectTrusted: true }).servers.find((server) => server.name === name && server.scope !== scope);
344
+ error(`No ${scope} MCP server named "${name}" in ${path}.${other ? ` It is defined in ${other.source}${other.scope === "project" ? "; use --local" : "; omit --local"}.` : ""}`);
345
+ return 1;
346
+ }
347
+ async function list(loaded, json, untrustedNote, options, credentials, log) {
348
+ const reports = await Promise.all(loaded.servers.map(async (entry) => {
349
+ const report = {
350
+ name: entry.name,
351
+ scope: entry.scope ?? "global",
352
+ source: entry.source,
353
+ enabled: entry.config.enabled !== false,
354
+ exposure: entry.config.exposure ?? "codemode",
355
+ transport: describeTransport(entry),
356
+ state: "disabled",
357
+ tools: [],
358
+ };
359
+ if (!report.enabled)
360
+ return report;
361
+ const connection = createConnection(entry, options, credentials);
362
+ try {
363
+ await connection.getClient();
364
+ }
365
+ catch {
366
+ // The connection records the state and error.
367
+ }
368
+ report.state = connection.state;
369
+ report.tools = connection.tools.map((tool) => tool.name);
370
+ const overrides = connection.tools.flatMap((tool) => {
371
+ const exposure = getMcpToolExposure(entry.config, tool.name);
372
+ return exposure === report.exposure ? [] : [[tool.name, exposure]];
373
+ });
374
+ if (overrides.length > 0)
375
+ report.toolExposure = Object.fromEntries(overrides);
376
+ if (connection.hasResources) {
377
+ report.resources = connection.resources.length;
378
+ report.resourceTemplates = connection.resourceTemplates.length;
379
+ }
380
+ if (connection.state !== "connected" && connection.error)
381
+ report.error = connection.error;
382
+ await connection.close();
383
+ return report;
384
+ }));
385
+ const failed = loaded.errors.length > 0 || reports.some((report) => report.enabled && report.state !== "connected");
386
+ if (json) {
387
+ log(JSON.stringify({ servers: reports, errors: loaded.errors, ...(untrustedNote ? { note: untrustedNote } : {}) }, null, 2));
388
+ return failed ? 1 : 0;
389
+ }
390
+ if (reports.length === 0 && loaded.errors.length === 0) {
391
+ log(`No MCP servers configured. Add them to ${join(options.agentDir, "mcp.json")} or .pi/mcp.json.`);
392
+ }
393
+ for (const report of reports) {
394
+ const state = report.state === "connected"
395
+ ? `connected, ${report.tools.length} tool${report.tools.length === 1 ? "" : "s"}`
396
+ : report.state === "needs-auth"
397
+ ? "needs sign-in"
398
+ : report.state;
399
+ log(`${report.name}: ${state} (${report.exposure}, ${report.scope})`);
400
+ log(` ${report.transport}`);
401
+ if (report.state === "needs-auth")
402
+ log(` sign in with: ${APP_NAME} mcp login ${report.name}`);
403
+ if (report.tools.length > 0) {
404
+ const tools = report.tools.map((tool) => {
405
+ const exposure = report.toolExposure?.[tool];
406
+ return exposure ? `${tool} [${exposure}]` : tool;
407
+ });
408
+ log(` tools: ${tools.join(", ")}`);
409
+ }
410
+ if (report.resources !== undefined) {
411
+ log(` resources: ${report.resources}, URI templates: ${report.resourceTemplates ?? 0}`);
412
+ }
413
+ if (report.error)
414
+ log(` ${report.error.split("\n").join("\n ")}`);
415
+ }
416
+ for (const configError of loaded.errors)
417
+ log(`config error: ${configError}`);
418
+ if (untrustedNote)
419
+ log(untrustedNote);
420
+ return failed ? 1 : 0;
421
+ }
422
+ async function login(entry, connection, url, timeoutMs, options, credentials, log, error) {
423
+ const { name } = entry;
424
+ // Connecting first answers whether a sign-in is needed and records the server's challenge.
425
+ try {
426
+ await connection.getClient();
427
+ log(`Already signed in to MCP server "${name}" (${connection.tools.length} tools).`);
428
+ return 0;
429
+ }
430
+ catch {
431
+ if (connection.state !== "needs-auth") {
432
+ error(`MCP server "${name}" failed to connect: ${connection.error ?? "unknown error"}`);
433
+ return 1;
434
+ }
435
+ }
436
+ const openUrl = options.openUrl ?? openBrowser;
437
+ const interactive = process.stdin.isTTY === true && options.openUrl === undefined;
438
+ try {
439
+ await signInMcpServer({
440
+ serverUrl: url,
441
+ store: credentials.forServer(url),
442
+ settings: connection.oauthSettings(),
443
+ challenge: connection.challenge,
444
+ prompt: {
445
+ showAuthorizationUrl: (authorizationUrl) => {
446
+ log(`Sign in to MCP server "${name}" in your browser:\n${authorizationUrl.href}`);
447
+ openUrl(authorizationUrl.href);
448
+ },
449
+ promptForRedirectUrl: (signal) => waitForRedirectUrl(signal, timeoutMs, interactive),
450
+ },
451
+ });
452
+ }
453
+ catch (signInError) {
454
+ error(signInError instanceof McpSignInCancelledError
455
+ ? `Sign-in to MCP server "${name}" was cancelled or not completed within ${Math.round(timeoutMs / 1000)} seconds.`
456
+ : `Sign-in to MCP server "${name}" failed: ${errorMessage(signInError)}`);
457
+ return 1;
458
+ }
459
+ connection.challenge = undefined;
460
+ try {
461
+ await connection.reconnect();
462
+ }
463
+ catch (connectError) {
464
+ error(`Signed in, but ${errorMessage(connectError)}`);
465
+ return 1;
466
+ }
467
+ log(`Signed in to MCP server "${name}" (${connection.tools.length} tools).`);
468
+ return 0;
469
+ }
470
+ /**
471
+ * The pasted redirect URL in a terminal; otherwise only the browser callback can finish the sign-in.
472
+ * Resolves to undefined (cancelling the sign-in) after `timeoutMs`, or when the callback arrived.
473
+ */
474
+ async function waitForRedirectUrl(signal, timeoutMs, interactive) {
475
+ const controller = new AbortController();
476
+ const abort = () => controller.abort();
477
+ signal.addEventListener("abort", abort, { once: true });
478
+ const timer = setTimeout(abort, timeoutMs);
479
+ try {
480
+ if (!interactive) {
481
+ await new Promise((resolve) => controller.signal.addEventListener("abort", () => resolve(), { once: true }));
482
+ return undefined;
483
+ }
484
+ const readline = createInterface({ input: process.stdin, output: process.stderr });
485
+ try {
486
+ return await readline.question("If the browser cannot reach this machine, paste the URL it was redirected to: ", { signal: controller.signal });
487
+ }
488
+ catch {
489
+ return undefined;
490
+ }
491
+ finally {
492
+ readline.close();
493
+ }
494
+ }
495
+ finally {
496
+ clearTimeout(timer);
497
+ signal.removeEventListener("abort", abort);
498
+ }
499
+ }
500
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../../../src/extensions/mcp/cli.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `pi mcp`: add, remove, and check MCP servers and sign in to them outside a session. Agents run it\n * through bash to configure servers, verify an `mcp.json` they wrote, and start an OAuth sign-in;\n * the user only approves access in the browser. Running sessions pick up new credentials on their\n * next turn.\n */\n\nimport { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { createInterface } from \"node:readline/promises\";\nimport chalk from \"chalk\";\nimport { APP_NAME, CONFIG_DIR_NAME } from \"../../config.js\";\nimport { validateMcpServerConfig } from \"../../core/mcp-servers.ts\";\nimport { ProjectTrustStore } from \"../../core/trust-manager.ts\";\nimport { openBrowser } from \"../../utils/open-browser.ts\";\nimport {\n\taddMcpServerConfig,\n\tgetMcpToolExposure,\n\ttype LoadedMcpConfig,\n\tloadMcpConfig,\n\ttype McpServerEntry,\n\tremoveMcpServerConfig,\n} from \"./config.ts\";\nimport {\n\tcreateDefaultTransport,\n\tMcpOAuthCredentialStore,\n\tMcpServerConnection,\n\tMcpServerLog,\n\tMcpSignInCancelledError,\n\tsignInMcpServer,\n} from \"./runtime.ts\";\n\nconst HELP = `${chalk.bold(\"Usage:\")}\n ${APP_NAME} mcp add <server> [options] -- <command> [args...]\n ${APP_NAME} mcp add <server> [options] --url <url>\n ${APP_NAME} mcp remove <server> [-l]\n ${APP_NAME} mcp list [--json]\n ${APP_NAME} mcp login <server> [--timeout <seconds>]\n ${APP_NAME} mcp logout <server>\n\nConfigure and check MCP servers and sign in to OAuth servers without starting a session.\nReads ~/${CONFIG_DIR_NAME}/agent/mcp.json and, in trusted projects, ${CONFIG_DIR_NAME}/mcp.json.\n\nCommands:\n add <server> Add or replace a server in mcp.json\n remove <server> Remove a server from mcp.json\n list Show state, tools, and errors (exits 1 on failure)\n login <server> Sign in through the browser\n logout <server> Delete the stored OAuth credentials\n\nOptions for add and remove:\n -l, --local Use ${CONFIG_DIR_NAME}/mcp.json in the current project instead of the global file\n\nOptions for add:\n --url <url> Streamable HTTP server URL (instead of a command)\n --env <KEY=VALUE> Environment variable for a stdio server (repeatable)\n --cwd <dir> Working directory for a stdio server\n --header <KEY=VALUE> HTTP header (repeatable)\n --bearer-token-env-var <NAME>\n Send \"Authorization: Bearer \\${NAME}\"\n --oauth-client-id <id> Pre-registered OAuth client id\n --oauth-client-secret <secret>\n OAuth client secret (may be \\${NAME} or !command)\n --oauth-callback-port <port>\n Fixed OAuth callback port\n --oauth-client-name <name>\n Client name sent when registering with the OAuth server\n --exposure <mode> codemode (default), deferred, direct, or hidden\n --description <text> What the server offers, shown in the system prompt\n\nOther options:\n --json Print the list as JSON\n --timeout <seconds> How long login waits for the browser (default: 300)`;\n\nconst HELP_HINT = chalk.dim(`Use \"${APP_NAME} mcp --help\" for usage.`);\n\nconst DEFAULT_LOGIN_TIMEOUT_SECONDS = 300;\n\nexport interface McpCommandOptions {\n\tcwd: string;\n\tagentDir: string;\n\t/** Defaults to `mcp-auth.json` in the agent directory. */\n\tcredentials?: McpOAuthCredentialStore;\n\t/** Defaults to the platform browser. */\n\topenUrl?: (url: string) => void;\n\t/** Defaults to console output. */\n\tlog?: (line: string) => void;\n\terror?: (line: string) => void;\n}\n\ninterface ServerReport {\n\tname: string;\n\tscope: string;\n\tsource: string;\n\tenabled: boolean;\n\texposure: string;\n\ttransport: string;\n\tstate: string;\n\ttools: string[];\n\t/** Tools whose exposure differs from the server's, from `toolExposure`. */\n\ttoolExposure?: Record<string, string>;\n\tresources?: number;\n\tresourceTemplates?: number;\n\terror?: string;\n}\n\nfunction errorMessage(error: unknown): string {\n\treturn error instanceof Error ? error.message : String(error);\n}\n\nfunction describeTransport(entry: McpServerEntry): string {\n\tconst { config } = entry;\n\treturn \"url\" in config ? config.url : [config.command, ...(config.args ?? [])].join(\" \");\n}\n\nfunction createConnection(entry: McpServerEntry, options: McpCommandOptions, credentials: McpOAuthCredentialStore) {\n\treturn new McpServerConnection({\n\t\tentry,\n\t\tcwd: options.cwd,\n\t\tcreateTransport: createDefaultTransport,\n\t\tcredentials,\n\t\tlog: new McpServerLog(join(options.agentDir, \"mcp.log\")),\n\t\tonTools: () => {},\n\t});\n}\n\n/** Short spellings of options. `-l`/`--local` match `pi install`. */\nconst OPTION_ALIASES = new Map([[\"-l\", \"--local\"]]);\n\ninterface ParsedOptions {\n\tpositional: string[];\n\tvalues: Map<string, string | true>;\n\t/** Values of `list` options, in order. */\n\tlists: Map<string, string[]>;\n}\n\n/**\n * Parse `--name value` options; returns undefined and reports unknown ones. `--` ends the options,\n * as does reaching `maxPositionals` positional arguments: the remaining arguments are positional,\n * so a command's own options (`add <server> <command> --flag`) are passed through.\n */\nfunction parseOptions(\n\targs: string[],\n\tknown: Record<string, \"flag\" | \"value\" | \"list\">,\n\terror: (line: string) => void,\n\tmaxPositionals = Number.POSITIVE_INFINITY,\n): ParsedOptions | undefined {\n\tconst positional: string[] = [];\n\tconst values = new Map<string, string | true>();\n\tconst lists = new Map<string, string[]>();\n\tfor (let index = 0; index < args.length; index++) {\n\t\tconst arg = OPTION_ALIASES.get(args[index]) ?? args[index];\n\t\tif (arg === \"--\" || positional.length >= maxPositionals) {\n\t\t\tpositional.push(...args.slice(arg === \"--\" ? index + 1 : index));\n\t\t\tbreak;\n\t\t}\n\t\tif (!arg.startsWith(\"--\")) {\n\t\t\tpositional.push(arg);\n\t\t\tcontinue;\n\t\t}\n\t\tconst name = arg.slice(2);\n\t\tconst kind = known[name];\n\t\tif (!kind) {\n\t\t\terror(`Unknown option ${arg}.\\n${HELP_HINT}`);\n\t\t\treturn undefined;\n\t\t}\n\t\tif (kind === \"flag\") {\n\t\t\tvalues.set(name, true);\n\t\t\tcontinue;\n\t\t}\n\t\tconst value = args[++index];\n\t\tif (value === undefined) {\n\t\t\terror(`${arg} needs a value.`);\n\t\t\treturn undefined;\n\t\t}\n\t\tif (kind === \"list\") lists.set(name, [...(lists.get(name) ?? []), value]);\n\t\telse values.set(name, value);\n\t}\n\treturn { positional, values, lists };\n}\n\n/** Run `pi mcp <args>` and return the exit code. */\nexport async function runMcpCommand(args: string[], options: McpCommandOptions): Promise<number> {\n\tconst log = options.log ?? ((line: string) => console.log(line));\n\tconst error = options.error ?? ((line: string) => console.error(line));\n\tconst [command, ...rest] = args;\n\tif (command === undefined || command === \"help\" || args.includes(\"--help\") || args.includes(\"-h\")) {\n\t\tlog(HELP);\n\t\treturn 0;\n\t}\n\n\tconst projectConfig = join(options.cwd, CONFIG_DIR_NAME, \"mcp.json\");\n\tif (command === \"add\" || command === \"remove\") {\n\t\treturn command === \"add\"\n\t\t\t? add(rest, projectConfig, options, log, error)\n\t\t\t: remove(rest, projectConfig, options, log, error);\n\t}\n\tconst projectTrusted = new ProjectTrustStore(options.agentDir).get(options.cwd) === true;\n\tconst loaded = loadMcpConfig({ agentDir: options.agentDir, cwd: options.cwd, projectTrusted });\n\tconst untrustedNote =\n\t\t!projectTrusted && existsSync(projectConfig)\n\t\t\t? `${projectConfig} is ignored because the project is not trusted. Start ${APP_NAME} in the project to trust it.`\n\t\t\t: undefined;\n\tconst credentials = options.credentials ?? new McpOAuthCredentialStore();\n\n\tswitch (command) {\n\t\tcase \"list\": {\n\t\t\tconst parsed = parseOptions(rest, { json: \"flag\" }, error);\n\t\t\tif (!parsed) return 1;\n\t\t\tif (parsed.positional.length > 0) {\n\t\t\t\terror(`Usage: ${APP_NAME} mcp list [--json]\\n${HELP_HINT}`);\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t\treturn list(loaded, parsed.values.has(\"json\"), untrustedNote, options, credentials, log);\n\t\t}\n\t\tcase \"login\":\n\t\tcase \"logout\": {\n\t\t\tconst parsed = parseOptions(rest, command === \"login\" ? { timeout: \"value\" } : {}, error);\n\t\t\tif (!parsed) return 1;\n\t\t\tconst [name, ...extra] = parsed.positional;\n\t\t\tif (!name || extra.length > 0) {\n\t\t\t\terror(`Usage: ${APP_NAME} mcp ${command} <server>\\n${HELP_HINT}`);\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t\tconst entry = loaded.servers.find((server) => server.name === name);\n\t\t\tif (!entry) {\n\t\t\t\terror(\n\t\t\t\t\t`No MCP server named \"${name}\".${untrustedNote ? ` ${untrustedNote}` : \"\"} Configured: ${loaded.servers.map((server) => server.name).join(\", \") || \"none\"}.`,\n\t\t\t\t);\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t\tconst connection = createConnection(entry, options, credentials);\n\t\t\tconst url = connection.oauthUrl;\n\t\t\tif (!url) {\n\t\t\t\terror(`MCP server \"${name}\" does not use OAuth. Only HTTP servers without an Authorization header do.`);\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t\tif (command === \"logout\") {\n\t\t\t\tconst removed = await credentials.removeAsync(url);\n\t\t\t\tlog(removed ? `Signed out of MCP server \"${name}\".` : `No stored credentials for MCP server \"${name}\".`);\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\tconst timeout = Number(parsed.values.get(\"timeout\") ?? DEFAULT_LOGIN_TIMEOUT_SECONDS);\n\t\t\tif (!Number.isFinite(timeout) || timeout <= 0) {\n\t\t\t\terror(\"--timeout must be a positive number of seconds.\");\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t\ttry {\n\t\t\t\treturn await login(entry, connection, url, timeout * 1000, options, credentials, log, error);\n\t\t\t} finally {\n\t\t\t\tawait connection.close();\n\t\t\t}\n\t\t}\n\t\tdefault:\n\t\t\terror(`Unknown mcp command \"${command}\".\\n${HELP_HINT}`);\n\t\t\treturn 1;\n\t}\n}\n\n/** Parse `KEY=VALUE` pairs of a repeatable option into a record. */\nfunction parsePairs(option: string, pairs: string[] | undefined, error: (line: string) => void) {\n\tif (!pairs) return {};\n\tconst record: Record<string, string> = {};\n\tfor (const pair of pairs) {\n\t\tconst separator = pair.indexOf(\"=\");\n\t\tif (separator <= 0) {\n\t\t\terror(`--${option} expects KEY=VALUE, got \"${pair}\".`);\n\t\t\treturn undefined;\n\t\t}\n\t\trecord[pair.slice(0, separator)] = pair.slice(separator + 1);\n\t}\n\treturn record;\n}\n\nfunction add(\n\targs: string[],\n\tprojectConfig: string,\n\toptions: McpCommandOptions,\n\tlog: (line: string) => void,\n\terror: (line: string) => void,\n): number {\n\tconst usage = `Usage: ${APP_NAME} mcp add <server> [options] (--url <url> | -- <command> [args...])\\n${HELP_HINT}`;\n\tconst parsed = parseOptions(\n\t\targs,\n\t\t{\n\t\t\tlocal: \"flag\",\n\t\t\turl: \"value\",\n\t\t\tenv: \"list\",\n\t\t\tcwd: \"value\",\n\t\t\theader: \"list\",\n\t\t\t\"bearer-token-env-var\": \"value\",\n\t\t\t\"oauth-client-id\": \"value\",\n\t\t\t\"oauth-client-secret\": \"value\",\n\t\t\t\"oauth-callback-port\": \"value\",\n\t\t\t\"oauth-client-name\": \"value\",\n\t\t\texposure: \"value\",\n\t\t\tdescription: \"value\",\n\t\t},\n\t\terror,\n\t\t2,\n\t);\n\tif (!parsed) return 1;\n\tconst { positional, values, lists } = parsed;\n\tconst [name, ...command] = positional;\n\tconst url = values.get(\"url\");\n\tif (!name || (url === undefined) === (command.length === 0)) {\n\t\terror(usage);\n\t\treturn 1;\n\t}\n\tconst value = (option: string) => {\n\t\tconst found = values.get(option);\n\t\treturn typeof found === \"string\" ? found : undefined;\n\t};\n\tconst exposure = value(\"exposure\");\n\tconst httpOnly = [\n\t\t\"header\",\n\t\t\"bearer-token-env-var\",\n\t\t\"oauth-client-id\",\n\t\t\"oauth-client-secret\",\n\t\t\"oauth-callback-port\",\n\t\t\"oauth-client-name\",\n\t];\n\tconst stdioOnly = [\"env\", \"cwd\"];\n\tconst misplaced = (url === undefined ? httpOnly : stdioOnly).find(\n\t\t(option) => values.has(option) || lists.has(option),\n\t);\n\tif (misplaced) {\n\t\terror(`--${misplaced} only applies to ${url === undefined ? \"HTTP servers (--url)\" : \"stdio servers\"}.`);\n\t\treturn 1;\n\t}\n\n\tlet config: Record<string, unknown>;\n\tif (typeof url === \"string\") {\n\t\tconst headers = parsePairs(\"header\", lists.get(\"header\"), error);\n\t\tif (!headers) return 1;\n\t\tconst bearer = value(\"bearer-token-env-var\");\n\t\tif (bearer !== undefined) headers.Authorization = `Bearer \\${${bearer}}`;\n\t\tconst port = value(\"oauth-callback-port\");\n\t\tconst oauth = {\n\t\t\t...(value(\"oauth-client-id\") === undefined ? {} : { clientId: value(\"oauth-client-id\") }),\n\t\t\t...(value(\"oauth-client-secret\") === undefined ? {} : { clientSecret: value(\"oauth-client-secret\") }),\n\t\t\t...(port === undefined ? {} : { callbackPort: Number(port) }),\n\t\t\t...(value(\"oauth-client-name\") === undefined ? {} : { clientName: value(\"oauth-client-name\") }),\n\t\t};\n\t\tconfig = {\n\t\t\turl,\n\t\t\t...(Object.keys(headers).length > 0 ? { headers } : {}),\n\t\t\t...(Object.keys(oauth).length > 0 ? { oauth } : {}),\n\t\t};\n\t} else {\n\t\tconst env = parsePairs(\"env\", lists.get(\"env\"), error);\n\t\tif (!env) return 1;\n\t\tconst [executable, ...commandArgs] = command;\n\t\tconfig = {\n\t\t\tcommand: executable,\n\t\t\t...(commandArgs.length > 0 ? { args: commandArgs } : {}),\n\t\t\t...(Object.keys(env).length > 0 ? { env } : {}),\n\t\t\t...(value(\"cwd\") === undefined ? {} : { cwd: value(\"cwd\") }),\n\t\t};\n\t}\n\tif (exposure !== undefined) config.exposure = exposure;\n\tconst description = value(\"description\");\n\tif (description !== undefined) config.description = description;\n\tconst validated = validateMcpServerConfig(name, config);\n\tif (typeof validated === \"string\") {\n\t\terror(validated);\n\t\treturn 1;\n\t}\n\n\tconst project = values.has(\"local\");\n\tconst path = project ? projectConfig : join(options.agentDir, \"mcp.json\");\n\tconst scope = project ? \"project\" : \"global\";\n\tlet replaced: boolean;\n\ttry {\n\t\treplaced = addMcpServerConfig(path, name, validated);\n\t} catch (addError) {\n\t\terror(`Could not update ${path}: ${errorMessage(addError)}`);\n\t\treturn 1;\n\t}\n\tlog(`${replaced ? \"Replaced\" : \"Added\"} ${scope} MCP server \"${name}\" in ${path}.`);\n\tif (project && new ProjectTrustStore(options.agentDir).get(options.cwd) !== true) {\n\t\tlog(`The project is not trusted, so ${path} is ignored until you start ${APP_NAME} in the project and trust it.`);\n\t}\n\t// HTTP servers without an Authorization header may use OAuth.\n\tconst mayNeedSignIn =\n\t\t\"url\" in validated &&\n\t\t!Object.keys(validated.headers ?? {}).some((header) => header.toLowerCase() === \"authorization\");\n\tlog(\n\t\t`Check it with: ${APP_NAME} mcp list${mayNeedSignIn ? `. If it requires sign-in: ${APP_NAME} mcp login ${name}` : \"\"}`,\n\t);\n\treturn 0;\n}\n\nfunction remove(\n\targs: string[],\n\tprojectConfig: string,\n\toptions: McpCommandOptions,\n\tlog: (line: string) => void,\n\terror: (line: string) => void,\n): number {\n\tconst parsed = parseOptions(args, { local: \"flag\" }, error);\n\tif (!parsed) return 1;\n\tconst [name, ...extra] = parsed.positional;\n\tif (!name || extra.length > 0) {\n\t\terror(`Usage: ${APP_NAME} mcp remove <server> [-l]\\n${HELP_HINT}`);\n\t\treturn 1;\n\t}\n\tconst project = parsed.values.has(\"local\");\n\tconst globalConfig = join(options.agentDir, \"mcp.json\");\n\tconst path = project ? projectConfig : globalConfig;\n\tconst scope = project ? \"project\" : \"global\";\n\tlet removed: boolean;\n\ttry {\n\t\tremoved = removeMcpServerConfig(path, name);\n\t} catch (removeError) {\n\t\terror(`Could not update ${path}: ${errorMessage(removeError)}`);\n\t\treturn 1;\n\t}\n\tif (removed) {\n\t\tlog(`Removed ${scope} MCP server \"${name}\" from ${path}.`);\n\t\treturn 0;\n\t}\n\tconst other = loadMcpConfig({ agentDir: options.agentDir, cwd: options.cwd, projectTrusted: true }).servers.find(\n\t\t(server) => server.name === name && server.scope !== scope,\n\t);\n\terror(\n\t\t`No ${scope} MCP server named \"${name}\" in ${path}.${other ? ` It is defined in ${other.source}${other.scope === \"project\" ? \"; use --local\" : \"; omit --local\"}.` : \"\"}`,\n\t);\n\treturn 1;\n}\n\nasync function list(\n\tloaded: LoadedMcpConfig,\n\tjson: boolean,\n\tuntrustedNote: string | undefined,\n\toptions: McpCommandOptions,\n\tcredentials: McpOAuthCredentialStore,\n\tlog: (line: string) => void,\n): Promise<number> {\n\tconst reports = await Promise.all(\n\t\tloaded.servers.map(async (entry): Promise<ServerReport> => {\n\t\t\tconst report: ServerReport = {\n\t\t\t\tname: entry.name,\n\t\t\t\tscope: entry.scope ?? \"global\",\n\t\t\t\tsource: entry.source,\n\t\t\t\tenabled: entry.config.enabled !== false,\n\t\t\t\texposure: entry.config.exposure ?? \"codemode\",\n\t\t\t\ttransport: describeTransport(entry),\n\t\t\t\tstate: \"disabled\",\n\t\t\t\ttools: [],\n\t\t\t};\n\t\t\tif (!report.enabled) return report;\n\t\t\tconst connection = createConnection(entry, options, credentials);\n\t\t\ttry {\n\t\t\t\tawait connection.getClient();\n\t\t\t} catch {\n\t\t\t\t// The connection records the state and error.\n\t\t\t}\n\t\t\treport.state = connection.state;\n\t\t\treport.tools = connection.tools.map((tool) => tool.name);\n\t\t\tconst overrides = connection.tools.flatMap((tool) => {\n\t\t\t\tconst exposure = getMcpToolExposure(entry.config, tool.name);\n\t\t\t\treturn exposure === report.exposure ? [] : [[tool.name, exposure] as const];\n\t\t\t});\n\t\t\tif (overrides.length > 0) report.toolExposure = Object.fromEntries(overrides);\n\t\t\tif (connection.hasResources) {\n\t\t\t\treport.resources = connection.resources.length;\n\t\t\t\treport.resourceTemplates = connection.resourceTemplates.length;\n\t\t\t}\n\t\t\tif (connection.state !== \"connected\" && connection.error) report.error = connection.error;\n\t\t\tawait connection.close();\n\t\t\treturn report;\n\t\t}),\n\t);\n\tconst failed = loaded.errors.length > 0 || reports.some((report) => report.enabled && report.state !== \"connected\");\n\n\tif (json) {\n\t\tlog(\n\t\t\tJSON.stringify(\n\t\t\t\t{ servers: reports, errors: loaded.errors, ...(untrustedNote ? { note: untrustedNote } : {}) },\n\t\t\t\tnull,\n\t\t\t\t2,\n\t\t\t),\n\t\t);\n\t\treturn failed ? 1 : 0;\n\t}\n\tif (reports.length === 0 && loaded.errors.length === 0) {\n\t\tlog(`No MCP servers configured. Add them to ${join(options.agentDir, \"mcp.json\")} or .pi/mcp.json.`);\n\t}\n\tfor (const report of reports) {\n\t\tconst state =\n\t\t\treport.state === \"connected\"\n\t\t\t\t? `connected, ${report.tools.length} tool${report.tools.length === 1 ? \"\" : \"s\"}`\n\t\t\t\t: report.state === \"needs-auth\"\n\t\t\t\t\t? \"needs sign-in\"\n\t\t\t\t\t: report.state;\n\t\tlog(`${report.name}: ${state} (${report.exposure}, ${report.scope})`);\n\t\tlog(` ${report.transport}`);\n\t\tif (report.state === \"needs-auth\") log(` sign in with: ${APP_NAME} mcp login ${report.name}`);\n\t\tif (report.tools.length > 0) {\n\t\t\tconst tools = report.tools.map((tool) => {\n\t\t\t\tconst exposure = report.toolExposure?.[tool];\n\t\t\t\treturn exposure ? `${tool} [${exposure}]` : tool;\n\t\t\t});\n\t\t\tlog(` tools: ${tools.join(\", \")}`);\n\t\t}\n\t\tif (report.resources !== undefined) {\n\t\t\tlog(` resources: ${report.resources}, URI templates: ${report.resourceTemplates ?? 0}`);\n\t\t}\n\t\tif (report.error) log(` ${report.error.split(\"\\n\").join(\"\\n \")}`);\n\t}\n\tfor (const configError of loaded.errors) log(`config error: ${configError}`);\n\tif (untrustedNote) log(untrustedNote);\n\treturn failed ? 1 : 0;\n}\n\nasync function login(\n\tentry: McpServerEntry,\n\tconnection: McpServerConnection,\n\turl: string,\n\ttimeoutMs: number,\n\toptions: McpCommandOptions,\n\tcredentials: McpOAuthCredentialStore,\n\tlog: (line: string) => void,\n\terror: (line: string) => void,\n): Promise<number> {\n\tconst { name } = entry;\n\t// Connecting first answers whether a sign-in is needed and records the server's challenge.\n\ttry {\n\t\tawait connection.getClient();\n\t\tlog(`Already signed in to MCP server \"${name}\" (${connection.tools.length} tools).`);\n\t\treturn 0;\n\t} catch {\n\t\tif (connection.state !== \"needs-auth\") {\n\t\t\terror(`MCP server \"${name}\" failed to connect: ${connection.error ?? \"unknown error\"}`);\n\t\t\treturn 1;\n\t\t}\n\t}\n\n\tconst openUrl = options.openUrl ?? openBrowser;\n\tconst interactive = process.stdin.isTTY === true && options.openUrl === undefined;\n\ttry {\n\t\tawait signInMcpServer({\n\t\t\tserverUrl: url,\n\t\t\tstore: credentials.forServer(url),\n\t\t\tsettings: connection.oauthSettings(),\n\t\t\tchallenge: connection.challenge,\n\t\t\tprompt: {\n\t\t\t\tshowAuthorizationUrl: (authorizationUrl) => {\n\t\t\t\t\tlog(`Sign in to MCP server \"${name}\" in your browser:\\n${authorizationUrl.href}`);\n\t\t\t\t\topenUrl(authorizationUrl.href);\n\t\t\t\t},\n\t\t\t\tpromptForRedirectUrl: (signal) => waitForRedirectUrl(signal, timeoutMs, interactive),\n\t\t\t},\n\t\t});\n\t} catch (signInError) {\n\t\terror(\n\t\t\tsignInError instanceof McpSignInCancelledError\n\t\t\t\t? `Sign-in to MCP server \"${name}\" was cancelled or not completed within ${Math.round(timeoutMs / 1000)} seconds.`\n\t\t\t\t: `Sign-in to MCP server \"${name}\" failed: ${errorMessage(signInError)}`,\n\t\t);\n\t\treturn 1;\n\t}\n\tconnection.challenge = undefined;\n\ttry {\n\t\tawait connection.reconnect();\n\t} catch (connectError) {\n\t\terror(`Signed in, but ${errorMessage(connectError)}`);\n\t\treturn 1;\n\t}\n\tlog(`Signed in to MCP server \"${name}\" (${connection.tools.length} tools).`);\n\treturn 0;\n}\n\n/**\n * The pasted redirect URL in a terminal; otherwise only the browser callback can finish the sign-in.\n * Resolves to undefined (cancelling the sign-in) after `timeoutMs`, or when the callback arrived.\n */\nasync function waitForRedirectUrl(\n\tsignal: AbortSignal,\n\ttimeoutMs: number,\n\tinteractive: boolean,\n): Promise<string | undefined> {\n\tconst controller = new AbortController();\n\tconst abort = () => controller.abort();\n\tsignal.addEventListener(\"abort\", abort, { once: true });\n\tconst timer = setTimeout(abort, timeoutMs);\n\ttry {\n\t\tif (!interactive) {\n\t\t\tawait new Promise<void>((resolve) =>\n\t\t\t\tcontroller.signal.addEventListener(\"abort\", () => resolve(), { once: true }),\n\t\t\t);\n\t\t\treturn undefined;\n\t\t}\n\t\tconst readline = createInterface({ input: process.stdin, output: process.stderr });\n\t\ttry {\n\t\t\treturn await readline.question(\n\t\t\t\t\"If the browser cannot reach this machine, paste the URL it was redirected to: \",\n\t\t\t\t{ signal: controller.signal },\n\t\t\t);\n\t\t} catch {\n\t\t\treturn undefined;\n\t\t} finally {\n\t\t\treadline.close();\n\t\t}\n\t} finally {\n\t\tclearTimeout(timer);\n\t\tsignal.removeEventListener(\"abort\", abort);\n\t}\n}\n"]}
@@ -0,0 +1,3 @@
1
+ /** Loads `pi mcp` and the MCP runtime only when the command runs (see cli.ts). */
2
+ export declare const loadMcpCommand: () => Promise<typeof import("./cli.ts")>;
3
+ //# sourceMappingURL=cli.lazy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.lazy.d.ts","sourceRoot":"","sources":["../../../src/extensions/mcp/cli.lazy.ts"],"names":[],"mappings":"AAAA,kFAAkF;AAClF,eAAO,MAAM,cAAc,0CAA2B,CAAC"}
@@ -0,0 +1,3 @@
1
+ /** Loads `pi mcp` and the MCP runtime only when the command runs (see cli.ts). */
2
+ export const loadMcpCommand = () => import("./cli.js");
3
+ //# sourceMappingURL=cli.lazy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.lazy.js","sourceRoot":"","sources":["../../../src/extensions/mcp/cli.lazy.ts"],"names":[],"mappings":"AAAA,kFAAkF;AAClF,MAAM,CAAC,MAAM,cAAc,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC","sourcesContent":["/** Loads `pi mcp` and the MCP runtime only when the command runs (see cli.ts). */\nexport const loadMcpCommand = () => import(\"./cli.ts\");\n"]}
@@ -0,0 +1,15 @@
1
+ export type McpFetch = (input: string | URL, init?: RequestInit) => Promise<Response>;
2
+ export interface UnauthorizedContext {
3
+ /** The 401 response, or a 403 response whose challenge reports `insufficient_scope`. */
4
+ response: Response;
5
+ serverUrl: URL;
6
+ fetch: McpFetch;
7
+ /** Access token the rejected request carried, if any. A different current token means another request already refreshed it. */
8
+ token?: string;
9
+ }
10
+ /** Supplies bearer tokens to an MCP HTTP transport and may refresh them after a 401 response. */
11
+ export interface AuthProvider {
12
+ token(): Promise<string | undefined>;
13
+ onUnauthorized?(context: UnauthorizedContext): Promise<void>;
14
+ }
15
+ //# sourceMappingURL=auth-provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-provider.d.ts","sourceRoot":"","sources":["../../../../src/extensions/mcp/client/auth-provider.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,QAAQ,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,GAAG,EAAE,IAAI,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;AAEtF,MAAM,WAAW,mBAAmB;IACnC,wFAAwF;IACxF,QAAQ,EAAE,QAAQ,CAAC;IACnB,SAAS,EAAE,GAAG,CAAC;IACf,KAAK,EAAE,QAAQ,CAAC;IAChB,+HAA+H;IAC/H,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAED,iGAAiG;AACjG,MAAM,WAAW,YAAY;IAC5B,KAAK,IAAI,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IACrC,cAAc,CAAC,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC7D"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=auth-provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-provider.js","sourceRoot":"","sources":["../../../../src/extensions/mcp/client/auth-provider.ts"],"names":[],"mappings":"","sourcesContent":["export type McpFetch = (input: string | URL, init?: RequestInit) => Promise<Response>;\n\nexport interface UnauthorizedContext {\n\t/** The 401 response, or a 403 response whose challenge reports `insufficient_scope`. */\n\tresponse: Response;\n\tserverUrl: URL;\n\tfetch: McpFetch;\n\t/** Access token the rejected request carried, if any. A different current token means another request already refreshed it. */\n\ttoken?: string;\n}\n\n/** Supplies bearer tokens to an MCP HTTP transport and may refresh them after a 401 response. */\nexport interface AuthProvider {\n\ttoken(): Promise<string | undefined>;\n\tonUnauthorized?(context: UnauthorizedContext): Promise<void>;\n}\n"]}