Skip to content

[FEATURE] Let VERYFRONT_HOST_ALLOWED_INTERNAL_PROVIDER_ORIGINS (or a sibling) cover mcpServers on private addresses #5193

Open

Description

@dberesford

Problem Statement

The egress guard blocks private and loopback destinations by default, and the documented opt-in for an internal model endpoint is VERYFRONT_HOST_ALLOWED_INTERNAL_PROVIDER_ORIGINS, an exact list of origins the host operator allows (docs/guides/providers.md). That list applies to model providers only. An mcpServers entry whose transport.url resolves to a private address is refused before any request is sent:

! Failed to fetch remote tool definitions from source  sourceId=policies-mcp
  error="Outbound network egress blocked for host: agent-router.envoy-gateway-system.svc.cluster.local"

The only switch that lets it through is VERYFRONT_HOST_ALLOW_INTERNAL_EGRESS=1 (src/security/sandbox/worker-egress-guard.ts, outbound-fetch.ts), which turns the guard off for every outbound call of the application, not for one origin. In a Kubernetes deployment every MCP server is a private address, so an operator who follows the providers guide for the model still cannot reach an in-cluster MCP server without removing the guard entirely. Neither the mcpServers documentation nor the self-hosting guide says so.

Proposed Solution

Either extend VERYFRONT_HOST_ALLOWED_INTERNAL_PROVIDER_ORIGINS to MCP transports, or add a sibling host-owned variable such as VERYFRONT_HOST_ALLOWED_INTERNAL_MCP_ORIGINS with the same exact-origin semantics, and document it beside mcpServers. The project environment must not be able to grant it, as with the provider list today.

Component

Tools, Deployment

Alternatives Considered

  • VERYFRONT_HOST_ALLOW_INTERNAL_EGRESS=1. It works, but it removes the guard for all egress, which a platform that runs other people's agents should not do; a pod NetworkPolicy is a second layer, not a replacement for the first.
  • Exposing the MCP gateway on a public address so the guard allows it. That defeats the point of an in-cluster gateway.

Example Use Case

As a platform operator running a Veryfront app in Kubernetes, I want to allow exactly one in-cluster MCP gateway origin for mcpServers, the way I already allow the in-cluster model gateway for providers, so that the app can call governed remote tools without the egress guard being switched off for everything else.

Verification

  • I have searched the existing issues to make sure this is not a duplicate
  • I have provided sufficient context for the team to understand the request

Activity

  1. kwakayama commented on Oct 16, 2026

    @kwakayama
    Contributor

    This was generated by AI during triage.

    Agent Brief

    Category: enhancement

    Summary:
    Let a host operator allow exact private or loopback origins for remote MCP (mcpServers) transports without disabling the egress guard for all outbound calls.

    Current behavior:

    • Remote MCP tool sources fetch through guardedOutboundFetch (src/tool/remote-mcp.ts). A transport.url that resolves to a private address is refused, which matches the logged "Outbound network egress blocked" warning from the remote tool definition fetch in src/agent/runtime/tool-helpers.ts.
    • VERYFRONT_HOST_ALLOWED_INTERNAL_PROVIDER_ORIGINS (src/security/http/outbound-fetch.ts) is host-owned, exact-origin, and rejects paths, credentials, query strings and fragments. It applies only to origin-bound provider transports configured for the same origin. Project environment overlays cannot add origins.
    • The only switch that admits a private MCP origin today is VERYFRONT_HOST_ALLOW_INTERNAL_EGRESS=1, which disables the private-network check for all host fetches.
    • docs/guides/providers.md and src/security/README.md describe the provider exception only. Neither the mcpServers docs nor the self-hosting guide mention that MCP cannot use it.
    • No duplicate issue found. Closed Guarded egress: pooled sockets skip the pinned address lookup #3350 concerns pooled-socket address pinning, not this request.

    Desired behavior:

    • A host-owned allowlist of exact origins admits private or loopback destinations for remote MCP transports only. Either extend the existing variable's scope to MCP, or add a sibling such as VERYFRONT_HOST_ALLOWED_INTERNAL_MCP_ORIGINS. The maintainer decision between the two is open (see below).
    • Same semantics as the provider list: exact origin (scheme, host, port), the same parse validation and error messages, and no project-environment grant.
    • The exception is origin-bound. Redirects stay rejected, and every other internal destination stays blocked.
    • A provider-only origin must not silently become reachable by MCP (or the reverse) unless the chosen design says so explicitly.
    • Document the variable beside mcpServers and in the self-hosting guide and src/security/README.md. Update .env.example if a new variable is added.

    Key interfaces:

    • Remote MCP tool source transport (mcpServers transport.url) and its outbound fetch.
    • Host-owned internal-origin allowlist and the egress guard's origin-bound exception.
    • Project environment overlay boundary (must not grant the allowlist).

    Acceptance criteria:

    • A remote MCP source whose transport.url origin is on the host allowlist reaches a private or loopback server.
    • An MCP origin not on the list, and an origin allowed only for providers (if a sibling variable is chosen), is still refused.
    • Setting the variable through project environment overlays has no effect.
    • Invalid entries (paths, credentials, non-HTTP schemes) fail with the same validation as the provider list.
    • Redirects from an allowed MCP origin are still rejected.
    • Regression tests cover the above, and docs describe the behavior.
    • Relevant formatting, lint, typecheck, and CI checks pass
    • Existing behavior outside this issue remains unchanged

    Out of scope:

    • Unrelated refactors
    • Changes to VERYFRONT_HOST_ALLOW_INTERNAL_EGRESS semantics
    • OpenAPI, OAuth, or remote-module egress policy
    • New dependencies

    Verification plan:

    • deno task test:file src/tool/remote-mcp.test.ts
    • deno task test:file src/security/http/outbound-fetch.test.ts
    • deno fmt --check, deno task lint:ci, deno task typecheck
    • CI jobs in .github/workflows/cicd.yml covering unit tests, lint, and typecheck. Run deno task docs on the pinned Deno version if generated references change.

    Open decision for maintainers: extend the existing variable or add a sibling. A sibling keeps provider and MCP trust separate and matches the reporter's least-privilege goal. Note that the existing provider variable is already reused for non-provider origins (application auth, eval), so there is precedent for both.

    Handoff: ready for agent

    Thanks @dberesford. I reviewed the report against the current Veryfront Code implementation and reduced it to the Agent Brief above. The remaining work is bounded by the acceptance criteria and verification plan.


    Generated by Claude Code

  2. added
    enhancementNew feature or request
    securitySecurity vulnerability or hardening
    mediumMedium priority
    on Oct 16, 2026
  3. dberesford commented on Oct 16, 2026

    @dberesford
    Author

    Correction from the author, after further testing on the same setup (veryfront 0.1.1276):

    • VERYFRONT_WORKER_ALLOWED_INTERNAL_HOSTS already does what this issue asks for. The host-side guarded fetch reads it when no allowedInternalHosts option is passed, so a comma-separated list of DNS names lets exactly those names resolve to internal addresses for mcpServers too. With the gateway's hostname on that list and nothing else, the in-cluster MCP calls went through. I had missed it because the providers guide and the mcpServers documentation only mention VERYFRONT_HOST_ALLOWED_INTERNAL_PROVIDER_ORIGINS.
    • "turns the guard off for every outbound call" overstated VERYFRONT_HOST_ALLOW_INTERNAL_EGRESS=1: it skips the private-address rejections for all requests through the guarded fetch, while the scheme check, the refusal of URL credentials, redirect authorisation and address pinning stay.

    What remains of this issue is documentation: mention VERYFRONT_WORKER_ALLOWED_INTERNAL_HOSTS beside mcpServers and in the self-hosting guide, and say that the provider origins list does not cover MCP transports. Feel free to retitle or close as a docs request.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestmediumMedium prioritysecuritySecurity vulnerability or hardening

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions