Files
ag-bids-mcp/deploy
justin e78733d55e Drop in-container auth — MetaMCP guards the user-facing edge
The MCP's port 8000 isn't exposed outside the private mcp-servers_mcp
Docker network, so only the MetaMCP gateway can ever reach it. MetaMCP
itself enforces auth at the gateway → MCP-client edge (bearer token in
its UI), which is the right layer for it. In-container Basic/Bearer was
defense-in-depth that turned out to be friction-in-depth.

Removed:
  - ag_bids_mcp/auth.py (HTTP Basic middleware)
  - tests/test_auth.py (3 tests covering the middleware)
  - AG_BIDS_MCP_USER / AG_BIDS_MCP_PASS env vars from .env.example, README,
    docker-compose.snippet.yml, and deploy/README.md

Server.py simplified — direct `mcp.run(transport=...)` like zerto-docs-mcp,
no Starlette wrapping. 21 tests passing.

Live on 192.168.0.2: container recreated, real MCP initialize handshake
returns 200 + capability metadata over the mcp-servers_mcp network with
no auth header.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 16:05:41 -04:00
..

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 MetaMCP/zerto-docs 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.

No in-container auth. Port 8000 is never exposed outside the private mcp-servers_mcp Docker network — only MetaMCP can reach it. MetaMCP enforces auth at the gateway → MCP-client edge (bearer token in its UI), which is the right layer for it.

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

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"

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
    • Bearer token: leave blank (the upstream has no auth; MetaMCP enforces at the user-facing endpoint instead)
  3. Save.

Public endpoint becomes: https://mcp.jpaul.io/metamcp/ag-bids/mcp

Smoke test

From inside the mcp-servers_mcp network the MCP should respond to a real MCP initialize handshake:

ssh justin@192.168.0.2 'docker run --rm --network mcp-servers_mcp curlimages/curl:latest \
  -s -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 the upstream API key

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