MagicMarkets について
MagicMarketsは、Magic Markets v2 APIを操作するコマンドラインツールで、スポーツ予測市場を扱うユーザーやエージェントを対象としています。価格配信、クオートと注文の管理に加え、同じAPI機能をMCPツールとして提供します。
主な機能
- 01スポーツ価格と口座アクティビティを配信
- 02イベントと価格付き選択肢を検索
- 03ベットスリップ作成と注文発注
- 04ポジション、残高、注文を確認
- 05期限後に注文を閉じるハートビートを管理
活用シーン
- 01指定イベントのライブ価格を監視
- 02選択肢をクオートして注文を発注
- 03ハートビートで自動戦略を保護
MCP 対応
CLIはstdioまたはローカルホスト上のStreamable HTTPでMCPツールを提供します。`MAGICMARKETS_ALLOW_TRADING`を設定しない限り、MCP経由の取引機能は無効です。
設定
リモートサーバーはインストール不要です。クライアントを選んで設定をコピーするか、ワンクリックで導入できます。
https://magicmarkets.com/mcpclaude mcp add --transport http com-magicmarkets https://magicmarkets.com/mcp{"mcpServers":{"com-magicmarkets":{"type":"http","url":"https://magicmarkets.com/mcp"}}}Cursor で開く{"servers":{"com-magicmarkets":{"type":"http","url":"https://magicmarkets.com/mcp"}}}VS Code で開く{"mcpServers":{"com-magicmarkets":{"type":"http","url":"https://magicmarkets.com/mcp"}}}{"mcpServers":{"com-magicmarkets":{"serverUrl":"https://magicmarkets.com/mcp"}}}コマンドはターミナルで実行し、JSON は各クライアントの MCP 設定に貼り付けて再起動します。認可が必要なサーバーは初回接続時にログインを求めます。
ツール
詳細
magicmarkets-cli
Magic Markets v2 API 用のコマンドラインインターフェースです。ライブスポーツ価格のストリーミング、選択肢の見積もり、注文の発注と管理、ポジションの確認ができます。同じ API は MCP ツールとしても利用でき、stdio(クライアントがサブプロセスとして magicmarkets mcp を起動)または localhost のストリーミング可能な HTTP トランスポートを使用できます。
単一の静的バイナリで、API キー 1 つで認証します。リクエストへの署名も秘密鍵も不要です。
magicmarkets markets --sport fb # find events with live prices
magicmarkets offers fb 2026-06-15,1001,2002 # list priced bet types
magicmarkets betslip create fb 2026-06-15,1001,2002 for,h --wait 5s
magicmarkets order place --betslip bs-123 --price 2.10 --stake 50
セットアップ
1. インストール
クローンしたリポジトリから:
git clone https://github.com/magicmarkets/magicmarkets-cli
cd magicmarkets-cli
make install # installs `magicmarkets` into your Go bin directory
make where を実行すると、インストール先が正確に表示されます。その後 magicmarkets が見つからない場合は、そのディレクトリが PATH に含まれていません:
export PATH="$PATH:$(go env GOPATH)/bin" # add to ~/.zshrc or ~/.bashrc
インストールしたくない場合は、make build を実行すると ./build/magicmarkets が生成され、PATH は変更されません。
go installを直接実行する
/cmd/magicmarkets のパスに注意してください。モジュールのルートをインストールすると、magicmarkets-cli という名前のバイナリがビルドされます:
go install ./cmd/magicmarkets
Go モジュールのパスは GitHub URL ではなく magicmarkets-cli なので、go install github.com/…/magicmarkets-cli@latest は動作しません。リポジトリをクローンして make install を実行する方法が推奨されています。
2. API キーを追加する
magicmarkets.com の Settings → API でキーを作成します。キーが表示されるのは作成時の 1 回限りなので、すぐに保存してください。
どのディレクトリからでも使えるよう、~/.magicmarkets/.env に設定します:
mkdir -p ~/.magicmarkets
echo 'MAGICMARKETS_API_KEY=your-key-here' > ~/.magicmarkets/.env
chmod 600 ~/.magicmarkets/.env
環境変数やプロジェクトローカルの .env も使用できます。cp env.example .env を実行して、値を設定してください。
3. 確認する
$ magicmarkets status
version v1.0.0
api url https://magicmarkets.com/v2
ws url wss://magicmarkets.com/v2/stream
lang en
api key ***********1234
env files [/Users/you/.magicmarkets/.env]
authenticated yes
ストリームを開く前に必ず確認してください。WebSocket は不正なキーをハンドシェイク時に拒否しますが、有用なエラーは表示されません。
セットアップはこれで完了です。以降はすべて任意です。
試してみる
magicmarkets balance # money position
magicmarkets xrates # exchange rates to USDT
magicmarkets markets --sport fb --limit 5 # events that currently have prices
magicmarkets offers fb <event-id> --depth 2 # priced bet types on one event
magicmarkets orders --open # your open orders
magicmarkets ticks 2.345 # where a price lands on the tick schedule
magicmarkets api endpoints # every endpoint (no key, no network)
任意のコマンドに --json を追加すると、出力を jq に渡せます。
設定
次の順に解決され、最初に一致した値が採用されます。
| 優先度 | ソース |
|---|---|
| 1 | 実際の環境変数 |
| 2 | ./.env |
| 3 | ~/.magicmarkets/.env |
| 4 | ~/.env |
| 5 | 組み込みのデフォルト値 |
| 変数 | デフォルト値 | 用途 |
|---|---|---|
MAGICMARKETS_API_KEY | — | API キー(X-Api-Key)。MAGICMARKETS_ACCESS_TOKEN が設定されていない場合は必須です |
MAGICMARKETS_ACCESS_TOKEN | — | CLI/stdio 用の OAuth Bearer トークン。HTTP MCP では、引き続きリクエストごとにトークンを指定します |
MAGICMARKETS_OAUTH_ISSUER | https://magicmarkets.com/api/auth | mcp --http が /authorize と /token をプロキシする上流 AS。また、Bearer 認証情報の解決先となる POST /oauth2/firebase-token の基準 URL です。詳しくは認証をご覧ください |
MAGICMARKETS_SESSION_GROUP_ID | — | Magic Markets の環境固有 ID。OAuth Bearer 認証情報が解決される session 値の生成に使用します。安全なデフォルト値はありません。Bearer 認証情報が必要な環境では必須です |
MAGICMARKETS_FIREBASE_WEB_API_KEY | — | Magic Markets Firebase プロジェクトの Firebase Web API キー。/oauth2/firebase-token の Firebase カスタムトークンを実際の Firebase ID トークンと交換するために使用します。詳しくは認証をご覧ください。安全なデフォルト値はありません。Bearer 認証情報が必要な環境では必須です |
MAGICMARKETS_OAUTH_CLIENT_ID | — | このホスト自身の /mcp/callback を許可リストに登録する、事前登録済みクライアント |
MAGICMARKETS_OAUTH_PROXY_SECRET | — | OAuth プロキシの状態を封印します。すべてのレプリカで同じ値を共有する必要があります |
MAGICMARKETS_MCP_PUBLIC_URL | — | mcp --http のパブリックベース URL(このホストが MCP 認可サーバーです) |
MAGICMARKETS_API_URL | https://magicmarkets.com/v2 | /v2 を含む REST ベース URL |
MAGICMARKETS_BASIC_AUTH | — | /v2/* へのすべての REST 呼び出しで追加の Authorization: Basic ヘッダーとして送信される、Base64 エンコードされた user:pass。一部の非本番環境で v2 API の前段に設置されているインフラレベルのアクセス制限用トークンです。本番環境にはこの制限がないため、設定されていません。/oauth2/firebase-token、Firebase の signInWithCustomToken、WebSocket ストリームには送信されません |
MAGICMARKETS_WS_URL | MAGICMARKETS_API_URL から導出 | ストリームエンドポイント |
MAGICMARKETS_LANG | en | イベント名の言語:en、ko、zh-hans |
MAGICMARKETS_TIMEOUT | 30s | リクエストごとのタイムアウト |
MAGICMARKETS_ALLOW_TRADING | 未設定(無効) | magicmarkets mcp に賭けを行う権限を付与します。CLI には影響しません。 |
グローバルフラグ:--json、--verbose/-v、--api-key、--api-url、--ws-url。
--api-url は、MAGICMARKETS_WS_URL と同じ方法でストリームエンドポイントも再導出します。ただし、MAGICMARKETS_WS_URL または --ws-url が明示的に指定されている場合を除きます。そのため、--api-url https://staging... を指定しても、他のすべてのコマンドがステージング環境に接続する一方で、stream だけが本番価格を読み込むことはありません。
使い方
2 段階のベットフロー
ベットを行うには、常に 2 つのステップが必要です。
- ベットスリップは、1 つの選択肢への関心を登録し、リアルタイムのオッズを受け取ります。費用はかからず、何も確定されません。
- 注文は、そのオッズに対する賭け金を確定します。
ベットスリップは有効期間が短く、作成時には価格がありません。オッズは非同期で、WebSocket の pmm メッセージまたはポーリングによって届きます。そのため、--wait を指定します。
# 1. find an event that has prices
$ magicmarkets markets --sport fb --limit 5
SPORT EVENT ID EVENT COMPETITION STATUS START
----- -------- ----- ----------- ------ -----
fb 2026-06-15,1001,2002 Arsenal v Chelsea England Premier League pre_event 2026-06-15 16:00:00
# 2. read a bet_type straight off the feed
$ magicmarkets offers fb 2026-06-15,1001,2002 --depth 2
BET TYPE MARKET IR PRICES (stake @ price) TOTAL
-------- ------ -- ---------------------- -----
for,h 1x2 - [email protected] [email protected] 230.00
for,ah,h,-4 ah - [email protected] [email protected] 320.00
# 3. quote it, waiting for the price to land
$ magicmarkets betslip create fb 2026-06-15,1001,2002 for,h --wait 5s
betslip id bs-abc123
bet type for,h
description Home
expires 2026-06-15 15:42:10 (28s)
total available 230.00 USDT
Prices:
PRICE MIN MAX
----- --- ---
2.10 5.00 150.00
2.08 - 80.00
# 4. commit a stake (asks for confirmation)
$ magicmarkets order place --betslip bs-abc123 --price 2.10 --stake 50
bet_type を手作業で作成しないでください。 magicmarkets offers またはストリームからそのままコピーしてください。1 つの文字列に市場、ハンディキャップ、結果、方向がエンコードされています。
コマンドリファレンス
アカウント
| コマンド | 用途 |
|---|---|
magicmarkets status | 設定を表示し、キーを検証します |
magicmarkets balance | 残高、未決済の賭け金、スマートクレジット、利用可能額を表示します |
magicmarkets xrates | USDT に対する為替レートを表示します |
magicmarkets position | 損益の合計を表示します。ペイオフマトリックスには --grid を指定します |
検索
| コマンド | 目的 |
|---|---|
magicmarkets markets | 現在価格が付いているイベント |
magicmarkets offers <sport> <event-id> | イベントで価格が付いている賭けの種類 |
magicmarkets stream | ライブ価格とアカウントのフィードを追跡 |
v2 REST APIにはイベント一覧を取得するエンドポイントがありません。イベントの検索はWebSocket経由で行います。これらのコマンドは接続してスナップショットを読み込み、切断するため、数秒かかります。
magicmarkets markets --sport fb,tennis --limit 20
magicmarkets markets --search arsenal
magicmarkets markets --in-play
magicmarkets offers fb 2026-06-15,1001,2002 --market ah --depth 3
magicmarkets stream --register fb:2026-06-15,1001,2002
magicmarkets stream --type order,bet # only order activity
取引
| コマンド | 目的 |
|---|---|
magicmarkets betslip create [sport] [event] [bet-type] | 選択内容の見積もりを取得 |
magicmarkets betslip get <id> | ベットスリップとその価格を表示 |
magicmarkets betslip list | オープン中のベットスリップID(詳細をすべて表示するには--expandを指定) |
magicmarkets betslip refresh <id> | 有効期限を延長 |
magicmarkets order place | ベットスリップに対して注文を発注 |
magicmarkets orders / magicmarkets order list | 注文を一覧表示 |
magicmarkets order get <id> | 1件の注文とそのベットを表示 |
magicmarkets order tracked <uuid> | 冪等性キーで注文を検索 |
magicmarkets order updates | 指定した時間枠内に変更された注文 |
magicmarkets order close <id> | 1件の注文をキャンセル |
magicmarkets order close-many <id>... | 最大500件の注文をキャンセル |
magicmarkets order close-all | オープン中のすべての注文をキャンセル |
レイベットとパーレー:
# lay (against) a selection
magicmarkets betslip create --lay fb 2026-06-15,1001,2002 for,over,2.5
# a 2-leg accumulator
magicmarkets betslip create \
--leg fb:2026-06-15,1001,2002:for,h \
--leg fb:2026-06-16,1003,2004:for,over,2.5 --wait 5s
リスク管理
| コマンド | 目的 |
|---|---|
magicmarkets heartbeat run | ハートビートを作成し、フォアグラウンドで維持 |
magicmarkets heartbeat create/list/get/refresh/cancel | ハートビートを直接管理 |
ハートビートはデッドマンスイッチです。有効期限が切れる前に更新されない場合、オープン中のすべての注文が自動的にクローズされます。自動化された戦略と一緒に実行すれば、クラッシュしても注文が有効なまま残ることはありません。
$ magicmarkets heartbeat run --timeout 60
heartbeat hb-xyz created, expires 2026-06-15 15:43:10; refreshing every 20s
press Ctrl-C to cancel it and leave orders open
Ctrl-Cを押すと、ハートビートは正常にキャンセルされ、注文はオープンのままになります。プロセスが終了すると、スイッチが作動します。
MCP
| コマンド | 目的 |
|---|---|
magicmarkets mcp | デフォルトではstdio経由でMCPツールを利用します。--httpを指定すると、localhost上でストリーミング可能なHTTPトランスポートを使用します。MCPを参照してください |
リファレンス
| コマンド | 目的 |
|---|---|
magicmarkets bet-type <sport> <bet-type> | 賭けの種類を検証し、ペイオフグリッドを表示 |
magicmarkets ticks <price> | 価格をティックスケジュールに合わせる |
magicmarkets api endpoints | すべてのエンドポイントを一覧表示 |
magicmarkets api show <path> [method] | エンドポイントの詳細:パラメーター、ボディ、レスポンス |
magicmarkets api schema [name] | コンポーネントスキーマ |
magicmarkets api curl <method> <path> | 実行可能なcurlコマンドを生成 |
magicmarkets api search <term> | エンドポイントとスキーマを検索 |
magicmarkets api spec | 埋め込みOpenAPI仕様を出力 |
magicmarkets apiコマンドの実行にAPIキーもネットワークも必要ありません。OpenAPI 3.1仕様はバイナリにコンパイルされています。
安全な運用のチェックリスト
資金を使うコマンドを実行する前に、次の点を覚えておいてください。
- すべての注文で
--request-uuidを指定してください。 発注が冪等になります。タイムアウト後に再試行しても注文が重複せず、注文は6時間取得可能な状態で保持されます。指定しない場合、タイムアウトするとベットが発注されたかどうか分からなくなります。 - 自動化する場合はハートビートを実行してください。 ハートビートがないと、戦略がクラッシュした際に注文が市場で有効なまま残ります。
- ストリームを開く前に、REST経由でキーを検証してください。 WebSocketのハンドシェイクは、役に立つエラーなしで失敗します。
bet_typeは必ずフィードから取得し、手入力しないでください。 アジアンハンディキャップのラインは実際のラインの4倍なので、手作業で作成した文字列は誤りに気づかないまま間違いやすくなります。- ティックに合わせられた価格を確認してください。
magicmarkets order placeは確認画面にその価格を表示します。注文に適用されるのは、入力した価格ではなく、この価格です。
価格とティックスケジュール
すべての価格は、価格が高くなるにつれて刻み幅が広がる固定のティックスケジュールに従います。
| 10 進価格 | ティック |
|---|---|
| 1.01 – 2 | 0.01 |
| 2 – 3 | 0.02 |
| 3 – 4 | 0.05 |
| 4 – 6 | 0.10 |
| 6 – 10 | 0.20 |
| 10 – 20 | 0.50 |
| 20 – 30 | 1 |
| 30 – 50 | 2 |
| 50 – 100 | 5 |
| 100 – 1000 | 10 |
ティックに合わない注文価格は、指値が厳しくならないように丸められます。バック(for)注文では切り下げ、レイ(against)注文では切り上げます。magicmarkets order place は価格自体を丸め、確認時に結果を表示します。
$ magicmarkets ticks 2.345
snapped price 2.34 # back: rounded down
$ magicmarkets ticks 2.345 --lay
snapped price 2.36 # lay: rounded up
フィードから引用された価格はすでにスケジュールに沿っており、再度丸められることはありません。
ベットタイプの文法
bet_type は、方向を先頭に指定するカンマ区切りの文字列です。バックする場合は for、レイする場合は against を指定します。ハンディキャップは常にホームチームを基準とします。
| 例 | 意味 |
|---|---|
for,h / for,d / for,a | ホーム/引き分け/アウェイの勝利 |
for,dnb,h | ホームの勝利。引き分けの場合は無効 |
for,dc,h,d | ダブルチャンス:ホームまたは引き分け |
for,over,2.5 / for,under,2.5 | 2.5 ゴールのオーバー/アンダー |
for,ah,h,-4 | アジアンハンディキャップ、ホーム -1.0 |
for,ahover,7 | アジアン合計のオーバー 1.75 |
for,cs,2,1 | 正確なスコア 2–1 |
for,score,both,yes | 両チームが得点する |
for,win,<team_id> | 優勝決定戦で指定のランナーが勝つ |
for,top,3,<team_id> | 指定のランナーがトップ 3 に入る |
アジアンハンディキャップのラインは、実際のラインを 4 倍した整数です。-4 は -1.0、2 は +0.5、7 は +1.75 です。これにより、0.25 刻みのラインもワイヤー上では整数のみになります。
候補の文字列を検証します。
$ magicmarkets bet-type fb for,ah,h,-4
description Home -1.0 (Asian)
valid yes
テニスの期間、時間帯トークン、すべてのマーケットを含む完全な文法は、docs/api-reference.md に記載されています。
JSON 出力
すべてのコマンドで --json を指定できます。
magicmarkets orders --open --json | jq -r '.[] | "\(.order_id) \(.status)"'
magicmarkets markets --sport fb --json | jq -r '.[].event_id'
magicmarkets stream --type order --json # one JSON object per line
ステークはオブジェクトではなく 2 要素のタプルです。--json は API のワイヤー形式をそのまま反映するため、フィールド名ではなくインデックスで参照してください。
$ magicmarkets balance --json
{
"balance": ["USDT", 10000.5],
"open_stake": ["USDT", 152.55],
"smart_credit": null
}
$ magicmarkets balance --json | jq '.balance[1]' # amount
10000.5
$ magicmarkets balance --json | jq -r '.balance[0]' # currency
USDT
同じことがすべての金額フィールドにも当てはまります。want_stake、stake、profit_loss、total、および価格レベル内の min/max です。
MCP
magicmarkets mcp は API を MCP ツールとして提供するため、LLM エージェントは価格を読み取り、注文を管理できます。デフォルトでは stdio を使用します。MCP クライアント(Claude Code、Cursor など)がサブプロセスとして起動し、stdin/stdout で JSON-RPC をやり取りします。代わりに --http を渡すと、localhost 上で MCP のストリーミング可能な HTTP トランスポートを提供します。詳しくは、以下のlocalhost HTTP 経由での提供を参照してください。
stdio
次のコマンドをクライアントに登録します。
claude mcp add magicmarkets -e MAGICMARKETS_API_KEY=your-key -- magicmarkets mcp
または、クライアントの MCP 設定に記述します。mcpServers は stdio サブプロセスに対するクライアント側の名称であり、ネットワークサービスではありません。
{
"mcpServers": {
"magicmarkets": {
"command": "magicmarkets",
"args": ["mcp"],
"env": { "MAGICMARKETS_API_KEY": "your-key" }
}
}
}
現時点で MCP サポートは開発者モードです。stdio サーバーを各クライアントに接続する際に多少の手間がかかる場合がありますが、今後も改善される予定です。クライアント固有の設定(設定ファイルの場所、再起動時の動作、ログの場所)については、この README ではなく各クライアントのドキュメントを参照してください。
- Claude Code:MCP 経由でツールに接続する
- Model Context Protocol:ローカル(stdio)サーバーに接続する — Claude Desktop など、さまざまな MCP クライアントについて説明しています
クライアントを問わず、最もよくある問題は command フィールドです。クライアントは多くの場合、シェルの PATH ではなく最小限の PATH でサブプロセスを起動するため、同じコマンドがターミナルでは動作しても、"command": "magicmarkets" では解決に失敗することがあります。その場合は、代わりに絶対パスを指定してください。
which magicmarkets # or: make where
localhost HTTP 経由での提供
stdio の代わりにストリーマブル HTTP トランスポートを提供するには、--http を渡します。クライアントがネットワーク経由で接続する場合や、クライアントごとにサブプロセスを起動するのではなく、複数のクライアントで1つの長時間稼働するサーバーを共有したい場合に便利です。
magicmarkets mcp --http --addr 127.0.0.1:8383
--addr の既定値は 127.0.0.1:8383 です。ループバック限定のため、いずれにしてもマシンの外部からはアクセスできません。--http 自体に TLS はありません。ループバックの範囲を超えて公開する場合は、リバースプロキシの背後に配置してください。
サーバーは MAGICMARKETS_API_KEY を使用しません。 各リクエストでは、呼び出し元の認証情報を X-Api-Key または Authorization: Bearer で送信する必要があります。API キーは変更せずに Magic Markets REST API と /v2/stream に転送されます。Bearer トークンはそのまま転送されません。まず POST {MAGICMARKETS_OAUTH_ISSUER}/oauth2/firebase-token 経由で、実際に必要とされる認証情報に解決されます。詳しいフローと既知の制限については、認証を参照してください。stdio では引き続き、環境変数から MAGICMARKETS_API_KEY または MAGICMARKETS_ACCESS_TOKEN を取得します。
コマンドの代わりに URL をクライアントに指定します。
{
"mcpServers": {
"magicmarkets": {
"url": "http://127.0.0.1:8383/mcp",
"headers": { "X-Api-Key": "your-key" }
}
}
}
同じ URL で OAuth アクセストークンも受け付けます。
{
"mcpServers": {
"magicmarkets": {
"url": "http://127.0.0.1:8383/mcp",
"headers": { "Authorization": "Bearer your-token" }
}
}
}
OAuth を扱うリモート MCP ホストでは、ヘッダーマップを省略できます。認証されていない /mcp の応答には、保護リソースのメタデータを指す WWW-Authenticate が含まれます。このメタデータでは、この MCP ホストが Authorization Server として指定されます(そのため、Claude の Dynamic Client Registration は https://magicmarkets.com/register ではなく、ここにある /register に POST します)。このプロセスは https://magicmarkets.com/api/auth に対して独自の PKCE ログインを実行します。実際の Magic Markets AS が許可リストに登録しているのはこのホスト独自のコールバック({public-url}/mcp/callback)だけであり、Claude や Cursor のものは登録されていないため、下流クライアントの redirect_uri が上流に転送されることはありません。次を設定します。
- ホストされたデプロイで
--public-url https://magicmarkets-mcp.dev-eu.kubershmuber.comを指定します MAGICMARKETS_OAUTH_ISSUER上で、リダイレクト URI の許可リストにこのホストの/mcp/callbackを含むクライアントをMAGICMARKETS_OAUTH_CLIENT_IDに設定します- 複数レプリカのデプロイでは、すべてのレプリカに
MAGICMARKETS_OAUTH_PROXY_SECRETを設定します。プロキシはサーバー側にセッション状態を保持しません(ログイン状態と一回限りのコードは、代わりに自己完結型のトークンとして封印されます)。そのため、このシークレットを共有していないレプリカは、互いの進行中のログインをデコードできません
取引を有効にする
取引は既定で無効です。 新規登録は読み取り専用のため、ベットを依頼されたエージェントには place_order ツールが表示されません。有効にするには、MAGICMARKETS_ALLOW_TRADING=1 を設定し、既存の登録を置き換えて、クライアントを再起動します。
claude mcp remove magicmarkets
claude mcp add magicmarkets -e MAGICMARKETS_API_KEY=your-key -e MAGICMARKETS_ALLOW_TRADING=1 -- magicmarkets mcp
再起動が重要です。クライアントは起動時にサブプロセスのツール一覧を一度だけ読み込むため、すでに実行中のセッションには、再登録後も読み取り専用の一覧が残ります。
クライアントの MCP 設定ファイルを直接編集する場合は、env に MAGICMARKETS_ALLOW_TRADING を設定します。
{
"mcpServers": {
"magicmarkets": {
"command": "magicmarkets",
"args": ["mcp"],
"env": {
"MAGICMARKETS_API_KEY": "your-key",
"MAGICMARKETS_ALLOW_TRADING": "1"
}
}
}
}
クライアントを介さずに、現在のモードを確認します。
$ MAGICMARKETS_ALLOW_TRADING=1 magicmarkets mcp --print-tools
mode: trading ENABLED (via MAGICMARKETS_ALLOW_TRADING) — this process can place real bets
TOOL
----
close_all_orders
close_order
create_betslip
place_order
...
環境変数を設定せずに実行すると、読み取り専用の一覧(11個のツール、取引有効時は19個)が表示されます。magicmarkets mcp は起動のたびにモードを stderr にもログ出力します。これはクライアントの MCP ログに表示されます(この出力先にできるのは stderr のみです。stdout は JSON-RPC ストリームに使用されます)。
各モードで公開される機能
| 常に利用可能 | MAGICMARKETS_ALLOW_TRADING が必要 |
|---|---|
get_balance、get_exchange_rates、get_position | create_betslip |
list_events、list_event_offers | place_order |
list_orders、get_order | close_order、close_all_orders |
list_betslips、get_betslip | create_heartbeat、refresh_heartbeat、cancel_heartbeat、list_heartbeats |
validate_bet_type、snap_price |
エージェントが実際に資金を賭けられるようにする場合にのみ、取引を有効にしてください。資金を使うツールには MCP の破壊的操作ヒントが設定されているため、クライアントは呼び出す前に確認を促します。
この制限が適用されるのは magicmarkets mcp のみである点に注意してください。CLI 独自の magicmarkets order place は常に利用できます。こちらには独自の確認プロンプトがあります。
エラー
エラーには、分岐処理に使える安定した機械可読の code が含まれます。
| HTTP | コード | 意味 |
|---|---|---|
| 400 | validation_error | リクエスト本文またはクエリの検証に失敗しました。フィールドごとの理由が表示されます |
| 400 | order_closed | 注文は存在しますが、すでに終了または決済されています |
| 401 | auth_error | キーがない、形式が不正、または拒否されました |
| 403 | forbidden | キーは有効ですが、この操作は許可されていません |
| 404 | not_found | リソースが不明、またはこのキーからは参照できません |
| 409 | order_already_created | request_uuid が再利用されました。既存の注文 ID が報告されます |
| 409 | limit_reached | 顧客ごとの上限に達しました |
| 429 | throttled | レート制限に達しました。Retry-After に従って自動的に再試行されます |
| 500 | server_error | 内部エラーです。報告時はサポートトークンを添えてください |
429 はリクエストが完全に拒否され、何も作成されていないことを意味するため、スロットリングされたリクエストは自動的に再試行されます(デフォルトでは 2 回)。それ以外のステータスは再試行されません。
冪等性
uuid=$(uuidgen)
magicmarkets order place --betslip bs-123 --price 2.10 --stake 50 --request-uuid "$uuid"
magicmarkets order tracked "$uuid" # recover after a timeout, safely
UUID が再利用されたことを検出すると、magicmarkets は失敗する代わりに元の注文を取得して表示します。
レート制限
アカウントごとのスライディングウィンドウ:全体でバースト時は 100 req/s、継続時は 1200 req/min、さらにベットスリップ作成用に 10 req/s、注文発注用に 5 req/s の専用枠があります。
トラブルシューティング
no API key configured — MAGICMARKETS_API_KEY を設定してください。magicmarkets status で読み込まれた .env ファイルを確認できます。
auth_error(401) — キーがまったく送信されていません。変数名を確認してください。
すべての呼び出しで session_not_found(404)が発生する — キーは送信されましたが、認識されていません。Settings → API でキーを再生成してください。
stream handshake failed — WebSocket は HTTP ハンドシェイク時に不正なキーを拒否します。まず magicmarkets status を実行してください。REST のほうが明確なエラーを返します。
magicmarkets markets が何も返さない — スナップショットには、現在ライブ価格が付いている イベントのみが含まれ、試合予定の全リストは含まれません。--sport を指定せずに試すか、--timeout を長くしてください。
ベットスリップに価格がない — オッズは非同期で届きます。--wait 5s を使用してください。それでも価格がなければ、その選択肢にオッズを提示しているソースはありません。
updated_at_to must be at least 60 seconds in the past — magicmarkets order updates の期間は、終了時刻が 60 秒以上前で、期間が 70 分以内である必要があります。
エージェントがベットできない、または MAGICMARKETS_ALLOW_TRADING が必要だと言う — magicmarkets mcp サブプロセスは読み取り専用で実行されているため、ベッティングツールが登録されていません。取引の有効化を参照してください。MAGICMARKETS_ALLOW_TRADING=1 を設定して再登録し、クライアントを再起動してください。現在のモードは magicmarkets mcp --print-tools で確認できます。
開発
レイアウト
cmd/magicmarkets/main.go entry point — signal handling, version
internal/config/ .env + environment resolution
internal/magicmarkets/ API client — no CLI or MCP dependencies
client.go transport, envelope, 429 retry
errors.go typed APIError per error code
types.go wire types (Stake is a [ccy, amount] tuple)
ticks.go tick schedule and price snapping
betslips.go orders.go account.go heartbeats.go
stream.go WebSocket client
internal/cli/ cobra command tree, table/JSON rendering
internal/mcpserver/ MCP tools over stdio or localhost HTTP, same client
internal/spec/ embedded openapi.json + reference commands
internal/magicmarketsapi/ generated models + the contract test guarding drift
tools/prepspec/ adapts the spec for oapi-codegen
docs/api-reference.md full API reference (vendored)
internal/magicmarkets は CLI 層や MCP 層に依存しないため、通常の Go クライアントライブラリとして利用できます。
日常的に使うコマンド
make test # go test ./...
make lint # go vet ./...
make fmt # gofmt -w
make build # ./build/magicmarkets
make install # install `magicmarkets` into your Go bin directory
make where # print where make install puts the binary
make generate # regenerate internal/magicmarketsapi from the vendored spec
make update-spec # refresh the vendored spec + docs, then regenerate
テストに API キーもネットワークも必要ありません。この状態を維持してください。
メインパッケージはモジュールのルートではなく cmd/magicmarkets/ にあるため、バイナリ名は magicmarkets になります。ルートをビルドすると、モジュールパスにちなんだ magicmarkets-cli という名前になり、ドキュメントや magicmarkets --help に記載されている実行名と異なります。新しいビルドターゲットも $(PKG) を指すようにしてください。
make build と make install は git describe の値を main.version に設定するため、magicmarkets --version で追跡可能なバージョンが報告されます。make build VERSION=v1.2.3 で上書きできます。
コード生成
internal/magicmarketsapi のモデルは、ベンダー管理されている OpenAPI 仕様から oapi-codegen を使って生成されます。
セットアップ:不要です。 oapi-codegen は go.mod の tool ディレクティブで固定されているため、新しいクローンでも make generate を実行できます。生成ファイルはコミット済みなので、git clone && go build でコード生成が必要になることはありません。
make generate # regenerate from internal/spec/openapi.json
make update-spec # pull the latest spec from the API, then regenerate
正規の仕様は magicmarkets.com/magic-api/docs から取得します。make update-spec は /magic-api/v2/openapi.json と Markdown リファレンスを取得します。その後 git diff を実行すると、API の変更点を正確に確認できます。
これらの生成型は契約の参照用であり、CLI が使用するものではありません
internal/magicmarkets のクライアントでは、手書きの型を維持しています。生成コードでは、この API に必要な次の 3 つを表現できないためです。
- Stake タプル。
["USDT", 115.38]は OpenAPI 3.1 のタプルですが、oapi-codegen ではまったく生成できません。 - ベットステータスのユニオン。 ベットのステータスは、単独の文字列かオブジェクトのどちらかです。
magicmarkets.BetStatusはどちらもアンマーシャルできますが、生成されたユニオン型では、呼び出し側すべてで分岐処理が必要になります。 - 非ポインターによるアクセス。 仕様ではほとんどの項目が
requiredとされていないため、生成されるフィールドはすべてポインターになります。API が常に送信するフィールドについて、CLI 全体に nil チェックを追加しても冗長です。
2 つの型の整合性を保つ仕組み
internal/magicmarketsapi/contract_test.go は、手書きの各型と対応する生成型の JSON フィールド名を双方向に比較し、差異があれば失敗します。上流のフィールドが追加、削除、または名前変更された場合、実行時に発覚するのではなく、make generate の後に go test が失敗します。
このチェックは初回の実行ですぐに役立ちました。Order に bet_bar_values がないことを検出し、magicmarkets order get --json でフィールドが黙って欠落していた問題を見つけました。
失敗した場合は、仕様とクライアントに食い違いがあります。クライアントを修正するか、理由を添えて、該当する組み合わせの specOnly / handOnly マップに例外を記録してください。テストを通すために組み合わせを削除してはいけません。
tools/prepspec で処理する 2 つの例外
ベンダー管理下のファイルには手を加えず、コード生成の前に仕様を調整します。
number→float64。 oapi-codegen は、フォーマット指定のない OpenAPI のnumberをfloat32(有効桁数は約 7 桁)にマッピングしますが、価格や賭け金には不十分です。prepspec はformat: doubleを追加します。これには、達成価格フィールドにのみ該当する nullable な["number", "null"]形式も含まれます。生成された金額フィールドがfloat32になっていないことを、テストで確認します。StakeTupleのフラット化。 oapi-codegen は 3.1 のタプルを処理できず、生成に失敗するため、型指定のない配列にフラット化します。実際に型指定された同等の型はmagicmarkets.Stakeです。
internal/magicmarketsapi/types.gen.go を手作業で編集しないでください。
規約と不変条件
このコードベースが前提としている事項です。変更する場合は、意図的に行ってください。
変更のテストに実際の注文を発注しないでください。 magicmarkets order place、magicmarkets order close*、および MCP の place_order / close_* ツールは、実際に資金を使います。読み取り専用のコマンド(status、balance、xrates、markets、offers、orders、position)と、オフラインの magicmarkets api コマンドは安全に実行できます。書き込み処理には、ローカルのスタブサーバーを使用してください。
データ構造を推測する前に仕様を確認してください。 magicmarkets api show orders POST で確認するほうが、推測するより確実です。いくつかのエンドポイントは一般的な {status, data} 形式と異なり、いずれも仕様を確認して初めて見つかったバグでした。
GET /v2/heartbeats/はデータをheartbeatsキーの下に格納します。他のリストエンドポイントはすべて、フラットな配列を返します。POST /v2/orders/{id}/close/は常にdata: nullを返します。最終状態を取得するには、注文を再読み込みしてください。POST /v2/betslips/{id}/refresh/にはレスポンスボディの仕様がありません。そのため、RefreshBetslipはレスポンスをデコードせず、ベットスリップを再読み込みします。
レイヤー構造を維持してください。 internal/magicmarkets から internal/cli または internal/mcpserver をインポートしてはいけません。
金額には float64 を使用し、価格には SnapPrice を通してください。 価格または賭け金の処理経路に float32 を導入してはいけません。
資金を使う新しい MCP ツールには AllowTrading を適用し、破壊的操作のヒントを付けてください。 このゲートはテストされています。弱めてはいけません。
金額を扱うコードにはテストが必要です。 ticks.go と MCP の取引ゲートには、安全性を確認するテストがあります。スナップによってベッターの上限が厳しくならないこと、および MAGICMARKETS_ALLOW_TRADING がないと取引ツールにアクセスできないことを確認しています。回避策を講じるのではなく、既存のテストを拡張してください。
すべてのコマンドが --json に対応し、それ以外の場合はテーブル形式で表示します。 データは stdout に、警告とプロンプトは stderr に出力し、パイプ処理を妨げないようにしてください。
文字列ではなくエラーコードで分岐してください。 magicmarkets.HasCode(err, magicmarkets.CodeOrderClosed) を使用してください。
認証
このリポジトリはパブリック v2 API(https://magicmarkets.com/v2)を対象としています。呼び出し元は、X-Api-Key または https://magicmarkets.com/api/auth から取得したトークンを使う Authorization: Bearer のいずれかの認証情報を提示しますが、実際に通信時に送信されるのは API キーだけです。v2 API と /v2/stream は Bearer トークンをそのまま受け付けません。これらのエンドポイントが必要とする magic-metadata-jwt/session のペアに、2 段階の処理で変換する必要があります。
POST {issuer}/oauth2/firebase-token(Authorization: Bearer <access token>)で、プレイヤーの実際の権限情報を持つFirebase カスタムトークンを発行します。- Firebase カスタムトークンは、それ自体では有効な ID トークンではありません。MCP サーバー実装者向けの Magic Markets 独自の OAuth 統合ガイドには、カスタムトークンを使用可能にするには、Firebase ID トークンと交換する必要があると明記されています。この処理では、Google Identity Toolkit REST API を直接呼び出して交換を行います(
POST https://identitytoolkit.googleapis.com/v1/accounts:signInWithCustomToken?key=<MAGICMARKETS_FIREBASE_WEB_API_KEY>)。返されたidTokenをmagic-metadata-jwtとして使用します。
GET {issuer}/me は、この処理には一切使用しません。このエンドポイントは Firebase ID トークンの検証によって保護されており、自己署名された OAuth アクセストークンでは検証を通過できないためです。internal/magicmarkets.MeResolver(internal/magicmarkets/meauth.go)が両方の段階を実行し、結果をキャッシュします。internal/mcpserver と CLI/stdio 経由の処理はどちらも同じクライアントを通るため、どちらでもこの処理が自動的に行われます。magicmarkets mcp --http は OAuth 保護リソースのメタデータを公開し、MCP ホスト(Claude、Cursor など)が Bearer トークンを取得できるようにします。
MAGICMARKETS_FIREBASE_WEB_API_KEY が必要な理由: 上記の 2 段階目では、Magic Markets のエンドポイントではなく、Firebase の Identity Toolkit API を呼び出します。Firebase は、どのプロジェクトのカスタムトークンを交換するのかを特定するために、Magic Markets の Firebase プロジェクトにスコープされたWeb API キーを必要とします。これは呼び出し元ごとに発行される秘密情報ではなく、Firebase の Web クライアントがクライアント側に埋め込んでいる、プロジェクト共通のキーです。プロジェクトと環境(STG と prod では Firebase プロジェクトが異なります)によって異なるため、安全なデフォルト値はありません。そのため、MAGICMARKETS_SESSION_GROUP_ID と同様に、OAuth Bearer を使用する呼び出し元が想定されるすべての環境で明示的に設定する必要があります。設定しない場合、Bearer 認証を使用するすべての呼び出しが失敗します。
sequenceDiagram
participant Caller
participant Resolver as MeResolver (cache)
participant Issuer as Magic Markets AS
participant Firebase as Firebase Identity Toolkit
participant API as v2 API / stream
Note over Caller,API: An X-Api-Key credential skips all of this, forwarded unchanged.
Caller->>Resolver: Authorization Bearer access token
alt cache hit, MeCacheTTL is 1 minute
Resolver->>Resolver: reuse cached magic-metadata-jwt and session
else cache miss
Resolver->>Issuer: POST /oauth2/firebase-token<br/>Authorization Bearer access token
Issuer-->>Resolver: firebase_token, a Firebase custom token<br/>not yet valid as magic-metadata-jwt
Resolver->>Firebase: POST accounts:signInWithCustomToken<br/>key is MAGICMARKETS_FIREBASE_WEB_API_KEY, token is firebase_token
Firebase-->>Resolver: idToken
Resolver->>Resolver: cache magic-metadata-jwt as idToken<br/>session as m, group id, uuid joined by dashes<br/>uuid read from the access token's own sub claim
end
Resolver-->>Caller: magic-metadata-jwt, session
Caller->>API: REST headers magic-metadata-jwt and session<br/>stream query params jwt and token
既知の制限事項
- このプロセスは、Magic Markets 側の責任ではなく、Firebase カスタムトークンを ID トークンに交換します。
POST /oauth2/firebase-tokenは、サーバー側でsignInWithCustomTokenを呼び出して、そのまま使える ID トークンを返すこともできます。そうすれば、この MCP サーバーだけでなく、すべての MCP サーバー実装者がMAGICMARKETS_FIREBASE_WEB_API_KEY、Google の Identity Toolkit エンドポイントへの直接依存、カスタムトークンと ID トークンの違いに関する知識を必要としなくなります。これは Authorization Server の契約上の不足を補うクライアント側の回避策であり、最終的な形ではありません。/oauth2/firebase-tokenが ID トークンを返すようになった場合、または v2 API がカスタムトークンを直接受け付けるようになった場合に見直してください。 - キャッシュはプロセス内にあり、共有されません。
MeResolverのキャッシュは、hashicorp/golang-lruの有効期限付きバリアントを使ったレプリカごとの LRU であり、internal/mcpserver/oauth.goが OAuth プロキシの状態に使用する、レプリカに依存しないシールド済み状態ではありません。ホスト型の複数レプリカ構成では、以前のリクエストとは異なるポッドにルーティングされた場合、キャッシュミス時に交換処理が 1 回余分に発生するだけです(呼び出しは 2 回になり、/oauth2/firebase-tokenとsignInWithCustomTokenが実行されます)。共有されていないMAGICMARKETS_OAUTH_PROXY_SECRETの場合とは異なり、失敗することはありません。これは意図的な回避策であり、最終的な形ではありません。共有キャッシュ、または Magic Markets から提供される、有効期間がより長いことを明記した認証情報があれば、レプリカごとのコールドスタートコストを完全になくせます。 - TTL とキャッシュサイズは固定の定数であり、環境変数ではありません(
magicmarkets.MeCacheTTL= 1 分、サイズは異なるアクセストークン 4096 個)。internal/magicmarkets/meauth.goを参照してください。/meの契約自体がまだ固まりきっていない間は、回避策をシンプルに保つためです。調整する価値が出てきた時点で見直してください。 MAGICMARKETS_SESSION_GROUP_IDとMAGICMARKETS_FIREBASE_WEB_API_KEYには安全なデフォルト値がなく、環境ごとに異なります。OAuth Bearer を使う呼び出し元が想定される環境では、両方を明示的に設定する必要があります。そうしないと、Bearer 認証を使うすべての呼び出しが失敗します。- トークンの事前更新はありません。 キャッシュミスのたびに解決処理が再試行されますが、アクセストークンの期限切れ前に更新する処理はありません。期限切れトークンは交換の失敗として表面化し、その結果、ツール呼び出しも失敗します。他の無効な認証情報の場合と同様です。
変更を加える
ブランチ → コード → チェック → PR のワークフローについては、CONTRIBUTING.md を参照してください。変更が vendored OpenAPI spec に影響する場合の対応方法も記載されています。
ライセンス
MIT — LICENSE を参照してください。
Magic Markets がメンテナンスしています。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。