Files
ag-bids-mcp/deploy/README.md
T
justin 8aa4cc0ef3 Make ag-bids-mcp a standalone compose project on .0.2
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>
2026-05-20 15:59:33 -04:00

4.2 KiB

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:

  1. Create namespace → name: ag-bids
  2. 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
  3. 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.2docker 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