# 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: ```ini AG_BIDS_API_URL=https://agbids.paul.farm AG_BIDS_API_KEY= AG_BIDS_API_TIMEOUT_SECS=20 AG_BIDS_MCP_USER= AG_BIDS_MCP_PASS=<32+ random bytes> ``` Generate a password locally: ```bash python3 -c "import secrets; print(secrets.token_urlsafe(32))" ``` ### 3. Build + push the image On any dev machine with the Gitea registry login: ```bash 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 ```bash 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: ```bash 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: ```bash # from the .0.2 host USER= PASS= 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