Skip to content

feat: superposition MCP server (smithy-generated)#1002

Draft
knutties wants to merge 20 commits into
mainfrom
design/mcp-server
Draft

feat: superposition MCP server (smithy-generated)#1002
knutties wants to merge 20 commits into
mainfrom
design/mcp-server

Conversation

@knutties
Copy link
Copy Markdown
Collaborator

Summary

Adds a Model Context Protocol (MCP) server that exposes the Superposition API as MCP tools, generated from the existing Smithy models.

  • crates/superposition_mcp — generated MCP wrapper crate produced by smithy-mcp-codegen. One MCP tool per @mcpTool-annotated Smithy operation (organisations, workspaces, dimensions, default-config, contexts, experiments, experiment groups, functions, type templates, variables, secrets, webhooks, audit logs, config).
  • crates/superposition_mcp_server — thin binary (superposition-mcp) wiring the generated tools to a transport.
    • stdio transport for direct client embedding; credentials come from SUPERPOSITION_BEARER_TOKEN or SUPERPOSITION_BASIC_USER / SUPERPOSITION_BASIC_PASS env vars.
    • HTTP+SSE transport (--http <addr>) with per-request Authorization passthrough; task-local auth scope means concurrent clients don't bleed credentials. --allow-static-auth opts into env-var fallback when a request has no header.
    • Workspace/org defaults can be injected from SUPERPOSITION_WORKSPACE_ID / SUPERPOSITION_ORG_ID so clients can omit them on every call.
  • Smithy build wiring@mcpTool annotations on operations, smithy-mcp-codegen registered in smithy-build.json, vendored smithy-mcp-codegen / smithy-mcp-traits JARs under smithy/maven-local/, makefile target for codegen, and a small mcp-rust.patch for the generated output.
  • Design + plan docs under .claude/plans/.

Sized at ~12.6k LOC, of which the generated superposition_mcp crate (conversions.rs, tools.rs, types.rs, server.rs) is ~8.2k — review effort is concentrated in superposition_mcp_server/ (config, auth, dispatch, transport) and the Smithy model annotations.

Test plan

  • cargo build -p superposition_mcp_server
  • cargo test -p superposition_mcp_server (includes the wiremock integration test covering tool dispatch + auth passthrough)
  • Smoke: launch in HTTP mode against a local Superposition (SUPERPOSITION_ENDPOINT=http://127.0.0.1:8080 superposition-mcp --http 127.0.0.1:8765 --allow-static-auth) and exercise ListOrganisationListWorkspaceListExperiment via an MCP client
  • Smoke: stdio mode with SUPERPOSITION_BEARER_TOKEN set
  • Verify per-request Authorization header is forwarded (and not leaked across concurrent requests)
  • Regenerate via make smithy-mcp and confirm the diff is empty (codegen is reproducible)

🤖 Generated with Claude Code

knutties added 20 commits May 11, 2026 19:16
Captures the design for integrating juspay/smithy-mcp-generator into
this repo: a generated superposition_mcp library crate plus a
hand-written superposition_mcp_server binary crate, both regenerated
when smithy models change. Covers crate layout, smithy model
annotations, build/CI wiring, CLI surface, auth (static + HTTP
passthrough), error mapping, testing strategy, and dependency
sourcing (transitional bundled JAR for the codegen plugin, git-ref
for smithy-mcp-runtime).
14 tasks covering: bundling the smithy-mcp-codegen JARs, wiring the
smithy-build plugin, annotating ~85 operations with @mcptool,
integrating the generated crate into the workspace, scaffolding the
binary crate with config / auth / dispatch / transport modules, and a
wiremock-backed integration test that asserts both tool count parity
with the smithy models and Authorization-header passthrough.

References the design spec at
docs/superpowers/specs/2026-05-11-superposition-mcp-server-design.md.
Transitional local Maven repo for the MCP-server smithy build plugin
and trait. See smithy/maven-local/README.md for the build recipe and
migration note tracked in
docs/superpowers/specs/2026-05-11-superposition-mcp-server-design.md
§11.4.
Adds the mcp-rust plugin entry and points SMITHY_MAVEN_REPOS at the
bundled local Maven repo. Smithy build is a no-op for MCP output until
@mcptool annotations are added on operations (next task).
Every operation in the io.superposition#Superposition service is
exposed as an MCP tool. Descriptions come from each operation's
existing @documentation trait via the generator's fallback (see
juspay/smithy-mcp-generator#5).
Patches generated Cargo.toml to inherit workspace fields, mirroring
the superposition_sdk pattern.
Rebundles smithy-mcp-codegen + smithy-mcp-traits from the combined
state of juspay/smithy-mcp-generator PR #6 (maven-publish gradle
config) and PR #7 (smithy-rs fluent-builder interop via From-based
bridging). Also bumps the smithy-mcp-runtime git ref in the patch to
the same SHA so the generated tools.rs and conversions.rs use the
runtime helpers (datetime_to_string, document_to_value, etc.) added
in PR #7.

Pins to juspay/smithy-mcp-generator HEAD 23080286 of branch
feat/smithy-rs-fluent-builder-interop until PR #7 merges to main.
Generated crate from smithy-mcp-generator. Patch redirects
smithy-mcp-runtime to a git ref (it is not yet on crates.io).
README and CHANGELOG are hand-preserved via git-restore in the
smithy-clients make target.
Rebundles smithy-mcp-codegen with juspay/smithy-mcp-generator PR #8
(commit 522aa24) on top of merged PR #7. PR #8 fixes four classes of
codegen gaps that blocked compiling the generated MCP crate against
the real smithy-rs SDK in this repo:

  1. Walk union variant target structures into types.rs emission.
  2. Harden StructureGenerator fallback (typed struct refs, bare
     String, user-namespaced Timestamp → String, no silent Value
     fallback for unrecognized shapes).
  3. Detect fallible smithy-rs builder.build() and emit .expect().
  4. Inline map-value conversions to avoid nested-closure E0282.

Also bumps chrono (0.4.34 → 0.4.44) and tokio-util in Cargo.lock to
satisfy rmcp 1.6.0's transitive requirements (rmcp comes in via
smithy-mcp-runtime). No source change in this repo required for that
bump.
Generated by smithy-mcp-generator from smithy/models/*.smithy. Re-run
make smithy-clients to regenerate.
Stub main; real wiring lands in subsequent commits.
Hand-rolled router builder wraps each generated tool handler with the
workspace/org default injection. The ~85-line tool registration block
is regenerated from crates/superposition_mcp/src/tools.rs by the
script in the comment above register!.
Mounts rmcp's StreamableHttpService under /mcp on an Axum router.
A tower middleware extracts the inbound Authorization header, parses
it into AuthValue, and wraps the inner service call in
SUPERPOSITION_AUTH.scope so the smithy-rs ResolveIdentity
implementations can read it per-request. --allow-static-auth enables
fallback to env-var creds when the header is absent.
…h passthrough

Refactors build_client / build_router out of main.rs into a lib target
so the integration test can call them directly without duplicating the
~85-tool registration list.
The smithy-rs SDK lists HTTP_BASIC_AUTH_SCHEME_ID first in every
operation's auth-options vector, and the orchestrator does not fall
back to subsequent schemes when the first resolver returns Err. So a
client sending Authorization: Bearer <token> would hit BasicResolver
first, get an error, and never reach the wire.

Fix: install a TaskLocalAuthSchemePlugin that overrides the SDK's
default StaticAuthSchemeOptionResolver with one that reads
SUPERPOSITION_AUTH at request time and returns the single scheme that
matches the credential variant. The fallback (used when the
task-local is unset in stdio mode or HTTP --allow-static-auth) comes
from the static-credential variant configured at startup.

Adds a regression test (passthrough_bearer_auth_reaches_the_wire) so
this can't silently break again. Also bumps the smithy-mcp-generator
git ref to main's merge SHA 6ec7445 (smithy-mcp-generator PR #8 is
now merged) and fixes two collapsible-if clippy lints in dispatch.rs
by switching to Map::entry().or_insert_with().
The Axum middleware's SUPERPOSITION_AUTH.scope only wrapped the
initialize request's future. rmcp's stateful StreamableHttpService
spawns a long-running session task during initialize; subsequent
tools/call requests are routed into that session task's queue, where
they execute with the session task's task-local context (set from
the initialize request's auth) — not the new request's.

Fix: introduce an AuthRouter that wraps the inner smithy_mcp_runtime
Router and implements ServerHandler::call_tool by extracting auth
from the per-request RequestContext (rmcp stores
http::request::Parts in context.extensions) and re-entering
SUPERPOSITION_AUTH.scope around the inner dispatch. This runs in
whatever task rmcp dispatches the handler in, so each request sees
its own auth — regardless of session affinity.

Smoke-tested end-to-end against a local Superposition: two
concurrent HTTP sessions with different schemes (Bearer + Basic)
both succeed; no-auth requests still get 401 at the Axum layer.
@semanticdiff-com
Copy link
Copy Markdown

semanticdiff-com Bot commented May 13, 2026

Review changes with  SemanticDiff

Changed Files
File Status
  smithy/smithy-build.json  19% smaller
  Cargo.lock Unsupported file format
  Cargo.toml Unsupported file format
  crates/superposition_mcp/CHANGELOG.md Unsupported file format
  crates/superposition_mcp/Cargo.toml Unsupported file format
  crates/superposition_mcp/README.md Unsupported file format
  crates/superposition_mcp/src/conversions.rs  0% smaller
  crates/superposition_mcp/src/lib.rs  0% smaller
  crates/superposition_mcp/src/server.rs  0% smaller
  crates/superposition_mcp/src/tools.rs  0% smaller
  crates/superposition_mcp/src/types.rs  0% smaller
  crates/superposition_mcp_server/Cargo.toml Unsupported file format
  crates/superposition_mcp_server/src/auth.rs  0% smaller
  crates/superposition_mcp_server/src/build.rs  0% smaller
  crates/superposition_mcp_server/src/config.rs  0% smaller
  crates/superposition_mcp_server/src/dispatch.rs  0% smaller
  crates/superposition_mcp_server/src/lib.rs  0% smaller
  crates/superposition_mcp_server/src/main.rs  0% smaller
  crates/superposition_mcp_server/src/transport_http.rs  0% smaller
  crates/superposition_mcp_server/tests/integration.rs  0% smaller
  docs/superpowers/plans/2026-05-11-superposition-mcp-server.md Unsupported file format
  docs/superpowers/specs/2026-05-11-superposition-mcp-server-design.md Unsupported file format
  makefile Unsupported file format
  smithy/maven-local/README.md Unsupported file format
  smithy/maven-local/in/juspay/smithy/smithy-mcp-codegen/0.1.0/smithy-mcp-codegen-0.1.0.jar Unsupported file format
  smithy/maven-local/in/juspay/smithy/smithy-mcp-codegen/0.1.0/smithy-mcp-codegen-0.1.0.module Unsupported file format
  smithy/maven-local/in/juspay/smithy/smithy-mcp-codegen/0.1.0/smithy-mcp-codegen-0.1.0.pom Unsupported file format
  smithy/maven-local/in/juspay/smithy/smithy-mcp-codegen/maven-metadata-local.xml  0% smaller
  smithy/maven-local/in/juspay/smithy/smithy-mcp-traits/0.1.0/smithy-mcp-traits-0.1.0.jar Unsupported file format
  smithy/maven-local/in/juspay/smithy/smithy-mcp-traits/0.1.0/smithy-mcp-traits-0.1.0.module Unsupported file format
  smithy/maven-local/in/juspay/smithy/smithy-mcp-traits/0.1.0/smithy-mcp-traits-0.1.0.pom Unsupported file format
  smithy/maven-local/in/juspay/smithy/smithy-mcp-traits/maven-metadata-local.xml  0% smaller
  smithy/models/audit.smithy Unsupported file format
  smithy/models/config.smithy Unsupported file format
  smithy/models/context.smithy Unsupported file format
  smithy/models/default-config.smithy Unsupported file format
  smithy/models/dimension.smithy Unsupported file format
  smithy/models/experiment_config.smithy Unsupported file format
  smithy/models/experiment_groups.smithy Unsupported file format
  smithy/models/experiments.smithy Unsupported file format
  smithy/models/functions.smithy Unsupported file format
  smithy/models/organisation.smithy Unsupported file format
  smithy/models/secret.smithy Unsupported file format
  smithy/models/type-templates.smithy Unsupported file format
  smithy/models/variable.smithy Unsupported file format
  smithy/models/webhook.smithy Unsupported file format
  smithy/models/workspace.smithy Unsupported file format
  smithy/patches/mcp-rust.patch Unsupported file format

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 13, 2026

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1b6aaa09-b417-42f8-92fc-fb9f4e89ad76

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch design/mcp-server

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant