From a43e12186f706696f1f8f3abff1cf1dda778e08b Mon Sep 17 00:00:00 2001 From: autocarl Date: Thu, 25 Jun 2026 14:15:54 -0400 Subject: [PATCH 1/3] docs: clarify Repl.Mcp sample host setup --- docs/mcp-overview.md | 3 +- docs/mcp-reference.md | 46 +++-- samples/08-mcp-server/Program.cs | 5 +- samples/08-mcp-server/README.md | 188 +++++++++++++++--- samples/08-mcp-server/configs/cursor.mcp.json | 15 ++ .../configs/generic-mcp-client.json | 15 ++ samples/08-mcp-server/configs/vscode.mcp.json | 16 ++ samples/README.md | 4 +- 8 files changed, 248 insertions(+), 44 deletions(-) create mode 100644 samples/08-mcp-server/configs/cursor.mcp.json create mode 100644 samples/08-mcp-server/configs/generic-mcp-client.json create mode 100644 samples/08-mcp-server/configs/vscode.mcp.json diff --git a/docs/mcp-overview.md b/docs/mcp-overview.md index 931734e..3cdee8f 100644 --- a/docs/mcp-overview.md +++ b/docs/mcp-overview.md @@ -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 @@ -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 diff --git a/docs/mcp-reference.md b/docs/mcp-reference.md index 4ea3eb3..27e42b2 100644 --- a/docs/mcp-reference.md +++ b/docs/mcp-reference.md @@ -335,7 +335,11 @@ 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. + +Prefer a stable executable command, such as a published `dotnet tool`, for shared team configs. When documenting a local sample, use an absolute path to the sample project because most hosts do not launch from your repository root. + +### Generic MCP client / Claude Desktop **File:** `~/.config/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows) @@ -350,24 +354,21 @@ app.UseMcpServer(o => } ``` +For a local sample project, use the same shape with `dotnet run --project /absolute/path/to/project.csproj -- mcp serve`. + ### Claude Code -**File:** `~/.claude.json` or project `.claude/settings.json` +Claude Code can use a command registration flow when available: -```json -{ - "mcpServers": { - "myapp": { - "command": "myapp", - "args": ["mcp", "serve"] - } - } -} +```bash +claude mcp add myapp -- myapp mcp serve ``` -### VS Code (GitHub Copilot) +If your Claude Code version uses settings files instead, use the generic `mcpServers` JSON shape above in user or project settings. + +### VS Code / GitHub Copilot -**File:** `.vscode/mcp.json` (workspace) or `~/.mcp.json` (global) +**File:** `.vscode/mcp.json` (workspace) ```json { @@ -381,6 +382,12 @@ app.UseMcpServer(o => } ``` +VS Code also supports command-line registration: + +```bash +code --add-mcp '{"name":"myapp","command":"myapp","args":["mcp","serve"]}' +``` + ### Cursor **File:** `.cursor/mcp.json` (project) or `~/.cursor/mcp.json` (global) @@ -396,6 +403,19 @@ app.UseMcpServer(o => } ``` +### Cline + +Use Cline's MCP settings or marketplace flow to add a local stdio server with the same command and args: + +- command: `myapp` +- args: `mcp`, `serve` + +If your Cline version asks for JSON, start from the generic `mcpServers` block above. + +### 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 Use the UI for interactive exploration: diff --git a/samples/08-mcp-server/Program.cs b/samples/08-mcp-server/Program.cs index 77b84e7..e9f51b1 100644 --- a/samples/08-mcp-server/Program.cs +++ b/samples/08-mcp-server/Program.cs @@ -7,10 +7,13 @@ // ── A Repl app exposed as an MCP server for AI agents ────────────── // +// 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. +// // Run interactively: dotnet run // Run as MCP server: dotnet run -- mcp serve // -// Configure in Claude Desktop or VS Code: +// Configure in an MCP host with: // { "command": "dotnet", "args": ["run", "--project", "path/to/08-mcp-server", "--", "mcp", "serve"] } var app = ReplApp.Create(services => diff --git a/samples/08-mcp-server/README.md b/samples/08-mcp-server/README.md index f2cefd2..369b04d 100644 --- a/samples/08-mcp-server/README.md +++ b/samples/08-mcp-server/README.md @@ -1,10 +1,15 @@ -# 08 — MCP Server +# 08 — Build an MCP Server with Repl.Mcp -Expose a Repl command graph as an MCP server for AI agents, including a minimal MCP Apps UI. +This sample shows how to build a real MCP server from a Repl command graph. + +> **Important:** Repl.Mcp is not itself the MCP server you install in an agent host. +> Repl.Mcp is the Repl Toolkit component that lets your app expose its own command graph as an MCP server. +> In this sample, the sample app is the MCP server. ## What this sample shows -- `app.UseMcpServer()` — one line to enable MCP stdio server +- `app.UseMcpServer()` — one line to enable an MCP stdio server for this app +- One command graph exposed as CLI, interactive REPL, and MCP tools/resources/prompts - `contacts paged` — paged structured output for large result sets - `IReplInteractionChannel` in MCP mode — portable notices, warnings, problems, and progress updates - `feedback demo` / `feedback fail` — deterministic progress sequences that are easy to inspect in MCP Inspector @@ -14,42 +19,69 @@ Expose a Repl command graph as an MCP server for AI agents, including a minimal - `.AsMcpAppResource()` — mark a command as a generated HTML MCP App resource - `.WithMcpAppBorder()` / `.WithMcpAppDisplayMode(...)` — add MCP Apps presentation preferences - `.AutomationHidden()` — hide interactive-only commands from agents -- `.WithDetails()` — rich descriptions consumed by agents and documentation tools (not displayed in `--help`) +- `.WithDetails()` — rich descriptions consumed by agents and documentation tools, not displayed in `--help` - `import {file}` — a realistic workflow that combines progress reporting, sampling, elicitation, and duplicate review -## Running +## Run from the repository root + +Use these commands from the root of the `yllibed/repl` repository. -**Interactive REPL:** +### CLI mode ```bash -dotnet run +dotnet run --project samples/08-mcp-server/McpServerSample.csproj -- contacts --json +``` + +Expected shape: + +```json +[ + { + "name": "Alice", + "email": "alice@example.com" + }, + { + "name": "Bob", + "email": "bob@example.com" + } +] ``` -**MCP server mode:** +Try another CLI command: ```bash -dotnet run -- mcp serve +dotnet run --project samples/08-mcp-server/McpServerSample.csproj -- contact 1 --json ``` -**Test with MCP Inspector:** +### Interactive REPL mode ```bash -npx @modelcontextprotocol/inspector dotnet run --project . -- mcp serve +dotnet run --project samples/08-mcp-server/McpServerSample.csproj ``` -Clients with MCP Apps support render the `contacts dashboard` tool's generated `ui://contacts/dashboard` resource. Other clients still receive the normal launcher text instead of raw HTML. +Then try: -In the current Repl.Mcp version, MCP Apps are experimental and the UI handler returns generated HTML as a string. Future versions may add richer return types and asset helpers. +```text +contacts +contacts paged --result:page-size=5 +contact 1 +feedback demo +exit +``` -## Demo workflow +### MCP server mode -In the interactive REPL, try: +```bash +dotnet run --project samples/08-mcp-server/McpServerSample.csproj -- mcp serve +``` -- `contacts paged --result:page-size=5` to inspect the first page of a synthetic long directory -- `contacts paged --result:page-size=5 --result:cursor=5` to continue from the next cursor -- `feedback demo` to emit a successful sequence with normal, indeterminate, and warning progress states -- `feedback fail` to emit warning and error progress, then finish with a problem result -- `import contacts.csv` to see the realistic workflow that uses sampling and elicitation when the connected client supports them +This starts a stdio MCP server for the sample app. It waits for an MCP client to connect over stdin/stdout. + +### Test with MCP Inspector + +```bash +npx @modelcontextprotocol/inspector dotnet run --project samples/08-mcp-server/McpServerSample.csproj -- mcp serve +``` In MCP Inspector: @@ -65,31 +97,133 @@ In MCP Inspector: The deterministic `feedback_*` tools make it easy to verify the host's notification rendering without depending on a real CSV file. -## Agent configuration +Clients with MCP Apps support render the `contacts dashboard` tool's generated `ui://contacts/dashboard` resource. Other clients still receive the normal launcher text instead of raw HTML. + +In the current Repl.Mcp version, MCP Apps are experimental and the UI handler returns generated HTML as a string. Future versions may add richer return types and asset helpers. + +## Agent host configuration + +Use an absolute project path in agent-host config. Most hosts launch MCP servers outside your shell's current working directory, so relative paths are fragile. + +Replace `/absolute/path/to/repl` with your local clone path. -### Claude Desktop +### Generic MCP client / Claude Desktop style ```json { "mcpServers": { - "contacts": { + "repl-contacts-sample": { "command": "dotnet", - "args": ["run", "--project", "samples/08-mcp-server", "--", "mcp", "serve"] + "args": [ + "run", + "--project", + "/absolute/path/to/repl/samples/08-mcp-server/McpServerSample.csproj", + "--", + "mcp", + "serve" + ] } } } ``` -### VS Code (GitHub Copilot) +A copyable file lives at [`configs/generic-mcp-client.json`](configs/generic-mcp-client.json). + +### Cursor + +Project config path: `.cursor/mcp.json`. + +```json +{ + "mcpServers": { + "repl-contacts-sample": { + "command": "dotnet", + "args": [ + "run", + "--project", + "/absolute/path/to/repl/samples/08-mcp-server/McpServerSample.csproj", + "--", + "mcp", + "serve" + ] + } + } +} +``` + +A copyable file lives at [`configs/cursor.mcp.json`](configs/cursor.mcp.json). + +### VS Code / GitHub Copilot + +Workspace config path: `.vscode/mcp.json`. ```json { "servers": { - "contacts": { + "repl-contacts-sample": { "type": "stdio", "command": "dotnet", - "args": ["run", "--project", "samples/08-mcp-server", "--", "mcp", "serve"] + "args": [ + "run", + "--project", + "/absolute/path/to/repl/samples/08-mcp-server/McpServerSample.csproj", + "--", + "mcp", + "serve" + ] } } } ``` + +A copyable file lives at [`configs/vscode.mcp.json`](configs/vscode.mcp.json). + +VS Code also supports adding MCP servers from the command line: + +```bash +code --add-mcp '{"name":"repl-contacts-sample","command":"dotnet","args":["run","--project","/absolute/path/to/repl/samples/08-mcp-server/McpServerSample.csproj","--","mcp","serve"]}' +``` + +### Claude Code + +If your Claude Code version supports command-line MCP registration, add the sample like this: + +```bash +claude mcp add repl-contacts-sample -- dotnet run --project /absolute/path/to/repl/samples/08-mcp-server/McpServerSample.csproj -- mcp serve +``` + +Otherwise, use the generic `mcpServers` JSON shape above in the relevant Claude Code project or user settings. + +### Cline + +Use Cline's MCP settings or marketplace flow to add a local stdio server with: + +- command: `dotnet` +- args: `run`, `--project`, `/absolute/path/to/repl/samples/08-mcp-server/McpServerSample.csproj`, `--`, `mcp`, `serve` + +If your Cline version asks for JSON, start from the generic `mcpServers` block above. + +## Adapting this sample to your app + +1. Keep your command handlers small, typed, and dependency-injected. +2. Return JSON-friendly objects instead of prose-only console output. +3. Add `app.UseMcpServer()` to register the hidden `mcp serve` command. +4. Annotate commands that agents can call: + - `.ReadOnly()` for safe queries; + - `.Destructive()` for mutations that need confirmation; + - `.Idempotent()` for operations safe to retry; + - `.OpenWorld()` for external systems; + - `.LongRunning()` for slow work; + - `.AutomationHidden()` for interactive-only or unsafe commands. +5. Document the exact MCP command and args your users should paste into their agent host. + +## Safety note + +Local MCP servers run commands on the user's machine. Only configure MCP servers from trusted repositories, review the command and arguments before starting them, and avoid hardcoding secrets in MCP config files. Prefer environment variables or host-supported secret inputs for API keys. + +## References + +- [MCP Server Integration](../../docs/mcp-overview.md) +- [MCP Server Reference](../../docs/mcp-reference.md) +- [MCP agent capabilities](../../docs/mcp-agent-capabilities.md) +- [MCP transports](../../docs/mcp-transports.md) diff --git a/samples/08-mcp-server/configs/cursor.mcp.json b/samples/08-mcp-server/configs/cursor.mcp.json new file mode 100644 index 0000000..27ff033 --- /dev/null +++ b/samples/08-mcp-server/configs/cursor.mcp.json @@ -0,0 +1,15 @@ +{ + "mcpServers": { + "repl-contacts-sample": { + "command": "dotnet", + "args": [ + "run", + "--project", + "/absolute/path/to/repl/samples/08-mcp-server/McpServerSample.csproj", + "--", + "mcp", + "serve" + ] + } + } +} diff --git a/samples/08-mcp-server/configs/generic-mcp-client.json b/samples/08-mcp-server/configs/generic-mcp-client.json new file mode 100644 index 0000000..27ff033 --- /dev/null +++ b/samples/08-mcp-server/configs/generic-mcp-client.json @@ -0,0 +1,15 @@ +{ + "mcpServers": { + "repl-contacts-sample": { + "command": "dotnet", + "args": [ + "run", + "--project", + "/absolute/path/to/repl/samples/08-mcp-server/McpServerSample.csproj", + "--", + "mcp", + "serve" + ] + } + } +} diff --git a/samples/08-mcp-server/configs/vscode.mcp.json b/samples/08-mcp-server/configs/vscode.mcp.json new file mode 100644 index 0000000..a7c4564 --- /dev/null +++ b/samples/08-mcp-server/configs/vscode.mcp.json @@ -0,0 +1,16 @@ +{ + "servers": { + "repl-contacts-sample": { + "type": "stdio", + "command": "dotnet", + "args": [ + "run", + "--project", + "/absolute/path/to/repl/samples/08-mcp-server/McpServerSample.csproj", + "--", + "mcp", + "serve" + ] + } + } +} diff --git a/samples/README.md b/samples/README.md index 0363665..159c2c6 100644 --- a/samples/README.md +++ b/samples/README.md @@ -20,8 +20,8 @@ If you’re new, start with **01**, then follow the sequence. `Repl.Testing` harness: multi-step + multi-session, typed results, interaction/timeline events, metadata snapshots. 7. [07 — Spectre](07-spectre/) `Repl.Spectre` integration: FigletText, Table, paged result tables, Panel, Tree, BarChart, BreakdownChart, Calendar, JsonText, TextPath, Grid, Columns, Rule, Status, Progress, and all Spectre-powered prompts. -8. [08 — MCP Server](08-mcp-server/) - MCP server mode: tools, paged structured results, resources, prompts, behavioral annotations, automation visibility, and a minimal MCP Apps UI. +8. [08 — Build an MCP Server with Repl.Mcp](08-mcp-server/) + Build a concrete MCP server from a Repl command graph: CLI + REPL + MCP mode, host config snippets for Cursor/VS Code/Claude/Cline, tools, resources, prompts, behavioral annotations, automation visibility, and a minimal MCP Apps UI. ## Run From c6a3c63acc34a1f444d7940bcee56ae86e645633 Mon Sep 17 00:00:00 2001 From: autocarl Date: Sat, 4 Jul 2026 12:14:03 -0400 Subject: [PATCH 2/3] Address MCP sample host configuration review --- README.md | 2 +- docs/mcp-reference.md | 108 +++++++++++----- docs/result-flow.md | 2 +- samples/08-mcp-server/Program.cs | 8 +- samples/08-mcp-server/README.md | 115 +++++++++--------- samples/08-mcp-server/configs/cursor.mcp.json | 15 --- .../configs/generic-mcp-client.json | 1 + samples/08-mcp-server/configs/vscode.mcp.json | 1 + src/Repl.Mcp/README.md | 2 +- 9 files changed, 144 insertions(+), 110 deletions(-) delete mode 100644 samples/08-mcp-server/configs/cursor.mcp.json diff --git a/README.md b/README.md index c1ec166..739ca6a 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/docs/mcp-reference.md b/docs/mcp-reference.md index 27e42b2..5581168 100644 --- a/docs/mcp-reference.md +++ b/docs/mcp-reference.md @@ -335,13 +335,20 @@ app.UseMcpServer(o => ## Agent configuration -Agent hosts configure the app or tool you built with Repl.Mcp. They do not install Repl.Mcp directly. +Agent hosts configure the app or tool you built with Repl.Mcp. They do not +install Repl.Mcp directly. -Prefer a stable executable command, such as a published `dotnet tool`, for shared team configs. When documenting a local sample, use an absolute path to the sample project because most hosts do not launch from your repository root. +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:** `~/.config/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows) +**File:** `~/Library/Application Support/Claude/claude_desktop_config.json` +(macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows) ```json { @@ -354,17 +361,47 @@ Prefer a stable executable command, such as a published `dotnet tool`, for share } ``` -For a local sample project, use the same shape with `dotnet run --project /absolute/path/to/project.csproj -- mcp serve`. +For a local sample project, split the launch into `command` and `args`: + +```json +{ + "mcpServers": { + "repl-contacts-sample": { + "command": "dotnet", + "args": [ + "run", + "--no-build", + "--project", + "/absolute/path/to/repl/samples/08-mcp-server/McpServerSample.csproj", + "--", + "mcp", + "serve" + ] + } + } +} +``` + +On Windows JSON, write paths with doubled backslashes, for example +`C:\Users\you\src\repl\samples\08-mcp-server\McpServerSample.csproj`. ### Claude Code -Claude Code can use a command registration flow when available: +Claude Code uses command registration as the standard flow: ```bash claude mcp add myapp -- myapp mcp serve ``` -If your Claude Code version uses settings files instead, use the generic `mcpServers` JSON shape above in user or project settings. +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 @@ -382,39 +419,34 @@ If your Claude Code version uses settings files instead, use the generic `mcpSer } ``` -VS Code also supports command-line registration: +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 Cline's MCP settings or marketplace flow to add a local stdio server with the same command and args: - -- command: `myapp` -- args: `mcp`, `serve` - -If your Cline version asks for JSON, start from the generic `mcpServers` block above. +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. +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 @@ -424,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. @@ -442,7 +483,8 @@ 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 \ @@ -450,11 +492,19 @@ REPL_RUN_MCP_INSPECTOR_TESTS=1 \ --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()` validates the handler return value before rendering, while `OutputText` / `ReadJson()` 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()` +validates the handler return value before rendering, while `OutputText` / +`ReadJson()` 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 diff --git a/docs/result-flow.md b/docs/result-flow.md index d9a81c9..7a3c4ab 100644 --- a/docs/result-flow.md +++ b/docs/result-flow.md @@ -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) diff --git a/samples/08-mcp-server/Program.cs b/samples/08-mcp-server/Program.cs index e9f51b1..0ecab15 100644 --- a/samples/08-mcp-server/Program.cs +++ b/samples/08-mcp-server/Program.cs @@ -10,11 +10,11 @@ // 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. // -// Run interactively: dotnet run -// Run as MCP server: dotnet run -- mcp serve +// Run interactively from this project: dotnet run +// Run as MCP server after building: dotnet run --no-build -- mcp serve // -// Configure in an MCP host with: -// { "command": "dotnet", "args": ["run", "--project", "path/to/08-mcp-server", "--", "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 => { diff --git a/samples/08-mcp-server/README.md b/samples/08-mcp-server/README.md index 369b04d..ce19721 100644 --- a/samples/08-mcp-server/README.md +++ b/samples/08-mcp-server/README.md @@ -64,6 +64,7 @@ Then try: ```text contacts contacts paged --result:page-size=5 +contacts paged --result:page-size=5 --result:cursor=5 contact 1 feedback demo exit @@ -71,8 +72,16 @@ exit ### MCP server mode +Build the sample once before launching it from MCP Inspector or an agent host: + +```bash +dotnet build samples/08-mcp-server/McpServerSample.csproj +``` + +Then start the stdio MCP server without rebuilding: + ```bash -dotnet run --project samples/08-mcp-server/McpServerSample.csproj -- mcp serve +dotnet run --no-build --project samples/08-mcp-server/McpServerSample.csproj -- mcp serve ``` This starts a stdio MCP server for the sample app. It waits for an MCP client to connect over stdin/stdout. @@ -80,7 +89,7 @@ This starts a stdio MCP server for the sample app. It waits for an MCP client to ### Test with MCP Inspector ```bash -npx @modelcontextprotocol/inspector dotnet run --project samples/08-mcp-server/McpServerSample.csproj -- mcp serve +npx @modelcontextprotocol/inspector dotnet run --no-build --project samples/08-mcp-server/McpServerSample.csproj -- mcp serve ``` In MCP Inspector: @@ -103,35 +112,31 @@ In the current Repl.Mcp version, MCP Apps are experimental and the UI handler re ## Agent host configuration -Use an absolute project path in agent-host config. Most hosts launch MCP servers outside your shell's current working directory, so relative paths are fragile. +Agent hosts should launch a stable, prebuilt command. Plain +`dotnet run --project ...` is fragile in MCP host configs: a cold build can +exceed host startup timeouts, and build or restore output can reach stdout +before the MCP JSON-RPC stream starts. -Replace `/absolute/path/to/repl` with your local clone path. +For this sample: -### Generic MCP client / Claude Desktop style +1. Build once from the repository root: -```json -{ - "mcpServers": { - "repl-contacts-sample": { - "command": "dotnet", - "args": [ - "run", - "--project", - "/absolute/path/to/repl/samples/08-mcp-server/McpServerSample.csproj", - "--", - "mcp", - "serve" - ] - } - } -} -``` + ```bash + dotnet build samples/08-mcp-server/McpServerSample.csproj + ``` + +2. Put `dotnet run --no-build --project ... -- mcp serve` in host config, or + replace it with a published app executable if you package the sample. + +Replace path placeholders before copying: -A copyable file lives at [`configs/generic-mcp-client.json`](configs/generic-mcp-client.json). +- macOS/Linux JSON: `/absolute/path/to/repl`. +- Windows JSON: `C:\Users\you\src\repl` (JSON requires doubled + backslashes). -### Cursor +### Shared `mcpServers` JSON -Project config path: `.cursor/mcp.json`. +Use this shape for Claude Desktop, Cursor, Cline, and generic MCP clients: ```json { @@ -140,6 +145,7 @@ Project config path: `.cursor/mcp.json`. "command": "dotnet", "args": [ "run", + "--no-build", "--project", "/absolute/path/to/repl/samples/08-mcp-server/McpServerSample.csproj", "--", @@ -151,57 +157,48 @@ Project config path: `.cursor/mcp.json`. } ``` -A copyable file lives at [`configs/cursor.mcp.json`](configs/cursor.mcp.json). +A copyable file lives at +[`configs/generic-mcp-client.json`](configs/generic-mcp-client.json). + +Common file locations: + +- Claude Desktop macOS: + `~/Library/Application Support/Claude/claude_desktop_config.json` +- Claude Desktop Windows: + `%APPDATA%\Claude\claude_desktop_config.json` +- Cursor project config: `.cursor/mcp.json` +- Cursor global config: `~/.cursor/mcp.json` +- Cline: use **Configure MCP Servers** to edit `cline_mcp_settings.json`. + The Cline marketplace is for published/curated servers; it will not install + this local sample. ### VS Code / GitHub Copilot Workspace config path: `.vscode/mcp.json`. -```json -{ - "servers": { - "repl-contacts-sample": { - "type": "stdio", - "command": "dotnet", - "args": [ - "run", - "--project", - "/absolute/path/to/repl/samples/08-mcp-server/McpServerSample.csproj", - "--", - "mcp", - "serve" - ] - } - } -} -``` - A copyable file lives at [`configs/vscode.mcp.json`](configs/vscode.mcp.json). -VS Code also supports adding MCP servers from the command line: +For macOS/Linux shells, VS Code also supports command-line registration: ```bash -code --add-mcp '{"name":"repl-contacts-sample","command":"dotnet","args":["run","--project","/absolute/path/to/repl/samples/08-mcp-server/McpServerSample.csproj","--","mcp","serve"]}' +code --add-mcp '{"name":"repl-contacts-sample","command":"dotnet","args":["run","--no-build","--project","/absolute/path/to/repl/samples/08-mcp-server/McpServerSample.csproj","--","mcp","serve"]}' ``` +On Windows, prefer editing `.vscode/mcp.json`. The `code.cmd --add-mcp` +argument path can mangle inline JSON in common shells. If you write JSON by +hand, use doubled backslashes in paths, for example +`C:\Users\you\src\repl\samples\08-mcp-server\McpServerSample.csproj`. + ### Claude Code -If your Claude Code version supports command-line MCP registration, add the sample like this: +Use the standard command registration flow: ```bash -claude mcp add repl-contacts-sample -- dotnet run --project /absolute/path/to/repl/samples/08-mcp-server/McpServerSample.csproj -- mcp serve +claude mcp add repl-contacts-sample -- dotnet run --no-build --project /absolute/path/to/repl/samples/08-mcp-server/McpServerSample.csproj -- mcp serve ``` -Otherwise, use the generic `mcpServers` JSON shape above in the relevant Claude Code project or user settings. - -### Cline - -Use Cline's MCP settings or marketplace flow to add a local stdio server with: - -- command: `dotnet` -- args: `run`, `--project`, `/absolute/path/to/repl/samples/08-mcp-server/McpServerSample.csproj`, `--`, `mcp`, `serve` - -If your Cline version asks for JSON, start from the generic `mcpServers` block above. +For file-based provisioning, use the shared `mcpServers` JSON shape above in +`.mcp.json` at the project root or in `~/.claude.json` for user/local settings. ## Adapting this sample to your app diff --git a/samples/08-mcp-server/configs/cursor.mcp.json b/samples/08-mcp-server/configs/cursor.mcp.json deleted file mode 100644 index 27ff033..0000000 --- a/samples/08-mcp-server/configs/cursor.mcp.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "mcpServers": { - "repl-contacts-sample": { - "command": "dotnet", - "args": [ - "run", - "--project", - "/absolute/path/to/repl/samples/08-mcp-server/McpServerSample.csproj", - "--", - "mcp", - "serve" - ] - } - } -} diff --git a/samples/08-mcp-server/configs/generic-mcp-client.json b/samples/08-mcp-server/configs/generic-mcp-client.json index 27ff033..2e94cf4 100644 --- a/samples/08-mcp-server/configs/generic-mcp-client.json +++ b/samples/08-mcp-server/configs/generic-mcp-client.json @@ -4,6 +4,7 @@ "command": "dotnet", "args": [ "run", + "--no-build", "--project", "/absolute/path/to/repl/samples/08-mcp-server/McpServerSample.csproj", "--", diff --git a/samples/08-mcp-server/configs/vscode.mcp.json b/samples/08-mcp-server/configs/vscode.mcp.json index a7c4564..057eef0 100644 --- a/samples/08-mcp-server/configs/vscode.mcp.json +++ b/samples/08-mcp-server/configs/vscode.mcp.json @@ -5,6 +5,7 @@ "command": "dotnet", "args": [ "run", + "--no-build", "--project", "/absolute/path/to/repl/samples/08-mcp-server/McpServerSample.csproj", "--", diff --git a/src/Repl.Mcp/README.md b/src/Repl.Mcp/README.md index f3e4e52..06ee966 100644 --- a/src/Repl.Mcp/README.md +++ b/src/Repl.Mcp/README.md @@ -49,7 +49,7 @@ Most MCP clients use the same shape: } ``` -Use the executable or `dotnet run --project ... -- mcp serve` command that matches your app packaging. +Use the executable that matches your app packaging. For local project samples, build once and use `dotnet run --no-build --project ... -- mcp serve` so host startup does not rebuild or write build output to stdout. ## MCP Apps From 4b6209ace1e09af27138fe7e9f27904ddf9c584f Mon Sep 17 00:00:00 2001 From: autocarl Date: Sat, 4 Jul 2026 14:53:38 -0400 Subject: [PATCH 3/3] docs: escape Windows JSON path examples --- docs/mcp-reference.md | 2 +- samples/08-mcp-server/README.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/mcp-reference.md b/docs/mcp-reference.md index 5581168..5190316 100644 --- a/docs/mcp-reference.md +++ b/docs/mcp-reference.md @@ -383,7 +383,7 @@ For a local sample project, split the launch into `command` and `args`: ``` On Windows JSON, write paths with doubled backslashes, for example -`C:\Users\you\src\repl\samples\08-mcp-server\McpServerSample.csproj`. +`C:\\Users\\you\\src\\repl\\samples\\08-mcp-server\\McpServerSample.csproj`. ### Claude Code diff --git a/samples/08-mcp-server/README.md b/samples/08-mcp-server/README.md index ce19721..45bfa42 100644 --- a/samples/08-mcp-server/README.md +++ b/samples/08-mcp-server/README.md @@ -131,7 +131,7 @@ For this sample: Replace path placeholders before copying: - macOS/Linux JSON: `/absolute/path/to/repl`. -- Windows JSON: `C:\Users\you\src\repl` (JSON requires doubled +- Windows JSON: `C:\\Users\\you\\src\\repl` (JSON requires doubled backslashes). ### Shared `mcpServers` JSON @@ -187,7 +187,7 @@ code --add-mcp '{"name":"repl-contacts-sample","command":"dotnet","args":["run", On Windows, prefer editing `.vscode/mcp.json`. The `code.cmd --add-mcp` argument path can mangle inline JSON in common shells. If you write JSON by hand, use doubled backslashes in paths, for example -`C:\Users\you\src\repl\samples\08-mcp-server\McpServerSample.csproj`. +`C:\\Users\\you\\src\\repl\\samples\\08-mcp-server\\McpServerSample.csproj`. ### Claude Code