Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
catalogs/
103 changes: 53 additions & 50 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,17 @@
Thank you for your interest in contributing to the official Docker MCP Registry.
This document outlines how to contribute to this project.

## Prerequisites

- Go v1.24+
- [Docker Desktop](https://www.docker.com/products/docker-desktop/)
- [Task](https://taskfile.dev/)


## 🔄 Pull request process overview
- Fork the repository to your own GitHub account and clone it locally.
- Repository includes a `servers` folder where you should add a new folder with a `server.yaml` inside.
- Repository includes a `scripts` folder with bash scripts to automate some of the steps.
- Repository includes a `scripts` folder with bash scripts and Go code to automate some of the steps.
- Correctly format your commit messages, see Commit message guidelines below. _Note: All commits must include a Signed-off-by trailer at the end of each commit message to indicate that the contributor agrees to the Developer Certificate of Origin._
- Open a PR by ensuring the title and its description reflect the content of the PR.
- Ensure that CI passes, if it fails, fix the failures.
Expand All @@ -22,76 +29,72 @@ Add your entry by creating a new folder following the `owner@name` template, and
- The GitHub URL of your project. The project needs to have a valid Dockerfile.
- A brief description of your MCP Server.
- A category for the MCP server, one of:
* 'ai'
* 'data-visualization'
* 'database'
* 'devops'
* 'ecommerce'
* 'finance'
* 'games'
* 'communication'
* 'monitoring'
* 'productivity'
* 'search'

#### 🚀 Generate folder and `server.yaml` using `new-server.sh` script
You can use our script to automate the creation of the files. Let's assume we have a new MCP Server to access my org's database. The MCP is called `My-ORGDB-MCP` and the GitHub repo is located at: `https://github.com/myorg/my-orgdb-mcp`

You can call the tool passing the MCP server name, category, and github url.
* 'ai'
* 'data-visualization'
* 'database'
* 'devops'
* 'ecommerce'
* 'finance'
* 'games'
* 'communication'
* 'monitoring'
* 'productivity'
* 'search'

#### 🚀 Generate folder and `server.yaml` using `task create`
You can use our command to automate the creation of the files. Let's assume we have a new MCP Server to access my org's database. My server's GitHub repo is located at: `https://github.com/myorg/my-orgdb-mcp`

You can call the creation tool passing the category (required), and github url. If your server requires any environment variables, pass them at the end with `-e KEY=value`.

```
./scripts/new-server.sh My-ORGDB-MCP databases https://github.com/myorg/my-orgdb-mcp
task create -- --category database https://github.com/myorg/my-orgdb-mcp -e API_TOKEN=test
```

This will create a directory under `servers` as follows: `./servers/my-orgdb-mcp` and inside you will find a `server.yaml` file with your MCP definition.
This will build an image using the Dockerfile at the root of the repository, run it while verifying the MCP server is able to list tools, and then create the necessary files. It will create a directory under `servers` as follows: `./servers/my-orgdb-mcp` and inside you will find a `server.yaml` file with your MCP definition.

```
server:
name: test01
image: mcp/test01
name: my-orgdb-mcp
image: mcp/my-orgdb-mcp
type: server
meta:
category: test
category: database
tags:
- test
highlighted: false
- database
about:
title: test01
title: My OrgDB MCP (TODO)
description: TODO (only to provide a better description than the upstream project)
icon: https://avatars.githubusercontent.com/u/182288589?s=200&v=4
source:
project: https://github.com/docker/mcp-registry
branch: main
# config:
# description: TODO
# secrets:
# - name: test01.secret_name
# env: TEST01
# example: TODO
# env:
# - name: ENV_VAR_NAME
# example: TODO
# value: '{{test01.env_var_name}}'
# parameters:
# type: object
# properties:
# param_name:
# type: string
# required:
# - param_name
project: https://github.com/myorg/my-orgdb-mcp
config:
description: Configure the connection to TODO
secrets:
- name: my-orgdb-mcp.api_token
env: API_TOKEN
example: <API_TOKEN>
```

If you want to provide a specific Docker image built by your organisation, you can pass it to the script as follows:
If you want to provide a specific Docker image built by your organisation instead of having Docker build the image, you can specify it with the `--image` flag:

```
IMAGE_NAME=myorg/myimage ./scripts/new-server.sh My-ORGDB-MCP databases https://github.com/myorg/my-orgdb-mcp
task create -- --category database --image myorg/my-mcp https://github.com/myorg/my-orgdb-mcp -e API_TOKEN=test
```

As you can see, the configuration block has been commented out. If you need to pass environmental variables or secrets, please uncomment the necessary lines.

🔒 If you don't provide a Docker image, we will build the image for you and host it in [Docker Hub's `mcp` namespace](https://hub.docker.com/u/mcp), the benefits are: image will include cryptographic signatures, provenance tracking, SBOMs, and automatic security updates. Otherwise, self-built images still benefit from container isolation but won't include the enhanced security features of Docker-built images.

### 3️⃣ Run & Test your MCP Server locally
🚧 tbd
After creating your server file with `task create`, you will be given instructions for running it locally. In the case of my-orgdb-mcp, we would run the following commands next.

```
task catalog -- my-orgdb-mcp
docker mcp catalog import $PWD/catalogs/my-orgdb-mcp/catalog.yaml
```

Now, if we go into the MCP Toolkit on Docker Desktop, we'll see our new MCP server there! We can configure and enable it there, and test it against configured clients. Once we're done testing, we can restore it back to the original Docker catalog.

```
docker mcp catalog reset
```

### 4️⃣ Create `commit` and raise the Pull Request
🚧 tbd
Expand Down
10 changes: 10 additions & 0 deletions Taskfile.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
version: "3"

tasks:
create:
desc: Create a new mcp server definition
cmd: go run ./cmd/create {{.CLI_ARGS}}

catalog:
desc: Generate a test catalog
cmd: go run ./cmd/catalog {{.CLI_ARGS}}
74 changes: 74 additions & 0 deletions cmd/catalog/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package main

import (
"context"
"fmt"
"log"
"os"
"path/filepath"

"github.com/docker/mcp-registry/pkg/catalog"
"github.com/docker/mcp-registry/pkg/servers"
)

func main() {
if len(os.Args) != 2 {
fmt.Println("Usage: catalog <server-name>")
os.Exit(1)
}

name := os.Args[1]

if err := run(name); err != nil {
log.Fatal(err)
}
}

func run(name string) error {
serverFile := filepath.Join("servers", name, "server.yaml")
server, err := servers.Read(serverFile)
if err != nil {
if os.IsNotExist(err) {
fmt.Fprintf(os.Stderr, "server.yaml for %s not found. Run `task create -- <your_repo>` to create a new server definition first.\n", name)
}
return err
}

tile, err := catalog.ToTile(context.Background(), server)
if err != nil {
return err
}

catalogDir := filepath.Join("catalogs", name)
if err := os.MkdirAll(catalogDir, 0755); err != nil {
return err
}

if err := writeCatalog(name, catalogDir, tile); err != nil {
return err
}

return nil
}

func writeCatalog(name, catalogDir string, tile catalog.Tile) error {
catalogFile := filepath.Join(catalogDir, "catalog.yaml")

if err := catalog.WriteYaml(catalogFile, catalog.TopLevel{
Version: catalog.Version,
Name: "docker-mcp", // overwrite the default catalog
DisplayName: "Local Test Catalog",
Registry: catalog.TileList{
{
Name: name,
Tile: tile,
},
},
}); err != nil {
return err
}

fmt.Printf("Catalog written to %s\n", catalogFile)

return nil
}
Loading
Loading