You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[FEATURE] Let VERYFRONT_HOST_ALLOWED_INTERNAL_PROVIDER_ORIGINS (or a sibling) cover mcpServers on private addresses #5193
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
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.
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 (mcpServerstransport.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
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.
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.
Activity
kwakayama commentedon Oct 16, 2026
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:
guardedOutboundFetch(src/tool/remote-mcp.ts). Atransport.urlthat resolves to a private address is refused, which matches the logged "Outbound network egress blocked" warning from the remote tool definition fetch insrc/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.VERYFRONT_HOST_ALLOW_INTERNAL_EGRESS=1, which disables the private-network check for all host fetches.docs/guides/providers.mdandsrc/security/README.mddescribe the provider exception only. Neither themcpServersdocs nor the self-hosting guide mention that MCP cannot use it.Desired behavior:
VERYFRONT_HOST_ALLOWED_INTERNAL_MCP_ORIGINS. The maintainer decision between the two is open (see below).mcpServersand in the self-hosting guide andsrc/security/README.md. Update.env.exampleif a new variable is added.Key interfaces:
mcpServerstransport.url) and its outbound fetch.Acceptance criteria:
transport.urlorigin is on the host allowlist reaches a private or loopback server.Out of scope:
VERYFRONT_HOST_ALLOW_INTERNAL_EGRESSsemanticsVerification plan:
deno task test:file src/tool/remote-mcp.test.tsdeno task test:file src/security/http/outbound-fetch.test.tsdeno fmt --check,deno task lint:ci,deno task typecheck.github/workflows/cicd.ymlcovering unit tests, lint, and typecheck. Rundeno task docson 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
dberesford commentedon Oct 16, 2026
Correction from the author, after further testing on the same setup (veryfront 0.1.1276):
VERYFRONT_WORKER_ALLOWED_INTERNAL_HOSTSalready does what this issue asks for. The host-side guarded fetch reads it when noallowedInternalHostsoption is passed, so a comma-separated list of DNS names lets exactly those names resolve to internal addresses formcpServerstoo. 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 themcpServersdocumentation only mentionVERYFRONT_HOST_ALLOWED_INTERNAL_PROVIDER_ORIGINS.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_HOSTSbesidemcpServersand 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.