@oh-my-pi/pi-coding-agent 1.337.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (224) hide show
  1. package/CHANGELOG.md +1228 -0
  2. package/README.md +1041 -0
  3. package/docs/compaction.md +403 -0
  4. package/docs/custom-tools.md +541 -0
  5. package/docs/extension-loading.md +1004 -0
  6. package/docs/hooks.md +867 -0
  7. package/docs/rpc.md +1040 -0
  8. package/docs/sdk.md +994 -0
  9. package/docs/session-tree-plan.md +441 -0
  10. package/docs/session.md +240 -0
  11. package/docs/skills.md +290 -0
  12. package/docs/theme.md +637 -0
  13. package/docs/tree.md +197 -0
  14. package/docs/tui.md +341 -0
  15. package/examples/README.md +21 -0
  16. package/examples/custom-tools/README.md +124 -0
  17. package/examples/custom-tools/hello/index.ts +20 -0
  18. package/examples/custom-tools/question/index.ts +84 -0
  19. package/examples/custom-tools/subagent/README.md +172 -0
  20. package/examples/custom-tools/subagent/agents/planner.md +37 -0
  21. package/examples/custom-tools/subagent/agents/reviewer.md +35 -0
  22. package/examples/custom-tools/subagent/agents/scout.md +50 -0
  23. package/examples/custom-tools/subagent/agents/worker.md +24 -0
  24. package/examples/custom-tools/subagent/agents.ts +156 -0
  25. package/examples/custom-tools/subagent/commands/implement-and-review.md +10 -0
  26. package/examples/custom-tools/subagent/commands/implement.md +10 -0
  27. package/examples/custom-tools/subagent/commands/scout-and-plan.md +9 -0
  28. package/examples/custom-tools/subagent/index.ts +1002 -0
  29. package/examples/custom-tools/todo/index.ts +212 -0
  30. package/examples/hooks/README.md +56 -0
  31. package/examples/hooks/auto-commit-on-exit.ts +49 -0
  32. package/examples/hooks/confirm-destructive.ts +59 -0
  33. package/examples/hooks/custom-compaction.ts +116 -0
  34. package/examples/hooks/dirty-repo-guard.ts +52 -0
  35. package/examples/hooks/file-trigger.ts +41 -0
  36. package/examples/hooks/git-checkpoint.ts +53 -0
  37. package/examples/hooks/handoff.ts +150 -0
  38. package/examples/hooks/permission-gate.ts +34 -0
  39. package/examples/hooks/protected-paths.ts +30 -0
  40. package/examples/hooks/qna.ts +119 -0
  41. package/examples/hooks/snake.ts +343 -0
  42. package/examples/hooks/status-line.ts +40 -0
  43. package/examples/sdk/01-minimal.ts +22 -0
  44. package/examples/sdk/02-custom-model.ts +49 -0
  45. package/examples/sdk/03-custom-prompt.ts +44 -0
  46. package/examples/sdk/04-skills.ts +44 -0
  47. package/examples/sdk/05-tools.ts +90 -0
  48. package/examples/sdk/06-hooks.ts +61 -0
  49. package/examples/sdk/07-context-files.ts +36 -0
  50. package/examples/sdk/08-slash-commands.ts +42 -0
  51. package/examples/sdk/09-api-keys-and-oauth.ts +55 -0
  52. package/examples/sdk/10-settings.ts +38 -0
  53. package/examples/sdk/11-sessions.ts +48 -0
  54. package/examples/sdk/12-full-control.ts +95 -0
  55. package/examples/sdk/README.md +154 -0
  56. package/package.json +81 -0
  57. package/src/cli/args.ts +246 -0
  58. package/src/cli/file-processor.ts +72 -0
  59. package/src/cli/list-models.ts +104 -0
  60. package/src/cli/plugin-cli.ts +650 -0
  61. package/src/cli/session-picker.ts +41 -0
  62. package/src/cli.ts +10 -0
  63. package/src/commands/init.md +20 -0
  64. package/src/config.ts +159 -0
  65. package/src/core/agent-session.ts +1900 -0
  66. package/src/core/auth-storage.ts +236 -0
  67. package/src/core/bash-executor.ts +196 -0
  68. package/src/core/compaction/branch-summarization.ts +343 -0
  69. package/src/core/compaction/compaction.ts +742 -0
  70. package/src/core/compaction/index.ts +7 -0
  71. package/src/core/compaction/utils.ts +154 -0
  72. package/src/core/custom-tools/index.ts +21 -0
  73. package/src/core/custom-tools/loader.ts +248 -0
  74. package/src/core/custom-tools/types.ts +169 -0
  75. package/src/core/custom-tools/wrapper.ts +28 -0
  76. package/src/core/exec.ts +129 -0
  77. package/src/core/export-html/index.ts +211 -0
  78. package/src/core/export-html/template.css +781 -0
  79. package/src/core/export-html/template.html +54 -0
  80. package/src/core/export-html/template.js +1185 -0
  81. package/src/core/export-html/vendor/highlight.min.js +1213 -0
  82. package/src/core/export-html/vendor/marked.min.js +6 -0
  83. package/src/core/hooks/index.ts +16 -0
  84. package/src/core/hooks/loader.ts +312 -0
  85. package/src/core/hooks/runner.ts +434 -0
  86. package/src/core/hooks/tool-wrapper.ts +99 -0
  87. package/src/core/hooks/types.ts +773 -0
  88. package/src/core/index.ts +52 -0
  89. package/src/core/mcp/client.ts +158 -0
  90. package/src/core/mcp/config.ts +154 -0
  91. package/src/core/mcp/index.ts +45 -0
  92. package/src/core/mcp/loader.ts +68 -0
  93. package/src/core/mcp/manager.ts +181 -0
  94. package/src/core/mcp/tool-bridge.ts +148 -0
  95. package/src/core/mcp/transports/http.ts +316 -0
  96. package/src/core/mcp/transports/index.ts +6 -0
  97. package/src/core/mcp/transports/stdio.ts +252 -0
  98. package/src/core/mcp/types.ts +220 -0
  99. package/src/core/messages.ts +189 -0
  100. package/src/core/model-registry.ts +317 -0
  101. package/src/core/model-resolver.ts +393 -0
  102. package/src/core/plugins/doctor.ts +59 -0
  103. package/src/core/plugins/index.ts +38 -0
  104. package/src/core/plugins/installer.ts +189 -0
  105. package/src/core/plugins/loader.ts +338 -0
  106. package/src/core/plugins/manager.ts +672 -0
  107. package/src/core/plugins/parser.ts +105 -0
  108. package/src/core/plugins/paths.ts +32 -0
  109. package/src/core/plugins/types.ts +190 -0
  110. package/src/core/sdk.ts +760 -0
  111. package/src/core/session-manager.ts +1128 -0
  112. package/src/core/settings-manager.ts +443 -0
  113. package/src/core/skills.ts +437 -0
  114. package/src/core/slash-commands.ts +248 -0
  115. package/src/core/system-prompt.ts +439 -0
  116. package/src/core/timings.ts +25 -0
  117. package/src/core/tools/ask.ts +211 -0
  118. package/src/core/tools/bash-interceptor.ts +120 -0
  119. package/src/core/tools/bash.ts +250 -0
  120. package/src/core/tools/context.ts +32 -0
  121. package/src/core/tools/edit-diff.ts +475 -0
  122. package/src/core/tools/edit.ts +208 -0
  123. package/src/core/tools/exa/company.ts +59 -0
  124. package/src/core/tools/exa/index.ts +64 -0
  125. package/src/core/tools/exa/linkedin.ts +59 -0
  126. package/src/core/tools/exa/logger.ts +56 -0
  127. package/src/core/tools/exa/mcp-client.ts +368 -0
  128. package/src/core/tools/exa/render.ts +196 -0
  129. package/src/core/tools/exa/researcher.ts +90 -0
  130. package/src/core/tools/exa/search.ts +337 -0
  131. package/src/core/tools/exa/types.ts +168 -0
  132. package/src/core/tools/exa/websets.ts +248 -0
  133. package/src/core/tools/find.ts +261 -0
  134. package/src/core/tools/grep.ts +555 -0
  135. package/src/core/tools/index.ts +202 -0
  136. package/src/core/tools/ls.ts +140 -0
  137. package/src/core/tools/lsp/client.ts +605 -0
  138. package/src/core/tools/lsp/config.ts +147 -0
  139. package/src/core/tools/lsp/edits.ts +101 -0
  140. package/src/core/tools/lsp/index.ts +804 -0
  141. package/src/core/tools/lsp/render.ts +447 -0
  142. package/src/core/tools/lsp/rust-analyzer.ts +145 -0
  143. package/src/core/tools/lsp/types.ts +463 -0
  144. package/src/core/tools/lsp/utils.ts +486 -0
  145. package/src/core/tools/notebook.ts +229 -0
  146. package/src/core/tools/path-utils.ts +61 -0
  147. package/src/core/tools/read.ts +240 -0
  148. package/src/core/tools/renderers.ts +540 -0
  149. package/src/core/tools/task/agents.ts +153 -0
  150. package/src/core/tools/task/artifacts.ts +114 -0
  151. package/src/core/tools/task/bundled-agents/browser.md +71 -0
  152. package/src/core/tools/task/bundled-agents/explore.md +82 -0
  153. package/src/core/tools/task/bundled-agents/plan.md +54 -0
  154. package/src/core/tools/task/bundled-agents/reviewer.md +59 -0
  155. package/src/core/tools/task/bundled-agents/task.md +53 -0
  156. package/src/core/tools/task/bundled-commands/architect-plan.md +10 -0
  157. package/src/core/tools/task/bundled-commands/implement-with-critic.md +11 -0
  158. package/src/core/tools/task/bundled-commands/implement.md +11 -0
  159. package/src/core/tools/task/commands.ts +213 -0
  160. package/src/core/tools/task/discovery.ts +208 -0
  161. package/src/core/tools/task/executor.ts +367 -0
  162. package/src/core/tools/task/index.ts +388 -0
  163. package/src/core/tools/task/model-resolver.ts +115 -0
  164. package/src/core/tools/task/parallel.ts +38 -0
  165. package/src/core/tools/task/render.ts +232 -0
  166. package/src/core/tools/task/types.ts +99 -0
  167. package/src/core/tools/truncate.ts +265 -0
  168. package/src/core/tools/web-fetch.ts +2370 -0
  169. package/src/core/tools/web-search/auth.ts +193 -0
  170. package/src/core/tools/web-search/index.ts +537 -0
  171. package/src/core/tools/web-search/providers/anthropic.ts +198 -0
  172. package/src/core/tools/web-search/providers/exa.ts +302 -0
  173. package/src/core/tools/web-search/providers/perplexity.ts +195 -0
  174. package/src/core/tools/web-search/render.ts +182 -0
  175. package/src/core/tools/web-search/types.ts +180 -0
  176. package/src/core/tools/write.ts +99 -0
  177. package/src/index.ts +176 -0
  178. package/src/main.ts +464 -0
  179. package/src/migrations.ts +135 -0
  180. package/src/modes/index.ts +43 -0
  181. package/src/modes/interactive/components/armin.ts +382 -0
  182. package/src/modes/interactive/components/assistant-message.ts +86 -0
  183. package/src/modes/interactive/components/bash-execution.ts +196 -0
  184. package/src/modes/interactive/components/bordered-loader.ts +41 -0
  185. package/src/modes/interactive/components/branch-summary-message.ts +42 -0
  186. package/src/modes/interactive/components/compaction-summary-message.ts +45 -0
  187. package/src/modes/interactive/components/custom-editor.ts +122 -0
  188. package/src/modes/interactive/components/diff.ts +147 -0
  189. package/src/modes/interactive/components/dynamic-border.ts +25 -0
  190. package/src/modes/interactive/components/footer.ts +381 -0
  191. package/src/modes/interactive/components/hook-editor.ts +117 -0
  192. package/src/modes/interactive/components/hook-input.ts +64 -0
  193. package/src/modes/interactive/components/hook-message.ts +96 -0
  194. package/src/modes/interactive/components/hook-selector.ts +91 -0
  195. package/src/modes/interactive/components/model-selector.ts +247 -0
  196. package/src/modes/interactive/components/oauth-selector.ts +120 -0
  197. package/src/modes/interactive/components/plugin-settings.ts +479 -0
  198. package/src/modes/interactive/components/queue-mode-selector.ts +56 -0
  199. package/src/modes/interactive/components/session-selector.ts +204 -0
  200. package/src/modes/interactive/components/settings-selector.ts +453 -0
  201. package/src/modes/interactive/components/show-images-selector.ts +45 -0
  202. package/src/modes/interactive/components/theme-selector.ts +62 -0
  203. package/src/modes/interactive/components/thinking-selector.ts +64 -0
  204. package/src/modes/interactive/components/tool-execution.ts +675 -0
  205. package/src/modes/interactive/components/tree-selector.ts +866 -0
  206. package/src/modes/interactive/components/user-message-selector.ts +159 -0
  207. package/src/modes/interactive/components/user-message.ts +18 -0
  208. package/src/modes/interactive/components/visual-truncate.ts +50 -0
  209. package/src/modes/interactive/components/welcome.ts +183 -0
  210. package/src/modes/interactive/interactive-mode.ts +2516 -0
  211. package/src/modes/interactive/theme/dark.json +101 -0
  212. package/src/modes/interactive/theme/light.json +98 -0
  213. package/src/modes/interactive/theme/theme-schema.json +308 -0
  214. package/src/modes/interactive/theme/theme.ts +998 -0
  215. package/src/modes/print-mode.ts +128 -0
  216. package/src/modes/rpc/rpc-client.ts +527 -0
  217. package/src/modes/rpc/rpc-mode.ts +483 -0
  218. package/src/modes/rpc/rpc-types.ts +203 -0
  219. package/src/utils/changelog.ts +99 -0
  220. package/src/utils/clipboard.ts +265 -0
  221. package/src/utils/fuzzy.ts +108 -0
  222. package/src/utils/mime.ts +30 -0
  223. package/src/utils/shell.ts +276 -0
  224. package/src/utils/tools-manager.ts +274 -0
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Core modules shared between all run modes.
3
+ */
4
+
5
+ export {
6
+ AgentSession,
7
+ type AgentSessionConfig,
8
+ type AgentSessionEvent,
9
+ type AgentSessionEventListener,
10
+ type ModelCycleResult,
11
+ type PromptOptions,
12
+ type SessionStats,
13
+ } from "./agent-session.js";
14
+ export { type BashExecutorOptions, type BashResult, executeBash } from "./bash-executor.js";
15
+ export type { CompactionResult } from "./compaction/index.js";
16
+ export {
17
+ type CustomTool,
18
+ type CustomToolAPI,
19
+ type CustomToolFactory,
20
+ type CustomToolsLoadResult,
21
+ type CustomToolUIContext,
22
+ discoverAndLoadCustomTools,
23
+ type ExecResult,
24
+ type LoadedCustomTool,
25
+ loadCustomTools,
26
+ type RenderResultOptions,
27
+ } from "./custom-tools/index.js";
28
+ export {
29
+ type HookAPI,
30
+ type HookContext,
31
+ type HookError,
32
+ type HookEvent,
33
+ type HookFactory,
34
+ HookRunner,
35
+ type HookUIContext,
36
+ loadHooks,
37
+ } from "./hooks/index.js";
38
+ export {
39
+ createMCPManager,
40
+ discoverAndLoadMCPTools,
41
+ expandEnvVars,
42
+ loadAllMCPConfigs,
43
+ type MCPConfigFile,
44
+ type MCPLoadResult,
45
+ MCPManager,
46
+ type MCPServerConfig,
47
+ type MCPServerConnection,
48
+ type MCPToolDefinition,
49
+ type MCPToolDetails,
50
+ type MCPToolsLoadResult,
51
+ type MCPTransport,
52
+ } from "./mcp/index.js";
@@ -0,0 +1,158 @@
1
+ /**
2
+ * MCP Client.
3
+ *
4
+ * Handles connection initialization, tool listing, and tool calling.
5
+ */
6
+
7
+ import { createHttpTransport } from "./transports/http.js";
8
+ import { createStdioTransport } from "./transports/stdio.js";
9
+ import type {
10
+ MCPHttpServerConfig,
11
+ MCPInitializeParams,
12
+ MCPInitializeResult,
13
+ MCPServerCapabilities,
14
+ MCPServerConfig,
15
+ MCPServerConnection,
16
+ MCPSseServerConfig,
17
+ MCPStdioServerConfig,
18
+ MCPToolCallParams,
19
+ MCPToolCallResult,
20
+ MCPToolDefinition,
21
+ MCPToolsListResult,
22
+ MCPTransport,
23
+ } from "./types.js";
24
+
25
+ /** MCP protocol version we support */
26
+ const PROTOCOL_VERSION = "2025-03-26";
27
+
28
+ /** Client info sent during initialization */
29
+ const CLIENT_INFO = {
30
+ name: "pi-coding-agent",
31
+ version: "1.0.0",
32
+ };
33
+
34
+ /**
35
+ * Create a transport for the given server config.
36
+ */
37
+ async function createTransport(config: MCPServerConfig): Promise<MCPTransport> {
38
+ const serverType = config.type ?? "stdio";
39
+
40
+ switch (serverType) {
41
+ case "stdio":
42
+ return createStdioTransport(config as MCPStdioServerConfig);
43
+ case "http":
44
+ case "sse":
45
+ return createHttpTransport(config as MCPHttpServerConfig | MCPSseServerConfig);
46
+ default:
47
+ throw new Error(`Unknown server type: ${serverType}`);
48
+ }
49
+ }
50
+
51
+ /**
52
+ * Initialize connection with MCP server.
53
+ */
54
+ async function initializeConnection(transport: MCPTransport): Promise<MCPInitializeResult> {
55
+ const params: MCPInitializeParams = {
56
+ protocolVersion: PROTOCOL_VERSION,
57
+ capabilities: {
58
+ roots: { listChanged: false },
59
+ },
60
+ clientInfo: CLIENT_INFO,
61
+ };
62
+
63
+ const result = await transport.request<MCPInitializeResult>(
64
+ "initialize",
65
+ params as unknown as Record<string, unknown>,
66
+ );
67
+
68
+ // Send initialized notification
69
+ await transport.notify("notifications/initialized");
70
+
71
+ return result;
72
+ }
73
+
74
+ /**
75
+ * Connect to an MCP server.
76
+ */
77
+ export async function connectToServer(name: string, config: MCPServerConfig): Promise<MCPServerConnection> {
78
+ const transport = await createTransport(config);
79
+
80
+ try {
81
+ const initResult = await initializeConnection(transport);
82
+
83
+ return {
84
+ name,
85
+ config,
86
+ transport,
87
+ serverInfo: initResult.serverInfo,
88
+ capabilities: initResult.capabilities,
89
+ };
90
+ } catch (error) {
91
+ await transport.close();
92
+ throw error;
93
+ }
94
+ }
95
+
96
+ /**
97
+ * List tools from a connected server.
98
+ */
99
+ export async function listTools(connection: MCPServerConnection): Promise<MCPToolDefinition[]> {
100
+ // Check if server supports tools
101
+ if (!connection.capabilities.tools) {
102
+ return [];
103
+ }
104
+
105
+ // Return cached tools if available
106
+ if (connection.tools) {
107
+ return connection.tools;
108
+ }
109
+
110
+ const allTools: MCPToolDefinition[] = [];
111
+ let cursor: string | undefined;
112
+
113
+ do {
114
+ const params: Record<string, unknown> = {};
115
+ if (cursor) {
116
+ params.cursor = cursor;
117
+ }
118
+
119
+ const result = await connection.transport.request<MCPToolsListResult>("tools/list", params);
120
+ allTools.push(...result.tools);
121
+ cursor = result.nextCursor;
122
+ } while (cursor);
123
+
124
+ // Cache tools
125
+ connection.tools = allTools;
126
+
127
+ return allTools;
128
+ }
129
+
130
+ /**
131
+ * Call a tool on a connected server.
132
+ */
133
+ export async function callTool(
134
+ connection: MCPServerConnection,
135
+ toolName: string,
136
+ args: Record<string, unknown> = {},
137
+ ): Promise<MCPToolCallResult> {
138
+ const params: MCPToolCallParams = {
139
+ name: toolName,
140
+ arguments: args,
141
+ };
142
+
143
+ return connection.transport.request<MCPToolCallResult>("tools/call", params as unknown as Record<string, unknown>);
144
+ }
145
+
146
+ /**
147
+ * Disconnect from a server.
148
+ */
149
+ export async function disconnectServer(connection: MCPServerConnection): Promise<void> {
150
+ await connection.transport.close();
151
+ }
152
+
153
+ /**
154
+ * Check if a server supports tools.
155
+ */
156
+ export function serverSupportsTools(capabilities: MCPServerCapabilities): boolean {
157
+ return capabilities.tools !== undefined;
158
+ }
@@ -0,0 +1,154 @@
1
+ /**
2
+ * MCP configuration loader.
3
+ *
4
+ * Loads .mcp.json files from project root with environment variable expansion.
5
+ * Supports ${VAR} and ${VAR:-default} syntax.
6
+ */
7
+
8
+ import { existsSync, readFileSync } from "node:fs";
9
+ import { homedir } from "node:os";
10
+ import { join } from "node:path";
11
+ import type { MCPConfigFile, MCPServerConfig } from "./types.js";
12
+
13
+ /** Environment variable expansion pattern: ${VAR} or ${VAR:-default} */
14
+ const ENV_VAR_PATTERN = /\$\{([^}:]+)(?::-([^}]*))?\}/g;
15
+
16
+ /**
17
+ * Expand environment variables in a string.
18
+ * Supports ${VAR} and ${VAR:-default} syntax.
19
+ */
20
+ export function expandEnvVars(value: string, extraEnv?: Record<string, string>): string {
21
+ return value.replace(ENV_VAR_PATTERN, (_, varName: string, defaultValue?: string) => {
22
+ const envValue = extraEnv?.[varName] ?? process.env[varName];
23
+ if (envValue !== undefined) {
24
+ return envValue;
25
+ }
26
+ if (defaultValue !== undefined) {
27
+ return defaultValue;
28
+ }
29
+ // If no value and no default, leave the placeholder (will likely cause an error later)
30
+ return `\${${varName}}`;
31
+ });
32
+ }
33
+
34
+ /**
35
+ * Recursively expand environment variables in an object.
36
+ */
37
+ function expandEnvVarsInObject<T>(obj: T, extraEnv?: Record<string, string>): T {
38
+ if (typeof obj === "string") {
39
+ return expandEnvVars(obj, extraEnv) as T;
40
+ }
41
+ if (Array.isArray(obj)) {
42
+ return obj.map((item) => expandEnvVarsInObject(item, extraEnv)) as T;
43
+ }
44
+ if (obj !== null && typeof obj === "object") {
45
+ const result: Record<string, unknown> = {};
46
+ for (const [key, value] of Object.entries(obj)) {
47
+ result[key] = expandEnvVarsInObject(value, extraEnv);
48
+ }
49
+ return result as T;
50
+ }
51
+ return obj;
52
+ }
53
+
54
+ /**
55
+ * Load and parse an .mcp.json file.
56
+ * Returns null if file doesn't exist or is invalid.
57
+ */
58
+ export function loadMCPConfigFile(filePath: string, extraEnv?: Record<string, string>): MCPConfigFile | null {
59
+ if (!existsSync(filePath)) {
60
+ return null;
61
+ }
62
+
63
+ try {
64
+ const content = readFileSync(filePath, "utf-8");
65
+ const parsed = JSON.parse(content) as MCPConfigFile;
66
+
67
+ // Expand environment variables in server configs
68
+ if (parsed.mcpServers) {
69
+ parsed.mcpServers = expandEnvVarsInObject(parsed.mcpServers, extraEnv);
70
+ }
71
+
72
+ return parsed;
73
+ } catch (error) {
74
+ console.error(`Warning: Failed to parse ${filePath}: ${error}`);
75
+ return null;
76
+ }
77
+ }
78
+
79
+ /**
80
+ * Configuration locations (in order of priority, later overrides earlier).
81
+ */
82
+ export interface MCPConfigLocations {
83
+ /** User-level config: ~/.pi/mcp.json or ~/.claude.json */
84
+ user?: string;
85
+ /** Project-level config: <cwd>/.mcp.json */
86
+ project?: string;
87
+ }
88
+
89
+ /**
90
+ * Get standard MCP config file paths.
91
+ */
92
+ export function getMCPConfigPaths(cwd: string): MCPConfigLocations {
93
+ const home = homedir();
94
+ return {
95
+ // User-level: ~/.pi/mcp.json (our standard)
96
+ user: join(home, ".pi", "mcp.json"),
97
+ // Project-level: .mcp.json at project root
98
+ project: join(cwd, ".mcp.json"),
99
+ };
100
+ }
101
+
102
+ /**
103
+ * Merge MCP configs from multiple sources.
104
+ * Later sources override earlier ones for servers with same name.
105
+ */
106
+ export function mergeMCPConfigs(...configs: (MCPConfigFile | null)[]): Record<string, MCPServerConfig> {
107
+ const result: Record<string, MCPServerConfig> = {};
108
+
109
+ for (const config of configs) {
110
+ if (config?.mcpServers) {
111
+ Object.assign(result, config.mcpServers);
112
+ }
113
+ }
114
+
115
+ return result;
116
+ }
117
+
118
+ /**
119
+ * Load all MCP server configs from standard locations.
120
+ * Returns merged config with project overriding user.
121
+ */
122
+ export function loadAllMCPConfigs(cwd: string, extraEnv?: Record<string, string>): Record<string, MCPServerConfig> {
123
+ const paths = getMCPConfigPaths(cwd);
124
+
125
+ const userConfig = paths.user ? loadMCPConfigFile(paths.user, extraEnv) : null;
126
+ const projectConfig = paths.project ? loadMCPConfigFile(paths.project, extraEnv) : null;
127
+
128
+ return mergeMCPConfigs(userConfig, projectConfig);
129
+ }
130
+
131
+ /**
132
+ * Validate server config has required fields.
133
+ */
134
+ export function validateServerConfig(name: string, config: MCPServerConfig): string[] {
135
+ const errors: string[] = [];
136
+
137
+ const serverType = config.type ?? "stdio";
138
+
139
+ if (serverType === "stdio") {
140
+ const stdioConfig = config as { command?: string };
141
+ if (!stdioConfig.command) {
142
+ errors.push(`Server "${name}": stdio server requires "command" field`);
143
+ }
144
+ } else if (serverType === "http" || serverType === "sse") {
145
+ const httpConfig = config as { url?: string };
146
+ if (!httpConfig.url) {
147
+ errors.push(`Server "${name}": ${serverType} server requires "url" field`);
148
+ }
149
+ } else {
150
+ errors.push(`Server "${name}": unknown server type "${serverType}"`);
151
+ }
152
+
153
+ return errors;
154
+ }
@@ -0,0 +1,45 @@
1
+ /**
2
+ * MCP (Model Context Protocol) support.
3
+ *
4
+ * Provides per-project .mcp.json configuration for connecting to
5
+ * MCP servers via stdio or HTTP transports.
6
+ */
7
+
8
+ // Client
9
+ export { callTool, connectToServer, disconnectServer, listTools, serverSupportsTools } from "./client.js";
10
+
11
+ // Config
12
+ export {
13
+ expandEnvVars,
14
+ getMCPConfigPaths,
15
+ loadAllMCPConfigs,
16
+ loadMCPConfigFile,
17
+ mergeMCPConfigs,
18
+ validateServerConfig,
19
+ } from "./config.js";
20
+ // Loader (for SDK integration)
21
+ export type { MCPToolsLoadResult } from "./loader.js";
22
+ export { discoverAndLoadMCPTools } from "./loader.js";
23
+ // Manager
24
+ export type { MCPLoadResult } from "./manager.js";
25
+ export { createMCPManager, MCPManager } from "./manager.js";
26
+ // Tool bridge
27
+ export type { MCPToolDetails } from "./tool-bridge.js";
28
+ export { createMCPTool, createMCPToolName, createMCPTools, parseMCPToolName } from "./tool-bridge.js";
29
+ // Transports
30
+ export { createHttpTransport, HttpTransport } from "./transports/http.js";
31
+ export { createStdioTransport, StdioTransport } from "./transports/stdio.js";
32
+ // Types
33
+ export type {
34
+ MCPConfigFile,
35
+ MCPContent,
36
+ MCPHttpServerConfig,
37
+ MCPServerCapabilities,
38
+ MCPServerConfig,
39
+ MCPServerConnection,
40
+ MCPSseServerConfig,
41
+ MCPStdioServerConfig,
42
+ MCPToolDefinition,
43
+ MCPToolWithServer,
44
+ MCPTransport,
45
+ } from "./types.js";
@@ -0,0 +1,68 @@
1
+ /**
2
+ * MCP tools loader.
3
+ *
4
+ * Integrates MCP tool discovery with the custom tools system.
5
+ */
6
+
7
+ import type { LoadedCustomTool } from "../custom-tools/types.js";
8
+ import { type MCPLoadResult, MCPManager } from "./manager.js";
9
+
10
+ /** Result from loading MCP tools */
11
+ export interface MCPToolsLoadResult {
12
+ /** MCP manager (for lifecycle management) */
13
+ manager: MCPManager;
14
+ /** Loaded tools as LoadedCustomTool format */
15
+ tools: LoadedCustomTool[];
16
+ /** Errors keyed by server name */
17
+ errors: Array<{ path: string; error: string }>;
18
+ /** Connected server names */
19
+ connectedServers: string[];
20
+ }
21
+
22
+ /**
23
+ * Discover and load MCP tools from .mcp.json files.
24
+ *
25
+ * @param cwd Working directory (project root)
26
+ * @param extraEnv Additional environment variables for expansion
27
+ * @returns MCP tools in LoadedCustomTool format for integration
28
+ */
29
+ export async function discoverAndLoadMCPTools(
30
+ cwd: string,
31
+ extraEnv?: Record<string, string>,
32
+ ): Promise<MCPToolsLoadResult> {
33
+ const manager = new MCPManager(cwd);
34
+
35
+ let result: MCPLoadResult;
36
+ try {
37
+ result = await manager.discoverAndConnect(extraEnv);
38
+ } catch (error) {
39
+ // If discovery fails entirely, return empty result
40
+ const message = error instanceof Error ? error.message : String(error);
41
+ return {
42
+ manager,
43
+ tools: [],
44
+ errors: [{ path: ".mcp.json", error: message }],
45
+ connectedServers: [],
46
+ };
47
+ }
48
+
49
+ // Convert MCP tools to LoadedCustomTool format
50
+ const loadedTools: LoadedCustomTool[] = result.tools.map((tool) => ({
51
+ path: `mcp:${tool.name}`,
52
+ resolvedPath: `mcp:${tool.name}`,
53
+ tool: tool as any, // MCPToolDetails is compatible with CustomTool<TSchema, any>
54
+ }));
55
+
56
+ // Convert error map to array format
57
+ const errors: Array<{ path: string; error: string }> = [];
58
+ for (const [serverName, errorMsg] of result.errors) {
59
+ errors.push({ path: `mcp:${serverName}`, error: errorMsg });
60
+ }
61
+
62
+ return {
63
+ manager,
64
+ tools: loadedTools,
65
+ errors,
66
+ connectedServers: result.connectedServers,
67
+ };
68
+ }
@@ -0,0 +1,181 @@
1
+ /**
2
+ * MCP Server Manager.
3
+ *
4
+ * Discovers, connects to, and manages MCP servers.
5
+ * Handles tool loading and lifecycle.
6
+ */
7
+
8
+ import type { TSchema } from "@sinclair/typebox";
9
+ import type { CustomTool } from "../custom-tools/types.js";
10
+ import { connectToServer, disconnectServer, listTools } from "./client.js";
11
+ import { loadAllMCPConfigs, validateServerConfig } from "./config.js";
12
+ import type { MCPToolDetails } from "./tool-bridge.js";
13
+ import { createMCPTools } from "./tool-bridge.js";
14
+ import type { MCPServerConfig, MCPServerConnection } from "./types.js";
15
+
16
+ /** Result of loading MCP tools */
17
+ export interface MCPLoadResult {
18
+ /** Loaded tools as CustomTool instances */
19
+ tools: CustomTool<TSchema, MCPToolDetails>[];
20
+ /** Connection errors by server name */
21
+ errors: Map<string, string>;
22
+ /** Connected server names */
23
+ connectedServers: string[];
24
+ }
25
+
26
+ /**
27
+ * MCP Server Manager.
28
+ *
29
+ * Manages connections to MCP servers and provides tools to the agent.
30
+ */
31
+ export class MCPManager {
32
+ private connections = new Map<string, MCPServerConnection>();
33
+ private tools: CustomTool<TSchema, MCPToolDetails>[] = [];
34
+
35
+ constructor(private cwd: string) {}
36
+
37
+ /**
38
+ * Discover and connect to all MCP servers from .mcp.json files.
39
+ * Returns tools and any connection errors.
40
+ */
41
+ async discoverAndConnect(extraEnv?: Record<string, string>): Promise<MCPLoadResult> {
42
+ const configs = loadAllMCPConfigs(this.cwd, extraEnv);
43
+ return this.connectServers(configs);
44
+ }
45
+
46
+ /**
47
+ * Connect to specific MCP servers.
48
+ */
49
+ async connectServers(configs: Record<string, MCPServerConfig>): Promise<MCPLoadResult> {
50
+ const errors = new Map<string, string>();
51
+ const connectedServers: string[] = [];
52
+ const allTools: CustomTool<TSchema, MCPToolDetails>[] = [];
53
+
54
+ for (const [name, config] of Object.entries(configs)) {
55
+ // Skip if already connected
56
+ if (this.connections.has(name)) {
57
+ connectedServers.push(name);
58
+ continue;
59
+ }
60
+
61
+ // Validate config
62
+ const validationErrors = validateServerConfig(name, config);
63
+ if (validationErrors.length > 0) {
64
+ errors.set(name, validationErrors.join("; "));
65
+ continue;
66
+ }
67
+
68
+ try {
69
+ const connection = await connectToServer(name, config);
70
+ this.connections.set(name, connection);
71
+ connectedServers.push(name);
72
+
73
+ // Load tools from this server
74
+ const serverTools = await listTools(connection);
75
+ const customTools = createMCPTools(connection, serverTools);
76
+ allTools.push(...customTools);
77
+ } catch (error) {
78
+ const message = error instanceof Error ? error.message : String(error);
79
+ errors.set(name, message);
80
+ }
81
+ }
82
+
83
+ // Update cached tools
84
+ this.tools = allTools;
85
+
86
+ return {
87
+ tools: allTools,
88
+ errors,
89
+ connectedServers,
90
+ };
91
+ }
92
+
93
+ /**
94
+ * Get all loaded tools.
95
+ */
96
+ getTools(): CustomTool<TSchema, MCPToolDetails>[] {
97
+ return this.tools;
98
+ }
99
+
100
+ /**
101
+ * Get a specific connection.
102
+ */
103
+ getConnection(name: string): MCPServerConnection | undefined {
104
+ return this.connections.get(name);
105
+ }
106
+
107
+ /**
108
+ * Get all connected server names.
109
+ */
110
+ getConnectedServers(): string[] {
111
+ return Array.from(this.connections.keys());
112
+ }
113
+
114
+ /**
115
+ * Disconnect from a specific server.
116
+ */
117
+ async disconnectServer(name: string): Promise<void> {
118
+ const connection = this.connections.get(name);
119
+ if (!connection) return;
120
+
121
+ await disconnectServer(connection);
122
+ this.connections.delete(name);
123
+
124
+ // Remove tools from this server
125
+ this.tools = this.tools.filter((t) => !t.name.startsWith(`mcp_${name}_`));
126
+ }
127
+
128
+ /**
129
+ * Disconnect from all servers.
130
+ */
131
+ async disconnectAll(): Promise<void> {
132
+ const promises = Array.from(this.connections.values()).map((conn) => disconnectServer(conn));
133
+ await Promise.allSettled(promises);
134
+
135
+ this.connections.clear();
136
+ this.tools = [];
137
+ }
138
+
139
+ /**
140
+ * Refresh tools from a specific server.
141
+ */
142
+ async refreshServerTools(name: string): Promise<void> {
143
+ const connection = this.connections.get(name);
144
+ if (!connection) return;
145
+
146
+ // Clear cached tools
147
+ connection.tools = undefined;
148
+
149
+ // Reload tools
150
+ const serverTools = await listTools(connection);
151
+ const customTools = createMCPTools(connection, serverTools);
152
+
153
+ // Replace tools from this server
154
+ this.tools = this.tools.filter((t) => !t.name.startsWith(`mcp_${name}_`));
155
+ this.tools.push(...customTools);
156
+ }
157
+
158
+ /**
159
+ * Refresh tools from all servers.
160
+ */
161
+ async refreshAllTools(): Promise<void> {
162
+ const promises = Array.from(this.connections.keys()).map((name) => this.refreshServerTools(name));
163
+ await Promise.allSettled(promises);
164
+ }
165
+ }
166
+
167
+ /**
168
+ * Create an MCP manager and discover servers.
169
+ * Convenience function for quick setup.
170
+ */
171
+ export async function createMCPManager(
172
+ cwd: string,
173
+ extraEnv?: Record<string, string>,
174
+ ): Promise<{
175
+ manager: MCPManager;
176
+ result: MCPLoadResult;
177
+ }> {
178
+ const manager = new MCPManager(cwd);
179
+ const result = await manager.discoverAndConnect(extraEnv);
180
+ return { manager, result };
181
+ }