Skip to content
Draft
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
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
46 changes: 33 additions & 13 deletions docs/mcp-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,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)

Expand All @@ -342,24 +346,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
{
Expand All @@ -373,6 +374,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)
Expand All @@ -388,6 +395,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

```bash
Expand Down
5 changes: 4 additions & 1 deletion samples/08-mcp-server/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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 =>
Expand Down
188 changes: 161 additions & 27 deletions samples/08-mcp-server/README.md
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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:

Expand All @@ -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)
15 changes: 15 additions & 0 deletions samples/08-mcp-server/configs/cursor.mcp.json
Original file line number Diff line number Diff line change
@@ -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"
]
}
}
}
15 changes: 15 additions & 0 deletions samples/08-mcp-server/configs/generic-mcp-client.json
Original file line number Diff line number Diff line change
@@ -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"
]
}
}
}
Loading
Loading