Reflect the deploy decision: ag-bids-mcp lives in its own ~/ag-bids-mcp/ folder on 192.168.0.2 (NOT inside zerto-docs-rag's compose). It joins the existing mcp-servers_mcp Docker network as external so MetaMCP can still reach it at http://ag-bids-mcp:8000/mcp. Updated: - deploy/docker-compose.snippet.yml — now a self-contained compose project file with `networks.mcp.external: true; name: mcp-servers_mcp` - deploy/README.md — full runbook for the standalone-folder deploy, smoke-test commands that match the actual network name, and a base64-encoded Authorization-header recipe for testing without fighting curl's -u quoting Verified live: container on .0.2 returns 401 anonymous and 200 with real MCP initialize handshake from inside mcp-servers_mcp. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Deploying ag-bids-mcp behind MetaMCP
This runs on the MetaMCP host (192.168.0.2) as its own standalone
docker-compose project — independent from the zerto-docs-rag stack but
joining the same mcp-servers_mcp Docker network so MetaMCP can proxy to it
by container DNS name (http://ag-bids-mcp:8000/mcp).
The deploy lives in /home/justin/ag-bids-mcp/ on .0.2. Watchtower (already
running on the host) auto-pulls a new image every 5 min whenever a fresh
git.jpaul.io/justin/ag-bids-mcp:latest is pushed.
One-time setup (already done — kept for re-runs)
1. Pull the deploy snippet
docker-compose.snippet.yml in this directory is the ENTIRE compose file
for the deployment. Copy it to /home/justin/ag-bids-mcp/docker-compose.yml
on .0.2.
2. Write the .env
Create /home/justin/ag-bids-mcp/.env (mode 600) on .0.2 with:
AG_BIDS_API_URL=https://agbids.paul.farm
AG_BIDS_API_KEY=<copy BRIEF_API_KEY from ag-monitor .env on 192.168.0.126>
AG_BIDS_API_TIMEOUT_SECS=20
AG_BIDS_MCP_USER=<pick a username; non-user-facing>
AG_BIDS_MCP_PASS=<32+ random bytes>
Generate a password locally:
python3 -c "import secrets; print(secrets.token_urlsafe(32))"
3. Build + push the image
On any dev machine with the Gitea registry login:
cd ~/github/ag-bids-mcp
docker login git.jpaul.io # use your Gitea PAT
docker build -t git.jpaul.io/justin/ag-bids-mcp:latest .
docker push git.jpaul.io/justin/ag-bids-mcp:latest
4. Start the container on .0.2
ssh justin@192.168.0.2
cd ~/ag-bids-mcp
docker compose pull
docker compose up -d
docker compose logs -f ag-bids-mcp # expect "starting ag-bids MCP on streamable-http://0.0.0.0:8000 (Basic auth enforced)"
5. Register the namespace in MetaMCP
In the MetaMCP web UI at https://mcp.jpaul.io:
- Create namespace → name:
ag-bids - Add upstream MCP server to that namespace:
- Transport: Streamable HTTP
- URL:
http://ag-bids-mcp:8000/mcp - Authentication: Basic
- Username: matches
AG_BIDS_MCP_USER - Password: matches
AG_BIDS_MCP_PASS
- Username: matches
- Save.
Public endpoint becomes:
https://mcp.jpaul.io/metamcp/ag-bids/mcp
Smoke test
From inside the mcp-servers_mcp network (e.g. the metamcp container)
the MCP should 401 anonymous, 200 authenticated:
ssh justin@192.168.0.2 'docker exec metamcp wget -qS -O- --tries=1 http://ag-bids-mcp:8000/mcp 2>&1 | head -3'
# expect: HTTP/1.1 401 Unauthorized
Then, with creds, an MCP initialize handshake should return capability
metadata:
# from the .0.2 host
USER=<env value> PASS=<env value>
CREDS=$(printf '%s:%s' "$USER" "$PASS" | base64 -w0)
docker run --rm --network mcp-servers_mcp curlimages/curl:latest \
-s -H "Authorization: Basic $CREDS" \
-H 'content-type: application/json' \
-H 'accept: application/json, text/event-stream' \
-X POST http://ag-bids-mcp:8000/mcp \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"smoke","version":"1"}}}'
# expect: event: message ... "serverInfo":{"name":"ag-bids", ...}
Then in a real MCP client (Claude Desktop / OpenWebUI / etc.) configured
against https://mcp.jpaul.io/metamcp/ag-bids/mcp, try:
- "What's the best place to sell corn today?" → calls
best_local_bid("corn") - "What's the current price of lime?" → calls
current_lime_price() - "Are any sources down?" → calls
source_health()
Rotating credentials
To rotate the Basic password: change AG_BIDS_MCP_PASS in ~/ag-bids-mcp/.env
on .0.2 → docker compose up -d to restart with the new value → update
the MetaMCP namespace's upstream Basic password to match.
To rotate the upstream API key: change BRIEF_API_KEY in ag-monitor's .env
on .0.126 + restart api there, then update AG_BIDS_API_KEY in
~/ag-bids-mcp/.env on .0.2 + docker compose up -d.
Observability
- Per-tool-call usage logs:
/home/justin/ag-bids-mcp/ag-bids-mcp-logs/usage-YYYY-MM-DD.jsonl - Container stdout:
docker compose logs ag-bids-mcp - Successful auth → no log line; failed auth → INFO line with the offending path