mcpField
M
MagicMarkets

MagicMarkets

リモート
magicmarkets.comゲーム・エンタメ1今日更新
リポジトリ公式サイト

MagicMarkets について

MagicMarketsは、Magic Markets v2 APIを操作するコマンドラインツールで、スポーツ予測市場を扱うユーザーやエージェントを対象としています。価格配信、クオートと注文の管理に加え、同じAPI機能をMCPツールとして提供します。

主な機能

  1. 01スポーツ価格と口座アクティビティを配信
  2. 02イベントと価格付き選択肢を検索
  3. 03ベットスリップ作成と注文発注
  4. 04ポジション、残高、注文を確認
  5. 05期限後に注文を閉じるハートビートを管理

活用シーン

  1. 01指定イベントのライブ価格を監視
  2. 02選択肢をクオートして注文を発注
  3. 03ハートビートで自動戦略を保護

MCP 対応

CLIはstdioまたはローカルホスト上のStreamable HTTPでMCPツールを提供します。`MAGICMARKETS_ALLOW_TRADING`を設定しない限り、MCP経由の取引機能は無効です。

設定

リモートサーバーはインストール不要です。クライアントを選んで設定をコピーするか、ワンクリックで導入できます。

エンドポイントhttps://magicmarkets.com/mcp
インストールコマンドをコピー
Claude CodeTerminal
Cursor.cursor/mcp.json
VS Code.vscode/mcp.json
Claude Desktopclaude_desktop_config.json
Windsurf~/.codeium/windsurf/mcp_config.json

コマンドはターミナルで実行し、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
  • セットアップ — インストール、認証、最初のコマンド
  • 使い方 — ベットの流れ、コマンドリファレンス、MCP、価格、エラー
  • 開発 — 構成、コード生成、規約、コントリビューション

セットアップ

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_ISSUERhttps://magicmarkets.com/api/authmcp --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_URLhttps://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_URLMAGICMARKETS_API_URL から導出ストリームエンドポイント
MAGICMARKETS_LANGenイベント名の言語:en、ko、zh-hans
MAGICMARKETS_TIMEOUT30sリクエストごとのタイムアウト
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. ベットスリップは、1 つの選択肢への関心を登録し、リアルタイムのオッズを受け取ります。費用はかからず、何も確定されません。
  2. 注文は、そのオッズに対する賭け金を確定します。

ベットスリップは有効期間が短く、作成時には価格がありません。オッズは非同期で、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 xratesUSDT に対する為替レートを表示します
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 – 20.01
2 – 30.02
3 – 40.05
4 – 60.10
6 – 100.20
10 – 200.50
20 – 301
30 – 502
50 – 1005
100 – 100010

ティックに合わない注文価格は、指値が厳しくならないように丸められます。バック(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.52.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 ではなく各クライアントのドキュメントを参照してください。

クライアントを問わず、最もよくある問題は 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_positioncreate_betslip
list_events、list_event_offersplace_order
list_orders、get_orderclose_order、close_all_orders
list_betslips、get_betslipcreate_heartbeat、refresh_heartbeat、cancel_heartbeat、list_heartbeats
validate_bet_type、snap_price

エージェントが実際に資金を賭けられるようにする場合にのみ、取引を有効にしてください。資金を使うツールには MCP の破壊的操作ヒントが設定されているため、クライアントは呼び出す前に確認を促します。

この制限が適用されるのは magicmarkets mcp のみである点に注意してください。CLI 独自の magicmarkets order place は常に利用できます。こちらには独自の確認プロンプトがあります。

エラー

エラーには、分岐処理に使える安定した機械可読の code が含まれます。

HTTPコード意味
400validation_errorリクエスト本文またはクエリの検証に失敗しました。フィールドごとの理由が表示されます
400order_closed注文は存在しますが、すでに終了または決済されています
401auth_errorキーがない、形式が不正、または拒否されました
403forbiddenキーは有効ですが、この操作は許可されていません
404not_foundリソースが不明、またはこのキーからは参照できません
409order_already_createdrequest_uuid が再利用されました。既存の注文 ID が報告されます
409limit_reached顧客ごとの上限に達しました
429throttledレート制限に達しました。Retry-After に従って自動的に再試行されます
500server_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 段階の処理で変換する必要があります。

  1. POST {issuer}/oauth2/firebase-token(Authorization: Bearer <access token>)で、プレイヤーの実際の権限情報を持つFirebase カスタムトークンを発行します。
  2. 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 がメンテナンスしています。

コメント

MCP は初めてですか?

プロトコルの概要から最初のサーバーの導入まで、よくある疑問にまとめて答えます。

AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。