Skip to content

v0.43.1

Pre-release
Pre-release

Choose a tag to compare

@docker-read-write docker-read-write released this 25 Jun 22:28
8f422b6

What changed

Remote URL handling is stricter by default

Remote MCP servers, OAuth discovery/DCR/token flows, catalog fetches, README fetches, and MCP registry imports now use a guarded URL path. By default, remote URLs must be public https:// destinations. The gateway rejects unsafe targets such as loopback, private networks, link-local addresses, metadata services, cluster-local names, URLs with userinfo, and unsafe redirects.

Docker Desktop's trusted local proxy socket is still supported when available. Generic proxy settings from the environment are not used for guarded remote URL paths because they can hide the final destination from client-side validation.

HTTP gateway transports require authentication

SSE and streaming gateway transports now require Bearer-token authentication by default, including when the gateway runs in a container. The /health endpoint remains available without authentication.

Use MCP_GATEWAY_AUTH_TOKEN to provide the token clients should send:

MCP_GATEWAY_AUTH_TOKEN=your-token docker mcp gateway run --transport=sse --port=8811

Clients should send:

Authorization: Bearer your-token

To intentionally disable HTTP authentication, pass --allow-unauthenticated. The gateway warns when this is used on an externally reachable listener.

Local catalog and file inputs must live under the catalog directory

Local catalog paths passed through --catalog or --additional-catalog must now resolve under:

~/.docker/mcp/catalogs

The same trusted-root rule applies to file:// server references used by profile and catalog commands. Symlinks are resolved before the trusted-root check, so symlinks cannot be used to escape the catalog directory.

Move custom local catalog and server files into ~/.docker/mcp/catalogs, then reference them by name or with a catalog-root-relative file:// path:

docker mcp gateway run --catalog team-catalog.yaml
docker mcp profile create --name dev-tools --server file://servers/github.yaml

Absolute paths or ./ paths outside ~/.docker/mcp/catalogs are rejected.

Docker bind mounts are validated before containers start

Host-path bind mounts configured for MCP server containers are now checked before Docker is invoked. Host binds must be read-only and must resolve under an allowed root. By default, temporary directories are allowed. Additional trusted roots can be configured with MCP_GATEWAY_DOCKER_BIND_ALLOWED_PATHS.

Named volumes continue to work. Writable host binds, relative host paths, sensitive system paths, Docker socket binds, and credential directories such as .ssh, .docker, .kube, .aws, and .gnupg are blocked.

Example:

MCP_GATEWAY_DOCKER_BIND_ALLOWED_PATHS=/Users/alice/project-data docker mcp gateway run

MCP server catalog entries should use read-only bind modes for host paths:

volumes:
  - /Users/alice/project-data:/data:ro

Docker MCP images are verified before pull

docker mcp gateway run now verifies Docker Hub mcp/... server image signatures before pulling images. Dynamic server add and profile activation paths use the same verification flow.

When signature verification is enabled, Docker MCP images must be pinned by digest:

image: mcp/time@sha256:...

Mutable Docker MCP tags such as mcp/time:latest are rejected by default. Non-mcp/... third-party images are pulled without Docker MCP signature verification. For local development or explicitly unverified images, use:

docker mcp gateway run --verify-signatures=false

The gateway logs a warning when signature verification is disabled.

Tool names can no longer shadow each other

The gateway now rejects exposed tool names that collide across servers or shadow reserved gateway tools such as mcp-exec. mcp-add returns an explicit collision error, and catalog search results can warn about risky tool names.

If a collision is reported, enable the tool-name prefix feature or update catalog metadata so each exposed tool name is unique. Explicit catalog prefix values resolve collisions for image and remote MCP servers; POCI-style catalog tools should use unique exposed names or the global tool-name-prefix feature.

Prompts and resources can no longer shadow each other

The gateway now rejects duplicate prompt names, resource URIs, and resource-template URI templates before registering capabilities. This prevents one server from silently replacing another server's prompt or resource inside the MCP SDK.

When dynamic tools are enabled, the gateway also reserves the mcp-discover prompt name for its own discovery prompt. mcp-add reports a clear collision error if a dynamically added server would shadow an existing prompt, resource, or resource template.

If a collision is reported, disable one of the conflicting servers or update the server/catalog so prompt names, resource URIs, and resource-template URI templates are unique.

Tool call logs no longer include raw argument values

When tool call logging is enabled, the gateway logs argument shape metadata instead of raw argument values. Secret blocking also runs before built-in tool call logging, so secret-shaped arguments are blocked before they can be logged.

Action required

  • Update HTTP/SSE/streaming clients to send Authorization: Bearer <token>, or pass --allow-unauthenticated only when unauthenticated access is intentional.
  • Move local catalogs and file:// server files into ~/.docker/mcp/catalogs.
  • Replace writable or broad host-path bind mounts with read-only binds under trusted roots, and configure MCP_GATEWAY_DOCKER_BIND_ALLOWED_PATHS for approved non-temporary directories.
  • Pin Docker MCP mcp/... images by digest, or explicitly disable verification for development-only flows.
  • Rename or prefix tools if the gateway reports a tool-name collision.
  • Rename or disable servers that expose duplicate prompt names, resource URIs, or resource-template URI templates. Avoid using mcp-discover as a server prompt name when dynamic tools are enabled.
  • For local HTTP or loopback remote MCP development, set DOCKER_MCP_ALLOW_INSECURE_REMOTE_URLS=1. Do not use that setting for production.