# `ClaudeWrapper.Commands.Mcp`
[🔗](https://github.com/genagent/claude_wrapper_ex/blob/main/lib/claude_wrapper/commands/mcp.ex#L1)

MCP (Model Context Protocol) server management commands.

Wraps `claude mcp add|add-json|add-from-claude-desktop|remove|list|get|serve|login|logout|reset-project-choices`.

## Usage

    config = ClaudeWrapper.Config.new()

    # List / inspect configured servers (raw text; the CLI has no JSON mode)
    {:ok, servers_text} = ClaudeWrapper.Commands.Mcp.list(config)
    {:ok, server_text} = ClaudeWrapper.Commands.Mcp.get(config, "sentry")

    # Add an HTTP server with an auth header
    {:ok, _} =
      ClaudeWrapper.Commands.Mcp.add(config, "sentry", "https://mcp.sentry.dev/mcp",
        [],
        transport: :http,
        header: ["Authorization: Bearer abc123"],
        scope: :user
      )

    # Add a stdio server with env vars and subprocess args
    {:ok, _} =
      ClaudeWrapper.Commands.Mcp.add(config, "my-server", "npx", [],
        env: %{"API_KEY" => "xxx"},
        server_args: ["my-mcp-server"]
      )

    # Add from a JSON blob, prompting for the OAuth client secret
    {:ok, _} =
      ClaudeWrapper.Commands.Mcp.add_json(config, "srv", ~s({"command":"npx"}),
        client_secret: true
      )

    # Import from Claude Desktop (Mac and WSL only)
    {:ok, _} = ClaudeWrapper.Commands.Mcp.add_from_desktop(config, nil, scope: :user)

    # Run Claude Code itself as an MCP server
    {:ok, _} = ClaudeWrapper.Commands.Mcp.serve(config, verbose: true)

# `scope`

```elixir
@type scope() :: :local | :user | :project
```

# `transport`

```elixir
@type transport() :: :stdio | :sse | :http
```

# `add`

```elixir
@spec add(ClaudeWrapper.Config.t(), String.t(), String.t(), [String.t()], keyword()) ::
  {:ok, String.t()} | {:error, term()}
```

Add an MCP server.

`command_or_url` is the stdio command (e.g. `"npx"`) or the server URL for
HTTP/SSE transports. Trailing `command_args` are passed through as positional
arguments; prefer `:server_args` (which uses the CLI's `--` separator) for
flags that would otherwise be parsed by `claude` itself.

## Options

  * `:transport` - Transport type (`:stdio`, `:sse`, or `:http`). Emits
    `--transport`. The CLI defaults to stdio when omitted.
  * `:scope` - Configuration scope (`:local`, `:user`, or `:project`). Emits
    `--scope`.
  * `:env` - Environment variables as a map or keyword list. Each pair emits
    `-e KEY=value`.
  * `:header` - WebSocket/HTTP headers for HTTP/SSE transports. Accepts a list
    of `"Key: Value"` strings or a map (each pair rendered `"Key: Value"`).
    Each header emits its own `--header` flag.
  * `:server_args` - Extra arguments for the server command, emitted after a
    `--` separator so `claude` does not interpret them.
  * `:callback_port` - Fixed port for the OAuth callback (`--callback-port`).
  * `:client_id` - OAuth client ID for HTTP/SSE servers (`--client-id`).
  * `:client_secret` - Prompt for the OAuth client secret (`--client-secret`,
    boolean; or set the `MCP_CLIENT_SECRET` env var).

# `add_from_desktop`

```elixir
@spec add_from_desktop(
  ClaudeWrapper.Config.t(),
  keyword()
) :: {:ok, String.t()} | {:error, term()}
```

Import MCP servers from Claude Desktop (Mac and WSL only).

`claude mcp add-from-claude-desktop` takes no name argument -- it imports
all Desktop servers -- so this accepts only options.

## Options

  * `:scope` - Configuration scope (`:local`, `:user`, or `:project`). Emits
    `--scope`.

# `add_json`

```elixir
@spec add_json(ClaudeWrapper.Config.t(), String.t(), String.t(), keyword()) ::
  {:ok, String.t()} | {:error, term()}
```

Add an MCP server from a JSON configuration.

## Options

  * `:scope` - Configuration scope (`:local`, `:user`, or `:project`). Emits
    `--scope`.
  * `:client_secret` - Prompt for the OAuth client secret (`--client-secret`,
    boolean; or set the `MCP_CLIENT_SECRET` env var).

# `get`

```elixir
@spec get(ClaudeWrapper.Config.t(), String.t()) ::
  {:ok, String.t()} | {:error, term()}
```

Get details for a specific MCP server.

`claude mcp get` emits human-readable text (it has no JSON mode), so
this returns the raw, trimmed output rather than structured data. The
subcommand takes only the server name (no `--scope`).

# `list`

```elixir
@spec list(ClaudeWrapper.Config.t()) :: {:ok, String.t()} | {:error, term()}
```

List configured MCP servers.

`claude mcp list` emits human-readable text (it has no JSON mode), so
this returns the raw, trimmed output rather than structured data. The
subcommand takes no `--scope` (it lists every scope).

# `remove`

```elixir
@spec remove(ClaudeWrapper.Config.t(), String.t(), keyword()) ::
  {:ok, String.t()} | {:error, term()}
```

Remove an MCP server.

## Options

  * `:scope` - Configuration scope (`:local`, `:user`, or `:project`). When
    omitted the CLI removes the server from whichever scope it exists in.

# `reset_project_choices`

```elixir
@spec reset_project_choices(ClaudeWrapper.Config.t()) ::
  {:ok, String.t()} | {:error, term()}
```

Reset project choices for MCP servers.

# `serve`

```elixir
@spec serve(
  ClaudeWrapper.Config.t(),
  keyword()
) :: {:ok, String.t()} | {:error, term()}
```

Start the Claude Code MCP server.

Wraps `claude mcp serve`, which exposes this Claude Code installation as an
MCP server over stdio.

## Options

  * `:debug` - Enable debug mode (`--debug`, boolean).
  * `:verbose` - Override the verbose-mode setting from config (`--verbose`,
    boolean).

---

*Consult [api-reference.md](api-reference.md) for complete listing*
