nestrs-mcp is the Model Context Protocol server for the nestrs framework. It exposes project structure, live runtime state, scaffolding actions, and docs search to MCP-aware clients (Claude Code, Cursor, VS Code, Codex CLI), plus the protocol surfaces beyond tools — prompts, resources, completion, elicitation, and tasks.
The narrative guide — install, client wiring for each editor, live-runtime setup, embedding recipes — lives on the Connect an AI editor to your nestrs project page. This page is the API reference.
Features
Crate layout
CLI
Thenestrs-mcp binary runs as either a server (no subcommand, with a --transport flag) or as a setup wizard (init / setup subcommand). --transport defaults to stdio; --http-addr defaults to 127.0.0.1:7777.
--yes, --no-interactive, --transport, --http-addr, --start-http-server) are documented in the setup wizard section of the guide.
NestrsMcpServer
The top-level rmcp ServerHandler. The binary serves this type; embedders construct it directly.
ServerHandler impl provides get_info (server name nestrs-mcp, version from Cargo), the full surface set (list_prompts, get_prompt, list_resources, list_resource_templates, read_resource, complete), subscriptions (accepted_subscription_filter, listen), and the task RPCs (get_task, update_task, cancel_task).
The wrapper’s
#[tool_router] impl block stays empty (rmcp routers are invariant in the handler type). list_tools / get_tool / call_tool dispatch to the four area handlers, so a tools/list against the stock binary returns the full 24-tool surface. Embedding a single area handler is still supported — see Embedding in another binary.SubServers bundles the four handlers:
Tool surface
Tools are declared with rmcp’s#[tool_router] / #[tool] macros — there is no manual registration API. The pattern every built-in handler follows:
Json<T> return (where T: Serialize + schemars::JsonSchema) stamps an outputSchema on the tool declaration and lands the typed value in structuredContent — plus a text fallback block for clients that only render text.
Introspection (read-only, read_only_hint = true) — IntrospectionTools
Every tool takes workspace_path: String (absolute path to the workspace root — the directory containing Cargo.toml) so one server instance can serve multiple projects over a long session.
Runtime — RuntimeTools
Each tool takes an AdminEndpoint: {base_url: String, token: Option<String>} (e.g. "http://127.0.0.1:7777"). No Cargo feature required — but the target app must have the admin feature and use_admin(...) enabled. Backed by the AdminClient.
Scaffolding (write actions, destructive_hint = true) — ScaffoldTools
fields is Vec<DtoFieldSpec> — {name, ty, optional?, validators?} per field (see Scaffold API). All write actions return a ScaffoldReport — {files_created: [..], files_modified: [..]} — so the model can show the user exactly what changed. Guards: module and DTO names must be valid Rust idents (is_safe_ident), and project names must be valid crate names; there is no workspace-containment check on path, so treat tool output paths as trusted input.
Docs search (read-only, read_only_hint = true) — DocsTools
The index is built lazily on first use per
workspace_path and cached for the process lifetime.
Protocol surfaces: McpSurfaces
Clone-cheap bundle of the non-tool protocol surfaces, carried by NestrsMcpServer (attach with .with_surfaces(...)).
resources/read checks the static resource map first (a static resource beats a matching template); templates match on their static prefix (everything before the first {, trailing / trimmed). Subscriptions use subscriptions/listen on protocol ≥ 2026-07-28 with the legacy subscribe/unsubscribe kept for older peers.
CacheHints (SEP-2549)
ttlMs / cacheScope fields on list_prompts, list_resources, list_resource_templates, and read_resource results — suppressed for peers below protocol 2026-07-28.
Message helpers
Elicitation
MRTR for tools (SEP-2322) — available without any feature. A tool returns anInputRequired result instead of an error:
"input"); the client echoes its response back under the same key.
Server→client elicitation (SEP-1034) — behind the elicitation feature. Register one handler via McpSurfaces::register_elicitation, then call the wrapper from a tool body:
elicit probes the client’s capabilities first and returns ElicitationAction::Cancel (rather than an error) if the client didn’t advertise elicitation.
Tasks (SEP-2663)
io.modelcontextprotocol/tasks. The TaskManager store always exists; .with_task_support() only advertises the extension (undeclared, the SDK rejects tasks/get|update|cancel with -32601 before the handler runs). Inside a tool body, spawn an operation and return CallToolResponse::Task(CreateTaskResult::new(task)):
Per-tool-call authorization (authz)
NestrsMcpServer’s call_tool override opens a TransactionSlot per call, installs the ability + principal + request scope, dispatches, post-masks the response with nestrs::mask_value (the same walker HTTP/WS/GraphQL use; error results are never masked), then commits on success / rolls back on tool error.
Task-local accessors for tool bodies:
AdminClient
HTTP client for a running nestrs app’s admin sidecar (reqwest + rustls-tls, 5-second timeout, no retries).
nestrs_mcp::runtime):
nestrs = { features = ["admin"] } + NestApplication::use_admin(AdminOptions { addr, token }), then tokio::spawn(handle.serve()). Token auth is Authorization: Bearer <token> header-only (query-string tokens are rejected); with no token the listener is loopback-only and 401s everything.
Introspection API
Source-level parsing, independent of a running app:introspection::source):
introspection::metadata):
ParserWarnings, never parse failures.
Scaffold API
Docs search API
Wizard API
Error type
Error conventions
Tool bodies returnResult<Json<...>, rmcp::ErrorData>:
- Operational failure (operation ran but failed — file not found, parse error, app not reachable, scaffold failure):
Err(ErrorData::internal_error(msg))— the message is visible to the model, which can read it and recover. - Bad parameters (unknown module / controller / provider / DTO / route name):
Err(ErrorData::invalid_params("modulexnot found")). - Success: a
Json<T>payload — typed value instructuredContent(with anoutputSchemastamped from the return type) plus a text fallback block.
Embedding in another binary
nestrs-mcp is a library as well as a binary. Each area handler is a standalone ServerHandler, so you can serve any subset without spawning a subprocess:
rmcp is not re-exported — depend on it directly (rmcp = { version = "3.1", default-features = false, features = ["server", "transport-io"] }, plus transport-streamable-http-server for HTTP).
The nestrs-cli Cargo manifest carries nestrs-mcp as an optional dependency behind its mcp feature (mcp = ["dep:nestrs-mcp", "nestrs-mcp/admin"]) so a future nestrs-cli mcp subcommand can serve the full tool set in-process — the dependency is stubbed (off by default, no subcommand yet), so existing CLI builds are unaffected.