← back to knowledge-hub

Docker MCP Toolkit: Catalogs, Profiles, and the Gateway

I had the GitHub MCP server configured four times. Once in Claude Code, once in VS Code, once in Cursor, once in Claude Desktop. Four JSON files, four copies of the same personal access token, and four slightly different npx versions — because each client had pulled the package on a different day. When the token rotated, I found out which clients I’d forgotten by watching them fail.

Docker MCP Toolkit fixes this by pulling MCP servers out of the individual clients. Servers run as containers and are grouped into profiles. Every client talks to one process, the MCP Gateway. You configure a server once, store its secret once, and every client that points at the profile gets the same tools.

This post is about the ideas: what the four parts are — catalogs, profiles, the gateway, and clients — and why they’re shaped the way they are. The hands-on CLI walkthrough is in the companion post, Docker MCP Toolkit CLI: Commands You’ll Actually Use.

The Mental Model

Here’s the one diagram that makes the rest click:

Docker MCP Toolkit architecture: catalogs of verified and custom servers feed named profiles like web-dev, which connect to clients such as Claude Code, OpenCode, and Zed Source: Docker documentation

  • Catalog — the library. It lists the MCP servers you can use: Docker’s official catalog, or a custom one your org curates.
  • Profile — the toolbox. It’s a named set of servers you do use, plus their config and a per-tool allowlist.
  • Gateway — the runtime. It’s one MCP server that starts server containers on demand, injects credentials, and routes tool calls.
  • Client — Claude Code, VS Code, Cursor, Zed, and so on. Each one sees a single MCP server called MCP_DOCKER.

Notice the arrows go one way. Clients never talk to individual servers. That one fact is where most of the Toolkit’s value comes from.

Enabling the Toolkit

The Toolkit ships with Docker Desktop and is still labelled Beta. On Docker Desktop 4.62+, go to Settings → Beta features, tick Enable Docker MCP Toolkit, and select Apply.

That adds an MCP Toolkit page to Desktop with three tabs — Catalog, Profiles, and Clients — which line up with the components below. It also installs the docker mcp CLI plugin, which the companion post covers.

Component 1: The Catalog

The Docker MCP Catalog is a curated set of MCP servers — 314 of them when I last checked. Each is either packaged as a Docker image or points to a hosted remote endpoint. Docker builds and signs the images under the mcp/ namespace and ships each with an SBOM, so provenance comes built in rather than being something you check afterwards.

The catalog holds two kinds of server:

TypeRuns whereExampleAuth
Local (image)A container on your machineSequential Thinking, PlaywrightSecrets from the OS keychain
RemoteThe provider’s infrastructureContext7, GitHub, Notion, LinearAPI key or OAuth (handled by the Toolkit)

Local servers keep working offline once the image is pulled, and your data stays on your machine. Remote servers trade that for zero local footprint. The nice part is that a profile can mix both, and the client never knows which is which.

A server can come from more places than Docker’s catalog, too: any Docker image that speaks MCP, the community MCP registry, or a local YAML definition. That matters for teams — your internal MCP server becomes just another image in your registry.

Custom catalogs

314 servers is great for exploring and a lot to vet for an enterprise. Custom catalogs let a platform team publish an approved subset, plus their own private servers, as an OCI artifact. Developers import it in Desktop (Catalog → Import catalog), and the gateway can be locked to it so nothing outside the list is reachable.

Component 2: Profiles

A profile is a named collection of servers with their configuration. Think web-dev (GitHub + Playwright), data (Postgres + a charting server), research (Context7 + Sequential Thinking). Different clients can connect to different profiles at the same time.

If you’re upgrading from an older Toolkit, your existing servers were migrated into a profile called default.

In Desktop, you create one from MCP Toolkit → Profiles → Create profile, then fill it from the Catalog tab: tick servers, select Add to, and pick the profile. Servers that need setup show a Configuration Required badge until you fill in their settings.

Opening a profile gives you two tabs:

  • Overview — its servers, their secrets, and which clients are connected.
  • Tools — every tool the profile exposes, each with its own toggle.

Tool allowlists: the feature I didn’t know I needed

That Tools tab is easy to skip past. Don’t. You can switch off individual tools, not just whole servers, and this matters more than it sounds. Every tool definition takes up context-window tokens, and some tools (delete_repository, anyone?) you never want an agent to call. A GitHub server with dozens of tools becomes the three read-only ones you actually use.

Secrets and OAuth

Secrets don’t live in the profile. They live in your OS keychain (Windows Credential Manager, macOS Keychain), and the gateway injects them only when a tool is called. The value never appears in any client config file.

Remote servers that use OAuth — GitHub, Notion, Linear — get a browser-based authorize flow from the server’s Configuration tab. You can revoke access at any time from the OAuth tab.

One caveat: OAuth credentials are shared across all profiles. If your work and personal profiles both use the GitHub remote server with different accounts, you have to re-authorize when you switch. That’s by design, but it catches people out.

Sharing profiles

Profiles are shareable in two ways. You can push one to any OCI registry and version it like an image. Or you can export it to a file and commit it next to your code, so anyone who clones the repo can import the same toolbox.

Either way, credentials are never included. Each teammate sets their own secrets and OAuth. The export does include a full snapshot of each server — tool schemas, pinned image digests, and secret names (not values) — so review the diff before committing, the same as you would for a lockfile.

It’s a lot like how dev containers standardised the build environment. This standardises the agent’s toolbox.

Component 3: The MCP Gateway

The MCP Gateway is the open-source part that does the actual work. It runs in the background whenever the Toolkit is enabled. When a client calls a tool, the gateway:

  1. works out which server owns that tool,
  2. starts the server’s container if it isn’t running,
  3. injects credentials and applies security restrictions,
  4. forwards the request and returns the result.

The security model

Step 3 is the interesting one. When I watched the gateway start up, every local server was launched with the same set of restrictions:

  • Thrown away after use — no state builds up between calls.
  • No privilege escalation inside the container.
  • 1 CPU and 2 GB of memory per server — a runaway server can’t take over your machine.
  • Image pinned by digest and signature-verified — you run exactly what Docker signed.
  • No host filesystem access unless you explicitly grant a mount for that server.
  • Secrets intercepted — requests carrying sensitive data are blocked before they reach a tool.

Compare that with npx some-mcp-server, which runs with your full user permissions, your whole home directory, and whatever version npm resolved that morning.

Security note: The gateway normally talks to clients over stdio, which is only reachable by the local process that launched it. It can also serve over HTTP. If you go that route, keep it bound to localhost with its auth token enabled. A gateway exposed on a shared network is a remote-code-execution endpoint with your credentials attached.

Dynamic MCP: agents that install their own tools

Next to your profile’s tools, the gateway also exposes a few management tools — mcp-find, mcp-add, mcp-remove, mcp-config-set, and an experimental code-mode. This is Dynamic MCP, and it’s on by default.

So you can ask your agent “What MCP servers can I use for working with SQL databases?”, then “Add the postgres mcp server”, and it will. Servers added this way last only for the session. They aren’t saved to the profile.

It’s handy. It’s also an agent choosing which third-party code to run on your machine. The container sandbox limits the damage, but if that bothers you (it should, a little), lock the gateway to a curated custom catalog. Then the agent can only find what your team has approved.

Component 4: Clients

From the client’s side, the whole Toolkit is one stdio MCP server named MCP_DOCKER, launched with a profile name. That’s it. To switch toolboxes, a client changes which profile it asks for — nothing else about its config changes.

For supported clients — Claude Code, Claude Desktop, VS Code, Cursor, Zed, Codex, Gemini CLI, Goose, LM Studio, and more — the Clients tab in Desktop has a Connect button that writes the config for you. Anything else can be wired up by hand with a few lines of JSON.

VS Code extensions view showing MCP_DOCKER installed as a stdio MCP server Source: Docker documentation

Claude Desktop tools menu with the MCP_DOCKER connector toggled on Source: Docker documentation

Once it’s connected, test it with a prompt that needs one of your servers — “Use the GitHub MCP server to show me my open pull requests” works well in Claude Code.

Gotchas I Hit

  • A profile’s ID isn’t always its name. Hyphens in the name become underscores in the ID. Use underscores from the start.
  • OAuth is global across profiles. Two GitHub accounts means re-authorizing when you switch.
  • Project-level client config is per-user. VS Code’s generated .vscode/mcp.json belongs in .gitignore. Commit the exported profile instead.
  • Heavy servers hit the 2 GB cap. Browser automation servers may need more memory.
  • Beta means beta. The UI changed a lot in Desktop 4.62, so older tutorials (and screenshots) may not match what you see.

Wrapping Up

Going back to my four-copies-of-a-token problem: I now have one secret in the keychain, two profiles (web_dev and research), and every client points at the gateway with a profile name. When a token rotates, I update it in one place. When a server updates, I update it once, pinned by digest and signature-verified. And every tool call runs in a throwaway container with a CPU and memory cap, not with my full user permissions.

Ready to set it up? The companion post, Docker MCP Toolkit CLI: Commands You’ll Actually Use, has every command for profiles, servers, secrets, the gateway, and custom catalogs.

Next, I want to package one of my own .NET tools as an MCP server image and publish it through a custom catalog. Stay tuned.

Further Reading

graph cloud Password Playground Speed Reader Lead Manager Job Copilot Universe Explorer Surya Siddhanta SettleUp