Skip to main content
Glama
xch1tbllc

storm-mcp

by xch1tbllc
README.md
# storm-mcp

MCP server that exposes the [Eyewall Markets](https://eyewallmarkets.com) public prediction-market reference dataset to any Model Context Protocol client.

Eyewall Markets is a market-data and research subscription. It maps the same real-world event across Polymarket, Kalshi, Manifold, ForecastEx, Futuur, Betfair, and other public prediction-market venues into a single canonical record, normalises each venue's published prices for that venue's posted fees, and publishes the comparison. The service is operated autonomously by an AI agent named **Storm** — there is no human in the loop.

This package is a thin stdio MCP bridge that lets LLM clients — Claude Desktop, Claude Code, Cursor, Zed, and any other MCP-aware host — read Storm's canonical events, recent cross-venue published-price observations, venue reference table, and the subscriber's own notification inbox as native tool calls.

It is intended for analysts, researchers, and agent builders who already have an Eyewall Markets subscription and want their LLM workspace to see what Storm sees. Everything the server returns is descriptive: published-price observations, the event ontology, and notifications a subscriber configured. Nothing returned is a buy or sell recommendation.

---

## Edge-tier required

> The Eyewall Markets API is gated to **Edge-tier** subscribers ($499/mo). Generate your `api_key` at <https://eyewallmarkets.com/account>. Lower tiers do not have API access and will receive `HTTP 403` from every endpoint this server calls.

API keys are formatted `stk_` followed by 48 hex characters (52 characters total) and are scoped to a single account. Treat them like any other bearer credential.

The full API reference lives at <https://eyewallmarkets.com/api/docs>.

---

## Quick start — Claude Desktop

Edit your Claude Desktop MCP config file and add a `storm` entry under `mcpServers`:

```json
{
  "mcpServers": {
    "storm": {
      "command": "npx",
      "args": ["-y", "@eyewallmarkets/storm-mcp"],
      "env": {
        "STORM_API_KEY": "stk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
      }
    }
  }
}
```

The macOS path is:

```
~/Library/Application Support/Claude/claude_desktop_config.json
```

> Linux: `~/.config/Claude/claude_desktop_config.json` &middot; Windows: `%APPDATA%\Claude\claude_desktop_config.json`.

Restart Claude Desktop. The seven `storm_*` tools should appear in the tools list inside any new conversation.

---

## Quick start — Claude Code

```
claude mcp add storm npx -- -y @eyewallmarkets/storm-mcp
```

Then export the API key into the environment Claude Code spawns the server in (or set it in your shell profile):

```
export STORM_API_KEY=stk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
```

The exact CLI invocation may vary by Claude Code version; see the official docs at <https://docs.claude.com/en/docs/claude-code/mcp> for the canonical form (including how to pass env vars on the `mcp add` line itself).

After install, run `/mcp` inside Claude Code to confirm the `storm` server is connected and the seven tools are registered.

---

## Quick start — Cursor

Cursor reads MCP server definitions from `~/.cursor/mcp.json`. Add the same shape used for Claude Desktop:

```json
{
  "mcpServers": {
    "storm": {
      "command": "npx",
      "args": ["-y", "@eyewallmarkets/storm-mcp"],
      "env": {
        "STORM_API_KEY": "stk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
      }
    }
  }
}
```

Reload Cursor's MCP integration (Settings &rarr; MCP &rarr; Refresh).

---

## Quick start — Zed

Zed configures MCP servers under `assistant.context_servers` in `~/.config/zed/settings.json`:

```json
{
  "assistant": {
    "context_servers": {
      "storm": {
        "command": "npx",
        "args": ["-y", "@eyewallmarkets/storm-mcp"],
        "env": {
          "STORM_API_KEY": "stk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
        }
      }
    }
  }
}
```

Restart Zed or reload the assistant panel.

---

## Configuration

All configuration is via environment variables read at server start.

| Variable | Required | Default | Description |
|---|---|---|---|
| `STORM_API_KEY` | yes | &mdash; | Edge-tier api key, format `stk_<48 hex>`. Without this the server starts but every tool call fails. |
| `STORM_API_BASE` | no | `https://eyewallmarkets.com/api/v1` | Override the API root. Useful for staging or a local dev server. |
| `STORM_HTTP_TIMEOUT` | no | `15000` | Per-request timeout in milliseconds. |
| `STORM_MCP_LOG_LEVEL` | no | `info` | One of `silent`, `error`, `warn`, `info`, `debug`. Logs go to stderr so they do not corrupt the stdio MCP transport. |

---

## Tool reference

All seven tools are read-only and idempotent. Argument shapes are documented in JSON-schema-ish form below; the live schema is what the MCP client actually sees.

### `storm_list_events`

List canonical (cross-venue) events. Cursor-paginated.

```json
{
  "limit":    { "type": "integer", "default": 50, "max": 200 },
  "cursor":   { "type": "string",  "optional": true },
  "category": { "type": "string",  "optional": true, "example": "politics" },
  "status":   { "type": "string",  "optional": true, "enum": ["open", "closed", "resolved"] }
}
```

Example prompt: *"List the next 20 open politics events on Eyewall Markets."*

### `storm_get_event`

Fetch a single canonical event by slug, including all linked outcomes and per-venue published prices.

```json
{
  "slug": { "type": "string", "required": true, "example": "us-pres-2028" }
}
```

Example prompt: *"Pull the full Eyewall Markets record for `us-pres-2028` and tell me which outcome has the widest cross-venue published-price difference."*

### `storm_list_spreads`

List recent cross-venue published-price observations — events where two venues are publishing different prices for the same canonical outcome. Returns rows whose published-price difference net of venue fees clears the floor, sorted by `net_edge_bps` DESC.

```json
{
  "min_edge_bps": { "type": "integer", "default": 100 },
  "limit":        { "type": "integer", "default": 50, "max": 200 },
  "cursor":       { "type": "string",  "optional": true }
}
```

Each row reports what each venue is publishing at the observation timestamp; it is descriptive market data, not a buy or sell recommendation, and Eyewall Markets does not warrant fillable depth at any price returned.

Example prompt: *"Show me the top 10 cross-venue published-price observations on Eyewall Markets where `net_edge_bps >= 250`."*

### `storm_get_market`

Look up a single venue/market record by `(venue_slug, external_id)`.

```json
{
  "venue":       { "type": "string", "required": true, "example": "polymarket" },
  "external_id": { "type": "string", "required": true }
}
```

Example prompt: *"Look up Polymarket market `0xabc...` on Eyewall Markets."*

### `storm_list_venues`

List every venue Eyewall Markets covers, with regulatory posture (CFTC-registered DCM, offshore, etc.), posted fee schedules, and capability flags (orderbook, AMM, parimutuel). Reference data only — venue eligibility for any individual user is governed by the venue and the user's local law.

```json
{}
```

Example prompt: *"Which of the venues Eyewall Markets covers are CFTC-registered DCMs?"*

### `storm_get_alerts_inbox`

Poll the subscriber's api-channel notification inbox. Edge subscribers can route notifications to the `api` delivery channel; this tool drains the unack'd queue.

```json
{
  "since": { "type": "integer", "minimum": 0, "optional": true, "example": 4521 }
}
```

The cursor is the integer `id` of the last notification you've seen. Pass `next_since` from the previous response to fetch only newer items; omit to read from the subscriber's persisted ack cursor. Each item is a descriptive notification — it names the canonical event, the two venues, the prices each venue was publishing at the observation timestamp, and the notification rule that matched.

Example prompt: *"Poll my Eyewall Markets inbox and summarise everything I haven't acked."*

### `storm_ack_alerts`

Advance the persistent ack cursor so future inbox polls skip already-handled items. The cursor is server-side and survives across MCP sessions.

```json
{
  "up_to": { "type": "integer", "minimum": 0, "required": true, "example": 4530 }
}
```

Example prompt: *"Ack all Eyewall Markets notifications up to right now."*

---

## Example transcripts

### Comparing published prices across venues for one event family

> **User:** Find me 2028-election cross-venue observations on Eyewall Markets where `net_edge_bps >= 300` and tell me which three events have the widest published-price differences.
>
> **Assistant:** *(calls `storm_list_spreads` with `min_edge_bps: 300, limit: 50`, filters the response by event slug prefix `2028_us_presidential_`, then calls `storm_get_event` on the top three to enrich)*
>
> Returns the three 2028-election events with the widest currently-published cross-venue price differences, the venue pair on each side, and which venue is publishing the lower price. Descriptive market data only; not a recommendation.

### Inbox triage

> **User:** Poll my Eyewall Markets inbox and summarise unack'd notifications, then ack everything you summarised.
>
> **Assistant:** *(calls `storm_get_alerts_inbox` with no `since`, summarises the items by category, then calls `storm_ack_alerts` with `up_to` set to the largest `id` it saw)*
>
> Returns a categorised summary of unack'd notifications (cross-venue published-price observations that matched a rule, venue-status changes, resolution events) and confirms the cursor advance so subsequent polls only return new items.

---

## Rate limits and error handling

The Eyewall Markets API enforces **10 requests per second per api key** server-side. If you exceed that, the server returns `HTTP 429` with `Retry-After: 1`. This MCP bridge does **not** retry automatically; it surfaces the error to the LLM as plain text content in the tool result so the model can decide whether to back off, retry, or give up.

Errors are returned to the LLM in this shape (text content on the tool result, `isError: true`):

```
Storm API error (HTTP 429, rate_limited): too many requests Retry after 1000 ms.
```

```
Storm API error (HTTP 403, edge_tier_required): edge_tier_required
```

```
Storm API error (HTTP 401, invalid_credentials): invalid_credentials
```

Network-level failures (DNS, TCP, TLS, timeout) surface as:

```
Storm API error (HTTP 0, transport): request timeout
```

The full HTTP status, server error code, and human message are always included so the LLM can act on them.

---

## Development

```
git clone https://github.com/xch1tbllc/storm-mcp.git
cd storm-mcp
npm install
npm test
```

Point at a local Storm dev server by overriding the API base:

```
STORM_API_BASE=http://localhost:8080/api/v1 \
STORM_API_KEY=stk_dev_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx \
node src/index.mjs
```

The server speaks stdio MCP, so you can drive it directly with any MCP test harness or by piping JSON-RPC frames in by hand.

Tests use Node's built-in test runner; no Jest, no Vitest, no transpiler.

---

## License

MIT &mdash; see [LICENSE](./LICENSE).

&copy; 2026 XCH1TB, LLC dba Eyewall Markets.

Storm itself &mdash; the autonomous AI agent that operates Eyewall Markets and produces the data this server exposes &mdash; is a separate, internal codebase. This package is only the client-facing MCP bridge to Eyewall Markets' public read-only API surface.

---

## Disclaimer

This software and the data it surfaces are provided **for informational purposes only**. Eyewall Markets is a market-data and research subscription, not a broker, exchange, trading platform, or financial advisor. The service does not place orders on any venue, does not custody funds, and does not recommend buying or selling any contract. Nothing returned by this MCP server is legal, financial, tax, or investment advice.

Prediction-market participation is subject to your local laws and to each venue's own eligibility rules; in particular, Polymarket is restricted in the United States under CFTC orders and is not available to most US persons. **Venue eligibility is the user's responsibility — not Eyewall Markets', not Storm's, and not this server's.** Eyewall Markets aggregates publicly observable market state and does not place trades on anyone's behalf.

---

## Autonomous-agent disclosure

Eyewall Markets is operated autonomously by an AI agent named **Storm**. Storm polls each covered venue's public read endpoint, normalises the observations, decides which observations match a subscriber's notification rule, dispatches notifications, and answers support mail at <storm@eyewallmarkets.com>. There is no human in the loop — no reviewer queue, no support team behind the inbox, no analyst checking matches before they go live. Errors are made and corrected by software. The [methodology page](https://eyewallmarkets.com/methodology) describes the provenance Storm stamps onto every match so a reader can see what was decided by a deterministic rule, what by an LLM proposal, and what by Storm's autonomous review.

TDQS

A4.5/5.0

Scored across 7 tools

Disambiguation5/5

Each tool targets a distinct action or resource: acking alerts, polling inbox, fetching events/markets, listing events/spreads/venues. No two tools have overlapping purposes, and descriptions clearly differentiate them.

Naming Consistency5/5

All tools follow a consistent 'storm_verb_noun' pattern in snake_case, with verbs like ack, get, list. This makes it easy for an agent to infer functionality from names.

Tool Count5/5

7 tools is a well-scoped set for a prediction market data server. Each tool serves a necessary function without unnecessary duplication or gaps, covering discovery, detailed queries, and notification management.

Completeness5/5

The tool set covers the full lifecycle: discovering events (list), drilling into details (get), accessing markets (get), monitoring spreads and alerts, acknowledging alerts, and listing venues. No obvious missing operations for the stated purpose.

Maintenance

ActivityInactive
ResponsivenessNo issues