GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — feat(mcp): write native OpenCode 2 entries under mcp.servers by RamsesJM · Pull Request #3414 · microsoft/apm

Conversation

@RamsesJM

@RamsesJM RamsesJ.Dev (RamsesJM) commented Oct 29, 2026

Copy link
Copy Markdown

Description

Adds OpenCode 2 MCP support to the existing opencode target. When the target opencode.json already declares an mcp.servers map, APM writes native OpenCode 2 entries there; otherwise it keeps the current OpenCode 1 layout. No new target, flag or manifest field is introduced.

Why the format is selected from the file

  • OpenCode 1 and 2 read the same opencode.json locations, and both ship as opencode, so there is no version signal to detect (Migrate from V1).
  • OpenCode 2 reads the v1 layout, but OpenCode 1 cannot read mcp.servers. Emitting v2 by default would break existing v1 users.
  • An mcp.servers map is therefore an explicit, user-owned opt-in that never converts an installation silently, as the scope requires.

Behavior in the v2 layout

Manifest input Written to mcp.servers.<name>
enabled omitted or true no field (v2 default)
enabled: false disabled: true
any non-boolean enabled nothing; warning, file unchanged
extra: {codemode: false} codemode: false (existing passthrough)
  • A v1 entry with the same name is removed only when it is byte-for-byte what APM would have written; an edited entry is kept with a warning, and OpenCode 2 uses the mcp.servers entry.
  • mcp.timeout, user-owned servers and unrelated settings are preserved.
  • Stale cleanup prunes managed names from both mcp and mcp.servers, and never removes the servers map itself.
  • get_current_config() exposes the effective server set (v1 entries overlaid by mcp.servers), so conflict detection and installed-server checks no longer see servers or timeout as server names.

Implementation

File Change
src/apm_cli/adapters/client/opencode.py uses_native_v2() selection rule; _to_opencode_v2_format(); v2 write path in update_config(); v2-aware get_current_config() and render_server_config()
src/apm_cli/integration/mcp_integrator.py _clean_json_mcp_config() accepts an optional nested_servers accessor; OpenCode passes OpenCodeClientAdapter.native_v2_servers
docs/.../consumer/install-mcp-servers.md New "OpenCode v2 configuration" section: selection, opt-in, field mapping, migration limits
docs/.../reference/manifest-schema.md enabled row notes the v2 mapping
tests/unit/test_opencode_mcp_v2.py Selection rule, rendering, write path, legacy handling, effective view, stale cleanup
tests/integration/test_opencode_v2_lifecycle.py CLI install, stable reinstall, prune, non-boolean enabled

Trade-offs

  • File-based selection over a new option. Avoids new manifest or CLI surface and cannot misconfigure v1 users. The cost is that v2 users opt in once by adding "mcp": {"servers": {}}; this is documented.
  • Reject non-boolean enabled in v2. v1 passes any JSON value through unchanged, but v2 has no enabled field and inverting a non-boolean would be a guess. v1 behavior is unchanged.
  • No conversion of user-authored v1 entries. Only exact APM-written entries move. Edited entries stay, which can leave a harmless duplicate that OpenCode 2 resolves in favor of mcp.servers.
  • Passthrough stays verbatim. Fields in extra are not translated (for example camelCase v1 oauth keys); the docs tell authors to use v2 spelling. Translating them would extend passthrough semantics, which is out of scope.

Issue and approved scope

Issue: #3112

Human scope-approval comment: #3112 (comment)

This PR completes the recorded scope: native v2 stdio and HTTP entries with disabled and codemode, v1 preserved, and a documented non-destructive selection. It adds no opencode2 target, no new trust semantics, and no changes to other targets.

Fixes #3112

Type of change

  • Bug fix
  • New feature
  • Documentation
  • Maintenance / refactor

Testing

  • Tested locally
  • All existing tests pass
  • Added tests for new functionality (if applicable)

Full CI on the fork (Lint, both Build & Test shards, both Lifecycle Smoke shards, Spec conformance, Windows Compatibility, Architecture ratchets): RamsesJM#1.

How to test

  1. In a project with .opencode/, create opencode.json containing {"mcp": {"servers": {}}}.
  2. Declare a self-defined stdio server with enabled: false and an HTTP server with extra: {codemode: false} in apm.yml, targeting opencode.
  3. Run apm install: both entries appear under mcp.servers, the first with disabled: true, the second with codemode: false, and neither with enabled.
  4. Run apm install again: the file is byte-identical.
  5. Remove one server from apm.yml and reinstall: only that entry is removed. Without mcp.servers, output is the unchanged v1 layout.

Spec conformance (OpenAPM v0.1)

  • N/A -- this PR does not change OpenAPM-observable behaviour.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@RamsesJM
feat(mcp): write native OpenCode 2 entries under mcp.servers
0b263d0
OpenCode 1 and 2 share opencode.json locations, and OpenCode 1 cannot
read the v2 mcp.servers layout. Select the layout from the target file:
when it declares an mcp.servers map, write native v2 entries there;
otherwise keep the v1 layout, which OpenCode 2 also reads.

In the v2 layout, boolean enabled is written as disabled and other values
are rejected without touching the file. Extra fields such as codemode pass
through unchanged. A v1 entry of the same name is removed only when it is
unchanged from what APM wrote, and stale cleanup also prunes mcp.servers.

Refs microsoft#3112
Copilot AI balanced review requested due to automatic review settings October 29, 2026 01:33
@RamsesJM
RamsesJ.Dev (RamsesJM) requested review from Daniel Meppiel (danielmeppiel) and Sergio Sisternes (sergio-sisternes-epam) as code owners October 29, 2026 01:33
Copilot started reviewing on behalf of RamsesJ.Dev (RamsesJM) October 29, 2026 01:33
View session
@RamsesJM
docs(changelog): reference microsoft#3414 for OpenCode 2 MCP support
b74d54a
@RamsesJM

RamsesJ.Dev (RamsesJM) commented Oct 29, 2026

Copy link
Copy Markdown
Author

@microsoft-github-policy-service agree

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

Copilot AI reviewed Oct 29, 2026
View reviewed changes

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

🟡 Changes recommended

Pruning managed v2 servers can delete user-owned MCP settings and edited legacy entries, risking loss of configuration that should be preserved.

5 open issues
  • High severity Exclude adapter-defined settings from top-level MCP pruning · New
  • High severity Preserve independently owned legacy entries during v2 pruning · New
  • Medium severity Require type-sensitive enabled matching before legacy cleanup · New
  • Medium severity Trigger v2 migration after adding an empty MCP servers map · New
  • Medium severity Deny disabled passthrough from overriding modeled enabled values · New
What changed in this PR

Adds native OpenCode 2 MCP configuration support to the existing opencode target for #3112, while retaining the v1 layout unless the configuration explicitly opts in.

Changes:

  • Selects native v2 output from an existing mcp.servers map and translates boolean enabled values.
  • Extends configuration reads and stale-server cleanup to handle both layouts.
  • Adds component and CLI lifecycle coverage, documentation, and a changelog entry.
File Description
tests/​unit/​test_opencode_mcp_v2.py Tests layout selection, rendering, legacy handling, and cleanup.
tests/​integration/​test_opencode_v2_lifecycle.py Covers CLI install, reinstall, pruning, and non-boolean rejection.
src/​apm_cli/​integration/​mcp_integrator.py Adds nested server-map cleanup for OpenCode.
src/​apm_cli/​adapters/​client/​opencode.py Implements v2 selection, rendering, writes, and effective configuration reads.
docs/​src/​content/​docs/​reference/​manifest-schema.md Documents v2 handling of enabled.
docs/​src/​content/​docs/​consumer/​install-mcp-servers.md Explains opt-in, field mapping, and migration behavior.
CHANGELOG.md Records native OpenCode 2 MCP support.

Review effort: Balanced

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread src/apm_cli/integration/mcp_integrator.py Outdated
Comment on lines +172 to +174
removed = [
n for n in stale_names if n in servers and (nested is None or servers[n] is not nested)
]

@RamsesJM RamsesJ.Dev (RamsesJM) Oct 29, 2026

Copy link
Copy Markdown
Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

Fixed in 6117faf. In a v2 config, top-level pruning now skips mcp.servers and mcp.timeout (nested_settings), while a server with either name is still removed from mcp.servers. Covered by test_stale_name_never_removes_v2_settings.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread src/apm_cli/integration/mcp_integrator.py Outdated
Comment on lines +173 to +174
n for n in stale_names if n in servers and (nested is None or servers[n] is not nested)
]

@RamsesJM RamsesJ.Dev (RamsesJM) Oct 29, 2026

Copy link
Copy Markdown
Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

Fixed in 6117faf. A v1 entry is pruned only when mcp.servers does not declare the same name. After migration, a remaining same-named v1 entry is by construction one APM kept because it was edited, so it is left alone. Legacy-only entries are still pruned. Covered by test_kept_legacy_entry_survives_pruning_of_native_entry and test_legacy_only_entry_is_pruned_in_v2_file.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread src/apm_cli/adapters/client/opencode.py Outdated
for name, entry in rendered.items():
legacy = mcp.get(name) if name not in _V2_MCP_SETTINGS else None
if legacy is not None:
if legacy == self._to_opencode_format(config_updates[name], enabled=enabled):

@RamsesJM RamsesJ.Dev (RamsesJM) Oct 29, 2026

Copy link
Copy Markdown
Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

Fixed in 6117faf as suggested: the v1 entry is retired only when it equals the APM rendering and opencode_enabled_matches() holds. Covered by test_keeps_legacy_entry_whose_enabled_type_changed.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread src/apm_cli/adapters/client/opencode.py Outdated
Comment on lines +224 to +226
effective = {name: entry for name, entry in mcp.items() if name not in _V2_MCP_SETTINGS}
effective.update(mcp[_V2_SERVERS_KEY])
return {**config, "mcp": effective}

@RamsesJM RamsesJ.Dev (RamsesJM) Oct 29, 2026

Copy link
Copy Markdown
Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

Fixed in 6117faf. In a v2 config, get_current_config() now reports only mcp.servers entries, so a server still in the v1 layout counts as not installed and the next install writes its native entry and retires the matching v1 one. Covered by test_legacy_only_server_is_reported_as_needing_installation and the CLI scenario test_opencode_v1_install_moves_to_v2_after_opt_in.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread src/apm_cli/adapters/client/opencode.py
Comment on lines +338 to +341
entry = cls._to_opencode_format(copilot_entry, enabled=enabled)
del entry["enabled"]
if not enabled:
entry["disabled"] = True

@RamsesJM RamsesJ.Dev (RamsesJM) Oct 29, 2026

Copy link
Copy Markdown
Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

Fixed in 6117faf, but locally rather than in _HARNESS_EXTRA_ALIASES: Kiro forwards disabled as a legitimate extension field (KiroClientAdapter._copy_kiro_extensions), so reserving it globally would change another target, which #3112 excludes. The OpenCode v2 conversion now drops any passthrough disabled and derives it solely from enabled. Covered by test_modeled_enabled_overrides_disabled_passthrough.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@RamsesJM
fix(mcp): tighten OpenCode 2 ownership and migration rules
6117faf
- Keep mcp.timeout and other v2 settings out of top-level pruning.
- Prune a v1 entry only when mcp.servers does not declare the same name,
  so an edited entry kept during migration survives removal.
- Compare enabled by JSON type before retiring a v1 entry.
- Report only mcp.servers entries in a v2 config, so adding an empty map
  migrates existing servers on the next install.
- Derive disabled from enabled even when an extra field supplies it.
@RamsesJM

RamsesJ.Dev (RamsesJM) commented Oct 29, 2026

Copy link
Copy Markdown
Author

@microsoft-github-policy-service agree

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@sergio-sisternes-epam

Sergio Sisternes (sergio-sisternes-epam) commented Nov 3, 2026

Copy link
Copy Markdown
Collaborator

Thank you for contributing this pull request. The linked issue #3112 has status/accepted for the bounded OpenCode v2 MCP scope. This is a ready-for-review recommendation only, not merge or additional scope approval. CODEOWNERS review contacts Daniel Meppiel (@danielmeppiel) and Sergio Sisternes (@sergio-sisternes-epam) are already requested; a responsible maintainer must review the implementation.


Generated by autopilot-pr-triage-worker. This comment is AI-generated and may contain errors.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@sergio-sisternes-epam Sergio Sisternes (sergio-sisternes-epam) added area/mcp-config MCP server configuration depth, transports, variable resolution. theme/portability One manifest, every target. Multi-target deploy, marketplace, packaging, install. triage/recommended Automated advice completed; not human scope approval. type/feature New capability, new flag, new primitive. labels Nov 3, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

Copilot code review Copilot
Copilot review effort
Applies to this pull request for everyone.Learn more about Copilot code review.
Copilot left review comments
@danielmeppiel Daniel Meppiel (danielmeppiel) Awaiting requested review from danielmeppiel danielmeppiel is a code owner
@sergio-sisternes-epam Sergio Sisternes (sergio-sisternes-epam) Awaiting requested review from sergio-sisternes-epam sergio-sisternes-epam is a code owner

At least 0 approving reviews are required to merge this pull request.

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

area/mcp-config MCP server configuration depth, transports, variable resolution. theme/portability One manifest, every target. Multi-target deploy, marketplace, packaging, install. triage/recommended Automated advice completed; not human scope approval. type/feature New capability, new flag, new primitive.

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

[FEATURE] Support Opencode 2 MCP server configuration

Uh oh!

There was an error while loading. Please reload this page.

3 participants

@RamsesJM @sergio-sisternes-epam
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.