Skip to content

mcpx: Phase 2 of #1753 — client-side sampling enforcement (-32602 on undeclared tools, drop undeclared includeContext) #1756

Closed

Description

@dezren39

Phase 2 of #1753 — client-side sampling enforcement

Design: #1753 (mcpx sub-capability gating). Design doc: files/designs/code-mcpx-subcapability-gating.md in the keep-the-four-repos-healthy goal workspace. Origin: dezren39/nix#210. Independent of Phase 1 (different package, different boundary).

Problem (verified on main f6760a69)

Client.answer (pkgs/mcpx/internal/mcpclient/modern.go ~L277-296) refuses an elicitation whose mode was not declared, with -32602 ("Answering anyway would teach the server that undeclared works"). The adjacent sampling/createMessage case has no equivalent check: mcpx declares sampling as a bare {} (capabilities() ~L85-87 — no tools, no context), yet an upstream request carrying tools/toolChoice or includeContext is handed to the handler untouched. Conformance gap (internal/conformance/coverage_clientfeatures.go, tagged #210): sampling-client-error-on-tools-without-capability. Register SMP-03 records the spec's asymmetry: the schema gate says the client MUST error on tools it did not declare.

Scope (decisions recorded on #1753)

In pkgs/mcpx/internal/mcpclient, beside elicitModeDeclared:

  • A sampling shape check runs in Client.answer before the handler is invoked (shared by both eras, as answer already is).
  • tools or toolChoice present and no sampling.tools declared (today: always — the declaration is bare {}) → refuse with -32602 naming the undeclared sub-capability, mirroring the elicitation-mode refusal's shape and wording style. The handler is never invoked.
  • includeContext present and no sampling.context declared → drop the field, then proceed to the handler (context inclusion is expressly ignorable — conformance override sampling-client-may-ignore-includecontext; dropping preserves the plain completion the upstream asked for).
  • Do NOT start declaring sampling.tools or sampling.context upstream: the broker answers plain messages, and declaring more would recreate the original lie in the other direction.

Out of scope

Acceptance criteria

  • Tools-carrying upstream sampling request is refused with -32602 naming sampling.tools, and the handler is never invoked — in both eras (legacy wire request and modern input_required, since answer is shared).
  • Context-carrying request is answered with includeContext removed before the handler sees it.
  • Plain sampling request reaches the handler untouched; existing elicitation-mode tests still pass.
  • Conformance gap sampling-client-error-on-tools-without-capability retired from coverage_clientfeatures.go with a passing conformance row.
  • CI green (GitHub Actions; per fleet rule, no builds on the sandbox).

Activity

  1. added
    kind/bugSomething isn't working (prefixed form of the classic bug label)
    task/triageQueue packet kind: verify, reproduce, and route this item
    priority/normalOrdinary priority (the default)
    queue/queuedHas a queued task in the Supabase agent queue
    app/mcpxPackage/app: mcpx (pkgs/ or apps/ in this repo)
    effort/sSmall: expected under 2 hours of work
    on Oct 28, 2026
  2. developing-today commented on Oct 28, 2026

    @developing-today
    Contributor
  3. dezren39 commented on Oct 28, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · filed

  4. 61 remaining items

  5. added
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    status/parkedDeliberately paused with a recorded resume condition
    and removed
    status/parkedDeliberately paused with a recorded resume condition
    queue/claimedQueue worker lifecycle state
    on Oct 29, 2026
  6. dezren39 commented on Oct 29, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · parked

  7. dezren39 commented on Oct 29, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · picked up

  8. added a commit that references this issue on Oct 29, 2026
  9. removed
    status/parkedDeliberately paused with a recorded resume condition
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    work/assignedQueue worker lifecycle state
    on Oct 29, 2026
  10. dezren39 commented on Oct 29, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · done

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

Metadata

Metadata

Assignees

Labels

app/mcpxPackage/app: mcpx (pkgs/ or apps/ in this repo)effort/sSmall: expected under 2 hours of workkind/bugSomething isn't working (prefixed form of the classic bug label)priority/normalOrdinary priority (the default)source/design-architectFiled by the repo design architect jobstatus:donetask/triageQueue packet kind: verify, reproduce, and route this item

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions