e78733d55e
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>
102 lines
3.6 KiB
Markdown
102 lines
3.6 KiB
Markdown
# 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:
|
|
|
|
```ini
|
|
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:
|
|
|
|
```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"
|
|
```
|
|
|
|
### 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:
|
|
|
|
```bash
|
|
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`
|