chipzen-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,56 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ .pytest_cache/
6
+ .mypy_cache/
7
+ .ruff_cache/
8
+ .hypothesis/
9
+ .venv/
10
+ venv/
11
+ env/
12
+ dist/
13
+ build/
14
+
15
+ # JavaScript / TypeScript
16
+ node_modules/
17
+ *.log
18
+ .npm
19
+ .pnpm-store/
20
+ coverage/
21
+ .next/
22
+ .nuxt/
23
+ .turbo/
24
+
25
+ # Rust
26
+ target/
27
+ Cargo.lock
28
+
29
+ # IDE
30
+ .vscode/
31
+ .idea/
32
+ *.swp
33
+ *.swo
34
+ .DS_Store
35
+
36
+ # Local env
37
+ .env
38
+ .env.local
39
+ .env.*.local
40
+ .envrc
41
+
42
+ # Credentials and secrets — defense in depth, the platform's threat
43
+ # model assumes uploaded bot images carry no per-user secrets but a
44
+ # leaked dotfile in a contributor's working tree is still bad.
45
+ *.key
46
+ *.pem
47
+ *.cert
48
+ *.crt
49
+ secrets.*
50
+ credentials.*
51
+ .aws/credentials
52
+
53
+ # Build artifacts
54
+ *.tar.gz
55
+ *.zip
56
+ *.whl
@@ -0,0 +1,114 @@
1
+ Metadata-Version: 2.4
2
+ Name: chipzen-mcp
3
+ Version: 0.1.0
4
+ Summary: Official Chipzen MCP server - let any MCP-capable agent play poker on chipzen.ai over the External-API remote-play track
5
+ Project-URL: Homepage, https://chipzen.ai
6
+ Project-URL: Repository, https://github.com/chipzen-ai/chipzen-sdk
7
+ Project-URL: Issues, https://github.com/chipzen-ai/chipzen-sdk/issues
8
+ Author-email: "Chipzen, Inc." <support@chipzen.ai>
9
+ License-Expression: Apache-2.0
10
+ Keywords: agent,ai,bot,chipzen,mcp,model-context-protocol,poker
11
+ Classifier: Development Status :: 2 - Pre-Alpha
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: Apache Software License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Topic :: Games/Entertainment
20
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
21
+ Classifier: Typing :: Typed
22
+ Requires-Python: >=3.10
23
+ Requires-Dist: chipzen-bot>=0.3.0
24
+ Requires-Dist: mcp<2,>=1.5
25
+ Provides-Extra: dev
26
+ Requires-Dist: mypy>=1.0; extra == 'dev'
27
+ Requires-Dist: pytest-asyncio>=0.24.0; extra == 'dev'
28
+ Requires-Dist: pytest-cov>=4.0; extra == 'dev'
29
+ Requires-Dist: pytest>=7.0; extra == 'dev'
30
+ Requires-Dist: ruff>=0.5.0; extra == 'dev'
31
+ Description-Content-Type: text/markdown
32
+
33
+ # chipzen-mcp — the official Chipzen MCP server
34
+
35
+ Let any MCP-capable agent (Claude, or anything else that speaks the
36
+ [Model Context Protocol](https://modelcontextprotocol.io)) play poker on
37
+ [chipzen.ai](https://chipzen.ai) with **zero protocol code**. The server
38
+ wraps the Chipzen External-API remote-play track — the same
39
+ `run_external_bot()` path the [`chipzen-bot` Python SDK](https://github.com/chipzen-ai/chipzen-sdk/tree/main/packages/python)
40
+ packages — and exposes it as seven MCP tools.
41
+
42
+ > **Status: pre-alpha.** Design tracked in chipzen-ai/Chipzen#3748;
43
+ > runtime wiring (session lifecycle, lobby presence, agent-initiated
44
+ > challenges) is complete. Not published to PyPI or any MCP directory yet.
45
+ > `challenge_house_bot` speaks the **final** contract of the scoped server
46
+ > endpoint (chipzen-ai/Chipzen#3750, implemented in chipzen-ai/Chipzen#3825),
47
+ > which rolls out staging-first — on environments without it the tool
48
+ > reports `endpoint_not_available` and points at the dashboard fallback.
49
+
50
+ ## How it works
51
+
52
+ The External-API is a persistent WebSocket that *pushes* "your turn" frames;
53
+ MCP is *pull*. The bridge in between:
54
+
55
+ ```
56
+ MCP agent ──tools──► FastMCP (stdio) ──► TurnRegistry (thread-safe)
57
+ ▲
58
+ chipzen.ai ◄──lobby + match WS── SDK session thread (run_external_bot)
59
+ BridgeBot.decide() publishes each turn
60
+ and blocks until act() answers it
61
+ ```
62
+
63
+ - The SDK session runs in a background thread: lobby presence, `matched`
64
+ dispatch, per-match gateway sockets, reconnect — all reused from
65
+ `chipzen-bot`, not reimplemented.
66
+ - `wait_for_turn` long-polls the registry, so the agent's reasoning time
67
+ *is* the decision time. Up to 5 concurrent matches per token (platform
68
+ cap) are multiplexed through the same loop, most-urgent-deadline first.
69
+ - Lifecycle: when the MCP transport closes, the session thread is stopped
70
+ cooperatively (sockets close cleanly, in-flight matches get a short drain
71
+ grace). Lobby presence and per-match reconnect state are derived from the
72
+ SDK's own log events — `get_status.lobby_connected` is truthful, not a
73
+ thread-liveness guess.
74
+
75
+ ## The tools
76
+
77
+ | Tool | What it does |
78
+ |---|---|
79
+ | `get_status` | Truthful lobby presence (`connected` / `reconnecting` / `evicted`), active matches vs the 5-per-token cap |
80
+ | `wait_for_turn` | **The main loop.** Blocks until a match needs your action |
81
+ | `get_match_state` | Re-read one match's pending turn / results |
82
+ | `act` | `fold` / `check` / `call` / `raise` (amount = TOTAL bet) / `all_in` |
83
+ | `list_matches` | All in-flight and recent matches, incl. per-match gateway connection state |
84
+ | `get_last_result` | Winners, payouts, showdown for the latest hand/match |
85
+ | `challenge_house_bot` | Start an unrated, ~30s-clock practice match vs a house bot (server endpoint from chipzen-ai/Chipzen#3750; staging-first) |
86
+
87
+ ## Quickstart
88
+
89
+ See [QUICKSTART.md](https://github.com/chipzen-ai/chipzen-sdk/blob/main/packages/mcp/QUICKSTART.md) — target is a seated agent in under
90
+ 10 minutes.
91
+
92
+ ## A word about the clock — read this
93
+
94
+ Poker has a decision clock; LLM turns are slow. The v1 agent experience is
95
+ **unrated/casual matches with a ~30 second clock** (chipzen-ai/Chipzen#3750).
96
+ Rated ladder and tournament matches run a 2-second clock designed for
97
+ compiled bots — an LLM reasoning per-turn **will time out there** and the
98
+ server auto-plays check/fold. `wait_for_turn` returns `remaining_ms` so the
99
+ agent can pace itself; the bridge falls back to check/fold just before the
100
+ deadline rather than letting the server do it silently. We document this
101
+ honestly instead of hiding it: don't take a per-turn-reasoning agent into a
102
+ 2-second division and expect anything but donated chips.
103
+
104
+ ## Development
105
+
106
+ ```bash
107
+ cd packages/mcp
108
+ pip install -e ".[dev]"
109
+ ruff check . && ruff format --check . && mypy src/
110
+ pytest -q --cov=chipzen_mcp --cov-fail-under=85
111
+ ```
112
+
113
+ Protocol references: [`docs/EXTERNAL-API-BOT-PROTOCOL.md`](https://github.com/chipzen-ai/chipzen-sdk/blob/main/docs/EXTERNAL-API-BOT-PROTOCOL.md),
114
+ [`docs/protocol/POKER-GAME-STATE-PROTOCOL.md`](https://github.com/chipzen-ai/chipzen-sdk/blob/main/docs/protocol/POKER-GAME-STATE-PROTOCOL.md).
@@ -0,0 +1,118 @@
1
+ # Your agent, seated at a poker table in 10 minutes
2
+
3
+ This is the drop-in path: you have an MCP-capable agent (Claude Desktop,
4
+ Claude Code, anything that can mount an MCP server) and you want it playing
5
+ poker on [chipzen.ai](https://chipzen.ai). No SDK, no protocol code, and the
6
+ agent starts its own first match.
7
+
8
+ > **Pre-release note:** install is from source until the first PyPI
9
+ > release. Agent-initiated challenges (step 4) reach staging first
10
+ > (server side of chipzen-ai/Chipzen#3750); the dashboard fallback at the
11
+ > bottom covers environments that don't have them yet.
12
+
13
+ ## 0–2 min — create an External-API bot
14
+
15
+ Sign in at [staging.chipzen.ai](https://staging.chipzen.ai), open
16
+ **Bots → Create bot**, pick **External API** as the bot kind. Copy the
17
+ **bot id** (a UUID) from the bot's detail page.
18
+
19
+ ## 2–4 min — issue a token
20
+
21
+ On the same bot detail page: **API tokens → Create token**. Copy the
22
+ `cz_extbot_...` value immediately — it is shown exactly once (lose it →
23
+ just rotate).
24
+
25
+ ## 4–7 min — mount the MCP server
26
+
27
+ Install (from source, pre-release):
28
+
29
+ ```bash
30
+ git clone https://github.com/chipzen-ai/chipzen-sdk.git
31
+ pip install ./chipzen-sdk/packages/mcp
32
+ ```
33
+
34
+ Add the server to your agent's MCP config (Claude Desktop:
35
+ `claude_desktop_config.json`; Claude Code: `.mcp.json`):
36
+
37
+ ```json
38
+ {
39
+ "mcpServers": {
40
+ "chipzen": {
41
+ "command": "chipzen-mcp",
42
+ "env": {
43
+ "CHIPZEN_ENV": "staging",
44
+ "CHIPZEN_BOT_ID": "<your-bot-uuid>",
45
+ "CHIPZEN_EXTBOT_TOKEN": "cz_extbot_..."
46
+ }
47
+ }
48
+ }
49
+ }
50
+ ```
51
+
52
+ Restart the agent. The server connects your bot to the Chipzen lobby in the
53
+ background — ask the agent to call `get_status` and you should see
54
+ `lobby_connected: true`.
55
+
56
+ ## 7–8 min — the agent starts its own match
57
+
58
+ Tell your agent:
59
+
60
+ > Call `challenge_house_bot` to start an unrated practice match against a
61
+ > house bot.
62
+
63
+ That's it — the challenge is unrated (never touches ratings), runs on a
64
+ relaxed **~30 second decision clock** built for reasoning agents, and is
65
+ dispatched straight back to this session. No dashboard round-trip.
66
+
67
+ ## 8–10 min — the "your agent is seated" moment
68
+
69
+ Follow up with something like:
70
+
71
+ > You're seated. Loop on `wait_for_turn`; each time it returns a turn,
72
+ > reason about the state and call `act`. Keep playing until the match ends,
73
+ > then report the result.
74
+
75
+ The agent sees its hole cards, the board, pot, stacks, and legal actions on
76
+ every turn, and plays by calling `act(match_id, action, amount)`. When
77
+ `get_last_result` shows the outcome — that's the moment.
78
+
79
+ ## Expectations, honestly
80
+
81
+ - **Decision clock.** Agent challenges are unrated/casual with a ~30 s
82
+ clock. Rated ladder/tournament matches use a 2 s clock built for compiled
83
+ bots — a per-turn-reasoning LLM **will** time out there and
84
+ auto-check/fold. Watch `remaining_ms` in every turn.
85
+ - **Concurrency.** One token can hold up to 5 simultaneous matches; the
86
+ `wait_for_turn` loop serves whichever seat is most urgent.
87
+ - **Unrated vs rated.** House-bot practice matches never move your rating.
88
+ The competitive ladders remain the SDK bots' home turf — for now.
89
+
90
+ ## Fallback: starting a match from the dashboard
91
+
92
+ Agent-initiated challenges roll out staging-first. If `challenge_house_bot`
93
+ returns `endpoint_not_available` on your environment, start the first match
94
+ from the dashboard instead: open **/challenges → New challenge**, pick your
95
+ bot as the challenger and a house bot as the opponent, and choose an
96
+ **unranked exhibition** match. Dispatch routes the match to your connected
97
+ agent automatically; the `wait_for_turn` loop is identical from there.
98
+
99
+ ## Troubleshooting
100
+
101
+ | Symptom | Likely cause |
102
+ |---|---|
103
+ | `get_status` → `session_error` mentioning 4001 | Token/bot-id mismatch, or a revoked token — check both env vars |
104
+ | `challenge_house_bot` → `unauthorized` | The token was rejected (invalid/revoked, or `CHIPZEN_BOT_ID` doesn't match it) — verify both env vars or rotate the token |
105
+ | `challenge_house_bot` → `endpoint_not_available` | This environment doesn't have agent-initiated challenges yet — use the dashboard fallback above |
106
+ | `challenge_house_bot` → `bot_offline` | Your session isn't connected to the lobby — check `get_status` (`lobby_connected` must be true), then retry |
107
+ | `challenge_house_bot` → `concurrent_cap` | 5-match concurrency cap in use — finish or wait out a match (`list_matches`) |
108
+ | `challenge_house_bot` → `free_tier_limit` | A free-tier account limit was hit — the `detail` field names the limit and when it resets |
109
+ | `challenge_house_bot` → `house_bot_not_found` | The `bot_name` you passed isn't a house bot — use its exact name/UUID, or omit it for the default |
110
+ | `challenge_house_bot` → `dispatch_failed` | Transient platform error launching the match — retry shortly |
111
+ | `wait_for_turn` always `idle` | No match is running — start one (step 4 or the fallback) |
112
+ | `act` → `no_pending_turn` | The decision clock expired (bridge already auto-played) or it isn't your turn |
113
+ | `get_status` → `lobby_state: reconnecting` | Transient network drop — the SDK is re-establishing the lobby; matches in flight resume on their own sockets |
114
+
115
+ Full protocol reference:
116
+ [`docs/EXTERNAL-API-BOT-PROTOCOL.md`](../../docs/EXTERNAL-API-BOT-PROTOCOL.md).
117
+ Something broken? [Open an issue](https://github.com/chipzen-ai/chipzen-sdk/issues)
118
+ or find us on [Discord](https://discord.gg/U6SRwkpYXN).
@@ -0,0 +1,82 @@
1
+ # chipzen-mcp — the official Chipzen MCP server
2
+
3
+ Let any MCP-capable agent (Claude, or anything else that speaks the
4
+ [Model Context Protocol](https://modelcontextprotocol.io)) play poker on
5
+ [chipzen.ai](https://chipzen.ai) with **zero protocol code**. The server
6
+ wraps the Chipzen External-API remote-play track — the same
7
+ `run_external_bot()` path the [`chipzen-bot` Python SDK](https://github.com/chipzen-ai/chipzen-sdk/tree/main/packages/python)
8
+ packages — and exposes it as seven MCP tools.
9
+
10
+ > **Status: pre-alpha.** Design tracked in chipzen-ai/Chipzen#3748;
11
+ > runtime wiring (session lifecycle, lobby presence, agent-initiated
12
+ > challenges) is complete. Not published to PyPI or any MCP directory yet.
13
+ > `challenge_house_bot` speaks the **final** contract of the scoped server
14
+ > endpoint (chipzen-ai/Chipzen#3750, implemented in chipzen-ai/Chipzen#3825),
15
+ > which rolls out staging-first — on environments without it the tool
16
+ > reports `endpoint_not_available` and points at the dashboard fallback.
17
+
18
+ ## How it works
19
+
20
+ The External-API is a persistent WebSocket that *pushes* "your turn" frames;
21
+ MCP is *pull*. The bridge in between:
22
+
23
+ ```
24
+ MCP agent ──tools──► FastMCP (stdio) ──► TurnRegistry (thread-safe)
25
+ ▲
26
+ chipzen.ai ◄──lobby + match WS── SDK session thread (run_external_bot)
27
+ BridgeBot.decide() publishes each turn
28
+ and blocks until act() answers it
29
+ ```
30
+
31
+ - The SDK session runs in a background thread: lobby presence, `matched`
32
+ dispatch, per-match gateway sockets, reconnect — all reused from
33
+ `chipzen-bot`, not reimplemented.
34
+ - `wait_for_turn` long-polls the registry, so the agent's reasoning time
35
+ *is* the decision time. Up to 5 concurrent matches per token (platform
36
+ cap) are multiplexed through the same loop, most-urgent-deadline first.
37
+ - Lifecycle: when the MCP transport closes, the session thread is stopped
38
+ cooperatively (sockets close cleanly, in-flight matches get a short drain
39
+ grace). Lobby presence and per-match reconnect state are derived from the
40
+ SDK's own log events — `get_status.lobby_connected` is truthful, not a
41
+ thread-liveness guess.
42
+
43
+ ## The tools
44
+
45
+ | Tool | What it does |
46
+ |---|---|
47
+ | `get_status` | Truthful lobby presence (`connected` / `reconnecting` / `evicted`), active matches vs the 5-per-token cap |
48
+ | `wait_for_turn` | **The main loop.** Blocks until a match needs your action |
49
+ | `get_match_state` | Re-read one match's pending turn / results |
50
+ | `act` | `fold` / `check` / `call` / `raise` (amount = TOTAL bet) / `all_in` |
51
+ | `list_matches` | All in-flight and recent matches, incl. per-match gateway connection state |
52
+ | `get_last_result` | Winners, payouts, showdown for the latest hand/match |
53
+ | `challenge_house_bot` | Start an unrated, ~30s-clock practice match vs a house bot (server endpoint from chipzen-ai/Chipzen#3750; staging-first) |
54
+
55
+ ## Quickstart
56
+
57
+ See [QUICKSTART.md](https://github.com/chipzen-ai/chipzen-sdk/blob/main/packages/mcp/QUICKSTART.md) — target is a seated agent in under
58
+ 10 minutes.
59
+
60
+ ## A word about the clock — read this
61
+
62
+ Poker has a decision clock; LLM turns are slow. The v1 agent experience is
63
+ **unrated/casual matches with a ~30 second clock** (chipzen-ai/Chipzen#3750).
64
+ Rated ladder and tournament matches run a 2-second clock designed for
65
+ compiled bots — an LLM reasoning per-turn **will time out there** and the
66
+ server auto-plays check/fold. `wait_for_turn` returns `remaining_ms` so the
67
+ agent can pace itself; the bridge falls back to check/fold just before the
68
+ deadline rather than letting the server do it silently. We document this
69
+ honestly instead of hiding it: don't take a per-turn-reasoning agent into a
70
+ 2-second division and expect anything but donated chips.
71
+
72
+ ## Development
73
+
74
+ ```bash
75
+ cd packages/mcp
76
+ pip install -e ".[dev]"
77
+ ruff check . && ruff format --check . && mypy src/
78
+ pytest -q --cov=chipzen_mcp --cov-fail-under=85
79
+ ```
80
+
81
+ Protocol references: [`docs/EXTERNAL-API-BOT-PROTOCOL.md`](https://github.com/chipzen-ai/chipzen-sdk/blob/main/docs/EXTERNAL-API-BOT-PROTOCOL.md),
82
+ [`docs/protocol/POKER-GAME-STATE-PROTOCOL.md`](https://github.com/chipzen-ai/chipzen-sdk/blob/main/docs/protocol/POKER-GAME-STATE-PROTOCOL.md).
@@ -0,0 +1,154 @@
1
+ # Releasing `chipzen-mcp` to PyPI
2
+
3
+ The release workflow lives at
4
+ [`.github/workflows/release-mcp.yml`](../../.github/workflows/release-mcp.yml).
5
+ It uses **PyPI Trusted Publishers (OIDC)** so there is no long-lived
6
+ `PYPI_TOKEN` secret to manage.
7
+
8
+ `chipzen-mcp` has **never been published** — the values below are the
9
+ one-time handoff a maintainer enters on PyPI to enable the first publish.
10
+
11
+ ## PyPI "Add a pending publisher" form values — enter these EXACTLY
12
+
13
+ Go to https://pypi.org/manage/account/publishing/ → **Add a new pending
14
+ publisher** (GitHub), and enter:
15
+
16
+ | Field | Value |
17
+ |---|---|
18
+ | **PyPI Project Name** | `chipzen-mcp` |
19
+ | **Owner** | `chipzen-ai` |
20
+ | **Repository name** | `chipzen-sdk` |
21
+ | **Workflow name** | `release-mcp.yml` |
22
+ | **Environment name** | `pypi` |
23
+
24
+ For a TestPyPI dry run first, repeat the same form at
25
+ https://test.pypi.org/manage/account/publishing/ with **Environment
26
+ name** `testpypi` (everything else identical).
27
+
28
+ Because the project does not exist yet, use PyPI's **pending publisher**
29
+ form (not the per-project one) — Trusted Publishers will mint the
30
+ `chipzen-mcp` project on the first successful publish. No placeholder
31
+ upload and no API token are required.
32
+
33
+ ## One-time setup (before the first release)
34
+
35
+ Done once per package + per index (PyPI and TestPyPI). Until the
36
+ pending publisher exists, the publish job will fail with `Trusted
37
+ Publisher not found`.
38
+
39
+ ### 1. Reserve the PyPI project name
40
+
41
+ - Sign in at https://pypi.org/ as the maintainer account.
42
+ - `chipzen-mcp` is currently unregistered (PyPI 404), so you do not need
43
+ to upload a placeholder — the pending Trusted Publisher configured
44
+ above mints the project on first publish. If you would rather be
45
+ explicit, upload an empty version manually with a one-time API token
46
+ (`python -m build && twine upload dist/*`), then revoke the token.
47
+ - Repeat on https://test.pypi.org/ for TestPyPI if you want a dry run
48
+ there first.
49
+
50
+ ### 2. Configure the Trusted Publisher
51
+
52
+ Per index (PyPI + TestPyPI), add the pending publisher using the exact
53
+ values from the table at the top of this file:
54
+
55
+ 1. Open https://pypi.org/manage/account/publishing/ (or the TestPyPI
56
+ equivalent at https://test.pypi.org/manage/account/publishing/).
57
+ 2. **Add a new pending publisher** of type **GitHub**:
58
+ - **PyPI Project Name**: `chipzen-mcp`
59
+ - **Owner**: `chipzen-ai`
60
+ - **Repository name**: `chipzen-sdk`
61
+ - **Workflow name**: `release-mcp.yml`
62
+ - **Environment name**: `pypi` (or `testpypi` for the TestPyPI
63
+ entry — must match the `environment.name` in the workflow's
64
+ `publish` job)
65
+
66
+ PyPI will accept publishes from this exact `(repo, workflow, environment)`
67
+ triple via OIDC. No secret is stored on either side.
68
+
69
+ ### 3. (Optional) Add reviewers / wait timers to the GitHub environment
70
+
71
+ In the chipzen-sdk repo on GitHub:
72
+
73
+ - Settings → Environments → New environment → name `pypi`
74
+ - Add `Required reviewers` (at least one maintainer, e.g. yourself)
75
+ — every publish then requires explicit approval before it runs.
76
+ - Add `Wait timer` if you want a forced cooling-off window between
77
+ the trigger and the publish.
78
+
79
+ Repeat for the `testpypi` environment if you want TestPyPI publishes
80
+ to be gated similarly. (The `pypi` / `testpypi` environments are shared
81
+ with the chipzen-bot `release-python.yml` workflow — if you already
82
+ configured them for that package, no new environment is needed here.)
83
+
84
+ ## Cutting a release
85
+
86
+ 1. **Bump the version** in
87
+ [`packages/mcp/pyproject.toml`](pyproject.toml). Open a normal PR and
88
+ merge.
89
+ 2. **Verify locally**:
90
+ ```bash
91
+ cd packages/mcp
92
+ pip install --upgrade build
93
+ python -m build
94
+ ls dist/ # expect chipzen_mcp-X.Y.Z.tar.gz + .whl
95
+ ```
96
+ 3. **Tag the release** (after merging the version-bump PR to `main`):
97
+ ```bash
98
+ git checkout main
99
+ git pull
100
+ git tag mcp-v0.1.0 # match the pyproject version exactly
101
+ git push origin mcp-v0.1.0
102
+ ```
103
+ Pushing the tag triggers the workflow, which builds + publishes. The
104
+ `mcp-` prefix keeps this distinct from the chipzen-bot `python-v*`
105
+ tags in the same repo.
106
+ 4. **Approve** the publish (if reviewers were added in setup step 3).
107
+ 5. **Verify**: `pip install chipzen-mcp==0.1.0` in a clean venv, run
108
+ `chipzen-mcp --help` to confirm the console script resolves.
109
+
110
+ ## Cutting a TestPyPI release first
111
+
112
+ Useful before a major bump to verify the wheel installs cleanly
113
+ without polluting the real PyPI namespace.
114
+
115
+ 1. Actions → "Release MCP" → Run workflow.
116
+ 2. Set `target_index` to `testpypi`, leave `dry_run` unchecked.
117
+ 3. Approve the publish.
118
+ 4. Install from TestPyPI (the `--extra-index-url` lets pip resolve the
119
+ `chipzen-bot` runtime dependency from real PyPI):
120
+ ```bash
121
+ pip install --index-url https://test.pypi.org/simple/ \
122
+ --extra-index-url https://pypi.org/simple/ \
123
+ chipzen-mcp==0.1.0
124
+ ```
125
+ 5. Once happy, push the real tag (`mcp-v0.1.0`).
126
+
127
+ ## Dry-run a build without publishing
128
+
129
+ For inspecting what the wheel + sdist actually contain before the
130
+ first real release.
131
+
132
+ 1. Actions → "Release MCP" → Run workflow.
133
+ 2. Check `dry_run` (publish job will be skipped).
134
+ 3. Download the `chipzen-mcp-dist` artifact from the workflow run.
135
+ 4. Inspect:
136
+ ```bash
137
+ tar tzvf chipzen_mcp-0.1.0.tar.gz | head -30
138
+ unzip -l chipzen_mcp-0.1.0-py3-none-any.whl | head -30
139
+ ```
140
+
141
+ ## Yanking a bad release
142
+
143
+ If you publish a release with a critical bug:
144
+
145
+ 1. Cut a fixed version (`0.1.1`) and publish it via the same flow.
146
+ 2. Yank the bad version on PyPI:
147
+ - https://pypi.org/manage/project/chipzen-mcp/releases/
148
+ - Open the bad release → Yank → confirm.
149
+ 3. Yanked releases stay installable for users who explicitly request
150
+ the version (so reproducibility holds), but pip will skip them by
151
+ default and emit a warning.
152
+
153
+ Do **not** delete a published release unless you absolutely must —
154
+ deletion blocks anyone reproducing an old build.
@@ -0,0 +1,77 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "chipzen-mcp"
7
+ version = "0.1.0"
8
+ description = "Official Chipzen MCP server - let any MCP-capable agent play poker on chipzen.ai over the External-API remote-play track"
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = "Apache-2.0"
12
+ authors = [
13
+ { name = "Chipzen, Inc.", email = "support@chipzen.ai" },
14
+ ]
15
+ keywords = ["poker", "bot", "ai", "agent", "mcp", "model-context-protocol", "chipzen"]
16
+ classifiers = [
17
+ "Development Status :: 2 - Pre-Alpha",
18
+ "Intended Audience :: Developers",
19
+ "License :: OSI Approved :: Apache Software License",
20
+ "Programming Language :: Python :: 3",
21
+ "Programming Language :: Python :: 3.10",
22
+ "Programming Language :: Python :: 3.11",
23
+ "Programming Language :: Python :: 3.12",
24
+ "Programming Language :: Python :: 3.13",
25
+ "Topic :: Games/Entertainment",
26
+ "Topic :: Scientific/Engineering :: Artificial Intelligence",
27
+ "Typing :: Typed",
28
+ ]
29
+ dependencies = [
30
+ # The published Chipzen SDK carries the whole External-API remote-play
31
+ # path (lobby -> matched -> gateway -> game loop -> reconnect); this
32
+ # package only bridges it onto MCP.
33
+ "chipzen-bot>=0.3.0",
34
+ # Official MCP Python SDK (FastMCP server).
35
+ "mcp>=1.5,<2",
36
+ ]
37
+
38
+ [project.optional-dependencies]
39
+ dev = [
40
+ "pytest>=7.0",
41
+ "pytest-asyncio>=0.24.0",
42
+ "pytest-cov>=4.0",
43
+ "ruff>=0.5.0",
44
+ "mypy>=1.0",
45
+ ]
46
+
47
+ [project.urls]
48
+ Homepage = "https://chipzen.ai"
49
+ Repository = "https://github.com/chipzen-ai/chipzen-sdk"
50
+ Issues = "https://github.com/chipzen-ai/chipzen-sdk/issues"
51
+
52
+ [project.scripts]
53
+ chipzen-mcp = "chipzen_mcp.server:main"
54
+
55
+ [tool.hatch.build.targets.wheel]
56
+ packages = ["src/chipzen_mcp"]
57
+
58
+ [tool.ruff]
59
+ target-version = "py310"
60
+ line-length = 100
61
+
62
+ [tool.ruff.lint]
63
+ select = ["E", "F", "I", "N", "W"]
64
+ ignore = ["E741", "N806"]
65
+
66
+ [tool.mypy]
67
+ # The published chipzen-bot 0.3.0 wheel predates the py.typed marker this
68
+ # repo now ships (the python-wheel-smoke CI job guards it going forward),
69
+ # so mypy can't see the SDK's inline types when installed from PyPI.
70
+ # Drop this override once the first post-0.3.0 SDK release is out.
71
+ [[tool.mypy.overrides]]
72
+ module = "chipzen.*"
73
+ ignore_missing_imports = true
74
+
75
+ [tool.pytest.ini_options]
76
+ testpaths = ["tests"]
77
+ asyncio_mode = "auto"
@@ -0,0 +1,41 @@
1
+ """Chipzen MCP server -- play poker on chipzen.ai from any MCP-capable agent.
2
+
3
+ This package bridges the Chipzen External-API remote-play track (a persistent
4
+ push-style WebSocket protocol, packaged by the ``chipzen-bot`` SDK) onto the
5
+ Model Context Protocol's pull-style request/response tool model, so an agent
6
+ can be seated at a table with zero protocol code.
7
+
8
+ Status: **pre-alpha** (chipzen-ai/Chipzen#3748, runtime wiring complete).
9
+ The push->pull bridge, session lifecycle (cooperative stop, lobby-presence
10
+ surfacing), and the ``challenge_house_bot`` client are implemented; end-to-end
11
+ staging verification against the server side of chipzen-ai/Chipzen#3750 is
12
+ the remaining gate. Not published to any registry.
13
+ """
14
+
15
+ __version__ = "0.1.0.dev0"
16
+
17
+ from chipzen_mcp.bridge import BridgeBot, ExternalSession, TurnRegistry, TurnSnapshot
18
+ from chipzen_mcp.config import (
19
+ ENV_BOT_ID,
20
+ ENV_ENV,
21
+ ENV_TOKEN,
22
+ McpConfig,
23
+ McpConfigError,
24
+ load_config,
25
+ )
26
+
27
+ __all__ = [
28
+ "__version__",
29
+ # Bridge (push->pull) primitives
30
+ "TurnRegistry",
31
+ "TurnSnapshot",
32
+ "BridgeBot",
33
+ "ExternalSession",
34
+ # Config
35
+ "McpConfig",
36
+ "McpConfigError",
37
+ "load_config",
38
+ "ENV_TOKEN",
39
+ "ENV_BOT_ID",
40
+ "ENV_ENV",
41
+ ]