Skip to content

fix(mcp): only complete the project, and only when nothing was scoped - #1116

Merged
codyde merged 1 commit into
masterfrom
cody/mcp-proxy-scoped-injection
Aug 21, 2026
Merged

fix(mcp): only complete the project, and only when nothing was scoped#1116
codyde merged 1 commit into
masterfrom
cody/mcp-proxy-scoped-injection

Conversation

@codyde

@codyde codyde commented Aug 21, 2026

Copy link
Copy Markdown
Collaborator

Fixes the link-context injection #1115 carried onto master. Not in a published release yet (v5.42.1 predates it, v5.43.0 is a draft).

Problem

Injection breaks explicit cross-project calls. From a directory linked to project A, asking about project B:

Call Result
get-logs + B's projectId + B's serviceId, no environment You don't have the required role (viewer)
Same, plus B's environmentId ✅ Works

The proxy filled environmentId from A's link; the server checked it against B's project and denied it.

Also: a serviceId from elsewhere with no projectId gets the linked project attached, so the error is No deployment found for this service and environment — which reads as "that service doesn't exist".

Solution

  1. Complete only projectId. environmentId/serviceId are subordinate to a project; the server defaults the environment where safe and requires both on destructive tools. LinkContext drops to one field.
  2. Complete nothing when the call names a scope (projectId, environmentId, serviceId, deploymentId) — that caller gets projectId Required and self-corrects.
  3. Completed requests carry x-railway-mcp-injected, so this is measurable. Recording it is a backboard follow-up.

Free, per ~80,000 local MCP calls on 2026-08-19:

project service calls
omitted omitted 39,791 (still served)
supplied supplied 31,842
supplied omitted 8,335
omitted supplied 0

Verified

Against production from a railbot-linked directory: no-args → railbot; foreign serviceIdprojectId Required; explicit cross-project → works (was broken). 15 link-context tests, 1,203 total, 0 clippy findings in proxy.rs.

No cutover — railway mcp unchanged. #1108 should be closed rather than merged; its content is already on master via #1115.

🤖 Generated with Claude Code

Live testing of the injection that #1115 carried onto master found it
corrupts explicitly cross-project calls, which is one of the things the
remote MCP is for.

Reproduced by hand: ask get-logs for another project's service and pass
that project's id, but omit the environment. The proxy filled the
environment from the directory link, the server checked the linked
environment against the caller's project, and denied the request with
"You don't have the required role (viewer) on this resource." Supplying
the environment explicitly made the same call succeed. Injection, not
permissions.

A second, quieter shape: a serviceId from elsewhere with no projectId got
the linked project stapled on, so the failure came back as "No deployment
found for this service and environment" — which reads to a model as "that
service does not exist" rather than "you did not say which project".

Two changes:

- Only projectId is completed. environmentId and serviceId are
  subordinate to a project; the server defaults the environment where
  that is safe and requires both explicitly on the destructive tools,
  where guessing is worse than asking. LinkContext collapses to the one
  field, so there is no longer a way to pair one project's id with
  another's resources.
- Nothing is completed when the call already names a projectId,
  environmentId, serviceId or deploymentId. A caller that named a
  resource has its own intent; it should get a plain "projectId Required"
  and correct itself, not a project we guessed.

This costs nothing measurable. Of ~80,000 successful local MCP calls on
2026-08-19, the project-omitted/service-supplied combination occurred
exactly zero times — callers supply full context or none — and the ~39,800
that supply none still get served, which is the population the injection
exists for.

Requests the proxy completed now carry x-railway-mcp-injected. Injection
is otherwise indistinguishable server-side from a caller's own argument,
so nothing could measure how often it fires or recognise it in a report of
"the agent looked at the wrong project".

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@codyde codyde added the release/patch Author patch release label Aug 21, 2026
@codyde
codyde merged commit 8f12c90 into master Aug 21, 2026
8 checks passed
@codyde
codyde deleted the cody/mcp-proxy-scoped-injection branch August 21, 2026 20:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

release/patch Author patch release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant