doer-agent 0.7.3 → 0.7.4

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.
@@ -11,6 +11,21 @@ function toTomlStringLiteral(value) {
11
11
  function toTomlStringArray(values) {
12
12
  return `[${values.map((value) => toTomlStringLiteral(value)).join(", ")}]`;
13
13
  }
14
+ function buildMcpServerConfigArgs(args) {
15
+ const serverName = args.serverName.trim();
16
+ const configArgs = [
17
+ "--config",
18
+ `mcp_servers.${serverName}.command=${toTomlStringLiteral(args.command)}`,
19
+ "--config",
20
+ `mcp_servers.${serverName}.args=${toTomlStringArray(args.commandArgs)}`,
21
+ "--config",
22
+ `mcp_servers.${serverName}.enabled=${args.enabled === false ? "false" : "true"}`,
23
+ ];
24
+ for (const [key, value] of Object.entries(args.env ?? {})) {
25
+ configArgs.push("--config", `mcp_servers.${serverName}.env.${key}=${toTomlStringLiteral(value)}`);
26
+ }
27
+ return configArgs;
28
+ }
14
29
  function hasDirectCodexBinary() {
15
30
  const result = spawnSync("bash", ["-lc", "command -v codex >/dev/null 2>&1"], {
16
31
  stdio: "ignore",
@@ -71,6 +86,26 @@ export function buildMobileMcpConfigArgs(args) {
71
86
  },
72
87
  });
73
88
  }
89
+ export function buildCustomMcpConfigArgs(servers) {
90
+ const configArgs = [];
91
+ const reservedNames = new Set(["doer_daemon", "doer_mobile"]);
92
+ const seenNames = new Set();
93
+ for (const server of servers) {
94
+ const serverName = server.name.trim();
95
+ if (!server.enabled || !serverName || !server.command.trim() || reservedNames.has(serverName) || seenNames.has(serverName)) {
96
+ continue;
97
+ }
98
+ seenNames.add(serverName);
99
+ configArgs.push(...buildMcpServerConfigArgs({
100
+ serverName,
101
+ command: server.command,
102
+ commandArgs: server.args,
103
+ env: Object.fromEntries(server.env.map((variable) => [variable.key, variable.value])),
104
+ enabled: true,
105
+ }));
106
+ }
107
+ return configArgs;
108
+ }
74
109
  function buildWorkspaceMcpConfigArgs(args) {
75
110
  const serverName = args.serverName.trim();
76
111
  const distEntry = path.join(args.agentProjectDir, args.distEntryRelativePath);
@@ -80,20 +115,16 @@ function buildWorkspaceMcpConfigArgs(args) {
80
115
  const commandArgs = existsSync(distEntry)
81
116
  ? [distEntry, "--workspace-root", args.workspaceRoot]
82
117
  : ["--import", tsxLoaderPath, srcEntry, "--workspace-root", args.workspaceRoot];
83
- const configArgs = [
84
- "--config",
85
- `mcp_servers.${serverName}.command=${toTomlStringLiteral(command)}`,
86
- "--config",
87
- `mcp_servers.${serverName}.args=${toTomlStringArray(commandArgs)}`,
88
- "--config",
89
- `mcp_servers.${serverName}.env.${args.workspaceRootEnvName}=${toTomlStringLiteral(args.workspaceRoot)}`,
90
- "--config",
91
- `mcp_servers.${serverName}.enabled=true`,
92
- ];
93
- for (const [key, value] of Object.entries(args.env ?? {})) {
94
- configArgs.push("--config", `mcp_servers.${serverName}.env.${key}=${toTomlStringLiteral(value)}`);
95
- }
96
- return configArgs;
118
+ return buildMcpServerConfigArgs({
119
+ serverName,
120
+ command,
121
+ commandArgs,
122
+ env: {
123
+ [args.workspaceRootEnvName]: args.workspaceRoot,
124
+ ...(args.env ?? {}),
125
+ },
126
+ enabled: true,
127
+ });
97
128
  }
98
129
  export function buildLocalCodexCliCommand(args) {
99
130
  const quotedArgs = args.map(shellSingleQuote).join(" ");
@@ -41,6 +41,9 @@ export function createDefaultAgentSettingsConfig() {
41
41
  env: {
42
42
  variables: [],
43
43
  },
44
+ mcp: {
45
+ servers: [],
46
+ },
44
47
  };
45
48
  }
46
49
  function normalizeNullableString(value) {
@@ -115,6 +118,74 @@ function normalizeAgentEnvironmentSettings(value, fallback) {
115
118
  }
116
119
  return { variables };
117
120
  }
121
+ function normalizeMcpServerName(value) {
122
+ if (typeof value !== "string") {
123
+ return null;
124
+ }
125
+ const trimmed = value.trim();
126
+ if (!trimmed || !/^[A-Za-z0-9_-]+$/.test(trimmed)) {
127
+ return null;
128
+ }
129
+ if (trimmed === "doer_daemon" || trimmed === "doer_mobile") {
130
+ return null;
131
+ }
132
+ return trimmed;
133
+ }
134
+ function normalizeStringArray(value) {
135
+ if (!Array.isArray(value)) {
136
+ return [];
137
+ }
138
+ return value
139
+ .map((item) => (typeof item === "string" ? item.replace(/\r/g, "") : null))
140
+ .filter((item) => item !== null && item.trim().length > 0);
141
+ }
142
+ function normalizeAgentMcpServer(value) {
143
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
144
+ return null;
145
+ }
146
+ const raw = value;
147
+ const name = normalizeMcpServerName(raw.name);
148
+ const command = typeof raw.command === "string" ? raw.command.trim() : "";
149
+ if (!name || !command) {
150
+ return null;
151
+ }
152
+ const env = [];
153
+ const seenKeys = new Set();
154
+ const envRaw = Array.isArray(raw.env) ? raw.env : [];
155
+ for (const item of envRaw) {
156
+ const normalized = normalizeAgentEnvironmentVariable(item);
157
+ if (!normalized || seenKeys.has(normalized.key)) {
158
+ continue;
159
+ }
160
+ seenKeys.add(normalized.key);
161
+ env.push(normalized);
162
+ }
163
+ return {
164
+ name,
165
+ command,
166
+ args: normalizeStringArray(raw.args),
167
+ env,
168
+ enabled: raw.enabled !== false,
169
+ };
170
+ }
171
+ function normalizeAgentMcpSettings(value, fallback) {
172
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
173
+ return fallback;
174
+ }
175
+ const raw = value;
176
+ const serversRaw = Array.isArray(raw.servers) ? raw.servers : [];
177
+ const servers = [];
178
+ const seenNames = new Set();
179
+ for (const item of serversRaw) {
180
+ const normalized = normalizeAgentMcpServer(item);
181
+ if (!normalized || seenNames.has(normalized.name)) {
182
+ continue;
183
+ }
184
+ seenNames.add(normalized.name);
185
+ servers.push(normalized);
186
+ }
187
+ return { servers };
188
+ }
118
189
  export function normalizeAgentSettingsConfig(value, fallback) {
119
190
  const base = fallback ?? createDefaultAgentSettingsConfig();
120
191
  const raw = value && typeof value === "object" && !Array.isArray(value) ? value : {};
@@ -123,6 +194,7 @@ export function normalizeAgentSettingsConfig(value, fallback) {
123
194
  const realtime = raw.realtime && typeof raw.realtime === "object" ? raw.realtime : {};
124
195
  const git = raw.git && typeof raw.git === "object" ? raw.git : {};
125
196
  const env = raw.env && typeof raw.env === "object" ? raw.env : null;
197
+ const mcp = raw.mcp && typeof raw.mcp === "object" ? raw.mcp : null;
126
198
  return {
127
199
  general: {
128
200
  personality: normalizeCodexPersonality(general.personality, base.general.personality),
@@ -152,6 +224,7 @@ export function normalizeAgentSettingsConfig(value, fallback) {
152
224
  oauthScope: git.oauthScope === null ? null : normalizeNullableString(git.oauthScope) ?? base.git.oauthScope,
153
225
  },
154
226
  env: normalizeAgentEnvironmentSettings(env, base.env),
227
+ mcp: normalizeAgentMcpSettings(mcp, base.mcp),
155
228
  };
156
229
  }
157
230
  export async function readAgentSettingsConfig(args) {
@@ -245,6 +318,18 @@ export async function toAgentSettingsPublic(args) {
245
318
  value: variable.value,
246
319
  })),
247
320
  },
321
+ mcp: {
322
+ servers: args.config.mcp.servers.map((server) => ({
323
+ name: server.name,
324
+ command: server.command,
325
+ args: [...server.args],
326
+ env: server.env.map((variable) => ({
327
+ key: variable.key,
328
+ value: variable.value,
329
+ })),
330
+ enabled: server.enabled,
331
+ })),
332
+ },
248
333
  };
249
334
  }
250
335
  export function normalizeAgentSettingsPatch(value) {
@@ -287,6 +372,7 @@ export function normalizeAgentSettingsPatch(value) {
287
372
  move("gitOauthLogin", "git", "oauthLogin");
288
373
  move("gitOauthScope", "git", "oauthScope");
289
374
  move("environmentVariables", "env", "variables");
375
+ move("mcpServers", "mcp", "servers");
290
376
  return patch;
291
377
  }
292
378
  export function buildAgentSettingsEnvPatch(config) {
@@ -1,5 +1,5 @@
1
1
  import { buildAgentSettingsEnvPatch, readAgentModelInstructions, resolveAgentModelInstructionsFilePath, } from "./agent-settings.js";
2
- import { buildDaemonMcpConfigArgs, buildMobileMcpConfigArgs } from "./agent-codex-cli.js";
2
+ import { buildCustomMcpConfigArgs, buildDaemonMcpConfigArgs, buildMobileMcpConfigArgs } from "./agent-codex-cli.js";
3
3
  import { CodexAppServerClient } from "./codex-app-server-client.js";
4
4
  function toTomlStringLiteral(value) {
5
5
  return `"${value.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
@@ -40,6 +40,7 @@ async function buildCodexAppServerArgs(args) {
40
40
  userId: args.userId,
41
41
  workspaceRoot: args.workspaceRoot,
42
42
  }),
43
+ ...buildCustomMcpConfigArgs(args.settings.mcp.servers),
43
44
  ...buildFeatureArg(true, "goals"),
44
45
  ...buildFeatureArg(args.settings.codex.computerUseEnabled, "computer_use"),
45
46
  ...buildFeatureArg(args.settings.codex.browserUseEnabled, "browser_use"),
@@ -82,7 +83,7 @@ export function createCodexAppServerManager(args) {
82
83
  settings,
83
84
  userId: args.userId,
84
85
  });
85
- args.onLog?.(`starting codex app-server model=${settings.codex.model} reasoningEffort=${settings.codex.reasoningEffort} personality=${settings.general.personality} computerUse=${settings.codex.computerUseEnabled} browserUse=${settings.codex.browserUseEnabled}`);
86
+ args.onLog?.(`starting codex app-server model=${settings.codex.model} reasoningEffort=${settings.codex.reasoningEffort} personality=${settings.general.personality} computerUse=${settings.codex.computerUseEnabled} browserUse=${settings.codex.browserUseEnabled} mcpServers=${settings.mcp.servers.filter((server) => server.enabled).length}`);
86
87
  return new CodexAppServerClient({
87
88
  cwd: args.workspaceRoot,
88
89
  args: appServerArgs,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "doer-agent",
3
- "version": "0.7.3",
3
+ "version": "0.7.4",
4
4
  "description": "Reverse-polling agent runtime for doer",
5
5
  "type": "module",
6
6
  "main": "dist/agent.js",