Skip to content
Open
Show file tree
Hide file tree
Changes from 6 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
29 changes: 29 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: CI

on:
push:
branches: [ "**" ]
pull_request:
branches: [ "**" ]

jobs:
lint:
name: Lint Markdown and YAML
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Markdown Lint
uses: avto-dev/markdown-lint@v1
with:
config: .markdownlint.yaml
args: |
**/*.md

- name: YAML Lint
uses: ibiqlik/action-yamllint@v3
with:
file_or_dir: .
config_file: .yamllint
strict: true
46 changes: 46 additions & 0 deletions .github/workflows/compose-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
name: Compose CI

on:
push:
branches: [ "**" ]
pull_request:
branches: [ "**" ]

jobs:
compose-validate:
name: Compose config validation (custom-mcp)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Docker version
run: docker version
- name: Compose config
run: |
docker compose -f custom-mcp/compose.yaml -f custom-mcp/compose.ci.yaml config
working-directory: agents/compose-for-agents

e2e-health:
name: E2E health check (custom-mcp)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Start stack
run: |
docker compose -f custom-mcp/compose.yaml -f custom-mcp/compose.ci.yaml up -d
working-directory: agents/compose-for-agents
- name: Wait for health
run: |
for i in $(seq 1 30); do
if curl -fsS http://localhost:8811/health; then
exit 0
fi
sleep 2
done
echo "Gateway health check failed" >&2
docker compose -f custom-mcp/compose.yaml -f custom-mcp/compose.ci.yaml logs || true
exit 1
working-directory: agents/compose-for-agents
- name: Teardown
if: always()
run: docker compose -f custom-mcp/compose.yaml -f custom-mcp/compose.ci.yaml down -v --remove-orphans
working-directory: agents/compose-for-agents
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@
/.cursor/
**/init-secrets.sh
**/secret.openai-api-key
**/.mcp.env
**/postgres_url
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ The demos support using OpenAI models instead of running models locally with Doc
| [ADK](https://github.com/google/adk-python) Sock Store Agent | Multi-Agent | qwen3 | MongoDb, Brave, Curl, | [./adk-sock-shop](./adk-sock-shop/) | [compose.yaml](./adk-sock-shop/compose.yaml) |
| [Langchaingo](https://github.com/tmc/langchaingo) DuckDuckGo Search | Single Agent | gemma3 | duckduckgo | [./langchaingo](./langchaingo) | [compose.yaml](./langchaingo/compose.yaml) |
| [MinionS](https://github.com/HazyResearch/minions) Cost-Efficient Local-Remote Collaboration | Local-Remote Protocol | qwen3(local), gpt-4o(remote) | | [./minions](./minions) | [docker-compose.minions.yml](https://github.com/HazyResearch/minions/blob/main/apps/minions-docker/docker-compose.minions.yml) |
| Custom MCP Gateway (this repo) | Gateway + Tools | none | duckduckgo, github-official (extensible) | [./custom-mcp](./custom-mcp) | [compose.yaml](./custom-mcp/compose.yaml) |
Copy link

Copilot AI Dec 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The MCPs column lists "duckduckgo, github-official (extensible)" but the actual compose.yaml includes additional servers: brave, wikipedia-mcp, and postgres. Consider updating this to be more accurate, such as "duckduckgo, github-official, brave, wikipedia-mcp, postgres (extensible)" or "duckduckgo, github-official, brave, and more (extensible)".

Suggested change
| Custom MCP Gateway (this repo) | Gateway + Tools | none | duckduckgo, github-official (extensible) | [./custom-mcp](./custom-mcp) | [compose.yaml](./custom-mcp/compose.yaml) |
| Custom MCP Gateway (this repo) | Gateway + Tools | none | duckduckgo, github-official, brave, wikipedia-mcp, postgres (extensible) | [./custom-mcp](./custom-mcp) | [compose.yaml](./custom-mcp/compose.yaml) |

Copilot uses AI. Check for mistakes.

## License

Expand Down
48 changes: 48 additions & 0 deletions custom-mcp/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Custom MCP Gateway Stack

This example wires a Docker MCP Gateway with a flexible set of MCP servers and secrets loaded from a `.mcp.env` file.

Prerequisites
Copy link

Copilot AI Dec 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The section headers in this README file should use proper markdown heading levels. "Prerequisites", "Setup", "Run", "Modify servers", "Included servers & secrets", and "Notes" should be marked as level 2 headings (##) for better document structure and accessibility.

Copilot uses AI. Check for mistakes.
- Docker Desktop 4.43+ or Docker Engine with Compose v2.38.1+
- Optional: Docker Model Runner if you plan to use local models

Setup
Copy link

Copilot AI Dec 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This section header should use a level 2 markdown heading (##) for proper document structure.

Copilot uses AI. Check for mistakes.
1. cd custom-mcp
2. cp mcp.env.example .mcp.env
3. Fill in required secrets (e.g., GITHUB_TOKEN for `github-official`).

Run
Copy link

Copilot AI Dec 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This section header should use a level 2 markdown heading (##) for proper document structure.

Suggested change
Run
## Run

Copilot uses AI. Check for mistakes.
- Start the stack:
docker compose up --build

- The gateway will listen on port 8811. A health endpoint is available at:
http://localhost:8811/health

Modify servers
Copy link

Copilot AI Dec 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This section header should use a level 2 markdown heading (##) for proper document structure.

Suggested change
Modify servers
## Modify servers

Copilot uses AI. Check for mistakes.
- Edit compose.yaml and add or remove `--servers=...` entries on the mcp-gateway service.
- If a server needs credentials, add them to `.mcp.env` and reference via `--secrets=...` if required.

Included servers & secrets
Copy link

Copilot AI Dec 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This section header should use a level 2 markdown heading (##) for proper document structure.

Suggested change
Included servers & secrets
## Included servers & secrets

Copilot uses AI. Check for mistakes.
- duckduckgo: No secret required (optional app name via DUCKDUCKGO_APP_NAME)
- github-official: Requires GITHUB_TOKEN in .mcp.env
- brave: Requires BRAVE_API_KEY in .mcp.env
- wikipedia-mcp: No secret required
- postgres with SQL query tool:
- Create a file named `postgres_url` in this directory containing the DSN, e.g.
postgres://user:password@host:5432/dbname
- This is mounted as a secret named `database-url` and used by the gateway.

Notes
Copy link

Copilot AI Dec 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This section header should use a level 2 markdown heading (##) for proper document structure.

Suggested change
Notes
## Notes

Copilot uses AI. Check for mistakes.
- The example includes a minimal curl-based `mcp-client` container that checks gateway health.
- To integrate with an agent, set its MCP server URL to the gateway endpoint, e.g. `http://mcp-gateway:8811/sse` for SSE transport.

Agent integration patterns
- LangGraph/LangChain: set MCP endpoint env (e.g., MCP_SERVER_URL=http://mcp-gateway:8811/sse) in your agent container.
- Agno/ADK: point to MCP gateway URL (SSE or streaming) as shown in existing examples in this repo.
- UI frontends (e.g., Vercel AI SDK demo): configure your backend/agent server to call the gateway; avoid exposing gateway publicly.

Troubleshooting
- 401/403 from servers: ensure tokens (e.g., GITHUB_TOKEN, BRAVE_API_KEY) are present in .mcp.env and mapped via --secrets if required.
- Postgres errors: verify postgres_url content is a valid DSN and the DB is reachable from the gateway container.
- Port already in use: change ports mapping under mcp-gateway, e.g., "8812:8811", and curl http://localhost:8812/health.
- CI differences: CI uses compose.ci.yaml override with only duckduckgo and wikipedia (no secrets, no Docker API socket).
27 changes: 27 additions & 0 deletions custom-mcp/Taskfile.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
version: "3"

tasks:
up:
desc: Start custom MCP stack
cmds:
- docker compose up --build
dir: .

down:
desc: Stop and remove containers
cmds:
- docker compose down -v --remove-orphans
dir: .

build:
desc: Build images
cmds:
- docker compose build
dir: .

clean:
desc: Clean everything
cmds:
- docker compose down -v --remove-orphans
- docker builder prune -f
dir: .
12 changes: 12 additions & 0 deletions custom-mcp/compose.ci.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
services:
mcp-gateway:
# In CI, avoid using Docker API socket and any external secrets.
# Only enable servers that require no credentials.
use_api_socket: false
ports:
- "8811:8811"
command:
- --transport=sse
- --servers=duckduckgo
- --servers=wikipedia-mcp
secrets: []
47 changes: 47 additions & 0 deletions custom-mcp/compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
services:
# Minimal test client to verify the MCP Gateway is reachable.
mcp-client:
image: curlimages/curl:8.11.1
depends_on:
- mcp-gateway
command: ["/bin/sh", "-lc", "curl -sS http://mcp-gateway:8811/health || sleep 3600"]

mcp-gateway:
# Secures and launches MCP servers via the Docker API socket
image: docker/mcp-gateway:latest
use_api_socket: true
ports:
- "8811:8811"
command:
# switch between streaming or sse depending on your agent
- --transport=sse
# secrets can be provided multiple times and referenced per server
- --secrets=docker-desktop:/run/secrets/mcp_secret
# For Postgres DSN
- --secrets=/run/secrets/database-url
Copy link

Copilot AI Dec 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The secrets path format is inconsistent. Line 19 uses 'docker-desktop:/run/secrets/mcp_secret' with a prefix notation, while line 21 uses '/run/secrets/database-url' without a prefix. Consider using a consistent format for both secrets to improve maintainability and clarity.

Suggested change
- --secrets=/run/secrets/database-url
- --secrets=docker-desktop:/run/secrets/database-url

Copilot uses AI. Check for mistakes.
# Enable the servers you need. Add/remove as desired.
# Built-in servers supported by gateway include e.g. duckduckgo, github-official, postgres
- --servers=duckduckgo
- --servers=github-official
- --servers=brave
- --servers=wikipedia-mcp
# Postgres server and SQL tool (requires database-url secret file)
- --servers=postgres
- --tools=query
Comment on lines +39 to +41
Copy link

Copilot AI Dec 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The postgres server is enabled by default but requires the database-url secret file to exist. Since this file doesn't exist by default and may not be needed by all users, consider adding a comment here noting that users can remove or comment out the postgres server and related secret references (lines 29-30, 33, 46-47) if they don't need postgres functionality.

Copilot uses AI. Check for mistakes.
secrets:
- mcp_secret
- database-url

# Example model configuration if you want to co-run with Docker Model Runner
# and point an agent to it. Not strictly required for MCP Gateway testing.
# models:
# qwen3-small:
# model: ai/qwen3:8B-Q4_0
# context_size: 15000

# Mount the secrets file used by MCP servers
secrets:
mcp_secret:
file: ./.mcp.env
database-url:
Copy link

Copilot AI Dec 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The database-url secret references './postgres_url' file which doesn't exist in the repository and isn't created by default. This will cause the compose stack to fail to start unless the user manually creates this file. Consider either making this secret optional, documenting the requirement more prominently in the compose file, or providing an example postgres_url.example file similar to the mcp.env.example pattern.

Suggested change
database-url:
database-url:
# IMPORTANT: You must create the './postgres_url' file containing your Postgres DSN.
# See 'postgres_url.example' for a template/example.

Copilot uses AI. Check for mistakes.
file: ./postgres_url
9 changes: 9 additions & 0 deletions custom-mcp/mcp.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Copy this file to .mcp.env and fill in the values you need
# Common MCP servers
GITHUB_TOKEN=
DUCKDUCKGO_APP_NAME=docker-compose-for-agents
BRAVE_API_KEY=

# Postgres DSN is read from a separate secret file named "postgres_url" in this directory.
# Example content:
# postgres://user:password@host:5432/dbname