Metadata-Version: 2.4
Name: smartoption-mcp
Version: 0.2.0
Summary: MCP server exposing the smartoption-ai customer auto-trade API as tools for AI agents (Claude Desktop / Claude Code / any MCP client).
Author-email: SmartOption <service.smartoption@gmail.com>
License: Proprietary
Project-URL: Homepage, https://github.com/SmartOption/smartoption-ai
Project-URL: Repository, https://github.com/SmartOption/smartoption-ai
Project-URL: Issues, https://github.com/SmartOption/smartoption-ai/issues
Keywords: mcp,smartoption,claude,auto-trade,copy-trading
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: Operating System :: OS Independent
Requires-Python: >=3.11
Description-Content-Type: text/markdown
Requires-Dist: mcp>=1.2.0
Requires-Dist: httpx>=0.27.0

# smartoption-mcp

MCP server that exposes the smartoption-ai **customer auto-trade API** as tools
for AI agents (Claude Desktop, Claude Code, anything that speaks MCP).

Phase 1 is **read-only**: 5 tools covering copy rules, virtual lots, agent
status, parsed signal history (大单/喊单历史), and copy-run logs. Write
operations (creating/modifying rules, placing orders) will be added in
Phase 2 once the read path is battle-tested.

## Architecture

```
Claude / Agent
   │  MCP stdio
   ▼
smartoption-mcp  ──HTTP + Bearer JWT──▶  backend  /api/customer/auto-trade/*
```

The server is a thin wrapper: each tool maps 1:1 (or close) to a customer
API endpoint, authenticated with a user JWT loaded from env at startup.

## Install

### End-user (recommended)

```bash
pip install smartoption-mcp
# or, in an isolated venv:
python3.11 -m venv ~/.smartoption-mcp && ~/.smartoption-mcp/bin/pip install smartoption-mcp
```

`smartoption-mcp` is published on [PyPI](https://pypi.org/project/smartoption-mcp/).
This installs the `smartoption-mcp` CLI entry point. Upgrade with
`pip install -U smartoption-mcp`.

### Local dev (from this repo)

```bash
cd mcp-server
python3.11 -m venv .venv
source .venv/bin/activate
pip install -e .
```

## Configure auth

**Recommended: long-lived API token** (1-year expiry, revocable any time).
Log into [portal.smartoption.ai](https://portal.smartoption.ai) → 个人中心
→ "API Token（用于 MCP / 脚本）" → 起个名字 → 复制生成的 token。
管理页面随时可以吊销。

**Fallback: session JWT** — if the API tokens page isn't deployed yet,
open DevTools → Application → Local Storage → copy the `access_token`
field. Expires in ~24h so you'll re-paste daily.

Either way, the token goes into `SMARTOPTION_JWT`. Set
`SMARTOPTION_API_BASE=https://api.smartoption.ai`.

Smoke test from a shell:

```bash
export SMARTOPTION_API_BASE="https://api.smartoption.ai"
export SMARTOPTION_JWT="eyJ..."   # no "Bearer " prefix
.venv/bin/python -c "from smartoption_mcp.client import SmartoptionClient; \
  print(SmartoptionClient().list_agents())"
```

## Register with Claude Code / Claude Desktop

**Claude Code** (this repo's primary host) — edit `~/.claude.json` and add
under the top-level `mcpServers` key:

```json
{
  "mcpServers": {
    "smartoption": {
      "command": "smartoption-mcp",
      "env": {
        "SMARTOPTION_API_BASE": "https://api.smartoption.ai",
        "SMARTOPTION_JWT": "eyJ..."
      }
    }
  }
}
```

Restart Claude Code (or start a new session). The 5 `smartoption` tools
should appear in the tool list.

**Claude Desktop** — same JSON shape, but the file lives at
`~/Library/Application Support/Claude/claude_desktop_config.json`. Restart
the app after editing.

Once registered, you should be able to ask things like:

- "查一下最近一周苹果相关的喊单"
- "我现在的虚拟仓有哪些标的？"
- "我的跟单 agent 在线吗？最近一次心跳是什么时候？"
- "今天 agent 跑了几条信号，有没有被跳过的？"

## Tools

### Read (Phase 1)

| Tool | Endpoint | Purpose |
|---|---|---|
| `list_copy_rules` | `GET /copy-rules` | Current copy-trading rules |
| `list_virtual_lots` | `GET /virtual-ledger` | Open virtual lots + qty_by_key |
| `get_agent_status` | `GET /agents` | Per-user agent online status |
| `query_signal_history` | `GET /signal-history` | Search parsed alerts (大单) |
| `list_run_logs` | `GET /copy-run-logs` | Per-signal execution outcomes |

### Write (Phase 2)

| Tool | Endpoint | Purpose |
|---|---|---|
| `update_copy_rules` | `PUT /copy-rules` | Replace full copy-trading settings (rules + toggles) |
| `ensure_agent` | `POST /agents/ensure` | Create / provision the user's agent k8s pod |
| `refresh_broker_snapshot` | `POST /broker-account-snapshot/refresh` | Ask agent to push fresh broker snapshot |

### Phase 2 extension (broker config + agent ops + signal detail + quant)

| Tool | Endpoint | Purpose |
|---|---|---|
| `list_broker_configurations` | `GET /broker-configurations` | All saved brokers + active (no creds returned) |
| `get_active_broker` | `GET /broker-configurations` | Just the active broker name + display name |
| `set_active_broker` | `PUT /active-broker` | Switch active broker — dry-run gated |
| `test_broker_connection` | `POST /broker-configurations/test-{ib,tiger,futu,moomoo}` | Verify creds against broker; does NOT save |
| `restart_agent_client` | `POST /agents/<id>/restart-client` | Restart in-pod agent process — dry-run gated |
| `stop_agent` | `POST /agents/<id>/stop` | Scale agent deployment to 0 — dry-run gated |
| `get_agent_logs` | `GET /agents/<id>/logs` | Tail recent agent-pod stdout |
| `get_signal_detail` | `GET /signal-history/<id>` | Full SignalForwardRecord for one signal |
| `get_signal_chain` | `GET /signal-history/<id>/chain-slots` | Paired/chained signal context (ROLL_UP pairs etc.) |
| `list_virtual_followers` | `GET /api/customer/virtual-followers` | User's virtual-follower accounts + equity summary |
| `list_quant_strategies` | `GET /api/customer/quant-strategies/list` | Available / subscribed quant strategies |
| `get_quant_strategy_snapshot` | `GET /api/customer/quant-strategies/<id>/snapshot` | One strategy's positions + canonical valuation |

### Data Center (暗盘大单 / 期权大单 / 交易员)

| Tool | Endpoint | Purpose |
|---|---|---|
| `list_data_center_tags` | `GET /data-center/overview` | Available tags + counts |
| `list_data_center_channels` | `GET /data-center/overview` | Active channels under one tag |
| `list_data_center_messages` | `GET /data-center/messages` | Paged messages with filters |
| `get_data_center_message_detail` | `GET /data-center/messages/<id>` | One message by id |
| `interpret_data_center_message` | `POST /data-center/messages/<id>/interpret` (SSE) | LLM "解读"; stream collected client-side |
| `chat_about_data_center_message` | `POST /data-center/messages/<id>/chat` (SSE) | Per-message free-form chat |
| `list_data_center_message_chat_history` | `GET /data-center/messages/<id>/chat` | Prior chat turns + quota |

The two SSE tools collect the entire backend stream and return one
payload: `status` (`done` / `cached` / `error` / `quota_exceeded`),
`content`, `duration_ms`, `event_count`, plus `remaining_quota` for
chat. Time inputs (`start_at` / `end_at`) are pass-through ISO 8601 —
include timezone offset (e.g. `-04:00` for ET); the server does not
normalize "today" / "now-7d".

**Confirmation model.** Destructive writes use a `confirmed: bool` flag,
defaulting to `False` for **dry-run**:

- `update_copy_rules(new_settings, confirmed=False)` → server fetches
  current settings, returns a structured diff (top-level toggle changes +
  rules added / removed / modified, keyed by `rule_id`). Nothing is
  written. The model is instructed (via docstring) to show the diff to
  the user and only call again with `confirmed=True` after approval.
- `ensure_agent(force_redeploy=True, confirmed=False)` → returns a
  description of the redeploy without doing it. Default `force_redeploy=False`
  is idempotent and skips the dry-run gate.
- `refresh_broker_snapshot` → no gate (non-destructive async request).

The host (Claude Code / Desktop) also shows tool-call arguments to the
user before each call, so `confirmed=True` is always visible in the
approval UI — the in-tool `confirmed` flag is a second belt on top of
that suspenders.

**Validation.** `update_copy_rules` rejects partial settings: the proposed
doc must contain `auto_buy_enabled`, `auto_sell_enabled`,
`use_all_matched_rules`, and `rules`. The model is expected to start from
`list_copy_rules`, mutate locally, and pass the full doc back —
preserving every rule's `rule_id` so the diff stays stable.

## Roadmap

- **Phase 3 (✅ Phase 3a done)**: long-lived API tokens managed from the
  customer portal — eliminates daily JWT re-paste, no protocol changes.
  Tokens are still pasted into env; Phase 3b would be full MCP OAuth 2.1
  with a remote HTTP MCP server so other users can connect from their own
  Claude install without copy-paste. Deferred until there's a real
  multi-user use case.
