[FEATURE]: Allow per-project MCP enabled/disabled overrides #2986

Closed
opened 2026-02-16 17:38:08 -05:00 by yindo · 8 comments
Owner

Originally created by @jknlsn on GitHub (Nov 19, 2025).

Feature hasn't been suggested before.

  • I have verified this feature I'm about to request hasn't been suggested before.

Describe the enhancement you want to request

Problem

Currently, OpenCode starts all configured MCP servers regardless of whether any agent has access to their tools. The sidebar shows "Connected" MCPs, but it's not obvious whether they're actually usable or not. For example, if I have Linear, GitHub, and Xcode MCPs configured globally but disable them all with "linear_*": false, "github_*": false, "xcode_*": false, all three MCP servers still start up - they're just not accessible to agents.

Proposed Solution

Only start MCP servers that are accessible to at least one agent based on the tools configuration. This involves:

  1. Check accessibility before starting - Before initializing an MCP server, check if any agent can access its tools
  2. Add "inaccessible" status - Mark MCPs that won't be started as "inaccessible" (displayed as "Inactive" in the UI)
  3. UI improvements - Sort MCP list (connected first), add optional hiding of inactive MCPs, improve status display

Example Use Case

Global config (~/.config/opencode/opencode.jsonc):

{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "linear": { "type": "remote", "url": "https://mcp.example.com/linear" },
    "github": { "type": "remote", "url": "https://mcp.example.com/github" },
    "xcode": { "type": "local", "command": ["npx", "-y", "@example/xcode"] },
  },
  "tools": {
    // Disable all MCPs globally by default
    "linear_*": false,
    "github_*": false,
    "xcode_*": false,
  },
  "tui": {
    "sidebar": {
      "hide_inactive_mcp": true, // Optional: hide inactive MCPs from UI
    },
  },
}

Project config (~/project/.opencode/opencode.jsonc):

{
  "$schema": "https://opencode.ai/config.json",
  "tools": {
    // Enable only the MCPs this project needs
    "linear_*": true,
    "github_*": true,
    // xcode remains disabled (inherited from global)
  },
}

With this approach:

  • All MCP servers are defined once (global config)
  • Each project specifies which MCPs it needs (project config)
  • Only enabled MCPs start
  • Inactive MCPs can be hidden from the UI (cleaner interface)

Why this belongs in OpenCode

This feature enables a more efficient and scalable MCP configuration workflow:

  • Doesn't run unnecessary processes
  • Can choose to define MCPs once, enable per-project
  • Can see at a glance which MCPs are active vs inactive
  • Builds on OpenCode's existing layered config system (global + project)

Implementation notes

I have a reference implementation on my fork that includes:

  • Core accessibility checking logic (MCP.isAccessible())
  • New "inaccessible" status type
  • Sidebar UI improvements/tweaks (sorting, hiding inactive MCPs, better status display)
  • Unit tests
  • Documentation updates

Reference implementation here: https://github.com/jknlsn/opencode/

I haven't opened a PR yet as I wanted to discuss the feature idea first per the contributing guidelines!

What do you think?

  1. Does this align with OpenCode's goals?
  2. Should inactive MCPs be hidden by default, or should that be opt-in (as currently implemented)?
  3. Any concerns about the approach or edge cases to consider?
Originally created by @jknlsn on GitHub (Nov 19, 2025). ### Feature hasn't been suggested before. - [x] I have verified this feature I'm about to request hasn't been suggested before. ### Describe the enhancement you want to request ## Problem Currently, OpenCode starts all configured MCP servers regardless of whether any agent has access to their tools. The sidebar shows "Connected" MCPs, but it's not obvious whether they're actually usable or not. For example, if I have Linear, GitHub, and Xcode MCPs configured globally but disable them all with `"linear_*": false`, `"github_*": false`, `"xcode_*": false`, all three MCP servers still start up - they're just not accessible to agents. ## Proposed Solution Only start MCP servers that are accessible to at least one agent based on the `tools` configuration. This involves: 1. **Check accessibility before starting** - Before initializing an MCP server, check if any agent can access its tools 2. **Add "inaccessible" status** - Mark MCPs that won't be started as "inaccessible" (displayed as "Inactive" in the UI) 3. **UI improvements** - Sort MCP list (connected first), add optional hiding of inactive MCPs, improve status display ### Example Use Case **Global config** (`~/.config/opencode/opencode.jsonc`): ```jsonc { "$schema": "https://opencode.ai/config.json", "mcp": { "linear": { "type": "remote", "url": "https://mcp.example.com/linear" }, "github": { "type": "remote", "url": "https://mcp.example.com/github" }, "xcode": { "type": "local", "command": ["npx", "-y", "@example/xcode"] }, }, "tools": { // Disable all MCPs globally by default "linear_*": false, "github_*": false, "xcode_*": false, }, "tui": { "sidebar": { "hide_inactive_mcp": true, // Optional: hide inactive MCPs from UI }, }, } ``` **Project config** (`~/project/.opencode/opencode.jsonc`): ```jsonc { "$schema": "https://opencode.ai/config.json", "tools": { // Enable only the MCPs this project needs "linear_*": true, "github_*": true, // xcode remains disabled (inherited from global) }, } ``` With this approach: - All MCP servers are defined once (global config) - Each project specifies which MCPs it needs (project config) - Only enabled MCPs start - Inactive MCPs can be hidden from the UI (cleaner interface) ## Why this belongs in OpenCode This feature enables a more efficient and scalable MCP configuration workflow: - Doesn't run unnecessary processes - Can choose to define MCPs once, enable per-project - Can see at a glance which MCPs are active vs inactive - Builds on OpenCode's existing layered config system (global + project) ## Implementation notes I have a reference implementation on my fork that includes: - Core accessibility checking logic (`MCP.isAccessible()`) - New "inaccessible" status type - Sidebar UI improvements/tweaks (sorting, hiding inactive MCPs, better status display) - Unit tests - Documentation updates Reference implementation here: [https://github.com/jknlsn/opencode/](https://github.com/jknlsn/opencode/tree/dev) I haven't opened a PR yet as I wanted to discuss the feature idea first per the contributing guidelines! ## What do you think? 1. Does this align with OpenCode's goals? 2. Should inactive MCPs be hidden by default, or should that be opt-in (as currently implemented)? 3. Any concerns about the approach or edge cases to consider?
yindo added the discussion label 2026-02-16 17:38:08 -05:00
yindo closed this issue 2026-02-16 17:38:08 -05:00
Author
Owner

@vaughngit commented on GitHub (Dec 1, 2025):

+1 I was just trying to understand this myself

@vaughngit commented on GitHub (Dec 1, 2025): +1 I was just trying to understand this myself
Author
Owner

@rekram1-node commented on GitHub (Dec 2, 2025):

This is a little weird because you could blacklist all the mcp tools using wildcarding patterns that may not be relying on mcp server name... And then wed have to connect to all the mcp servers, get all the tools, then mark them as disconnected after....

I get what you are saying but the "tools":... just say if an agent has access to the tool or not, maybe the UI needs to make it more clear what tools are loaded for a given agent instead

@rekram1-node commented on GitHub (Dec 2, 2025): This is a little weird because you could blacklist all the mcp tools using wildcarding patterns that may not be relying on mcp server name... And then wed have to connect to all the mcp servers, get all the tools, then mark them as disconnected after.... I get what you are saying but the "tools":... just say if an agent has access to the tool or not, maybe the UI needs to make it more clear what tools are loaded for a given agent instead
Author
Owner

@jknlsn commented on GitHub (Dec 3, 2025):

Thanks for the feedback @rekram1-node. That's a good point about the tools, it's probably the wrong level for the outcome I want.

I think what I'm really trying to find a way to do, is to define MCP servers once in my global config and leave them disabled, and then be able to selectively enable for individual project configs without needing to define the entire MCP again. I can copy it to each relevant project manually, but then if say the command changes, I need to go update each project. Which is fine, but suboptimal.

After thinking about this more, I agree that using tools config for determining MCP startup conflates two concerns: tool access control vs process lifecycle.

Instead I've reworked my approach to use per-project MCP config overrides via the existing mcp key. This leverages the existing mergeDeep behaviour:

// ~/.config/opencode/opencode.jsonc
{
  "mcp": {
    "linear": { "type": "remote", "url": "..." , "enabled": false},
    "github": { "type": "remote", "url": "...", "enabled": false},
    "xcode": { "type": "local", "command": ["..."], "enabled": false}
  }
}
// ~/dev/project/.opencode/opencode.jsonc
{
  "mcp": {
    "linear": { "enabled": true },
    "github": { "enabled": true }
    // xcode not mentioned - uses global default
  }
}

I also right-aligned the MCP status messages to match the modified files layout, but I can remove this if preferred.

I've updated my reference implementation on my fork at https://github.com/jknlsn/opencode/ and I'm happy to open a PR if this direction makes sense!

@jknlsn commented on GitHub (Dec 3, 2025): Thanks for the feedback @rekram1-node. That's a good point about the tools, it's probably the wrong level for the outcome I want. I think what I'm really trying to find a way to do, is to define MCP servers once in my global config and leave them disabled, and then be able to selectively enable for individual project configs without needing to define the entire MCP again. I can copy it to each relevant project manually, but then if say the command changes, I need to go update each project. Which is fine, but suboptimal. After thinking about this more, I agree that using tools config for determining MCP startup conflates two concerns: tool access control vs process lifecycle. Instead I've reworked my approach to use per-project MCP config overrides via the existing mcp key. This leverages the existing mergeDeep behaviour: ```jsonc // ~/.config/opencode/opencode.jsonc { "mcp": { "linear": { "type": "remote", "url": "..." , "enabled": false}, "github": { "type": "remote", "url": "...", "enabled": false}, "xcode": { "type": "local", "command": ["..."], "enabled": false} } } ``` ```jsonc // ~/dev/project/.opencode/opencode.jsonc { "mcp": { "linear": { "enabled": true }, "github": { "enabled": true } // xcode not mentioned - uses global default } } ``` I also right-aligned the MCP status messages to match the modified files layout, but I can remove this if preferred. I've updated my reference implementation on my fork at [https://github.com/jknlsn/opencode/](https://github.com/jknlsn/opencode/tree/dev) and I'm happy to open a PR if this direction makes sense!
Author
Owner

@eXamadeus commented on GitHub (Dec 31, 2025):

Correct me if I'm wrong, but this issue is basically solved right? By disabling the MCPs at the user-level you can then enable them with a simple one-liner in your project-level configs.

Isn't this what you wanted? The other things you mentioned seem tangent to the original request (which seems solved). Let me know if I'm misunderstanding something.

@eXamadeus commented on GitHub (Dec 31, 2025): Correct me if I'm wrong, but this issue is basically solved right? By disabling the MCPs at the user-level you can then enable them with a simple one-liner in your project-level configs. Isn't this what you wanted? The other things you mentioned seem tangent to the original request (which seems solved). Let me know if I'm misunderstanding something.
Author
Owner

@jknlsn commented on GitHub (Dec 31, 2025):

No, I don't believe it's quite solved. I'd like the MCP to not start and not be connected, and using this config, no agent can use the MCP's but they are still connected. Unless I've misunderstood what you were suggesting by disabling the MCP's at the user-level and enabling with a one-liner in the project-level configs.

Here's a minimal config:

{
  "$schema": "https://opencode.ai/config.json",
  "tools": {
    "sosumi_*": false,
    "rfc-mcp_*": false
  },
  "mcp": {
    "sosumi": {
      "type": "remote",
      "url": "https://sosumi.ai/mcp",
      "enabled": true
    },
    "rfc-mcp": {
      "type": "local",
      "command": ["npx", "@mjpitz/mcp-rfc"],
      "enabled": true
    }
  }
}
Image

Sidebar, but I wasn't able to get the config with mcp-* approach you mentioned here to work on 1.0.222, not sure why.

So I think it's still useful, just based on the feedback from @rekram1-node I changed the implementation to be at the MCP level configuration not based on agent tools to separate the tool access control vs process lifecycle concerns.

@jknlsn commented on GitHub (Dec 31, 2025): No, I don't believe it's quite solved. I'd like the MCP to not start and not be connected, and using this config, no agent can use the MCP's but they are still connected. Unless I've misunderstood what you were suggesting by disabling the MCP's at the user-level and enabling with a one-liner in the project-level configs. Here's a minimal config: ```jsonc { "$schema": "https://opencode.ai/config.json", "tools": { "sosumi_*": false, "rfc-mcp_*": false }, "mcp": { "sosumi": { "type": "remote", "url": "https://sosumi.ai/mcp", "enabled": true }, "rfc-mcp": { "type": "local", "command": ["npx", "@mjpitz/mcp-rfc"], "enabled": true } } } ``` <img width="1081" height="466" alt="Image" src="https://github.com/user-attachments/assets/00eb14ec-2e9f-4a35-8ffe-2dbe9c635df8" /> Sidebar, but I wasn't able to get the config with `mcp-*` approach [you mentioned here](https://github.com/sst/opencode/issues/6543#issuecomment-3702887689) to work on 1.0.222, not sure why. So I think it's still useful, just based on the feedback from @rekram1-node I changed the implementation to be at the MCP level configuration not based on agent tools to separate the tool access control vs process lifecycle concerns.
Author
Owner

@eXamadeus commented on GitHub (Jan 1, 2026):

@jknlsn ahh, that provides some clarity.

OK so this original issue is a request to turn off MCPs based on whether any of the agents in scope have access to them, correct?

If so, this seems a non-issue because you can easily achieve this (as you already mentioned) by disabling the MCPs globally and only enabling the ones you want at the project level. In my mind, this is just a config tweak not worthy of a feature request.

To the second point about the wildcards not working, can you provide a more explicit example? I have it working locally quite well (this is literally the main reason I switched to OpenCode). I definitely want to see if we can get that working for you, since it's so useful.

@eXamadeus commented on GitHub (Jan 1, 2026): @jknlsn ahh, that provides some clarity. OK so this original issue is a request to turn off MCPs based on whether any of the agents in scope have access to them, correct? If so, this seems a non-issue because you can easily achieve this (as you already mentioned) by disabling the MCPs globally and only enabling the ones you want at the project level. In my mind, this is just a config tweak not worthy of a feature request. To the second point about the wildcards not working, can you provide a more explicit example? I have it working locally quite well (this is literally the main reason I switched to OpenCode). I definitely want to see if we can get that working for you, since it's so useful.
Author
Owner

@jknlsn commented on GitHub (Jan 1, 2026):

@eXamadeus I think we are still possibly looking at it from slightly different angles. I know I can restrict the agents from using the MCP's with tool configurations, but I don't want the MCP's to activate and connect at all in this case. So for the use case I am after the agent permissions are not really relevant, I just started looking at it from that direction before discussion. Instead the level for doing this isn't really at the agent layer at all, but instead just staying within the MCP configuration.

It's possible to configure MCP's globally and disable, and then enable per-project, only if you copy the entire configuration currently. So like this:

// Global config
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "linear": { "type": "remote", "url": "https://mcp.example.com/linear", "enabled": false },
    "github": { "type": "remote", "url": "https://mcp.example.com/github", "enabled": false },
    "xcode": { "type": "local", "command": ["npx", "-y", "@example/Xcode"], "enabled": false },
  }
}
// Project config
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "linear": { "type": "remote", "url": "https://mcp.example.com/linear", "enabled": true },
    "github": { "type": "remote", "url": "https://mcp.example.com/github", "enabled": true },
    "xcode": { "type": "local", "command": ["npx", "-y", "@example/Xcode"], "enabled": true },
  }
}

My PR here, pretty much just a config change, allows this to instead be done like so:

// Global config
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "linear": { "type": "remote", "url": "https://mcp.example.com/linear", "enabled": false },
    "github": { "type": "remote", "url": "https://mcp.example.com/github", "enabled": false },
    "xcode": { "type": "local", "command": ["npx", "-y", "@example/Xcode"], "enabled": false },
  }
}
// Project config
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "linear": { "enabled": true },
    "github": { "enabled": true },
    "xcode": { "enabled": true },
  }
}

The current state requires copying the configurations around between projects, and there isn't much point in defining the MCP's at the global level at all for this use case. If any MCP configuration changes, you need to update it in every project.

In the second example, because per-project the only thing that is happening is toggling the MCP to enabled by merging the configuration instead of requiring the entire configuration again, the global MCP configuration is useful.

Happy to update the issue description to clarify if that would help, I can see how it's not clear from the original description unless you read the full discussion!

@jknlsn commented on GitHub (Jan 1, 2026): @eXamadeus I think we are still possibly looking at it from slightly different angles. I know I can restrict the agents from using the MCP's with tool configurations, but I don't want the MCP's to activate and connect at all in this case. So for the use case I am after the agent permissions are not really relevant, I just started looking at it from that direction before discussion. Instead the level for doing this isn't really at the agent layer at all, but instead just staying within the MCP configuration. It's possible to configure MCP's globally and disable, and then enable per-project, only if you copy the entire configuration currently. So like this: ```jsonc // Global config { "$schema": "https://opencode.ai/config.json", "mcp": { "linear": { "type": "remote", "url": "https://mcp.example.com/linear", "enabled": false }, "github": { "type": "remote", "url": "https://mcp.example.com/github", "enabled": false }, "xcode": { "type": "local", "command": ["npx", "-y", "@example/Xcode"], "enabled": false }, } } ``` ```jsonc // Project config { "$schema": "https://opencode.ai/config.json", "mcp": { "linear": { "type": "remote", "url": "https://mcp.example.com/linear", "enabled": true }, "github": { "type": "remote", "url": "https://mcp.example.com/github", "enabled": true }, "xcode": { "type": "local", "command": ["npx", "-y", "@example/Xcode"], "enabled": true }, } } ``` [My PR here](https://github.com/sst/opencode/pull/5406), pretty much just a config change, allows this to instead be done like so: ```jsonc // Global config { "$schema": "https://opencode.ai/config.json", "mcp": { "linear": { "type": "remote", "url": "https://mcp.example.com/linear", "enabled": false }, "github": { "type": "remote", "url": "https://mcp.example.com/github", "enabled": false }, "xcode": { "type": "local", "command": ["npx", "-y", "@example/Xcode"], "enabled": false }, } } ``` ```jsonc // Project config { "$schema": "https://opencode.ai/config.json", "mcp": { "linear": { "enabled": true }, "github": { "enabled": true }, "xcode": { "enabled": true }, } } ``` The current state requires copying the configurations around between projects, and there isn't much point in defining the MCP's at the global level at all for this use case. If any MCP configuration changes, you need to update it in every project. In the second example, because per-project the only thing that is happening is toggling the MCP to enabled by merging the configuration instead of requiring the entire configuration again, the global MCP configuration is useful. Happy to update the issue description to clarify if that would help, I can see how it's not clear from the original description unless you read the full discussion!
Author
Owner

@eXamadeus commented on GitHub (Jan 3, 2026):

Ahh, I was under the impression the simple enable: true process worked already, not that it was a suggestion you had implemented. My apologies.

My recommendation would be to reframe this request as "enable proper MCP configuration merging from user to project level" or something similar. I see now that's what you were looking for, but I definitely didn't pick up on that immediately. Maybe that's just on me though, haha!

@eXamadeus commented on GitHub (Jan 3, 2026): Ahh, I was under the impression the simple `enable: true` process worked already, not that it was a suggestion you had implemented. My apologies. My recommendation would be to reframe this request as "enable proper MCP configuration merging from user to project level" or something similar. I see now that's what you were looking for, but I definitely didn't pick up on that immediately. Maybe that's just on me though, haha!
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: anomalyco/opencode#2986