Skip to content

mcp: a cold connection receives the hidden option's target, token and route #104

Description

@carldebilly

Carved out of #95, whose item 3 is otherwise internal quality. This is the one part of it a remote
client can observe.

What reaches the client

McpServerHandler.ThrowSanitizedIfAClientAlreadyHasASchema replaces the failure with a generic
McpException only when a snapshot has already been served on that connection. On the first
request of a connection there is no previous snapshot, so the original HiddenRequiredOptionException
is rethrown and its message travels verbatim:

Option target '<parameterName>' (rendered as '<token>') for command '<route>' cannot be hidden
because it is required. Either drop the Required/Arity constraint on the option, or hide a
different one.

That is the option's target, its rendered token and its route — precisely the identity that hiding the
option was meant to withhold.

Why it is worth revisiting rather than a plain oversight

The asymmetry is deliberate and the comment above the method says so: a cold-start failure is a
configuration error whose reader is the operator at the console, so letting the detail through tells
them which option and route are misconfigured. That premise held while a Repl app had one local
operator.

It stopped holding when the caller became a concurrent, potentially remote MCP client. On the
mcp serve path the reader of the first request's failure is the client, not the operator — and the
same connection's second request would be sanitised, so the disclosure is not even consistent within
one session.

Shape

Sanitise unconditionally, and log the detail server-side so the operator keeps what the current
behaviour was protecting. That ordering is the reason this is blocked on #99: src/Repl.Mcp has
nowhere to log today, so sanitising first would trade a disclosure for a silent failure.

Guard belongs beside the existing snapshot-failure tests: a cold connection whose app hides a required
option must receive the generic message, and the operator sink must carry the option target and route.

Milestoned 0.12.0 — it is a disclosure on a surface that shipped in #71.

Activity

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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions