{"id":2644,"date":"2025-10-24T19:24:44","date_gmt":"2025-10-24T19:24:44","guid":{"rendered":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/2025\/10\/24\/your-org-your-tools-building-a-custom-mcp-catalog\/"},"modified":"2025-10-24T19:24:44","modified_gmt":"2025-10-24T19:24:44","slug":"your-org-your-tools-building-a-custom-mcp-catalog","status":"publish","type":"post","link":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/2025\/10\/24\/your-org-your-tools-building-a-custom-mcp-catalog\/","title":{"rendered":"Your Org, Your Tools: Building a Custom MCP Catalog"},"content":{"rendered":"<p>I\u2019m Mike Coleman, a staff solutions architect at Docker. In this role, I spend a lot of time talking to enterprise customers about AI adoption. One thing I hear over and over again is that these companies want to ensure appropriate guardrails are in place when it comes to deploying AI tooling.\u00a0<\/p>\n<p>For instance, many organizations want tighter control over which tools developers and AI assistants can access via Docker\u2019s Model Context Protocol (MCP) tooling. Some have strict security policies that prohibit pulling images directly from Docker Hub. Others simply want to offer a curated set of trusted MCP servers to their teams or customers.<\/p>\n<p>In this post, we walk through how to build your own MCP catalog. You\u2019ll see how to:<\/p>\n<p>Fork Docker\u2019s official MCP catalog<\/p>\n<p>Host MCP server images in your own container registry<\/p>\n<p>Publish a private catalog<\/p>\n<p>Use MCP Gateway to expose those servers to clients<\/p>\n<p>Whether you\u2019re pulling existing MCP servers from Docker\u2019s MCP Catalog or building your own, you\u2019ll end up with a clean, controlled MCP environment that fits your organization.<\/p>\n<h2 class=\"wp-block-heading\"><strong>Introducing Docker\u2019s MCP Tooling<\/strong><\/h2>\n<p>Docker\u2019s MCP ecosystem has three core pieces:<\/p>\n<h3 class=\"wp-block-heading\"><strong>MCP Catalog<\/strong><\/h3>\n<p>A YAML-based index of MCP server definitions. These describe how to run each server and what metadata (description, image, repo) is associated with it. The <a href=\"https:\/\/hub.docker.com\/mcp\" target=\"_blank\">MCP Catalog<\/a> hosts over 220+ containerized MCP servers, ready to run with just a click.\u00a0<\/p>\n<p>The official docker-mcp catalog is read-only. But you can fork it, export it, or build your own.<\/p>\n<h3 class=\"wp-block-heading\"><strong>MCP Gateway<\/strong><\/h3>\n<p>The MCP Gateway connects your clients to your MCP servers. It doesn\u2019t \u201chost\u201d anything \u2014 the servers are just regular Docker containers. But it provides a single connection point to expose multiple servers from a catalog over HTTP SSE or STDIO.<\/p>\n<p>Traditionally, with X servers and Y clients, you needed X * Y configuration entries. MCP Gateway reduces that to just Y entries (one per client). Servers are managed behind the scenes based on your selected catalog.<\/p>\n<p>You can start the gateway using a specific catalog:<\/p>\n<p>docker mcp gateway run \u2013catalog my-private-catalog<\/p>\n<p>MCP Gateway is open source:<a href=\"https:\/\/github.com\/docker\/mcp-gateway\" target=\"_blank\"> https:\/\/github.com\/docker\/mcp-gateway<\/a><\/p>\n<div class=\"wp-block-ponyo-image\"><\/div>\n<p class=\"has-xs-font-size\">Figure 1: The MCP Gateway provides a single connection point to expose multiple MCP servers<\/p>\n\n<h3 class=\"wp-block-heading\"><strong>MCP Toolkit (GUI)<\/strong><\/h3>\n<p>Built into Docker Desktop, the <a href=\"https:\/\/hub.docker.com\/open-desktop?url=https:\/\/open.docker.com\/dashboard\/mcp\" target=\"_blank\">MCP Toolkit<\/a> provides a graphical way to work with the MCP Catalog and MCP Gateway. This allows you to:<\/p>\n<p>Access to Docker\u2019s MCP Catalog via a rich GUI<\/p>\n<p>Secure handling of secrets (like GitHub tokens)<\/p>\n<p>Easily enable MCP servers<\/p>\n<p>Connect your selected MCP servers with one click to a variety of clients like Claude code, Claude Desktop, Codex, Cursor, Continue.dev, and Gemini CLI<\/p>\n<h2 class=\"wp-block-heading\"><strong>Workflow Overview<\/strong><\/h2>\n<p>The workflow below will show you the steps necessary to create and use a custom MCP catalog.\u00a0<\/p>\n<p>The basic steps are:<\/p>\n<p>Export the official MCP Catalog to inspect its contents<\/p>\n<p>Fork the Catalog so you can edit it<\/p>\n<p>Create your own private catalog<\/p>\n<p>Add specific server entries<\/p>\n<p>Pull (or rebuild) images and push them to your registry<\/p>\n<p>Update your catalog to use your images<\/p>\n<p>Run the MCP Gateway using your catalog<\/p>\n<p>Connect clients to it<\/p>\n<h2 class=\"wp-block-heading\"><strong>Step-by-Step Guide: Creating and Using a Custom MCP Catalog<\/strong><\/h2>\n<p>We start by setting a few environment variables to make this process repeatable and easy to modify later.<\/p>\n<p>For the purpose of this example, assume we are migrating an existing MCP server (DuckDuckGo) to a private registry (<a href=\"http:\/\/ghcr.io\/mikegcoleman\" target=\"_blank\">ghcr.io\/mikegcoleman<\/a>). You can also add your own custom MCP server images into the catalog, and we mention that below as well.\u00a0<\/p>\n\n<div class=\"wp-block-syntaxhighlighter-code \">\nexport MCP_SERVER_NAME=&#8221;duckduckgo&#8221;<br \/>\nexport GHCR_REGISTRY=&#8221;ghcr.io&#8221;<br \/>\nexport GHCR_ORG=&#8221;mikegcoleman&#8221;<br \/>\nexport GHCR_IMAGE=&#8221;${GHCR_REGISTRY}\/${GHCR_ORG}\/${MCP_SERVER_NAME}:latest&#8221;<br \/>\nexport FORK_CATALOG=&#8221;my-fork&#8221;<br \/>\nexport PRIVATE_CATALOG=&#8221;my-private-catalog&#8221;<br \/>\nexport FORK_EXPORT=&#8221;.\/my-fork.yaml&#8221;<br \/>\nexport OFFICIAL_DUMP=&#8221;.\/docker-mcp.yaml&#8221;<br \/>\nexport MCP_HOME=&#8221;${HOME}\/.docker\/mcp&#8221;<br \/>\nexport MCP_CATALOG_FILE=&#8221;${MCP_HOME}\/catalogs\/${PRIVATE_CATALOG}.yaml&#8221;\n<\/div>\n<h3 class=\"wp-block-heading\">Step 1: Export the official MCP Catalog\u00a0<\/h3>\n<p>Exporting the official Docker MCPCatalog gives you a readable local YAML file listing all servers. This makes it easy to inspect metadata like images, descriptions, and repository sources outside the CLI.<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\ndocker mcp catalog show docker-mcp &#8211;format yaml &gt; &#8220;${OFFICIAL_DUMP}&#8221;\n<\/div>\n<h3 class=\"wp-block-heading\">Step 2: Fork the official MCP Catalog<\/h3>\n<p>Forking the official catalog creates a copy you can modify. Since the built-in Docker catalog is read-only, this fork acts as your editable version.<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\ndocker mcp catalog fork docker-mcp &#8220;${FORK_CATALOG}&#8221;<br \/>\ndocker mcp catalog ls\n<\/div>\n<h3 class=\"wp-block-heading\">Step 3: Create a new catalog<\/h3>\n<p>Now create a brand-new catalog that will hold only the servers you explicitly want to support. This ensures your organization runs a clean, controlled catalog that you fully own.<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\ndocker mcp catalog create &#8220;${PRIVATE_CATALOG}&#8221;\n<\/div>\n<h3 class=\"wp-block-heading\">Step 4: Add specific server entries<\/h3>\n<p>Export your forked catalog to a file so you can copy over just the entries you want. Here we\u2019ll take only the duckduckgo server and add it to your private catalog.<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\ndocker mcp catalog export &#8220;${FORK_CATALOG}&#8221; &#8220;${FORK_EXPORT}&#8221;<br \/>\ndocker mcp catalog add &#8220;${PRIVATE_CATALOG}&#8221; &#8220;${MCP_SERVER_NAME}&#8221; &#8220;${FORK_EXPORT}&#8221;\n<\/div>\n<h3 class=\"wp-block-heading\">Step 5: Pull (or rebuild) images and push them to your registry<\/h3>\n<p>At this point you have two options:<\/p>\n<p>If you are able to\u00a0pull from Docker Hub, find the image key for the server you\u2019re interested in by looking at the YAML file you exported earlier. Then pull that image down to your local machine. After you\u2019ve pulled it down, retag it for whatever repository it is you want to use.\u00a0<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\nExample for duckduckgo\n<p>vi &#8220;${OFFICIAL_DUMP}&#8221; # look for the duckduck go entry and find the image: key which will look like this:<br \/>\n# image: mcp\/duckduckgo@sha256:68eb20db6109f5c312a695fc5ec3386ad15d93ffb765a0b4eb1baf4328dec14f<\/p>\n<p># pull the image to your machine<br \/>\ndocker pull <br \/>\nmcp\/duckduckgo@sha256:68eb20db6109f5c312a695fc5ec3386ad15d93ffb765a0b4eb1baf4328dec14f <\/p>\n<p># tag the image with the appropriate registry<br \/>\ndocker image tag mcp\/duckduckgo@sha256:68eb20db6109f5c312a695fc5ec3386ad15d93ffb765a0b4eb1baf4328dec14f  ${GHCR_IMAGE}<\/p>\n<p># push the  image<br \/>\ndocker push ${GHCR_IMAGE}<\/p>\n<\/div>\n<p>At this point you can move on to editing the MCP Catalog file in the next section.<\/p>\n<p>\u00a0<br \/>If you cannot download from Docker Hub you can always rebuild the MCP server from its GitHub repo. To do this, open the exported YAML and look for your target server\u2019s GitHub source repository. You can use tools like vi, cat, or grep to find it \u2014 it\u2019s usually listed under a source key.\u00a0<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\nExample for duckduckgo:<br \/>\nsource: https:\/\/github.com\/nickclyde\/duckduckgo-mcp-server\/tree\/main\n<p>export SOURCE_REPO=&#8221;https:\/\/github.com\/nickclyde\/duckduckgo-mcp-server.git&#8221;<\/p>\n<\/div>\n<p>Next, you\u2019ll rebuild the MCP server image from the original GitHub repository and push it to your own registry. This gives you full control over the image and eliminates dependency on Docker Hub access.<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\necho &#8220;${GH_PAT}&#8221; | docker login &#8220;${GHCR_REGISTRY}&#8221; -u &#8220;${GHCR_ORG}&#8221; &#8211;password-stdin\n<p>docker buildx build <br \/>\n  &#8211;platform linux\/amd64,linux\/arm64 <br \/>\n  &#8220;${SOURCE_REPO}&#8221; <br \/>\n  -t &#8220;${GHCR_IMAGE}&#8221; <br \/>\n  &#8211;push<\/p>\n<\/div>\n<h3 class=\"wp-block-heading\">Step 6: Update your catalog\u00a0<\/h3>\n<p>After publishing the image to GHCR, update your private catalog so it points to that new image instead of the Docker Hub version. This step links your catalog entry directly to the image you just built.<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\nvi &#8220;${MCP_CATALOG_FILE}&#8221;\n<p># Update the image line for the duckduckgo server to point to the image you created in the previous step (e.g. ghcr.io\/mikegcoleman\/duckduckgo-mcp)<\/p>\n<\/div>\n<p>Remove the forked version of the catalog as you no longer need it<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\ndocker mcp catalog rm &#8220;${FORK_CATALOG}&#8221;\n<\/div>\n<h3 class=\"wp-block-heading\">Step 7: Run the MCP Gateway\u00a0<\/h3>\n<p>Enabling the server activates it within your MCP environment. Once enabled, the gateway can load it and make it available to connected clients. You will get warnings about \u201coverlapping servers\u201d that is because the same servers are listed in two places (your catalog and the original catalog)<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\ndocker mcp server enable &#8220;${MCP_SERVER_NAME}&#8221;<br \/>\ndocker mcp server list\n<\/div>\n<h3 class=\"wp-block-heading\">Step 8: Connect to popular clients\u00a0<\/h3>\n<p>Now integrate the MCP Gateway with your chosen client. The raw command to run the gateway is:\u00a0<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\ndocker mcp gateway run &#8211;catalog &#8220;${PRIVATE_CATALOG}&#8221;\n<\/div>\n<p>But that just runs an instance on your local machine, when what you probably want is to integrate with some client application.\u00a0<\/p>\n<p>To do this you need to format the raw command so that it works for the client you wish to use. For example, with VS Code you\u2019d want to update the mcp.json as follows:<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\n&#8220;servers&#8221;: {<br \/>\n    &#8220;docker-mcp-gateway-private&#8221;: {<br \/>\n        &#8220;type&#8221;: &#8220;stdio&#8221;,<br \/>\n        &#8220;command&#8221;: &#8220;docker&#8221;,<br \/>\n        &#8220;args&#8221;: [<br \/>\n            &#8220;mcp&#8221;,<br \/>\n           &#8220;gateway&#8221;,<br \/>\n            &#8220;run&#8221;,<br \/>\n            &#8220;&#8211;catalog&#8221;,<br \/>\n            &#8220;my-private-catalog&#8221;<br \/>\n        ]<br \/>\n    }<br \/>\n}\n<\/div>\n<p>Finally, verify that the gateway is using your new GHCR image and that the server is properly enabled. This quick check confirms everything is configured as expected before connecting clients.<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\ndocker mcp server inspect &#8220;${MCP_SERVER_NAME}&#8221; | grep -E &#8216;name|image&#8217;\n<\/div>\n<h2 class=\"wp-block-heading\">Summary of Key Commands<\/h2>\n<p>You might find the following CLI commands handy: <\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\ndocker mcp catalog show docker-mcp &#8211;format yaml &gt; .\/docker-mcp.yaml<br \/>\ndocker mcp catalog fork docker-mcp my-fork<br \/>\ndocker mcp catalog export my-fork .\/my-fork.yaml<br \/>\ndocker mcp catalog create my-private-catalog<br \/>\ndocker mcp catalog add my-private-catalog duckduckgo .\/my-fork.yaml<br \/>\ndocker buildx build &#8211;platform linux\/amd64,linux\/arm64 https:\/\/github.com\/nickclyde\/duckduckgo-mcp-server.git <br \/>\n  -t ghcr.io\/mikegcoleman\/duckduckgo:latest &#8211;push<br \/>\ndocker mcp server enable duckduckgo<br \/>\ndocker mcp gateway run &#8211;catalog my-private-catalog\n<\/div>\n<h2 class=\"wp-block-heading\"><strong>Conclusion<\/strong><\/h2>\n<p>By using Docker\u2019s MCP Toolkit, Catalog, and Gateway, you can fully control the tools available to your developers, customers, or AI agents. No more one-off setups, scattered images, or cross-client connection headaches.<\/p>\n<p>Your next steps:<\/p>\n<p>Add more servers to your catalog<\/p>\n<p>Set up CI to rebuild and publish new server images<\/p>\n<p>Share your catalog internally or with customers<\/p>\n<p>Docs:<\/p>\n<p><a href=\"https:\/\/docs.docker.com\/ai\/mcp-catalog-and-toolkit\/\" target=\"_blank\">https:\/\/docs.docker.com\/ai\/mcp-catalog-and-toolkit\/<br \/><\/a><\/p>\n<p><a href=\"https:\/\/github.com\/docker\/mcp-gateway\/\" target=\"_blank\">https:\/\/github.com\/docker\/mcp-gateway\/<br \/><\/a><\/p>\n<p>Happy curating.\u00a0<\/p>\n<p>We\u2019re working on some exciting enhancements to make creating custom catalogs even easier. Stay tuned for updates!<\/p>\n\n<h3 class=\"wp-block-heading\"><strong>Learn more<\/strong><\/h3>\n<p><a href=\"https:\/\/hub.docker.com\/mcp\" target=\"_blank\">Explore the MCP Catalog<\/a>: Discover containerized, security-hardened MCP servers<\/p>\n<p>Open Docker Desktop and<a href=\"https:\/\/hub.docker.com\/open-desktop?url=https:\/\/open.docker.com\/dashboard\/mcp\" target=\"_blank\"> get started with the MCP Toolkit<\/a> <em>(Requires version 4.48 or newer to launch the MCP Toolkit automatically)<\/em><\/p>\n<p>Read about <a href=\"https:\/\/www.docker.com\/blog\/open-source-genius-cut-entropy-debt-docker-mcp-claude\/\">How Open Source Genius Cut Entropy Debt with Docker MCP Toolkit and Claude Desktop<\/a><\/p>","protected":false},"excerpt":{"rendered":"<p>I\u2019m Mike Coleman, a staff solutions architect at Docker. In this role, I spend a lot of time talking to [&hellip;]<\/p>\n","protected":false},"author":0,"featured_media":0,"comment_status":"","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"default","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","ast-disable-related-posts":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"footnotes":""},"categories":[4],"tags":[],"class_list":["post-2644","post","type-post","status-publish","format-standard","hentry","category-docker"],"_links":{"self":[{"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/posts\/2644","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/types\/post"}],"replies":[{"embeddable":true,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/comments?post=2644"}],"version-history":[{"count":0,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/posts\/2644\/revisions"}],"wp:attachment":[{"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/media?parent=2644"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/categories?post=2644"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/tags?post=2644"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}