Skip to content

[feat] Enable user MCP servers by default (http; stdio stays off-by-design)#4912

Open
mmabrouk wants to merge 1 commit into
big-agentsfrom
feat/mcp-user-servers-default-on
Open

[feat] Enable user MCP servers by default (http; stdio stays off-by-design)#4912
mmabrouk wants to merge 1 commit into
big-agentsfrom
feat/mcp-user-servers-default-on

Conversation

@mmabrouk

@mmabrouk mmabrouk commented Jun 28, 2026

Copy link
Copy Markdown
Member

What this changes

User-declared MCP servers now resolve by default. Before, every deployment shipped with AGENTA_AGENT_MCPS_ENABLED=false, so an agent config that declared mcps failed with MCPDisabledError until the operator found and flipped the flag. After, the same config works out of the box; operators set the flag to false to opt out.

What default-on actually enables (scope check)

  • http servers only. stdio stays refused by design (it would run an arbitrary process on the runner host).
  • Claude-class harnesses only. Pi refuses user MCP; that is unchanged.
  • SSRF-guarded. validateUserMcpUrl requires https and rejects loopback, link-local, metadata, and private hosts, with AGENTA_AGENT_MCPS_HOST_ALLOWLIST as the escape hatch.

Owner ruling baked in: the guard's residual (DNS rebinding, redirect re-validation) stays tracked in #4911 and is out of MVP scope. The resolver docstrings and docs now say so explicitly.

This is a recut, not a rebase

The original branch was 516 commits behind and predated two renames (AGENTA_AGENT_MCP_SERVERS_ENABLED -> AGENTA_AGENT_MCPS_ENABLED, services/agent/ -> services/runner/). The branch was recut as one commit against current big-agents; the old history is gone by design.

Review guide (one commit, 19 files, ~5 minutes)

  • services/oss/src/agent/tools/resolver.py is the only behavior change: _mcp_enabled() defaults to "true". Everything else is deployment defaults and docs following it.
  • 7 compose files, railway, helm _helpers.tpl: one-line false -> true flips.
  • 4 env examples: the commented default line now documents true.
  • Judgment call worth a look: the three Helm example values files re-add a minimal commented agentRunner: block. A prior cleanup deleted the whole block, so self-hosters had no example to uncomment even though values.schema.json still documents the shape.
  • Tests: new test_mcp_enabled_by_default_when_unset; the two disabled-path tests now set false explicitly. 6 passed.
  • running-the-agent.md stops claiming default false. The other design docs that mention the default are being edited on the feat(agent): deliver client tools to Claude over the internal MCP channel #4985 lane, so they get one docs pass after both merge (avoids a cross-lane conflict).

How to QA

Unset the flag, declare an https MCP server with a vault secret, run on Claude: the server resolves and its tools are callable. Set the flag to false: the same config fails loud with MCPDisabledError.

https://claude.ai/code/session_01HhBEUFbXETNjYdcz71AGrT

@dosubot dosubot Bot added the size:M This PR changes 30-99 lines, ignoring generated files. label Jun 28, 2026
@vercel

vercel Bot commented Jun 28, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
agenta-documentation Ready Ready Preview, Comment Jul 4, 2026 5:45pm

Request Review

@coderabbitai

coderabbitai Bot commented Jun 28, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

AGENTA_AGENT_MCP_SERVERS_ENABLED is flipped from false to true as the default across all hosting configurations (Docker Compose OSS/EE, Kubernetes, Railway). The Python resolver's _mcp_enabled() is updated to treat an unset flag as enabled, the SSRF guard comment is revised, and tests are updated to match.

MCP Default-On Enablement

Layer / File(s) Summary
Resolver logic and default-on behavior
services/oss/src/agent/tools/resolver.py, services/agent/src/engines/sandbox_agent/mcp.ts, services/oss/tests/pytest/unit/agent/tools/test_resolution.py
_mcp_enabled() now defaults AGENTA_AGENT_MCP_SERVERS_ENABLED to "true" when unset; module docs and SSRF guard comment updated; tests add a test_mcp_enabled_by_default_when_unset case and update disabled-state tests to explicitly set the flag to "false".
Hosting config defaults
hosting/docker-compose/oss/..., hosting/docker-compose/ee/..., hosting/kubernetes/..., hosting/railway/oss/scripts/configure.sh
All Docker Compose, Kubernetes Helm, and Railway configurations change the AGENTA_AGENT_MCP_SERVERS_ENABLED default (or enableMcp) from false to true, including example env files.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related issues

Possibly related PRs

  • Agenta-AI/agenta#4871: Modifies the same resolver.py MCP gating logic and related tests that this PR builds on.
  • Agenta-AI/agenta#4899: Touches the same SSRF guard documentation in mcp.ts that this PR updates.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 60.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 clearly states the main change: enabling user MCP servers by default, with stdio noted as still off by design.
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 description matches the patch theme: enabling user-declared MCP servers by default and updating deployment defaults, tests, and docs accordingly.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/mcp-user-servers-default-on

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.

@mmabrouk mmabrouk added the needs-review Agent updated; awaiting Mahmoud's review label Jun 28, 2026
@mmabrouk

Copy link
Copy Markdown
Member Author

🤖 The AI agent says:

Changes made

This flips user MCP servers to on by default, per your direction that MCP should not be off by default.

  • The service resolver (services/oss/src/agent/tools/resolver.py) now defaults the gate to on: an unset AGENTA_AGENT_MCP_SERVERS_ENABLED enables user MCP.
  • Every deployment default is flipped to match: 7 docker-compose files, 4 env.*.example files, the Helm chart (values.yaml + _helpers.tpl) with its oss/ee example values, and the Railway configure.sh.
  • Only user-declared mcpServers are gated. The internal agenta-tools channel was never gated, so it is unaffected.
  • http user MCP is verified working end-to-end behind the runner's https + SSRF guards. stdio user MCP still fails loud (disabled by design), so default-on does not expose stdio.
  • Tests: a new test pins the default-on behavior, and the two disabled-path tests now set the flag false explicitly. The services unit suite for this file passes (6 passed).

Decision needed (this is a design call, not a code review)

The runner's http SSRF guard is scheme + host only. It does not pin DNS resolution to the validated host, and it does not re-validate redirects. With user MCP now on by default, an author-controlled config could reach an internal host through DNS rebinding or an https->internal redirect. Secrets ride headers only to https hosts, so the blast radius is bounded, but this is a real residual for an OSS default-on.

Options:

  1. Harden first — land DNS-resolution pinning + manual-redirect re-validation ((feat) Harden user-MCP http SSRF guard (DNS rebinding + redirects) for OSS default-on #4911) before this default-on ships.
  2. Ship default-on now, harden next — merge this and track the residual in (feat) Harden user-MCP http SSRF guard (DNS rebinding + redirects) for OSS default-on #4911.

My recommendation: option 2 if this rides only on big-agents / cloud, where egress is already constrained; option 1 if it can reach an OSS self-host build. Once you pick, I will queue the matching work.

What I need from you: the decision above, harden-first vs ship-with-residual. The code change is a one-line default flip plus the matching deployment defaults; a quick correctness skim is welcome, but the real ask is the security call.

Do not merge. I am leaving this for you / the orchestrator to fold back.

# runner's https + SSRF guards; stdio servers still fail loud (disabled by design). Set
# the flag to a falsy value to turn user MCP servers off entirely.
return (
os.getenv("AGENTA_AGENT_MCP_SERVERS_ENABLED", "true").strip().lower() in TRUTHY

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

🤖 The AI agent says: This is the whole behavior change: the default moved from "" (off) to "true" (on). An unset AGENTA_AGENT_MCP_SERVERS_ENABLED now enables user MCP. To turn it back off, set the flag to any falsy value. Everything else in this PR is the matching deployment defaults.

* - reject loopback, link-local (incl. the `169.254.169.254` cloud metadata host), and private
* address literals unless the host is in `AGENTA_AGENT_MCP_HOST_ALLOWLIST` (comma-separated).
*
* RESIDUAL (tracked in #4911): the guard does NOT pin DNS resolution to the validated host and

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

🤖 The AI agent says: This is the residual behind the decision. The guard validates scheme + host but does not pin DNS resolution or re-validate redirects, so DNS rebinding or an https->internal redirect can still reach an internal sink. Bounded (secrets ride headers only to https hosts) but real now that the flag defaults on. Hardening is tracked in #4911.

@mmabrouk

Copy link
Copy Markdown
Member Author

🤖 The AI agent says: triggering an automated review.

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 28, 2026

Copy link
Copy Markdown

@mmabrouk Reviewing the changes now.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@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: 4


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: d9caf658-3bfc-47eb-886c-2b00d46ecbd0

📥 Commits

Reviewing files that changed from the base of the PR and between 1e55134 and f209643.

📒 Files selected for processing (19)
  • hosting/docker-compose/ee/docker-compose.dev.yml
  • hosting/docker-compose/ee/docker-compose.gh.local.yml
  • hosting/docker-compose/ee/docker-compose.gh.yml
  • hosting/docker-compose/ee/env.ee.dev.example
  • hosting/docker-compose/ee/env.ee.gh.example
  • hosting/docker-compose/oss/docker-compose.dev.yml
  • hosting/docker-compose/oss/docker-compose.gh.local.yml
  • hosting/docker-compose/oss/docker-compose.gh.ssl.yml
  • hosting/docker-compose/oss/docker-compose.gh.yml
  • hosting/docker-compose/oss/env.oss.dev.example
  • hosting/docker-compose/oss/env.oss.gh.example
  • hosting/kubernetes/ee/values.ee.example.yaml
  • hosting/kubernetes/helm/templates/_helpers.tpl
  • hosting/kubernetes/helm/values.yaml
  • hosting/kubernetes/oss/values.oss.example.yaml
  • hosting/railway/oss/scripts/configure.sh
  • services/agent/src/engines/sandbox_agent/mcp.ts
  • services/oss/src/agent/tools/resolver.py
  • services/oss/tests/pytest/unit/agent/tools/test_resolution.py

DOCKER_NETWORK_MODE: ${DOCKER_NETWORK_MODE:-bridge}
AGENTA_AGENT_RUNNER_URL: ${AGENTA_AGENT_RUNNER_URL:-http://sandbox-agent:8765}
AGENTA_AGENT_MCP_SERVERS_ENABLED: ${AGENTA_AGENT_MCP_SERVERS_ENABLED:-false}
AGENTA_AGENT_MCP_SERVERS_ENABLED: ${AGENTA_AGENT_MCP_SERVERS_ENABLED:-true}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Don't enable user MCP by default in self-hosted compose until the runner hardening lands.

Line 456 turns this OSS compose stack into opt-out for author-controlled HTTP MCP even though the PR notes the runner guard still lacks DNS pinning and redirect re-validation. In this same topology, services already gets host.docker.internal:host-gateway, so the residual SSRF path becomes reachable on default installs instead of only on explicit opt-in. Keep the self-hosted compose/env default false until the runner fix ships.

Suggested minimal mitigation
-            AGENTA_AGENT_MCP_SERVERS_ENABLED: ${AGENTA_AGENT_MCP_SERVERS_ENABLED:-true}
+            AGENTA_AGENT_MCP_SERVERS_ENABLED: ${AGENTA_AGENT_MCP_SERVERS_ENABLED:-false}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
AGENTA_AGENT_MCP_SERVERS_ENABLED: ${AGENTA_AGENT_MCP_SERVERS_ENABLED:-true}
AGENTA_AGENT_MCP_SERVERS_ENABLED: ${AGENTA_AGENT_MCP_SERVERS_ENABLED:-false}

- SCRIPT_NAME=/services
- AGENTA_AGENT_RUNNER_URL=${AGENTA_AGENT_RUNNER_URL:-http://sandbox-agent:8765}
- AGENTA_AGENT_MCP_SERVERS_ENABLED=${AGENTA_AGENT_MCP_SERVERS_ENABLED:-false}
- AGENTA_AGENT_MCP_SERVERS_ENABLED=${AGENTA_AGENT_MCP_SERVERS_ENABLED:-true}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Keep MCP disabled by default in the OSS compose stack. Defaulting AGENTA_AGENT_MCP_SERVERS_ENABLED to true exposes self-hosted installs to the MCP SSRF surface before the HTTP guard hardening lands.

{{- end }}
- name: AGENTA_AGENT_MCP_SERVERS_ENABLED
value: {{ default false $runner.enableMcp | quote }}
value: {{ default true $runner.enableMcp | quote }}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Preserve explicit false for enableMcp

default treats false as empty here, so agentRunner.enableMcp: false still renders "true". Use a nil/hasKey check instead if the chart needs to support disabling MCP.

Comment on lines +25 to +30
# On by default: an unset flag enables user MCP servers. http servers run behind the
# runner's https + SSRF guards; stdio servers still fail loud (disabled by design). Set
# the flag to a falsy value to turn user MCP servers off entirely.
return (
os.getenv("AGENTA_AGENT_MCP_SERVERS_ENABLED", "true").strip().lower() in TRUTHY
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Keep the unset default opt-in until the runner hardening lands.

services/agent/src/engines/sandbox_agent/mcp.ts:44-48 now explicitly documents that DNS rebinding and HTTPS→internal redirects can still bypass the current guard. Making _mcp_enabled() return True when the flag is unset exposes that residual in fresh OSS/self-hosted installs that never opted into user MCP. Please keep the unset default falsy here (or scope default-on to controlled environments only) until that hardening ships.

@linear-code

linear-code Bot commented Jun 28, 2026

Copy link
Copy Markdown

AGE-3843

…f-by-design)

Recut of the stale #4912 against the current tree (new flag name
AGENTA_AGENT_MCPS_ENABLED, post runner-rename). Unset now means enabled; set
the flag to false to disable. What default-on activates: http-only user MCP,
Claude-harness-only, behind the scheme+host-literal SSRF guard. Owner ruling:
the DNS-rebinding/redirect hardening stays tracked in #4911, out of MVP scope.

- resolver.py: _mcp_enabled() defaults to true; docstrings state the new
  default and the #4911 residual.
- 7 compose files + railway + helm _helpers.tpl: :-false -> :-true.
- 4 env examples: documented default flipped (kept commented).
- Helm example values: re-add the minimal commented agentRunner block that a
  prior cleanup deleted (values.schema.json still documents the shape, but
  self-hosters had no example line to uncomment).
- tests: new test_mcp_enabled_by_default_when_unset; the disabled-path tests
  now set the flag to false explicitly.
- running-the-agent.md: stop claiming default false.

Claude-Session: https://claude.ai/code/session_01HhBEUFbXETNjYdcz71AGrT
@mmabrouk mmabrouk force-pushed the feat/mcp-user-servers-default-on branch from f209643 to 7003fe5 Compare July 4, 2026 17:43
@mmabrouk

mmabrouk commented Jul 4, 2026

Copy link
Copy Markdown
Member Author

Ready for review. What I need from you: (1) OK the default-on-with-#4911-open framing as written in the resolver docstring, and (2) OK the re-added commented agentRunner example block in the three Helm values files (a cleanup had deleted it; without it self-hosters have no line to uncomment). Everything else is one-line default flips. Tests: 6/6 on the touched file.

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

Labels

Backend feature needs-review Agent updated; awaiting Mahmoud's review size:M This PR changes 30-99 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant