Skip to main content
Glama
PublicDotCom

Public.com MCP Server

Official
by PublicDotCom
README.md
# Public.com MCP Server

[![License](https://img.shields.io/badge/license-Apache%202.0-green?style=flat-square)](LICENSE)
[![Python](https://img.shields.io/badge/python-3.10%2B-blue?style=flat-square)](https://python.org)
[![MCP](https://img.shields.io/badge/MCP-compatible-purple?style=flat-square)](https://modelcontextprotocol.io)

An [MCP (Model Context Protocol)](https://modelcontextprotocol.io) server that connects AI assistants to your [Public.com](https://public.com) brokerage account. Trade stocks, options, and crypto — get quotes, manage orders, and view your portfolio — all through natural language.

> **Disclaimer:** For illustrative and informational purposes only. Not investment advice or recommendations. Use at your own risk.

## Tools

### Read-Only

| Tool | Description |
|------|-------------|
| `check_setup` | Verify API credentials and connectivity |
| `get_accounts` | List all brokerage accounts |
| `get_portfolio` | View positions, equity, buying power (including `dayTradeBuyingPower`), open orders |
| `get_orders` | List active/open orders (bracket legs share a `bracketId`) |
| `get_order` | Status and details of a specific order, including its fills (`trades` with each fill's venue MIC, `filledAt`, `replacedAt`, `lastModified`); last 30 days |
| `search_orders` | Search order history — any status, last 30 days, up to 500 orders, filtered by status/side/symbols/type/time |
| `get_history` | Transaction history (trades, deposits, dividends, etc.) |
| `get_quotes` | Real-time quotes for stocks, crypto, options, event contracts |
| `get_price_history` | OHLCV price history for equities, crypto, options, indices, or event contracts |
| `get_instrument` | Details about a specific tradeable instrument |
| `get_all_instruments` | List all available instruments with filters |
| `search_bonds` | Filtered, paged search for fixed income instruments |
| `get_bond_details` | Pricing, ratings, coupon and maturity info for a bond |
| `get_option_expirations` | Available expiration dates for options |
| `get_option_chain` | Full option chain (calls + puts) for a symbol |
| `get_option_greeks` | Greeks (delta, gamma, theta, vega, rho, IV) for multiple options |
| `get_option_greek` | Greeks for a single option symbol |
| `get_tax_lots` | Unrealized tax-lot summary (per-lot gain/loss, term, cost basis) |
| `get_tax_lots_for_symbol` | Unrealized tax-lot detail for a single symbol |
| `get_tax_lots_csv` | Export unrealized tax lots as a Base64-encoded CSV file |
| `get_strategy_quote` | Consolidated quote for a multi-leg option strategy |
| `get_event_categories` | Event-contract (prediction market) categories, subcategories and frequency filters |
| `get_event_summary` | Browse event contracts by category / symbol / frequency / resolution time, 100 per page |
| `get_event_details` | One event's outcomes (with `floorStrike`), YES/NO contract prices, timeline and CFTC terms, plus per-outcome `tradable` / `secondsLeft` / `winner` |
| `get_event_contract_bars` | Price-history bars for up to 8 contracts of one event |
| `get_current_event` | The window of a recurring market (e.g. 15-minute `KXBTC15M`) trading right now; optional bounded wait |
| `wait_for_settlement` | Wait (bounded) for an event outcome to settle and report the winning contract |
| `preflight_order` | Estimate costs/impact before placing a single-leg order |
| `preflight_multileg_order` | Estimate costs for multi-leg options strategies |
| `preflight_short_order` | Estimate costs before placing a short-sale order |
| `preflight_call_credit_spread` | Estimate costs for a Bear Call Spread |
| `preflight_call_debit_spread` | Estimate costs for a Bull Call Spread |
| `preflight_put_credit_spread` | Estimate costs for a Bull Put Spread |
| `preflight_put_debit_spread` | Estimate costs for a Bear Put Spread |
| `preflight_buy_event_contract` | Estimate costs before buying an event contract (YES or NO side) |

### Write (Destructive)

| Tool | Description |
|------|-------------|
| `place_order` | Place a single-leg order (stocks, crypto, options), including market-on-close / limit-on-close; optionally a bracket order via `order_class` + exit-leg prices, or target specific tax lots via `tax_lot_matching_instructions` |
| `place_multileg_order` | Place multi-leg orders (spreads, straddles, etc.) |
| `place_call_credit_spread` | Place a Bear Call Spread |
| `place_call_debit_spread` | Place a Bull Call Spread |
| `place_put_credit_spread` | Place a Bull Put Spread |
| `place_put_debit_spread` | Place a Bear Put Spread |
| `place_short_order` | Place an equity short-sale order |
| `buy_event_contract` | Buy an event contract (YES or NO side) with a DAY limit order, at the ask by default |
| `flatten_and_go_short` | Sell an existing long position then go short (experimental) |
| `cancel_order` | Cancel an existing order |
| `cancel_and_replace_order` | Atomically cancel and replace an order |

### Order types

`place_order`, `preflight_order`, `cancel_and_replace_order` and the short-sale tools
take `order_type` as one of:

| `order_type` | Price arguments |
|------|-------------|
| `MARKET` | none |
| `LIMIT` | `limit_price` |
| `STOP` | `stop_price` |
| `STOP_LIMIT` | `stop_price` and `limit_price` |
| `MARKET_ON_CLOSE` | none — executes at the closing auction |
| `LIMIT_ON_CLOSE` | `limit_price` — executes at the closing auction |

`place_order`, `preflight_order` and the short-sale tools also reject a price argument
the order type doesn't take (e.g. `limit_price` on `MARKET_ON_CLOSE`). Bracket entries
are `LIMIT` or `MARKET` only, and multi-leg orders are always `LIMIT`.

### Bracket orders

`place_order` places a bracket by setting `order_class` to `BRACKET`, `OCO` or `OTO`
and supplying at least one exit leg:

| Argument | Meaning |
|------|-------------|
| `order_class` | `SIMPLE` (default, standalone) or `BRACKET` / `OCO` / `OTO` |
| `take_profit_limit_price` | Limit price of the take-profit leg |
| `stop_loss_stop_price` | Stop price of the stop-loss leg |
| `stop_loss_limit_price` | Optional — makes the stop-loss a `STOP_LIMIT` rather than a `STOP` |

The exit legs are submitted automatically when the entry order fills, and every leg
of the bracket — the entry included — reports the entry's order ID as its
`bracketId`, so `get_orders` groups them.

The API accepts brackets for `EQUITY` and `OPTION` only; they need a whole-share
`quantity` (not `amount`), must use the `CORE` market session, and the entry
`order_type` must be `LIMIT` or `MARKET` (`LIMIT` only for `OCO`). `preflight_order`
validates the entry order only — it has no view of the exit legs.

### Order history

`get_orders` lists only the open/active orders in the portfolio snapshot. For everything
else use the order-history tools:

| Tool | Returns |
|------|-------------|
| `search_orders` | Orders in any status (filled, cancelled, rejected, …) matching optional `status`, `side`, `symbols` (`"SYMBOL"` or `"SYMBOL:TYPE"`), `security_type`, `open_close_indicator`, `created_after` / `created_before` filters |
| `get_order` | One order by ID in the same shape |

Both are limited by the API to orders created within the **last 30 days**, and
`search_orders` returns at most **500** orders. Each order includes `trades` (the
individual fills, each with the `marketIdentificationCode` — the ISO 10383 MIC of the
execution venue, e.g. `XNAS` — when reported), `filledAt`, `replacedAt`, `lastModified`
and `equityMarketSession`.
Note that `equityMarketSession` uses `REGULAR` / `REST_OF_DAY` / `TWENTY_FOUR_HOURS`,
which is not the `CORE` / `EXTENDED` / `TWENTY_FOUR_HOURS` vocabulary that
`place_order`'s `equity_market_session` argument takes.

### Event contracts

Browse event contracts (prediction markets) with `get_event_categories` →
`get_event_summary` (page with `next_token`) → `get_event_details`, and chart with
`get_event_contract_bars`. Prices are dollars from 0.00 to 1.00 and equal the implied
probability. `EventSummary.symbols` lists related instruments (e.g. `BTC-CRYPTO`), not
the event's contracts — those come from `get_event_details`. Outcome ids carry no
exchange prefix (e.g. `KXBALANCESHEET-EO26-6.6`).

#### Trading recurring markets

For a recurring market such as the 15-minute "Up or Down" windows:

1. `get_current_event(series="KXBTC15M")` — the window open right now (`series` is the
   series ticker, shown on every `get_event_summary` / `get_event_details` result).
   Pass `wait_seconds` (≤ 120) to wait between windows.
2. `get_event_details(event_symbol)` — the YES/NO contracts, their asks, and whether the
   outcome is `tradable` and how many `secondsLeft`.
3. `preflight_buy_event_contract` → `buy_event_contract(contract_symbol, quantity,
   limit_price)` — a DAY limit buy. Omit `limit_price` and pass `event_symbol` to buy at
   the current ask, rounded up to a whole cent. Quantities take at most 2 decimals.
4. `wait_for_settlement(event_symbol, contract_symbol=...)` — waits up to 120 s per call
   and reports `winner` and `won`; on timeout it returns `"status": "pending"`, so call
   again.

The two halves take different identifiers, and the API rejects the wrong one:

| Tools | Event identifier | Contract symbol |
|------|-------------|-------------|
| `get_event_summary`, `get_event_details`, `get_current_event`, `wait_for_settlement`, `*buy_event_contract` | `eventSymbol`, e.g. `KALSHI.KXBALANCESHEET-EO26` | e.g. `KALSHI.KXBALANCESHEET-EO26-6.6.Y` |
| `get_event_contract_bars` | `-EVENT` id, e.g. `KALSHI.KXBALANCESHEET-EO26-EVENT` | `-EVENTCONTRACT` symbol, e.g. `KALSHI.KXBALANCESHEET-EO26-6.6.Y-EVENTCONTRACT` |

`EVENTCONTRACT` is also accepted as an instrument type by `get_quotes`,
`get_price_history`, `get_instrument`, `get_all_instruments` and `search_orders`.

## Prerequisites

- **Python 3.10+**
- **Public.com account** — [Sign up](https://public.com/signup)
- **Public.com API key** — [Get one here](https://public.com/settings/v2/api)

## Installation

```bash
pip install publicdotcom-mcp-server
```

Or install from source:

```bash
git clone https://github.com/publicdotcom/publicdotcom-mcp-server.git
cd publicdotcom-mcp-server
pip install .
```

## Configuration

Set your API credentials as environment variables:

```bash
# Required
export PUBLIC_COM_SECRET=your_api_secret_key

# Optional — sets a default account so you don't need to specify it each time
export PUBLIC_COM_ACCOUNT_ID=your_account_id
```

## Usage

### Claude Desktop

Add this to your Claude Desktop config (`~/Library/Application Support/Claude/claude_desktop_config.json` on macOS):

```json
{
  "mcpServers": {
    "public-com": {
      "command": "publicdotcom-mcp-server",
      "env": {
        "PUBLIC_COM_SECRET": "your_api_secret_key",
        "PUBLIC_COM_ACCOUNT_ID": "your_account_id"
      }
    }
  }
}
```

### Claude Desktop (using uvx)

If you prefer using `uvx` (no pre-install needed):

```json
{
  "mcpServers": {
    "public-com": {
      "command": "uvx",
      "args": ["publicdotcom-mcp-server"],
      "env": {
        "PUBLIC_COM_SECRET": "your_api_secret_key",
        "PUBLIC_COM_ACCOUNT_ID": "your_account_id"
      }
    }
  }
}
```

### Running Directly

```bash
# stdio transport (default — for Claude Desktop, Claude Code, etc.)
publicdotcom-mcp-server

# Or run as a Python module
python -m publicdotcom_mcp_server
```

### Hosted / Remote Deployment

For remote deployments (behind a reverse proxy or load balancer), switch to the streamable-HTTP transport:

```bash
export MCP_TRANSPORT=streamable-http
export PUBLIC_COM_SECRET=your_api_secret_key
export PORT=8000  # optional, defaults to 8000
export HOST=0.0.0.0  # optional, defaults to 0.0.0.0
publicdotcom-mcp-server
```

In this mode the server listens for MCP requests at `POST /mcp`. Clients authenticate per-request via an `Authorization: Bearer <key>` header, which takes priority over the `PUBLIC_COM_SECRET` environment variable — useful for multi-tenant deployments.

### Testing with MCP Inspector

```bash
npx @modelcontextprotocol/inspector publicdotcom-mcp-server
```

## Development

```bash
# Clone and install in development mode
git clone https://github.com/publicdotcom/publicdotcom-mcp-server.git
cd publicdotcom-mcp-server
pip install -e ".[dev]"

# Run tests
pytest

# Run the server locally
python -m publicdotcom_mcp_server
```

### CI & Releases

- **CI** (`.github/workflows/ci.yml`) runs the test suite (Python 3.10–3.13) and `ruff` on every push to `main` and every pull request.
- **Releases** (`.github/workflows/release.yml`) run on every push to `main`. When the `version` in `pyproject.toml` is one that hasn't been released yet (no matching `v<version>` tag), the workflow builds the package, publishes to PyPI via [Trusted Publishing (OIDC)](https://docs.pypi.org/trusted-publishers/) — no API token is stored — and creates the corresponding GitHub Release. Merges that don't change the version are no-ops.

**To cut a release:** bump `version` in `pyproject.toml` in your PR and merge it to `main`. The release + PyPI publish + `v<version>` tag/GitHub Release happen automatically. One-time setup on PyPI (project → **Publishing**) must register a Trusted Publisher for this repo with workflow `release.yml` and environment `pypi`.

## How It Works

This server wraps the [`publicdotcom-py`](https://pypi.org/project/publicdotcom-py/) Python SDK, exposing each API operation as an MCP tool. The MCP protocol allows AI clients to discover and call these tools through a standardized interface.

```
AI Client (Claude, etc.)
    ↕ MCP Protocol (stdio)
Public.com MCP Server
    ↕ HTTPS
Public.com Trading API
```

All tools include proper [MCP tool annotations](https://modelcontextprotocol.io/docs/concepts/tools#tool-annotations):
- Read-only tools are marked with `readOnlyHint: true`
- Order-placement tools are marked with `readOnlyHint: false` (they modify account state)
- Order cancellation tools (`cancel_order`, `cancel_and_replace_order`) are additionally marked with `destructiveHint: true`

## License

[Apache 2.0](LICENSE)

TDQS

A3.8/5.0

Scored across 46 tools

Disambiguation3/5

The descriptions are unusually thorough and explicitly cross-reference sibling tools (get_orders vs search_orders, get_quotes vs get_price_history, preflight vs place), which resolves most boundary questions. However, several near-duplicate pairs remain: get_option_greek vs get_option_greeks, get_tax_lots vs get_tax_lots_for_symbol vs get_tax_lots_csv, and four preflight_*_spread tools whose names (call_credit/call_debit/put_credit/put_debit) map to bull/bear semantics only via the description. An agent can still misselect among the many order-placement variants.

Naming Consistency4/5

Strong verb_noun snake_case convention throughout: get_*, place_*, preflight_*, search_*, cancel_*, wait_for_*. Minor deviations like check_setup, flatten_and_go_short, and cancel_and_replace_order break the strict two-token pattern but remain readable and verb-first.

Tool Count2/5

46 tools is heavy for a single server, well above the 25-tool comfort threshold. Much of the bulk is redundant surface: eight spread tools (four preflight + four place) that could be one parameterized tool, plus a singular/plural Greeks pair. The domain is genuinely broad (equities, options, crypto, bonds, prediction markets), so some size is justified, but the set is over-expanded.

Completeness4/5

Coverage is impressive: accounts, instruments, quotes, price history, full order lifecycle (place, preflight, cancel, replace, search, get), portfolio, tax lots, option chains/Greeks, bonds, and event contracts. Minor gaps: prediction markets support buying event contracts but no sell/close path, and there is no dedicated position-lookup or close-position tool beyond the portfolio snapshot.

Maintenance

ActivityMaintained
ResponsivenessNo issues