Skip to content

fix: merge global MCP config with workspace config with deduplication#450

Open
AdJIa wants to merge 2 commits intodifferent-ai:devfrom
AdJIa:fix/mcp-global-config
Open

fix: merge global MCP config with workspace config with deduplication#450
AdJIa wants to merge 2 commits intodifferent-ai:devfrom
AdJIa:fix/mcp-global-config

Conversation

@AdJIa
Copy link

@AdJIa AdJIa commented Feb 5, 2026

Problem

Fixes #451

listMcp() was only reading workspace-level opencode.jsonc, completely ignoring global MCP servers configured in ~/.config/opencode/opencode.json. This meant users had to duplicate their global MCP configurations in every workspace.

Solution

Modified packages/server/src/mcp.ts to:

  1. Merge configurations: Read both global (~/.config/opencode/opencode.json) and workspace (opencode.jsonc) MCP configs
  2. Priority: Workspace config takes precedence over global for same-name MCPs
  3. Deduplication: Handle two types of duplicates:
    • Same name: Workspace config wins (already handled by merge order)
    • Different name, same config: Based on URL for remote MCPs or command for local MCPs
  4. Source tracking: Each MCP item is tagged with source: "config.global" or source: "config.project"
  5. Disable check: Check disabled status against the appropriate config source

Changes

  • Added getGlobalOpencodeConfigPath() helper
  • Added getMcpConfigId() to generate unique identifiers for deduplication
  • Added isSameMcpConfig() for deep comparison fallback
  • Refactored listMcp() to merge and deduplicate configs

Updates (Addressing Review Feedback)

Thanks @benjaminshafii for the thorough security review! Changes made:

  1. Command dedup now keeps all arguments - No longer strips --* flags, so configs with different security settings (e.g., --sandbox vs no sandbox) won't be incorrectly merged
  2. Environment is now included in comparison - Configs with different environment values (tokens, endpoints) are no longer considered duplicates
  3. All comments translated to English

Regarding the secrets exposure concern: The environment field is indeed returned in the API response. This may need UI-level redaction in a follow-up PR to ensure secrets aren't displayed in the interface.

Testing

To test this fix:

  1. Configure MCP servers in ~/.config/opencode/opencode.json
  2. Open a workspace with different MCPs in its opencode.jsonc
  3. Verify both global and workspace MCPs are available in openwork
  4. Verify no duplicates appear when same MCP is defined in both places

Closes #451

Co-authored-by: opencode 令狐冲 opencode@different.ai

The listMcp function was only reading workspace-level opencode.jsonc,
ignoring global MCP servers configured in ~/.config/opencode/opencode.json.

Changes:
- Merge both global and workspace MCP configurations
- Workspace config takes precedence over global for same-name MCPs
- Deduplicate MCPs with different names but same configuration:
  - Remote MCPs: deduplicate by URL
  - Local MCPs: deduplicate by command (ignoring flags like -y)
- Each MCP item is tagged with its source (config.global or config.project)
- Check disabled status against the appropriate config source

Fixes different-ai#448

Co-authored-by: opencode 令狐冲 <opencode@different.ai>
@github-actions
Copy link
Contributor

github-actions bot commented Feb 5, 2026

The following comment was made by an LLM, it may be inaccurate:

Copy link
Member

@benjaminshafii benjaminshafii left a comment

Choose a reason for hiding this comment

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

Bot disclosure: I'm an automated reviewer (OpenWork bot).

Thanks for the fix — the merge + source tagging is useful. Security-focused review:

  1. Dedup for local MCPs in getMcpConfigId strips all --* flags. This can collapse commands that differ in security-relevant flags (sandboxing, allowlists, auth), which could allow a more permissive project config to shadow a safer global config. Suggestion: only ignore a small allowlist like -y/--yes, or keep the full command/args in the ID.
  2. isSameMcpConfig ignores environment. If two configs differ only by env vars (tokens/endpoints), one will be dropped and the remaining one may be used with the wrong credentials. Suggestion: include environment in equality (or at least compare env keys/values).
  3. listMcp now returns global configs too; if environment contains secrets, those will be surfaced to any consumer of McpItem. Please confirm UI/API redaction or consider redacting secrets here.
  4. Workspace config can shadow global entries by name. Please ensure the UI surfaces source prominently and requires explicit user approval before running workspace-sourced remote MCPs.

Non-security:

  • Please translate the new Chinese comments in packages/server/src/mcp.ts to English so CJK text doesn't bleed into the codebase.

No tests run.

- Keep all command arguments (including --flags) in dedup ID to avoid merging configs with different security settings
- Include environment in config comparison to prevent merging configs with different credentials
- Translate all Chinese comments to English
@vercel
Copy link

vercel bot commented Feb 8, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
openwork-software Ready Ready Preview, Comment Feb 8, 2026 3:54pm

@AdJIa
Copy link
Author

AdJIa commented Feb 9, 2026

@benjaminshafii Friendly ping! I've addressed all the review feedback in the latest commit:

  1. ✅ Command dedup now keeps ALL arguments (no more stripping flags)
  2. ✅ Environment is now included in config comparison
  3. ✅ All comments translated to English

The security concerns about merging configs with different security settings or credentials should now be resolved. Could you take another look when you have a chance? Thanks! 🙏

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.

MCP servers from global config (~/.config/opencode/opencode.json) are ignored

2 participants