Metadata-Version: 2.4
Name: clause-mcp
Version: 0.1.0
Summary: MCP server for prediction markets: are these two contracts the same bet, and how much size will this market actually take?
Author: Clause
License-Expression: MIT
Keywords: mcp,model-context-protocol,prediction-markets,polymarket,kalshi,order-book,liquidity,market-microstructure
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Financial and Insurance Industry
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Office/Business :: Financial
Classifier: Typing :: Typed
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: httpx>=0.28
Requires-Dist: mcp>=2.0
Provides-Extra: api
Requires-Dist: fastapi>=0.115; extra == "api"
Requires-Dist: uvicorn[standard]>=0.32; extra == "api"
Provides-Extra: chain
Requires-Dist: eth-abi>=5.0; extra == "chain"
Requires-Dist: eth-hash[pycryptodome]>=0.7; extra == "chain"
Requires-Dist: websockets>=15; extra == "chain"
Provides-Extra: postgres
Requires-Dist: psycopg[binary]>=3.2; extra == "postgres"
Provides-Extra: analysis
Requires-Dist: duckdb>=1.5; extra == "analysis"
Requires-Dist: rapidfuzz>=3.14; extra == "analysis"
Provides-Extra: dev
Requires-Dist: pytest>=8.0; extra == "dev"
Requires-Dist: build>=1.2; extra == "dev"
Requires-Dist: twine>=5.0; extra == "dev"
Dynamic: license-file

# clause-mcp

**You are about to trade a spread between two contracts that resolve
differently, and nothing you own will tell you.**

Polymarket lists *"U.S. enacts AI safety bill before 2027?"*. Kalshi lists what
reads as the same contract. Polymarket's resolves YES only on **restrictive
provisions**. Kalshi's resolves YES on a federal framework *"regardless of
whether those provisions mandate private-sector compliance or **promote
voluntary guidelines**."*

A voluntary standards act resolves one YES and the other NO. They are not the
same bet at any price. Every arbitrage screen in existence shows them as one
market at a spread, and a language model reading both rules texts will agree
with the screen — because the divergence is not a difference between the two
documents. It is **an explicit clause on one side matched by silence on the
other**, and silence is the one thing a comparator has to be told not to read
as agreement.

This is an MCP server. It gives an agent the checks it cannot perform on its
own.

---

## The second failure: the book that isn't there

A market on a major venue reported **$65,883** of order-book depth. Within a
sensible band of its own mid it held **$33**. It had traded **$122 in thirty
days**. Putting $200,000 into it is 49,276 days of volume — **135 years**.

A book is an offer. The tape is a fact. When they disagree, believe the tape.

---

## Install

```bash
pip install clause-mcp
```

### Claude Code

```bash
claude mcp add --scope user clause -- clause-mcp
```

`--scope user` matters: the default registers the server for one project
directory only. **The tools appear in a new session**, not the one you ran the
add from.

### Claude Desktop, or any stdio client

```json
{
  "mcpServers": {
    "clause": { "command": "clause-mcp" }
  }
}
```

Streamable-HTTP instead of stdio: `clause-mcp --http --port 8848`.

---

## The eight tools

| Tool | Answers | Needs |
| --- | --- | --- |
| `check_equivalence` | are these two contracts the same bet? | live venues |
| `market_liquidity` | can this market absorb size — book *and* tape | live venues |
| `preflight` | will this specific order work, with numbers | live venues |
| `capacity` | how much fits inside 0.5¢ / 1¢ / 2¢ / 5¢ | live venues |
| `resting_order` | rest or cross, and how long to fill | live venues |
| `venue_conventions` | how each venue's API lies to you | nothing |
| `find_markets` | identifiers the other tools need | an archive |
| `identify_market` | which contract did the user mean, in plain words | an archive |

**Six of the eight work the moment you install this.** They read the venues
live and need no local data.

The two search tools need a Clause archive — a hash-chained daily record of
every open market's terms. This package does not ship one, and it will not
pretend otherwise: with no archive, both tools **refuse**, name the state, and
say in words that nothing was searched.

```json
{
  "ok": false,
  "error": "archive_unavailable",
  "this_is_not_a_negative_result":
    "Do NOT report this as 'no such market' or 'no results'. Nothing was
     searched. The named market may exist and be trading; this install
     simply has no corpus to look in."
}
```

That refusal is the point of the package rather than a limitation of it. The
alternative — falling back to a live search — is what the tool exists to
avoid: Polymarket's list API caps pages at 100 rows and rejects offsets past
~2,100, so a live search silently misses the quiet markets, which are exactly
the ones whose liquidity most needs checking. Point `CLAUSE_DB` at an archive
if you have one.

---

## Why the tool descriptions read the way they do

They are written for the agent, not for a human browsing a catalogue. An agent
does not know it has a problem, so each description leads with the failure it
prevents rather than with what the tool returns. A tool called after the
mistake has been made is a tool that did nothing.

The verdicts are built the same way. `check_equivalence` returns two of them,
because two different things can make two contracts different bets. `verdict`
compares thresholds and settlement sources; it can reach `EQUIVALENT` when
both are genuinely comparable. `criteria_verdict` compares the *provisions* —
subject, jurisdiction, actor, action breadth, voluntary conduct, logical
structure, carve-outs — and it **never returns a bare `EQUIVALENT`**:
`LIKELY_EQUIVALENT` is its ceiling, with the clauses to read attached. That is
the one that catches the AI bills above, and roughly half the board resolves
on provisions rather than on numbers.

An `unknown` on a material field returns `REVIEW_REQUIRED`, never a pass.
`INSUFFICIENT_DATA` is a distinct verdict from `LIQUID` and must never render
as one.

---

## `venue_conventions`

Thirteen documented ways a venue API returns HTTP 200 while being wrong, each
one found by losing time to it and each one pinned by a test. A sample:

- Polymarket's `/book` returns **asks descending** — `asks[0]` is the worst price.
- A **YES bid at 0.10 is a NO ask at 0.90**. One order, two books. Never add the ladders.
- `data-api /trades` **ignores the `asset` parameter** and returns the full tape. A five-row sample "confirms" the filter works.
- Trades are **newest-first**; a capped pull is recent history, so dividing by 30 days understates a busy market ~15×.
- Kalshi's orderbook is under `orderbook_fp`, and **both sides are resting bids** — the NO ask is `1 − best YES bid`.
- Limitless caps `limit` at 25 and **400s above it**, which reads as "0 markets found".

The meta-lesson, and the reason the tools refuse the way they do: **a check
that cannot run reads as a check that passed.**

---

## Honest status

Version 0.1.0. The verdicts are conservative by construction and the refusals
are deliberate, but this is early software with no user base behind it yet.
It measures and records; **it does not recommend positions and it is not legal
advice**. Order transmission is off.

Requires Python 3.11+. Tested on 3.13.

**Name collision:** an unrelated PyPI package called `clause` (a Chinese NLP
SDK) also installs a top-level `clause` module. Installing both into one
environment will produce a broken hybrid. Run this server with `uvx`, `pipx`,
or its own virtualenv — which is how MCP servers are usually run anyway.

MIT licensed.
