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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ Each sample has a companion cookbook page with explanations and patterns.
| **[Hosting Remote](samples/05-hosting-remote/)** — remote interactive REPL sessions | [repl.yllibed.org/cookbook/hosting-remote/](https://repl.yllibed.org/cookbook/hosting-remote/) |
| **[Testing](samples/06-testing/)** — multi-session typed assertions | [repl.yllibed.org/cookbook/testing/](https://repl.yllibed.org/cookbook/testing/) |
| **[Spectre](samples/07-spectre/)** — Spectre.Console renderables, visualizations, rich prompts | [repl.yllibed.org/cookbook/spectre/](https://repl.yllibed.org/cookbook/spectre/) |
| **[MCP Server](samples/08-mcp-server/)** — MCP tools, resources, prompts, and MCP Apps UI | [repl.yllibed.org/cookbook/mcp-server/](https://repl.yllibed.org/cookbook/mcp-server/) |
| **[Build an MCP Server with Repl.Mcp](samples/08-mcp-server/)** — MCP tools, resources, prompts, and MCP Apps UI | [repl.yllibed.org/cookbook/mcp-server/](https://repl.yllibed.org/cookbook/mcp-server/) |

## More documentation

Expand Down
3 changes: 2 additions & 1 deletion docs/mcp-overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ myapp # still works as CLI / interactive REPL
One command graph. CLI, REPL, remote sessions, and AI agents — all from the same code.

> `UseMcpServer()` registers a hidden `mcp serve` context. The tool list is built lazily when an agent connects, so it sees all commands regardless of registration order.
> Repl.Mcp is the component that lets your app become an MCP server; it is not itself the MCP server you configure in an agent host.

## What it does

Expand Down Expand Up @@ -105,7 +106,7 @@ Most MCP clients use the same format:
}
```

See [mcp-reference.md](mcp-reference.md#agent-configuration) for all client-specific paths and formats (Claude Desktop, Claude Code, VS Code Copilot, Cursor, MCP Inspector).
See [mcp-reference.md](mcp-reference.md#agent-configuration) for all client-specific paths and formats (Claude Desktop, Claude Code, VS Code Copilot, Cursor, Cline, MCP Inspector). For a complete copy/paste sample, see [sample 08 — Build an MCP Server with Repl.Mcp](../samples/08-mcp-server/).

## What most apps need vs what few apps need

Expand Down
120 changes: 95 additions & 25 deletions docs/mcp-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -335,9 +335,20 @@ app.UseMcpServer(o =>

## Agent configuration

### Claude Desktop
Agent hosts configure the app or tool you built with Repl.Mcp. They do not
install Repl.Mcp directly.

**File:** `~/.config/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows)
Prefer a stable executable command, such as a published `dotnet tool`, for
shared team configs. When documenting a local sample, build it once and use
`dotnet run --no-build`, or point the host at a published executable. Plain
`dotnet run --project ...` is fragile in host configs because cold builds can
exceed startup timeouts and build/restore output can reach stdout before the MCP
JSON-RPC stream starts.

### Generic MCP client / Claude Desktop

**File:** `~/Library/Application Support/Claude/claude_desktop_config.json`
(macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows)

```json
{
Expand All @@ -350,24 +361,51 @@ app.UseMcpServer(o =>
}
```

### Claude Code

**File:** `~/.claude.json` or project `.claude/settings.json`
For a local sample project, split the launch into `command` and `args`:

```json
{
"mcpServers": {
"myapp": {
"command": "myapp",
"args": ["mcp", "serve"]
"repl-contacts-sample": {
"command": "dotnet",
"args": [
"run",
"--no-build",
"--project",
"/absolute/path/to/repl/samples/08-mcp-server/McpServerSample.csproj",
"--",
"mcp",
"serve"
]
}
}
}
```

### VS Code (GitHub Copilot)
On Windows JSON, write paths with doubled backslashes, for example
`C:\\Users\\you\\src\\repl\\samples\\08-mcp-server\\McpServerSample.csproj`.

### Claude Code

**File:** `.vscode/mcp.json` (workspace) or `~/.mcp.json` (global)
Claude Code uses command registration as the standard flow:

```bash
claude mcp add myapp -- myapp mcp serve
```

For a local Repl sample after an initial build:

```bash
claude mcp add repl-contacts-sample -- dotnet run --no-build --project /absolute/path/to/repl/samples/08-mcp-server/McpServerSample.csproj -- mcp serve
```

For file-based provisioning, use `.mcp.json` at the project root for project
settings or `~/.claude.json` for user/local settings. Both use the generic
`mcpServers` JSON shape.

### VS Code / GitHub Copilot

**File:** `.vscode/mcp.json` (workspace)

```json
{
Expand All @@ -381,20 +419,34 @@ app.UseMcpServer(o =>
}
```

VS Code also supports command-line registration from macOS/Linux shells:

```bash
code --add-mcp '{"name":"myapp","command":"myapp","args":["mcp","serve"]}'
```

On Windows, prefer the `.vscode/mcp.json` file. The `code.cmd --add-mcp`
argument path can mangle inline JSON in common shells; if you write JSON by
hand, remember to escape backslashes in Windows paths.

### Cursor

**File:** `.cursor/mcp.json` (project) or `~/.cursor/mcp.json` (global)

```json
{
"mcpServers": {
"myapp": {
"command": "myapp",
"args": ["mcp", "serve"]
}
}
}
```
Cursor uses the generic `mcpServers` JSON shape.

### Cline

Use **Configure MCP Servers** to edit `cline_mcp_settings.json`, then add the
local stdio server with the generic `mcpServers` JSON shape. The Cline
marketplace is for published/curated servers and will not install an unpublished
local sample.

### Complete copy/paste sample

See [sample 08 — Build an MCP Server with Repl.Mcp](../samples/08-mcp-server/)
for Cursor, VS Code, Claude Code, Cline, generic JSON, and MCP Inspector
examples.

### Debugging with MCP Inspector

Expand All @@ -404,7 +456,16 @@ Use the UI for interactive exploration:
npx @modelcontextprotocol/inspector myapp mcp serve
```

Use CLI mode for repeatable smoke checks. `resources/list` exposes the advertised resource MIME type, and `resources/read` exposes the MIME type and body returned on the wire:
For a local sample project, build first and pass the same no-build command used
by agent hosts:

```bash
npx @modelcontextprotocol/inspector dotnet run --no-build --project /absolute/path/to/repl/samples/08-mcp-server/McpServerSample.csproj -- mcp serve
```

Use CLI mode for repeatable smoke checks. `resources/list` exposes the
advertised resource MIME type, and `resources/read` exposes the MIME type and
body returned on the wire:

```bash
# Build or publish the server first; this example uses a built sample DLL.
Expand All @@ -422,19 +483,28 @@ npx -y @modelcontextprotocol/inspector@0.22.0 --cli \
| jq '.contents[] | { uri, mimeType, text }'
```

The repository also includes an opt-in `dotnet test` smoke guard for this external toolchain:
The repository also includes an opt-in `dotnet test` smoke guard for this
external toolchain:

```bash
REPL_RUN_MCP_INSPECTOR_TESTS=1 \
dotnet test src/Repl.McpTests/Repl.McpTests.csproj -c Release \
--filter 'TestCategory=ExternalToolchain'
```

It is skipped by default so the normal .NET test suite stays hermetic and does not require Node/npm or npm registry access.
It is skipped by default so the normal .NET test suite stays hermetic and does
not require Node/npm or npm registry access.

For command-level tests, use `Repl.Testing`: `CommandExecution.GetResult<T>()` validates the handler return value before rendering, while `OutputText` / `ReadJson<T>()` validate rendered output. For MCP wire contracts such as `Resource.MimeType` and `TextResourceContents.MimeType`, use the MCP test fixture or the opt-in Inspector CLI smoke check because those values are protocol metadata, not `Repl.Testing` command results.
For command-level tests, use `Repl.Testing`: `CommandExecution.GetResult<T>()`
validates the handler return value before rendering, while `OutputText` /
`ReadJson<T>()` validate rendered output. For MCP wire contracts such as
`Resource.MimeType` and `TextResourceContents.MimeType`, use the MCP test
fixture or the opt-in Inspector CLI smoke check because those values are
protocol metadata, not `Repl.Testing` command results.

Command-backed resources expose the rendered handler return value as the resource body. Low-level writes to `IReplIoContext.Output` are treated as side-channel command output and are not included in `resources/read` bodies.
Command-backed resources expose the rendered handler return value as the
resource body. Low-level writes to `IReplIoContext.Output` are treated as
side-channel command output and are not included in `resources/read` bodies.

## Client compatibility

Expand Down
2 changes: 1 addition & 1 deletion docs/result-flow.md
Original file line number Diff line number Diff line change
Expand Up @@ -765,7 +765,7 @@ dependency-free and can opt in by registering their own

- [Core Basics sample](../samples/01-core-basics/README.md#result-flow-paging)
- [Spectre sample](../samples/07-spectre/README.md#activity--paged-long-data-source)
- [MCP Server sample](../samples/08-mcp-server/README.md#demo-workflow)
- [MCP Server sample](../samples/08-mcp-server/README.md#test-with-mcp-inspector)
- [Output System](output-system.md)
- [Command Reference](commands.md)
- [MCP Reference](mcp-reference.md)
Expand Down
11 changes: 7 additions & 4 deletions samples/08-mcp-server/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,14 @@

// ── A Repl app exposed as an MCP server for AI agents ──────────────
//
// Run interactively: dotnet run
// Run as MCP server: dotnet run -- mcp serve
// Repl.Mcp is the component that lets this sample app become an MCP server.
// Agent hosts install/configure the sample app command, not Repl.Mcp itself.
//
// Configure in Claude Desktop or VS Code:
// { "command": "dotnet", "args": ["run", "--project", "path/to/08-mcp-server", "--", "mcp", "serve"] }
// Run interactively from this project: dotnet run
// Run as MCP server after building: dotnet run --no-build -- mcp serve
//
// Configure an MCP host with an absolute project path and no build step:
// { "command": "dotnet", "args": ["run", "--no-build", "--project", "/absolute/path/to/repl/samples/08-mcp-server/McpServerSample.csproj", "--", "mcp", "serve"] }

var app = ReplApp.Create(services =>
{
Expand Down
Loading
Loading