Skip to content

feat(workflows): support Codex MCP nodes#1459

Merged
Wirasm merged 3 commits into
coleam00:devfrom
borshyo:codex/codex-mcp-workflows
May 15, 2026
Merged

feat(workflows): support Codex MCP nodes#1459
Wirasm merged 3 commits into
coleam00:devfrom
borshyo:codex/codex-mcp-workflows

Conversation

@borshyo

@borshyo borshyo commented Apr 28, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Adds Codex support for workflow node mcp: configs, matching the existing Claude workflow capability.
  • Moves MCP JSON loading into a shared provider utility, including env/header expansion and support for the common { "mcpServers": { ... } } wrapper.
  • Translates workflow MCP server configs into Codex SDK mcp_servers overrides, including headers -> http_headers.
  • Keeps Codex tool allow/deny restrictions out of scope: allowed_tools / denied_tools remain unsupported for Codex sandboxing.
  • Follow-up from closed PR feat(workflows): support Codex MCP nodes #1456: addresses review feedback around title generation, fail-fast MCP config validation, Codex MCP warnings, docs wording, and test robustness.

UX Journey

Before, a Codex workflow node could declare mcp: figma.json, but Archon treated MCP as unsupported for Codex and the provider never attached those servers. Users had to configure MCP globally in Codex outside the workflow.

After, a Codex workflow node can attach MCP servers through its workflow-scoped JSON config. The provider loads the node config, expands env/header vars, passes per-call mcp_servers config to Codex, and surfaces workflow-configured MCP connection errors to the user.

Architecture Diagram

packages/workflows
  dag-executor.ts
    nodeConfig.mcp -> provider sendQuery()

packages/providers
  mcp/config.ts
    shared loadMcpConfig()
      - direct server map JSON
      - { "mcpServers": { ... } } wrapper
      - env/header expansion
      - fail-fast validation for malformed configs

  claude/provider.ts
    imports shared loadMcpConfig()
    preserves existing Claude MCP behavior

  codex/provider.ts
    imports shared loadMcpConfig()
    converts MCP JSON to Codex config.mcp_servers overrides
    creates a per-call Codex client when MCP overrides are needed

  codex/capabilities.ts
    mcp: true

Label Snapshot

  • Risk: risk: medium
  • Size: size: M
  • Scope: workflows|providers|docs|tests
  • Module: providers:codex-mcp

Change Metadata

  • Change type: feature
  • Primary scope: multi

Linked Issue

No linked issue. This PR replaces #1456, which was closed unmerged on 2026-04-28, and carries forward the same Codex MCP workflow capability with the follow-up review fixes and a refresh against current dev.

Validation Evidence

bun test src/codex/provider.test.ts
# 53 pass, 0 fail

bun test src/dag-executor.test.ts
# 202 pass, 0 fail

bun test src/commands/workflow.test.ts
# 94 pass, 0 fail

bun run validate
# exit 0
# includes check:bundled, type-check, lint --max-warnings 0, format:check, and full test suite

Security Impact

  • New permissions/capabilities? Yes. Codex workflow nodes can now attach MCP servers explicitly configured by a node's mcp: file.
  • New external network calls? Indirectly yes, if the MCP config points at an HTTP/SSE endpoint or starts a local MCP process that calls a network service.
  • Secrets/tokens handling changed? Yes. Codex MCP env and headers values can be expanded from Archon's process env plus codebase-scoped env vars.
  • File system access scope changed? Yes. Codex provider reads the per-node MCP config file selected by workflow authors.

Mitigations:

  • The capability is opt-in per workflow node and scoped to the configured MCP JSON path.
  • Missing env vars are reported by name only, not by secret value.
  • Invalid MCP config shapes now fail fast instead of being coerced or skipped silently.
  • Header values are translated to Codex http_headers; secret values are not logged.
  • Workflow-configured MCP failures are surfaced, while unrelated user plugin MCP noise remains filtered at the workflow layer.

Compatibility / Migration

  • Backward compatible: existing Claude MCP workflows keep working, and Codex workflows without mcp: are unchanged.
  • No database migration.
  • No server API or Web UI schema changes.
  • Existing direct server-map MCP JSON works; the common { "mcpServers": { ... } } wrapper also works. Mixed top-level mcpServers plus sibling metadata is rejected with a clear error.

Human Verification

Verified locally:

  • Codex provider receives nodeConfig.mcp, loads JSON, and passes per-call config.mcp_servers to the Codex SDK.
  • $VAR_NAME expansion uses request/codebase env over process env when provided.
  • headers maps to Codex http_headers.
  • mcpServers wrapper JSON loads as the server map.
  • malformed MCP configs fail fast for mixed wrapper metadata, array-valued servers, and non-string env/header values.
  • workflow title generation is fire-and-forget again and no longer makes loadConfig(cwd) a hard dependency of workflowRunCommand.
  • Codex provider warnings now use the ⚠️ prefix so DAG workflows forward them.
  • Full bun run validate passes locally.

Not verified in this PR:

  • A live Figma Desktop MCP end-to-end against the upstream CI environment. Local/manual Figma MCP behavior depends on the user's Figma Desktop session, seat permissions, and MCP server availability.

Side Effects / Blast Radius

Affected areas:

  • @archon/providers Codex/Claude provider internals and shared MCP loader.
  • Workflow MCP validation and DAG tests.
  • CLI workflow title generation path.
  • Docs for workflow authoring and MCP servers.

Potential unintended effects:

  • Codex SDK config compatibility is delegated to the SDK/CLI mcp_servers parser.
  • Codex allowed_tools: [] still does not enforce MCP-only sandboxing, and docs call this out.
  • MCP configs with mixed mcpServers wrapper metadata now fail clearly rather than being interpreted incorrectly.

Rollback Plan

  • Revert this PR commit range from dev if Codex MCP config parsing causes runtime failures.
  • No feature flag or migration cleanup required.
  • Observable failure symptoms: Codex workflows with mcp: fail during node startup with Codex config parsing errors, or workflow-configured MCP server errors appear in node output.

Risks and Mitigations

  • Risk: Codex SDK/CLI changes the accepted mcp_servers override shape or rejects a field passed through this integration.
    • Mitigation: the provider translates only the MCP fields Archon supports and the tests assert the generated Codex config shape.
  • Risk: Users assume allowed_tools / denied_tools now enforce MCP-only sandboxing for Codex.
    • Mitigation: this remains explicitly out of scope and the docs call out that Codex tool restrictions are unsupported for sandboxing.
  • Risk: Broken user-level Codex MCP/plugin config could be confused with workflow-scoped MCP failures.
    • Mitigation: workflow-configured MCP errors are surfaced, while unrelated user plugin MCP noise remains filtered at the workflow layer.
  • Risk: MCP configs copied from other tools use the common { "mcpServers": { ... } } wrapper or mix wrapper metadata with direct server maps.
    • Mitigation: the loader accepts direct maps and pure mcpServers wrappers, and fails fast for mixed top-level wrapper metadata.

Summary by CodeRabbit

  • New Features

    • Enabled MCP support for Codex workflow nodes and surfaced MCP-related errors as workflow system messages
    • Exposed MCP config utilities for provider consumers
  • Improvements

    • Conversation title generation now respects the workflow provider and its provider-specific model options
    • Better warnings and logging around config loading and title generation
  • Documentation

    • Clarified MCP behavior across Codex and Claude and env-var expansion guidance
  • Tests

    • Expanded tests for MCP loading, provider capabilities, and title generation

Review Change Stack

@coderabbitai

coderabbitai Bot commented Apr 28, 2026

Copy link
Copy Markdown

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: dbd4003b-bf22-434b-b606-81eb042cbdc7

📥 Commits

Reviewing files that changed from the base of the PR and between ac1af58 and 4795be8.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (21)
  • CHANGELOG.md
  • packages/cli/src/commands/workflow.test.ts
  • packages/cli/src/commands/workflow.ts
  • packages/core/src/services/title-generator.test.ts
  • packages/core/src/services/title-generator.ts
  • packages/docs-web/src/content/docs/guides/authoring-workflows.md
  • packages/docs-web/src/content/docs/guides/mcp-servers.md
  • packages/providers/package.json
  • packages/providers/src/claude/index.ts
  • packages/providers/src/claude/provider.ts
  • packages/providers/src/codex/capabilities.ts
  • packages/providers/src/codex/provider.test.ts
  • packages/providers/src/codex/provider.ts
  • packages/providers/src/index.ts
  • packages/providers/src/mcp/config.ts
  • packages/providers/src/registry.test.ts
  • packages/workflows/package.json
  • packages/workflows/src/dag-executor.test.ts
  • packages/workflows/src/dag-executor.ts
  • packages/workflows/src/loader.test.ts
  • packages/workflows/src/validator.test.ts

📝 Walkthrough

Walkthrough

Adds a shared MCP config loader, enables MCP support and config conversion for Codex, adjusts provider exports, and makes CLI title generation provider-aware by resolving assistant type and forwarding per-assistant config to generateAndSetTitle. Tests and docs updated accordingly.

Changes

Provider-Aware Title Generation & Assistant Configuration

Layer / File(s) Summary
Provider-aware CLI and tests
packages/cli/src/commands/workflow.ts, packages/cli/src/commands/workflow.test.ts
Resolve assistant type from workflow.provider, load workflow config, derive assistantConfig and pass it to generateAndSetTitle; tests updated to assert the new 6-argument call and provider-aware behavior.
Title generator API & tests
packages/core/src/services/title-generator.ts, packages/core/src/services/title-generator.test.ts
generateAndSetTitle gains an optional assistantConfig parameter and forwards it into client.sendQuery; unit tests verify the provider receives assistantConfig.

Shared MCP Infrastructure & Codex MCP Support

Layer / File(s) Summary
Shared MCP loader
packages/providers/src/mcp/config.ts, packages/providers/package.json
New loadMcpConfig and LoadedMcpConfig exported; normalizes { mcpServers: ... } wrapper, validates server objects, and expands $VAR_NAME in env/headers while tracking missing vars.
Codex provider MCP integration
packages/providers/src/codex/provider.ts, packages/providers/src/codex/capabilities.ts
Codex advertises mcp: true; provider loads MCP config when nodeConfig.mcp is set, converts servers into Codex mcp_servers overrides (maps headers→http_headers, converts nested values, skips invalid types), avoids cached client when overrides exist, and can surface MCP client errors as system messages.
Provider export reorg
packages/providers/src/claude/provider.ts, packages/providers/src/claude/index.ts, packages/providers/src/index.ts
Extracted MCP loader out of Claude provider into shared module; Claude now imports loadMcpConfig; barrel exports updated to re-export loadMcpConfig and its type.
Tests, docs, packaging, workflows
packages/providers/src/codex/provider.test.ts, packages/providers/src/registry.test.ts, packages/workflows/src/*, packages/docs-web/src/content/docs/guides/*, packages/workflows/package.json, CHANGELOG.md
Updated tests to expect mcp: true, added MCP-forwarding tests (env expansion, missing-vars warnings, error surfacing), updated docs to reflect Codex+Claude MCP support and mcpServers wrapper, added package exports and changelog entry.

Sequence Diagram

sequenceDiagram
  participant CLI as CLI Workflow Command
  participant WC as Workflow Config
  participant TG as Title Generator
  participant CP as Codex Provider
  participant MCP as MCP Config Module
  participant Codex as Codex SDK Client

  CLI->>WC: loadConfig(cwd)
  WC-->>CLI: { assistants: { codex: { model: 'gpt-5.4' } } }
  
  CLI->>CLI: resolveTitleAssistantType(workflow.provider='codex')
  CLI->>TG: generateAndSetTitle(conversationId, message, 'codex', cwd, workflowName, assistantConfig)
  TG->>TG: Build prompt, call AI provider
  TG->>CP: client.sendQuery(..., { assistantConfig })

  Note over CP: If nodeConfig.mcp set
  CP->>MCP: loadMcpConfig(mcpPath, cwd, envSource)
  MCP->>MCP: Parse JSON, expand $VAR_NAME, validate
  MCP-->>CP: { servers, serverNames, missingVars }
  
  CP->>CP: convert servers -> codex mcp_servers override
  CP->>Codex: createCodexClient(requestEnv, { config: { mcp_servers: ... } })
  Codex-->>CP: client instance/response
  CP-->>TG: provider response
  TG-->>CLI: (title set on conversation)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

  • coleam00/Archon#1137: Modifies provider request options used by generateAndSetTitle; related to forwarding assistant/config options to provider.

Poem

🐰 I hopped through configs, vars, and code today,

Codex now welcomes MCP in play,
Titles learn which assistant has the say,
Shared loader hums in a tidy, tested way,
Happy hops for builds and CI’s ballet!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 47.37% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat(workflows): support Codex MCP nodes' accurately summarizes the primary change: enabling MCP node configuration support for Codex workflows.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description check ✅ Passed The PR description is comprehensive and follows the template structure with all critical sections completed: Summary, UX Journey, Architecture Diagram, Label Snapshot, Change Metadata, Linked Issue, Validation Evidence, Security Impact, Compatibility, Human Verification, Side Effects, Rollback Plan, and Risks/Mitigations.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@borshyo

borshyo commented Apr 28, 2026

Copy link
Copy Markdown
Contributor Author

checked in my workflow (i'm human), mcp has been started to working

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (4)
packages/core/src/services/title-generator.test.ts (1)

180-196: Good test coverage for assistantConfig passthrough.

The test correctly verifies that assistantConfig is forwarded to the provider's sendQuery call.

Minor nit: Line 186 uses 'conv-12' but line 208 (the double failure test) also uses 'conv-12'. This doesn't affect test correctness since beforeEach clears mocks, but updating to 'conv-17' would maintain the sequential naming convention used throughout the file.

Optional: Update conversation ID to avoid duplicate
     await generateAndSetTitle(
-      'conv-12',
+      'conv-17',
       'Some message',
       'codex',
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/core/src/services/title-generator.test.ts` around lines 180 - 196,
Update the conversation id in the test named "passes assistantConfig through to
the provider" from 'conv-12' to 'conv-17' so it doesn't duplicate the id used by
the "double failure" test; modify the call to generateAndSetTitle in that test
(which ultimately drives mockSendQuery) to use 'conv-17' so naming remains
sequential while behavior and assertions (inspecting
mockSendQuery.mock.calls[0][3] and expect(optionsArg.assistantConfig)) remain
unchanged.
packages/providers/src/mcp/config.ts (1)

35-35: Document the uppercase-only environment variable convention.

The regex /\$([A-Z_][A-Z0-9_]*)/g deliberately restricts variable references to uppercase identifiers (e.g., $GITHUB_TOKEN, $API_KEY). This aligns with the documented example in mcp-servers.md and appears consistent with Archon's workflow variable naming convention (which uses uppercase throughout: $ARTIFACTS_DIR, $WORKFLOW_ID, $BASE_BRANCH, etc.).

However, this design choice should be documented in the function comment or in the MCP config guide to clarify that only uppercase env var references are expanded. This helps prevent user confusion when lowercase or mixed-case references are silently ignored.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/providers/src/mcp/config.ts` at line 35, Add a short comment above
the replacement logic explaining that only uppercase environment variable
references are expanded (per the regex /\$([A-Z_][A-Z0-9_]*)/g), so references
like $GITHUB_TOKEN or $API_KEY will be substituted but lowercase or mixed-case
names will be ignored; update the MCP config guide or mcp-servers.md to call out
this uppercase-only convention so users know why result[key] = val.replace(...)
only matches uppercase identifiers.
packages/workflows/src/dag-executor.test.ts (1)

26-32: Add explicit return types to new @archon/paths mock functions.

The newly added mock functions rely on inferred return types; please annotate them explicitly for consistency with strict TS guidelines.

Suggested patch
-  getWorkflowFolderSearchPaths: () => ['.archon/workflows'],
+  getWorkflowFolderSearchPaths: (): string[] => ['.archon/workflows'],
   getDefaultCommandsPath: () => '/nonexistent/defaults',
-  getDefaultWorkflowsPath: () => '/nonexistent/defaults/workflows',
-  getHomeWorkflowsPath: () => '/nonexistent/home/workflows',
-  getLegacyHomeWorkflowsPath: () => '/nonexistent/home/.archon/workflows',
-  getArchonHome: () => '/nonexistent/home',
+  getDefaultWorkflowsPath: (): string => '/nonexistent/defaults/workflows',
+  getHomeWorkflowsPath: (): string => '/nonexistent/home/workflows',
+  getLegacyHomeWorkflowsPath: (): string => '/nonexistent/home/.archon/workflows',
+  getArchonHome: (): string => '/nonexistent/home',

As per coding guidelines: "**/*.{ts,tsx}: Enforce strict TypeScript configuration with complete type annotations on all functions; no any types without explicit justification".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/workflows/src/dag-executor.test.ts` around lines 26 - 32, The mock
functions added (getWorkflowFolderSearchPaths, getDefaultCommandsPath,
getDefaultWorkflowsPath, getHomeWorkflowsPath, getLegacyHomeWorkflowsPath,
getArchonHome) lack explicit return type annotations; update each mock to
include the correct TypeScript return types (getWorkflowFolderSearchPaths: () =>
string[], and the others: () => string) so the mocked API signatures are fully
typed and satisfy the project's strict TS rules.
packages/cli/src/commands/workflow.ts (1)

671-677: Use resolved workflow name when generating titles.

Consider passing workflow.name instead of the raw CLI input workflowName so suffix/substring-resolved runs generate consistent canonical titles.

Suggested tweak
       await generateAndSetTitle(
         conversation.id,
         userMessage,
         titleAssistantType,
         workingCwd,
-        workflowName,
+        workflow.name,
         titleAssistantConfig
       );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/cli/src/commands/workflow.ts` around lines 671 - 677, The call to
generateAndSetTitle currently passes the raw CLI input workflowName, which can
differ from the resolved workflow object; update the invocation to pass the
resolved workflow.name instead so canonical titles use the finalized workflow
identifier—locate the generateAndSetTitle(...) call (parameters:
conversation.id, userMessage, titleAssistantType, workingCwd, workflowName,
titleAssistantConfig) and replace the workflowName argument with workflow.name
(the resolved workflow object available in this scope).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/providers/src/codex/provider.test.ts`:
- Around line 901-905: The test "prefixes workflow MCP warnings for workflow
forwarding" mutates process.env.ARCHON_CODEX_MISSING_TOKEN without restoring it;
capture the original value at test start (e.g., const orig =
process.env.ARCHON_CODEX_MISSING_TOKEN), delete or modify it for the test, and
then restore it in a finally block or afterEach so the environment is returned
to orig (also apply the same save/restore pattern for the other test around
lines 933-935 that deletes this env var); reference the test block name and
ensure restoration happens even on failures.

---

Nitpick comments:
In `@packages/cli/src/commands/workflow.ts`:
- Around line 671-677: The call to generateAndSetTitle currently passes the raw
CLI input workflowName, which can differ from the resolved workflow object;
update the invocation to pass the resolved workflow.name instead so canonical
titles use the finalized workflow identifier—locate the generateAndSetTitle(...)
call (parameters: conversation.id, userMessage, titleAssistantType, workingCwd,
workflowName, titleAssistantConfig) and replace the workflowName argument with
workflow.name (the resolved workflow object available in this scope).

In `@packages/core/src/services/title-generator.test.ts`:
- Around line 180-196: Update the conversation id in the test named "passes
assistantConfig through to the provider" from 'conv-12' to 'conv-17' so it
doesn't duplicate the id used by the "double failure" test; modify the call to
generateAndSetTitle in that test (which ultimately drives mockSendQuery) to use
'conv-17' so naming remains sequential while behavior and assertions (inspecting
mockSendQuery.mock.calls[0][3] and expect(optionsArg.assistantConfig)) remain
unchanged.

In `@packages/providers/src/mcp/config.ts`:
- Line 35: Add a short comment above the replacement logic explaining that only
uppercase environment variable references are expanded (per the regex
/\$([A-Z_][A-Z0-9_]*)/g), so references like $GITHUB_TOKEN or $API_KEY will be
substituted but lowercase or mixed-case names will be ignored; update the MCP
config guide or mcp-servers.md to call out this uppercase-only convention so
users know why result[key] = val.replace(...) only matches uppercase
identifiers.

In `@packages/workflows/src/dag-executor.test.ts`:
- Around line 26-32: The mock functions added (getWorkflowFolderSearchPaths,
getDefaultCommandsPath, getDefaultWorkflowsPath, getHomeWorkflowsPath,
getLegacyHomeWorkflowsPath, getArchonHome) lack explicit return type
annotations; update each mock to include the correct TypeScript return types
(getWorkflowFolderSearchPaths: () => string[], and the others: () => string) so
the mocked API signatures are fully typed and satisfy the project's strict TS
rules.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 9c0ae4dd-b13a-4abb-8e7e-767b6e14ea4b

📥 Commits

Reviewing files that changed from the base of the PR and between 2220ffe and c5a34ce.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (20)
  • packages/cli/src/commands/workflow.test.ts
  • packages/cli/src/commands/workflow.ts
  • packages/core/src/services/title-generator.test.ts
  • packages/core/src/services/title-generator.ts
  • packages/docs-web/src/content/docs/guides/authoring-workflows.md
  • packages/docs-web/src/content/docs/guides/mcp-servers.md
  • packages/providers/package.json
  • packages/providers/src/claude/index.ts
  • packages/providers/src/claude/provider.ts
  • packages/providers/src/codex/capabilities.ts
  • packages/providers/src/codex/provider.test.ts
  • packages/providers/src/codex/provider.ts
  • packages/providers/src/index.ts
  • packages/providers/src/mcp/config.ts
  • packages/providers/src/registry.test.ts
  • packages/workflows/package.json
  • packages/workflows/src/dag-executor.test.ts
  • packages/workflows/src/dag-executor.ts
  • packages/workflows/src/loader.test.ts
  • packages/workflows/src/validator.test.ts

Comment thread packages/providers/src/codex/provider.test.ts

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c5a34ce557

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines 334 to 336
const isMcpClientError = errorEvent.message.toLowerCase().includes('mcp client');
if (surfaceMcpClientErrors || !isMcpClientError) {
yield { type: 'system', content: `⚠️ ${errorEvent.message}` };

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep unrelated MCP client errors suppressed

When nodeConfig.mcp is set, this branch now emits every "mcp client" stream error to users. Because Codex config overrides are additive (global ~/.codex/config.toml MCP servers still load), a broken user-level/plugin MCP server can produce the same error string and get surfaced during workflow runs even if the failing server is not in the workflow MCP file. That regresses the prior behavior (always suppressing MCP-client noise) and can mislead users into debugging the wrong MCP config.

Useful? React with 👍 / 👎.

@borshyo

borshyo commented May 2, 2026

Copy link
Copy Markdown
Contributor Author

Updated this PR branch against current upstream/dev and pushed ac1af587 to borshyo/Archon-fork:codex/codex-mcp-workflows.

What changed in the update:

  • Merged current dev to clear the stale/conflicting PR state.
  • Addressed CodeRabbit follow-ups: env restoration in Codex MCP tests, canonical workflow name for title generation, explicit mock return types, and uppercase-only env expansion docs/comment.
  • Adapted the title-generation provider logic to current dev after @archon/workflows/model-validation was removed upstream.

Validation:

  • bun run validate passed on the updated branch.
  • Real Archon workflow-scoped MCP smoke tests passed from the updated PR worktree with temporary workflows using per-node mcp: JSON:
    • memory: loaded serverNames:["memory"], called memory/create_entities, memory/read_graph, memory/add_observations, completed with MEMORY_MCP_OK: codex-memory-mcp-smoke-pr1459-2026-05-02.
    • everything: loaded serverNames:["everything"], called everything/echo, completed with EVERYTHING_MCP_OK: codex-everything-mcp-smoke-pr1459-2026-05-02.

The temporary smoke workflow/config files and local artifacts were removed after validation.

@Wirasm

Wirasm commented May 4, 2026

Copy link
Copy Markdown
Collaborator

@borshyo this PR looks similar to #1456, which was closed on 2026-04-28 (not merged). You may want to read the discussion there before pushing further.

@Wirasm

Wirasm commented May 4, 2026

Copy link
Copy Markdown
Collaborator

Hi @borshyo — thanks for opening this PR.

This repository uses a PR template at .github/pull_request_template.md with several required
sections. A few of them appear to be empty or placeholder here:

  • Change Metadata
  • Linked Issue
  • Risks and Mitigations

Could you fill those out (even briefly)? The template
helps reviewers understand scope, risk, and rollback — it
speeds up review significantly.

If a section genuinely doesn't apply, just write "N/A" in
it rather than leaving it blank.

borshyo commented May 4, 2026

Copy link
Copy Markdown
Contributor Author

Thanks @Wirasm — I updated the PR body to fill the missing template sections:

  • Change Metadata
  • Linked Issue, including Supersedes #1456
  • Risks and Mitigations

Also clarified that this PR replaces the closed, unmerged #1456 and carries forward the follow-up fixes on current dev.

@borshyo

borshyo commented May 4, 2026

Copy link
Copy Markdown
Contributor Author

Thanks @Wirasm — I updated the PR body to fill the missing template sections:

  • Change Metadata
  • Linked Issue, including Supersedes #1456
  • Risks and Mitigations

Also clarified that this PR replaces the closed, unmerged #1456 and carries forward the follow-up fixes on current dev.

@Wirasm

Wirasm commented May 11, 2026

Copy link
Copy Markdown
Collaborator

Review Summary

Verdict: minor-fixes-needed

Your PR extends MCP server support from Claude to Codex provider nodes, adds a shared config loader, and fixes title generation to use the workflow's actual provider. The code is well-structured, thoroughly tested, and error handling is solid throughout. Two small items need attention before merge.

Suggested fixes

  • packages/workflows/src/dag-executor.ts:325: Remove the stale comment // loadMcpConfig moved to @archon/providers/src/mcp/config.ts. It describes a past refactoring with no WHY context and has no value for future maintainers.

  • CHANGELOG.md: Add a Keep-a-Changelog entry under [Unreleased] → ### Added for the new Codex MCP capability:

    Codex workflow nodes now support per-node MCP server config via mcp:, matching the existing Claude support. This enables MCP tools (GitHub, Postgres, Figma, etc.) on Codex nodes without global config setup. Additionally, MCP JSON config files now accept the standard { "mcpServers": { ... } } wrapper format alongside the bare server-map format.

  • packages/core/src/services/title-generator.ts:35: The JSDoc @param assistantConfig just restates the parameter name. Either remove the line, or add a sentence explaining when/why a caller would populate this vs. relying on defaults.

Minor / nice-to-have

  • packages/cli/src/commands/workflow.ts:651: Optional — a unit test asserting no error propagates when generateAndSetTitle throws would tighten coverage (currently only tested via happy-path integration). Low priority since it's fire-and-forget.

Compliments

  • The new resolveTitleAssistantType docstring in workflow.ts is exemplary — it explains WHY the function exists rather than just what it does. Good pattern.
  • Error handling is clean: loadMcpConfig throws with specific context, MCP errors surface correctly in streamCodexEvents, and fire-and-forget paths log warnings appropriately.
  • The mcp-servers.md and authoring-workflows.md docs are updated consistently and accurately reflect the new Codex support.

Reviewed via maintainer-review-pr workflow (Pi/Minimax). Aspects run: code-review, error-handling, test-coverage, comment-quality, docs-impact.

@Wirasm

Wirasm commented May 13, 2026

Copy link
Copy Markdown
Collaborator

Review Summary

Verdict: blocking-issues

This PR adds excellent MCP support for Codex workflow nodes — the shared config module, error surfacing, and documentation updates are all well done. However, one CRITICAL issue must be resolved before merge: the import of a non-existent module will cause CI to fail.

Blocking issues

  • packages/cli/src/commands/workflow.ts:17: inferProviderFromModel is imported from @archon/workflows/model-validation, but that module file does not exist in the PR or the base branch. CI will fail.
    • Fix: Either add packages/workflows/src/model-validation.ts to the PR, or remove the import and implement model-to-provider inference inline (e.g., model.startsWith('gpt-')codex, model.startsWith('sonnet') / 'claude' / 'haiku' / 'opus'claude).

Suggested fixes

  • packages/workflows/src/validator.ts:393-402: The test validator.test.ts was updated to reflect that Codex no longer triggers the "MCP not supported by provider" warning, but the source validator.ts was not changed (or the change is missing). Verify the source reflects this — if it does, add a comment anchoring the test to prevent future drift.

Minor / nice-to-have

  • CHANGELOG.md: Add entry under [Unreleased] for MCP-for-Codex — user-visible feature deserves a changelog line.
  • packages/docs-web/src/content/docs/guides/mcp-servers.md:218: Drop "for Claude workflows" — the log name dag.mcp_plugin_connection_suppressed is provider-agnostic.
  • assistantConfig docs: generateAndSetTitle now forwards assistantConfig from workflow config to title generation, but this capability isn't documented. Consider adding to the Node Fields table in authoring-workflows.md or the configuration reference.
  • packages/providers/src/mcp/config.ts:39-40: Add end-to-end test for lowercase env var references (regex ignores $lowercase_var — documented but not regression-tested). Suggested test added in the full review.
  • packages/providers/src/mcp/config.ts:118: Error message uses single-quotes while the rest of the file uses double-quotes — minor style normalization.
  • packages/providers/src/mcp/config.ts: normalizeMcpConfig() rejects configs with a $schema key alongside mcpServers — overly strict for JSON Schema-wrapped configs from common MCP tools.

Compliments

  • The fire-and-forget error handling patterns (title config load, title generation, MCP timeout when MCP not configured) are consistent and well-reasoned.
  • The shared loadMcpConfig module extraction is clean and the new envSource overload is a good interface addition.
  • mcp-servers.md docs are thorough — the "Codex currently does not support Archon's allowed_tools / denied_tools restrictions" caveat is exactly the kind of edge case that saves workflow authors debugging time.

Reviewed via maintainer-review-pr workflow (Pi/Minimax). Aspects run: code-review, error-handling, test-coverage, comment-quality, docs-impact.

borshyo and others added 3 commits May 15, 2026 16:27
- Drop the broken `inferProviderFromModel` import from
  packages/cli/src/commands/workflow.ts. The module it referenced
  (@archon/workflows/model-validation) does not exist, which caused the
  CLI package's type-check to fail. Per CLAUDE.md, provider is resolved
  via an explicit chain (`node.provider ?? workflow.provider ?? config.assistant`)
  and model never influences provider selection — vendor SDKs add new
  model names faster than we can keep a mapping in sync, so the
  model-based inference fallback was the wrong primitive anyway. Removed
  the use site and added a comment anchoring the explicit-chain rule.
- Drop "for Claude workflows" from the
  `dag.mcp_plugin_connection_suppressed` documentation in mcp-servers.md.
  The log event is provider-agnostic and the qualifier was misleading
  once Codex got MCP support too.
- Add CHANGELOG.md entry under [Unreleased] for the MCP-for-Codex
  feature with a short note on the system-chunk surfacing behavior.
@Wirasm Wirasm force-pushed the codex/codex-mcp-workflows branch from ac1af58 to 4795be8 Compare May 15, 2026 13:32
@Wirasm Wirasm merged commit 96c73b1 into coleam00:dev May 15, 2026
1 check was pending
cropse pushed a commit to cropse/Archon that referenced this pull request May 19, 2026
* feat(workflows): support Codex MCP nodes

* fix: address MCP workflow review feedback

* fix: address review feedback on Codex MCP support

- Drop the broken `inferProviderFromModel` import from
  packages/cli/src/commands/workflow.ts. The module it referenced
  (@archon/workflows/model-validation) does not exist, which caused the
  CLI package's type-check to fail. Per CLAUDE.md, provider is resolved
  via an explicit chain (`node.provider ?? workflow.provider ?? config.assistant`)
  and model never influences provider selection — vendor SDKs add new
  model names faster than we can keep a mapping in sync, so the
  model-based inference fallback was the wrong primitive anyway. Removed
  the use site and added a comment anchoring the explicit-chain rule.
- Drop "for Claude workflows" from the
  `dag.mcp_plugin_connection_suppressed` documentation in mcp-servers.md.
  The log event is provider-agnostic and the qualifier was misleading
  once Codex got MCP support too.
- Add CHANGELOG.md entry under [Unreleased] for the MCP-for-Codex
  feature with a short note on the system-chunk surfacing behavior.

---------

Co-authored-by: Kirill <borshyo@users.noreply.github.com>
Co-authored-by: Rasmus Widing <rasmus.widing@gmail.com>
danielscholl pushed a commit to danielscholl/Archon that referenced this pull request May 20, 2026
- Update loadMcpConfig import to ../../mcp/config — coleam00#1459 (Codex MCP
  nodes) extracted it out of claude/provider.ts into its own module.
- Regenerate bun.lock from current dev (configVersion: 1). Old commits
  on this branch carried configVersion: 0; rebased forward unchanged
  but produced different transitive resolution on install (telegram
  markdown tests fail locally despite identical telegramify-markdown
  pin). bun install re-adds @github/copilot-sdk on top of the fresh
  lockfile.
danielscholl pushed a commit to danielscholl/Archon that referenced this pull request May 20, 2026
coleam00#1459 (Codex MCP nodes) extracted loadMcpConfig out of
claude/provider.ts into a shared mcp/config.ts module. Update the
applyMcpServers docblock to reflect that the helper is shared, not
Claude-specific.
Wirasm added a commit that referenced this pull request May 25, 2026
* feat(providers): add GitHub Copilot provider configuration types
Define CopilotProviderDefaults with model, reasoning effort, and auth options
Include system message injection and CLI path configuration support

* feat(providers): add GitHub Copilot community provider integration
Implement full provider with session management, streaming, and binary resolution
Include comprehensive test coverage and lazy-load SDK pattern

* feat(providers): add Copilot provider registration and exports
Export CopilotProvider, config parser, and binary resolver utilities
Register Copilot provider in community providers initialization

* test(e2e): add GitHub Copilot provider smoke and abort tests
Include streaming verification, token validation, and interrupt handling
Verify connectivity, output plumbing, and session management

* feat(copilot): add reasoning effort alias and session timeout improvements
Map Archon `max` effort to SDK `xhigh` and extend sendAndWait timeout to 60min
Handle fork-session requests with fresh session creation fallback

* feat(copilot): add environment variable override support and auto model default
Add COPILOT_MODEL env var with envOverrides tracking across config system
Update provider to default model to 'auto' and enhance settings UI

* docs(copilot): clarify session option handling comment

* feat(copilot): add MCP, skills, agents, and structured output support

Implement full Copilot SDK feature translation including tool restrictions,
session config assembly, and best-effort JSON parsing for structured output

* feat(copilot): respect useLoggedInUser to override env token
test(copilot): cover env token precedence and override behavior

* refactor(copilot): remove isCopilotModelCompatible and model-ref
delete model-ref.ts and model-ref.test.ts
update copilot index and registration to drop isCopilotModelCompatible export

* fix(struct-out): enforce object requirement for structured output parsing
return undefined if parsed JSON is not an object
add tests covering non-object JSON in structured output parsing

* feat(copilot): add isExecutableFile check for Copilot binary
implement isExecutableFile using stat/access and use it in path resolution
update errors to reference executable file and chmod guidance

* feat(copilot): add PATH lookup for copilot binary resolution
export resolveFromPath and prefer PATH result when executable

* ci(workflows): migrate and add Copilot CI workflows
- rename e2e-copilot-abort.yaml to test-workflows/e2e-copilot-abort.yaml
- add e2e-copilot-all-features.yaml and relocate smoke workflow to test-workflows

* refactor(shared): centralize structured-output parsing and skills
update providers to re-export shared implementations
expose shared utilities: tryParseStructuredOutput, augmentPromptForJsonSchema

* feat(registry): register Copilot community provider
update registry tests to cover copilot provider registration
verify no collision with built-ins and copilot appears in lists

* feat(copilot): defer session error warning and harden abort flow
update event-bridge to emit no system chunk on session.error
add provider-hardening tests for abort, trim model config and cleanup

* ci(workflow): simplify output capture in e2e-copilot-smoke workflow

* ci(workflows): restructure Copilot e2e workflows for clarity
refactor multiple files into sections for fixtures, demos, and checks

* ci(workflow): remove e2e-copilot-all-features workflow

* feat(workflows): add e2e-copilot-all-nodes-smoke workflow
delete old e2e-copilot-smoke workflow
extend Copilot smoke tests to cover all node types and structured outputs

* refactor(config): remove envOverrides support and COPILOT_MODEL usage
use DEFAULT_AI_ASSISTANT env var to select default ai assistant
update tests and docs to reflect new default and env var usage

* docs: update Copilot docs and env sample

* feat(copilot): implement token precedence for Copilot auth
introduce COPILOT_GITHUB_TOKEN and generic GH tokens; track tokenSource
reorder provider registration to register Pi before Copilot

* fe​at(copilot): improve binary resolution and skill dir validation
use isExecutableFile for vendor and autodetect checks
validate skill names to reject absolute or traversal paths

* fix: address review feedback on Copilot community provider

- Add packages/providers/src/shared/structured-output.test.ts covering
  augmentPromptForJsonSchema, the happy-path clean parse, fence stripping
  (both ```json and bare ```), the forward-brace scan recovery for
  reasoning-model prose preamble, fence + preamble combo, whitespace
  trimming, invalid JSON, empty input, and the bare-primitive rejection
  contract (null/number/string/boolean).
- Add packages/providers/src/shared/skills.test.ts covering empty/null
  inputs, non-string and empty-string skipping, missing skills, cwd vs
  home resolution order, cwd-shadows-home semantics, deduplication, and
  the name-only contract (rejection of absolute paths, nested paths,
  and parent traversal). Uses a staged temp HOME so reads are isolated.
- Wire both new test files into packages/providers/package.json so they
  run in CI as separate bun test invocations.
- Add `copilot` to the registered-providers list in the validation
  error example at guides/authoring-workflows.md, add a Copilot bullet
  to the Model strings section, and add an AI Providers -- Copilot
  env-var subsection plus DEFAULT_AI_ASSISTANT enumeration to
  reference/configuration.md.

The two duplicate-import HIGH findings from the May 14 review were
hallucinations — the imports don't exist in the current branch — so
they need no fix.

* chore(rebase): resolve semantic conflicts from dev

- Update loadMcpConfig import to ../../mcp/config — #1459 (Codex MCP
  nodes) extracted it out of claude/provider.ts into its own module.
- Regenerate bun.lock from current dev (configVersion: 1). Old commits
  on this branch carried configVersion: 0; rebased forward unchanged
  but produced different transitive resolution on install (telegram
  markdown tests fail locally despite identical telegramify-markdown
  pin). bun install re-adds @github/copilot-sdk on top of the fresh
  lockfile.

* test(copilot): address CodeRabbit feedback on shared/skills tests

- Stage the home copy of `delta` in `.agents` (not `.claude`) so the
  "prefers cwd over home" precedence test actually verifies precedence
  within `.agents`. Previously the home copy was in `.claude`, which
  could not have beaten the cwd `.agents` copy regardless of the
  resolver's behavior.
- Add explicit return types on `makeFakeWorld` and the inner
  `stageSkill` to satisfy the project's strict TS annotation rule.

* fix(providers): address remaining Wirasm review items

- pi/event-bridge.ts: consolidate the `export-from` + `import-from`
  pair on shared/structured-output into the idiomatic
  `import { X }; export { X };` form. The preceding comment already
  promised "import once for local use and re-export" but the prior
  order said the opposite.
- authoring-workflows.md: add `copilot` to the prose listing of
  registered providers (the example validation error string below it
  already includes copilot).

* chore(copilot): drop stale "Claude's loadMcpConfig" attribution

#1459 (Codex MCP nodes) extracted loadMcpConfig out of
claude/provider.ts into a shared mcp/config.ts module. Update the
applyMcpServers docblock to reflect that the helper is shared, not
Claude-specific.

---------

Co-authored-by: Daniel Scholl <daniel.scholl@microsoft.com>
Co-authored-by: Rasmus Widing <rasmus.widing@gmail.com>
@Wirasm Wirasm mentioned this pull request May 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants