langbot-mcp 0.1.0__tar.gz

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.
@@ -0,0 +1,8 @@
1
+ __pycache__/
2
+ *.pyc
3
+ .env
4
+ .env.*
5
+ .venv/
6
+ dist/
7
+ .pytest_cache/
8
+ .ruff_cache/
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Langbot
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,197 @@
1
+ Metadata-Version: 2.5
2
+ Name: langbot-mcp
3
+ Version: 0.1.0
4
+ Summary: Langbot MCP server: every market on Kalshi and Polymarket, its history and replays against recorded order books, for Claude Code, Cursor, Claude Desktop and Codex.
5
+ Project-URL: Homepage, https://langbot.ai
6
+ Project-URL: Documentation, https://langbot.ai/docs
7
+ Author-email: Langbot <hello@langbot.ai>
8
+ Maintainer-email: Langbot <hello@langbot.ai>
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: backtesting,kalshi,mcp,polymarket,prediction-markets,trading-agents
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Framework :: AsyncIO
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3 :: Only
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Typing :: Typed
21
+ Requires-Python: >=3.12
22
+ Requires-Dist: anthropic>=1.0
23
+ Requires-Dist: fastmcp<5,>=4
24
+ Requires-Dist: httpx>=0.27
25
+ Requires-Dist: langbot-sdk<0.2,>=0.1.0
26
+ Description-Content-Type: text/markdown
27
+
28
+ # langbot-mcp
29
+
30
+ <!-- mcp-name: ai.langbot/langbot -->
31
+
32
+ MCP server for [Langbot](https://langbot.ai), the data and simulation layer for every market on
33
+ Kalshi and Polymarket: search any market and read its price history, compare the same question
34
+ across both venues, replay past events against the order books Langbot recorded, and, for
35
+ markets that settle on what is said (mention markets are one example), the live record of the
36
+ event with verifiable receipts. Data, never trading signals or advice: the optional strategy
37
+ tools are off unless you opt in.
38
+
39
+ Over local stdio, `search_markets` and `get_market_history` work without a token.
40
+
41
+ ```bash
42
+ uvx langbot-mcp # stdio — what Claude Code / Cursor / Claude Desktop / Codex run
43
+ langbot-mcp --http # streamable HTTP on 0.0.0.0:8001 at /mcp (hosted: https://mcp.langbot.ai/mcp); multi-tenant, token per request
44
+ langbot mcp install claude-code # one-command install (also: cursor, claude-desktop, codex, all)
45
+ ```
46
+
47
+ Manual client entry:
48
+
49
+ ```json
50
+ { "mcpServers": { "langbot": { "command": "uvx", "args": ["langbot-mcp"], "env": { "LANGBOT_API_TOKEN": "lb_…" } } } }
51
+ ```
52
+
53
+ Hosted, for clients that send headers (Cursor, Claude Code `--transport http`):
54
+
55
+ ```json
56
+ { "mcpServers": { "langbot": { "url": "https://mcp.langbot.ai/mcp", "headers": { "Authorization": "Bearer lb_…" } } } }
57
+ ```
58
+
59
+ **Auth.** Each tool's `_meta` has `langbot/auth` (`none` | `token`: what the feed needs, which is
60
+ what applies over local stdio) and `langbot/auth_hosted` (always `bearer`). The hosted endpoint
61
+ needs `Authorization: Bearer lb_…` on every tool call and resource read, including `none` tools;
62
+ without a token, run it locally (`uvx langbot-mcp`).
63
+
64
+ ## Tools
65
+
66
+ | tool | what |
67
+ |---|---|
68
+ | `search_markets(query, venue?, status, category?, limit)` | every Kalshi and Polymarket market Langbot lists (no token on stdio) |
69
+ | `get_market_history(ticker, max_points=200)` | one market's status, result and price history; whether its books can be replayed (no token on stdio) |
70
+ | `list_live_events()` | live + upcoming events with sources, markets, phrases |
71
+ | `list_markets(query, venue?, status)` | public market metadata search |
72
+ | `get_market_rules(ticker)` | rules text + phrases for one market |
73
+ | `subscribe_phrases(event_id, phrases[], webhook_url?)` | account subscription (needs token) |
74
+ | `get_transcript(event_id, since_seq?, limit=2000)` | one page of transcript words + `text` and `last_seq` (pass back as `since_seq`); empty with `redacted_sources` for restricted sources |
75
+ | `get_recent_events(event_id?, phrases?, limit)` | latest phrase detections / lifecycle events |
76
+ | `get_latency_stats()` | per-source p50/p90 lag vs public stream |
77
+ | `watch_event(event_id, phrases?, max_wait_s=30, cursor?)` | long-poll: new phrase hits (with §21 `verdict`) since `cursor`, waits ≤ 60 s; token |
78
+
79
+ ### Langbot Sim
80
+
81
+ | tool | what |
82
+ |---|---|
83
+ | `sim_events()` | past events with a feed record and recorded Kalshi books: coverage (book rows, first/last snapshot, tickers, settled markets), Free sample flag, the caller's allowance (public) |
84
+ | `sim_run(event_id, strategy, params?, latency_ms?, starting_cash, detail)` | a built-in strategy (`hold_none`, `buy_yes_on_first_counting_hit`, `buy_yes_near_threshold`, `fade_rule_mismatch`) replayed on the feed → scorecard with the latency table and caveats (token; `langbot/per_call_usd` 0.25 via x402 without a plan). Custom code never runs on the server: `langbot sim run --strategy my_bot.py` runs it locally |
85
+
86
+ ### Opt-in strategy tools (`LANGBOT_MCP_STRATEGY_TOOLS=1`)
87
+
88
+ Off by default: Langbot serves data, not signals. Set `LANGBOT_MCP_STRATEGY_TOOLS=1` in the
89
+ client's `env` to list and allow these three; without it they are hidden and cannot be called.
90
+
91
+ | tool | what |
92
+ |---|---|
93
+ | `draft_strategy(thesis, speaker?, phrase?, series?, window_days)` | Claude drafts a `langbot.Strategy` file (template without `ANTHROPIC_API_KEY`); with `speaker`/`phrase` it fetches base rates and prices the draft off them |
94
+ | `backtest_strategy(code, event_ids[] \| fixture)` | replay through a paper broker → PnL summary |
95
+ | `run_paper(strategy_path \| code)` | POSTs to the local daemon `http://127.0.0.1:8787` (demo mode only) |
96
+
97
+ ### Terminal: what's live, what's priced, what's been said, how often before
98
+
99
+ | tool | what |
100
+ |---|---|
101
+ | `get_calendar(days=7)` | upcoming events with sources, markets, `speaker_keys` and `rights` |
102
+ | `get_market_context(ticker)` | one call per ticker: market + rules, current book, base rate for its speaker/phrase, the event, recent mentions |
103
+ | `get_base_rates(speaker?, phrase?, series?, window_days=365)` | how often that mention market settled YES: `yes_rate`, `markets`, `avg_open_price`, `mispricing` = avg(result − open), `by_month` |
104
+ | `search_outcomes(speaker?, phrase?, series?, venue?, since?, until?, limit, cursor?)` | the settled markets behind a base rate (venue settlement facts, paginated) |
105
+ | `search_mentions(speaker?, phrase?, since?, until?, limit)` | Langbot's own `phrase_detected` facts: phrase, speaker, event, `t_spoken`, `lag_vs_public_ms` — never transcript text |
106
+ | `list_speakers(q?)` | canonical speaker keys (`powell`, `jensen-huang`) with aliases and counts |
107
+
108
+ Each docstring says when an agent should reach for it. Rights (CONTRACTS §10): `get_transcript` returns
109
+ full text for `public_domain` / `licensed` sources and phrase facts only for `restricted` / `unknown`
110
+ ones; `get_calendar` and `get_market_context` carry `rights` so an agent knows in advance.
111
+
112
+ Resources: `langbot://events/live`, `langbot://events/{id}/transcript`, `langbot://latency`,
113
+ `langbot://calendar`, `langbot://context/{ticker}`, `langbot://markets/{ticker}/brief`, and the
114
+ two live (subscribable) ones below.
115
+
116
+ ## Live push
117
+
118
+ | resource | state |
119
+ |---|---|
120
+ | `langbot://events/{event_id}/hits` | every `phrase_detected` on the event, each with its §21 `verdict` (null when the feed has none), and a `cursor` |
121
+ | `langbot://markets/{ticker}/state` | `said`, `counts` (§21 reading; null = unclear), `mention` / `needed` / `mention_text`, `last_hit`, `verdict` |
122
+
123
+ How an agent subscribes depends on the MCP revision its client negotiated; the server serves both:
124
+
125
+ - **2025-11-25 and older**: `resources/subscribe {uri}`; on each `notifications/resources/updated`
126
+ for the URI, `resources/read` it. `resources/unsubscribe` (or disconnecting) stops it.
127
+ - **2026-07-28**: `subscriptions/listen` with `resource_subscriptions: [uri, …]`; the same
128
+ notification rides the listen stream (the SDK's `ListenHandler`), closing it unsubscribes.
129
+ - **neither**: `watch_event` in a loop with the returned `cursor`.
130
+
131
+ Upstream is one `WS /v1/stream` per token (stdio: one; hosted HTTP: one per tenant), filtered to
132
+ the subscribed events and `types=phrase_detected`, re-filtered with `{"op":"subscribe"}`,
133
+ closed when nothing is subscribed, reconnected with jittered backoff (1 → 30 s) and backfilled
134
+ from the transcript after a reconnect. See `live.py`. Push over HTTP needs the default stateful
135
+ streamable HTTP (SSE responses, the GET stream); with `stateless_http` / `json_response` only
136
+ `watch_event` works.
137
+
138
+ ## Paying per call
139
+
140
+ Some feed endpoints are sold by the call (CONTRACTS §17): replay bundles ($0.50), history
141
+ ($0.05), evidence packs ($0.25), provenance reports ($0.10), facts ($0.02) — initial list
142
+ prices. Tools that map to them carry `_meta` `langbot/per_call_usd` next to the plan fields,
143
+ so an agent can read the price before calling, and `get_pricing` passes through the feed's
144
+ `per_call` (always) and `x402` (`{enabled: false}` or `{enabled: true, x402_version, scheme,
145
+ network, pay_to, asset, asset_decimals, facilitator, max_timeout_seconds, headers, …}`) sections.
146
+
147
+ The MCP server holds no wallet. When the feed answers an x402 v2-shaped 402, the tool returns a
148
+ structured error instead of a bare failure:
149
+
150
+ ```json
151
+ {"ok": false, "error": "payment_required", "status": 402, "price_usd": 0.5, "x402Version": 2,
152
+ "accepts": [{"scheme": "exact", "network": "eip155:8453", "amount": "500000", "asset": "0x…USDC", "payTo": "0x…", "maxTimeoutSeconds": 60, "extra": {"name": "USD Coin", "version": "2"}}],
153
+ "pricing_url": "https://langbot.ai/.well-known/langbot-pricing.json", "hint": "…"}
154
+ ```
155
+
156
+ The agent can then pay with its own wallet through the SDK (`LangbotClient(x402_wallet=…)` in
157
+ `langbot-sdk[x402]`, or `@langbotai/sdk` with `x402Wallet`), or ask the user for a plan token.
158
+ A 402 that is not x402-shaped (a plan gate) is reported as before.
159
+
160
+ ## Env
161
+
162
+ | var | default | |
163
+ |---|---|---|
164
+ | `LANGBOT_API_URL` | `https://api.langbot.ai` | feed base URL (Dedicated VPC/on-prem deployments set their own) |
165
+ | `LANGBOT_API_TOKEN` | — | `lb_…` token, **stdio mode only**; public endpoints work without it |
166
+ | `LANGBOT_MCP_STRATEGY_TOOLS` | off | `1` exposes `draft_strategy`, `backtest_strategy`, `run_paper` |
167
+ | `ANTHROPIC_API_KEY` | — | enables `draft_strategy` via Claude |
168
+ | `LANGBOT_LLM_MODEL` | `claude-opus-5-5` | drafting model |
169
+ | `LANGBOT_LLM_EFFORT` | `high` | `output_config.effort` for drafting (`none` to omit) |
170
+ | `LANGBOT_DAEMON_URL` | `http://127.0.0.1:8787` | local agent daemon |
171
+ | `LANGBOT_BACKTEST_FIXTURE` | — | default JSONL fixture for `backtest_strategy` |
172
+ | `LANGBOT_MCP_HOST/PORT/PATH` | `0.0.0.0` / `8001` / `/mcp` | HTTP mode |
173
+
174
+ ## Tokens in HTTP mode
175
+
176
+ `--http` is multi-tenant: every request must carry `Authorization: Bearer lb_…` and that token is used for the feed call; the server's `LANGBOT_API_TOKEN` is ignored. Tool calls and resource reads without a token are refused with a message pointing at <https://langbot.ai/app/tokens> (listing tools still works). The header is read with `fastmcp.server.dependencies.get_http_headers(include={"authorization"})`; see `get_client()` and `TokenGate` in `server.py`.
177
+
178
+ ## Compliance shape
179
+
180
+ The server emits **facts** (what was said, when) and runs nothing live. The strategy tools
181
+ are opt-in (`LANGBOT_MCP_STRATEGY_TOOLS=1`); when enabled, `run_paper` only
182
+ starts demo-mode strategies on the user's local daemon, and `draft_strategy` output is
183
+ reviewed by the user before `langbot run`. Live trading requires `--mode live` plus
184
+ `LANGBOT_I_UNDERSTAND_LIVE=1` on the user's machine.
185
+
186
+ ## Develop
187
+
188
+ ```bash
189
+ uv run --package langbot-mcp pytest services/mcp -q
190
+ docker build -f services/mcp/Dockerfile -t langbot-mcp . # from repo root
191
+ ```
192
+
193
+ Registry metadata: `server.json` (MCP registry, `mcp-publisher publish`) and `smithery.yaml`.
194
+
195
+ ## License
196
+
197
+ MIT (`LICENSE` in this directory). `langbot-mcp` is published on PyPI; it is a thin client over the hosted Langbot feed, which is a proprietary service.
@@ -0,0 +1,170 @@
1
+ # langbot-mcp
2
+
3
+ <!-- mcp-name: ai.langbot/langbot -->
4
+
5
+ MCP server for [Langbot](https://langbot.ai), the data and simulation layer for every market on
6
+ Kalshi and Polymarket: search any market and read its price history, compare the same question
7
+ across both venues, replay past events against the order books Langbot recorded, and, for
8
+ markets that settle on what is said (mention markets are one example), the live record of the
9
+ event with verifiable receipts. Data, never trading signals or advice: the optional strategy
10
+ tools are off unless you opt in.
11
+
12
+ Over local stdio, `search_markets` and `get_market_history` work without a token.
13
+
14
+ ```bash
15
+ uvx langbot-mcp # stdio — what Claude Code / Cursor / Claude Desktop / Codex run
16
+ langbot-mcp --http # streamable HTTP on 0.0.0.0:8001 at /mcp (hosted: https://mcp.langbot.ai/mcp); multi-tenant, token per request
17
+ langbot mcp install claude-code # one-command install (also: cursor, claude-desktop, codex, all)
18
+ ```
19
+
20
+ Manual client entry:
21
+
22
+ ```json
23
+ { "mcpServers": { "langbot": { "command": "uvx", "args": ["langbot-mcp"], "env": { "LANGBOT_API_TOKEN": "lb_…" } } } }
24
+ ```
25
+
26
+ Hosted, for clients that send headers (Cursor, Claude Code `--transport http`):
27
+
28
+ ```json
29
+ { "mcpServers": { "langbot": { "url": "https://mcp.langbot.ai/mcp", "headers": { "Authorization": "Bearer lb_…" } } } }
30
+ ```
31
+
32
+ **Auth.** Each tool's `_meta` has `langbot/auth` (`none` | `token`: what the feed needs, which is
33
+ what applies over local stdio) and `langbot/auth_hosted` (always `bearer`). The hosted endpoint
34
+ needs `Authorization: Bearer lb_…` on every tool call and resource read, including `none` tools;
35
+ without a token, run it locally (`uvx langbot-mcp`).
36
+
37
+ ## Tools
38
+
39
+ | tool | what |
40
+ |---|---|
41
+ | `search_markets(query, venue?, status, category?, limit)` | every Kalshi and Polymarket market Langbot lists (no token on stdio) |
42
+ | `get_market_history(ticker, max_points=200)` | one market's status, result and price history; whether its books can be replayed (no token on stdio) |
43
+ | `list_live_events()` | live + upcoming events with sources, markets, phrases |
44
+ | `list_markets(query, venue?, status)` | public market metadata search |
45
+ | `get_market_rules(ticker)` | rules text + phrases for one market |
46
+ | `subscribe_phrases(event_id, phrases[], webhook_url?)` | account subscription (needs token) |
47
+ | `get_transcript(event_id, since_seq?, limit=2000)` | one page of transcript words + `text` and `last_seq` (pass back as `since_seq`); empty with `redacted_sources` for restricted sources |
48
+ | `get_recent_events(event_id?, phrases?, limit)` | latest phrase detections / lifecycle events |
49
+ | `get_latency_stats()` | per-source p50/p90 lag vs public stream |
50
+ | `watch_event(event_id, phrases?, max_wait_s=30, cursor?)` | long-poll: new phrase hits (with §21 `verdict`) since `cursor`, waits ≤ 60 s; token |
51
+
52
+ ### Langbot Sim
53
+
54
+ | tool | what |
55
+ |---|---|
56
+ | `sim_events()` | past events with a feed record and recorded Kalshi books: coverage (book rows, first/last snapshot, tickers, settled markets), Free sample flag, the caller's allowance (public) |
57
+ | `sim_run(event_id, strategy, params?, latency_ms?, starting_cash, detail)` | a built-in strategy (`hold_none`, `buy_yes_on_first_counting_hit`, `buy_yes_near_threshold`, `fade_rule_mismatch`) replayed on the feed → scorecard with the latency table and caveats (token; `langbot/per_call_usd` 0.25 via x402 without a plan). Custom code never runs on the server: `langbot sim run --strategy my_bot.py` runs it locally |
58
+
59
+ ### Opt-in strategy tools (`LANGBOT_MCP_STRATEGY_TOOLS=1`)
60
+
61
+ Off by default: Langbot serves data, not signals. Set `LANGBOT_MCP_STRATEGY_TOOLS=1` in the
62
+ client's `env` to list and allow these three; without it they are hidden and cannot be called.
63
+
64
+ | tool | what |
65
+ |---|---|
66
+ | `draft_strategy(thesis, speaker?, phrase?, series?, window_days)` | Claude drafts a `langbot.Strategy` file (template without `ANTHROPIC_API_KEY`); with `speaker`/`phrase` it fetches base rates and prices the draft off them |
67
+ | `backtest_strategy(code, event_ids[] \| fixture)` | replay through a paper broker → PnL summary |
68
+ | `run_paper(strategy_path \| code)` | POSTs to the local daemon `http://127.0.0.1:8787` (demo mode only) |
69
+
70
+ ### Terminal: what's live, what's priced, what's been said, how often before
71
+
72
+ | tool | what |
73
+ |---|---|
74
+ | `get_calendar(days=7)` | upcoming events with sources, markets, `speaker_keys` and `rights` |
75
+ | `get_market_context(ticker)` | one call per ticker: market + rules, current book, base rate for its speaker/phrase, the event, recent mentions |
76
+ | `get_base_rates(speaker?, phrase?, series?, window_days=365)` | how often that mention market settled YES: `yes_rate`, `markets`, `avg_open_price`, `mispricing` = avg(result − open), `by_month` |
77
+ | `search_outcomes(speaker?, phrase?, series?, venue?, since?, until?, limit, cursor?)` | the settled markets behind a base rate (venue settlement facts, paginated) |
78
+ | `search_mentions(speaker?, phrase?, since?, until?, limit)` | Langbot's own `phrase_detected` facts: phrase, speaker, event, `t_spoken`, `lag_vs_public_ms` — never transcript text |
79
+ | `list_speakers(q?)` | canonical speaker keys (`powell`, `jensen-huang`) with aliases and counts |
80
+
81
+ Each docstring says when an agent should reach for it. Rights (CONTRACTS §10): `get_transcript` returns
82
+ full text for `public_domain` / `licensed` sources and phrase facts only for `restricted` / `unknown`
83
+ ones; `get_calendar` and `get_market_context` carry `rights` so an agent knows in advance.
84
+
85
+ Resources: `langbot://events/live`, `langbot://events/{id}/transcript`, `langbot://latency`,
86
+ `langbot://calendar`, `langbot://context/{ticker}`, `langbot://markets/{ticker}/brief`, and the
87
+ two live (subscribable) ones below.
88
+
89
+ ## Live push
90
+
91
+ | resource | state |
92
+ |---|---|
93
+ | `langbot://events/{event_id}/hits` | every `phrase_detected` on the event, each with its §21 `verdict` (null when the feed has none), and a `cursor` |
94
+ | `langbot://markets/{ticker}/state` | `said`, `counts` (§21 reading; null = unclear), `mention` / `needed` / `mention_text`, `last_hit`, `verdict` |
95
+
96
+ How an agent subscribes depends on the MCP revision its client negotiated; the server serves both:
97
+
98
+ - **2025-11-25 and older**: `resources/subscribe {uri}`; on each `notifications/resources/updated`
99
+ for the URI, `resources/read` it. `resources/unsubscribe` (or disconnecting) stops it.
100
+ - **2026-07-28**: `subscriptions/listen` with `resource_subscriptions: [uri, …]`; the same
101
+ notification rides the listen stream (the SDK's `ListenHandler`), closing it unsubscribes.
102
+ - **neither**: `watch_event` in a loop with the returned `cursor`.
103
+
104
+ Upstream is one `WS /v1/stream` per token (stdio: one; hosted HTTP: one per tenant), filtered to
105
+ the subscribed events and `types=phrase_detected`, re-filtered with `{"op":"subscribe"}`,
106
+ closed when nothing is subscribed, reconnected with jittered backoff (1 → 30 s) and backfilled
107
+ from the transcript after a reconnect. See `live.py`. Push over HTTP needs the default stateful
108
+ streamable HTTP (SSE responses, the GET stream); with `stateless_http` / `json_response` only
109
+ `watch_event` works.
110
+
111
+ ## Paying per call
112
+
113
+ Some feed endpoints are sold by the call (CONTRACTS §17): replay bundles ($0.50), history
114
+ ($0.05), evidence packs ($0.25), provenance reports ($0.10), facts ($0.02) — initial list
115
+ prices. Tools that map to them carry `_meta` `langbot/per_call_usd` next to the plan fields,
116
+ so an agent can read the price before calling, and `get_pricing` passes through the feed's
117
+ `per_call` (always) and `x402` (`{enabled: false}` or `{enabled: true, x402_version, scheme,
118
+ network, pay_to, asset, asset_decimals, facilitator, max_timeout_seconds, headers, …}`) sections.
119
+
120
+ The MCP server holds no wallet. When the feed answers an x402 v2-shaped 402, the tool returns a
121
+ structured error instead of a bare failure:
122
+
123
+ ```json
124
+ {"ok": false, "error": "payment_required", "status": 402, "price_usd": 0.5, "x402Version": 2,
125
+ "accepts": [{"scheme": "exact", "network": "eip155:8453", "amount": "500000", "asset": "0x…USDC", "payTo": "0x…", "maxTimeoutSeconds": 60, "extra": {"name": "USD Coin", "version": "2"}}],
126
+ "pricing_url": "https://langbot.ai/.well-known/langbot-pricing.json", "hint": "…"}
127
+ ```
128
+
129
+ The agent can then pay with its own wallet through the SDK (`LangbotClient(x402_wallet=…)` in
130
+ `langbot-sdk[x402]`, or `@langbotai/sdk` with `x402Wallet`), or ask the user for a plan token.
131
+ A 402 that is not x402-shaped (a plan gate) is reported as before.
132
+
133
+ ## Env
134
+
135
+ | var | default | |
136
+ |---|---|---|
137
+ | `LANGBOT_API_URL` | `https://api.langbot.ai` | feed base URL (Dedicated VPC/on-prem deployments set their own) |
138
+ | `LANGBOT_API_TOKEN` | — | `lb_…` token, **stdio mode only**; public endpoints work without it |
139
+ | `LANGBOT_MCP_STRATEGY_TOOLS` | off | `1` exposes `draft_strategy`, `backtest_strategy`, `run_paper` |
140
+ | `ANTHROPIC_API_KEY` | — | enables `draft_strategy` via Claude |
141
+ | `LANGBOT_LLM_MODEL` | `claude-opus-5-5` | drafting model |
142
+ | `LANGBOT_LLM_EFFORT` | `high` | `output_config.effort` for drafting (`none` to omit) |
143
+ | `LANGBOT_DAEMON_URL` | `http://127.0.0.1:8787` | local agent daemon |
144
+ | `LANGBOT_BACKTEST_FIXTURE` | — | default JSONL fixture for `backtest_strategy` |
145
+ | `LANGBOT_MCP_HOST/PORT/PATH` | `0.0.0.0` / `8001` / `/mcp` | HTTP mode |
146
+
147
+ ## Tokens in HTTP mode
148
+
149
+ `--http` is multi-tenant: every request must carry `Authorization: Bearer lb_…` and that token is used for the feed call; the server's `LANGBOT_API_TOKEN` is ignored. Tool calls and resource reads without a token are refused with a message pointing at <https://langbot.ai/app/tokens> (listing tools still works). The header is read with `fastmcp.server.dependencies.get_http_headers(include={"authorization"})`; see `get_client()` and `TokenGate` in `server.py`.
150
+
151
+ ## Compliance shape
152
+
153
+ The server emits **facts** (what was said, when) and runs nothing live. The strategy tools
154
+ are opt-in (`LANGBOT_MCP_STRATEGY_TOOLS=1`); when enabled, `run_paper` only
155
+ starts demo-mode strategies on the user's local daemon, and `draft_strategy` output is
156
+ reviewed by the user before `langbot run`. Live trading requires `--mode live` plus
157
+ `LANGBOT_I_UNDERSTAND_LIVE=1` on the user's machine.
158
+
159
+ ## Develop
160
+
161
+ ```bash
162
+ uv run --package langbot-mcp pytest services/mcp -q
163
+ docker build -f services/mcp/Dockerfile -t langbot-mcp . # from repo root
164
+ ```
165
+
166
+ Registry metadata: `server.json` (MCP registry, `mcp-publisher publish`) and `smithery.yaml`.
167
+
168
+ ## License
169
+
170
+ MIT (`LICENSE` in this directory). `langbot-mcp` is published on PyPI; it is a thin client over the hosted Langbot feed, which is a proprietary service.
@@ -0,0 +1,53 @@
1
+ [project]
2
+ name = "langbot-mcp"
3
+ version = "0.1.0"
4
+ description = "Langbot MCP server: every market on Kalshi and Polymarket, its history and replays against recorded order books, for Claude Code, Cursor, Claude Desktop and Codex."
5
+ readme = "README.md"
6
+ license = "MIT"
7
+ license-files = ["LICENSE"]
8
+ requires-python = ">=3.12"
9
+ authors = [{ name = "Langbot", email = "hello@langbot.ai" }]
10
+ maintainers = [{ name = "Langbot", email = "hello@langbot.ai" }]
11
+ keywords = ["mcp", "kalshi", "polymarket", "prediction-markets", "backtesting", "trading-agents"]
12
+ classifiers = [
13
+ "Development Status :: 3 - Alpha",
14
+ "Intended Audience :: Developers",
15
+ "Operating System :: OS Independent",
16
+ "Programming Language :: Python :: 3",
17
+ "Programming Language :: Python :: 3 :: Only",
18
+ "Programming Language :: Python :: 3.12",
19
+ "License :: OSI Approved :: MIT License",
20
+ "Framework :: AsyncIO",
21
+ "Typing :: Typed",
22
+ ]
23
+ dependencies = [
24
+ "langbot-sdk>=0.1.0,<0.2",
25
+ "fastmcp>=4,<5",
26
+ "anthropic>=1.0",
27
+ "httpx>=0.27",
28
+ ]
29
+
30
+ [project.scripts]
31
+ langbot-mcp = "langbot_mcp.server:main"
32
+
33
+ [project.urls]
34
+ Homepage = "https://langbot.ai"
35
+ Documentation = "https://langbot.ai/docs"
36
+
37
+ [build-system]
38
+ requires = ["hatchling>=1.24"]
39
+ build-backend = "hatchling.build"
40
+
41
+ [tool.hatch.build.targets.wheel]
42
+ packages = ["src/langbot_mcp"]
43
+
44
+ [tool.hatch.build.targets.sdist]
45
+ include = ["src/langbot_mcp", "README.md", "LICENSE", "pyproject.toml"]
46
+
47
+ [dependency-groups]
48
+ dev = [
49
+ "pytest>=8",
50
+ "pytest-asyncio>=0.23",
51
+ "respx>=0.21",
52
+ "ruff>=0.5",
53
+ ]
@@ -0,0 +1,3 @@
1
+ """Langbot MCP server package."""
2
+
3
+ __version__ = "0.1.0"