Repository navigation
Repl 0.12 is about automation and embedding. Exit codes are now structured and configurable, Repl.Mcp moves to the stable MCP SDK 2.x with stateless HTTP hosting, and applications get hooks before parsing, at startup and around every invocation. A new pair of opt-in packages lets an operator attach to a running process. Hosted Telnet and WebSocket sessions, prompts and cancellation were also tightened, and several of those fixes change observable behaviour: read Breaking changes before upgrading.
Highlights
- MCP SDK 2.2 with dual-era serving.
Repl.Mcpruns onModelContextProtocol2.2.0 and serves revisions2025-11-25and2026-07-28, with roots, sampling, elicitation, feedback and tool snapshots isolated per session (#71). - Stateless MCP over HTTP.
ConfigureMcpServerOptionsapplies a Repl catalog to the SDK's own options, so ASP.NET Core hosts it per request withHttpContext.RequestServices(#123). - Structured exit codes. Every run produces a
ReplExecutionOutcomemapped throughReplOptions.ExitCodesand an optionalResolver(#85),Results.CompletedWithFailures(report)reports a run that completed with failures (#128), and a module can declare its own codes withIReplModuleExitCodes(#129). - Process signals. With
UseCliProfile()orUseDefaultInteractive(), Ctrl+C, Ctrl+Break and SIGTERM cancel cooperatively and exit130or143(#80).Repl.TestingaddsReplProcessSignalHarnessandReplProcessProbe(#90). - Advanced input and startup. Argument adapters and injectable input validators (#118), typed startup preparation (#120), and
UseInvocationHookwith nativeReplInvocationRequests across CLI, interactive, programmatic and MCP calls (#121). - Remote administration (new packages).
Repl.RemoteandRepl.Remote.Defaultsattach a console to a running process, or run one command in it, over same-user named pipes. Nothing is enabled unless the app starts an endpoint (#148). Server-side failures reach the host through anonErrorcallback (#171). Sample 05 adds container health and live administration (#149), and sample 10 is a documentation MCP server administered the same way (#161). - Per-session DI scopes.
Scopedresolves once per session, and once per connection under MCP (#74). - Feedback stays out of machine output. With
--json,--xml,--yamlor a redirected stdout, progress, status and prompts go to stderr (#127, #133). - Hidden options.
.Hidden()andHiddenAliases/.HiddenAlias(...)keep options parsable without showing them in help, completion, docs or MCP (#77). - JSON results render as data.
JsonNodeandJsonElementresults render as key/value lines or tables, which also fixes a Spectre stack overflow (#111).
Breaking changes and migration
Each item links to the documentation page that carries its "Changed in 0.12" note.
- MCP SDK 2.x required (#71). SDK 1.4.x is unsupported,
IMcpFeedback.SendMessageAsynctakesMcpMessageLevel, the advertised tool set is invariant on2026-07-28, uncaught exceptions reach the client asCommand failed with exit code N., and.LongRunning()no longer advertises task support. See Upgrading from the 1.x SDK. Scopedis per session (#74). A scoped disposable is disposed at session end, a singleton that injects a scoped service captures the first session's instance, and MCP scopes per connection. UseReplRunOptions.SessionScope = SessionScopeBehavior.CallerOwnedwhen the caller's provider already is the session. See Pick the lifetime that matches the boundary.- Signal ownership under the CLI and interactive profiles (#80). Interrupted runs exit
130or143, and one-shot handlers get a run-scoped token. Restore the old behaviour withProcessSignalHandling = ProcessSignalHandlingMode.None. See What changes for an existing application. - Framework exit codes (#85). Usage and binding refusals exit
2instead of1. A handler's ownOperationCanceledExceptionis aHandlerException. Hosted-lifecycle failures and the unknown--outputrefusal go to stderr, and--output:bogusis aUsageError. See Restoring the pre-policy codes. - Feedback moves to stderr (#127). Restore it with
options.Output.FeedbackStream = ReplFeedbackStream.Output. See Which stream receives progress. - Refusals, passthrough feedback and prompt echo (#133). An input that a better-matching route outscores is an unknown command (
unknown_commandunder--json), passthrough feedback leaves the protocol stream, and typed input echoes with the prompt label. - Parameters Repl supplies (#137).
Maprefuses option metadata on them,.WithOption("progress", ...), and route segments named like them.IProgress<double>no longer receives aUseGlobalOptions<T>()instance, and[FromServices]/[FromContext]group properties are not options. See Simple progress. - Prompt cancellation (#139, #146). Esc in a timed secret prompt, and a hosted terminal disconnecting during a prompt, throw
OperationCanceledException. See Cancellation. - Hosted sessions (#146, #161). Cancelling a session's token while the editor waits ends as a cancellation instead of exit
0. Telnet ends when the peer closes its input,TelnetFramingmust be disposed, andReplWebSocketSession.RunAsynccloses the WebSocket normally, up to a second later. Incoming WebSocket messages are limited to 64 KiB; a larger one closes the session withMessageTooBig(1009). See the execution pipeline. - MCP hidden required option (#163). Every connection now receives "The server's MCP catalog is unavailable because of a server configuration error."; the detail goes to operator event 2008. See Operator diagnostics.
- MCP error codes (#107). An unknown resource is
-32002on2025-11-25and-32602on2026-07-28, and an unknown prompt is-32602; both used to be-32603. See What differs by revision. Repl.Testingread-through (#128).TryGetResult<Payload>()onResults.Exit(code, payload)now returns the payload. See Typed result object.- Required arity with a default (#164).
Maprefuses an explicitExactlyOneorOneOrMorearity on a parameter with a default value. See the parameter system.
Other changes
- Core: input-callback failures in the requested format (#131), collection defaults and group option help lines (#137), completion on the executable name (#144), context input validated before entering (#145), one message for any repeated scalar enum (#164), and live-analysis messages that name the option token (#171).
- MCP: operator events 2001-2009 (#106, #163), one catalog per protocol era (#109), prompt services reach capability and keyed services (#110), the compatibility shim notifies only its own session (#108), and array options bind as repeated values (#119).
- Hosting: masked secret input in hosted terminals (#139), non-BMP characters across Telnet writer overloads (#162),
ReplWebSocketSession.RunWithServicesAsync, fragmented-message reassembly andSpectreConsoleOptions.AddView<T>(#161). - Testing:
Repl.TestingXML docs (#90), test sessions see app services (#74), andCommandExecution.OutcomeKind(#128). - Packaging and CI: MIT license expression (#69), SourceLink 10.0.303 for CVE-2026-62900 (#87), NuGet publishing through OIDC trusted publishing (#150), and a publish step that fails when any package does not reach NuGet (#171).
CHANGELOG.mdis retired in favour of these generated notes (#88).
What's Changed
- fix(packaging): declare MIT license expression by @autocarl in #69
- feat: add fluent hidden options by @autocarl in #77
- test: neutralise the ANSI escape hatches in environment-sensitive tests by @carldebilly in #87
- feat(core): structured execution outcomes and configurable exit codes by @carldebilly in #85
- fix(runtime): cancel standalone runs on process signals by @autocarl in #80
- docs: retire CHANGELOG.md in favour of the generated release notes by @carldebilly in #88
- feat(testing): deterministic process-signal lifecycle support in Repl.Testing by @carldebilly in #90
- feat(mcp)!: require ModelContextProtocol SDK 2.x and isolate MCP state per session by @carldebilly in #71
- fix(di): open one DI scope per session so Scoped services match the documented lifetime by @carldebilly in #74
- fix(output): render JsonNode and JsonElement results as JSON data in human output by @carldebilly in #111
- feat(input): argument adapters and injectable input validators by @carldebilly in #118
- feat: add typed startup preparation and service-aware hooks by @carldebilly in #120
- fix(mcp): bind array options as repeated values by @autocarl in #119
- feat(input): add parsed invocation hooks and native requests by @carldebilly in #121
- feat(mcp): integrate stateless HTTP hosting with SDK options by @carldebilly in #123
- feat(output): move interaction feedback to stderr when the output is for a program by @carldebilly in #127
- feat: add Results.CompletedWithFailures for runs that complete with failures by @carldebilly in #128
- feat: let a module declare the exit codes of its commands by @carldebilly in #129
- fix: report input-callback failures in the requested format; split passthrough feedback onto stderr by @carldebilly in #131
- fix: refuse unknown commands consistently; keep passthrough feedback and prompt echo out of program output by @carldebilly in #133
- fix(options)!: hide Repl-supplied parameters from options; show collection defaults by @carldebilly in #137
- Mask a secret typed in a hosted terminal by @carldebilly in #139
- ci: install the MCP Inspector before its test calls by @carldebilly in #143
- fix(completion): offer plain completion when the cursor is on the executable name by @carldebilly in #144
- Validate input that names a context before entering it by @carldebilly in #145
- fix(hosting)!: propagate session cancellation and close Telnet/WebSocket sessions cleanly by @carldebilly in #146
- feat(remote): local console and structured CLI over named pipes by @carldebilly in #148
- docs(samples): container health checks and live administration in sample 05 by @carldebilly in #149
- ci: publish NuGet packages with GitHub OIDC by @carldebilly in #150
- fix(mcp): answer an unknown resource or prompt with a standard error code by @carldebilly in #107
- feat(mcp): log the failures the MCP server hides from its clients by @carldebilly in #106
- fix(mcp): send the compatibility shim's tools/list_changed only to its own session by @carldebilly in #108
- fix(mcp): keep a connection's legacy catalog when a modern request finishes after initialize by @carldebilly in #109
- fix(mcp): let a prompt reach the capability services through its IServiceProvider by @carldebilly in #110
- fix(mcp): log a hidden required option for operators and return one sanitized error to clients by @carldebilly in #163
- fix(telnet): keep a surrogate pair whole across the writer's overloads by @carldebilly in #162
- fix(core): refuse an explicit required arity with a default value by @carldebilly in #164
- Add a documentation MCP server sample with remote Repl administration by @carldebilly in #161
- fix: release-review fixes before 0.12 (remote diagnostics, live-analysis tokens, publish safety, migration notes) by @carldebilly in #171
Full Changelog: v0.11.0...v0.12.0