Continental-MCP-Server
Continental-MCP-Server
A 24/7 data-collection, analytics, and intelligence service for Polymarket BTC 5-minute Up/Down markets, exposed to LLM agents over the Model Context Protocol (MCP). It runs on an Ubuntu VPS and is strictly research-only: no API keys, no order placement, no bot-status decisions. Every response is framed as evidence (data with sample sizes, confidence intervals, and freshness), not trading advice.
Consumers are (a) LLM agents via MCP, (b) a trading bot via a read-only REST
data plane + ingest, and (c) humans via reports and Telegram alerts. The Python
package is named pmre (pm-research-engine); this repository is the MCP server
that fronts it.
For agents: connect to the MCP server
The server speaks Streamable HTTP with bearer-token auth and is
read-only. Any MCP-capable client (Claude, the OpenAI Agents SDK, OpenAI's
hosted {"type": "mcp"} tool, custom clients) can auto-discover every tool via
tools/list and call it — you do not hand-wire the tools.
Endpoint:
http://<host>:8090/mcp(default port8090)Transport: Streamable HTTP
Auth:
Authorization: Bearer <PMRE_MCP_BEARER_TOKEN>on every request (a missing/invalid token returns401)Network: bind to a private WireGuard/Tailscale overlay IP — never expose it publicly
Claude Code / mcp.json
{
"mcpServers": {
"continental": {
"type": "http",
"url": "http://127.0.0.1:8090/mcp",
"headers": { "Authorization": "Bearer <PMRE_MCP_BEARER_TOKEN>" }
}
}
}OpenAI Agents SDK (Python)
A complete, runnable example lives at examples/openai_agent_mcp.py:
from agents import Agent, Runner
from agents.mcp import MCPServerStreamableHttp
async with MCPServerStreamableHttp(
name="continental",
params={
"url": "http://127.0.0.1:8090/mcp",
"headers": {"Authorization": "Bearer <PMRE_MCP_BEARER_TOKEN>"},
},
cache_tools_list=True,
) as server:
agent = Agent(name="analyst", model="gpt-4o-mini", mcp_servers=[server])
result = await Runner.run(agent, "Is the engine healthy? What is the "
"strongest candidate by CI-lower net EV?")
print(result.final_output)Response envelope
Every tool response is wrapped in a freshness envelope carrying
data_last_updated_at, current_session, session_integrity, and any
warnings. Decisions should be made on CI lower bounds, never point
estimates.
Tools (16, all read-only)
Tool | Returns |
| Which collectors are alive/silent + recent incidents |
| Primary/overlap session, integrity, seconds to next boundary |
| Active + next market: token ids, price-to-beat, fee params, tick size |
| Latest order book: mids, spreads, depth, fee estimate |
| Per-timestamp win rate, net EV (taker/maker), CI-lower, Brier |
| Reliability curve (win rate vs price) per 2¢ bin, Wilson CIs, FDR flags |
| Performance per session/overlap (each with its own n and CI) |
| Performance per volatility regime |
| Fee params for a market (feesEnabled, rate, model version) + history |
| Fair-value output: |
| P(fill) and time-to-fill for hypothetical maker posts |
| Strategy candidates with status + full evidence |
| Current champion strategy and its CI-lower net EV (or null) |
| Aggregated paper-trade telemetry ingested from the bot |
| Summary of an analysis run: counts, versions, deterministic hash |
| Snapshot counts, stale/crossed/close-call rates over a window |
Resources
URI | Contents |
| Calibration-first, CI-lower decisions, BH-FDR, dual-scope sessions |
| Schema / field dictionary for the served tables |
| Dynamic taker fee curve notes |
| Latest daily research report (markdown) |
Run the server
uv sync
# Set the MCP bearer token (and other secrets) — copy the template first.
cp .env.example .env # then edit PMRE_MCP_BEARER_TOKEN, PMRE_DATABASE_URL, ...
uv run python -m pmre migrate # create/upgrade the schema
uv run python -m pmre serve-mcp # MCP server on PMRE_SERVING_HOST:PMRE_MCP_PORT (default :8090)./run.sh launches the whole system locally (migrate + calendar + collectors +
REST + MCP + hourly analytics). Modes: all (default), serve (no collectors),
demo (synthetic offline dataset), collectors. See the header of run.sh.
Relevant environment variables (all PMRE_-prefixed; see .env.example):
Variable | Purpose |
| MCP server port (default |
| Bearer token agents must present |
| Bind address — set to the overlay IP |
| Postgres 16 + TimescaleDB in prod; SQLite for dev/tests |
|
|
What the engine does
Fees are first-class — dynamic taker-fee curve
rate·p·(1−p); every EV in gross / net-taker / net-maker variants; maker entries are a first-class family.Calibration-first analytics — reliability curves (win rate vs price) with Wilson CIs; decisions on CI-lower net EV, never point estimates.
Multiple-testing control — Benjamini-Hochberg FDR (q=0.10) on every bucket claim; a null dataset produces ~zero "edges" (the project's most important test).
Fair-value benchmark —
p_fair = Φ(z),z = ln(S/S_ptb)/(σ_1s·√τ), independent of the empirical tables.Session & holiday model — tz-native Tokyo/London/New York + overlaps; holidays are integrity labels (regular/holiday/half_day/weekend), not closures. Every metric ships at
totalAND per-session scope.Two facades, one service layer — FastAPI REST (bot) + MCP (agents), both read-only, both stamped with freshness + evidence + current session.
Storage triad — PostgreSQL 16 + TimescaleDB (hypertables + compression), daily Parquet exports, zstd raw JSONL archive (replayable).
Layout
src/pm_sessions/ shared, versioned session/calendar model (the bot reuses it)
src/pmre/
config.py pydantic-settings (fails fast on missing prod secrets)
db/ SQLAlchemy models (all v1+v2 tables) + engine + timescale
collectors/ slugs, discovery, clob_ws (book engine), snapshotter,
btc_feed, resolution, calendar_job, supervisor
features/ fair_value, btc_state
analytics/ stats (Wilson/BH), ev, calibration, regime, maker_fill,
walkforward, runner, reports
registry/ candidates, gates, extractor (research_only -> ... -> disabled)
serving/ service (shared), envelope, auth, ingest,
rest/ (FastAPI), mcp/ (FastMCP) <-- MCP server lives here
ops/ health, alerts, clock, watchdog, backup, systemd_notify
parquet_export.py daily exporter + duckdb + replay
cli.py `python -m pmre <command>`
tests/ unit + integration + golden fixtures
deploy/ systemd units/timers, compose, Caddy, wireguard, runbooksREST facade (for the bot, not agents)
serve-rest exposes read-only GET /v1/health|session/current|markets/current| snapshots/latest|performance/*|candidates*|fills/maker-estimates| fairvalue/params|fees/parameters|quality/report|analysis/summary plus ingest
POST /v1/ingest/paper-trades|bot-decisions|bot-heartbeat. Bearer auth (read vs
ingest scopes), freshness envelope on every read.
Development
uv sync
uv run pytest # full suite (SQLite; no Docker needed)
uv run ruff check src tests
# End-to-end on a throwaway DB: seed synthetic data with a planted, persistent
# NY-session edge, run analytics -> walk-forward -> candidate extraction.
export PMRE_DATABASE_URL="sqlite+pysqlite:///./pmre.db"
uv run python -m pmre migrate
uv run python -m pmre pipeline-demo --days 25 # discovers the planted edge
uv run python -m pmre daily-reportTesting on real PostgreSQL + TimescaleDB
docker run -d --name pg -e POSTGRES_USER=pmre -e POSTGRES_PASSWORD=pmre \
-e POSTGRES_DB=pmre -p 55432:5432 timescale/timescaledb:latest-pg16
PMRE_TEST_POSTGRES_URL=postgresql+psycopg2://pmre:pmre@127.0.0.1:55432/pmre \
uv run pytest tests/test_postgres_integration.pyDeployment
deploy/ ships systemd units/timers (pmre-mcp.service, pmre-rest.service,
analytics/backup timers), a Docker Compose stack, a Caddyfile, and WireGuard
notes. Bind both facades to the overlay IP; nothing is public. See
deploy/README.md for install, runbooks, and chaos drills.
Design docs
mcp_plan.md (v2.1 spec) and mcp_phases.md (the 10 build phases) document the
full design and status. All phases are implemented and tested.
Research only. Every response is evidence — data with n, confidence intervals, and freshness — not trading advice.