# Technical Documentation: docker/mcp-gateway

> ℹ️ **Provenance:** Multi-Tier Ingestion · [CodeWiki Reference](https://codewiki.google/github.com/docker/mcp-gateway)

### Overview (README.md)

# Docker MCP Plugin and Docker MCP Gateway



The [MCP Toolkit](https://docs.docker.com/ai/mcp-catalog-and-toolkit/toolkit/), in Docker Desktop, allows
developers to configure and consume MCP servers from the [Docker MCP Catalog](https://hub.docker.com/mcp).

Underneath, the Toolkit is powered by a docker CLI plugin: `docker-mcp`. This repository is the code of this CLI plugin. It can work in Docker Desktop or independently.

The main feature of this CLI is the **Docker MCP Gateway** which allows easy and secure running and deployment of MCP servers. See [Features](#Features) for a list of all the features.

## What is MCP?

The [Model Context Protocol (MCP)](https://spec.modelcontextprotocol.io/) is an open protocol that standardizes how AI applications connect to external data sources and tools. It provides a secure, controlled way for language models to access and interact with various services, databases, and APIs.

## Overview

Developers face criticial barriers when integrating Model Context Protocol (MCP) tools into production workflows:

- **Managing MCP server lifecycle** Each local MCP sever in the catalog runs in an isolated Docker container. npx and uvx servers are granted minimal host privileges.
- **Providing a unified interface** AI models access MCP servers through a single Gateway.
- **Handling authentication and security** Keep secrets out of environment variables using Docker Desktop's secrets management.
- **Supports dynamic tool discovery** and configuration. Each MCP client (eg VS Code, Cursor, Claude Desktop, etc.) connects to the same Gateway configuration, ensuring consistency across different clients.
- **Enables OAuth flows** for MCPs that require OAuth access token service connections.

## Features

- 🐳 **Container-based Servers**: Run MCP servers as Docker containers with proper isolation.
- 🔧 **Server Management**: List, inspect, and call MCP tools, resources and prompts from multiple servers.
- 🔐 **Secrets Management**: Secure handling of API keys and credentials via Docker Desktop.
- 🌐 **OAuth Integration**: Built-in OAuth flows for service authentication.
- 📋 **Server Catalog**: Manage and configure multiple MCP catalogs.
- 🔍 **Dynamic Discovery**: Automatic tool, prompt, and resource discovery from running servers.
- 📊 **Monitoring**: Built-in logging and call tracing capabilities.

## Installation

### Prerequisites

- Docker Desktop `4.59+` (with MCP Toolkit feature enabled)

<div align="left">
  <img src="./img/enable_toolkit.png" width="400"/>
</div>
- Go 1.24+ (for development)

### Install as Docker CLI Plugin

The MCP cli will already be installed on recent versions of Docker Desktop but you can build and install the latest version by following these steps:

```bash
# Clone the repository
git clone https://github.com/docker/mcp-gateway.git
cd mcp-gateway
mkdir -p "$HOME/.docker/cli-plugins/"

# Build and install the plugin
make docker-mcp
```

After installation, the plugin will be available as:

```bash
docker mcp --help
```

## Usage

> [!NOTE]
> **Running without Docker Desktop Feature Flags**
>
> If you encounter "Docker Desktop is not running" errors when the Docker daemon is active, you can bypass Desktop feature checks by setting:
> ```bash
> export DOCKER_MCP_IN_CONTAINER=1
> ```
> This is useful when running in WSL2, containerized environments, or Docker CE where Desktop backend sockets are unavailable.

> [!NOTE]
> **Enabling Profiles outside Docker Desktop**
>
> Profiles are enabled automatically in Docker Desktop. If you are using the CLI independently (e.g. Docker CE, WSL2, or a containerized environment), enable the profiles feature first:
> ```bash
> docker mcp feature enable profiles
> ```

### Profile Management

Servers are organized into **profiles**. A profile groups related MCP servers together and can be connected to clients, exported, and shared via OCI registries.

Servers in a profile can reference multiple sources:
- **Catalog references**: `catalog://mcp/docker-mcp-catalog/github`
- **OCI image references**: `docker://my-server:latest`
- **MCP Registry references**: `https://registry.modelcontextprotocol.io/v0/servers/<id>`
- **Local file references**: `file://./server.yaml`

```bash
# Make sure to `docker mcp catalog pull mcp/docker-mcp-catalog` first.

# Create a new profile
docker mcp profile create --name dev-tools \
  --server catalog://mcp/docker-mcp-catalog/github

# Create a profile and connect it to a client
docker mcp profile create --name dev-tools \
  --server catalog://mcp/docker-mcp-catalog/github \
  --connect cursor

# List all profiles
docker mcp profile list

# Show profile details
docker mcp profile show <profile-id>

# Remove a profile
docker mcp profile remove <profile-id>

# Export/import profiles
docker mcp profile export <profile-id> output.yaml
docker mcp profile import input.yaml

# Push/pull profiles to OCI registries
docker mcp profile push <profile-id> <oci-reference>
docker mcp profile pull <oci-reference>
```

#### Manage servers in a profile

```bash
# List servers across all profiles
docker mcp profile server ls

# Filter servers by name or profile
docker mcp profile server ls --filter name=github
docker mcp profile server ls --filter profile=dev-tools

# Add servers to a profile
docker mcp profile server add dev-tools \
  --server catalog://mcp/docker-mcp-catalog/notion

# Remove servers from a profile
docker mcp profile server remove dev-tools github slack
```

#### Configure servers in a profile

```bash
# Set configuration values (<server-name>.<config-key>=<value>)
docker mcp profile config <profile-id> --set github.timeout=30

# Get configuration values (<server-name>.<config-key>)
docker mcp profile config <profile-id> --get github.timeout

# Get all configuration
docker mcp profile config <profile-id> --get-all

# Delete configuration values (<server-name>.<config-key>)
docker mcp profile config <profile-id> --del github.timeout
```

#### Manage tool allowlists in a profile

```bash
# Enable specific tools (dot notation: <server>.<tool>)
docker mcp profile tools <profile-id> --enable github.create_issue --enable github.list_repos

# Disable specific tools
docker mcp profile tools <profile-id> --disable github.search_code

# Enable/disable all tools for a server
docker mcp profile tools <profile-id> --enable-all github
docker mcp profile tools <profile-id> --disable-all github
```

### Catalog Management

Manage the OCI-based catalogs available to the MCP gateway. The [default catalog](https://hub.docker.com/mcp) is the image `mcp/docker-mcp-catalog`.

```bash
# List catalogs
docker mcp catalog ls

# Show a catalog
docker mcp catalog show <oci-reference>

# Create a catalog from server references
docker mcp catalog create myorg/catalog:latest --title "My Catalog" \
  --server catalog://mcp/docker-mcp-catalog/github \
  --server file://./my-server.yaml

# Create a catalog from an existing profile
docker mcp catalog create myorg/catalog:latest --from-profile dev-tools

# Create a catalog from the community registry
docker mcp catalog create myorg/catalog:latest \
  --from-community-registry registry.modelcontextprotocol.io

# Push/pull catalogs to OCI registries
docker mcp catalog push <oci-reference>
docker mcp catalog pull <oci-reference>

# Manage servers within a catalog
docker mcp catalog server ls <oci-reference>
docker mcp catalog server add <oci-reference> --server docker://my-server:latest
docker mcp catalog server remove <oci-reference> github
docker mcp catalog server inspect <oci-reference> <server-name>

# Remove a catalog
docker mcp catalog remove <oci-reference>

# Tag a catalog
docker mcp catalog tag <source>:<tag> <target>:<tag>
```


More about [importing from the OSS MCP Community Registry](docs/catalog.md#importing-from-the-oss-mcp-community-registry).

### MCP Gateway Operations

Start up an MCP Gateway. This can be used for one client, or to service multiple clients if using either `sse` or `streaming` transports.

```bash
# Run the MCP gateway (stdio, using the default profile)
docker mcp gateway run

# Run with a specific profile
docker mcp gateway run --profile dev-tools

# Run the MCP gateway (streaming)
docker mcp gateway run --port 8080 --transport streaming
```

If no `--profile` flag is provided, the gateway uses the `default` profile.

* more about [the MCP Gateway](docs/mcp-gateway.md)

### Client Connection

Connect AI clients to the MCP gateway.

```bash
# List client configurations
docker mcp client ls

# Connect a client to a profile
docker mcp client connect <client-name> --profile <profile-id>

# Disconnect from a client
docker mcp client disconnect <client-name>
```

### Secrets and OAuth

Configure MCP servers that require either secrets or OAuth.

```bash
# Manage secrets
docker mcp secret --help

# Handle OAuth flows
docker mcp oauth --help

# export any desktop secrets needed by either server1 or server2
#   (temporary requirement to export secrets for docker cloud runs - this command
#    will no longer be required once Docker Cloud can access secret stores)
docker mcp secret export server1 server2
```

### Tool Management

```bash
# Count available tools
docker mcp tools count

# List all available MCP tools
docker mcp tools ls

# List all available MCP tools in JSON format
docker mcp tools ls --format=json

# Inspect a specific tool
docker mcp tools inspect <tool-name>

# Call a tool with arguments
docker mcp tools call <tool-name> [arguments...]

# Enable/disable tools for a server in a profile
docker mcp profile tools <profile-id> --enable <server>.<tool>
docker mcp profile tools <profile-id> --disable <server>.<tool>
```

## Configuration

Configuration is stored in a local database. Profiles, catalogs, and server configuration are managed through the `docker mcp profile` and `docker mcp catalog` commands. Feature flags are stored in `~/.docker/config.json`.

### Environment Variables

The MCP CLI respects the following environment variables for client configuration:

- **`CLAUDE_CONFIG_DIR`**: Override the default Claude Code configuration directory (`~/.claude`). When set, Claude Code will use `$CLAUDE_CONFIG_DIR/.claude.json` instead of `~/.claude.json` for its MCP server configuration. This is useful for:
  - Maintaining separate Claude Code installations for work and personal use
  - Testing configuration changes in isolation
  - Managing multiple Claude Code profiles

Example usage:
```bash
# Set custom Claude Code configuration directory
export CLAUDE_CONFIG_DIR=/path/to/custom/config

# Connect MCP Gateway to Claude Code
docker mcp client connect claude-code --profile dev-tools --global

# Claude Code will now use /path/to/custom/config/.claude.json
```

## Architecture

The Docker MCP CLI implements a gateway pattern:

```
AI Client → MCP Gateway → MCP Servers (Docker Containers)
```

- **AI Client**: Language model or AI application
- **MCP Gateway**: This CLI tool managing protocol translation and routing
- **MCP Servers**: Individual MCP servers running in Docker containers

See [docs/message-flow.md](docs/message-flow.md) for detailed message flow diagrams.

## Contributing

The build instructions are available in the [contribution guide](CONTRIBUTING.md).

## License

This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

## Support

- 💬 [Troubleshooting](/docs/troubleshooting.md)
- 📖 [MCP Specification](https://modelcontextprotocol.io/specification/2025-11-25)
- 🐳 [Docker Desktop Documentation](https://docs.docker.com/desktop/)
- 🐛 [Report Issues](https://github.com/docker/mcp-gateway/issues)
- 💬 [Discussions](https://github.com/docker/mcp-gateway/discussions)

---

### Database README (`docs/database/README.md`)

# Docker MCP Gateway Database

## Overview

The Docker MCP Gateway uses an embedded SQLite database to store configuration data, profiles (working sets), server catalogs, and migration status. The database is located at `~/.docker/mcp/mcp-toolkit.db` and is automatically created and migrated when the CLI first runs.

This document covers the database architecture, migration system, concurrent access handling, and troubleshooting.

## Architecture

### Database Location

```
~/.docker/mcp/
├── mcp-toolkit.db           # Main SQLite database
├── .mcp-toolkit-migration.lock  # Migration lock file (persists after creation)
```

### Database Schema

The database schema is managed through versioned migrations in `pkg/db/migrations/`

### Key Components

**Database Package** (`pkg/db/`)
   - DAO interface for all database operations
   - Migration management with golang-migrate
   - Connection pooling and configuration
   - File locking for concurrent access safety


## Migration System

### How Migrations Work

The Docker MCP Gateway uses [golang-migrate](https://github.com/golang-migrate/migrate) for schema versioning:

```
Application Startup
    ↓
pkg/db/New() called
    ↓
[Acquire File Lock] ← Prevents concurrent migrations
    ↓
Check current database version
    ↓
Database version > available migrations?
    ├─ Yes → Return error (database from newer version)
    └─ No  → Run pending migrations sequentially
    ↓
[Release File Lock]
    ↓
Database ready for use
```

### Migration Lock File

To prevent race conditions when multiple processes start simultaneously, migrations use an OS-level file lock:

- **Lock File**: `~/.docker/mcp/.mcp-toolkit-migration.lock`
- **Library**: `github.com/gofrs/flock` (cross-platform)
- **Persistence**: The lock file persists on disk after migrations complete (this is intentional and safe)

### Migration Operations

Migrations use both SQLite locks AND file locks:
- File lock prevents multiple processes from attempting migrations
- SQLite locks protect individual migration transactions
- This two-level locking ensures safety during initialization

### Why File Locking Is Necessary

Migrations with [golang-migrate](https://github.com/golang-migrate/migrate) are not run within a single transaction. There is the possibility
for a race condition if two process concurrently attempt to run the migrations.

**The Problem**: When multiple processes start simultaneously:
1. All check the database state (clean)
2. All try to run migrations at the same time
3. Race condition occurs → "Dirty database version" error

**The Solution**: OS-level file locking ensures only one process runs migrations at a time. Other processes wait, then see migrations already complete.

### Database Version Compatibility

#### Running Older Version After Newer Version

If you run an older version of the tool after having used a newer version, the database may be at a higher schema version than the older tool expects. In this case:

- The tool detects the database is ahead of available migrations
- An error is returned to prevent potential data corruption:
  ```
  database version 8 (~/.docker/mcp/mcp-toolkit.db) is ahead of the current application version. Please upgrade to the latest version
  ```

## Testing

### Concurrent Migration Test

Test that file locking prevents migration race conditions:

```bash
go run test_migration_race.go
```

This test launches 100 concurrent processes that all try to initialize the database simultaneously. With file locking, all 100 should succeed (100% success rate). Without file locking, most would fail with "Dirty database version" errors.

---

### Telemetry README (`docs/telemetry/README.md`)

# Docker MCP Gateway Telemetry

## Overview

The Docker MCP Gateway now includes comprehensive OpenTelemetry (OTEL) instrumentation to provide visibility into Model Context Protocol (MCP) operations. This telemetry system tracks all interactions between AI clients and MCP servers, providing metrics and distributed tracing for debugging, monitoring, and performance analysis.

## Architecture

### Data Flow

The telemetry system captures data at multiple points in the MCP Gateway architecture:

```
AI Client (e.g., Claude Code)
    ↓
[Gateway Entry Point] → Records gateway startup
    ↓
[Interceptor Middleware] → Tracks list operations
    ↓
[Protocol Handlers] → Records tool/prompt/resource operations
    ↓
[MCP Servers] → Executes requested operations
    ↓
[Response Path] → Records duration, errors, results
    ↓
[OTEL Collector] → Aggregates and exports metrics
```

### Key Components

1. **Telemetry Package** (`internal/telemetry`)
   - Initializes OTEL tracer and meter from global providers
   - Defines all metrics and span creation functions
   - Provides recording functions for each operation type

2. **Interceptor Middleware** (`internal/interceptors`)
   - Tracks list operations (tools/list, prompts/list, resources/list, resourceTemplates/list)
   - Creates spans for tracking operation flow
   - Records metrics before operations reach handlers

3. **Protocol Handlers** (`internal/gateway/handlers.go`)
   - Instruments tool calls, prompt retrievals, and resource reads
   - Preserves server lineage in all telemetry
   - Records operation duration and errors

4. **Periodic Export** (`internal/gateway/run.go`)
   - Exports metrics every 30 seconds for long-running gateways
   - Configurable via `DOCKER_MCP_METRICS_INTERVAL` environment variable
   - Ensures metrics are available without waiting for shutdown

## Telemetry Coverage

### Gateway Operations

#### Startup and Lifecycle
- **`mcp.gateway.starts`** - Records when the gateway starts, including transport mode (stdio/sse/streaming)
- **`mcp.initialize`** - Records when the host initializes a connection with the gateway

#### Discovery Operations
When the gateway connects to MCP servers, it discovers their capabilities:
- **`mcp.tools.discovered`** - Number of tools available per server
- **`mcp.prompts.discovered`** - Number of prompts available per server
- **`mcp.resources.discovered`** - Number of resources available per server
- **`mcp.resource_templates.discovered`** - Number of resource templates available per server

#### Tool Schema Dialects
A discovered tool schema that declares JSON Schema draft-04, draft-06 or draft-07 is
translated into 2020-12, the only dialect MCP requires clients to support:
- **`mcp.tool.schema_dialects`** - Counter of tool schemas by what the gateway did with the
  dialect they declared. Attributes: `mcp.server.origin`, `mcp.tool.schema_field`
  (`inputSchema` or `outputSchema`) and `mcp.tool.schema_outcome`:
  - `translated` - a declared draft-04/06/07 schema was converted to 2020-12
  - `relayed` - a declared draft-04/06/07 schema held a construct with no faithful 2020-12
    equivalent, so it was passed through as declared
  - `unsupported_dialect` - the schema declared a dialect the gateway does not translate at
    all (draft-03, 2019-09, anything unrecognised). Equally rejected by a 2020-12-only
    client, and not fixable here

This counter is not a census of discovered schemas. A schema that declares no dialect is
already 2020-12 by default and is never counted, and nothing is recorded at all when the
gateway runs with `--preserve-tool-schema-dialect`. A flat zero across all three outcomes
therefore means no server declares any dialect.

### Client Operations

#### List Operations
When clients query available capabilities:
- **`mcp.list.tools`** - Client requests list of available tools
- **`mcp.list.prompts`** - Client requests list of available prompts
- **`mcp.list.resources`** - Client requests list of available resources
- **`mcp.list.resource_templates`** - Client requests list of available resource templates

### Protocol Operations

#### Tool Calls
- **`mcp.tool.calls`** - Counter of tool invocations
- **`mcp.tool.duration`** - Histogram of end-to-end tool call handling time, including validation and policy checks (milliseconds)
- **`mcp.tool.errors`** - Counter of tool execution failures

#### Prompt Operations
- **`mcp.prompt.gets`** - Counter of prompt retrievals
- **`mcp.prompt.duration`** - Histogram of prompt operation time
- **`mcp.prompt.errors`** - Counter of prompt operation failures

#### Resource Operations
- **`mcp.resource.reads`** - Counter of resource reads
- **`mcp.resource.duration`** - Histogram of resource operation time
- **`mcp.resource.errors`** - Counter of resource operation failures

#### Resource Template Operations
- **`mcp.resource_template.reads`** - Counter of resource template reads
- **`mcp.resource_template.duration`** - Histogram of template operation time
- **`mcp.resource_template.errors`** - Counter of template operation failures

### CLI Direct Operations

When using the Docker CLI directly (not through the gateway):
- **`mcp.cli.tool.calls`** - Tool calls made directly from CLI
- **`mcp.cli.tool.duration`** - CLI tool execution duration
- **`mcp.cli.tools.discovered`** - Tools discovered via CLI commands

### Catalog Management

Operations for managing MCP server configurations:
- **`mcp.catalog.operations`** - Catalog management operations (ls, add, rm, create, push, pull, remove)
- **`mcp.catalog.operation.duration`** - Duration of catalog operations
- **`mcp.catalog.servers`** - Gauge showing number of servers in catalogs

### Profile Operations

Operations for managing working sets (profiles) of servers:
- **`mcp.profile.operations`** - Profile operations (create, push, pull, remove)
- **`mcp.profile.operation.duration`** - Duration of profile operations

## Metric Attributes

All metrics include contextual attributes for filtering and aggregation:

### Common Attributes
- **`mcp.server.name`** - Name of the MCP server handling the operation
- **`mcp.server.origin`** - Name of the MCP server a capability was discovered on. This is
  what discovery and listing metrics carry; `mcp.server.name` is used on the tool-error
  path, paired with `mcp.server.type`
- **`mcp.server.type`** - Type of server (docker, stdio, sse, unknown)

### Initialize Attributes
- **`mcp.client.name`** - Name of the connecting client (e.g. `claude-ai`)
- **`mcp.client.version`** - Version of the connecting client (e.g. `0.1.0`)

### Operation-Specific Attributes
- **`mcp.tool.name`** - Name of the tool being called
- **`mcp.prompt.name`** - Name of the prompt being retrieved
- **`mcp.resource.uri`** - URI of the resource being read
- **`mcp.operation.error`** - Error message if operation failed
- **`mcp.transport.mode`** - Gateway transport mode (stdio, sse, streaming)

### Catalog Attributes
- **`mcp.catalog.operation`** - Type of catalog operation (ls, add, rm, create, push, pull, remove)
- **`mcp.catalog.name`** - Name or reference of the catalog
- **`mcp.catalog.success`** - Boolean indicating operation success

### Profile Attributes
- **`mcp.profile.operation`** - Type of profile operation (create, push, pull, remove)
- **`mcp.profile.id`** - Profile identifier
- **`mcp.profile.success`** - Boolean indicating operation success

### Tool Schema Dialect Attributes
- **`mcp.tool.schema_field`** - Which schema of the tool (`inputSchema`, `outputSchema`)
- **`mcp.tool.schema_outcome`** - What the gateway did with the declared dialect
  (`translated`, `relayed`, `unsupported_dialect`)

## Distributed Tracing

The system creates spans for tracking operation flow:

### Span Hierarchy
```
gateway.run
├── tools/list
├── prompts/list
├── resources/list
├── resourceTemplates/list
├── mcp.tool.call
│   └── [tool execution]
├── mcp.prompt.get
│   └── [prompt retrieval]
├── mcp.resource.read
│   └── [resource read]
└── mcp.resource_template.read
    └── [template read]
```

### Span Attributes
Each span includes:
- Operation name and type
- Server information
- Duration
- Error details (if failed)
- Input parameters (tool name, prompt name, resource URI)

## Server Lineage Preservation

A key feature of the telemetry system is preserving the origin server for all operations. This allows you to:
- Track which MCP servers are most utilized
- Identify performance bottlenecks per server
- Monitor error rates by server
- Understand capability usage patterns

The server information is determined by analyzing the server configuration:
- **Docker containers**: Identified by image name
- **SSE endpoints**: Identified by URL
- **Stdio commands**: Identified by command path
- **Unknown**: Fallback for unrecognized configurations

## Long-Running Gateway Support

The MCP Gateway operates differently from typical Docker CLI commands. While most Docker commands are short-lived (running for seconds or minutes), the `docker mcp gateway run` command creates a long-running process that maintains persistent connections with AI clients. These gateway processes can run for hours, days, or even weeks as long as the client (such as Claude Code) remains connected.

Docker CLI's built-in OTEL exporter is designed for short-lived commands - it collects metrics throughout the command's execution and exports them when the command completes. This approach doesn't work well for the MCP Gateway because metrics would only be visible when the gateway shuts down, potentially days or weeks after interesting events occurred.

To address this difference, the MCP Gateway implements periodic metric export:

1. **Periodic Metric Export**: Metrics are exported every 30 seconds (configurable via `DOCKER_MCP_METRICS_INTERVAL`)
2. **Applies to All Transport Modes**: Whether using stdio, SSE, or streaming transports, all gateway processes are long-lived
3. **Non-blocking Operations**: Telemetry never blocks MCP operations
4. **Memory Efficiency**: Metrics are aggregated efficiently to minimize overhead
5. **Graceful Shutdown**: Final metric export still occurs on gateway termination

## Configuration

### Checking Current Configuration

View your Docker context's OTEL settings:
```bash
docker context inspect | jq '.[].Metadata.otel'
```

Typical output for Docker Desktop:
```json
{
  "OTEL_EXPORTER_OTLP_ENDPOINT": "unix:///Users/username/.docker/run/user-analytics.otlp.grpc.sock"
}
```

### Environment Variables

- **`DOCKER_MCP_TELEMETRY_DEBUG`** - Enable debug logging for telemetry operations
- **`DOCKER_MCP_METRICS_INTERVAL`** - Set metric export interval (default: 30s)
- **`DOCKER_CLI_OTEL_EXPORTER_OTLP_ENDPOINT`** - Override OTEL collector endpoint for testing
- **`OTEL_EXPORTER_OTLP_ENDPOINT`** - OTEL collector endpoint (inherited from Docker CLI)
- **`OTEL_EXPORTER_OTLP_HEADERS`** - Authentication headers for OTEL collector

### Debug Mode

Enable debug logging to see telemetry events:
```bash
export DOCKER_MCP_TELEMETRY_DEBUG=1
docker mcp gateway run --catalog catalog.yaml
```

Debug output appears on stderr and includes:
- Provider initialization status
- Tool call instrumentation events
- Metric recording confirmations

### Integration with Docker Desktop

The telemetry system integrates with Docker Desktop's existing OTEL infrastructure:
1. Uses Docker CLI's global OTEL providers
2. Inherits Docker Desktop's telemetry configuration
3. Exports to the same OTEL collector as other Docker operations
4. Appears alongside other Docker metrics in monitoring systems

### Docker Desktop vs Open Source Docker

The telemetry behavior differs between Docker Desktop and open source Docker installations:

**Docker Desktop**:
- The Docker context includes OTEL configuration with an endpoint (typically a Unix socket at `~/.docker/run/user-analytics.otlp.grpc.sock`)
- The Docker Desktop backend process receives and processes metrics
- Metrics are filtered by instrumentation scope and exported to analytics services
- Users can disable telemetry through Docker Desktop settings

**Open Source Docker** (without Docker Desktop):
- The Docker context lacks OTEL configuration, causing `dockerExporterOTLPEndpoint()` to return an empty endpoint
- Without an endpoint, no metric exporter is created (`dockerMetricExporter()` returns nil)
- The MCP Gateway telemetry code runs but metrics are not exported anywhere
- No external connections are made for telemetry purposes

This design ensures that telemetry only operates within the Docker Desktop environment where users have explicitly agreed to usage analytics. Open source Docker users experience no telemetry collection, maintaining complete privacy by default.

## Use Cases

### Performance Monitoring
- Track response times for different MCP servers
- Identify slow operations by percentile analysis
- Monitor operation volume and patterns

### Debugging
- Trace failed operations through distributed spans
- Identify error patterns by server or operation type
- Correlate gateway operations with server behavior

### Capacity Planning
- Understand which capabilities are most used
- Track growth in operation volume
- Identify servers that need scaling

### Security and Compliance
- Audit tool usage patterns
- Track access to sensitive resources
- Monitor for unusual operation patterns

## Testing Telemetry

### Quick Test

Use the provided test script for complete telemetry validation:
```bash
cd docs/telemetry/testing
./test-telemetry.sh --full
```

### Manual Testing

1. **Start an OTEL Collector**:

For debug output only:
```bash
docker run --rm -d --name otel-debug \
  -p 4317:4317 -p 4318:4318 \
  -v $(pwd)/docs/telemetry/testing/otel-collector-config.yaml:/config.yaml \
  otel/opentelemetry-collector:latest --config=/config.yaml
```

For Prometheus export (port 8889):
```bash
docker run --rm -d --name otel-prometheus \
  -p 4317:4317 -p 4318:4318 -p 8889:8889 \
  -v $(pwd)/docs/telemetry/testing/otel-collector-prometheus.yaml:/config.yaml \
  otel/opentelemetry-collector:latest --config=/config.yaml
```

2. **Run MCP Gateway with Custom Endpoint**:
```bash
export DOCKER_MCP_TELEMETRY_DEBUG=1
export DOCKER_CLI_OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317
docker mcp gateway run --catalog ~/.docker/mcp/catalogs/docker-mcp.yaml \
  --transport sse --port 3000
```

3. **Make Tool Calls**:
Connect an MCP client to `http://localhost:3000/sse` and execute tools.

4. **View Telemetry**:
```bash
docker logs otel-debug | grep "mcp\."
```

### Expected Output

When telemetry is working correctly, you'll see:

**Traces**:
```
Span #0
    Trace ID       : 3482c4807337c24926eca041191e9d74
    Name           : mcp.tool.call
    Kind           : Client
    Status code    : Ok
Attributes:
     -> mcp.tool.name: Str(getPersonalNamespace)
     -> mcp.server.name: Str(dockerhub)
     -> mcp.server.type: Str(docker)
```

**Metrics**:
```
Metric #0
Descriptor:
     -> Name: mcp.tool.calls
     -> Description: Number of tool calls executed
NumberDataPoints #0
     -> mcp.server.name: Str(dockerhub)
     -> mcp.tool.name: Str(getPersonalNamespace)
Value: 2
```

## Troubleshooting

### No Telemetry Visible

1. **Check Provider Types**:
   ```bash
   DOCKER_MCP_TELEMETRY_DEBUG=1 docker mcp gateway run --dry-run
   ```
   Look for: `Tracer provider type: *trace.TracerProvider` (not noop)

2. **Verify Endpoint Configuration**:
   - Check Docker context: `docker context inspect`
   - Check environment: `echo $DOCKER_CLI_OTEL_EXPORTER_OTLP_ENDPOINT`

3. **Ensure Tool Calls Are Made**:
   - Telemetry is event-driven
   - No tool calls = no telemetry
   - Use SSE mode with an MCP client to trigger calls

### Debug Logging Not Appearing

- Ensure `DOCKER_MCP_TELEMETRY_DEBUG=1` is exported
- Check stderr output (debug logs go to stderr, not stdout)
- Verify the plugin was rebuilt after adding telemetry

### Collector Connection Issues

- Verify collector is running: `docker ps | grep otel`
- Check port availability: `lsof -i :4317`
- Test connectivity: `telnet localhost 4317`

## Privacy and Security

The telemetry system is designed with privacy in mind:
- **No PII**: No personally identifiable information is collected
- **No Content**: Operation contents (arguments, results) are not recorded
- **Metadata Only**: Only operation metadata and performance metrics
- **Local Control**: All telemetry can be disabled via Docker Desktop settings

## Performance Impact

The telemetry implementation is optimized for minimal overhead:
- Target: <1% performance impact
- Non-blocking metric recording
- Efficient attribute handling
- Batched metric exports
- No synchronous network calls in operation path

## Development Guidelines

### Adding New Telemetry

When adding telemetry to new operations:

1. **Use Existing Providers**:
   ```go
   tracer := otel.GetTracerProvider().Tracer("github.com/docker/mcp-gateway")
   meter := otel.GetMeterProvider().Meter("github.com/docker/mcp-gateway")
   ```

2. **Preserve Server Lineage**:
   Always include server attribution in spans and metrics:
   ```go
   attrs := []attribute.KeyValue{
       attribute.String("mcp.server.name", serverConfig.Name),
       attribute.String("mcp.server.type", inferServerTransportType(serverConfig)),
       attribute.String("mcp.tool.name", toolName),
   }
   ```

3. **Non-Blocking Operations**:
   Telemetry must never block or fail operations:
   ```go
   if span != nil {
       defer span.End()
   }
   // Continue even if telemetry fails
   ```

4. **Debug Support**:
   Add debug logging behind the environment flag:
   ```go
   if os.Getenv("DOCKER_MCP_TELEMETRY_DEBUG") != "" {
       fmt.Fprintf(os.Stderr, "[MCP-TELEMETRY] Recording tool call: %s\n", toolName)
   }
   ```

### Testing Changes

1. **Build the Plugin**:
   ```bash
   make docker-mcp
   ```

2. **Run the Test Suite**:
   ```bash
   ./docs/telemetry/testing/test-telemetry.sh --full
   ```

3. **Verify with Real Tool Calls**:
   Test in SSE mode with an actual MCP client

4. **Check Both Traces and Metrics**:
   Ensure both appear correctly in the collector output

## Future Enhancements

While the current implementation provides comprehensive coverage, potential future enhancements include:

### MCP Protocol Operations (Planned)
- **Sampling Operations**: Telemetry for when MCP servers request LLM completions from the MCP host via the client
- **Prompting Operations**: Metrics for when MCP servers request user input from the MCP host via the client
- **Roots Operations**: Tracking of filesystem boundaries where servers are allowed to operate

### Infrastructure Metrics
- Session-level metrics and tracking
- Connection pool metrics
- Interceptor execution metrics
- Advanced sampling strategies
- Custom dashboard templates

## Summary

The Docker MCP Gateway telemetry system provides complete visibility into MCP operations, from client requests through server execution. By leveraging OpenTelemetry standards and integrating with Docker Desktop's existing infrastructure, it enables effective monitoring, debugging, and optimization of AI-powered workflows using MCP servers.

The system balances comprehensive coverage with performance efficiency, ensuring that telemetry enhances rather than hinders the gateway's operation. With built-in support for long-running processes and careful preservation of server lineage, it provides the insights needed to operate MCP infrastructure effectively at scale.

## References

- [OpenTelemetry Documentation](https://opentelemetry.io/docs/) - Core OTEL concepts and SDKs
- [Docker CLI Telemetry](https://github.com/docker/cli/tree/master/cli/command) - Docker's telemetry implementation
- [MCP Protocol Specification](https://modelcontextprotocol.io/) - Model Context Protocol details
- [MCP Gateway Repository](https://github.com/docker/mcp-gateway) - Source code and issues

---

### Catalog (`docs/catalog.md`)

# MCP Catalog Management

*Important note: This method of catalog management is deprecated and only works if the profiles feature flag is off. Please see [Profiles](profiles.md) for more information on how to use catalogs.*

Docker MCP Gateway provides comprehensive catalog management capabilities, allowing you to create, manage, and use custom MCP server catalogs alongside Docker's official catalog.

## Quick Start with Bootstrap

The easiest way to get started with custom catalogs is to use the `bootstrap` command, which creates a starter catalog file with Docker's official server entries as examples:

```bash
# Create a starter catalog with Docker Hub and Docker CLI server examples
docker mcp catalog bootstrap ./my-starter-catalog.yaml

# The file now contains properly formatted server definitions you can modify
```

This creates a YAML file with real server definitions that you can:
- Modify to understand the catalog format
- Use as a foundation for your custom servers
- Import directly into your catalog collection
- Use as a source for copying individual servers to other catalogs

## Catalog Management Commands

### Listing Catalogs

```bash
# List all configured catalogs
docker mcp catalog ls

# List in JSON format
docker mcp catalog ls --format=json
```

### Creating Catalogs

```bash
# Create a new empty catalog
docker mcp catalog create my-custom-catalog

# The catalog is now ready for adding servers
```

### Viewing Catalog Contents

```bash
# Show servers in the default Docker catalog
docker mcp catalog show

# Show servers in a specific catalog
docker mcp catalog show my-custom-catalog

# Show in different formats
docker mcp catalog show docker-mcp --format json
docker mcp catalog show docker-mcp --format yaml
```

### Adding Servers to Catalogs

```bash
# Add a server from another catalog file
docker mcp catalog add my-custom-catalog server-name ./source-catalog.yaml

# Force overwrite if server already exists
docker mcp catalog add my-custom-catalog server-name ./source-catalog.yaml --force
```

### Importing Servers from OSS MCP Community Registry

```bash
# replace {id} in the url below
docker mcp catalog import my-custom-catalog --mcp-registry https://registry.modelcontextprotocol.io/v0/servers/{id}
```

### Importing Other Catalogs

```bash
# Import a catalog from a local file
docker mcp catalog import ./my-catalog.yaml

# Import from a URL
docker mcp catalog import https://example.com/catalog.yaml

# Import with an alias
docker mcp catalog import team-servers
```

### Exporting Catalogs

```bash
# Export a custom catalog to a file
docker mcp catalog export my-custom-catalog ./backup.yaml

# Note: You cannot export Docker's official catalog
docker mcp catalog export docker-mcp ./docker-backup.yaml
# Error: Cannot export the Docker MCP catalog as it is managed by Docker
```

### Forking Catalogs

```bash
# Create a copy of an existing catalog
docker mcp catalog fork docker-mcp my-custom-version

# Now you can modify my-custom-version independently
```

### Removing Catalogs

```bash
# Remove a custom catalog
docker mcp catalog rm my-custom-catalog

# Note: You cannot remove Docker's official catalog
```

### Updating Catalogs

```bash
# Update all catalogs
docker mcp catalog update

# Update a specific catalog
docker mcp catalog update my-custom-catalog
```

### Resetting Catalogs

```bash
# Remove all custom catalogs and reset to Docker defaults
docker mcp catalog reset
```

## Catalog YAML Format

Catalogs use a specific YAML format with server definitions. Here's the structure:

### Basic Structure

```yaml
name: my-catalog
displayName: My Custom Catalog
registry:
  server-name:
    description: "Description of what this server does"
    title: "Server Display Name"
    type: "server"  # or "poci" for container tools
    image: "namespace/image:tag"
    # Additional server configuration...
```

### Complete Server Example

```
/* Detailed source-code truncated for AI context efficiency. */
```

### POCI (Container) Tool Example

```yaml
registry:
  my-container-tool:
    description: "A containerized tool for file processing"
    title: "File Processor"
    type: "poci"
    tools:
      - name: "process_files"
        description: "Process files in a directory"
        parameters:
          type: "object"
          properties:
            input_path:
              type: "string"
              description: "Path to input files"
            output_path:
              type: "string"
              description: "Path for output files"
          required: ["input_path", "output_path"]
        container:
          image: "myorg/file-processor:latest"
          command:
            - "process"
            - "{{input_path}}"
            - "{{output_path}}"
          volumes:
            - "{{input_path}}:{{input_path}}"
            - "{{output_path}}:{{output_path}}"
```

## Common Workflows

### Development Workflow

```bash
# 1. Create a starter catalog for reference
docker mcp catalog bootstrap ./starter-catalog.yaml

# 2. Create your own catalog
docker mcp catalog create dev-servers

# 3. Add useful servers from the starter (optional)
docker mcp catalog add dev-servers dockerhub ./starter-catalog.yaml

# 4. Create a custom server definition file
cat > my-server.yaml << EOF
registry:
  my-dev-server:
    description: "My development server"
    title: "Dev Server"
    type: "server"
    image: "myorg/dev-server:latest"
    tools:
      - name: "dev_tool"
EOF

# 5. Add your custom server
docker mcp catalog add dev-servers my-dev-server ./my-server.yaml
```

### Importing from the OSS MCP Community Registry

```bash
# 1. Create a destination catalog for your community servers
docker mcp catalog create community-catalog

# 2. import the OSS MCP community server resource
docker mcp catalog import --mcp-registry http://registry.modelcontextprotocol.io/v0/servers/71de5a2a-6cfb-4250-a196-f93080ecc860

# 3. show the imported server
docker mcp catalog show community-catalog --format=json | jq .
```

### Team Sharing Workflow

```bash
# Team lead: Create and export a team catalog
docker mcp catalog create team-servers
docker mcp catalog add team-servers shared-db ./shared-db-server.yaml
docker mcp catalog add team-servers api-helper ./api-helper-server.yaml
docker mcp catalog export team-servers ./team-catalog.yaml

# Share team-catalog.yaml with team members

# Team members: Import the shared catalog
docker mcp catalog import ./team-catalog.yaml
docker mcp gateway run
```

### Testing New Servers

```bash
# 1. Create a test catalog
docker mcp catalog create test-servers

# 2. Add your server for testing
docker mcp catalog add test-servers test-server ./test-server.yaml

# 3. Run gateway with test catalog
docker mcp gateway run

# 4. When done testing, clean up
docker mcp catalog rm test-servers
```

### Production Deployment

```bash
# 1. Create production catalog
docker mcp catalog create prod-servers

# 2. Add only production-ready servers
docker mcp catalog add prod-servers monitoring ./monitoring-server.yaml
docker mcp catalog add prod-servers logging ./logging-server.yaml

# 3. Export for backup and deployment
docker mcp catalog export prod-servers ./prod-catalog-backup.yaml

# 4. Deploy with production catalog
docker mcp gateway run
```

## Catalog Precedence

Catalogs are loaded in this order:

1. **Docker Official Catalog** (always loaded first)
2. **Configured Catalogs** (user-imported catalogs)
3. **CLI-specified Catalogs** (via `--catalog` flag)

If multiple catalogs define the same server name, the **last-loaded catalog wins**. This means CLI-specified catalogs take highest precedence, followed by configured catalogs, with Docker's catalog as the base.

## Registry Submission

For servers you want to share with the broader community, consider submitting them to Docker's official registry:

**Official Docker MCP Registry**: https://github.com/docker/mcp-registry

This process makes your servers available to all Docker MCP users through the official catalog.

## Troubleshooting

### File Already Exists
```bash
Error: file "catalog.yaml" already exists - will not overwrite
```
**Solution**: Choose a different filename or move/remove the existing file

### Server Not Found
```bash
Error: server "server-name" not found in catalog "source.yaml"
```
**Solution**: Check the server name spelling and verify it exists in the source catalog

### Cannot Export Docker Catalog
```bash
Error: cannot export the Docker MCP catalog as it is managed by Docker
```
**Solution**: This is intentional - Docker's catalog cannot be exported. Use `bootstrap` to get Docker server examples instead.

### Container Mode Issues
If running in container mode, ensure proper volume mounts for accessing catalog files and Docker configuration.

---

### Config Flow (`docs/config-flow.md`)

# Gateway startup

```mermaid
sequenceDiagram
    participant Gateway
    participant Config
    participant Configurator
    participant Server
    participant Listener

    Gateway->>Listener: Start listening immediately if not-stdio
    Gateway->>Configurator: Read
    Configurator-->>Config: hello
    Config-->>Gateway: configured
    Configurator->>Watcher: channel
    Watcher-->>Gateway: watch channel config changes
    Gateway->>Gateway: pullAndVerify(config)
    Gateway->>Gateway: reloadConfiguration(config)
    Gateway->>Server: start
    Gateway->>Listener: healthy
```

## Reading Config

The `Read` method in `Configurator` is responsible for building an initial `Configuration`

* serverNames
* catalog.Servers (this is our catalog)
    * read from catalog.yaml files
    * read from oci artifacts
* config map
* tool filters
* secret providers
    * DD
    * file

## reloadConfiguration

The gateway `reloadConfiguration` extracts capabilities from the current configuration, and updates the Server. It starts up the server to do this.

When running servers raise change notifications, the capabilities also have to be reloaded.

# Dynamic Server Add

Another place where the capabilities should be considered _dynamic_ is with the `mcp-server-add` tool. This tool loads new mcp servers into a gateway session.

```mermaid
sequenceDiagram
    AddTool->>Config: find
    AddTool->>Config: append server
    AddTool->>Config: update secrets
    AddTool->>Gateway: reloadConfiguration
    Gateway-->>Config: is used
```

During `reloadConfiguration` all updates to capabilities will cause change events to be sent to any clients connected to this server.

# Images without Catalogs

A Docker Image can contain its own catalog description via the
`io.docker.server.metadata` label. When such an image is referenced
through a profile or working set (see [profiles](profiles.md)), the
label is parsed through the narrow `ImportedServer` schema so that only
descriptive metadata is trusted. Runtime-shaping fields and secrets are
sourced exclusively from curated catalogs or user configuration.

---

### Mcp Gateway (`docs/mcp-gateway.md`)

# Docker MCP Gateway

Running MCP Servers in Docker Containers is robust and secure. 

See [Why running MCP Servers in Container is more secure](security.md)

## How to run the MCP Gateway?

Start up an MCP Gateway. This can be used for one client, or to service multiple clients if using either `sse` or `streaming` transports.

```bash
# Run the MCP gateway (stdio)
docker mcp gateway run

# Run the MCP gateway (streaming)
docker mcp gateway run --port 8080 --transport streaming

# Run with specific servers only, and select all tools from server1 and just tool2 from server2
docker mcp gateway run --servers server1,server2 --tools server1:* --tools server2:tool2

# Run a fallback secret lookup - lookup desktop secret first and the fallback to a local .env file
docker mcp gateway run --secrets=docker-desktop:./.env

# Run with verbose logging
docker mcp gateway run --verbose --log-calls

# Run in watch mode (auto-reload on config changes)
docker mcp gateway run --watch

# Run a standalone dockerized MCP server (no catalog required)
docker mcp gateway run --server docker.io/namespace/repository:latest

# Run with a profile (requires profiles feature to be enabled)
docker mcp gateway run --profile my-working-set
```

See [Profiles](profiles.md) for more information about organizing servers into reusable collections.

## How to connect to an MCP Client?

A typical usage looks like this Claude Desktop configuration:

```
{
    "mcpServers": {
        "MCP_DOCKER": {
            "command": "docker",
            "args": ["mcp", "gateway", "run"]
        }
    }
}
```

## How to run the MCP Gateway with Docker Compose?

The simplest way to tun the MCP Gateway with Docker Compose is with this kind of compose file:

```
services:
  gateway:
    image: docker/mcp-gateway
    command:
      - --servers=duckduckgo
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
```

### What does it do?

+ Starts an MCP Gateway for other services to use. Think AI Agents.
+ Work independently from Docker Desktop's MCP Toolkit. It can run anywhere there's a Docker engine.
+ Defines the list of enabled servers from the gateway's command line, with `--servers`
+ Uses the online Docker MCP Catalog (v2: https://desktop.docker.com/mcp/catalog/v2/catalog.yaml by default, v3: https://desktop.docker.com/mcp/catalog/v3/catalog.yaml when `mcp-oauth-dcr` feature is enabled).

### How to run

```console
docker compose up
```

## More examples

See [Examples](examples/README.md)

## Complete set of command line flags

See the generated reference: [`docker mcp gateway run`](generator/reference/mcp_gateway_run.md).

It is regenerated from the command definitions by `make docs` and checked in CI, so unlike
a pasted `--help` dump it cannot drift.

## Troubleshooting

Look at our [Troubleshooting Guide](/docs/troubleshooting.md)

---

### Message Flow (`docs/message-flow.md`)

## Message Flow
Src: [official docs page](https://spec.modelcontextprotocol.io/specification/2025-03-26/server/tools/#message-flow)
```mermaid
sequenceDiagram
    participant LLM
    participant Client
    participant Server

    Note over Client,Server: Discovery
    Client->>Server: tools/list
    Server-->>Client: List of tools

    Note over Client,LLM: Tool Selection
    LLM->>Client: Select tool to use

    Note over Client,Server: Invocation
    Client->>Server: tools/call
    Server-->>Client: Tool result
    Client->>LLM: Process result

    Note over Client,Server: Updates
    Server--)Client: tools/list_changed
    Client->>Server: tools/list
    Server-->>Client: Updated tools
```

Docker Model

```mermaid
sequenceDiagram
    participant LLM
    participant Client
    participant Server as Server (Gateway)<br/>mcp/docker
    participant ToolServer as Tool Server 1<br/>(tools runtime, potentially ephemeral)

    Note over Client,Server: Discovery
    Client->>Server: tools/list
    Server-->>ToolServer: tools/list
    ToolServer-->>Server: List of tools
    Server-->>Client: Combined list of tools

    Note over Client,LLM: Tool Selection
    LLM->>Client: Select tool to use

    Note over Client,Server: Invocation
    Client->>Server: tools/call
    Server->>ToolServer: tools/call
    ToolServer-->>Server: Tool result
    Server-->>Client: Tool result
    Client->>LLM: Process result

%%    Note over Client,Server: Updates
%%    Server--)Client: tools/list_changed
%%    Client->>Server: tools/list
%%    Server-->>Client: Updated tools
```

---

### Oauth Ce Mode (`docs/oauth-ce-mode.md`)

# OAuth DCR with Docker CE

Complete guide for using MCP Gateway OAuth with Docker Engine (CE Mode).

## Prerequisites

### 1. Credential Helper Installed

MCP Gateway requires [Docker credential helper](https://github.com/docker/docker-credential-helpers) configured to securely store OAuth tokens.


Download from releases:
https://github.com/docker/docker-credential-helpers/releases

### 2. Configure Docker to Use Credential Helper

Edit or create `~/.docker/config.json`:

**macOS:**
```json
{
  "credsStore": "osxkeychain"
}
```

**Linux (Desktop):**
```json
{
  "credsStore": "secretservice"
}
```

**Linux (Headless):**
```json
{
  "credsStore": "pass"
}
```

**Windows:**
```json
{
  "credsStore": "wincred"
}
```

**Verify configuration:**
```bash
# Helper should be in your PATH
which docker-credential-osxkeychain  # macOS
which docker-credential-secretservice  # Linux Desktop
which docker-credential-pass  # Linux Headless
where docker-credential-wincred.exe  # Windows
```

For detailed installation instructions, see:
https://github.com/docker/docker-credential-helpers

## Configuration

### Enable CE Mode

Set the environment variable to enable standalone OAuth:

```bash
export DOCKER_MCP_USE_CE=true
```
### Optional: Customize OAuth Callback Port

By default, MCP Gateway listens on `localhost:5000` for OAuth callbacks.

If port 5000 is already in use, set a custom port:

```bash
export MCP_GATEWAY_OAUTH_PORT=5001
```

Valid range: 1024-65535

**Error handling:**
- If port is in use, you'll see a clear error message with solutions
- Invalid port values (< 1024 or > 65535) fall back to default with warning

## Usage

### Step-by-Step: Authorizing an OAuth Server

This example uses Notion, but works with any OAuth-enabled MCP server.

#### Step 1: Enable the Server

```bash
docker mcp server enable notion-remote
```

#### Step 2: Authorize

```bash
docker mcp oauth authorize notion-remote
```

---

### Oauth Flows (`docs/oauth-flows.md`)

# OAuth Flows Comparison

### 2.2 Basic OAuth 2.1 Authorization

When authorization is required and not yet proven by the client, servers **MUST** respond
with _HTTP 401 Unauthorized_.

Clients initiate the
[OAuth 2.1 IETF DRAFT](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-12)
authorization flow after receiving the _HTTP 401 Unauthorized_.

The following demonstrates the basic OAuth 2.1 for public clients using PKCE.

```mermaid
sequenceDiagram
    participant B as User-Agent (Browser)
    participant C as Client
    participant M as MCP Server

    C->>M: MCP Request
    M->>C: HTTP 401 Unauthorized
    Note over C: Generate code_verifier and code_challenge
    C->>B: Open browser with authorization URL + code_challenge
    B->>M: GET /authorize
    Note over M: User logs in and authorizes
    M->>B: Redirect to callback URL with auth code
    B->>C: Callback with authorization code
    C->>M: Token Request with code + code_verifier
    M->>C: Access Token (+ Refresh Token)
    C->>M: MCP Request with Access Token
    Note over C,M: Begin standard MCP message exchange
```

## Official MCP OAuth diagram mapped

```mermaid
sequenceDiagram
    participant A as Authorisation Server
    participant B as User-Agent (Browser)
    participant C as Client
    participant M as MCP Server
    participant R as Resource

    C->>M: MCP Request
    M->>R: Resource Request
    R-->>M: HTTP 401 Unauthorized
    M->>C: HTTP 401 Unauthorized
    Note over C: Generate code_verifier and code_challenge
    C->>B: Open browser with authorization URL + code_challenge
    B->>M: GET /authorize
    Note over M: User logs in and authorizes
    M->>B: Redirect to callback URL with auth code
    B->>C: Callback with authorization code
    C->>M: Token Request with code + code_verifier
    M->>C: Access Token (+ Refresh Token)
    C->>M: MCP Request with Access Token
    Note over C,M: Begin standard MCP message exchange
```

### Questions


## Docker MCP OAuth Model
Key points:
- We implement the OAuth flows, nobody else has to.
- Via a developer portal, 3rd parties can add OAuth clients (config with client_id, client_secret, redirect_uri).
- We provide a secure and easy way to store and access secrets.

### Pre-authorization (`docker mcp auth notion my-server`)
```mermaid
sequenceDiagram
    participant A as Authorisation Server
    participant B as User-Agent (Browser)
    participant C as CLI
    participant P as DD Auth API<br>(handles all OAuth flows)
    participant SM as secret management API<br>(handles secret storage+access)
    participant M as MCP Server
    participant R as Resource

    C->>P: docker mcp auth notion my-server
    Note over A,P: Auth Phase (outcome: access/refresh token)<br>(can be local/local+partially hub/fully hub)
    P->>B: Open browser with authorization URL + code_challenge
    B->>A: login
    A->>B: consent
    B->>P: custom protocol callback with authorization code
    P->>A: Token Request with code + code_verifier
    A->>P: Access Token (+ Refresh Token)
    Note over P,SM: Secret Management Preparation/Setup Phase
    P->>SM: create policy 'notion'
    P->>SM: add 'my-server' to policy 'notion'
    P->>SM: set secret 'notion-access-token' with policy 'notion'
    Note over SM,R: Do MCP activity (eg requests to resources that require auth)
    M->>M: mount secret<br>x-secret:notion=/access-token/file.txt
    M->>SM: read access token from file
    SM->>M: grant access to token
    M->>R: Resource Request
    R-->>M: Data
```


### Handling 401 Unauthorized
Note: Option 2 is the most elegant and safest solution. Neither the MCP server nor the MCP client need to know about all the details of the OAuth flow.
```mermaid
sequenceDiagram
    participant C as MCP Client
    participant G as Gateway<br/>mcp/docker
    participant P as DD Auth API<br>(handles all OAuth flows)
    participant SM as secret management API<br>(handles secret storage+access)
    participant M as MCP Server
    participant R as Resource

    C->>G: MCP Request
    G->>M: MCP Request
    M->>SM: read access token from file
    SM->>M: grant access to token
    M->>R: Resource Request
    R-->>M: HTTP 401 Unauthorized
    Note over P,M: Option 1: MCP servers can trigger refresh
    M->>P: refresh
    Note over G,M: Option 2: The gateway can trigger refresh
    M->>G: HTTP 401 Unauthorized
    G->>P: refresh
    Note over C,M: Option 3: The client can trigger refresh
    G->>C: HTTP 401 Unauthorized
    C->>P: refresh
    Note over P,SM: Do refresh + propagate new access token
    P->>P: refresh<br>(if refresh token is expired, then re-authenticate)
    P->>SM: set secret 'notion-access-token'
    Note over SM,R: Do MCP activity (eg requests to resources that require auth)
    M->>SM: read access token from file
    SM->>M: grant access to token
    M->>R: Resource Request
    R-->>M: Data
```

### Notes and observations
Docker has some advantages:
- We are already running in the background all the time.
- This allows us to handle secret storage and management seamlessly in the background on the user's machine instead of on our infrastructure.
- We don't need to be an OAuth server to register dynamic clients. 
  The client can use the credentials stored by DD, since we are in a trusted environment (on the user's machine).
  We just need to be a good proxy.
- Usually clients have the problem of not being trusted.
  We also have an advantage here as we can use the Docker Desktop login to provide a secure environment for clients.


#### 2.9.2 Flow Description

[src](https://spec.modelcontextprotocol.io/specification/2025-03-26/basic/authorization/#292-flow-description)

The third-party authorization flow comprises these steps:

1. MCP client initiates standard OAuth flow with MCP server
2. MCP server redirects user to third-party authorization server
3. User authorizes with third-party server
4. Third-party server redirects back to MCP server with authorization code
5. MCP server exchanges code for third-party access token
6. MCP server generates its own access token bound to the third-party session
7. MCP server completes original OAuth flow with MCP client

```mermaid
sequenceDiagram
    participant B as User-Agent (Browser)
    participant C as MCP Client
    participant M as MCP Server
    participant T as Third-Party Auth Server

    C->>M: Initial OAuth Request
    M->>B: Redirect to Third-Party /authorize
    B->>T: Authorization Request
    Note over T: User authorizes
    T->>B: Redirect to MCP Server callback
    B->>M: Authorization code
    M->>T: Exchange code for token
    T->>M: Third-party access token
    Note over M: Generate bound MCP token
    M->>B: Redirect to MCP Client callback
    B->>C: MCP authorization code
    C->>M: Exchange code for token
    M->>C: MCP access token
```

Questions:
- Alano: The diagram implies that the MCP server runs remotely. Is that correct? Because why otherwise would you need the MCP client to be authorized?

#### All details included
```mermaid
sequenceDiagram
    participant B as User-Agent (Browser)
    participant C as MCP Client
    participant M as MCP Server
    participant T as Third-Party Auth Server<br>Google, Notion, etc.

    C->>M: Initial OAuth Request
    M->>C: Auth browser URL
    C->>B: Open browser URL (Redirect to Third-Party /authorize)
    B->>T: request authorization
    T->>B: request user consent
    B->>T: user approval (consent/accept)
    T->>B: auth code in redirect URL
    B->>M: Redirect to MCP Server callback (authorization code)
    M->>T: Exchange code for token
    T->>M: access + refresh token
    M->>M: Store access + refresh token
    Note over M: Generate bound MCP token<br>MCP server becomes an auth server towards MCP client
    M->>B: Proxy auth code (redirect)
    M->>M: Store link between proxy auth code and access+refresh token
    B->>C: Proxy auth code (redirect)
    C->>M: Exchange proxy code for token
    M->>M: Link proxy access+refresh token to earlier 3rd party session
    M->>C: Proxy access+refresh token
```

---

### Profiles (`docs/profiles.md`)

# Profiles

Profiles allow you to organize and manage collections of MCP servers as a single unit. Unlike catalogs that serve as repositories of available servers, profiles represent specific configurations of servers you want to use together for different purposes or contexts.

## What are Profiles?

A profile is a named collection of MCP servers that can be:
- Created and managed independently of catalogs
- Shared across teams via export/import or OCI registries
- Used to quickly switch between different server configurations

Profiles are decoupled from catalogs, meaning the servers in a profile can come from:
- **MCP Registry references**: HTTP(S) URLs pointing to servers in the Model Context Protocol registry
- **OCI image references**: Docker images with the `docker://` prefix
- **Catalog references**: Servers from existing catalogs with the `catalog://` prefix
- **Local file references**: Server definitions from local YAML or JSON files with the `file://` prefix (see [Server Entry Specification](./server-entry-spec.md) for file format details)

⚠️ **Important Caveat:** MCP Registry references are not fully implemented and are not expected to work yet.

## Enabling Profiles

Profiles are a feature that must be enabled first.

In Docker CE or container mode:

```bash
# Enable the profiles feature
docker mcp feature enable profiles

# Verify it's enabled
docker mcp feature list
```

If you're using Docker Desktop, you have to enable the `MCPWorkingSets` feature flag within Docker Desktop instead.

Once enabled, you'll have access to:
- `docker mcp profile` commands for managing profiles
- `--profile` flag for `docker mcp gateway run`
- `-p` or `--profile` flag for `docker mcp client connect`

## Profile Commands

### Creating Profiles

Create a new profile with a name and list of servers:

```bash
# Create a profile with OCI image references
docker mcp profile create --name dev-tools \
  --server docker://my-server:latest \
  --server docker://my-other-server:latest

# Create with servers from a catalog
docker mcp profile create --name catalog-servers \
  --server catalog://mcp/docker-mcp-catalog/github+slack

# Create with MCP Registry references
docker mcp profile create --name registry-servers \
  --server https://registry.modelcontextprotocol.io/v0/servers/71de5a2a-6cfb-4250-a196-f93080ecc860

# Mix different methods of specifying servers
docker mcp profile create --name mixed \
  --server catalog://mcp/docker-mcp-catalog/dockerhub \
  --server https://registry.modelcontextprotocol.io/v0/servers/71de5a2a-6cfb-4250-a196-f93080ecc860 \
  --server docker://my-server:latest
  --server file://./my-server.yaml

# Create with servers from local files
docker mcp profile create --name local-servers \
  --server file://./my-server.yaml \
  --server file://./another-server.json

# Specify a custom ID (otherwise derived from name)
docker mcp profile create --name "My Servers" --id my-servers \
  --server docker://my-server:latest
```

**Notes:**
- `--name` is required and serves as the human-readable name
- `--id` is optional; if not provided, it's generated from the name (lowercase, alphanumeric with underscores)
- `--server` can be specified multiple times to add multiple servers
- Server references must be either:
  - `docker://` prefix for OCI images
  - `http://` or `https://` URLs for MCP Registry references
  - `catalog://` prefix for catalog references
  - `file://` prefix for local YAML or JSON server definition files

### Adding Servers to a Profile

After creating a profile, you can add more servers to it:

```bash
# Add servers with OCI references
docker mcp profile server add dev-tools \
  --server docker://my-server:latest \
  --server docker://my-other-server:latest

# Add servers from a catalog
docker mcp profile server add dev-tools \
  --server catalog://mcp/docker-mcp-catalog/github+slack

# Add servers with MCP Registry references
docker mcp profile server add dev-tools \
  --server https://registry.modelcontextprotocol.io/v0/servers/71de5a2a-6cfb-4250-a196-f93080ecc860

# Mix MCP Registry references and OCI references
docker mcp profile server add dev-tools \
  --server https://registry.modelcontextprotocol.io/v0/servers/71de5a2a-6cfb-4250-a196-f93080ecc860 \
  --server docker://my-server:latest

# Add servers from local files
docker mcp profile server add dev-tools \
  --server file://./my-server.yaml \
  --server file://./another-server.json

# Mix catalog servers with direct server references
docker mcp profile server add dev-tools \
  --server catalog://mcp/docker-mcp-catalog/github \
  --server docker://my-server:latest
```

**Local File Format:**

When using `file://`, the file should contain a server definition in YAML or JSON format:

```yaml
# my-server.yaml
name: my-custom-server
title: My Custom Server
type: server
image: my-org/my-server:latest
description: A custom MCP server
allowHosts:
  - api.example.com:443
```

See the [Server Entry Specification](./server-entry-spec.md) for complete file format documentation including configuration schemas, secrets, OAuth, and advanced options.

**Server References:**
- Use `--server` flag for all server references (can be specified multiple times)
- Server references must start with:
  - `catalog://` for catalog references. This takes the form of `catalog://<catalog-oci-refence>/<server-1>+<server-2>`
  - `docker://` for OCI images
  - `http://` or `https://` for MCP Registry URLs
  - `file://` for local YAML or JSON server definition files (see [Server Entry Specification](./server-entry-spec.md))
- Catalog servers are referenced by their name within the catalog

**Notes:**
- You can add multiple servers in a single command
- You can mix direct server references with catalog-based references
- If a server already exists in the profile, the operation will skip it or update it

### Removing Servers from a Profile

Remove servers from a profile by their server name:

```bash
# Remove servers by name
docker mcp profile server remove dev-tools \
  --name github \
  --name slack

# Remove a single server
docker mcp profile server remove dev-tools --name github

# Using alias
docker mcp profile server rm dev-tools --name github
```

**Server Names:**
- Use `--name` flag to specify server names to remove (can be specified multiple times)
- Server names are determined by the server's snapshot (not the image name or source URL)
- Use `docker mcp profile show <profile-id>` to see available server names in a profile

### Listing Servers Across Profiles

View all servers grouped by profile, with filtering capabilities:

```bash
# List all servers across all profiles
docker mcp profile servers

# Filter servers by name (case-insensitive substring matching)
docker mcp profile servers --filter github

# Show servers from a specific profile only
docker mcp profile servers --profile dev-tools

# Combine filter and profile
docker mcp profile servers --profile dev-tools --filter slack

# Output in JSON format
docker mcp profile servers --format json

# Output in YAML format
docker mcp profile servers --format yaml
```

**Output options:**
- `--filter`: Search for servers matching a query (case-insensitive substring matching on image names or source URLs)
- `--profile` or `-p`: Show servers only from a specific profile
- `--format`: Output format - `human` (default), `json`, or `yaml`

**Notes:**
- This command provides a global view of all servers across your profiles
- Useful for finding which profiles contain specific servers
- The filter applies to both image names and source URLs

### Listing Profiles

View all profiles in your system:

```bash
# List all profiles (human-readable format)
docker mcp profile list

# List with aliases
docker mcp profile ls

# List in JSON format
docker mcp profile list --format json

# List in YAML format
docker mcp profile list --format yaml
```

**Output formats:**
- `human` (default): Tabular format with ID and Name columns
- `json`: Complete JSON representation
- `yaml`: Complete YAML representation

### Showing Profile Details

Display detailed information about a specific profile:

```bash
# Show a profile (human-readable)
docker mcp profile show my-profile

# Show in JSON format
docker mcp profile show my-profile --format json

# Show in YAML format
docker mcp profile show my-profile --format yaml
```

The output includes:
- Profile ID and name
- List of servers with their types and references
- Configuration for each server
- Secrets configuration
- Tools associated with each server

### Removing Profiles

Delete a profile from your system:

```bash
# Remove a profile
docker mcp profile remove my-profile

# Using alias
docker mcp profile rm my-profile
```

**Note:** This only removes the profile definition, not the actual server images or registry entries.

### Configuring Profile Servers

Manage configuration values for servers within a profile:

```bash
# Set a single configuration value
docker mcp profile config my-profile --set github.timeout=30

# Set multiple configuration values
docker mcp profile config my-profile \
  --set github.timeout=30 \
  --set github.maxRetries=3 \
  --set slack.channel=general

# Get a specific configuration value
docker mcp profile config my-profile --get github.timeout

# Get multiple configuration values
docker mcp profile config my-profile \
  --get github.timeout \
  --get github.maxRetries

# Get all configuration values
docker mcp profile config my-profile --get-all

# Delete configuration values
docker mcp profile config my-profile --del github.maxRetries

# Combine operations (set new values and get existing ones)
docker mcp profile config my-profile \
  --set github.timeout=60 \
  --get github.maxRetries

# Output in JSON format
docker mcp profile config my-profile --get-all --format json

# Output in YAML format
docker mcp profile config my-profile --get-all --format yaml
```

**Configuration format:**
- `--set`: Format is `<server-name>.<config-key>=<value>` (can be specified multiple times)
- `--get`: Format is `<server-name>.<config-key>` (can be specified multiple times)
- `--del`: Format is `<server-name>.<config-key>` (can be specified multiple times)
- `--get-all`: Retrieves all configuration values from all servers in the profile
- `--format`: Output format - `human` (default), `json`, or `yaml`

**Typed values via JSON:**

- Values passed to `--set` are parsed as JSON when possible. This allows arrays, numbers, booleans and objects.
- If the value is not valid JSON, it is stored as a plain string.
- Examples:

```bash
# Numbers and booleans
docker mcp profile config my-profile --set github.timeout=60 --set github.debug=true

# Strings (either raw or JSON-quoted both work)
docker mcp profile config my-profile --set slack.channel=general
docker mcp profile config my-profile --set slack.channel='"general"'

# Arrays
docker mcp profile config my-profile --set filesystem.paths='["/Users/dk/dev","/Users/dk/projects"]'

# Objects
docker mcp profile config my-profile --set build.options='{"retries":3,"cache":false}'
```

**Important notes:**
- The server name must match the name from the server's snapshot (not the image or source URL)
- Use `docker mcp profile show <profile-id> --format yaml` to see available server names
- Configuration changes are persisted immediately to the profile
- You cannot both `--set` and `--del` the same key in a single command
- **Note**: Config is for non-sensitive settings. Use secrets management for API keys, tokens, and passwords.

### Managing Tools for Profile Servers

Control which tools are enabled or disabled for servers in a profile:

```bash
# Enable specific tools for a server
docker mcp profile tools my-profile \
  --enable github.create_issue \
  --enable github.list_repos

# Disable specific tools for a server
docker mcp profile tools my-profile \
  --disable github.create_issue \
  --disable github.search_code

# Enable and disable in one command
docker mcp profile tools my-profile \
  --enable github.create_issue \
  --disable github.search_code

# Enable all tools for a server
docker mcp profile tools my-profile --enable-all github

# Disable all tools for a server
docker mcp profile tools my-profile --disable-all github

# View all enabled tools in the profile
docker mcp profile show my-profile
```

**Tool management format:**
- `--enable`: Format is `<server-name>.<tool-name>` (can be specified multiple times)
- `--disable`: Format is `<server-name>.<tool-name>` (can be specified multiple times)
- `--enable-all`: Format is `<server-name>` to enable all tools for a server (can be specified multiple times)
- `--disable-all`: Format is `<server-name>` to disable all tools for a server (can be specified multiple times)

**Important notes:**
- Tool names use dot notation: `<serverName>.<toolName>`
- The server name must match the name from the server's snapshot
- Use `docker mcp profile show <profile-id>` to see which tools are currently enabled
- By default, all tools are enabled unless explicitly disabled
- Changes take effect immediately and persist in the profile

### Managing Secrets for Profile Servers

Secrets provide secure storage for sensitive values like API keys, tokens, and passwords. Unlike configuration values, secrets are stored securely and never displayed in plain text.

```bash
# Set a secret for a server in a profile
docker mcp secret set github.pat=ghp_xxxxx
```

**Secret format:**
- Format is `<server-name>.<secret-key>=<value>`
- The server name must match the name from the server's snapshot
- Secrets are stored in Docker Desktop's secure secret store

**Current Limitation**: Secrets are scoped across all servers rather than for each profile. We plan to address this.

### Exporting Profiles

Export a profile to a file for backup or sharing:

```bash
# Export to YAML
docker mcp profile export my-profile ./my-profile.yaml

# Export to JSON
docker mcp profile export my-profile ./my-profile.json
```

The file format is automatically detected from the extension (`.yaml` or `.json`).

### Importing Profiles

Import a profile from a file:

```bash
# Import from YAML
docker mcp profile import ./my-profile.yaml

# Import from JSON
docker mcp profile import ./my-profile.json
```

**Behavior:**
- If a profile with the same ID doesn't exist, it will be created
- If a profile with the same ID exists, it will be updated
- The file format is automatically detected from the extension

### Pushing Profiles to OCI Registry

Share profiles via OCI registries:

```bash
# Push to a registry
docker mcp profile push my-profile docker.io/myorg/my-profile:latest

# Push to a private registry
docker mcp profile push my-profile registry.example.com/team/profile:v1.0
```

This allows you to:
- Version control your profiles
- Share with team members
- Deploy consistent configurations across environments

### Pulling Profiles from OCI Registry

Retrieve profiles from OCI registries:

```bash
# Pull from a registry
docker mcp profile pull docker.io/myorg/my-profile:latest

# Pull from a private registry
docker mcp profile pull registry.example.com/team/profile:v1.0
```

The profile will be imported into your local system and ready to use.

## Using Profiles with the Gateway

Once you have profiles configured, you can use them to run the MCP gateway:

```bash
# Run gateway with a specific profile
docker mcp gateway run --profile my-profile

# The gateway will start with only the servers defined in that profile
```

**Important restrictions:**
- `--profile` cannot be used with `--servers` flag
- `--profile` cannot be used with `--enable-all-servers` flag
- These flags are mutually exclusive to ensure clear server selection

**Current limitations:**
- Profiles currently support image-only servers in the gateway
- Configuration and secrets support is being expanded
- Watch mode and dynamic updates are in development

## Using Profiles with MCP Clients

Connect an MCP client with a specific profile:

```bash
# Connect client with a profile
docker mcp client connect claude -p my-profile

# Using long form
docker mcp client connect cursor --profile my-profile

# Connect upon creating the profile
docker mcp profile create --name my-profile --connect cursor
```

This generates the appropriate client configuration using the servers from your profile.

## Profile File Format

Profiles are stored in YAML or JSON with the following structure:

### YAML Format

```yaml
version: 1
id: my-profile
name: My Profile
servers:
  - type: image
    image: mcp/github:latest
  - type: registry
    source: https://registry.modelcontextprotocol.io/v0/servers/71de5a2a-6cfb-4250-a196-f93080ecc860
    config:
      key: value
    secrets: default
    tools:
      - tool1
      - tool2
secrets:
  default:
    provider: docker-desktop-store
```

### JSON Format

```json
{
  "version": 1,
  "id": "my-profile",
  "name": "My Profile",
  "servers": [
    {
      "type": "image",
      "image": "mcp/github:latest"
    },
    {
      "type": "registry",
      "source": "https://registry.modelcontextprotocol.io/v0/servers/71de5a2a-6cfb-4250-a196-f93080ecc860",
      "config": {
        "key": "value"
      },
      "secrets": "default",
      "tools": ["tool1", "tool2"]
    }
  ],
  "secrets": {
    "default": {
      "provider": "docker-desktop-store"
    }
  }
}
```

### Field Descriptions

- **version**: Profile format version (currently `1`)
- **id**: Unique identifier for the profile
- **name**: Human-readable name
- **servers**: Array of server definitions
  - **type**: Either `image` or `registry`
  - **image**: (For type `image`) Docker image reference
  - **source**: (For type `registry`) MCP Registry URL
  - **config**: Optional configuration key-value pairs
  - **secrets**: Optional reference to a secrets configuration
  - **tools**: Optional list of specific tools to enable from this server
- **secrets**: Map of secret configurations
  - **provider**: Currently only `docker-desktop-store` is supported

## Common Workflows

### Development Workflow

```bash
# 1. Create a development profile
docker mcp profile create --name dev \
  --server catalog://mcp/docker-mcp-catalog:latest/filesystem

# 2. Test it with the gateway
docker mcp gateway run --profile dev

# 3. Add more servers as needed
docker mcp profile server add dev \
  --server catalog://mcp/docker-mcp-catalog:latest/slack

# 4. Remove servers you don't need
docker mcp profile server remove dev --name filesystem

# 5. Disable dangerous tools in filesystem server for safety
docker mcp profile tools dev --disable filesystem.delete_file

# 6. View all servers across profiles to check your setup
docker mcp profile servers

# 7. Once satisfied, export for sharing
docker mcp profile export dev ./dev-profile.yaml
```

### Team Collaboration

```bash
# Team lead: Create and share
docker mcp profile create --name team-tools \
  --server docker://my-server:latest \
  --server docker://my-other-server:latest \
  --server docker://mcp/jira:latest

docker mcp profile push team-tools docker.io/myorg/team-tools:v1.0

# Team members: Pull and use
docker mcp profile pull docker.io/myorg/team-tools:v1.0
docker mcp gateway run --profile team-tools
```

### Environment-Specific Configurations

```bash
# Create different profiles for different environments
docker mcp profile create --name production \
  --server docker://monitoring:latest \
  --server docker://logging:latest

docker mcp profile create --name staging \
  --server docker://monitoring:latest \
  --server docker://logging:latest \
  --server docker://debug:latest

# Run with appropriate environment
docker mcp gateway run --profile production  # In production
docker mcp gateway run --profile staging     # In staging
```

### Project-Based Organization

```bash
# Create profiles per project
docker mcp profile create --name project-a \
  --server docker://my-server:latest \
  --server docker://postgres:latest

docker mcp profile create --name project-b \
  --server docker://my-server:latest \
  --server docker://mongodb:latest

# Switch between projects easily
docker mcp gateway run --profile project-a
# ... or ...
docker mcp gateway run --profile project-b
```

### Versioning Profiles

```bash
# Create a profile
docker mcp profile create --name my-tools \
  --server docker://my-server:v1.0

# Push version 1.0
docker mcp profile push my-tools docker.io/myorg/my-tools:1.0

# Update the profile (modify via export/import)
docker mcp profile export my-tools ./temp.yaml
# ... edit temp.yaml ...
docker mcp profile import ./temp.yaml

# Push version 1.1
docker mcp profile push my-tools docker.io/myorg/my-tools:1.1

# Pull specific version when needed
docker mcp profile pull docker.io/myorg/my-tools:1.0
docker mcp profile pull docker.io/myorg/my-tools:1.1
```

### Building Profiles from Catalogs

```bash
# 1. Import Docker's official catalog (or pull from OCI registry)
docker mcp catalog create docker-mcp-catalog \
  --from-legacy-catalog https://desktop.docker.com/mcp/catalog/v3/catalog.json

# Or pull a team catalog from OCI registry
docker mcp catalog pull myorg/team-catalog:latest

# 2. Create an initial profile
docker mcp profile create --name my-workflow

# 3. Add specific servers from Docker's official catalog
docker mcp profile server add my-workflow \
  --server catalog://docker-mcp-catalog/github+slack

# 4. Optionally add servers from another catalog or direct references
docker mcp profile server add my-workflow \
  --server catalog://my-org/team-catalog/custom-tool

# Or add a direct OCI reference
docker mcp profile server add my-workflow \
  --server docker://mcp/custom-tool:latest

# 5. Configure and use
docker mcp profile config my-workflow --set github.timeout=30
docker mcp gateway run --profile my-workflow
```

### Fine-Tuning Tool Access

```bash
# Create a production profile with restricted tool access
docker mcp profile create --name production \
  --server docker://my-server:latest \
  --server docker://my-other-server:latest

# Disable all tools first, then enable only what's needed
docker mcp profile tools production --disable-all github --disable-all slack

# Enable only safe, read-only tools for GitHub
docker mcp profile tools production \
  --enable github.list_repos \
  --enable github.get_file \
  --enable github.search_code

# Enable only message sending for Slack (no channel management)
docker mcp profile tools production \
  --enable slack.send_message \
  --enable slack.list_channels

# Verify the tool configuration
docker mcp profile show production --format yaml

# Use the restricted profile
docker mcp gateway run --profile production
```

## Best Practices

### Naming Conventions

- Use descriptive names: `dev-tools`, `production-monitoring`, `team-shared`
- Keep IDs short and memorable: `dev`, `prod`, `team`
- Use versioning in OCI tags: `v1.0`, `v1.1`, `latest`

### Organization Strategies

- **By Environment**: Separate profiles for dev, staging, production
- **By Team**: Different sets for frontend, backend, devops teams
- **By Project**: One profile per major project or application
- **By Use Case**: Sets for debugging, monitoring, development, etc.

### Sharing and Collaboration

- Use OCI registries for team sharing rather than file exports
- Document your profiles in team wikis or READMEs
- Use semantic versioning for profile tags
- Keep a "team-shared" profile for common tools

### Security Considerations

- Always use `docker mcp secret set` for sensitive values (API keys, tokens, passwords)
- Never use `docker mcp profile config` for secrets - it's for non-sensitive settings only
- Secrets are stored in Docker Desktop's secure secret store
- Use private OCI registries for proprietary server configurations
- Review server references before importing from external sources
- Use `docker mcp profile tools` to disable dangerous or unnecessary tools in production
- Apply the principle of least privilege: enable only the tools actually needed
- Create separate profiles for different security contexts (dev vs. production)

## Troubleshooting

### Profile Not Found

```bash
Error: profile my-set not found
```

**Solution**: Check available profiles with `docker mcp profile list`

### Feature Not Enabled

```bash
Error: unknown command "profile" for "docker mcp"
```

**Solution**: In Docker CE or container mode, enable the feature with `docker mcp feature enable profiles`. In Docker Desktop, enable the `MCPWorkingSets` feature flag.

### Invalid Server Reference

```bash
Error: invalid server value: myserver
```

**Solution**: Ensure server references use either:
- `docker://` prefix for images
- `http://` or `https://` for registry URLs
- `catalog://` prefix for catalog references
- `file://` prefix for local server definition files

### Conflicting Flags

```bash
Error: cannot use --profile with --servers flag
```

**Solution**: Choose either `--profile` or `--servers`, not both

### ID Already Exists

```bash
Error: profile with id my-set already exists
```

**Solution**: Either:
- Choose a different name/ID
- Remove the existing set first with `docker mcp profile rm my-set`
- Omit the `--id` flag to auto-generate a unique ID

### Export/Import File Format

```bash
Error: unsupported file extension: .txt, must be .yaml or .json
```

**Solution**: Use `.yaml` or `.json` file extensions

### Invalid Config Format

```bash
Error: invalid config argument: myconfig, expected <serverName>.<configName>=<value>
```

**Solution**: Ensure config arguments follow the correct format:
- For `--set`: `<server-name>.<config-key>=<value>` (e.g., `github.timeout=30`)
- For `--get`: `<server-name>.<config-key>` (e.g., `github.timeout`)
- For `--del`: `<server-name>.<config-key>` (e.g., `github.timeout`)

### Server Not Found in Config Command

```bash
Error: server github not found in profile
```

**Solution**: 
- Use `docker mcp profile show <profile-id>` to see available server names
- Ensure you're using the server's name from its snapshot, not the image name or source URL
- Server names are case-sensitive

### Cannot Delete and Set Same Config

```bash
Error: cannot both delete and set the same config value: github.timeout
```

**Solution**: Don't use `--set` and `--del` for the same key in a single command. Run them separately:
```bash
# First delete
docker mcp profile config my-set --del github.timeout
# Then set (if needed)
docker mcp profile config my-set --set github.timeout=60
```

### Server Not Found in Catalog

```bash
Error: server 'nonexistent' not found in catalog
```

**Solution**: 
- Use `docker mcp catalog show <catalog-name>` to see available servers in the catalog
- Check that the server name is spelled correctly (names are case-sensitive)

### Cannot Remove Server

```bash
Error: server 'github' not found in profile
```

**Solution**:
- Use `docker mcp profile show <profile-id> --format yaml` to see current servers in the profile
- Ensure you're using the correct server name in the snapshot (not the image name or source URL)
- Server names are case-sensitive

### Invalid Tool Name Format

```bash
Error: invalid tool specification: github
```

**Solution**: Tool names must use dot notation with both server and tool name:
```bash
# Wrong
docker mcp profile tools my-profile --enable github

# Correct
docker mcp profile tools my-profile --enable github.create_issue
```

### Server Not Found When Managing Tools

```bash
Error: server 'github' not found in profile
```

**Solution**:
- Ensure the server with that snapshot name exists in the profile: `docker mcp profile show <profile-id> --format yaml`
- Server names are case-sensitive and must match the snapshot name
- Add the server first if it doesn't exist: `docker mcp profile server add <profile-id> --server docker://my-org/my-server`

### Tool Not Found in Server

```bash
Error: tool 'invalid_tool' not found in server 'github'
```

**Solution**:
- Use `docker mcp profile show <profile-id> --format yaml` to see available tools for each server
- Tool names are case-sensitive and must match exactly
- Check the server's documentation for available tool names

## Limitations and Future Enhancements

### Current Limitations

- Gateway support is limited to image-only servers
- No automatic watch/reload when profiles are updated
- Limited to Docker Desktop's secret store for secrets
- No built-in conflict resolution for duplicate server names

### Planned Enhancements

- Full registry support in the gateway
- Search and discovery features

## Creating Catalogs

The `catalog` command allows you to create and share catalogs:

```
/* Detailed source-code truncated for AI context efficiency. */
```

**Key points:**
- Catalogs are an immutable collection of MCP Servers
- When creating a catalog from a profile, only the servers are included in the catalog.
- Use catalogs to share a stable server collection across teams
- Catalogs can be pushed to/pulled from OCI registries like Docker images
- Output supports `--format` flag: `human` (default), `json`, or `yaml`

**💡 Tip:** You can import Docker's official MCP catalog as a starting point:
```bash
docker mcp catalog create docker-mcp-catalog \
  --from-legacy-catalog https://desktop.docker.com/mcp/catalog/v3/catalog.json
```
This gives you access to Docker's curated collection of MCP servers, which you can then use to build your profiles with the `--server catalog://docker-mcp-catalog/<server>` flag

## Related Documentation

- [MCP Gateway](./mcp-gateway.md) - Running the MCP gateway
- [Catalog Management](./catalog.md) - Managing MCP server catalogs
- [Feature Management](./troubleshooting.md#features) - Enabling/disabling features
- [Security](./security.md) - Security considerations

---

### Security (`docs/security.md`)

# Docker MCP Gateway security model

Docker MCP Gateway is a security boundary between MCP clients and the MCP servers
that the gateway runs or connects to. The gateway is designed to reduce what a
malicious or compromised MCP server can read, receive, log, or route through the
host.

This document describes the default security boundaries for the Docker MCP
Gateway and how we triage vulnerability reports. A report is usually in scope
when an untrusted catalog entry, remote server, image label, or MCP server can
bypass one of the boundaries below without the user or operator explicitly
granting that access.

## Trust assumptions

- The local OS user, Docker daemon, Docker Desktop components, configured
  credential store, configured interceptors, and local Docker MCP configuration
  files are trusted. An attacker who can modify those inputs can change gateway
  behavior and is outside this boundary.
- A catalog, profile, server entry, OCI image label, MCP registry entry, README
  URL, or remote MCP server URL may be untrusted. The gateway should treat those
  values as data and must not let them expand into broader host, network, secret,
  or routing access.
- The code inside an enabled MCP server may be malicious. It should only receive
  the environment variables, secrets, filesystem mounts, network access, and MCP
  routing access granted by the gateway configuration and defaults.
- Docker's MCP Catalog build-time review, dependency scanning, malware scanning,
  and publishing process are separate from this repository. Bypasses of those
  processes should be reported against the catalog or publishing system. Bypasses
  of gateway enforcement are in scope here.

## Gateway boundaries

### HTTP transports

The default `stdio` transport is local to the launching MCP client. When the
gateway is run with the `sse` or `streaming` HTTP transports, requests require a
Bearer token by default. The token is read from `MCP_GATEWAY_AUTH_TOKEN` when set
or generated by the gateway. `--allow-unauthenticated` is an explicit opt-out.

Browser requests with an `Origin` header are accepted only from localhost origins
(`localhost`, `127.0.0.1`, or `::1`). Requests without an `Origin` header remain
allowed so non-browser MCP clients can connect. The `/health` endpoint is not an
MCP protocol endpoint and is intentionally unauthenticated.

### Catalogs, local files, and OCI metadata

Catalog paths supplied to gateway commands must resolve under
`~/.docker/mcp/catalogs/`. Local `file://` server references are also resolved
relative to that trusted catalog directory, including symlink containment checks,
before a file is opened.

OCI image labels are treated as import metadata only. Labels may provide
descriptive server and tool metadata, but they must not inject runtime-shaping
fields such as commands, volume mounts, secrets, environment values, users, or
nested container configuration. Those fields must come from trusted catalog or
user configuration paths.

### Remote URLs and untrusted fetches

Remote MCP URLs and untrusted HTTP fetches require public HTTPS destinations by
default. The gateway rejects userinfo, unsafe hostnames, loopback, private,
link-local, metadata-service, and other non-public IP ranges, and it validates
redirect destinations. Guarded direct transports also validate the resolved
destination at dial time.

`DOCKER_MCP_ALLOW_INSECURE_REMOTE_URLS=1` is a development and test opt-out for
local or HTTP endpoints. Reports that depend on this opt-out are out of scope
unless they also bypass another documented boundary.

### Image verification

Signature verification is enabled by default for Docker MCP images in the Docker
Hub `mcp/` namespace. Those images must be referenced by digest when verification
is enabled, and they are verified before pull or run. `--verify-signatures=false`
is an explicit opt-out.

Third-party images outside Docker MCP's signing namespace are not verified with
Docker MCP signatures. Their trust comes from the user's catalog, profile, or
operator configuration choice.

### Container execution

MCP server containers do not receive the user's host environment by default. The
gateway passes only configured environment variables, server config values, and
secrets declared for that server. Containers are started with Docker isolation,
`no-new-privileges`, and configured CPU and memory limits.

Host bind mounts from catalog or profile configuration are validated before they
are passed to Docker. Named and anonymous Docker volumes are allowed. Host path
binds default to read-only, must resolve under trusted roots such as temporary
directories or `MCP_GATEWAY_DOCKER_BIND_ALLOWED_PATHS`, and cannot target known
sensitive system or credential paths. Writable host path binds require an exact
path allowlist entry in `MCP_GATEWAY_DOCKER_BIND_ALLOW_WRITABLE_PATHS`.

Network egress is not globally denied by default. Servers can request
`disableNetwork`, `allowHosts`, and the gateway can run with `--block-network` to
enforce more restrictive network access. A server making network calls within the
granted network configuration is not, by itself, a gateway vulnerability.

### Secrets and logs

Secrets are scoped to the server that declares them. Secret names are validated
before they are used with the credential resolver, and one server should not be
able to receive another server's declared secrets by guessing names or using
pattern metacharacters.

`--block-secrets` is enabled by default and scans tool-call arguments and text
responses for secret-like values before and after tool execution. `--log-calls`
is also enabled by default, but call logs record the tool name and argument shape
metadata only. Raw tool-call argument keys and values must not be logged by the
default call logger.

### MCP routing and policy

The gateway rejects exposed tool names that collide with reserved gateway tools
or with tools from another enabled server. It also rejects collisions for prompt
names, resource URIs, and resource template URI templates. Dynamic registration
and reload paths must apply the same collision checks before capabilities become
available to clients.

Gateway policy decisions must apply consistently across direct tool calls,
dynamic tool execution, `mcp-exec`, and code-mode generated tools. A path that
invokes a denied or disabled backend tool despite policy is in scope.

### Tool schema translation

A tool schema is a JSON document supplied by a backend server, so the gateway
treats it as untrusted input. Tool schemas declaring JSON Schema draft-04,
draft-06 or draft-07 are translated to 2020-12 before being advertised, which
means the gateway walks a document it previously relayed opaquely. That walk is
bounded in both depth and node count and leaves the schema untranslated when
either limit is exceeded; an unbounded walk over a crafted schema would be in
scope. Translation never widens what a schema accepts -- a construct with no
faithful 2020-12 equivalent is relayed as declared rather than reinterpreted --
and `--preserve-tool-schema-dialect` turns the translation off entirely.

## In-scope report examples

- An untrusted catalog, profile, image label, registry entry, or remote URL causes
  the gateway to read a host file outside the trusted catalog directory.
- A server receives another server's secret, or a secret is sent to a remote
  server without being declared for that server.
- A catalog-controlled volume mounts a sensitive host path, creates a writable
  host bind without an explicit writable allowlist entry, or smuggles Docker
  flags through mount values.
- A default remote URL or redirect reaches loopback, private networks, cloud
  metadata endpoints, or other non-public destinations without the insecure URL
  opt-out.
- An unauthenticated request reaches MCP protocol endpoints on the `sse` or
  `streaming` transports without `--allow-unauthenticated`.
- A browser request with a non-localhost `Origin` can use MCP protocol endpoints.
- A Docker MCP `mcp/` image bypasses default signature verification or mutable tag
  rejection while verification is enabled.
- A colliding tool, prompt, resource, or resource template shadows another server
  or a gateway capability.
- Code-mode, dynamic tools, or `mcp-exec` can invoke a tool that policy denies.
- Default call logging records raw tool-call argument keys or values.

## Out-of-scope report examples

- A user or operator explicitly enables unsafe behavior, such as
  `--allow-unauthenticated`, `--verify-signatures=false`,
  `DOCKER_MCP_ALLOW_INSECURE_REMOTE_URLS=1`, broad bind-mount allowlists,
  writable bind allowlists, custom interceptors, or intentionally granted
  secrets, and the reported behavior stays within that grant.
- A malicious enabled MCP server abuses access that was intentionally granted to
  it, such as reading a mounted directory, using an assigned secret, contacting
  an allowed host, or returning malicious content to the MCP client.
- Prompt injection, tool-description poisoning, or malicious content from a tool,
  README, remote service, or upstream API, unless it bypasses a gateway boundary
  described in this document.
- Compromise of the local OS user, Docker daemon, Docker Desktop, host keychain,
  Docker credential helper, or local gateway binary.
- Unauthenticated access to `/health`, or requests without an `Origin` header
  from non-browser clients.
- Use of unsigned or malicious third-party images outside Docker MCP's signing
  namespace when the user or operator chose to run those images.
- Resource consumption that remains within the configured CPU and memory limits.
- Logs that include only tool names and argument shape metadata, without raw
  argument keys or values.

---

### Server Entry Spec (`docs/server-entry-spec.md`)

# MCP Server Entry Specification

This document defines the specification for MCP server entries in the Docker MCP Gateway catalog system.

Server entries can be defined for an mcp server by writing a yaml file and using it as a CLI flag for profiles or catalogs via `--server file://my-server.yaml`.

**A note about legacy catalogs:** Legacy catalogs such as `.docker/mcp/catalogs/docker-mcp.yaml` or https://desktop.docker.com/mcp/catalog/v3/catalog.yaml use a similar schema for servers under the `registry` property. However, this spec is intended for defining server configurations for MCP Profiles and OCI Catalogs. Thus, it's expected that this spec will drift from what exists in legacy catalogs.


## Example Server Entry YAML

```yaml
name: duckduckgo
title: DuckDuckGo
type: server
image: mcp/duckduckgo@sha256:68eb20db6109f5c312a695fc5ec3386ad15d93ffb765a0b4eb1baf4328dec14f
description: A Model Context Protocol (MCP) server that provides web search capabilities through DuckDuckGo, with additional features for content fetching and parsing.
allowHosts:
  - html.duckduckgo.com:443
```

## Server Entry Structure

### Core Fields

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `name` | string | **Yes** | Unique identifier for the server. Used for referencing and managing the server. |
| `type` | string | **Yes** | Server type. Must be one of: `server`, `remote`, or `poci`. |
| `title` | string | **Yes** | Human-readable display name for the server. |
| `description` | string | **Yes** | Brief description of the server's capabilities and purpose. |
| `icon` | string | No | URL to an icon/logo representing the server. |
| `readme` | string | No | URL to a README file with detailed documentation for the server. |

### Container Configuration (for type: "server")

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `image` | string | Yes* | Docker image reference (can be SHA256 digest or tag). Required for `server` type. |
| `command` | []string | No | Command-line arguments to pass to the container. |
| `volumes` | []string | No | Volume mount specifications (format: `host:container`, `host:container:ro`, or `host:container:rw`). |
| `user` | string | No | User to run the container as (e.g., `1000:1000`). |
| `longLived` | boolean | No | Whether the server should remain running (true) or start on-demand (false). Default: false. |

#### Host Bind Mount Safety

Host path bind mounts default to read-only when no mode is specified. Explicit writable host path bind mounts, and no-mode bind mounts that should become writable, are rejected unless the resolved host source exactly matches an entry in `MCP_GATEWAY_DOCKER_BIND_ALLOW_WRITABLE_PATHS`. Use the OS path-list separator when setting multiple entries.

Setting `MCP_GATEWAY_DOCKER_BIND_ALLOW_WRITABLE_PATHS` means any catalog or profile you load can request that exact host path as writable. Scope writable entries to dedicated data directories, not source trees or broad project directories.

### Remote Configuration (for type: "remote")

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `remote` | Remote | Yes* | Remote server configuration. Required for `remote` type. |
| `sseEndpoint` | string | No | **Deprecated**: Legacy SSE endpoint URL. Use `remote` instead. |

**Remote Object Structure:**

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `url` | string | Yes | URL endpoint for the remote MCP server. |
| `transport_type` | string | No | Transport protocol type (e.g., `sse` for Server-Sent Events). |
| `headers` | map[string]string | No | Custom HTTP headers to send with requests. |

### Authentication & Secrets

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `secrets` | []Secret | No | API keys and secrets required by the server. |
| `oauth` | OAuth | No | OAuth configuration for authentication flows. |

**Secret Object Structure:**

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `name` | string | Yes | Name of the secret. Must be prefixed by unique name of the server (e.g., `brave.api_key`). |
| `env` | string | Yes | Environment variable name to inject the secret as (e.g., `BRAVE_API_KEY`). |
| `example` | string | Yes | An example value for the key (e.g. `your_api_key`) |

**OAuth Object Structure:**

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `providers` | []OAuthProvider | Yes | List of OAuth providers supported. |
| `scopes` | []string | No | OAuth scopes to request. |

**OAuthProvider Object Structure:**

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `provider` | string | Yes | OAuth provider identifier (e.g., `github`, `google`). |
| `secret` | string | Yes | Reference to stored OAuth credentials. Must be prefixed by unique name of the server (e.g., `asana.personal_access_token`) |
| `env` | string | Yes | Environment variable to inject OAuth token as. |

### Environment Variables

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `env` | []Env | No | Static environment variables to set in the container. |

**Env Object Structure:**

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `name` | string | Yes | Environment variable name. (e.g. `ASTRA_DB_API_ENDPOINT`) |
| `value` | string | Yes | Environment variable value. Can reference config fields using template syntax (e.g., `{{astra-db.endpoint}}`). |

### Network & Security

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `disableNetwork` | boolean | No | If true, disables all network access for the container. Default: false. |
| `allowHosts` | []string | No | Whitelist of hosts/domains the server is allowed to access (e.g., `["api.github.com:443", "github.com:443"]`). |

### Tools Definition

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `tools` | []Tool | No | Array of tools provided by this server. Used for discovery and documentation. |

**Tool Object Structure:**

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `name` | string | Yes | Tool identifier (unique within the server). |
| `description` | string | No | Human-readable description of what the tool does. |
| `arguments` | []ToolArgument | No | Tool argument definitions (only set for OCI catalogs, not legacy catalogs). |
| `annotations` | ToolAnnotations | No | Tool annotations with hints about behavior (only set for OCI catalogs). |

**ToolArgument Object Structure:**

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `name` | string | Yes | Argument name. |
| `type` | string | No | JSON Schema type (`string`, `number`, `boolean`, `array`, etc.). |
| `desc` | string | No | Description of the argument. |
| `items` | Items | No | For array types, defines the item schema. |
| `optional` | boolean | No | Whether the argument is optional. Default: false. |

**ToolAnnotations Object Structure:**

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `title` | string | No | Human-readable title for the tool. |
| `readOnlyHint` | boolean | No | Hint that the tool only reads data and does not modify state. |
| `destructiveHint` | boolean | No | Hint that the tool may perform destructive operations. |
| `idempotentHint` | boolean | No | Hint that the tool is idempotent (repeated calls have the same effect). |
| `openWorldHint` | boolean | No | Hint that the tool interacts with external systems/world. |

### Configuration Schema

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `config` | []ConfigObject | No | Array of configuration objects defining user-configurable settings for the server. Each config object represents a group of related settings that users must provide before using the server. |

**ConfigObject Structure:**

The config field accepts an array of configuration objects. Each object defines a set of user-configurable parameters that can be referenced in environment variables using template syntax (e.g., `{{server-name.property-name}}`).

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `name` | string | Yes | Unique identifier for this config object. Should match the server's unique name (e.g., `couchbase`, `desktop-commander`). |
| `description` | string | Yes | Human-readable description explaining what these settings configure. |
| `type` | string | Yes | Must be `object`. Defines this as a configuration object. |
| `properties` | map[string]PropertySchema | Yes | Map of property names to their schema definitions. Each key is a field name that users will configure. |
| `required` | []string | No | Array of property names that must be provided by the user. |
| `anyOf` | []RequirementSet | No | Alternative requirement sets - user must satisfy at least one set. |
| `oneOf` | []RequirementSet | No | Exclusive requirement sets - user must satisfy exactly one set. |

**PropertySchema Structure:**

Defines the schema for a single configurable property:

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `type` | string | Yes | JSON Schema type: `string`, `number`, `boolean`, `array`, or `object`. |
| `description` | string | No | User-facing description explaining what this property configures. |
| `items` | ItemsSchema | No | For `array` types, defines the schema of array elements. |
| `properties` | map[string]PropertySchema | No | For `object` types, defines nested properties. |
| `required` | []string | No | For `object` types, lists required nested properties. |
| `default` | any | No | Default value if user doesn't provide one. |
| `enum` | []any | No | Allowed values for this property. |
| `pattern` | string | No | Regular expression pattern for string validation. |
| `minimum` | number | No | Minimum value for numbers. |
| `maximum` | number | No | Maximum value for numbers. |

**ItemsSchema Structure:**

For array-type properties:

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `type` | string | Yes | Type of array elements (e.g., `string`, `number`, `object`). |

**RequirementSet Structure:**

For `anyOf` or `oneOf` conditional requirements:

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `required` | []string | Yes | List of property names that must be provided together. |

**Config Examples:**

**Example 1: Simple String Properties**
```yaml
config:
  - name: couchbase
    description: "Configure the connection to Couchbase"
    type: object
    properties:
      cb_connection_string:
        type: string
        description: "Connection string for the Couchbase cluster"
      cb_username:
        type: string
        description: "Username for the Couchbase cluster with access to the bucket"
      cb_bucket_name:
        type: string
        description: "Bucket in the Couchbase cluster to use for the MCP server"
    required:
      - cb_connection_string
      - cb_username
      - cb_bucket_name
```

**Example 2: Array Type Configuration**
```yaml
config:
  - name: desktop-commander
    description: "Configure filesystem access and network permissions"
    type: object
    properties:
      paths:
        type: array
        description: "List of directories that Desktop Commander can access"
        items:
          type: string
    required:
      - paths
```

**Example 3: Nested Object Properties**
```yaml
config:
  - name: atlassian
    description: "The MCP server is allowed to access these paths"
    type: object
    properties:
      confluence:
        type: object
        properties:
          url:
            type: string
            description: "Confluence instance URL"
          username:
            type: string
            description: "Confluence username"
      jira:
        type: object
        properties:
          url:
            type: string
            description: "Jira instance URL"
          username:
            type: string
            description: "Jira username"
    anyOf:
      - required: [confluence]
      - required: [jira]
```

**Referencing Config Values:**

Config values can be referenced in environment variables and command arguments using template syntax:

```yaml
name: astra-db
config:
  - name: astra-db
    description: "Configure Astra DB connection"
    type: object
    properties:
      endpoint:
        type: string
        description: "Astra DB API endpoint URL"
      token:
        type: string
        description: "Astra DB application token"
    required:
      - endpoint
      - token
env:
  - name: ASTRA_DB_API_ENDPOINT
    value: "{{astra-db.endpoint}}"
  - name: ASTRA_DB_APPLICATION_TOKEN
    value: "{{astra-db.token}}"
```

### Metadata

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `metadata` | Metadata | No | Additional metadata about the server (for display and categorization). |

**Metadata Object Structure:**

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `pulls` | integer | No | Number of Docker image pulls. |
| `stars` | integer | No | Number of stars/ratings. |
| `githubStars` | integer | No | Number of GitHub stars for the source repository. |
| `category` | string | No | Category classification (e.g., `Development`, `Cloud`, `AI`). |
| `tags` | []string | No | Tags for searchability and filtering. |
| `license` | string | No | Software license (e.g., `MIT`, `Apache-2.0`). |
| `owner` | string | No | Owner/maintainer identifier. |

## Server Types

### Type: "server"

A containerized MCP server that runs as a Docker container managed by the gateway.

**Required fields:**
- `name`
- `type: "server"`
- `image`

**Example:**
```yaml
name: github-official
type: server
title: GitHub Official
description: Official GitHub MCP server for repository management
image: ghcr.io/github/github-mcp-server@sha256:a1d43076a36638ee24520fd6e83c3905ae41bc9850179081df1de2ba3a7afae0
icon: https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png
secrets:
  - name: github.personal_access_token
    env: GITHUB_PERSONAL_ACCESS_TOKEN
    example: <YOUR_TOKEN>
    description: You can create a GitHub personal access token [on GitHub](https://github.com/settings/personal-access-tokens/new)
allowHosts:
  - api.github.com:443
  - github.com:443
  - raw.githubusercontent.com:443
```

### Type: "remote"

An MCP server hosted remotely and accessed via HTTP/SSE protocol.

**Required fields:**
- `name`
- `type: "remote"`
- `remote.url`

**Example:**
```yaml
name: cloudflare-docs
description: Access the latest documentation on Cloudflare products such as Workers, Pages, R2, D1, KV.
title: Cloudflare Docs
type: remote
remote:
  transport_type: sse
  url: https://docs.mcp.cloudflare.com/sse
icon: https://www.cloudflare.com/favicon.ico
```

## Best Practices

1. **Naming**: Use lowercase, hyphen-separated names (e.g., `github-official`, `aws-core-mcp-server`)
2. **Images**: Prefer SHA256 digests for production, tags for development. Make sure images exist on a repository that can be accessed by those who can access the server entry (e.g. via code commit or in a private catalog)
3. **Security**:
   - Use `allowHosts` to restrict network access
   - Use `disableNetwork: true` for tools that don't need network
   - Always use secrets for credentials, never hardcode in `env`

---

### Troubleshooting (`docs/troubleshooting.md`)

# Troubleshooting the MCP Gateway

Sometimes, you plug the MCP Gateway into your favorite MCP client and it doesn't work as expected.
What can you do to pinpoint where the problem comes from?

## Debug the MCP Gateway's startup sequence

The go to command to start a fresh Gateway, plugged into Docker Desltop's Toolkit is this one:

```console
docker mcp gateway run --verbose --dry-run
```

This will show you how the Gateway is reading the configuration, which servers are actually
enabled, which images are pulled and which MCP servers are started with which command line arguments.

It'll show you how many tools you have, in aggregate.

This is usually a good way to troubleshoot missing images, invalid server names, missing config
or secrets...

You can also focus a one given server with:

```console
docker mcp gateway run --verbose --dry-run --servers=duckduckgo
```

## Debug tool calls

Full fledge MCP clients might sometimes hide the errors they encounter while calling tools
on the MCP Gateway.

Here's a useful set of commands you can use to debug your tool calls:

```console
# List the aggregate number of tools
docker mcp tools ls

# To see what's going on in the gateway while listing tools
docker mcp tools ls --verbose

# Call one of the tools
docker mcp tools call search query=Docker

# Be verbose and pass additional parameters to the Gateway
docker mcp tools call --gateway-arg="--servers=duckduckgo" --verbose search query=Docker
```

## A client rejects every tool of one server: "unsupported dialect"

Some clients validate tool schemas with a validator configured for JSON Schema 2020-12
only, and refuse a tool whose schema declares an older dialect. The error names one tool
but applies to every tool on that server:

```
Tool 'list_bases' has an invalid outputSchema: JSON Schema declares an unsupported
dialect ("$schema": "http://json-schema.org/draft-07/schema#").
```

This is not a broken or stale server image, and rebuilding it will not help. MCP lets a
schema declare any dialect and requires clients to support only 2020-12, so both sides are
behaving correctly; servers built on the MCP TypeScript SDK declare draft-07 for every tool
because its zod converter defaults to that target.

The gateway translates draft-04, draft-06 and draft-07 tool schemas into 2020-12 before
advertising them, so an up to date gateway resolves this on its own. To see what a server
declared versus what clients are served, compare the two:

```console
# what clients are served
docker mcp tools ls --format json | jq '.[] | {name, dialect: .inputSchema["$schema"]}'

# what the server declared, with translation turned off
docker mcp tools ls --gateway-arg="--preserve-tool-schema-dialect" --format json | jq '.[] | {name, dialect: .inputSchema["$schema"]}'
```

A schema the gateway cannot translate without changing what it accepts is relayed exactly
as the server declared it, and so is one declaring a dialect the gateway does not handle at
all (draft-03, 2019-09) — that second case is counted separately as `unsupported_dialect`,
because nothing about the schema can be fixed here. The gateway reports those once per server and reason on its
stderr, which `docker mcp tools ls` surfaces under `--verbose`:

```console
docker mcp tools ls --verbose 2>&1 | grep 'Relaying'
```

```
- mcp-gateway:   > Relaying 3 schema(s) from some-server with the dialect declared, outputSchema: schema declares unevaluatedProperties, which the declared dialect does not define and 2020-12 enforces
```

Those tools still work; a 2020-12-only client will still reject them, and the fix has to
happen in the server. The reasons are all cases where relabelling the dialect would change
which inputs the schema accepts, so the gateway declines to guess. The commonest is a
keyword the declared dialect does not define: `const` in a draft-04 schema, or
`if`/`then`/`else` in a draft-06 one, are inert where they were written and become live
assertions the moment the document claims 2020-12.

---

### Feature Specs Dynamic Servers (`docs/feature-specs/dynamic_servers.md`)

# Dynamic Server Management

## Overview

The Dynamic Server Management feature allows users to dynamically add, remove, and configure MCP servers at runtime without restarting the gateway. This feature is enabled by the `dynamic-tools` feature flag and provides a set of internal management tools that can be called by AI clients.

## Feature Flag

This feature is controlled by the `dynamic-tools` feature flag:

```bash
# Enable dynamic tools feature
docker mcp feature enable dynamic-tools

# Check if enabled
docker config view | grep dynamic-tools
```

When enabled, the gateway adds five internal management tools to the available tool set.

**Note**: Dynamic tools are automatically disabled when using the `--servers` flag to explicitly specify which servers to run. This is because explicit server configuration indicates a manual mode where automatic server management tools are not needed.

### Security boundary

The registry is the gateway's operator-enabled active set. Servers already in that set can be managed without an external policy provider. A catalog-only server can be activated or configured—individually or through a profile—only when a non-noop policy provider explicitly allows its `load` action. The self-hosted/no-governance noop client is not treated as authorization to cross from the catalog into the active set.

Deployments that need catalog-wide dynamic activation must configure governance policy rules for the servers that may be loaded. Deployments requiring a fixed server set can pass the allowed names with `--servers`, which disables dynamic tools entirely.

## Available Tools

### 1. mcp-find

**Purpose**: Search for MCP servers in the current catalog by name or description.

**Parameters**:
- `query` (required): Search query to find servers by name or description (case-insensitive)
- `limit` (optional): Maximum number of results to return (default: 10)

**Example Usage**:
```json
{
  "name": "mcp-find",
  "arguments": {
    "query": "filesystem",
    "limit": 5
  }
}
```

**Response**: Returns matching servers with their details including name, description, required secrets, config schema, and long-lived status.

### 2. mcp-add

**Purpose**: Add a new MCP server to the registry and reload the configuration.

**Parameters**:
- `name` (required): Name of the MCP server to add to the registry (must exist in catalog)

**Example Usage**:
```json
{
  "name": "mcp-add",
  "arguments": {
    "name": "filesystem"
  }
}
```

**Behavior**:
- Checks if the server exists in the catalog
- Requires the server to be enabled already or explicitly allowed by an enforcing policy provider
- Adds the server to the active server list (avoiding duplicates)
- Fetches updated secrets for the new server
- Reloads the gateway configuration
- Returns success/error message

### 3. mcp-remove

**Purpose**: Remove an MCP server from the registry and reload the configuration.

**Parameters**:
- `name` (required): Name of the MCP server to remove from the registry

**Example Usage**:
```json
{
  "name": "mcp-remove",
  "arguments": {
    "name": "filesystem"
  }
}
```

**Behavior**:
- Removes the server from the active server list
- Reloads the gateway configuration
- Returns success message

### 4. mcp-official-registry-import

**Purpose**: Import MCP servers from an official registry URL.

**Parameters**:
- `url` (required): URL to fetch the official registry JSON from (must be HTTP/HTTPS)

**Example Usage**:
```json
{
  "name": "mcp-official-registry-import",
  "arguments": {
    "url": "https://registry.example.com/servers.json"
  }
}
```

**Behavior**:
- Validates the URL format
- Fetches server definitions via HTTP GET
- Adds imported servers to the local catalog
- Automatically enables imported servers
- Reloads the gateway configuration
- Returns detailed summary of each imported server including:
  - Server name and description
  - Docker image information  
  - Required secrets with configuration warnings
  - Available configuration schemas
  - Long-lived server indicators
  - Ready-to-use server list

### 5. mcp-config-set

**Purpose**: Set configuration values for MCP servers.

**Parameters**:
- `server` (required): Name of the MCP server to configure
- `key` (required): Configuration key to set
- `value` (required): Configuration value to set (can be string, number, boolean, or object)

**Example Usage**:
```json
{
  "name": "mcp-config-set",
  "arguments": {
    "server": "filesystem",
    "key": "allowed_paths",
    "value": ["/home/user/documents", "/tmp"]
  }
}
```

**Behavior**:
- Requires the server to be enabled already or explicitly allowed by an enforcing policy provider
- Creates or updates server configuration
- Reloads the gateway configuration to apply changes
- Returns success message with old/new values

## Implementation Details

### Secret Management

When servers are added dynamically, the system automatically:

1. **Fetches required secrets**: Calls `readDockerDesktopSecrets()` with the updated server list
2. **Updates configuration**: Replaces the existing secrets map with newly fetched secrets
3. **Handles errors gracefully**: Logs warnings if secret fetching fails but continues operation

### Duplicate Prevention

The `mcp-add` tool ensures server name uniqueness by:
- Checking existing server names before adding
- Only appending new servers if not already present
- Maintaining the original order of servers

### Configuration Reloading

All management tools trigger configuration reloading via `reloadConfiguration()`:
- Updates tool, prompt, and resource registrations
- Refreshes capabilities with the MCP server
- Applies new secrets and configurations
- Maintains session state for existing connections

## Use Cases

### 1. Development Workflow
```
AI: I need to work with files. Let me find filesystem tools.
Tool: mcp-find -> query: "filesystem"
AI: Great! I'll add the filesystem server.
Tool: mcp-add -> name: "filesystem"
AI: Now I can use file operations.
```

### 2. Importing Official Servers
```
AI: I want to use servers from the official registry.
Tool: mcp-official-registry-import -> url: "https://registry.mcp.dev/servers.json"
AI: Successfully imported 12 servers. I can now use them.
```

### 3. Server Configuration
```
AI: I need to configure the filesystem server with specific paths.
Tool: mcp-config-set -> server: "filesystem", key: "allowed_paths", value: ["/workspace"]
AI: Configuration updated. The server now has restricted access.
```

## Security Considerations

- **Catalog validation**: Only servers that exist in the catalog can be considered
- **Activation authorization**: Catalog-only servers require an enforcing policy provider; a noop or missing policy cannot authorize individual, profile-based, or configuration-driven activation
- **Secret management**: Secrets are fetched securely through Docker Desktop's secrets API
- **Configuration isolation**: Server configurations are isolated and validated
- **URL validation**: Official registry imports require valid HTTP/HTTPS URLs

## Logging

The feature provides detailed logging for:
- Server additions and removals
- Configuration changes
- Secret fetching operations
- Import operations from external registries
- Warnings for duplicate servers or failed operations

## Error Handling

- **Missing servers**: Returns helpful error messages when servers aren't found in catalog
- **Secret failures**: Logs warnings but continues operation
- **Configuration errors**: Returns detailed error messages for troubleshooting
- **Network failures**: Handles HTTP errors gracefully for registry imports

## Future Enhancements

Potential future improvements include:
- Bulk server operations
- Server dependency management
- Configuration validation
- Server status monitoring
- Rollback capabilities

---

### Feature Specs Embeddings Feature (`docs/feature-specs/embeddings-feature.md`)

---
marp: true
theme: default
paginate: true
---

# Vector Embeddings for MCP Gateway

**Semantic Search for MCP Servers and Tools**

---

## Overview

Added AI-powered semantic search capabilities to the MCP Gateway using OpenAI embeddings and SQLite vector database.

**Key Features:**
- Vector similarity search for finding relevant MCP servers
- Feature flag system for opt-in usage
- Graceful fallback to keyword search

---

## Components

```mermaid
  flowchart TD
    A["MCP Gateway"] --> B["Embeddings Client"]
    B --> C["Docker Container"]
    C --> D["vector-db MCP Server"]
    D --> E["SQLite-vec extension"]
    E --> F["~/.docker/mcp/vectors.db"]
    A --> G["OpenAI API"]
    G --> H["text-embedding-3-small"]
    style A fill:#e1f5ff
    style B fill:#fff3e0
    style D fill:#f3e5f5
```

---

## Feature Flag System

```bash
# Enable embeddings feature
docker mcp feature enable use-embeddings

# Set OpenAI API key
export OPENAI_API_KEY="sk-..."
```

**Configuration:**
- Feature: `use-embeddings` (disabled by default)
- Storage: `~/.docker/mcp/vectors.db`
- Model: OpenAI `text-embedding-3-small` (1536 dimensions)

---

## How mcp-find Works with Embeddings

```mermaid
  sequenceDiagram
    participant User
    participant Gateway
    participant OpenAI
    participant VectorDB
    participant Catalog
    User->>Gateway: mcp-find "tools for github"
    alt Embeddings Enabled
        Gateway->>OpenAI: Generate embedding for query
        OpenAI-->>Gateway: [0.014, -0.018, ...]
        Gateway->>VectorDB: Search mcp-server-collection
        VectorDB-->>Gateway: Top 5 similar servers
        Gateway->>Catalog: Lookup server details
        Catalog-->>Gateway: Server metadata
    else Embeddings Disabled
        Gateway->>Catalog: Keyword search (title/description)
        Catalog-->>Gateway: Matching servers
    end
    Gateway-->>User: Server results
```

---

## Implementation: VectorDBClient

```go
type VectorDBClient struct {
    cmd     *exec.Cmd
    client  *mcp.Client
    session *mcp.ClientSession
}

// Connects to Docker container running vector-db
func NewVectorDBClient(ctx context.Context, dataDir string) (*VectorDBClient, error) {
    cmd := exec.CommandContext(ctx,
        "docker", "run", "-i", "--rm",
        "-v", fmt.Sprintf("%s:/data", dataDir),
        "-e", "DB_PATH=/data/vectors.db",
        "-e", "VECTOR_DIMENSION=1536",
        "jimclark106/vector-db:latest",
    )
    // ... MCP client setup with CommandTransport
}
```

---

## Key Operations

```go
type SearchArgs struct {
    Vector             []float64 `json:"vector"`
    CollectionName     string    `json:"collection_name,omitempty"`
    ExcludeCollections []string  `json:"exclude_collections,omitempty"`
    Limit              int       `json:"limit,omitempty"`
}

func (c *VectorDBClient) SearchVectors(
    ctx context.Context,
    vector []float64,
    options *SearchOptions,
) ([]SearchResult, error)
```
**Collections:**
- `Tool embeddings`: one vector collection/server
- `mcp-server-collection`: MCP server metadata

---

## Updated Tools

### mcp-find Tool
- **With Embeddings:** Semantic search against `mcp-server-collection`
- **Without Embeddings:** Traditional keyword matching
- Returns: Server name, description, secrets, config schema

### find-tools Tool
- **With Embeddings:** AI-powered server recommendations
- **Without Embeddings:** Error message with guidance
- Input: Natural language task description
- Output: Relevant servers from catalog

---

## Code Structure

```
pkg/gateway/
├── embeddings/
│   └── client.go          # VectorDBClient implementation
├── findmcps.go            # findServersByEmbedding()
├── findtools.go           # generateEmbedding() + find-tools tool
└── dynamic_mcps.go        # mcp-find tool + decodeArguments()

cmd/docker-mcp/commands/
├── feature.go             # use-embeddings feature flag
└── gateway.go             # Feature check + client init
```

---

## Embeddings Client Lifecycle

```mermaid
stateDiagram-v2
    [*] --> Checking: Gateway starts
    Checking --> Disabled: Feature flag off
    Checking --> Disabled: No OPENAI_API_KEY
    Checking --> Initializing: Feature enabled + API key set
    Initializing --> Running: Docker container started
    Initializing --> Disabled: Init failed (logged warning)
    Running --> SearchVectors: find-tools called
    Running --> AddVector: Store embeddings
    Running --> ListCollections: Manage collections
    Running --> [*]: Gateway stops
    Disabled --> [*]: Gateway stops
```

---

## Data Flow: Semantic Search

```mermaid
flowchart LR
    A[User Query] --> B[Generate Embedding]
    B --> C[OpenAI API]
    C --> D[1536-dim Vector]
    D --> E[Search VectorDB]
    E --> F[Top K Results]
    F --> G[Extract Server Names]
    G --> H[Lookup in Catalog]
    H --> I[Return Server Info]
    style A fill:#e3f2fd
    style D fill:#fff3e0
    style F fill:#f3e5f5
    style I fill:#e8f5e9
```

---

## Benefits

✅ **Natural Language Search**
- "tools for github" → github server
- "database queries" → sqlite server

✅ **Better Discovery**
- Semantic matching vs exact keywords
- Handles synonyms and related concepts

✅ **Graceful Degradation**
- Falls back to keyword search if unavailable
- Gateway continues working without embeddings

✅ **Opt-in Feature**
- Disabled by default
- Requires explicit enablement + API key

---

## Testing & Validation

**Build:**
```bash
make docker-mcp
make lint
```

**Enable Feature:**
```bash
docker mcp feature enable use-embeddings
export OPENAI_API_KEY="sk-..."
docker mcp gateway run
```

**Test Search:**
```bash
# Via Claude Desktop or other MCP client
Find mcp tools that can help me ...
```

---

## Implementation Details

**Files Created:**
- `pkg/gateway/embeddings/client.go` (318 lines)
- `pkg/gateway/findmcps.go` (83 lines)

**Files Modified:**
- `pkg/gateway/dynamic_mcps.go` - Base64 decoding + mcp-find handler
- `pkg/gateway/findtools.go` - Embedding generation
- `pkg/gateway/run.go` - Client initialization
- `pkg/gateway/config.go` - UseEmbeddings flag
- `cmd/docker-mcp/commands/feature.go` - Feature registration
- `cmd/docker-mcp/commands/gateway.go` - Feature check

---

## Future Enhancements

🔮 **Possible Improvements:**
- distribute embeddings with catalogs
- Support other embedding models and providers
- Automatic reindexing on catalog changes

---

## Summary

✨ **What We Built:**
- sqlite-vec integration
- LLM embeddings integration
- Semantic search for MCP servers

🎯 **Impact:**
- Better server/tool discovery
- Natural language queries
- Foundation for AI-powered gateway

---

## Questions?

**Documentation:**
- Feature flags: `docker mcp feature ls`
- sqlite-vec service image: `jimclark106/vector-db:latest`
- model: `text-embedding-3-small`

**Storage:**
- `~/.docker/mcp/vectors.db`
- `~/.docker/config.json` (feature flags)

**Code:**
- Branch: `slim/embeddings`
- Main files: `pkg/gateway/embeddings/`, `findmcps.go`

---

### Feature Specs Catalog Management Feature Spec (`docs/feature-specs/catalog-management/feature-spec.md`)

# User-Managed Catalogs Feature Specification

## Overview

Enable Docker MCP Gateway users to create, manage, and automatically use custom MCP server catalogs alongside the default Docker catalog, while maintaining backward compatibility with Docker Desktop.

## Background

### Current State
- **Docker Official Catalog**: Hardcoded catalog at `https://desktop.docker.com/mcp/catalog/v2/catalog.yaml`
- **Catalog Management System**: Full CRUD operations exist but are hidden and unused by gateway runtime
- **Multi-Catalog Gateway**: Infrastructure exists but defaults to Docker-only catalog
- **Docker Desktop**: Expects explicit catalog requests, doesn't auto-discover user catalogs

### Problem Statement
Users can create and manage custom catalogs using hidden commands (`create`, `add`, `import`, `fork`, `rm`), but the gateway runtime ignores these catalogs and only uses the hardcoded Docker catalog. This forces users to manually specify catalog paths via CLI flags for every gateway run.

## Goals

### Primary Goals
1. **Enable User-Managed Catalogs**: Allow users to create custom catalogs that automatically work with the gateway
2. **Maintain Docker Desktop Compatibility**: Ensure existing Docker Desktop integration remains unchanged
3. **Progressive Enhancement**: Provide opt-in feature activation with safe defaults
4. **Unified User Experience**: Eliminate the need for manual `--catalog` flags in typical usage

### Secondary Goals
1. **Discoverability**: Make catalog management commands visible to users
2. **Clear Precedence**: Define predictable catalog merge behavior when servers conflict
3. **Comprehensive Logging**: Provide visibility into catalog loading and conflicts
4. **Container Support**: Ensure feature works in containerized deployments

## User Stories

### US1: Local Development Workflow
**As a developer**, I want to create a custom catalog for my development MCP servers so that I can easily switch between development and production gateway configurations.

```bash
# Setup once
docker mcp feature enable configured-catalogs
docker mcp catalog create dev-servers
docker mcp catalog add dev-servers local-db ./local-db-server.yaml
docker mcp catalog add dev-servers test-api ./test-api-server.yaml

# Daily usage - custom servers automatically available
docker mcp gateway run --use-configured-catalogs
docker mcp tools enable local-db-query
```

### US2: Team Shared Catalogs
**As a team lead**, I want to import our team's shared catalog so that all team members have access to our custom MCP servers without manual configuration.

```bash
# One-time setup
docker mcp feature enable configured-catalogs
docker mcp catalog import https://internal.company.com/mcp/team-catalog.yaml

# Ongoing usage - team servers automatically available
docker mcp gateway run --use-configured-catalogs
```

### US3: Production Server Management
**As a DevOps engineer**, I want to combine official Docker servers with our production-specific servers in a single gateway instance.

```bash
# Production setup
docker mcp catalog create prod-monitoring  
docker mcp catalog add prod-monitoring datadog ./datadog-mcp.yaml
docker mcp catalog add prod-monitoring pagerduty ./pagerduty-mcp.yaml

# Gateway includes Docker + production servers automatically
docker mcp gateway run --use-configured-catalogs
```

### US4: Catalog Sharing and Backup
**As a team member**, I want to export my custom catalog configuration so I can share it with teammates or backup my configuration.

```bash
# Export custom catalog to share with team
docker mcp catalog export my-servers ./team-servers.yaml

# Team member imports the shared catalog
docker mcp catalog import ./team-servers.yaml

# Cannot export Docker's official catalog (protected)
docker mcp catalog export docker-mcp ./backup.yaml
# Error: Cannot export official Docker catalog 'docker-mcp'
```

### US5: Quick Start with Examples
**As a new user**, I want to easily understand the catalog format and get started with custom catalogs by having examples based on Docker's official servers.

```bash
# Create a starter catalog file with Docker Hub and Docker CLI as examples
docker mcp catalog bootstrap ./my-starter-catalog.yaml

# File contains properly formatted Docker and DockerHub entries as reference
# User can modify file to add their own servers
# Then import or use as source for other commands

docker mcp catalog import ./my-starter-catalog.yaml
# OR
docker mcp catalog add existing-catalog my-server ./my-starter-catalog.yaml
```

### US6: Docker Desktop Compatibility
**As a Docker Desktop user**, I want the existing catalog functionality to continue working without any changes to my workflow.

```bash
# This continues to work exactly as before - no user catalogs included
docker mcp gateway run

# Docker Desktop continues to request specific catalogs explicitly
# (Internal: docker mcp catalog show docker-mcp --format=json)
```

## Technical Requirements

### Functional Requirements

#### FR1: Feature Flag System
- **Feature Name**: `configured-catalogs`
- **Storage**: `~/.docker/config.json` in `features` object
- **Activation**: `docker mcp feature enable configured-catalogs`
- **Validation**: Gateway commands validate feature enablement before using configured catalogs

#### FR2: Gateway Integration  
- **New Flag**: `--use-configured-catalogs` for `docker mcp gateway run`
- **Behavior**: When enabled, includes user-managed catalogs from `~/.docker/mcp/catalog.json`
- **Fallback**: If configuration loading fails, continues with Docker catalog only
- **Logging**: Comprehensive logging of catalog loading and server conflicts

#### FR3: Catalog Precedence Order
When multiple catalogs contain the same server name, **last loaded wins**:

1. **Built-in Gateway catalogs** (future expansion point)
2. **Docker official catalog** (`docker-mcp.yaml`) 
3. **User configured catalogs** (from catalog management system) *[if `--use-configured-catalogs`]*
4. **CLI-specified catalogs** (`--catalog` and `--additional-catalog` flags)

#### FR4: Command Visibility
- **Unhide Commands**: Remove `Hidden: true` from catalog CRUD commands
- **New Export Command**: Add `export <catalog-name> [output-file]` command for user-managed catalogs
- **Documentation**: Update command help text to reference feature flag requirement
- **Discovery**: `docker mcp catalog --help` shows all available commands

#### FR5: Configuration Access
- **Plugin Mode**: Full access to `dockerCli.ConfigFile().Features`
- **Standalone Mode**: Same access pattern via Docker CLI infrastructure  
- **Container Mode**: Graceful degradation when config not mounted
- **Error Handling**: Clear messages when config inaccessible

### Non-Functional Requirements

#### NFR1: Backward Compatibility
- **Docker Desktop**: Zero changes to existing behavior when feature not enabled
- **CLI Compatibility**: All existing flags and commands work identically
- **Default Behavior**: `docker mcp gateway run` remains unchanged
- **Migration**: No existing configurations require updates

#### NFR2: Performance
- **Catalog Loading**: Minimal overhead when loading multiple catalogs
- **Conflict Resolution**: Efficient server deduplication across catalogs  
- **Startup Time**: Feature flag validation adds <50ms to command startup
- **Memory Usage**: Catalog merging uses reasonable memory footprint

#### NFR3: Security
- **Feature Isolation**: Disabled feature cannot access user catalogs
- **Config Validation**: Validate catalog URLs and file paths for safety
- **Access Control**: Respect Docker configuration directory permissions
- **Container Safety**: No privilege escalation in container mode

#### NFR4: Usability
- **Error Messages**: Clear, actionable error messages with exact commands to run  
- **Documentation**: Feature flag requirement clearly documented
- **Discoverability**: Users can discover catalog management without external documentation
- **Logging**: Gateway startup logs indicate which catalogs are active

## Technical Design

### Architecture Overview

```
Docker Desktop (unchanged)
├── docker mcp catalog show docker-mcp --format=json
└── docker mcp gateway run (Docker catalog only)

Manual CLI Usage (new capability)
├── docker mcp feature enable configured-catalogs  
├── docker mcp catalog create/add/import (now visible)
├── docker mcp gateway run --use-configured-catalogs
└── Automatic: Docker + User catalogs merged
```

### Implementation Components

#### 1. Feature Management Commands

**New Commands**:
```bash
docker mcp feature enable configured-catalogs   # Set features.configured-catalogs=enabled
docker mcp feature disable configured-catalogs  # Set features.configured-catalogs=disabled  
docker mcp feature list                         # Show all feature flags and status
```

**Implementation**: New `cmd/docker-mcp/commands/feature.go`

#### 2. Bootstrap Command (New)

**New Command**: `docker mcp catalog bootstrap <output-file-path>`

**Purpose**: Create a starter catalog file with Docker and Docker Hub server entries as examples, making it easy for users to understand the catalog format and quickly get started with custom catalogs.

**Behavior**:
- Extracts `dockerhub` and `docker` server entries from live Docker catalog
- Creates a properly formatted YAML catalog file at specified path
- File is standalone (not automatically imported) - ready for user modification
- Provides real working examples of catalog server definitions

**Usage Examples**:
```bash
# Create starter catalog with Docker examples
docker mcp catalog bootstrap ./my-starter-catalog.yaml

# Output file contains:
# registry:
#   dockerhub:
#     description: "Docker Hub official MCP server."
#     title: "Docker Hub"
#     image: "mcp/dockerhub@sha256:..."
#     tools: [...]
#     # ... complete server definition
#   docker:
#     description: "Use the Docker CLI."
#     title: "Docker"  
#     type: "poci"
#     # ... complete server definition

# User can then modify and import
docker mcp catalog import ./my-starter-catalog.yaml

# Or use as source for copying specific servers
docker mcp catalog add my-catalog docker-hub ./my-starter-catalog.yaml
```

**Implementation Strategy**:
1. **Config Loading**: Call `ReadConfigWithDefaultCatalog(ctx)` to load Docker catalog config
2. **YAML Reading**: Call `ReadCatalogFile("docker-mcp")` to get raw catalog YAML
3. **Struct Parsing**: Unmarshal YAML to `Registry` struct for Go data access
4. **Server Extraction**: Extract `registry.Registry["dockerhub"]` and `registry.Registry["docker"]` entries
5. **Bootstrap Generation**: Create new `Registry` struct with only extracted servers
6. **YAML Output**: Marshal to YAML and write standalone catalog file

**Error Handling**:
- Validate output path is writable
- Handle Docker catalog access failures gracefully
- Provide overwrite protection/confirmation for existing files

**Implementation**: New `cmd/docker-mcp/commands/bootstrap.go` and `cmd/docker-mcp/catalog/bootstrap.go`

#### 3. Gateway Command Enhancement

**Modified Command**: `docker mcp gateway run`

**New Flag**: `--use-configured-catalogs`

**Validation Logic**:
```go
func validateConfiguredCatalogsFeature(dockerCli command.Cli, useConfigured bool) error {
    if !useConfigured {
        return nil // No validation when feature not requested
    }
    
    featuresMap := dockerCli.ConfigFile().Features
    if v, ok := featuresMap["configured-catalogs"]; ok {
        if enabled, err := strconv.ParseBool(v); err == nil && enabled {
            return nil // Feature enabled
        }
    }
    
    return fmt.Errorf(`configured catalogs feature is not enabled.

To enable this experimental feature, run:
  docker mcp feature enable configured-catalogs

This feature allows the gateway to automatically include user-managed catalogs
alongside the default Docker catalog.`)
}
```

#### 3. Catalog Loading Enhancement

**Modified Function**: `cmd/docker-mcp/catalog/catalog.go:Get()`

**Current**:
```go
func Get(ctx context.Context) (Catalog, error) {
    return ReadFrom(ctx, []string{"docker-mcp.yaml"})
}
```

**New**:
```go  
func Get(ctx context.Context, useConfigured bool, additionalCatalogs []string) (Catalog, error) {
    var catalogSources []string
    
    // 1. Future: Built-in catalogs
    // catalogSources = append(catalogSources, getBuiltinCatalogs()...)
    
    // 2. Docker official catalog (always included)
    catalogSources = append(catalogSources, "docker-mcp.yaml")
    
    // 3. User configured catalogs (only if feature enabled)
    if useConfigured {
        configuredCatalogs, err := getConfiguredCatalogs()
        if err != nil {
            log.Printf("Warning: failed to load configured catalogs: %v", err)
        } else {
            catalogSources = append(catalogSources, configuredCatalogs...)
        }
    }
    
    // 4. CLI-specified additional catalogs  
    catalogSources = append(catalogSources, additionalCatalogs...)
    
    return ReadFrom(ctx, catalogSources)
}

func getConfiguredCatalogs() ([]string, error) {
    cfg, err := catalogConfig.ReadConfig() // Read ~/.docker/mcp/catalog.json
    if err != nil {
        return nil, err
    }
    
    var catalogFiles []string
    for name := range cfg.Catalogs {
        catalogFiles = append(catalogFiles, name + ".yaml")
    }
    return catalogFiles, nil  
}
```

#### 4. Enhanced Conflict Resolution

**Modified Function**: `cmd/docker-mcp/catalog/catalog.go:ReadFrom()`

**Enhanced Logging**:
```go
func ReadFrom(ctx context.Context, fileOrURLs []string) (Catalog, error) {
    mergedServers := map[string]Server{}
    catalogSources := make(map[string]string) // server -> source catalog

    log.Printf("Loading %d catalogs in precedence order", len(fileOrURLs))
    
    for i, fileOrURL := range fileOrURLs {
        log.Printf("Loading catalog %d/%d: %s", i+1, len(fileOrURLs), fileOrURL)
        
        servers, err := readMCPServers(ctx, fileOrURL)
        if err != nil {
            log.Printf("Warning: failed to load catalog '%s': %v", fileOrURL, err)
            continue
        }

        for serverName, server := range servers {
            if existingSource, exists := catalogSources[serverName]; exists {
                log.Printf("SERVER OVERRIDE: '%s' from '%s' replaces version from '%s'", 
                    serverName, fileOrURL, existingSource)
            } else {
                log.Printf("SERVER ADDED: '%s' from '%s'", serverName, fileOrURL)
            }
            
            mergedServers[serverName] = server
            catalogSources[serverName] = fileOrURL
        }
    }

    log.Printf("Final catalog contains %d servers from %d catalogs", 
        len(mergedServers), len(fileOrURLs))

    return Catalog{Servers: mergedServers}, nil
}
```

#### 5. Export Command Implementation

**New Command**: `docker mcp catalog export <catalog-name> [output-file]`

**Purpose**: Export user-managed catalogs to files for sharing, backup, or migration.

**Implementation**: New `cmd/docker-mcp/catalog/export.go`

**Key Features**:
```go
func exportCatalog(ctx context.Context, catalogName, outputFile string) error {
    // 1. Validate catalog exists and is user-managed
    if catalogName == "docker-mcp" || catalogName == DockerCatalogName {
        return fmt.Errorf("cannot export official Docker catalog '%s'", catalogName)
    }
    
    // 2. Read catalog from ~/.docker/mcp/catalogs/{catalogName}.yaml
    catalogPath, err := catalogConfig.FilePath(fmt.Sprintf("catalogs/%s.yaml", catalogName))
    if err != nil {
        return err
    }
    
    catalogData, err := os.ReadFile(catalogPath)
    if err != nil {
        return fmt.Errorf("catalog '%s' not found", catalogName)
    }
    
    // 3. Default output file if not specified
    if outputFile == "" {
        outputFile = fmt.Sprintf("./%s.yaml", catalogName)
    }
    
    // 4. Write to output file
    return os.WriteFile(outputFile, catalogData, 0644)
}
```

**Protection Logic**:
- **Official Catalog Protection**: Prevent export of `docker-mcp` catalog
- **User Catalog Only**: Only export catalogs that exist in `~/.docker/mcp/catalogs/`
- **File Validation**: Ensure target catalog exists before attempting export

**Usage Examples**:
```bash
# Export to default filename (my-servers.yaml)
docker mcp catalog export my-servers

# Export to specific file
docker mcp catalog export my-servers ./shared/team-catalog.yaml

# Export for backup
docker mcp catalog export prod-monitoring ./backups/prod-$(date +%Y%m%d).yaml
```

#### 6. Command Visibility Updates

**Modified Files**: All catalog command files in `cmd/docker-mcp/catalog/`

**Changes**: Remove `Hidden: true` from:
- `import.go` - Import catalogs from URLs/files
- `export.go` - Export user catalogs to files (new command)
- `create.go` - Create empty local catalogs  
- `add.go` - Add servers to catalogs
- `fork.go` - Duplicate existing catalogs
- `rm.go` - Remove catalogs

**Enhanced Help Text**: Reference feature flag requirement in command descriptions.

### Container Mode Support

**Volume Mount Requirement**:
```bash
# For feature flags to work in container mode
docker run -v ~/.docker:/root/.docker docker/mcp-gateway gateway run --use-configured-catalogs

# Or mount just the config
docker run -v ~/.docker/config.json:/root/.docker/config.json docker/mcp-gateway gateway run --use-configured-catalogs
```

**Enhanced Error Handling**:
```go
func validateConfiguredCatalogsFeature(dockerCli command.Cli, useConfigured bool) error {
    if !useConfigured {
        return nil
    }
    
    configFile := dockerCli.ConfigFile()
    if configFile == nil {
        return fmt.Errorf(`Docker configuration not accessible.

If running in container, mount Docker config:
  -v ~/.docker:/root/.docker
  
Or mount just the config file:  
  -v ~/.docker/config.json:/root/.docker/config.json`)
    }
    
    // Continue with feature validation...
}
```

## Testing Strategy

### Unit Tests

#### Test Coverage Areas
1. **Feature Flag Validation**: Test enabled/disabled/missing scenarios
2. **Catalog Loading**: Test precedence order and conflict resolution  
3. **Error Handling**: Test config inaccessible, malformed catalogs
4. **Container Mode**: Test behavior without volume mounts

#### Key Test Cases
```go
func TestCatalogPrecedenceOrder(t *testing.T) {
    // Test that CLI catalogs override configured catalogs override Docker catalog
}

func TestFeatureFlagValidation(t *testing.T) {
    // Test feature flag validation in various states
}

func TestContainerModeGracefulDegradation(t *testing.T) {
    // Test behavior when Docker config is inaccessible
}
```

### Integration Tests

#### Test Scenarios
1. **End-to-End Workflow**: Create catalog → Add server → Enable feature → Run gateway → Verify server availability
2. **Docker Desktop Compatibility**: Verify existing workflows unchanged
3. **Multi-Catalog Conflicts**: Test server override behavior across catalogs
4. **Feature Flag Lifecycle**: Enable → Use → Disable → Verify disabled

#### Test Environment
- **Docker Desktop**: Verify no regression in existing behavior
- **Standalone Binary**: Verify feature works in standalone mode  
- **Container**: Verify graceful degradation without volume mounts

## Migration Strategy

### Phase 1: Implementation (No Breaking Changes)
1. **Add Feature Management**: Implement `docker mcp feature` commands
2. **Enhance Gateway**: Add `--use-configured-catalogs` flag with validation
3. **Update Catalog Loading**: Implement precedence-based catalog merging
4. **Unhide Commands**: Make catalog CRUD commands visible
5. **Comprehensive Testing**: Unit and integration test coverage

### Phase 2: Documentation and User Communication
1. **User Documentation**: Update CLI reference and tutorials
2. **Migration Guide**: Document feature enablement and workflows
3. **Release Notes**: Highlight new capability and backward compatibility
4. **Community Communication**: Blog post explaining enhanced catalog management

### Phase 3: Future Enhancements (Optional)
1. **Docker Desktop Integration**: UI for managing custom catalogs
2. **Catalog Signing**: Implement signature verification for remote catalogs
3. **Default Feature**: Consider making configured catalogs default in future major version
4. **Well-Known Catalogs**: Add community catalog aliases

## Risk Assessment

### High-Impact Risks

#### Risk: Docker Desktop Regression
- **Probability**: Low
- **Impact**: High
- **Mitigation**: Extensive testing, feature flag gating, unchanged default behavior

#### Risk: Configuration Corruption  
- **Probability**: Low
- **Impact**: Medium
- **Mitigation**: Atomic config updates, backup/restore commands, validation

### Medium-Impact Risks

#### Risk: Performance Degradation
- **Probability**: Low  
- **Impact**: Medium
- **Mitigation**: Efficient catalog loading, caching, performance testing

#### Risk: User Confusion
- **Probability**: Medium
- **Impact**: Low
- **Mitigation**: Clear error messages, comprehensive documentation, progressive disclosure

### Low-Impact Risks

#### Risk: Container Mode Limitations
- **Probability**: Medium
- **Impact**: Low  
- **Mitigation**: Clear documentation, graceful degradation, helpful error messages

## Success Metrics

### User Adoption
- **Feature Enablement**: Track `configured-catalogs` feature activation
- **Command Usage**: Monitor usage of previously hidden catalog commands
- **Gateway Usage**: Track `--use-configured-catalogs` flag adoption

### Technical Metrics  
- **Performance**: Gateway startup time with multiple catalogs
- **Reliability**: Error rates when loading configured catalogs
- **Compatibility**: Docker Desktop integration regression testing results

### User Experience
- **Support Requests**: Reduction in catalog-related support questions
- **Documentation Engagement**: Usage of new catalog management documentation
- **Community Feedback**: User satisfaction with enhanced catalog workflow

## Open Questions

1. **Default Behavior**: Should configured catalogs eventually become the default (breaking change)?
2. **Catalog Validation**: What level of validation should be applied to imported catalogs?
3. **Performance Optimization**: Should catalog loading be cached between gateway runs?
4. **Docker Desktop UI**: When should Docker Desktop add catalog management UI?

## Conclusion

This feature specification provides a comprehensive, backward-compatible enhancement to MCP Gateway catalog management. By using Docker CLI's existing feature flag system and maintaining strict compatibility with Docker Desktop, users gain powerful catalog management capabilities while ensuring existing workflows remain unchanged.

The implementation leverages existing infrastructure (Jim Clark's multi-catalog support, David Gageot's catalog management system) to provide a complete solution with minimal risk and maximum user value.

---

### Feature Specs Catalog Management Implementation Checklist (`docs/feature-specs/catalog-management/implementation-checklist.md`)

# User-Managed Catalogs Implementation Checklist

## Project Status: ✅ PHASE 1 & 2 COMPLETE - PRODUCTION READY

**Last Updated**: August 1, 2025  
**Feature Spec**: [feature-spec.md](./feature-spec.md)  
**Investigation Notes**: `/Users/masegraye/dev/docker/id-writing/scratch/mcp-gateway-investigation.md`

### 🎉 Implementation Summary
All Phase 1 & 2 implementation work has been **completed and tested**:
- ✅ **Feature Management System**: Full TDD implementation with 8 test cases
- ✅ **Gateway Enhancement**: Complete flag integration with 5 test cases  
- ✅ **Catalog Loading**: Multi-catalog support with 6 test cases
- ✅ **Export Command**: New functionality with 4 test cases
- ✅ **Bootstrap Command**: New quick-start functionality with 4 test cases
- ✅ **Command Visibility**: All CRUD commands now user-accessible
- ✅ **Container Test Suite**: All tests pass in Docker container environment
- ✅ **Binary Build**: Successful compilation and CLI plugin installation
- ✅ **End-to-End Workflow**: Complete bootstrap → add → export validation

## Development Workflow & TDD Instructions

### Essential Commands for Development

All commands should be run from `/Users/masegraye/dev/docker/workspaces/catalog-management/mcp-gateway/`:

```bash
# Scoped Test-Driven Development Cycle
go test ./cmd/docker-mcp/commands           # Test specific package (fastest)
go test ./cmd/docker-mcp/...               # Test cmd tree (medium scope)
make test                                   # Test entire system (broadest scope)
make docker-mcp                            # Build and install binary (only after tests pass)
make lint-darwin                           # Run linting (only when implementation complete)

# Manual testing commands
./dist/docker-mcp --help                    # Verify binary works
./dist/docker-mcp catalog --help           # Check catalog commands
./dist/docker-mcp gateway run --help       # Check gateway flags
```

### TDD Development Process

**CRITICAL**: Follow this exact workflow with progressively broader scope:

#### 1. Red Phase - Write Failing Tests First
```bash
# Test just the specific package you're working on
go test ./cmd/docker-mcp/commands    # Example: testing feature commands
# Should show failing tests for new functionality
```

#### 2. Green Phase - Make Tests Pass
```bash
# Write minimal implementation to make tests pass
go test ./cmd/docker-mcp/commands    # Test same package again
# Should show all tests passing in that package
```

#### 3. Package Integration Test
```bash
# Test all related packages together
go test ./cmd/docker-mcp/...         # Test entire cmd tree
# Should show all tests passing across packages
```

#### 4. Full System Test
```bash
# Test the entire system
make test
# Should show all tests passing system-wide
```

#### 5. Build Phase - Verify Compilation
```bash
# Only build after all tests pass
make docker-mcp
# Should build successfully and install to ~/.docker/cli-plugins/docker-mcp
```

#### 6. Manual Verification
```bash
# Test the actual CLI functionality
./dist/docker-mcp [your-new-command] --help
# Verify your changes work as expected
```

#### 7. Refactor Phase (Optional)
```bash
# Improve code while keeping tests green
go test ./path/to/package    # Test specific package after changes
```

#### 8. Lint Phase (End of Implementation Only)
```bash
# Only run linting when feature is complete
make lint-darwin
# Should show 0 issues
```

### Test Categories & Strategy

#### Unit Tests (Primary Focus)
- **Location**: Tests should be in `*_test.go` files alongside implementation
- **Speed**: Fast (< 1 second per test file)
- **Focus**: Individual function/method behavior
- **Run Command**: `make test`

#### Integration Tests (Secondary)
- **Location**: `cmd/docker-mcp/integration_test.go` and similar
- **Speed**: Slower (requires Docker daemon)
- **Focus**: End-to-end command workflows
- **Note**: Some are skipped in normal `make test` runs

#### Manual Tests (Verification)
- **Purpose**: Verify CLI behavior matches expectations
- **When**: After successful build, before marking tasks complete
- **Focus**: User experience and error messages

### Implementation Guidelines

1. **Test First**: Always write tests before implementation
2. **Small Steps**: Implement one small piece at a time
3. **Green Tests**: Never commit with failing tests
4. **Build Validation**: Only build after tests pass
5. **Manual Check**: Always verify CLI behavior manually
6. **Lint Last**: Only run linting when implementation is complete

### Error Handling Strategy

#### Test Failures
```bash
make test
# If tests fail, fix the code, don't skip tests
```

#### Build Failures
```bash
make docker-mcp
# If build fails, check compilation errors and fix
# Don't proceed to manual testing until build succeeds
```

#### Lint Failures (End of Development)
```bash
make lint-darwin
# Fix all linting issues before marking feature complete
```

### Baseline Verification ✅

The following baseline tests have been verified to work:
- `make docker-mcp` - Builds successfully 
- `make test` - All existing tests pass
- `make lint-darwin` - 0 linting issues
- CLI functionality verified working

**Ready to begin TDD implementation following the above workflow.**

## 🧪 Test Strategy Overview

### Required Test Files for TDD Implementation

Each implementation section below specifies **TEST FIRST** requirements. These test files must be created with failing tests before writing implementation code:

| Component | Test File | Purpose |
|-----------|-----------|---------|
| Feature Management | `cmd/docker-mcp/commands/feature_test.go` | Test feature enable/disable/list commands |
| Gateway Enhancement | `cmd/docker-mcp/commands/gateway_test.go` | Test --use-configured-catalogs flag validation |
| Catalog Loading | `cmd/docker-mcp/internal/catalog/catalog_test.go` | Test catalog precedence and loading logic |
| Export Command | `cmd/docker-mcp/catalog/export_test.go` | Test export functionality and protection |
| Command Visibility | `cmd/docker-mcp/catalog/*_test.go` | Test unhidden commands appear in help |

### Test-First Workflow Reminder

```bash
# 1. Write failing tests first
go test ./cmd/docker-mcp/commands -v  # Should show failing tests

# 2. Write minimal implementation  
go test ./cmd/docker-mcp/commands -v  # Should show passing tests

# 3. Test broader scope
go test ./cmd/docker-mcp/... -v      # Should show all integration tests pass

# 4. Test full system
make test                            # Should show all system tests pass

# 5. Build and verify
make docker-mcp                      # Should build successfully
```

## Quick Context for Claude Code Sessions

### What This Feature Does
Enable users to create and manage custom MCP server catalogs that automatically work with the gateway runtime, while maintaining backward compatibility with Docker Desktop through feature flag gating.

### Current Architecture Status
- ✅ **Catalog CRUD System**: Fully implemented by David Gageot (June-July 2025)
- ✅ **Multi-Catalog Gateway**: Implemented by Jim Clark (July 21, 2025) 
- ✅ **Infrastructure**: All underlying systems exist and work
- ❌ **Integration Gap**: Gateway runtime ignores catalog management system
- ❌ **User Discovery**: Catalog management commands are hidden

### Implementation Strategy
**Feature Flag Approach**: Use Docker CLI's existing `features` config system to gate new functionality, ensuring Docker Desktop compatibility.

## Implementation Checklist

### Phase 1: Core Implementation ✅ COMPLETED

#### 1.1 Feature Management System ✅ COMPLETED

**🧪 TEST FIRST**: `cmd/docker-mcp/commands/feature_test.go` ✅ COMPLETED
- [x] **Write tests for feature command structure**
  ```go
  // Test cases implemented:
  func TestFeatureEnableCommand(t *testing.T)     // ✅ Test enabling configured-catalogs
  func TestFeatureDisableCommand(t *testing.T)    // ✅ Test disabling configured-catalogs  
  func TestFeatureListCommand(t *testing.T)       // ✅ Test listing all features and status
  func TestFeatureInvalidFeature(t *testing.T)    // ✅ Test error for unknown feature names
  ```

- [x] **Create feature command structure** ✅ COMPLETED
  - [x] File: `cmd/docker-mcp/commands/feature.go`
  - [x] Commands: `enable <feature>`, `disable <feature>`, `list`
  - [x] Target: `~/.docker/config.json` → `features.configured-catalogs`

**🧪 TEST FIRST**: `cmd/docker-mcp/commands/feature_test.go` (validation utilities) ✅ COMPLETED
- [x] **Write tests for feature validation utilities**
  ```go
  // Test cases implemented:
  func TestIsFeatureEnabledTrue(t *testing.T)       // ✅ Test when feature is enabled
  func TestIsFeatureEnabledFalse(t *testing.T)      // ✅ Test when feature is disabled
  func TestIsFeatureEnabledMissing(t *testing.T)    // ✅ Test when config missing
  func TestIsFeatureEnabledCorrupt(t *testing.T)    // ✅ Test when config corrupted
  ```

- [x] **Feature validation utilities** ✅ COMPLETED
  - [x] Function: `isFeatureEnabled(dockerCli command.Cli, feature string) bool`
  - [x] Handle missing config file gracefully
  - [x] Support container mode detection

- [x] **Integration with root command** ✅ COMPLETED
  - [x] Add feature command to `cmd/docker-mcp/commands/root.go`
  - [x] Ensure proper dockerCli context passing

#### 1.2 Gateway Command Enhancement ✅ COMPLETED

**🧪 TEST FIRST**: `cmd/docker-mcp/commands/gateway_test.go` ✅ COMPLETED
- [x] **Write tests for gateway flag validation**
  ```go
  // Test cases implemented:
  func TestGatewayUseConfiguredCatalogsEnabled(t *testing.T)   // ✅ Test flag works when feature enabled
  func TestGatewayUseConfiguredCatalogsDisabled(t *testing.T)  // ✅ Test flag fails when feature disabled
  func TestGatewayFeatureFlagErrorMessage(t *testing.T)        // ✅ Test error message clarity
  func TestGatewayContainerModeDetection(t *testing.T)         // ✅ Test container mode handling
  func TestGatewayNoValidationWhenFlagNotUsed(t *testing.T)    // ✅ Test no validation when flag not used
  ```

- [x] **Add --use-configured-catalogs flag** ✅ COMPLETED
  - [x] File: `cmd/docker-mcp/commands/gateway.go`
  - [x] Flag: `--use-configured-catalogs` (boolean)
  - [x] Validation: Check feature flag before allowing flag usage

- [x] **Feature validation integration** ✅ COMPLETED
  - [x] PreRunE validation for feature flag requirement
  - [x] Clear error messages with exact enable command
  - [x] Container mode detection and helpful errors

- [x] **Pass flag to catalog system** ✅ COMPLETED
  - [x] Update `catalog.Get()` call site
  - [x] Pass useConfigured boolean parameter

#### 1.3 Catalog Loading Enhancement ✅ COMPLETED

**🧪 TEST FIRST**: `cmd/docker-mcp/internal/catalog/catalog_test.go` ✅ COMPLETED
- [x] **Write tests for catalog loading logic**
  ```go
  // Test cases implemented:
  func TestCatalogGetWithConfigured(t *testing.T)         // ✅ Test loading configured catalogs
  func TestCatalogGetWithoutConfigured(t *testing.T)      // ✅ Test default behavior unchanged
  func TestGetConfiguredCatalogsSuccess(t *testing.T)     // ✅ Test reading catalog.json
  func TestGetConfiguredCatalogsMissing(t *testing.T)     // ✅ Test missing catalog.json
  func TestGetConfiguredCatalogsCorrupt(t *testing.T)     // ✅ Test corrupted catalog.json
  func TestCatalogPrecedenceOrder(t *testing.T)           // ✅ Test Docker → Configured → CLI order
  ```

- [x] **Update catalog.Get() signature** ✅ COMPLETED  
  - [x] File: `cmd/docker-mcp/internal/catalog/catalog.go`
  - [x] New function: `GetWithOptions(ctx context.Context, useConfigured bool, additionalCatalogs []string) (Catalog, error)`
  - [x] Backward compatibility: Keep current `Get()` for existing callers

- [x] **Implement getConfiguredCatalogs()** ✅ COMPLETED
  - [x] Read from `~/.docker/mcp/catalog.json`
  - [x] Return list of catalog file names
  - [x] Handle missing/corrupted catalog registry gracefully

- [x] **Implement catalog precedence logic** ✅ COMPLETED
  - [x] Order: Docker → Configured → CLI-specified
  - [x] Use existing `ReadFrom()` function with ordered list
  - [x] Comprehensive logging of loading process with warnings

#### 1.4 Enhanced Conflict Resolution & Logging ✅ COMPLETED

**🧪 TEST FIRST**: `cmd/docker-mcp/internal/catalog/catalog_test.go` (conflict resolution) ✅ COMPLETED
- [x] **Write tests for conflict resolution**
  ```go
  // Test cases implemented:
  func TestCatalogPrecedenceOrder(t *testing.T)     // ✅ Test server-level precedence (architecturally correct)
  // Additional conflict resolution validated through existing ReadFrom() behavior
  ```

- [x] **Validate ReadFrom() logging** ✅ COMPLETED
  - [x] File: `cmd/docker-mcp/internal/catalog/catalog.go`
  - [x] Existing warning messages for server conflicts confirmed working
  - [x] Server-level precedence correctly implemented

- [x] **Server conflict handling** ✅ COMPLETED
  - [x] Confirmed server-level replacement prevents tool mixing issues
  - [x] "Last wins" precedence behavior validated as architecturally correct
  - [x] Gateway tool flattening works properly with resolved servers

#### 1.5 Export Command Implementation ✅ COMPLETED

**🧪 TEST FIRST**: `cmd/docker-mcp/commands/export_test.go` ✅ COMPLETED
- [x] **Write tests for export command**
  ```go
  // Test cases implemented:
  func TestExportCatalogCommand(t *testing.T)           // ✅ Test successful export
  func TestExportDockerCatalogShouldFail(t *testing.T)  // ✅ Test docker-mcp protection
  func TestExportNonExistentCatalog(t *testing.T)       // ✅ Test missing catalog error
  func TestExportInvalidOutputPath(t *testing.T)        // ✅ Test file permission/path errors
  ```

- [x] **Create export command** ✅ COMPLETED
  - [x] File: `cmd/docker-mcp/catalog/export.go` (new)
  - [x] Command: `export <catalog-name> <file-path>`
  - [x] Protection: Prevent export of `docker-mcp` official catalog

- [x] **Export functionality** ✅ COMPLETED
  - [x] Read catalog from `~/.docker/mcp/catalogs/{name}.yaml`
  - [x] Validate catalog exists and is user-managed
  - [x] Support for custom output file path

- [x] **Error handling** ✅ COMPLETED
  - [x] Clear error for attempting to export official Docker catalog
  - [x] Helpful error when catalog doesn't exist
  - [x] File system permission error handling

#### 1.6 Command Visibility Updates ✅ COMPLETED

**🧪 TEST FIRST**: Command visibility validated through CLI help output ✅ COMPLETED
- [x] **Manual validation of command visibility**
  ```bash
  # All commands now visible in docker mcp catalog --help:
  # ✅ add         Add a server to your catalog
  # ✅ create      Create a new catalog
  # ✅ export      Export a configured catalog to a file
  # ✅ fork        Fork a catalog
  # ✅ import      Import a catalog
  # ✅ rm          Remove a catalog
  ```

- [x] **Unhide catalog CRUD commands** ✅ COMPLETED
  - [x] Files: `cmd/docker-mcp/commands/catalog.go`  
  - [x] Removed `Hidden: true` from all command definitions
  - [x] All catalog management commands now user-visible

- [x] **Update command descriptions** ✅ COMPLETED
  - [x] Export command includes clear protection messaging
  - [x] Help text explains user-managed vs Docker catalog distinction

### Phase 2: Testing & Validation ✅ COMPLETED

#### 2.1 Unit Tests ✅ COMPLETED

- [x] **Feature flag validation tests** ✅ COMPLETED
  - [x] Test enabled/disabled/missing scenarios (4 test cases)
  - [x] Test Docker CLI integration
  - [x] Test container mode behavior

- [x] **Catalog loading tests** ✅ COMPLETED  
  - [x] Test precedence order with multiple catalogs (6 test cases)
  - [x] Test conflict resolution logging with warning messages
  - [x] Test graceful failure handling for missing/corrupt registry

- [x] **Export command tests** ✅ COMPLETED
  - [x] Test successful export of user catalogs
  - [x] Test prevention of Docker catalog export
  - [x] Test catalog not found scenarios
  - [x] Test file permission error handling

- [x] **Gateway integration tests** ✅ COMPLETED
  - [x] Test flag validation (5 test cases)
  - [x] Test feature flag gating with clear error messages
  - [x] Test container mode detection and guidance

#### 2.2 Integration Tests ✅ COMPLETED

- [x] **End-to-end workflow tests** ✅ COMPLETED
  - [x] All test suites pass in container environment
  - [x] Binary builds and installs successfully as Docker CLI plugin
  - [x] All commands visible and functional in CLI help

- [x] **Docker Desktop compatibility tests** ✅ COMPLETED
  - [x] Verified `docker mcp gateway run` behavior unchanged (backward compatibility)
  - [x] Verified existing catalog commands work as expected
  - [x] No regression in Docker Desktop workflow

- [x] **Container mode tests** ✅ COMPLETED
  - [x] Tests pass in Docker container environment (`make test`)
  - [x] Feature flag validation works in container mode
  - [x] Clear error messages for missing config scenarios

#### 2.3 Manual Testing Scenarios ✅ COMPLETED

- [x] **Development workflow testing** ✅ COMPLETED
  - [x] Feature enable/disable cycle verified working
  - [x] All catalog commands now visible in `docker mcp catalog --help`
  - [x] Export command protection working correctly
  - [x] Binary installation to `~/.docker/cli-plugins/docker-mcp` successful

- [x] **Multi-catalog testing** ✅ COMPLETED
  - [x] Server-level precedence correctly implemented and tested
  - [x] Warning logging for overlapping servers verified working
  - [x] Architecture validated as correct for tool flattening

### Phase 2: Bootstrap Command Implementation

#### 2.1 Bootstrap Command Design ✅ COMPLETED

**Command Name**: `docker mcp catalog bootstrap <output-file-path>`

**Purpose**: Create a starter catalog file with Docker and Docker Hub server entries as examples, making it easy for users to understand the catalog format and get started with custom catalogs.

**🧪 TEST FIRST**: `cmd/docker-mcp/commands/bootstrap_test.go` ✅ COMPLETED
- [x] **Write tests for bootstrap command**
  ```go
  // Test cases implemented:
  func TestBootstrapCatalogCommand(t *testing.T)        // ✅ Test successful bootstrap creation
  func TestBootstrapExistingFile(t *testing.T)          // ✅ Test overwrite protection/confirmation
  func TestBootstrapInvalidPath(t *testing.T)           // ✅ Test invalid output path handling
  func TestBootstrapDockerEntriesExtraction(t *testing.T) // ✅ Test Docker/DockerHub entry extraction
  ```

**Implementation Strategy**:
1. **Config loading**: Call `ReadConfigWithDefaultCatalog(ctx)` to load Docker catalog
2. **YAML reading**: Call `ReadCatalogFile("docker-mcp")` to get raw catalog YAML  
3. **Struct parsing**: Unmarshal to `Registry` struct for Go data access
4. **Server extraction**: Extract `registry.Registry["dockerhub"]` and `registry.Registry["docker"]`
5. **Bootstrap generation**: Create new `Registry` with only extracted servers  
6. **File creation**: Marshal to YAML and write standalone catalog file

**Expected User Workflow**:
```bash
# Create bootstrap catalog with Docker examples
docker mcp catalog bootstrap ./my-custom-catalog.yaml

# User modifies the file to add their own servers
# User can then import it
docker mcp catalog import ./my-custom-catalog.yaml

# Or use it as source for adding individual servers
docker mcp catalog add existing-catalog my-server ./my-custom-catalog.yaml
```

**Implementation Tasks**: ✅ ALL COMPLETED
- [x] **Create bootstrap command** ✅ COMPLETED
  - [x] File: `cmd/docker-mcp/commands/bootstrap.go` (new)
  - [x] Command: `bootstrap <output-file-path>`
  - [x] Internal calls to `ReadConfigWithDefaultCatalog()` and `ReadCatalogFile()`

- [x] **Bootstrap functionality** ✅ COMPLETED  
  - [x] File: `cmd/docker-mcp/catalog/bootstrap.go` (new)
  - [x] Extract Docker and DockerHub entries from live catalog using YAML parsing
  - [x] Generate properly formatted YAML catalog structure with extracted servers
  - [x] File overwrite protection with clear error messages

- [x] **Error handling** ✅ COMPLETED
  - [x] Validate output path is writable with directory creation
  - [x] Handle Docker catalog access failures gracefully
  - [x] Clear error messages for file conflicts and missing servers

- [x] **Integration with catalog command** ✅ COMPLETED
  - [x] Added bootstrap command to `cmd/docker-mcp/commands/catalog.go`
  - [x] Comprehensive help text and examples
  - [x] Full CLI integration and visibility

**End-to-End Validation**: ✅ COMPLETED
- [x] **Bootstrap file creation**: Successfully creates YAML with Docker and DockerHub servers
- [x] **Catalog add integration**: Bootstrap file works as source for `catalog add` command
- [x] **Server extraction**: Individual servers can be copied from bootstrap file to catalogs
- [x] **Export roundtrip**: Full workflow (bootstrap → add → export) validated
- [x] **Real-world usage**: Tested with actual Docker catalog data and server definitions

### Phase 3: Documentation & Polish

#### 3.1 Documentation Updates

- [ ] **CLI reference updates**
  - [ ] Update generated docs for newly visible commands
  - [ ] Document feature flag requirement
  - [ ] Document new bootstrap command workflow
  - [ ] Provide usage examples

- [ ] **User workflow documentation**
  - [ ] Development workflow example including bootstrap
  - [ ] Production setup guide
  - [ ] Container deployment instructions

#### 3.2 Error Handling Polish

- [ ] **Comprehensive error messages**
  - [ ] Feature not enabled → exact enable command
  - [ ] Container mode → volume mount instructions  
  - [ ] Catalog loading failures → helpful diagnostics

- [ ] **Logging improvements**
  - [ ] Structured logging for catalog operations
  - [ ] Clear startup messages about active catalogs
  - [ ] Performance timing for catalog loading

### Phase 4: Advanced Features (Future)

#### 4.1 Performance Optimizations
- [ ] **Catalog caching**
  - [ ] Cache loaded catalogs between gateway runs
  - [ ] Invalidate cache on catalog updates
  - [ ] Performance benchmarking

#### 4.2 Enhanced Validation
- [ ] **Catalog URL validation**
  - [ ] HTTPS requirement for remote catalogs
  - [ ] URL safety validation
  - [ ] Optional signature verification

#### 4.3 Docker Desktop Integration
- [ ] **UI for catalog management**
  - [ ] List configured catalogs in Docker Desktop
  - [ ] Enable/disable specific catalogs
  - [ ] Import catalogs via UI

## Progress Tracking

### Completed Analysis Work ✅
- [x] **Architecture Investigation**: Complete understanding of existing systems
- [x] **Git Blame Analysis**: Identified key contributors and implementation timeline  
- [x] **Docker Desktop Integration**: Understood compatibility requirements
- [x] **Binary Distribution Analysis**: Confirmed feature flag system works across all modes
- [x] **Feature Flag Research**: Identified Docker CLI `features` system as perfect solution
- [x] **Implementation Planning**: Complete technical design and user workflows
- [x] **Feature Specification**: Comprehensive spec document created
- [x] **Risk Assessment**: Identified and mitigated major risks

### Current Status
**✅ PHASE 1 & 2 IMPLEMENTATION COMPLETE - PRODUCTION READY**

All Phase 1 & 2 implementation, testing, and validation work is **complete**. The feature is ready for production use with:

- **27 comprehensive test cases** covering all functionality (Phase 1: 23 tests, Phase 2: 4 tests)
- **Full TDD implementation** with test-first development methodology
- **Container environment validation** - all tests pass in `make test`
- **End-to-End workflow validation** - complete bootstrap → add → export tested
- **Backward compatibility** - no changes to existing Docker Desktop workflows  
- **Production-ready binary** - builds and installs successfully as Docker CLI plugin

**Key Achievements**: 
- Users can now enable `configured-catalogs` feature and use custom catalogs alongside Docker's official catalog with full CLI management capabilities
- New users can quickly get started with the `bootstrap` command to understand catalog format and create starter files with real Docker server examples

## Key Implementation Notes

### Critical Success Factors
1. **Maintain Docker Desktop Compatibility**: Never change default behavior of `docker mcp gateway run`
2. **Feature Flag Gating**: All new functionality MUST be gated behind `configured-catalogs` feature
3. **Graceful Degradation**: System must work properly when config is inaccessible
4. **Clear User Communication**: Error messages must provide exact commands to fix issues

### Technical Constraints  
1. **Backward Compatibility**: All existing command signatures and behaviors preserved
2. **Container Support**: Feature must work in container mode with proper volume mounts
3. **Performance**: Catalog loading must not significantly impact gateway startup time
4. **Security**: No privilege escalation or unsafe file operations

### Architecture Decisions Made
1. **Feature Flag System**: Use Docker CLI's existing `features` config approach
2. **Catalog Precedence**: Last-loaded-wins for server conflicts (Docker → Configured → CLI)
3. **Command Structure**: Add `--use-configured-catalogs` flag rather than change defaults
4. **Error Handling**: Fail-safe approach where config problems disable feature rather than break gateway

## File Locations Reference

### Implementation Target Files
- **Feature Commands**: `cmd/docker-mcp/commands/feature.go` (new)
- **Export Command**: `cmd/docker-mcp/catalog/export.go` (new)
- **Gateway Enhancement**: `cmd/docker-mcp/commands/gateway.go` 
- **Catalog Loading**: `cmd/docker-mcp/catalog/catalog.go`
- **Command Visibility**: `cmd/docker-mcp/catalog/{import,export,create,add,fork,rm}.go`

### Key Reference Files  
- **Command Structure**: `cmd/docker-mcp/commands/root.go`
- **Docker CLI Integration**: `cmd/docker-mcp/main.go:33-35`
- **Config Pattern**: `cli/cli/config/configfile/file.go:120` (Features map)
- **Storage Pattern**: `cmd/docker-mcp/internal/config/readwrite.go`

### Investigation Documentation
- **Detailed Investigation**: `/Users/masegraye/dev/docker/id-writing/scratch/mcp-gateway-investigation.md`
- **Feature Specification**: `docs/feature-specs/catalog-management/feature-spec.md`

## Contact Information

**Primary Technical Contact**: Jim Clark (@slimslenderslacks)
- Implemented multi-catalog gateway support (July 21, 2025)
- Best person to consult for architecture questions

**Secondary Contact**: David Gageot  
- Implemented catalog management system (June-July 2025)
- Expert on catalog CRUD operations and storage patterns

---

## Quick Start for New Claude Code Sessions

1. **Read the feature spec**: Start with `feature-spec.md` for complete context
2. **Check current status**: Review completed items in this checklist
3. **Start implementation**: Begin with Phase 1.1 (Feature Management System)
4. **Test thoroughly**: Each component must work in plugin, standalone, and container modes  
5. **Maintain compatibility**: Docker Desktop behavior must never change

**Key Commands to Validate Success**:
```bash
# Phase 1: Configured catalogs workflow
docker mcp feature enable configured-catalogs
docker mcp catalog create my-servers  
docker mcp catalog add my-servers test-server ./server.yaml
docker mcp catalog export my-servers ./backup.yaml
docker mcp gateway run --use-configured-catalogs
# Gateway should start with both Docker servers AND test-server available

# Phase 2: Bootstrap workflow for new users
docker mcp catalog bootstrap ./starter-catalog.yaml
# Creates file with Docker and DockerHub server examples
docker mcp catalog create custom-servers
docker mcp catalog add custom-servers dockerhub ./starter-catalog.yaml
# Copies Docker Hub server from bootstrap file to custom catalog

# Validate export protection
docker mcp catalog export docker-mcp ./should-fail.yaml
# Should fail with: "Cannot export official Docker catalog 'docker-mcp'"
```

---

### Generator Reference Mcp (`docs/generator/reference/mcp.md`)

# docker mcp


Manage MCP servers and clients

### Subcommands

| Name                        | Description                             |
|:----------------------------|:----------------------------------------|
| [`catalog`](mcp_catalog.md) | Manage MCP server catalogs              |
| [`client`](mcp_client.md)   | Manage MCP clients                      |
| [`config`](mcp_config.md)   | Manage the configuration                |
| [`feature`](mcp_feature.md) | Manage experimental features            |
| [`gateway`](mcp_gateway.md) | Manage the MCP Server gateway           |
| [`oauth`](mcp_oauth.md)     | Manage OAuth app authorizations         |
| [`secret`](mcp_secret.md)   | Manage secrets in the local OS Keychain |
| [`server`](mcp_server.md)   | Manage servers                          |
| [`tools`](mcp_tools.md)     | Manage tools                            |
| [`version`](mcp_version.md) | Show the version information            |


### Options

| Name              | Type   | Default | Description                        |
|:------------------|:-------|:--------|:-----------------------------------|
| `-v`, `--version` | `bool` |         | Print version information and quit |




## Description

The MCP Gateway is Docker's open-source enterprise solution for orchestrating
Model Context Protocol (MCP) servers and clients.

For more information see [Docker MCP](https://docs.docker.com/ai/mcp-gateway/) and
the public [GitHub repository](https://github.com/docker/mcp-gateway).

---

### Generator Reference Mcp Catalog (`docs/generator/reference/mcp_catalog.md`)

# docker mcp catalog


Manage MCP server catalogs for organizing and configuring custom MCP servers alongside Docker's official catalog.

### Aliases

`docker mcp catalog`, `docker mcp catalogs`

### Subcommands

| Name                                    | Description                                                                         |
|:----------------------------------------|:------------------------------------------------------------------------------------|
| [`add`](mcp_catalog_add.md)             | Add a server to a catalog                                                           |
| [`bootstrap`](mcp_catalog_bootstrap.md) | Create a starter catalog file with Docker and Docker Hub server entries as examples |
| [`create`](mcp_catalog_create.md)       | Create a new empty catalog                                                          |
| [`export`](mcp_catalog_export.md)       | Export a configured catalog to a file                                               |
| [`fork`](mcp_catalog_fork.md)           | Create a copy of an existing catalog                                                |
| [`import`](mcp_catalog_import.md)       | Import a catalog from URL or file                                                   |
| [`init`](mcp_catalog_init.md)           | Initialize the catalog system                                                       |
| [`ls`](mcp_catalog_ls.md)               | List all configured catalogs                                                        |
| [`reset`](mcp_catalog_reset.md)         | Reset the catalog system                                                            |
| [`rm`](mcp_catalog_rm.md)               | Remove a catalog                                                                    |
| [`show`](mcp_catalog_show.md)           | Display catalog contents                                                            |
| [`update`](mcp_catalog_update.md)       | Update catalog(s) from remote sources                                               |

---

### Generator Reference Mcp Catalog Add (`docs/generator/reference/mcp_catalog_add.md`)

# docker mcp catalog add


Add an MCP server definition to an existing catalog by copying it from another catalog file.
The server definition includes all configuration, tools, and metadata.

### Options

| Name      | Type   | Default | Description                              |
|:----------|:-------|:--------|:-----------------------------------------|
| `--force` | `bool` |         | Overwrite existing server in the catalog |

---

### Generator Reference Mcp Catalog Bootstrap (`docs/generator/reference/mcp_catalog_bootstrap.md`)

# docker mcp catalog bootstrap


Create a starter catalog file with Docker Hub and Docker CLI server entries as examples.
This command extracts the official Docker server definitions and creates a properly formatted
catalog file that users can modify and use as a foundation for their custom catalogs.

The output file is standalone and not automatically imported - users can modify it and then
import it or use it as a source for the 'catalog add' command.

---

### Generator Reference Mcp Catalog Create (`docs/generator/reference/mcp_catalog_create.md`)

# docker mcp catalog create


Create a new empty catalog for organizing custom MCP servers. The catalog will be stored locally and can be populated using 'docker mcp catalog add'.

---

### Generator Reference Mcp Catalog Export (`docs/generator/reference/mcp_catalog_export.md`)

# docker mcp catalog export


Export a user-managed catalog to a file. This command only works with catalogs
that have been imported or configured manually. The canonical Docker MCP catalog
cannot be exported as it is managed by Docker.

---

### Generator Reference Mcp Catalog Fork (`docs/generator/reference/mcp_catalog_fork.md`)

# docker mcp catalog fork


Create a new catalog by copying all servers from an existing catalog. Useful for creating variations of existing catalogs.

---

### Generator Reference Mcp Catalog Import (`docs/generator/reference/mcp_catalog_import.md`)

# docker mcp catalog import


Import an MCP server catalog from a URL or local file. The catalog will be downloaded 
and stored locally for use with the MCP gateway.

When --mcp-registry flag is used, the argument must be an existing catalog name, and the
command will import servers from the MCP registry URL into that catalog.

### Options

| Name             | Type     | Default | Description                                               |
|:-----------------|:---------|:--------|:----------------------------------------------------------|
| `--dry-run`      | `bool`   |         | Show Imported Data but do not update the Catalog          |
| `--mcp-registry` | `string` |         | Import server from MCP registry URL into existing catalog |

---

### Generator Reference Mcp Catalog Init (`docs/generator/reference/mcp_catalog_init.md`)

# docker mcp catalog init


Initialize the local catalog management system by creating the necessary configuration files and directories.

---

### Generator Reference Mcp Catalog Ls (`docs/generator/reference/mcp_catalog_ls.md`)

# docker mcp catalog ls


List all configured catalogs including Docker's official catalog and any locally managed catalogs.

### Options

| Name       | Type     | Default | Description                               |
|:-----------|:---------|:--------|:------------------------------------------|
| `--format` | `format` |         | Output format. Supported: "json", "yaml". |

---

### Generator Reference Mcp Catalog Reset (`docs/generator/reference/mcp_catalog_reset.md`)

# docker mcp catalog reset


Reset the local catalog management system by removing all user-managed catalogs and configuration. This does not affect Docker's official catalog.

### Aliases

`docker mcp catalog reset`, `docker mcp catalog empty`

---

### Generator Reference Mcp Catalog Rm (`docs/generator/reference/mcp_catalog_rm.md`)

# docker mcp catalog rm


Remove a locally configured catalog. This will delete the catalog and all its server definitions.
The Docker official catalog cannot be removed.

---

### Generator Reference Mcp Catalog Show (`docs/generator/reference/mcp_catalog_show.md`)

# docker mcp catalog show


Display the contents of a catalog including all server definitions and metadata.
If no name is provided, shows the Docker official catalog.

### Options

| Name       | Type     | Default | Description                |
|:-----------|:---------|:--------|:---------------------------|
| `--format` | `format` |         | Supported: "json", "yaml". |

---

### Generator Reference Mcp Catalog Update (`docs/generator/reference/mcp_catalog_update.md`)

# docker mcp catalog update


Update one or more catalogs by re-downloading from their original sources.
If no name is provided, updates all catalogs that have remote sources.

---

### Generator Reference Mcp Client (`docs/generator/reference/mcp_client.md`)

# docker mcp client


Manage MCP clients

### Subcommands

| Name                                     | Description                                                                                                                                                                                  |
|:-----------------------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| [`connect`](mcp_client_connect.md)       | Connect the Docker MCP Toolkit to a client. Supported clients: claude-code claude-desktop cline codex continue crush cursor gemini goose gordon kiro lmstudio opencode sema4 vscode zed      |
| [`disconnect`](mcp_client_disconnect.md) | Disconnect the Docker MCP Toolkit from a client. Supported clients: claude-code claude-desktop cline codex continue crush cursor gemini goose gordon kiro lmstudio opencode sema4 vscode zed |
| [`ls`](mcp_client_ls.md)                 | List client configurations                                                                                                                                                                   |

---

### Generator Reference Mcp Client Connect (`docs/generator/reference/mcp_client_connect.md`)

# docker mcp client connect


Connect the Docker MCP Toolkit to a client. Supported clients: claude-code claude-desktop cline codex continue crush cursor gemini goose gordon kiro lmstudio opencode sema4 vscode zed

### Options

| Name             | Type   | Default | Description                                                                         |
|:-----------------|:-------|:--------|:------------------------------------------------------------------------------------|
| `-g`, `--global` | `bool` |         | Change the system wide configuration or the clients setup in your current git repo. |
| `-q`, `--quiet`  | `bool` |         | Only display errors.                                                                |

---

### Generator Reference Mcp Client Disconnect (`docs/generator/reference/mcp_client_disconnect.md`)

# docker mcp client disconnect


Disconnect the Docker MCP Toolkit from a client. Supported clients: claude-code claude-desktop cline codex continue crush cursor gemini goose gordon kiro lmstudio opencode sema4 vscode zed

### Options

| Name             | Type   | Default | Description                                                                         |
|:-----------------|:-------|:--------|:------------------------------------------------------------------------------------|
| `-g`, `--global` | `bool` |         | Change the system wide configuration or the clients setup in your current git repo. |
| `-q`, `--quiet`  | `bool` |         | Only display errors.                                                                |

---

### Generator Reference Mcp Client Ls (`docs/generator/reference/mcp_client_ls.md`)

# docker mcp client ls


List client configurations

### Options

| Name             | Type   | Default | Description                                                                         |
|:-----------------|:-------|:--------|:------------------------------------------------------------------------------------|
| `-g`, `--global` | `bool` |         | Change the system wide configuration or the clients setup in your current git repo. |
| `--json`         | `bool` |         | Print as JSON.                                                                      |

---

### Generator Reference Mcp Config (`docs/generator/reference/mcp_config.md`)

# docker mcp config


Manage the configuration

### Subcommands

| Name                           | Description             |
|:-------------------------------|:------------------------|
| [`read`](mcp_config_read.md)   | Read the configuration  |
| [`reset`](mcp_config_reset.md) | Reset the configuration |
| [`write`](mcp_config_write.md) | Write the configuration |

---

### Generator Reference Mcp Config Reset (`docs/generator/reference/mcp_config_reset.md`)

# docker mcp config reset


Reset the configuration

---

### Generator Reference Mcp Config Write (`docs/generator/reference/mcp_config_write.md`)

# docker mcp config write


Write the configuration

---

### Generator Reference Mcp Feature (`docs/generator/reference/mcp_feature.md`)

# docker mcp feature


Manage experimental features for Docker MCP Gateway.

Features are stored in your Docker configuration file (~/.docker/config.json)
and control optional functionality that may change in future versions.

### Subcommands

| Name                                | Description                                  |
|:------------------------------------|:---------------------------------------------|
| [`disable`](mcp_feature_disable.md) | Disable an experimental feature              |
| [`enable`](mcp_feature_enable.md)   | Enable an experimental feature               |
| [`ls`](mcp_feature_ls.md)           | List all available features and their status |

---

### Generator Reference Mcp Feature Disable (`docs/generator/reference/mcp_feature_disable.md`)

# docker mcp feature disable


Disable an experimental feature that was previously enabled.

---

### Generator Reference Mcp Feature Enable (`docs/generator/reference/mcp_feature_enable.md`)

# docker mcp feature enable


Enable an experimental feature.

Available features:
  oauth-interceptor      Enable GitHub OAuth flow interception for automatic authentication
  mcp-oauth-dcr          Enable Dynamic Client Registration (DCR) for automatic OAuth client setup
  dynamic-tools          Enable internal MCP management tools (mcp-find, mcp-add, mcp-remove)
	profiles               Enable profile management (docker mcp profile <subcommand>)
  tool-name-prefix       Prefix all tool names with server name to avoid conflicts

---

### Generator Reference Mcp Feature List (`docs/generator/reference/mcp_feature_list.md`)

# docker mcp feature list


List all available experimental features and show whether they are enabled or disabled.

---

### Generator Reference Mcp Feature Ls (`docs/generator/reference/mcp_feature_ls.md`)

# docker mcp feature ls


List all available experimental features and show whether they are enabled or disabled.

### Aliases

`docker mcp feature ls`, `docker mcp feature list`

---

### Generator Reference Mcp Gateway (`docs/generator/reference/mcp_gateway.md`)

# docker mcp gateway


Manage the MCP Server gateway

### Subcommands

| Name                        | Description     |
|:----------------------------|:----------------|
| [`run`](mcp_gateway_run.md) | Run the gateway |

---

### Generator Reference Mcp Gateway Run (`docs/generator/reference/mcp_gateway_run.md`)

# docker mcp gateway run


Run the gateway

### Options

| Name                             | Type          | Default             | Description                                                                                                                                   |
|:---------------------------------|:--------------|:--------------------|:----------------------------------------------------------------------------------------------------------------------------------------------|
| `--additional-catalog`           | `stringSlice` |                     | Additional catalog paths must resolve under ~/.docker/mcp/catalogs/                                                                           |
| `--additional-config`            | `stringSlice` |                     | Additional config paths to merge with the default config.yaml                                                                                 |
| `--additional-registry`          | `stringSlice` |                     | Additional registry paths to merge with the default registry.yaml                                                                             |
| `--additional-tools-config`      | `stringSlice` |                     | Additional tools paths to merge with the default tools.yaml                                                                                   |
| `--allow-unauthenticated`        | `bool`        |                     | Allow unauthenticated HTTP/SSE gateway requests                                                                                               |
| `--block-network`                | `bool`        |                     | Block tools from accessing forbidden network resources                                                                                        |
| `--block-secrets`                | `bool`        | `true`              | Block secrets from being/received sent to/from tools                                                                                          |
| `--catalog`                      | `stringSlice` | `[docker-mcp.yaml]` | Catalog paths must resolve under ~/.docker/mcp/catalogs/                                                                                      |
| `--config`                       | `stringSlice` | `[config.yaml]`     | Paths to the config files (absolute or relative to ~/.docker/mcp/)                                                                            |
| `--cpus`                         | `int`         | `1`                 | CPUs allocated to each MCP Server (default is 1)                                                                                              |
| `--debug-dns`                    | `bool`        |                     | Debug DNS resolution                                                                                                                          |
| `--dry-run`                      | `bool`        |                     | Start the gateway but do not listen for connections (useful for testing the configuration)                                                    |
| `--enable-all-servers`           | `bool`        |                     | Enable all servers in the catalog (instead of using individual --servers options)                                                             |
| `--host`                         | `string`      |                     | Host or IP address to bind TCP transports to                                                                                                  |
| `--interceptor`                  | `stringArray` |                     | List of interceptors to use (format: when:type:path, e.g. 'before:exec:/bin/path')                                                            |
| `--log-calls`                    | `bool`        | `true`              | Log calls to the tools                                                                                                                        |
| `--long-lived`                   | `bool`        |                     | Containers are long-lived and will not be removed until the gateway is stopped, useful for stateful servers                                   |
| `--mcp-registry`                 | `stringSlice` |                     | MCP registry URLs to fetch servers from (can be repeated)                                                                                     |
| `--memory`                       | `string`      | `2Gb`               | Memory allocated to each MCP Server (default is 2Gb)                                                                                          |
| `--oci-ref`                      | `stringArray` |                     | OCI image references to use                                                                                                                   |
| `--port`                         | `int`         | `0`                 | TCP port to listen on (default is to listen on stdio)                                                                                         |
| `--preserve-tool-schema-dialect` | `bool`        |                     | Relay tool schemas with the JSON Schema dialect the server declared, instead of translating pre-2020-12 dialects                              |
| `--registry`                     | `stringSlice` | `[registry.yaml]`   | Paths to the registry files (absolute or relative to ~/.docker/mcp/)                                                                          |
| `--secrets`                      | `string`      | `docker-desktop`    | Colon separated paths to search for secrets. Can be `docker-desktop` or a path to a .env file (default to using Docker Desktop's secrets API) |
| `--servers`                      | `stringSlice` |                     | Names of the servers to enable (if non empty, ignore --registry flag)                                                                         |
| `--static`                       | `bool`        |                     | Enable static mode (aka pre-started servers)                                                                                                  |
| `--tools`                        | `stringSlice` |                     | List of tools to enable                                                                                                                       |
| `--tools-config`                 | `stringSlice` | `[tools.yaml]`      | Paths to the tools files (absolute or relative to ~/.docker/mcp/)                                                                             |
| `--transport`                    | `string`      | `stdio`             | stdio, sse or streaming. Uses MCP_GATEWAY_AUTH_TOKEN environment variable for localhost authentication to prevent dns rebinding attacks.      |
| `--verbose`                      | `bool`        |                     | Verbose output                                                                                                                                |
| `--verify-signatures`            | `bool`        | `true`              | Verify signatures of Docker MCP server images                                                                                                 |
| `--watch`                        | `bool`        | `true`              | Watch for changes and reconfigure the gateway                                                                                                 |

---

### Generator Reference Mcp Import (`docs/generator/reference/mcp_import.md`)

# docker mcp import


Import and parse a server definition from an official MCP registry URL.

This command fetches the server definition from the provided URL, parses it as a ServerDetail,
converts it to the internal Server format, and displays the results.

Example:
  docker mcp officialregistry import https://registry.example.com/servers/my-server

### Options

| Name             | Type     | Default | Description                     |
|:-----------------|:---------|:--------|:--------------------------------|
| `--catalog`      | `string` |         | import to local catalog         |
| `--mcp-registry` | `string` |         | import from MCP registry format |
| `--push`         | `bool`   |         | push the new server artifact    |

---

### Generator Reference Mcp Oauth (`docs/generator/reference/mcp_oauth.md`)

# docker mcp oauth


Manage OAuth app authorizations

### Subcommands

| Name                                  | Description                        |
|:--------------------------------------|:-----------------------------------|
| [`authorize`](mcp_oauth_authorize.md) | Authorize the specified OAuth app. |
| [`ls`](mcp_oauth_ls.md)               | List available OAuth apps.         |
| [`revoke`](mcp_oauth_revoke.md)       | Revoke the specified OAuth app.    |

---

### Generator Reference Mcp Oauth Authorize (`docs/generator/reference/mcp_oauth_authorize.md`)

# docker mcp oauth authorize


Authorize the specified OAuth app.

### Options

| Name             | Type     | Default | Description                                                     |
|:-----------------|:---------|:--------|:----------------------------------------------------------------|
| `--open-browser` | `bool`   |         | Open the authorization URL in the default browser automatically |
| `--scopes`       | `string` |         | OAuth scopes to request (space-separated)                       |

---

### Generator Reference Mcp Oauth Ls (`docs/generator/reference/mcp_oauth_ls.md`)

# docker mcp oauth ls


List available OAuth apps.

### Options

| Name     | Type   | Default | Description    |
|:---------|:-------|:--------|:---------------|
| `--json` | `bool` |         | Print as JSON. |

---

### Generator Reference Mcp Oauth Revoke (`docs/generator/reference/mcp_oauth_revoke.md`)

# docker mcp oauth revoke


Revoke the specified OAuth app.

---

### Generator Reference Mcp Policy (`docs/generator/reference/mcp_policy.md`)

# docker mcp policy


Manage secret policies

### Aliases

`docker mcp policy`, `docker mcp policies`

### Subcommands

| Name                         | Description                                          |
|:-----------------------------|:-----------------------------------------------------|
| [`dump`](mcp_policy_dump.md) | Dump the policy content                              |
| [`set`](mcp_policy_set.md)   | Set a policy for secret management in Docker Desktop |

---

### Generator Reference Mcp Policy Dump (`docs/generator/reference/mcp_policy_dump.md`)

# docker mcp policy dump


Dump the policy content

---

### Generator Reference Mcp Policy Set (`docs/generator/reference/mcp_policy_set.md`)

# docker mcp policy set


Set a policy for secret management in Docker Desktop

---

### Generator Reference Mcp Secret (`docs/generator/reference/mcp_secret.md`)

# docker mcp secret


Manage secrets in the local OS Keychain

### Subcommands

| Name                       | Description                                                                               |
|:---------------------------|:------------------------------------------------------------------------------------------|
| [`ls`](mcp_secret_ls.md)   | List all secrets from the local OS Keychain as well as any active Secrets Engine provider |
| [`rm`](mcp_secret_rm.md)   | Remove secrets from the local OS Keychain                                                 |
| [`set`](mcp_secret_set.md) | Set a secret in the local OS Keychain                                                     |

---

### Generator Reference Mcp Secret Ls (`docs/generator/reference/mcp_secret_ls.md`)

# docker mcp secret ls


List all secrets from the local OS Keychain as well as any active Secrets Engine provider

### Options

| Name     | Type   | Default | Description    |
|:---------|:-------|:--------|:---------------|
| `--json` | `bool` |         | Print as JSON. |

---

### Generator Reference Mcp Secret Rm (`docs/generator/reference/mcp_secret_rm.md`)

# docker mcp secret rm


Remove secrets from the local OS Keychain

### Options

| Name    | Type   | Default | Description        |
|:--------|:-------|:--------|:-------------------|
| `--all` | `bool` |         | Remove all secrets |

---

### Generator Reference Mcp Secret Set (`docs/generator/reference/mcp_secret_set.md`)

# docker mcp secret set


Set a secret in the local OS Keychain




## Examples

### Pass the secret via STDIN

```console
echo my-secret-password | docker mcp secret set postgres_password
```

---

### Generator Reference Mcp Server (`docs/generator/reference/mcp_server.md`)

# docker mcp server


Manage servers

### Subcommands

| Name                               | Description                                               |
|:-----------------------------------|:----------------------------------------------------------|
| [`disable`](mcp_server_disable.md) | Disable a server or multiple servers                      |
| [`enable`](mcp_server_enable.md)   | Enable a server or multiple servers                       |
| [`init`](mcp_server_init.md)       | Initialize a new MCP server project                       |
| [`inspect`](mcp_server_inspect.md) | Get information about a server or inspect an OCI artifact |
| [`ls`](mcp_server_ls.md)           | List enabled servers                                      |
| [`reset`](mcp_server_reset.md)     | Disable all the servers                                   |

---

### Generator Reference Mcp Server Disable (`docs/generator/reference/mcp_server_disable.md`)

# docker mcp server disable


Disable a server or multiple servers

### Aliases

`docker mcp server disable`, `docker mcp server remove`, `docker mcp server rm`

---

### Generator Reference Mcp Server Enable (`docs/generator/reference/mcp_server_enable.md`)

# docker mcp server enable


Enable a server or multiple servers

### Aliases

`docker mcp server enable`, `docker mcp server add`

---

### Generator Reference Mcp Server Import (`docs/generator/reference/mcp_server_import.md`)

# docker mcp server import


Import a server

### Options

| Name     | Type   | Default | Description                  |
|:---------|:-------|:--------|:-----------------------------|
| `--push` | `bool` |         | push the new server artifact |

---

### Generator Reference Mcp Server Init (`docs/generator/reference/mcp_server_init.md`)

# docker mcp server init


Initialize a new MCP server project in the specified directory with boilerplate code, Dockerfile, and compose.yaml

### Options

| Name         | Type     | Default | Description                                                            |
|:-------------|:---------|:--------|:-----------------------------------------------------------------------|
| `--language` | `string` | `go`    | Programming language for the server (currently only 'go' is supported) |
| `--template` | `string` | `basic` | Template to use (basic, chatgpt-app-basic)                             |

---

### Generator Reference Mcp Server Inspect (`docs/generator/reference/mcp_server_inspect.md`)

# docker mcp server inspect


Get information about a server or inspect an OCI artifact

---

### Generator Reference Mcp Server List (`docs/generator/reference/mcp_server_list.md`)

# docker mcp server list


List enabled servers

### Aliases

`docker mcp server list`, `docker mcp server ls`

### Options

| Name     | Type   | Default | Description           |
|:---------|:-------|:--------|:----------------------|
| `--json` | `bool` |         | Output in JSON format |

---

### Generator Reference Mcp Server Ls (`docs/generator/reference/mcp_server_ls.md`)

# docker mcp server ls


List enabled servers

### Aliases

`docker mcp server ls`, `docker mcp server list`

### Options

| Name     | Type   | Default | Description           |
|:---------|:-------|:--------|:----------------------|
| `--json` | `bool` |         | Output in JSON format |

---

### Generator Reference Mcp Server Reset (`docs/generator/reference/mcp_server_reset.md`)

# docker mcp server reset


Disable all the servers

---

### Generator Reference Mcp Tools (`docs/generator/reference/mcp_tools.md`)

# docker mcp tools


Manage tools

### Subcommands

| Name                              | Description               |
|:----------------------------------|:--------------------------|
| [`call`](mcp_tools_call.md)       | Call a tool               |
| [`count`](mcp_tools_count.md)     | Count tools               |
| [`disable`](mcp_tools_disable.md) | disable one or more tools |
| [`enable`](mcp_tools_enable.md)   | enable one or more tools  |
| [`inspect`](mcp_tools_inspect.md) | Inspect a tool            |
| [`ls`](mcp_tools_ls.md)           | List tools                |


### Options

| Name            | Type          | Default | Description                                |
|:----------------|:--------------|:--------|:-------------------------------------------|
| `--format`      | `string`      | `list`  | Output format (json\|list)                 |
| `--gateway-arg` | `stringSlice` |         | Additional arguments passed to the gateway |
| `--verbose`     | `bool`        |         | Verbose output                             |
| `--version`     | `string`      | `2`     | Version of the gateway                     |

---

### Generator Reference Mcp Tools Call (`docs/generator/reference/mcp_tools_call.md`)

# docker mcp tools call


Call a tool

### Options

| Name            | Type          | Default | Description                                |
|:----------------|:--------------|:--------|:-------------------------------------------|
| `--format`      | `string`      | `list`  | Output format (json\|list)                 |
| `--gateway-arg` | `stringSlice` |         | Additional arguments passed to the gateway |
| `--verbose`     | `bool`        |         | Verbose output                             |
| `--version`     | `string`      | `2`     | Version of the gateway                     |

---

### Generator Reference Mcp Tools Count (`docs/generator/reference/mcp_tools_count.md`)

# docker mcp tools count


Count tools

### Options

| Name            | Type          | Default | Description                                |
|:----------------|:--------------|:--------|:-------------------------------------------|
| `--format`      | `string`      | `list`  | Output format (json\|list)                 |
| `--gateway-arg` | `stringSlice` |         | Additional arguments passed to the gateway |
| `--verbose`     | `bool`        |         | Verbose output                             |
| `--version`     | `string`      | `2`     | Version of the gateway                     |

---

### Generator Reference Mcp Tools Disable (`docs/generator/reference/mcp_tools_disable.md`)

# docker mcp tools disable


disable one or more tools

### Options

| Name            | Type          | Default | Description                                                                            |
|:----------------|:--------------|:--------|:---------------------------------------------------------------------------------------|
| `--format`      | `string`      | `list`  | Output format (json\|list)                                                             |
| `--gateway-arg` | `stringSlice` |         | Additional arguments passed to the gateway                                             |
| `--server`      | `string`      |         | Specify which server provides the tools (optional, will auto-discover if not provided) |
| `--verbose`     | `bool`        |         | Verbose output                                                                         |
| `--version`     | `string`      | `2`     | Version of the gateway                                                                 |

---

### Generator Reference Mcp Tools Enable (`docs/generator/reference/mcp_tools_enable.md`)

# docker mcp tools enable


enable one or more tools

### Options

| Name            | Type          | Default | Description                                                                            |
|:----------------|:--------------|:--------|:---------------------------------------------------------------------------------------|
| `--format`      | `string`      | `list`  | Output format (json\|list)                                                             |
| `--gateway-arg` | `stringSlice` |         | Additional arguments passed to the gateway                                             |
| `--server`      | `string`      |         | Specify which server provides the tools (optional, will auto-discover if not provided) |
| `--verbose`     | `bool`        |         | Verbose output                                                                         |
| `--version`     | `string`      | `2`     | Version of the gateway                                                                 |

---

### Generator Reference Mcp Tools Inspect (`docs/generator/reference/mcp_tools_inspect.md`)

# docker mcp tools inspect


Inspect a tool

### Options

| Name            | Type          | Default | Description                                |
|:----------------|:--------------|:--------|:-------------------------------------------|
| `--format`      | `string`      | `list`  | Output format (json\|list)                 |
| `--gateway-arg` | `stringSlice` |         | Additional arguments passed to the gateway |
| `--verbose`     | `bool`        |         | Verbose output                             |
| `--version`     | `string`      | `2`     | Version of the gateway                     |

---

### Generator Reference Mcp Tools List (`docs/generator/reference/mcp_tools_list.md`)

# docker mcp tools list


List tools

### Aliases

`docker mcp tools list`, `docker mcp tools ls`

### Options

| Name            | Type          | Default | Description                                |
|:----------------|:--------------|:--------|:-------------------------------------------|
| `--format`      | `string`      | `list`  | Output format (json\|list)                 |
| `--gateway-arg` | `stringSlice` |         | Additional arguments passed to the gateway |
| `--verbose`     | `bool`        |         | Verbose output                             |
| `--version`     | `string`      | `2`     | Version of the gateway                     |

---

### Generator Reference Mcp Tools Ls (`docs/generator/reference/mcp_tools_ls.md`)

# docker mcp tools ls


List tools

### Aliases

`docker mcp tools ls`, `docker mcp tools list`

### Options

| Name            | Type          | Default | Description                                |
|:----------------|:--------------|:--------|:-------------------------------------------|
| `--format`      | `string`      | `list`  | Output format (json\|list)                 |
| `--gateway-arg` | `stringSlice` |         | Additional arguments passed to the gateway |
| `--verbose`     | `bool`        |         | Verbose output                             |
| `--version`     | `string`      | `2`     | Version of the gateway                     |

---

### Generator Reference Mcp Version (`docs/generator/reference/mcp_version.md`)

# docker mcp version


Show the version information

---

--- METRICS ---
- Files Extracted: 76
- Estimated Token Budget: ~56281 tokens
- Canonical Reference: https://codewiki.google/github.com/docker/mcp-gateway
