Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
**A .NET framework for building composable command surfaces.**

- Define your commands once — run them as a CLI, explore them in an interactive REPL,
- host them in session-based terminals, expose them as MCP servers for AI agents,
- host them in session-based terminals, expose them as MCP servers and MCP Apps for AI agents,
- or drive them from automation scripts.

> **New here?** The [DeepWiki](https://deepwiki.com/yllibed/repl) has full architecture docs, diagrams, and an AI assistant you can ask questions about the toolkit.
Expand Down Expand Up @@ -83,6 +83,14 @@ app.UseMcpServer(); // add one line
{ "command": "myapp", "args": ["mcp", "serve"] }
```

**MCP Apps** (same server, host-rendered UI for capable clients):

```csharp
app.Map("contacts dashboard", (IContactStore contacts) => BuildHtml(contacts))
.WithDescription("Open the contacts dashboard")
.AsMcpAppResource();
```

One command graph. CLI, REPL, remote sessions, and AI agents — all from the same code.

## What's included
Expand All @@ -93,7 +101,7 @@ One command graph. CLI, REPL, remote sessions, and AI agents — all from the sa
| Interactive REPL — scopes, history, autocomplete | [![Repl.Defaults](https://img.shields.io/nuget/vpre/Repl.Defaults?logo=nuget&label=Repl.Defaults)](https://www.nuget.org/packages/Repl.Defaults) | <ul><li>[Interactive loop](docs/interactive-loop.md)</li><li>[Configuration](docs/configuration-reference.md)</li></ul> |
| Parameters & options — typed binding, options groups, response files | [![Repl.Core](https://img.shields.io/nuget/vpre/Repl.Core?logo=nuget&label=Repl.Core)](https://www.nuget.org/packages/Repl.Core) | <ul><li>[Parameter system](docs/parameter-system.md)</li><li>[Route system](docs/route-system.md)</li></ul> |
| Multiple output formats — JSON, XML, YAML, Markdown | [![Repl.Core](https://img.shields.io/nuget/vpre/Repl.Core?logo=nuget&label=Repl.Core)](https://www.nuget.org/packages/Repl.Core) | <ul><li>[Output system](docs/output-system.md)</li></ul> |
| MCP server — expose commands as AI agent tools | [![Repl.Mcp](https://img.shields.io/nuget/vpre/Repl.Mcp?logo=nuget&label=Repl.Mcp)](https://www.nuget.org/packages/Repl.Mcp) | <ul><li>[MCP server](docs/mcp-server.md)</li><li>[MCP advanced](docs/mcp-advanced.md)</li></ul> |
| MCP server + MCP Apps — expose commands as agent tools, resources, prompts, and UI | [![Repl.Mcp](https://img.shields.io/nuget/vpre/Repl.Mcp?logo=nuget&label=Repl.Mcp)](https://www.nuget.org/packages/Repl.Mcp) | <ul><li>[MCP server](docs/mcp-server.md)</li><li>[MCP advanced](docs/mcp-advanced.md)</li><li>[MCP sample](samples/08-mcp-server/)</li></ul> |
| Typed results & interactions — prompts, progress, cancellation | [![Repl.Core](https://img.shields.io/nuget/vpre/Repl.Core?logo=nuget&label=Repl.Core)](https://www.nuget.org/packages/Repl.Core) | <ul><li>[Interaction channel](docs/interaction.md)</li></ul> |
| Session hosting — WebSocket, Telnet, remote terminals | [![Repl.WebSocket](https://img.shields.io/nuget/vpre/Repl.WebSocket?logo=nuget&label=Repl.WebSocket)](https://www.nuget.org/packages/Repl.WebSocket) [![Repl.Telnet](https://img.shields.io/nuget/vpre/Repl.Telnet?logo=nuget&label=Repl.Telnet)](https://www.nuget.org/packages/Repl.Telnet) | <ul><li>[Runtime channels](docs/runtime-channels.md)</li><li>[Terminal metadata](docs/terminal-metadata.md)</li></ul> |
| Shell completion — Bash, PowerShell, Zsh, Fish, Nushell | [![Repl.Core](https://img.shields.io/nuget/vpre/Repl.Core?logo=nuget&label=Repl.Core)](https://www.nuget.org/packages/Repl.Core) | <ul><li>[Shell completion](docs/shell-completion.md)</li></ul> |
Expand All @@ -115,7 +123,7 @@ Progressive learning path — each sample builds on the previous:
5. **[Hosting Remote](samples/05-hosting-remote/)** — WebSocket / Telnet session hosting
6. **[Testing](samples/06-testing/)** — multi-session typed assertions
7. **[Spectre](samples/07-spectre/)** — Spectre.Console renderables, visualizations, rich prompts
8. **[MCP Server](samples/08-mcp-server/)** — expose commands as MCP tools for AI agents
8. **[MCP Server](samples/08-mcp-server/)** — expose commands as MCP tools, resources, prompts, and a minimal MCP Apps UI

## More documentation

Expand Down
4 changes: 2 additions & 2 deletions docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
- `Repl.Spectre`
- Spectre.Console integration: `SpectreInteractionHandler` for rich prompts, `IAnsiConsole` DI injection, `"spectre"` output transformer for auto-rendered tables, `SpectreConsoleOptions` for capability configuration.
- `Repl.Mcp`
- MCP (Model Context Protocol) integration: `UseMcpServer()`, `BuildMcpServerOptions()`, tool/resource/prompt mapping, client roots, transport factory.
- MCP (Model Context Protocol) integration: `UseMcpServer()`, `BuildMcpServerOptions()`, tool/resource/prompt mapping, MCP Apps UI resources, client roots, transport factory.
- `Repl.Testing`
- In-memory multi-session testing toolkit (`ReplTestHost`, `ReplSessionHandle`, typed execution results/events).
- `Repl.Tests`
Expand All @@ -30,7 +30,7 @@
- `Repl.ProtocolTests`
- Contract tests for machine-readable help/error payloads.
- `Repl.McpTests`
- Tests for MCP server options, tool mapping, and transport integration.
- Tests for MCP server options, tool/resource/prompt/app mapping, and transport integration.
- `Repl.SpectreTests`
- Tests for Spectre.Console integration.
- `Repl.ShellCompletionTestHost`
Expand Down
10 changes: 10 additions & 0 deletions docs/best-practices.md
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,16 @@ app.Map("clear", static async (IReplInteractionChannel ch, CancellationToken ct)
.AutomationHidden(); // not exposed to agents
```

For MCP Apps, mark the HTML-producing command as an app resource:

```csharp
app.Map("contacts dashboard", static (IContactStore contacts) => BuildHtml(contacts))
.WithDescription("Open the contacts dashboard")
.AsMcpAppResource();
```

This lets capable hosts render the UI while keeping raw HTML out of the model-facing transcript. The handler is still a normal Repl mapping, so it can use DI, cancellation tokens, and the usual command pipeline.

Declare answer slots for interactive prompts so agents and `--answer:` flags can provide values:

```csharp
Expand Down
4 changes: 3 additions & 1 deletion docs/comparison.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ Repl Toolkit is a command-surface framework — not just a CLI parser. It builds
| Structured help output | ❌ Text only | ❌ Text only | ✅ JSON / XML / YAML |
| Documentation export | ❌ | ❌ | ✅ `doc export` command |
| Protocol passthrough (MCP, LSP...) | ❌ | ❌ | ✅ `AsProtocolPassthrough()` |
| MCP server tools/resources/prompts | ❌ | ❌ | ✅ `Repl.Mcp` |
| MCP Apps UI resources | ❌ | ❌ | ✅ `AsMcpAppResource()` |
| Shell completion | ⚠️ Tab completion API | ❌ | ✅ Bash, PS, Zsh, Fish, Nu |

## When to Use What
Expand All @@ -113,7 +115,7 @@ Repl Toolkit is a command-surface framework — not just a CLI parser. It builds
- Commands involve multi-step guided workflows (prompts, progress, confirmations)
- Remote terminal hosting is planned (WebSocket, Telnet)
- The command model must be testable in both one-shot and interactive contexts
- AI/LLM agent readiness matters (structured help, protocol passthrough, pre-answered prompts)
- AI/LLM agent readiness matters (structured help, MCP tools/resources/prompts, MCP Apps UI, protocol passthrough, pre-answered prompts)

## Migration from System.CommandLine

Expand Down
4 changes: 4 additions & 0 deletions docs/glossary.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,10 @@ Static text in a route template matched exactly.

Model Context Protocol. Allows AI agents to discover and invoke commands.

### MCP App

MCP UI extension that lets a command open a `ui://` HTML resource. Repl maps this with `.AsMcpAppResource()` on the HTML-producing command and returns launcher text for normal tool calls.

### Middleware

Pipeline function registered via `app.Use()` that wraps handler execution.
Expand Down
2 changes: 1 addition & 1 deletion docs/help-system.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ Each `ReplDocCommand` includes:
This model powers:

- `--help` text rendering
- MCP tool/resource/prompt schema generation
- MCP tool/resource/prompt schema generation and MCP Apps metadata
- Shell completion candidate generation

See also: [Commands](commands.md) | [MCP Server](mcp-server.md) | [Parameter System](parameter-system.md)
138 changes: 137 additions & 1 deletion docs/mcp-advanced.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
# MCP Advanced: Dynamic Tools, Roots, and Session-Aware Patterns
# MCP Advanced: Dynamic Tools, Roots, MCP Apps, and Session-Aware Patterns

This guide covers advanced MCP usage patterns for Repl apps:

- Tool visibility that changes per session
- Native MCP client roots
- Soft roots for clients that don't support roots
- Compatibility shims for clients that don't refresh dynamic tool lists well
- Advanced MCP Apps patterns

> **Prerequisite**: read [mcp-server.md](mcp-server.md) first for the basic setup.
>
Expand All @@ -23,6 +24,7 @@ Use the techniques in this page when:
- The agent needs to know which directories it is allowed to work in
- Your MCP client does not support native roots
- Your MCP client does not seem to refresh its tool list after `list_changed`
- Your MCP App should render HTML without exposing that HTML as the model-facing tool result

If your tool list is static, stay with the default setup from [mcp-server.md](mcp-server.md).

Expand Down Expand Up @@ -248,8 +250,142 @@ Avoid it when:
| Client supports tools but misses dynamic refreshes | Enable `DiscoverAndCallShim` |
| Client has both issues | Use soft roots and, if needed, the dynamic tool shim |

## MCP Apps advanced patterns

For the basic MCP Apps setup, start with [mcp-server.md](mcp-server.md#mcp-apps). This section covers the patterns that matter once the UI is more than a trivial inline HTML card.

MCP Apps support is experimental in this version. Resource handlers should return generated HTML as `string`, `Task<string>`, or `ValueTask<string>`; the API is expected to become more flexible as host support and Repl's asset story evolve.

### One mapping, two MCP surfaces

`AsMcpAppResource()` keeps the Repl authoring model simple: one mapping produces both the launcher tool metadata and the UI resource.

```csharp
app.Map("contacts dashboard", (IContactDb contacts) => BuildHtml(contacts))
.WithDescription("Open the contacts dashboard")
.AsMcpAppResource();
```

The handler return value is used for `resources/read` and is returned as `text/html;profile=mcp-app`. When a client calls the MCP tool, Repl returns launcher text instead of raw HTML, using `WithMcpAppLauncherText(...)`, `WithDescription(...)`, or a generated fallback.

Use `WithMcpAppLauncherText(...)` when the description is not the text you want in the chat transcript:

```csharp
app.Map("contacts dashboard", (IContactDb contacts) => BuildHtml(contacts))
.WithDescription("Open the contacts dashboard")
.AsMcpAppResource()
.WithMcpAppLauncherText("Opening the contacts dashboard.");
```

`WithMcpApp("ui://...")` remains available for advanced cases where a normal tool should point at a separately registered UI resource, but it is not the default pattern.

```csharp
app.Map("status dashboard", (IStatusStore store) => store.GetSummary())
.ReadOnly()
.WithMcpApp("ui://status/dashboard");
```

### Generated UI resource URIs

`AsMcpAppResource()` generates a `ui://` URI from the route path, matching how `AsResource()` generates `repl://` URIs:

```csharp
app.Map("contact {id:int} panel", (int id, IContactDb contacts) => BuildHtml(contacts.Get(id)))
.AsMcpAppResource();
```

This produces a resource template like `ui://contact/{id}/panel`.

The generated URI uses the full route path, including contexts:

```csharp
app.Context("viewer", viewer =>
{
viewer.Context("session {id:int}", session =>
{
session.Map("attach", (int id) => BuildHtml(id))
.AsMcpAppResource();
});
});
```

This produces `ui://viewer/session/{id}/attach`. MCP URI templates keep the variable name but not the Repl route constraint, so `{id:int}` becomes `{id}` in the URI and is validated when Repl dispatches the resource read through the normal command pipeline.

Pass an explicit URI only when you need a stable public URI that is decoupled from the route path:

```csharp
app.Map("contacts dashboard", (IContactDb contacts) => BuildHtml(contacts))
.AsMcpAppResource("ui://contacts/summary");
```

### Display preferences

MCP Apps standard display modes are `inline`, `fullscreen`, and `pip`, but hosts decide what they support. Repl can express a preference:

```csharp
app.Map("contacts dashboard", (IContactDb contacts) => BuildHtml(contacts))
.AsMcpAppResource()
.WithMcpAppDisplayMode(McpAppDisplayModes.Fullscreen);
```

As of April 2026, VS Code renders MCP Apps inline only. Microsoft 365 Copilot declarative agents support fullscreen display requests for widgets. Other hosts vary; check [mcp-server.md](mcp-server.md#mcp-apps-host-compatibility) for the current compatibility notes.

If the HTML uses the MCP Apps JavaScript bridge, it should still ask the host what is available before requesting a different display mode:

```javascript
const modes = app.getHostContext()?.availableDisplayModes ?? [];
if (modes.includes("fullscreen")) {
await app.requestDisplayMode({ mode: "fullscreen" });
}
```

For host-specific hints that are not yet modeled by Repl, use simple string metadata:

```csharp
app.Map("contacts dashboard", (IContactDb contacts) => BuildHtml(contacts))
.AsMcpAppResource()
.WithMcpAppUiMetadata("presentation", "flyout");
```

### HTML now, assets later

The v1 Repl API expects the UI resource handler to return generated HTML. This is enough for small cards, forms, and proof-of-concept dashboards.

For WebAssembly UIs such as Uno-Wasm, the likely shape is:

1. Map a `ui://` app resource that returns a small HTML shell.
2. Serve published static assets such as `embedded.js`, `_framework/*`, `.wasm`, fonts, and images from an HTTP endpoint.
3. Inject the HTTP base URL into the generated shell.
4. Set CSP metadata for asset and fetch domains.

```csharp
var assetBaseUri = new Uri("http://127.0.0.1:5123/");

app.Map("contacts dashboard", () => BuildUnoShellHtml(assetBaseUri))
.AsMcpAppResource()
.WithMcpAppCsp(new McpAppCsp
{
ResourceDomains = [assetBaseUri.ToString()],
ConnectDomains = [assetBaseUri.ToString()],
});
```

Keep the shell and asset server host-aware: clients may preload or cache UI resources, and not every host supports every display mode or browser capability.

## Troubleshooting patterns

### My MCP App shows HTML text in the chat

Use `.AsMcpAppResource()` on the HTML-producing command instead of linking a normal tool to raw HTML manually. Repl will return launcher text for tool calls and reserve the HTML for `resources/read`.

Also restart or reload the MCP server in the client. Some hosts cache tool lists and will not pick up MCP Apps metadata changes until the server is refreshed.

### My MCP App does not open fullscreen

Check whether the host supports fullscreen. VS Code currently renders MCP Apps inline only, even when Repl sets `preferredDisplayMode: McpAppDisplayModes.Fullscreen`.

For hosts that support display mode changes, request fullscreen from inside the HTML app after checking host capabilities.

### The agent doesn't see tools that should appear later

Check:
Expand Down
Loading
Loading