Technical Documentation: docker/mcp-gateway
โน๏ธ Provenance: Multi-Tier Ingestion ยท CodeWiki Reference
Overview (README.md)
Docker MCP Plugin and Docker MCP Gateway
The MCP Toolkit, in Docker Desktop, allows
developers to configure and consume MCP servers from the Docker MCP Catalog.
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 for a list of all the features.
What is MCP?
The Model Context Protocol (MCP) 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)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:
# 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-mcpAfter installation, the plugin will be available as:
docker mcp --helpUsage
[!NOTE]
Running without Docker Desktop Feature FlagsIf you encounter "Docker Desktop is not running" errors when the Docker daemon is active, you can bypass Desktop feature checks by setting:
bashexport DOCKER_MCP_IN_CONTAINER=1This is useful when running in WSL2, containerized environments, or Docker CE where Desktop backend sockets are unavailable.
[!NOTE]
Enabling Profiles outside Docker DesktopProfiles 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:
bashdocker 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/ - Local file references:
file://./server.yaml
# 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
# 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 slackConfigure servers in a profile
# 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.timeoutManage tool allowlists in a profile
# 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 githubCatalog Management
Manage the OCI-based catalogs available to the MCP gateway. The default catalog is the image mcp/docker-mcp-catalog.
# 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.
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.
# 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 streamingIf no --profile flag is provided, the gateway uses the default profile.
- more about the MCP Gateway
Client Connection
Connect AI clients to the MCP gateway.
# 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.
# 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 server2Tool Management
# 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.jsoninstead of~/.claude.jsonfor 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:
# 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.jsonArchitecture
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 for detailed message flow diagrams.
Contributing
The build instructions are available in the contribution guide.
License
This project is licensed under the MIT License - see the LICENSE file for details.
Support
- ๐ฌ Troubleshooting
- ๐ MCP Specification
- ๐ณ Docker Desktop Documentation
- ๐ Report Issues
- ๐ฌ 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 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 useMigration 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 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:
- All check the database state (clean)
- All try to run migrations at the same time
- 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:text
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:
go run test_migration_race.goThis 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 metricsKey Components
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
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
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
Periodic Export (
internal/gateway/run.go)- Exports metrics every 30 seconds for long-running gateways
- Configurable via
DOCKER_MCP_METRICS_INTERVALenvironment 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 servermcp.prompts.discovered- Number of prompts available per servermcp.resources.discovered- Number of resources available per servermcp.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
(inputSchemaoroutputSchema) andmcp.tool.schema_outcome:translated- a declared draft-04/06/07 schema was converted to 2020-12relayed- a declared draft-04/06/07 schema held a construct with no faithful 2020-12
equivalent, so it was passed through as declaredunsupported_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 toolsmcp.list.prompts- Client requests list of available promptsmcp.list.resources- Client requests list of available resourcesmcp.list.resource_templates- Client requests list of available resource templates
Protocol Operations
Tool Calls
mcp.tool.calls- Counter of tool invocationsmcp.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 retrievalsmcp.prompt.duration- Histogram of prompt operation timemcp.prompt.errors- Counter of prompt operation failures
Resource Operations
mcp.resource.reads- Counter of resource readsmcp.resource.duration- Histogram of resource operation timemcp.resource.errors- Counter of resource operation failures
Resource Template Operations
mcp.resource_template.reads- Counter of resource template readsmcp.resource_template.duration- Histogram of template operation timemcp.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 CLImcp.cli.tool.duration- CLI tool execution durationmcp.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 operationsmcp.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 operationmcp.server.origin- Name of the MCP server a capability was discovered on. This is
what discovery and listing metrics carry;mcp.server.nameis used on the tool-error
path, paired withmcp.server.typemcp.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 calledmcp.prompt.name- Name of the prompt being retrievedmcp.resource.uri- URI of the resource being readmcp.operation.error- Error message if operation failedmcp.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 catalogmcp.catalog.success- Boolean indicating operation success
Profile Attributes
mcp.profile.operation- Type of profile operation (create, push, pull, remove)mcp.profile.id- Profile identifiermcp.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:
- Periodic Metric Export: Metrics are exported every 30 seconds (configurable via
DOCKER_MCP_METRICS_INTERVAL) - Applies to All Transport Modes: Whether using stdio, SSE, or streaming transports, all gateway processes are long-lived
- Non-blocking Operations: Telemetry never blocks MCP operations
- Memory Efficiency: Metrics are aggregated efficiently to minimize overhead
- Graceful Shutdown: Final metric export still occurs on gateway termination
Configuration
Checking Current Configuration
View your Docker context's OTEL settings:
docker context inspect | jq '.[].Metadata.otel'Typical output for Docker Desktop:
{
"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 operationsDOCKER_MCP_METRICS_INTERVAL- Set metric export interval (default: 30s)DOCKER_CLI_OTEL_EXPORTER_OTLP_ENDPOINT- Override OTEL collector endpoint for testingOTEL_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:
export DOCKER_MCP_TELEMETRY_DEBUG=1
docker mcp gateway run --catalog catalog.yamlDebug 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:
- Uses Docker CLI's global OTEL providers
- Inherits Docker Desktop's telemetry configuration
- Exports to the same OTEL collector as other Docker operations
- 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:
cd docs/telemetry/testing
./test-telemetry.sh --fullManual Testing
- Start an OTEL Collector:
For debug output only:
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.yamlFor Prometheus export (port 8889):
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- Run MCP Gateway with Custom Endpoint:
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 3000Make Tool Calls:
Connect an MCP client tohttp://localhost:3000/sseand execute tools.View Telemetry:
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: 2Troubleshooting
No Telemetry Visible
Check Provider Types:
bashDOCKER_MCP_TELEMETRY_DEBUG=1 docker mcp gateway run --dry-runLook for:
Tracer provider type: *trace.TracerProvider(not noop)Verify Endpoint Configuration:
- Check Docker context:
docker context inspect - Check environment:
echo $DOCKER_CLI_OTEL_EXPORTER_OTLP_ENDPOINT
- Check Docker context:
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=1is 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:
Use Existing Providers:
gotracer := otel.GetTracerProvider().Tracer("github.com/docker/mcp-gateway") meter := otel.GetMeterProvider().Meter("github.com/docker/mcp-gateway")Preserve Server Lineage:
Always include server attribution in spans and metrics:goattrs := []attribute.KeyValue{ attribute.String("mcp.server.name", serverConfig.Name), attribute.String("mcp.server.type", inferServerTransportType(serverConfig)), attribute.String("mcp.tool.name", toolName), }Non-Blocking Operations:
Telemetry must never block or fail operations:goif span != nil { defer span.End() } // Continue even if telemetry failsDebug Support:
Add debug logging behind the environment flag:goif os.Getenv("DOCKER_MCP_TELEMETRY_DEBUG") != "" { fmt.Fprintf(os.Stderr, "[MCP-TELEMETRY] Recording tool call: %s\n", toolName) }
Testing Changes
Build the Plugin:
bashmake docker-mcpRun the Test Suite:
bash./docs/telemetry/testing/test-telemetry.sh --fullVerify with Real Tool Calls:
Test in SSE mode with an actual MCP clientCheck 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 - Core OTEL concepts and SDKs
- Docker CLI Telemetry - Docker's telemetry implementation
- MCP Protocol Specification - Model Context Protocol details
- MCP Gateway Repository - 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 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:
# 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 modifyThis 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
# List all configured catalogs
docker mcp catalog ls
# List in JSON format
docker mcp catalog ls --format=jsonCreating Catalogs
# Create a new empty catalog
docker mcp catalog create my-custom-catalog
# The catalog is now ready for adding serversViewing Catalog Contents
# 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 yamlAdding Servers to Catalogs
# 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 --forceImporting Servers from OSS MCP Community Registry
# 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
# 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-serversExporting Catalogs
# 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 DockerForking Catalogs
# Create a copy of an existing catalog
docker mcp catalog fork docker-mcp my-custom-version
# Now you can modify my-custom-version independentlyRemoving Catalogs
# Remove a custom catalog
docker mcp catalog rm my-custom-catalog
# Note: You cannot remove Docker's official catalogUpdating Catalogs
# Update all catalogs
docker mcp catalog update
# Update a specific catalog
docker mcp catalog update my-custom-catalogResetting Catalogs
# Remove all custom catalogs and reset to Docker defaults
docker mcp catalog resetCatalog YAML Format
Catalogs use a specific YAML format with server definitions. Here's the structure:
Basic Structure
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
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
# 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.yamlImporting from the OSS MCP Community Registry
# 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
# 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 runTesting New Servers
# 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-serversProduction Deployment
# 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 runCatalog Precedence
Catalogs are loaded in this order:
- Docker Official Catalog (always loaded first)
- Configured Catalogs (user-imported catalogs)
- CLI-specified Catalogs (via
--catalogflag)
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
Error: file "catalog.yaml" already exists - will not overwriteSolution: Choose a different filename or move/remove the existing file
Server Not Found
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
Error: cannot export the Docker MCP catalog as it is managed by DockerSolution: 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
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: healthyReading 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.
sequenceDiagram
AddTool->>Config: find
AddTool->>Config: append server
AddTool->>Config: update secrets
AddTool->>Gateway: reloadConfiguration
Gateway-->>Config: is usedDuring 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 theio.docker.server.metadata label. When such an image is referenced
through a profile or working set (see profiles), 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
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.
# 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-setSee Profiles 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.sockWhat 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-dcrfeature is enabled).
How to run
docker compose upMore examples
See Examples
Complete set of command line flags
See the generated reference: docker mcp gateway run.
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
Message Flow (`docs/message-flow.md`)
Message Flow
Src: official docs page
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 toolsDocker Model
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 toolsOauth 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 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:
{
"credsStore": "osxkeychain"
}Linux (Desktop):
{
"credsStore": "secretservice"
}Linux (Headless):
{
"credsStore": "pass"
}Windows:
{
"credsStore": "wincred"
}Verify configuration:
# 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 # WindowsFor detailed installation instructions, see:
https://github.com/docker/docker-credential-helpers
Configuration
Enable CE Mode
Set the environment variable to enable standalone OAuth:
export DOCKER_MCP_USE_CE=trueOptional: 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:
export MCP_GATEWAY_OAUTH_PORT=5001Valid 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
docker mcp server enable notion-remoteStep 2: Authorize
docker mcp oauth authorize notion-remoteOauth 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
authorization flow after receiving the HTTP 401 Unauthorized.
The following demonstrates the basic OAuth 2.1 for public clients using PKCE.
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 exchangeOfficial MCP OAuth diagram mapped
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 exchangeQuestions
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`)
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: DataHandling 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.
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: DataNotes 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
The third-party authorization flow comprises these steps:
- MCP client initiates standard OAuth flow with MCP server
- MCP server redirects user to third-party authorization server
- User authorizes with third-party server
- Third-party server redirects back to MCP server with authorization code
- MCP server exchanges code for third-party access token
- MCP server generates its own access token bound to the third-party session
- MCP server completes original OAuth flow with MCP client
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 tokenQuestions:
- 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
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 tokenProfiles (`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 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:
# Enable the profiles feature
docker mcp feature enable profiles
# Verify it's enabled
docker mcp feature listIf 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 profilecommands for managing profiles--profileflag fordocker mcp gateway run-por--profileflag fordocker mcp client connect
Profile Commands
Creating Profiles
Create a new profile with a name and list of servers:
# 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:latestNotes:
--nameis required and serves as the human-readable name--idis optional; if not provided, it's generated from the name (lowercase, alphanumeric with underscores)--servercan be specified multiple times to add multiple servers- Server references must be either:
docker://prefix for OCI imageshttp://orhttps://URLs for MCP Registry referencescatalog://prefix for catalog referencesfile://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:
# 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:latestLocal File Format:
When using file://, the file should contain a server definition in YAML or JSON format:
# 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:443See the Server Entry Specification for complete file format documentation including configuration schemas, secrets, OAuth, and advanced options.
Server References:
- Use
--serverflag for all server references (can be specified multiple times) - Server references must start with:
catalog://for catalog references. This takes the form ofcatalog://<catalog-oci-refence>/<server-1>+<server-2>docker://for OCI imageshttp://orhttps://for MCP Registry URLsfile://for local YAML or JSON server definition files (see Server Entry Specification)
- 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:
# 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 githubServer Names:
- Use
--nameflag 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 showto see available server names in a profile
Listing Servers Across Profiles
View all servers grouped by profile, with filtering capabilities:
# 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 yamlOutput options:
--filter: Search for servers matching a query (case-insensitive substring matching on image names or source URLs)--profileor-p: Show servers only from a specific profile--format: Output format -human(default),json, oryaml
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:
# 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 yamlOutput formats:
human(default): Tabular format with ID and Name columnsjson: Complete JSON representationyaml: Complete YAML representation
Showing Profile Details
Display detailed information about a specific profile:
# 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 yamlThe 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:
# Remove a profile
docker mcp profile remove my-profile
# Using alias
docker mcp profile rm my-profileNote: 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:
# 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 yamlConfiguration 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, oryaml
Typed values via JSON:
- Values passed to
--setare 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:
# 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 --format yamlto see available server names - Configuration changes are persisted immediately to the profile
- You cannot both
--setand--delthe 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:
# 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-profileTool 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 showto 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.
# Set a secret for a server in a profile
docker mcp secret set github.pat=ghp_xxxxxSecret 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:
# Export to YAML
docker mcp profile export my-profile ./my-profile.yaml
# Export to JSON
docker mcp profile export my-profile ./my-profile.jsonThe file format is automatically detected from the extension (.yaml or .json).
Importing Profiles
Import a profile from a file:
# Import from YAML
docker mcp profile import ./my-profile.yaml
# Import from JSON
docker mcp profile import ./my-profile.jsonBehavior:
- 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:
# 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.0This 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:
# 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.0The 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:
# Run gateway with a specific profile
docker mcp gateway run --profile my-profile
# The gateway will start with only the servers defined in that profileImportant restrictions:
--profilecannot be used with--serversflag--profilecannot be used with--enable-all-serversflag- 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:
# 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 cursorThis 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
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-storeJSON Format
{
"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
imageorregistry - 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
- type: Either
- secrets: Map of secret configurations
- provider: Currently only
docker-desktop-storeis supported
- provider: Currently only
Common Workflows
Development Workflow
# 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.yamlTeam Collaboration
# 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-toolsEnvironment-Specific Configurations
# 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 stagingProject-Based Organization
# 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-bVersioning Profiles
# 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.1Building Profiles from Catalogs
# 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-workflowFine-Tuning Tool Access
# 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 productionBest 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 setfor sensitive values (API keys, tokens, passwords) - Never use
docker mcp profile configfor 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 toolsto 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
Error: profile my-set not foundSolution: Check available profiles with docker mcp profile list
Feature Not Enabled
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
Error: invalid server value: myserverSolution: Ensure server references use either:
docker://prefix for imageshttp://orhttps://for registry URLscatalog://prefix for catalog referencesfile://prefix for local server definition files
Conflicting Flags
Error: cannot use --profile with --servers flagSolution: Choose either --profile or --servers, not both
ID Already Exists
Error: profile with id my-set already existsSolution: Either:
- Choose a different name/ID
- Remove the existing set first with
docker mcp profile rm my-set - Omit the
--idflag to auto-generate a unique ID
Export/Import File Format
Error: unsupported file extension: .txt, must be .yaml or .jsonSolution: Use .yaml or .json file extensions
Invalid Config Format
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
Error: server github not found in profileSolution:
- Use
docker mcp profile showto 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
Error: cannot both delete and set the same config value: github.timeoutSolution: Don't use --set and --del for the same key in a single command. Run them separately:
# First delete
docker mcp profile config my-set --del github.timeout
# Then set (if needed)
docker mcp profile config my-set --set github.timeout=60Server Not Found in Catalog
Error: server 'nonexistent' not found in catalogSolution:
- 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
Error: server 'github' not found in profileSolution:
- Use
docker mcp profile show --format yamlto 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
Error: invalid tool specification: githubSolution: Tool names must use dot notation with both server and tool name:
# Wrong
docker mcp profile tools my-profile --enable github
# Correct
docker mcp profile tools my-profile --enable github.create_issueServer Not Found When Managing Tools
Error: server 'github' not found in profileSolution:
- Ensure the server with that snapshot name exists in the profile:
docker mcp profile show --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 --server docker://my-org/my-server
Tool Not Found in Server
Error: tool 'invalid_tool' not found in server 'github'Solution:
- Use
docker mcp profile show --format yamlto 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
--formatflag:human(default),json, oryaml
๐ก Tip: You can import Docker's official MCP catalog as a starting point:
docker mcp catalog create docker-mcp-catalog \
--from-legacy-catalog https://desktop.docker.com/mcp/catalog/v3/catalog.jsonThis 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 - Running the MCP gateway
- Catalog Management - Managing MCP server catalogs
- Feature Management - Enabling/disabling features
- Security - 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 requestdisableNetwork, 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
sseorstreamingtransports without--allow-unauthenticated. - A browser request with a non-localhost
Origincan 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-execcan 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 anOriginheader
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
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:443Server 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
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_nameExample 2: Array Type Configuration
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:
- pathsExample 3: Nested Object Properties
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:
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:
nametype: "server"image
Example:
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:443Type: "remote"
An MCP server hosted remotely and accessed via HTTP/SSE protocol.
Required fields:
nametype: "remote"remote.url
Example:
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.icoBest Practices
- Naming: Use lowercase, hyphen-separated names (e.g.,
github-official,aws-core-mcp-server) - 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)
- Security:
- Use
allowHoststo restrict network access - Use
disableNetwork: truefor tools that don't need network - Always use secrets for credentials, never hardcode in
env
- Use
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:
docker mcp gateway run --verbose --dry-runThis 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:
docker mcp gateway run --verbose --dry-run --servers=duckduckgoDebug 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:
# 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=DockerA 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:
# 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:
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 enforcesThose 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, orif/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:
# Enable dynamic tools feature
docker mcp feature enable dynamic-tools
# Check if enabled
docker config view | grep dynamic-toolsWhen 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:
{
"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:
{
"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:
{
"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:
{
"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 configurekey(required): Configuration key to setvalue(required): Configuration value to set (can be string, number, boolean, or object)
Example Usage:
{
"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:
- Fetches required secrets: Calls
readDockerDesktopSecrets()with the updated server list - Updates configuration: Replaces the existing secrets map with newly fetched secrets
- 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
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:#f3e5f5Feature Flag System
# 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
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 resultsImplementation: VectorDBClient
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
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/servermcp-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 initEmbeddings Client Lifecycle
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 stopsData Flow: Semantic Search
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:#e8f5e9Benefits
โ 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:
make docker-mcp
make lintEnable Feature:
docker mcp feature enable use-embeddings
export OPENAI_API_KEY="sk-..."
docker mcp gateway runTest Search:
# 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 handlerpkg/gateway/findtools.go- Embedding generationpkg/gateway/run.go- Client initializationpkg/gateway/config.go- UseEmbeddings flagcmd/docker-mcp/commands/feature.go- Feature registrationcmd/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
- Enable User-Managed Catalogs: Allow users to create custom catalogs that automatically work with the gateway
- Maintain Docker Desktop Compatibility: Ensure existing Docker Desktop integration remains unchanged
- Progressive Enhancement: Provide opt-in feature activation with safe defaults
- Unified User Experience: Eliminate the need for manual
--catalogflags in typical usage
Secondary Goals
- Discoverability: Make catalog management commands visible to users
- Clear Precedence: Define predictable catalog merge behavior when servers conflict
- Comprehensive Logging: Provide visibility into catalog loading and conflicts
- 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.
# 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-queryUS2: 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.
# 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-catalogsUS3: Production Server Management
As a DevOps engineer, I want to combine official Docker servers with our production-specific servers in a single gateway instance.
# 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-catalogsUS4: 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.
# 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.
# 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.yamlUS6: Docker Desktop Compatibility
As a Docker Desktop user, I want the existing catalog functionality to continue working without any changes to my workflow.
# 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.jsoninfeaturesobject - Activation:
docker mcp feature enable configured-catalogs - Validation: Gateway commands validate feature enablement before using configured catalogs
FR2: Gateway Integration
- New Flag:
--use-configured-catalogsfordocker 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:
- Built-in Gateway catalogs (future expansion point)
- Docker official catalog (
docker-mcp.yaml) - User configured catalogs (from catalog management system) [if
--use-configured-catalogs] - CLI-specified catalogs (
--catalogand--additional-catalogflags)
FR4: Command Visibility
- Unhide Commands: Remove
Hidden: truefrom 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 --helpshows 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 runremains 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 mergedImplementation Components
1. Feature Management Commands
New Commands:
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 statusImplementation: 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
dockerhubanddockerserver 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:
# 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.yamlImplementation Strategy:
- Config Loading: Call
ReadConfigWithDefaultCatalog(ctx)to load Docker catalog config - YAML Reading: Call
ReadCatalogFile("docker-mcp")to get raw catalog YAML - Struct Parsing: Unmarshal YAML to
Registrystruct for Go data access - Server Extraction: Extract
registry.Registry["dockerhub"]andregistry.Registry["docker"]entries - Bootstrap Generation: Create new
Registrystruct with only extracted servers - 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:
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:
func Get(ctx context.Context) (Catalog, error) {
return ReadFrom(ctx, []string{"docker-mcp.yaml"})
}New:
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:
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:
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-mcpcatalog - User Catalog Only: Only export catalogs that exist in
~/.docker/mcp/catalogs/ - File Validation: Ensure target catalog exists before attempting export
Usage Examples:
# 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).yaml6. 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/filesexport.go- Export user catalogs to files (new command)create.go- Create empty local catalogsadd.go- Add servers to catalogsfork.go- Duplicate existing catalogsrm.go- Remove catalogs
Enhanced Help Text: Reference feature flag requirement in command descriptions.
Container Mode Support
Volume Mount Requirement:
# 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-catalogsEnhanced Error Handling:
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
- Feature Flag Validation: Test enabled/disabled/missing scenarios
- Catalog Loading: Test precedence order and conflict resolution
- Error Handling: Test config inaccessible, malformed catalogs
- Container Mode: Test behavior without volume mounts
Key Test Cases
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
- End-to-End Workflow: Create catalog โ Add server โ Enable feature โ Run gateway โ Verify server availability
- Docker Desktop Compatibility: Verify existing workflows unchanged
- Multi-Catalog Conflicts: Test server override behavior across catalogs
- 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)
- Add Feature Management: Implement
docker mcp featurecommands - Enhance Gateway: Add
--use-configured-catalogsflag with validation - Update Catalog Loading: Implement precedence-based catalog merging
- Unhide Commands: Make catalog CRUD commands visible
- Comprehensive Testing: Unit and integration test coverage
Phase 2: Documentation and User Communication
- User Documentation: Update CLI reference and tutorials
- Migration Guide: Document feature enablement and workflows
- Release Notes: Highlight new capability and backward compatibility
- Community Communication: Blog post explaining enhanced catalog management
Phase 3: Future Enhancements (Optional)
- Docker Desktop Integration: UI for managing custom catalogs
- Catalog Signing: Implement signature verification for remote catalogs
- Default Feature: Consider making configured catalogs default in future major version
- 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-catalogsfeature activation - Command Usage: Monitor usage of previously hidden catalog commands
- Gateway Usage: Track
--use-configured-catalogsflag 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
- Default Behavior: Should configured catalogs eventually become the default (breaking change)?
- Catalog Validation: What level of validation should be applied to imported catalogs?
- Performance Optimization: Should catalog loading be cached between gateway runs?
- 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
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/:
# 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 flagsTDD Development Process
CRITICAL: Follow this exact workflow with progressively broader scope:
1. Red Phase - Write Failing Tests First
# 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 functionality2. Green Phase - Make Tests Pass
# Write minimal implementation to make tests pass
go test ./cmd/docker-mcp/commands # Test same package again
# Should show all tests passing in that package3. Package Integration Test
# Test all related packages together
go test ./cmd/docker-mcp/... # Test entire cmd tree
# Should show all tests passing across packages4. Full System Test
# Test the entire system
make test
# Should show all tests passing system-wide5. Build Phase - Verify Compilation
# Only build after all tests pass
make docker-mcp
# Should build successfully and install to ~/.docker/cli-plugins/docker-mcp6. Manual Verification
# Test the actual CLI functionality
./dist/docker-mcp [your-new-command] --help
# Verify your changes work as expected7. Refactor Phase (Optional)
# Improve code while keeping tests green
go test ./path/to/package # Test specific package after changes8. Lint Phase (End of Implementation Only)
# Only run linting when feature is complete
make lint-darwin
# Should show 0 issuesTest Categories & Strategy
Unit Tests (Primary Focus)
- Location: Tests should be in
*_test.gofiles 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.goand similar - Speed: Slower (requires Docker daemon)
- Focus: End-to-end command workflows
- Note: Some are skipped in normal
make testruns
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
- Test First: Always write tests before implementation
- Small Steps: Implement one small piece at a time
- Green Tests: Never commit with failing tests
- Build Validation: Only build after tests pass
- Manual Check: Always verify CLI behavior manually
- Lint Last: Only run linting when implementation is complete
Error Handling Strategy
Test Failures
make test
# If tests fail, fix the code, don't skip testsBuild Failures
make docker-mcp
# If build fails, check compilation errors and fix
# Don't proceed to manual testing until build succeedsLint Failures (End of Development)
make lint-darwin
# Fix all linting issues before marking feature completeBaseline Verification โ
The following baseline tests have been verified to work:
make docker-mcp- Builds successfullymake test- All existing tests passmake 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
# 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 successfullyQuick 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
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 namesCreate feature command structure โ COMPLETED
- File:
cmd/docker-mcp/commands/feature.go - Commands:
enable <feature>,disable <feature>,list - Target:
~/.docker/config.jsonโfeatures.configured-catalogs
- File:
๐งช TEST FIRST: cmd/docker-mcp/commands/feature_test.go (validation utilities) โ
COMPLETED
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 corruptedFeature validation utilities โ COMPLETED
- Function:
isFeatureEnabled(dockerCli command.Cli, feature string) bool - Handle missing config file gracefully
- Support container mode detection
- Function:
Integration with root command โ COMPLETED
- Add feature command to
cmd/docker-mcp/commands/root.go - Ensure proper dockerCli context passing
- Add feature command to
1.2 Gateway Command Enhancement โ COMPLETED
๐งช TEST FIRST: cmd/docker-mcp/commands/gateway_test.go โ
COMPLETED
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 usedAdd --use-configured-catalogs flag โ COMPLETED
- File:
cmd/docker-mcp/commands/gateway.go - Flag:
--use-configured-catalogs(boolean) - Validation: Check feature flag before allowing flag usage
- File:
Feature validation integration โ COMPLETED
- PreRunE validation for feature flag requirement
- Clear error messages with exact enable command
- Container mode detection and helpful errors
Pass flag to catalog system โ COMPLETED
- Update
catalog.Get()call site - Pass useConfigured boolean parameter
- Update
1.3 Catalog Loading Enhancement โ COMPLETED
๐งช TEST FIRST: cmd/docker-mcp/internal/catalog/catalog_test.go โ
COMPLETED
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 orderUpdate catalog.Get() signature โ COMPLETED
- File:
cmd/docker-mcp/internal/catalog/catalog.go - New function:
GetWithOptions(ctx context.Context, useConfigured bool, additionalCatalogs []string) (Catalog, error) - Backward compatibility: Keep current
Get()for existing callers
- File:
Implement getConfiguredCatalogs() โ COMPLETED
- Read from
~/.docker/mcp/catalog.json - Return list of catalog file names
- Handle missing/corrupted catalog registry gracefully
- Read from
Implement catalog precedence logic โ COMPLETED
- Order: Docker โ Configured โ CLI-specified
- Use existing
ReadFrom()function with ordered list - 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
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() behaviorValidate ReadFrom() logging โ COMPLETED
- File:
cmd/docker-mcp/internal/catalog/catalog.go - Existing warning messages for server conflicts confirmed working
- Server-level precedence correctly implemented
- File:
Server conflict handling โ COMPLETED
- Confirmed server-level replacement prevents tool mixing issues
- "Last wins" precedence behavior validated as architecturally correct
- Gateway tool flattening works properly with resolved servers
1.5 Export Command Implementation โ COMPLETED
๐งช TEST FIRST: cmd/docker-mcp/commands/export_test.go โ
COMPLETED
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 errorsCreate export command โ COMPLETED
- File:
cmd/docker-mcp/catalog/export.go(new) - Command:
export <catalog-name> <file-path> - Protection: Prevent export of
docker-mcpofficial catalog
- File:
Export functionality โ COMPLETED
- Read catalog from
~/.docker/mcp/catalogs/{name}.yaml - Validate catalog exists and is user-managed
- Support for custom output file path
- Read catalog from
Error handling โ COMPLETED
- Clear error for attempting to export official Docker catalog
- Helpful error when catalog doesn't exist
- File system permission error handling
1.6 Command Visibility Updates โ COMPLETED
๐งช TEST FIRST: Command visibility validated through CLI help output โ COMPLETED
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 catalogUnhide catalog CRUD commands โ COMPLETED
- Files:
cmd/docker-mcp/commands/catalog.go - Removed
Hidden: truefrom all command definitions - All catalog management commands now user-visible
- Files:
Update command descriptions โ COMPLETED
- Export command includes clear protection messaging
- Help text explains user-managed vs Docker catalog distinction
Phase 2: Testing & Validation โ COMPLETED
2.1 Unit Tests โ COMPLETED
Feature flag validation tests โ COMPLETED
- Test enabled/disabled/missing scenarios (4 test cases)
- Test Docker CLI integration
- Test container mode behavior
Catalog loading tests โ COMPLETED
- Test precedence order with multiple catalogs (6 test cases)
- Test conflict resolution logging with warning messages
- Test graceful failure handling for missing/corrupt registry
Export command tests โ COMPLETED
- Test successful export of user catalogs
- Test prevention of Docker catalog export
- Test catalog not found scenarios
- Test file permission error handling
Gateway integration tests โ COMPLETED
- Test flag validation (5 test cases)
- Test feature flag gating with clear error messages
- Test container mode detection and guidance
2.2 Integration Tests โ COMPLETED
End-to-end workflow tests โ COMPLETED
- All test suites pass in container environment
- Binary builds and installs successfully as Docker CLI plugin
- All commands visible and functional in CLI help
Docker Desktop compatibility tests โ COMPLETED
- Verified
docker mcp gateway runbehavior unchanged (backward compatibility) - Verified existing catalog commands work as expected
- No regression in Docker Desktop workflow
- Verified
Container mode tests โ COMPLETED
- Tests pass in Docker container environment (
make test) - Feature flag validation works in container mode
- Clear error messages for missing config scenarios
- Tests pass in Docker container environment (
2.3 Manual Testing Scenarios โ COMPLETED
Development workflow testing โ COMPLETED
- Feature enable/disable cycle verified working
- All catalog commands now visible in
docker mcp catalog --help - Export command protection working correctly
- Binary installation to
~/.docker/cli-plugins/docker-mcpsuccessful
Multi-catalog testing โ COMPLETED
- Server-level precedence correctly implemented and tested
- Warning logging for overlapping servers verified working
- 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
- Write tests for bootstrap commandgo
// 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:
- Config loading: Call
ReadConfigWithDefaultCatalog(ctx)to load Docker catalog - YAML reading: Call
ReadCatalogFile("docker-mcp")to get raw catalog YAML - Struct parsing: Unmarshal to
Registrystruct for Go data access - Server extraction: Extract
registry.Registry["dockerhub"]andregistry.Registry["docker"] - Bootstrap generation: Create new
Registrywith only extracted servers - File creation: Marshal to YAML and write standalone catalog file
Expected User Workflow:
# 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.yamlImplementation Tasks: โ ALL COMPLETED
Create bootstrap command โ COMPLETED
- File:
cmd/docker-mcp/commands/bootstrap.go(new) - Command:
bootstrap <output-file-path> - Internal calls to
ReadConfigWithDefaultCatalog()andReadCatalogFile()
- File:
Bootstrap functionality โ COMPLETED
- File:
cmd/docker-mcp/catalog/bootstrap.go(new) - Extract Docker and DockerHub entries from live catalog using YAML parsing
- Generate properly formatted YAML catalog structure with extracted servers
- File overwrite protection with clear error messages
- File:
Error handling โ COMPLETED
- Validate output path is writable with directory creation
- Handle Docker catalog access failures gracefully
- Clear error messages for file conflicts and missing servers
Integration with catalog command โ COMPLETED
- Added bootstrap command to
cmd/docker-mcp/commands/catalog.go - Comprehensive help text and examples
- Full CLI integration and visibility
- Added bootstrap command to
End-to-End Validation: โ COMPLETED
- Bootstrap file creation: Successfully creates YAML with Docker and DockerHub servers
- Catalog add integration: Bootstrap file works as source for
catalog addcommand - Server extraction: Individual servers can be copied from bootstrap file to catalogs
- Export roundtrip: Full workflow (bootstrap โ add โ export) validated
- 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 โ
- Architecture Investigation: Complete understanding of existing systems
- Git Blame Analysis: Identified key contributors and implementation timeline
- Docker Desktop Integration: Understood compatibility requirements
- Binary Distribution Analysis: Confirmed feature flag system works across all modes
- Feature Flag Research: Identified Docker CLI
featuressystem as perfect solution - Implementation Planning: Complete technical design and user workflows
- Feature Specification: Comprehensive spec document created
- 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-catalogsfeature and use custom catalogs alongside Docker's official catalog with full CLI management capabilities - New users can quickly get started with the
bootstrapcommand to understand catalog format and create starter files with real Docker server examples
Key Implementation Notes
Critical Success Factors
- Maintain Docker Desktop Compatibility: Never change default behavior of
docker mcp gateway run - Feature Flag Gating: All new functionality MUST be gated behind
configured-catalogsfeature - Graceful Degradation: System must work properly when config is inaccessible
- Clear User Communication: Error messages must provide exact commands to fix issues
Technical Constraints
- Backward Compatibility: All existing command signatures and behaviors preserved
- Container Support: Feature must work in container mode with proper volume mounts
- Performance: Catalog loading must not significantly impact gateway startup time
- Security: No privilege escalation or unsafe file operations
Architecture Decisions Made
- Feature Flag System: Use Docker CLI's existing
featuresconfig approach - Catalog Precedence: Last-loaded-wins for server conflicts (Docker โ Configured โ CLI)
- Command Structure: Add
--use-configured-catalogsflag rather than change defaults - 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
- Read the feature spec: Start with
feature-spec.mdfor complete context - Check current status: Review completed items in this checklist
- Start implementation: Begin with Phase 1.1 (Feature Management System)
- Test thoroughly: Each component must work in plugin, standalone, and container modes
- Maintain compatibility: Docker Desktop behavior must never change
Key Commands to Validate Success:
# 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 |
Manage MCP server catalogs |
client |
Manage MCP clients |
config |
Manage the configuration |
feature |
Manage experimental features |
gateway |
Manage the MCP Server gateway |
oauth |
Manage OAuth app authorizations |
secret |
Manage secrets in the local OS Keychain |
server |
Manage servers |
tools |
Manage tools |
version |
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 and
the public GitHub repository.
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 |
Add a server to a catalog |
bootstrap |
Create a starter catalog file with Docker and Docker Hub server entries as examples |
create |
Create a new empty catalog |
export |
Export a configured catalog to a file |
fork |
Create a copy of an existing catalog |
import |
Import a catalog from URL or file |
init |
Initialize the catalog system |
ls |
List all configured catalogs |
reset |
Reset the catalog system |
rm |
Remove a catalog |
show |
Display catalog contents |
update |
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 |
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 |
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 |
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 |
Read the configuration |
reset |
Reset the configuration |
write |
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 |
Disable an experimental feature |
enable |
Enable an experimental feature |
ls |
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
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 |
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 |
Authorize the specified OAuth app. |
ls |
List available OAuth apps. |
revoke |
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 |
Dump the policy content |
set |
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 |
List all secrets from the local OS Keychain as well as any active Secrets Engine provider |
rm |
Remove secrets from the local OS Keychain |
set |
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
echo my-secret-password | docker mcp secret set postgres_passwordGenerator Reference Mcp Server (`docs/generator/reference/mcp_server.md`)
docker mcp server
Manage servers
Subcommands
| Name | Description |
|---|---|
disable |
Disable a server or multiple servers |
enable |
Enable a server or multiple servers |
init |
Initialize a new MCP server project |
inspect |
Get information about a server or inspect an OCI artifact |
ls |
List enabled servers |
reset |
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 |
Call a tool |
count |
Count tools |
disable |
disable one or more tools |
enable |
enable one or more tools |
inspect |
Inspect a tool |
ls |
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