@coinrithm/mcp-trading 0.7.1 → 0.7.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/CHANGELOG.md +48 -3
  2. package/README.md +240 -238
  3. package/dist/agent/act.d.ts +2 -2
  4. package/dist/agent/act.js +24 -3
  5. package/dist/agent/cli.js +59 -18
  6. package/dist/agent/client.d.ts +33 -0
  7. package/dist/agent/client.js +34 -7
  8. package/dist/agent/decision.d.ts +3 -0
  9. package/dist/agent/decision.js +26 -3
  10. package/dist/agent/decisionValidator.js +2 -1
  11. package/dist/agent/deploymentOverlay.js +25 -5
  12. package/dist/agent/engine.d.ts +2 -1
  13. package/dist/agent/engine.js +4 -1
  14. package/dist/agent/extract.js +3 -1
  15. package/dist/agent/gate.js +25 -5
  16. package/dist/agent/index.js +0 -1
  17. package/dist/agent/indicators.js +4 -2
  18. package/dist/agent/manifest.js +1 -1
  19. package/dist/agent/mechanical.d.ts +36 -0
  20. package/dist/agent/mechanical.js +286 -0
  21. package/dist/agent/observe.js +120 -52
  22. package/dist/agent/prompt.d.ts +3 -1
  23. package/dist/agent/prompt.js +17 -6
  24. package/dist/agent/providers.js +39 -4
  25. package/dist/agent/resolve.js +23 -6
  26. package/dist/agent/resolvePm.js +14 -3
  27. package/dist/agent/runEvidence.js +6 -2
  28. package/dist/agent/runner.d.ts +8 -2
  29. package/dist/agent/runner.js +370 -60
  30. package/dist/agent/scorecard.js +12 -4
  31. package/dist/agent/setups.js +57 -9
  32. package/dist/agent/skill.js +1 -1
  33. package/dist/agent/state.js +9 -4
  34. package/dist/agent/types.d.ts +17 -2
  35. package/dist/agent/types.js +2 -1
  36. package/dist/agent/util.js +11 -4
  37. package/dist/agent/version.d.ts +1 -1
  38. package/dist/agent/version.js +1 -1
  39. package/dist/client.d.ts +33 -0
  40. package/dist/client.js +12 -3
  41. package/dist/executionPolicy.d.ts +2 -0
  42. package/dist/executionPolicy.js +21 -0
  43. package/dist/http.js +10 -2
  44. package/dist/tools.d.ts +1 -0
  45. package/dist/tools.js +220 -32
  46. package/package.json +9 -1
package/CHANGELOG.md CHANGED
@@ -3,7 +3,52 @@
3
3
  All notable changes to `@coinrithm/mcp-trading` are documented here. The package
4
4
  ships two binaries — `coinrithm-mcp` (the MCP server) and `coinrithm-agent` (the
5
5
  self-host agent runner) — versioned together. The CoinRithm **API contract** is
6
- versioned separately (see `openapi.yaml` `info.version`, currently `1.5.0`).
6
+ versioned separately (see `openapi.yaml` `info.version`, currently `1.6.0`).
7
+
8
+ ## 0.7.3
9
+
10
+ Quality-engine surfaces + independent forecasts. Additive; no breaking change.
11
+
12
+ - **Quality verdicts in tool responses.** `discover_pm_markets`, `pm_quote`, and
13
+ the `pm_data_*` tools now surface the persisted truth-engine `quality` object
14
+ (`decisionEligible`, warning/block reason codes, `policyVersion`, `assessedAt`).
15
+ Markets with critical failures stay visible but cannot drive paper opens or
16
+ alerts.
17
+ - **`openBlocked` preview on `pm_quote`.** Quotes preview the open-time quality
18
+ gate (`openBlocked` + `openBlockReasons`), so an agent can skip a market that
19
+ would 422 before burning the open attempt. The self-host runner
20
+ (`coinrithm-agent`) does this skip automatically.
21
+ - **Independent forecasts in the runner.** The self-host agent runner elicits the
22
+ model's OWN probability (judged from the question/resolution criteria/deadline,
23
+ never anchored to the market price) and submits it as `forecastProbability` on
24
+ PM opens — feeding the public calibration dataset with proper-scoring-rule
25
+ forecasts. Clamped to [1,99]; omitted (never faked) when the model does not
26
+ produce one; `HOUSE_AGENT_FORECAST_ENABLED=false` disables.
27
+ - **`crossPlatform` on event lists** documented in the API contract: sibling
28
+ venues pricing the same question, on list rows.
29
+ - **ForecastEx venue truth.** Public MCP discovery copy and registry metadata
30
+ now describe all 11 live venues, including ForecastEx.
31
+ - **Contract synchronization.** Runner templates and example bundles pin the
32
+ served OpenAPI 1.6.0 contract; canonical scorecard paths are unambiguous.
33
+
34
+ ## 0.7.2
35
+
36
+ Docs-truth + privacy release. No tool behavior change, no API-surface change.
37
+
38
+ - **Ten venues in the public listing.** `pm_data_*` tool copy, the README, and
39
+ `server.json` now name all ten venues (adds Futuur and Myriad). npm `0.7.1` was
40
+ published before those landed, so the registry listing still advertised "eight
41
+ venues"; npm versions are immutable, so correcting the public listing required
42
+ a new release.
43
+ - **`source` parameter description** on `pm_data_events` / `pm_data_event_detail`
44
+ now enumerates all ten venue slugs. Accepted values are unchanged — this is
45
+ description text only, which is why it is a patch and not a minor.
46
+ - **Privacy.** Raw model output is no longer persisted, enforcing the package's
47
+ no-chain-of-thought promise.
48
+ - **New tripwire.** `server.json` (the MCP-registry listing) is now guarded
49
+ against version and venue-count drift; it had no guard, which is how it went
50
+ stale in the first place.
51
+ - Refreshed stale Arena-gate example copy.
7
52
 
8
53
  ## 0.7.1
9
54
 
@@ -11,8 +56,8 @@ Docs + registry-metadata release; no tool behavior changes.
11
56
 
12
57
  - **README refresh**: the keyless `pm_data_*` data surface is now front and
13
58
  center — 8 venues (Polymarket, Kalshi, Smarkets, Limitless, Manifold,
14
- Metaculus, Futuur, Rothera; an earlier line wrongly listed PredictIt), the
15
- anonymous hosted-endpoint path, and the `referenceProbability` /
59
+ Metaculus, PredictIt, Rothera the "seven venues" line predated Rothera),
60
+ the anonymous hosted-endpoint path, and the `referenceProbability` /
16
61
  `volumeHistory` fields the data tools return.
17
62
  - **`server.json`**: hosted endpoint's `Authorization` header marked optional
18
63
  (the `pm_data_*` tools work anonymously — verified live) and the server
package/README.md CHANGED
@@ -1,238 +1,240 @@
1
- # @coinrithm/mcp-trading
2
-
3
- **Deploy an AI trading agent with paper money — for free.** Give any model
4
- (Claude, GPT, Gemini, Llama…) a 50,000 mUSD virtual account and let it trade
5
- spot, futures, and prediction markets on
6
- [CoinRithm](https://coinrithm.com/agentic-trading). No real money, no exchange,
7
- no risk — a proving ground to show an agent works *before* anything is on the
8
- line, with a public **Agent Arena** leaderboard ranked by realized paper PnL.
9
-
10
- **Plus a free prediction-market data surface — no key at all.** The same server
11
- ships four keyless `pm_data_*` tools serving CoinRithm's public cross-venue
12
- dataset: live odds across 8 venues (Polymarket, Kalshi, Smarkets, Limitless,
13
- Manifold, Metaculus, Futuur, Rothera), cross-venue matches with a
14
- liquidity-aware reference probability, a whale-trade tape, and market-wide
15
- volume stats ($60B+ all-time tracked). Point any MCP client at the hosted
16
- endpoint `https://mcp.coinrithm.com/mcp` and call them anonymously — the API
17
- key is only needed for the trading tools.
18
-
19
- Agents are **OKF bundles** — an open, model-agnostic folder of markdown + YAML
20
- (strategy, persona, hard caps) that any runtime can read. Two ways to run the
21
- **same** bundle:
22
-
23
- - **Managed — nothing to install.** Build and deploy an agent in your browser
24
- with the **Agent Studio** (CoinRithm → My Agents → Studio): fork a house agent
25
- or write one from scratch, and CoinRithm runs it **free on Llama 3.1 8B**
26
- (NVIDIA NIM) on an always-on scheduler. The fastest path to a live agent.
27
- - **Self-host — this package.** Bring your own model key and run the
28
- `observe→decide→validate→act` loop on your machine, or wire the MCP server
29
- into Claude Desktop / Cursor / Codex.
30
-
31
- This package ships two binaries:
32
-
33
- - **`coinrithm-mcp`** — an MCP server that lets an AI agent paper-trade on
34
- CoinRithm (spot, futures, prediction markets) using a personal API key.
35
- - **`coinrithm-agent`** — a self-host **agent runner**: author an agent as a
36
- folder and run an `observe→decide→validate→act` loop with your own model key,
37
- **dry-run by default**. See [Agent runner](#agent-runner-coinrithm-agent) below.
38
-
39
- > **Paper trading only** — virtual funds (50,000 mUSD). Not financial advice.
40
-
41
- ## Quick start
42
-
43
- ```bash
44
- # Run the MCP server with your CoinRithm key (no install needed):
45
- COINRITHM_API_KEY=crk_live_… npx -y @coinrithm/mcp-trading
46
- ```
47
-
48
- Get a `crk_live_…` key from CoinRithm → Profile → API Keys. To author and run a
49
- self-host agent instead, see [Agent runner](#agent-runner-coinrithm-agent).
50
- Building from source? `npm install && npm run build`.
51
-
52
- ## Agent runner (`coinrithm-agent`)
53
-
54
- This package also ships a **self-host agent runner**. You write an agent as a
55
- folder (strategy + hard caps in markdown/YAML); the runner compiles it and runs
56
- an `observe → decide → validate → act` loop, asking *your* model (bring-your-own
57
- key) for structured decisions and executing only the ones that pass your caps —
58
- **dry-run by default**, paper-only across spot, futures, and prediction markets.
59
-
60
- ```bash
61
- coinrithm-agent new my-agent --preset conservative
62
- coinrithm-agent validate my-agent
63
- COINRITHM_API_KEY=crk_live_… ANTHROPIC_API_KEY=sk-ant-… \
64
- coinrithm-agent run my-agent --once --dry-run
65
- ```
66
-
67
- Full guide (env vars, fail-closed guarantees, folder layout):
68
- **[docs/agent-runner.md](https://github.com/CoinRithm/coinrithm-agent-trading/blob/main/docs/agent-runner.md)**.
69
- The CoinRithm hosted scheduler runs this same engine for you — see the
70
- [scheduler README](../../packages/scheduler/README.md) for the built,
71
- DB-driven runtime.
72
-
73
- ## Two ways to run
74
-
75
- | Mode | Entry | Auth | Who it's for |
76
- | --- | --- | --- | --- |
77
- | **stdio** (single-user, local) | `dist/index.js` | `COINRITHM_API_KEY` env var | Claude Desktop / Cursor / Codex on your machine |
78
- | **Streamable HTTP** (multi-user, hosted) | `dist/http.js` | **per-request** `Authorization: Bearer` header | The shared hosted endpoint at `mcp.coinrithm.com` |
79
-
80
- The hosted HTTP server holds **no** key: each request brings its own
81
- `crk_live_…` in the Authorization header, and the server forwards exactly that
82
- key upstream. The Authorization header is **optional** on the hosted endpoint —
83
- the four keyless `pm_data_*` market-data tools work anonymously; every other
84
- tool requires it. See [`DEPLOY.md`](./DEPLOY.md).
85
-
86
- ## Configure (stdio)
87
-
88
- | Env var | Required | Default | Notes |
89
- | --- | --- | --- | --- |
90
- | `COINRITHM_API_KEY` | yes (stdio only) | — | A `crk_live_…` key from CoinRithm → Profile → API Keys. **Ignored by the HTTP entry.** |
91
- | `COINRITHM_API_URL` | no | `https://api.coinrithm.com` | Upstream base URL (live) |
92
- | `PORT` | no | `8787` | HTTP entry only |
93
-
94
- ## Run
95
-
96
- - **stdio** (for Claude Desktop / Claude Code / Cursor / most MCP hosts):
97
- ```bash
98
- COINRITHM_API_KEY=crk_live_... node dist/index.js
99
- # or, after npm link / npx:
100
- coinrithm-mcp
101
- ```
102
- - **Streamable HTTP** (multi-user; no key in env — clients send their own):
103
- ```bash
104
- npm run start:http
105
- # POST http://localhost:8787/mcp with Authorization: Bearer crk_live_...
106
- # GET http://localhost:8787/healthz (liveness, no auth)
107
- ```
108
-
109
- ## Tools
110
-
111
- | Tool | Scope | Wraps |
112
- | --- | --- | --- |
113
- | `whoami` | any | `GET /api/agent/me` |
114
- | `get_portfolio` | read | `GET /api/agent/portfolio` |
115
- | `get_wallet` | read | `GET /api/agent/wallet` |
116
- | `resolve_symbol` | read | `GET /api/agent/resolve` |
117
- | `get_equity_curve` | read | `GET /api/agent/equity-curve` |
118
- | `get_my_trades` (venue) | read | `GET /api/agent/trades` |
119
- | `get_market_context` (coinId) | read | `GET /api/agent/market/:coinId` |
120
- | `get_candles` (coinId, range) | read | `GET /api/agent/market/:coinId/candles` |
121
- | `discover_pm_markets` | read | `GET /api/agent/pm/discover` |
122
- | `get_performance` | read | `GET /api/agent/performance` |
123
- | `get_agent_ledger` | read | `GET /api/agent/ledger` |
124
- | `export_agent_ledger` | read | `GET /api/agent/ledger/export` |
125
- | `export_run_evidence` | read | `GET /api/agent/ledger/export?runId=...` |
126
- | `get_arena_leaderboard` | read | `GET /api/arena` |
127
- | `get_arena_agent` (handle) | read | `GET /api/arena/:handle` |
128
- | `list_open_orders` | read | `GET /api/agent/orders/open` |
129
- | `get_positions` (venue) | read | `GET /api/agent/positions/{futures,pm}` |
130
- | `spot_quote` | read | `POST /api/agent/spot/quote` |
131
- | `futures_quote` | read | `POST /api/agent/futures/quote` |
132
- | `pm_quote` | read | `POST /api/agent/pm/quote` |
133
- | `place_spot_order` | trade:spot | `POST /api/agent/spot/order` |
134
- | `cancel_spot_order` | trade:spot | `POST /api/agent/spot/order/:id/cancel` |
135
- | `open_futures_position` | trade:futures | `POST /api/agent/futures/open` ¹ |
136
- | `set_futures_sl_tp` | trade:futures | `POST /api/agent/futures/sl-tp` ² |
137
- | `close_futures_position` | trade:futures | `POST /api/agent/futures/close` |
138
- | `open_pm_position` | trade:pm | `POST /api/agent/pm/open` ¹ |
139
- | `pm_data_overview` | none (public) | `GET /api/prediction-markets/overview` |
140
- | `pm_data_events` | none (public) | `GET /api/prediction-markets/events` |
141
- | `pm_data_event` (source, slug) | none (public) | `GET /api/prediction-markets/events/:source/:slug` |
142
- | `pm_data_whales` | none (public) | `GET /api/prediction-markets/whales` |
143
-
144
- The four `pm_data_*` tools wrap CoinRithm's free public cross-venue dataset
145
- (all eight venues: Polymarket, Kalshi, Smarkets, Limitless, Manifold,
146
- Metaculus, Futuur, Rothera). They require no API key, never attach yours, and
147
- are research surfaces: `pm_data_events` list rows carry `referenceProbability`
148
- (a liquidity-aware cross-venue consensus on matched questions); `pm_data_event`
149
- includes `crossSourceMatches` (the same real-world question priced on other
150
- venues), `referenceProbability`, `volumeHistory`, and resolution evidence.
151
- Figures are self-computed aggregates on a disclosed per-venue basis — cite
152
- CoinRithm when quoting them.
153
-
154
- ¹ Server-flag gated; live now. Returns `403 … not enabled` only if CoinRithm later disables it.
155
-
156
- ² Set/clear resting stop-loss / take-profit on an open futures position.
157
- Naturally idempotent — no `idempotencyKey` needed (unlike spot orders, opens,
158
- and closes, which all require one; reuse replays the original result).
159
-
160
- Tool results return the raw HTTP status + JSON body so the model sees real
161
- server responses (including `{ error, blockReasons }` on blocked entries).
162
- They also include `ledgerEventId` and `ledgerStatus` when CoinRithm records the
163
- private action ledger row for the call.
164
-
165
- ## Private ledger and trace metadata
166
-
167
- Every `/api/agent/*` call is recorded privately for the calling key: reads,
168
- quotes, writes, rejects, idempotent replays, latency, sanitized summaries, and
169
- optional run/decision metadata. CoinRithm logs execution and performance for
170
- paper trading; it does **not** run your agent or verify hidden reasoning.
171
-
172
- All MCP read/quote/write tools accept optional `agentTrace`:
173
-
174
- ```json
175
- {
176
- "runId": "run-2026-06-12",
177
- "decisionId": "decision-7",
178
- "strategyLabel": "momentum",
179
- "confidence": 0.72,
180
- "rationaleSummary": "Short private summary only; no chain-of-thought."
181
- }
182
- ```
183
-
184
- Use the same `runId` across a session and a new `decisionId` per quote/write
185
- intent. Then call `get_agent_ledger` to inspect rows or `export_agent_ledger`
186
- with `runId` to export a private run-evidence bundle:
187
-
188
- ```json
189
- {
190
- "runId": "run-2026-06-12",
191
- "limit": 1000
192
- }
193
- ```
194
-
195
- The export includes a manifest and summary: first/last event time, venues,
196
- ledger statuses, quote/write/reject/replay counts, related paper-trade ids, and
197
- the sanitized ledger rows. It also includes `executionAssumptions`: paper
198
- account only, latest stored market/probability snapshots, no explicit
199
- commission/slippage in v1, no futures funding/fees, and worker-driven resting
200
- order / SL / TP / settlement timing. It is a reproducibility artifact for your
201
- run; it is not a full point-in-time market archive and does not expose hidden
202
- reasoning. Aggregate audit stats include trace coverage for `runId` and
203
- `decisionId`. Run exports also include `retentionPolicy`: private ledger rows
204
- use a rolling retention window and exports are capped. They include
205
- `evidenceChecklist`, a derived pass/warn/fail checklist for trace completeness,
206
- decision ids, quote-before-trade coverage, rejected calls, export truncation,
207
- execution assumptions, and outcome attribution; it does not create additional
208
- retained data. `outcomeSummary` derives best-effort realized PnL from existing
209
- related trade/position ids, and spot orders can also match through their
210
- idempotency keys once a terminal `ClosedOrder` exists. It reports whether
211
- coverage is `none`, `partial`, or `complete`; it does not store new data. Public
212
- Arena surfaces only aggregate audit stats; raw request logs and rationale
213
- summaries stay private.
214
-
215
- `get_my_trades`, `list_open_orders`, and `get_positions` accept an optional
216
- `updatedSince` cursor and their responses carry `asOf` — pass it back to poll
217
- only what changed (how an agent discovers worker-fired SL/TP, liquidations,
218
- and PM settlements).
219
-
220
- ## Rate limits
221
-
222
- Every key carries two per-key budgets: **120 requests/min** and **20
223
- trade-writes/min**, surfaced via `RateLimit-*` response headers. On a `429`
224
- the tool result includes `retryAfterSeconds` plus a pacing hint — wait at
225
- least that long before retrying.
226
-
227
- ## Agent Arena
228
-
229
- Opted-in agents are publicly ranked by realized PnL — every agent with any
230
- decided (win/loss) trade is listed (a small-sample asterisk flags thin records;
231
- the live gate is surfaced as `minDecidedTrades` in the response) at
232
- [coinrithm.com](https://coinrithm.com/agentic-trading) set `agentName` /
233
- `agentPublic` / `agentModel` on your key to join, then check your standing
234
- with `get_arena_leaderboard` / `get_arena_agent`. Pass `window: "7d" | "30d"`
235
- to `get_arena_leaderboard` for the weekly/monthly board (re-ranked by
236
- in-window PnL; the min-decided gate and badges stay all-time).
237
-
238
- stdout is the MCP JSON-RPC channel; this server logs only to stderr.
1
+ # @coinrithm/mcp-trading
2
+
3
+ **Deploy an AI trading agent with paper money — for free.** Give any model
4
+ (Claude, GPT, Gemini, Llama…) a 50,000 mUSD virtual account and let it trade
5
+ spot, futures, and prediction markets on
6
+ [CoinRithm](https://coinrithm.com/agentic-trading). No real money, no exchange,
7
+ no risk — a proving ground to show an agent works *before* anything is on the
8
+ line, with a public **Agent Arena** leaderboard ranked by realized paper PnL.
9
+
10
+ **Plus a free prediction-market data surface — no key at all.** The same server
11
+ ships four keyless `pm_data_*` tools serving CoinRithm's public cross-venue
12
+ dataset: live odds across 11 venues (Polymarket, Kalshi, Smarkets, Limitless,
13
+ Manifold, Metaculus, PredictIt, Rothera, Futuur, Myriad, ForecastEx), cross-venue matches with a
14
+ liquidity-aware reference probability, a whale-trade tape, and market-wide
15
+ volume stats ($60B+ all-time tracked). Point any MCP client at the hosted
16
+ endpoint `https://mcp.coinrithm.com/mcp` and call them anonymously — the API
17
+ key is only needed for the trading tools.
18
+
19
+ Agents are **OKF bundles** — an open, model-agnostic folder of markdown + YAML
20
+ (strategy, persona, hard caps) that any runtime can read. Two ways to run the
21
+ **same** bundle:
22
+
23
+ - **Managed — nothing to install.** Build and deploy an agent in your browser
24
+ with the **Agent Studio** (CoinRithm → My Agents → Studio): fork a house agent
25
+ or write one from scratch, and CoinRithm runs it **free on Llama 3.1 8B**
26
+ (NVIDIA NIM) on an always-on scheduler. The fastest path to a live agent.
27
+ - **Self-host — this package.** Bring your own model key and run the
28
+ `observe→decide→validate→act` loop on your machine, or wire the MCP server
29
+ into Claude Desktop / Cursor / Codex.
30
+
31
+ This package ships two binaries:
32
+
33
+ - **`coinrithm-mcp`** — an MCP server that lets an AI agent paper-trade on
34
+ CoinRithm (spot, futures, prediction markets) using a personal API key.
35
+ - **`coinrithm-agent`** — a self-host **agent runner**: author an agent as a
36
+ folder and run an `observe→decide→validate→act` loop with your own model key,
37
+ **dry-run by default**. See [Agent runner](#agent-runner-coinrithm-agent) below.
38
+
39
+ > **Paper trading only** — virtual funds (50,000 mUSD). Not financial advice.
40
+
41
+ ## Quick start
42
+
43
+ ```bash
44
+ # Run the MCP server with your CoinRithm key (no install needed):
45
+ COINRITHM_API_KEY=crk_live_… npx -y @coinrithm/mcp-trading
46
+ ```
47
+
48
+ Get a `crk_live_…` key from CoinRithm → Profile → API Keys. To author and run a
49
+ self-host agent instead, see [Agent runner](#agent-runner-coinrithm-agent).
50
+ Building from source? `npm install && npm run build`.
51
+
52
+ ## Agent runner (`coinrithm-agent`)
53
+
54
+ This package also ships a **self-host agent runner**. You write an agent as a
55
+ folder (strategy + hard caps in markdown/YAML); the runner compiles it and runs
56
+ an `observe → decide → validate → act` loop, asking *your* model (bring-your-own
57
+ key) for structured decisions and executing only the ones that pass your caps —
58
+ **dry-run by default**, paper-only across spot, futures, and prediction markets.
59
+
60
+ ```bash
61
+ coinrithm-agent new my-agent --preset conservative
62
+ coinrithm-agent validate my-agent
63
+ COINRITHM_API_KEY=crk_live_… ANTHROPIC_API_KEY=sk-ant-… \
64
+ coinrithm-agent run my-agent --once --dry-run
65
+ ```
66
+
67
+ Full guide (env vars, fail-closed guarantees, folder layout):
68
+ **[docs/agent-runner.md](https://github.com/CoinRithm/coinrithm-agent-trading/blob/main/docs/agent-runner.md)**.
69
+ The CoinRithm hosted scheduler runs this same engine for you — see the
70
+ [scheduler README](../../packages/scheduler/README.md) for the built,
71
+ DB-driven runtime.
72
+
73
+ ## Two ways to run
74
+
75
+ | Mode | Entry | Auth | Who it's for |
76
+ | --- | --- | --- | --- |
77
+ | **stdio** (single-user, local) | `dist/index.js` | `COINRITHM_API_KEY` env var | Claude Desktop / Cursor / Codex on your machine |
78
+ | **Streamable HTTP** (multi-user, hosted) | `dist/http.js` | **per-request** `Authorization: Bearer` header | The shared hosted endpoint at `mcp.coinrithm.com` |
79
+
80
+ The hosted HTTP server holds **no** key: each request brings its own
81
+ `crk_live_…` in the Authorization header, and the server forwards exactly that
82
+ key upstream. The Authorization header is **optional** on the hosted endpoint —
83
+ the four keyless `pm_data_*` market-data tools work anonymously; every other
84
+ tool requires it. See [`DEPLOY.md`](./DEPLOY.md).
85
+
86
+ ## Configure (stdio)
87
+
88
+ | Env var | Required | Default | Notes |
89
+ | --- | --- | --- | --- |
90
+ | `COINRITHM_API_KEY` | yes (stdio only) | — | A `crk_live_…` key from CoinRithm → Profile → API Keys. **Ignored by the HTTP entry.** |
91
+ | `COINRITHM_API_URL` | no | `https://api.coinrithm.com` | Upstream base URL (live) |
92
+ | `PORT` | no | `8787` | HTTP entry only |
93
+
94
+ ## Run
95
+
96
+ - **stdio** (for Claude Desktop / Claude Code / Cursor / most MCP hosts):
97
+ ```bash
98
+ COINRITHM_API_KEY=crk_live_... node dist/index.js
99
+ # or, after npm link / npx:
100
+ coinrithm-mcp
101
+ ```
102
+ - **Streamable HTTP** (multi-user; no key in env — clients send their own):
103
+ ```bash
104
+ npm run start:http
105
+ # POST http://localhost:8787/mcp with Authorization: Bearer crk_live_...
106
+ # GET http://localhost:8787/healthz (liveness, no auth)
107
+ ```
108
+
109
+ ## Tools
110
+
111
+ | Tool | Scope | Wraps |
112
+ | --- | --- | --- |
113
+ | `whoami` | any | `GET /api/agent/me` |
114
+ | `get_portfolio` | read | `GET /api/agent/portfolio` |
115
+ | `get_wallet` | read | `GET /api/agent/wallet` |
116
+ | `resolve_symbol` | read | `GET /api/agent/resolve` |
117
+ | `get_equity_curve` | read | `GET /api/agent/equity-curve` |
118
+ | `get_my_trades` (venue) | read | `GET /api/agent/trades` |
119
+ | `get_market_context` (coinId) | read | `GET /api/agent/market/:coinId` |
120
+ | `get_candles` (coinId, range) | read | `GET /api/agent/market/:coinId/candles` |
121
+ | `discover_pm_markets` | read | `GET /api/agent/pm/discover` |
122
+ | `get_performance` | read | `GET /api/agent/performance` |
123
+ | `get_agent_ledger` | read | `GET /api/agent/ledger` |
124
+ | `export_agent_ledger` | read | `GET /api/agent/ledger/export` |
125
+ | `export_run_evidence` | read | `GET /api/agent/ledger/export?runId=...` |
126
+ | `get_arena_leaderboard` | read | `GET /api/arena` |
127
+ | `get_arena_agent` (handle) | read | `GET /api/arena/:handle` |
128
+ | `list_open_orders` | read | `GET /api/agent/orders/open` |
129
+ | `get_positions` (venue) | read | `GET /api/agent/positions/{futures,pm}` |
130
+ | `spot_quote` | read | `POST /api/agent/spot/quote` |
131
+ | `futures_quote` | read | `POST /api/agent/futures/quote` |
132
+ | `pm_quote` | read | `POST /api/agent/pm/quote` |
133
+ | `place_spot_order` | trade:spot | `POST /api/agent/spot/order` |
134
+ | `cancel_spot_order` | trade:spot | `POST /api/agent/spot/order/:id/cancel` |
135
+ | `open_futures_position` | trade:futures | `POST /api/agent/futures/open` ¹ |
136
+ | `set_futures_sl_tp` | trade:futures | `POST /api/agent/futures/sl-tp` ² |
137
+ | `close_futures_position` | trade:futures | `POST /api/agent/futures/close` |
138
+ | `open_pm_position` | trade:pm | `POST /api/agent/pm/open` ¹ |
139
+ | `pm_data_overview` | none (public) | `GET /api/prediction-markets/overview` |
140
+ | `pm_data_events` | none (public) | `GET /api/prediction-markets/events` |
141
+ | `pm_data_event` (source, slug) | none (public) | `GET /api/prediction-markets/events/:source/:slug` |
142
+ | `pm_data_whales` | none (public) | `GET /api/prediction-markets/whales` |
143
+
144
+ The four `pm_data_*` tools wrap CoinRithm's free public cross-venue dataset
145
+ (all 11 venues: Polymarket, Kalshi, Smarkets, Limitless, Manifold,
146
+ Metaculus, PredictIt, Rothera, Futuur, Myriad, ForecastEx). They require no API key, never attach yours, and
147
+ are research surfaces: `pm_data_events` list rows carry `referenceProbability`
148
+ (a liquidity-aware cross-venue consensus on matched questions); `pm_data_event`
149
+ includes `crossSourceMatches` (the same real-world question priced on other
150
+ venues), `referenceProbability`, `volumeHistory`, and resolution evidence.
151
+ Figures are self-computed aggregates on a disclosed per-venue basis — cite
152
+ CoinRithm when quoting them.
153
+
154
+ ¹ Server-flag gated; live now. Returns `403 … not enabled` only if CoinRithm later disables it.
155
+
156
+ ² Set/clear resting stop-loss / take-profit on an open futures position.
157
+ Naturally idempotent — no `idempotencyKey` needed (unlike spot orders, opens,
158
+ and closes, which all require one; reuse replays the original result).
159
+
160
+ Tool results return the raw HTTP status + JSON body so the model sees real
161
+ server responses (including `{ error, blockReasons }` on blocked entries).
162
+ They also include `ledgerEventId` and `ledgerStatus` when CoinRithm records the
163
+ private action ledger row for the call.
164
+
165
+ ## Private ledger and trace metadata
166
+
167
+ Every `/api/agent/*` call is recorded privately for the calling key: reads,
168
+ quotes, writes, rejects, idempotent replays, latency, sanitized summaries, and
169
+ optional run/decision metadata. CoinRithm logs execution and performance for
170
+ paper trading; it does **not** run your agent or verify hidden reasoning.
171
+
172
+ All MCP read/quote/write tools accept optional `agentTrace`:
173
+
174
+ ```json
175
+ {
176
+ "runId": "run-2026-06-12",
177
+ "decisionId": "decision-7",
178
+ "strategyLabel": "momentum",
179
+ "confidence": 0.72,
180
+ "rationaleSummary": "Short private summary only; no chain-of-thought."
181
+ }
182
+ ```
183
+
184
+ Use the same `runId` across a session and a new `decisionId` per quote/write
185
+ intent. Then call `get_agent_ledger` to inspect rows or `export_agent_ledger`
186
+ with `runId` to export a private run-evidence bundle:
187
+
188
+ ```json
189
+ {
190
+ "runId": "run-2026-06-12",
191
+ "limit": 1000
192
+ }
193
+ ```
194
+
195
+ The export includes a manifest and summary: first/last event time, venues,
196
+ ledger statuses, quote/write/reject/replay counts, related paper-trade ids, and
197
+ the sanitized ledger rows. It also includes `executionAssumptions`: paper
198
+ account only, latest stored market/probability snapshots, and the versioned
199
+ `paper_execution_v1` cost model (paper execution is **not costless** — fills
200
+ charge a modeled taker fee plus spread + slippage on spot/PM, disclosed per fill;
201
+ futures funding is not modeled), and worker-driven resting order / SL / TP /
202
+ settlement timing. It is a reproducibility artifact for your
203
+ run; it is not a full point-in-time market archive and does not expose hidden
204
+ reasoning. Aggregate audit stats include trace coverage for `runId` and
205
+ `decisionId`. Run exports also include `retentionPolicy`: private ledger rows
206
+ use a rolling retention window and exports are capped. They include
207
+ `evidenceChecklist`, a derived pass/warn/fail checklist for trace completeness,
208
+ decision ids, quote-before-trade coverage, rejected calls, export truncation,
209
+ execution assumptions, and outcome attribution; it does not create additional
210
+ retained data. `outcomeSummary` derives best-effort realized PnL from existing
211
+ related trade/position ids, and spot orders can also match through their
212
+ idempotency keys once a terminal `ClosedOrder` exists. It reports whether
213
+ coverage is `none`, `partial`, or `complete`; it does not store new data. Public
214
+ Arena surfaces only aggregate audit stats; raw request logs and rationale
215
+ summaries stay private.
216
+
217
+ `get_my_trades`, `list_open_orders`, and `get_positions` accept an optional
218
+ `updatedSince` cursor and their responses carry `asOf` — pass it back to poll
219
+ only what changed (how an agent discovers worker-fired SL/TP, liquidations,
220
+ and PM settlements).
221
+
222
+ ## Rate limits
223
+
224
+ Every key carries two per-key budgets: **120 requests/min** and **20
225
+ trade-writes/min**, surfaced via `RateLimit-*` response headers. On a `429`
226
+ the tool result includes `retryAfterSeconds` plus a pacing hint — wait at
227
+ least that long before retrying.
228
+
229
+ ## Agent Arena
230
+
231
+ Opted-in agents are publicly ranked by realized PnL every agent with any
232
+ decided (win/loss) trade is listed (a small-sample asterisk flags thin records;
233
+ the live gate is surfaced as `minDecidedTrades` in the response) at
234
+ [coinrithm.com](https://coinrithm.com/agentic-trading) set `agentName` /
235
+ `agentPublic` / `agentModel` on your key to join, then check your standing
236
+ with `get_arena_leaderboard` / `get_arena_agent`. Pass `window: "7d" | "30d"`
237
+ to `get_arena_leaderboard` for the weekly/monthly board (re-ranked by
238
+ in-window PnL; the min-decided gate and badges stay all-time).
239
+
240
+ stdout is the MCP JSON-RPC channel; this server logs only to stderr.
@@ -1,4 +1,4 @@
1
- import { CoinRithmClient } from "./client.js";
1
+ import { CoinRithmClient, ProvenanceReport } from "./client.js";
2
2
  import { ProposedAction, AgentTrace, ApiResult, Observation, QuoteEvidence } from "./types.js";
3
3
  export declare function fetchQuote(client: CoinRithmClient, action: ProposedAction, observation: Observation, trace?: AgentTrace): Promise<QuoteEvidence | undefined>;
4
- export declare function executeAction(client: CoinRithmClient, action: ProposedAction, observation: Observation, trace: AgentTrace, idempotencyKey: string): Promise<ApiResult>;
4
+ export declare function executeAction(client: CoinRithmClient, action: ProposedAction, observation: Observation, trace: AgentTrace, idempotencyKey: string, provenance?: ProvenanceReport): Promise<ApiResult>;
package/dist/agent/act.js CHANGED
@@ -3,7 +3,7 @@
3
3
  // idempotency key.
4
4
  import { asObj, asNum, asStr } from "./extract.js";
5
5
  function coinIdFor(observation, symbol) {
6
- return observation.watch.find((w) => w.symbol.toUpperCase() === symbol.toUpperCase())?.coinId ?? undefined;
6
+ return (observation.watch.find((w) => w.symbol.toUpperCase() === symbol.toUpperCase())?.coinId ?? undefined);
7
7
  }
8
8
  function freshnessOf(block) {
9
9
  const fr = asObj(block.freshness);
@@ -17,7 +17,12 @@ export async function fetchQuote(client, action, observation, trace) {
17
17
  const coinId = coinIdFor(observation, action.symbol);
18
18
  if (!coinId)
19
19
  return { eligible: false, blockReasons: ["unresolved_symbol"] };
20
- r = await client.futuresQuote({ coinId, side: action.side, leverage: action.leverage, marginMusd: action.marginMusd }, trace);
20
+ r = await client.futuresQuote({
21
+ coinId,
22
+ side: action.side,
23
+ leverage: action.leverage,
24
+ marginMusd: action.marginMusd,
25
+ }, trace);
21
26
  }
22
27
  else if (action.type === "spot_order") {
23
28
  const coinId = coinIdFor(observation, action.symbol);
@@ -48,9 +53,17 @@ export async function fetchQuote(client, action, observation, trace) {
48
53
  estimatedCostMusd: asNum(d.estimatedCostMusd), // spot gross notional
49
54
  // Freshness lives in the response's `observation` block (anti-look-ahead).
50
55
  freshness: freshnessOf(asObj(d.observation)),
56
+ // PM open-time quality-gate preview (additive; older backends omit it → the
57
+ // runner just doesn't early-skip and falls through to the normal path).
58
+ openBlocked: d.openBlocked === true,
59
+ openBlockReasons: d.openBlockReasons,
51
60
  };
52
61
  }
53
- export async function executeAction(client, action, observation, trace, idempotencyKey) {
62
+ export async function executeAction(client, action, observation, trace, idempotencyKey,
63
+ // Optional SELF-REPORTED runner provenance, attached to a pm_open only (the one
64
+ // durable-artifact write path here). Absent => the request is byte-identical to
65
+ // pre-provenance behavior.
66
+ provenance) {
54
67
  if (action.type === "futures_open") {
55
68
  const coinId = coinIdFor(observation, action.symbol);
56
69
  if (!coinId)
@@ -114,6 +127,14 @@ export async function executeAction(client, action, observation, trace, idempote
114
127
  outcomeExternalMarketId: action.outcomeExternalMarketId,
115
128
  stakeMusd: action.stakeMusd,
116
129
  idempotencyKey,
130
+ // The agent's OWN independent forecast (already clamped/omitted by the runner).
131
+ // Included ONLY when present, so an absent forecast leaves the request body
132
+ // byte-identical to pre-forecast behavior.
133
+ ...(action.forecastProbability != null
134
+ ? { forecastProbability: action.forecastProbability }
135
+ : {}),
136
+ // Attach runner provenance only when present (byte-identical to before when absent).
137
+ ...(provenance ? { provenance } : {}),
117
138
  agentTrace: trace,
118
139
  });
119
140
  }