ooligo
mcp-server

MCP server exposing ZoomInfo GTM data to Claude under a credit ceiling

Difficulty
上級
Setup time
60min
For
revops · gtm-engineer
RevOps

Stack

ZoomInfo の GTM API 上で Claude に 5 つの読み取り専用ツール、すなわち無料の検索 2 つ、エンリッチメント 2 つ、クレジット残高ツール 1 つを提供する Model Context Protocol サーバーです。エージェントと高コストな呼び出しのあいだに支出ガバナーを置いています。エンリッチメントは返却されたレコード 1 件につき bulk data credit を 1 消費するため、ここで面白いのは API との接続部分ではありません。監視なしのエージェントが火曜の午後に数百ドルを使い切るのを止める上限のほうです。スキャフォールドは apps/web/public/artifacts/mcp-server-zoominfo-gtm-revops/ にあります。README.mdpyproject.toml、ツールを定義する src/zoominfo_gtm_mcp/server.py、台帳とキャッシュを担う src/zoominfo_gtm_mcp/budget.py の構成で、pip install -e . でインストールします。

次のセクションを先に読んでください。ZoomInfo はすでに同種のサーバーを提供しており、しかも無料だからです。

これを使うべきとき

ZoomInfo は自社の MCP server を https://mcp.zoominfo.com/mcp でホストしています。ブラウザ上の OAuth 2.0 で認証し、追加費用なしで全サブスクリプションに含まれ、19 のツールを公開しています。内訳は、企業とコンタクトの検索およびエンリッチメント、intent、scoops、ニュース、lookup、lookalikes、推奨コンタクト、オーディエンス、GTM コンテキストをカバーする 16 のデータツールと、Account Research、Contact Research、Update GTM Context というエージェント型の 3 つです。管理者が Admin Portal でユーザー単位に有効化します。人間が対話的にアカウント調査を行うなら、それが正解であり、このスキャフォールドは無駄な作業です。 claude mcp add --transport http zoominfo https://mcp.zoominfo.com/mcp で接続して、この先を読むのをやめてください。

自前で構築すべきなのは、次の 4 条件のいずれかに当てはまるときです。

エージェントが無人またはスケジュール実行で動く。 これは当社の好みではなく ZoomInfo 自身の指針です。ホスト版サーバーは一括エクスポート、CRM への書き戻し、スケジュールジョブには適さないと明記されており、スケジュール実行のパイプラインは API を使うよう案内されています。朝 6 時に起動して誰も見ていない状態でリストをエンリッチするエージェントは、ベンダー自身の説明に照らして誤った道具を使っています。

ユーザー ID ではなくサービス ID が必要。 ホスト版サーバーはサインインした本人として、その本人の権限で動き、管理者がユーザー単位で有効化します。Slack やジョブランナーから起動される共有エージェントには、なるべき「本人」が存在しません。このスキャフォールドが使う client credentials フローは、専用の client id と api:data:companyapi:data:contact という 2 つの専用スコープを与えます。

厳格な支出上限が必要。 ホスト版サーバーには実行あたりのクレジット上限がなく、後述の計算がそれがどれほど早く実際の金額になるかを示します。ZI_DAILY_CREDIT_LIMIT は、エージェントが交渉できない数値です。

契約が月次の繰り返しクレジットで動いている。 ホスト版 MCP server は bulk data credit を消費し、月次の繰り返しクレジットでは動作しません。契約がその形なら、ホスト版サーバーはそもそも機能せず、API だけが入り口になります。

これが効くのは 2 つの役割です。支出を自分の管理する台帳に載せたい RevOps リーダーと、このシリーズの ApolloAttio のサーバーをすでに出荷し、あらゆるデータソースに同じ読み取り専用の姿勢を通したい GTM engineer です。

これを使うべきでないとき

  • 人間が操作している。 前述のとおりで、繰り返す価値があります。ホスト版サーバーは無料で、対象範囲が広く、手間も少ない。このスキャフォールドは無人実行のためのものです。
  • ZoomInfo や CRM への書き戻しがほしい。 ここには書き込み処理が一切ありません。要求するスコープに api:gtm-config:manageapi:audience:manageapi:gtm-data-model:manage は含まれておらず、追加すればこの設計が意図的に握らせていないボタンをエージェントに渡すことになります。
  • コンタクトの個人データを LLM に触れさせられない。 zi_enrich_contacts は検証済みのビジネスメールと直通番号を返します。返却された各フィールドは会話に入り、トランスクリプトに残ります。output_fields を絞ればその範囲は小さくなりますが、なくなりはしません。答えが明確に「不可」なら、コンタクトデータベースの上に MCP server を置くこと自体が適切な企画ではありません。
  • エージェント型のブリーフィングがほしい。 Account Research と Contact Research は AI action として課金されるホスト版サーバーのツールです。このスキャフォールドはそれらを再実装しませんし、すべきでもありません。ZoomInfo の提供物のうち最も再構築が難しく、そのまま使うのが最も安い部分だからです。

公開するもの

src/zoominfo_gtm_mcp/server.py に定義された、すべて読み取りの 5 ツールです。

  • zi_credit_status() — 無料。GET /data/v1/users/usage から得る ZoomInfo 自身のサブスクリプションカウンター(limitTypetotalLimitcurrentUsageusageRemaining)と、ローカル台帳(本日の消費、上限、実行中の呼び出しによる確保分、利用可能分、7 日間のツール別消費)を結合します。ツール説明は、バッチを計画する前にこれを呼ぶようエージェントに指示します。ZoomInfo の usage エンドポイントが失敗した場合、ツールはエラーにせずローカル台帳に縮退します。ローカル上限はいずれにせよ適用されるからです。
  • zi_search_companies(criteria, page_size, page_number, sort)POST /data/v1/companies/search。無料です。クレジットは消費せず、返却された企業はレコード上限にも数えられません。ただし各リクエストは rate limit には数えられます。page size は 100 に制限されます。
  • zi_search_contacts(criteria, page_size, page_number)POST /data/v1/contacts/search。無料、条件は同じです。
  • zi_enrich_companies(company_ids, output_fields)POST /data/v1/companies/enrich。クレジットを消費します。1 回の呼び出しにつき最大 25 件で、これは当方ではなく ZoomInfo 側の上限です。
  • zi_enrich_contacts(contact_ids, output_fields)POST /data/v1/contacts/enrich。クレジットを消費し、上限も同じです。

検索結果は id と薄いラベルだけに削っています。検索は無料でエンリッチメントは有料なので、検索結果の唯一の仕事は、どの id に支払う価値があるかをエージェントに判断させることです。検索のペイロードを丸ごと返せば、未検証のフィールドをエンリッチ済みの検証データであるかのように扱うよう、モデルを誘うことになります。

クレジットガバナーの仕組み

エンリッチメント呼び出しのコストは、レスポンスをパースするまで確定しません。ZoomInfo は返却レコード単位で課金しますが、マッチなしの結果とエラーは課金されず、すでに under management のレコードも課金されません。そのため src/zoominfo_gtm_mcp/budget.py は予算を 2 段階で強制します。

最悪ケースを確保する。 リクエストを送る前に、キャッシュにまだ無い要求レコード 1 件ごとに 1 クレジットを確保します。すべての入力がマッチし、すべてのマッチが新規である場合を想定します。この最悪ケースが上限の残りを超えるなら拒否します。拒否が全か無かなのは意図的です。部分確保を許せば、エージェントが 25 件中最初の 8 件だけをエンリッチして成功と報告でき、それは完全な回答に読めて実際には違うからです。

実績で精算する。 レスポンス受領後、ZoomInfo がマッチとして返したレコード数を数え、その数を永続的な SQLite 台帳に書き込み、未使用の確保分を解放します。

拒否は例外ではなく結果として返します。refused: true、残高、次に取るべき手順を含む JSON オブジェクトです。モデルはそれを読んで残額に合わせて計画を立て直せます。例外を投げるとたいていその場でターンが終わります。

キャッシュは ZoomInfo 自身のレコード id をキーに、TTL 365 日で保持します。これは再エンリッチが無料になる Records Under Management の 12 か月ウィンドウに合わせたものです。ヒットすればクレジットも HTTP リクエストも消費しません。エージェントが 1 セッション中に同じ質問を 4 回する場面では、そこが効きます。

コストの実態

エンリッチメントは返却レコード 1 件につき bulk data credit を 1 消費し、1 リクエストあたり最大 25 件です。bulk credit は小口では 1 件あたり $0.60〜$1.00、大量では $0.20 程度まで下がる水準で再販業者に提示されています。これは第三者の数字であって ZoomInfo の価格表ではなく、実際にはお客様の契約が優先します。

200 アカウントを調査し 1 社あたり 4 名のコンタクトを取得するエージェントなら、新規レコードは 800 件です。エンリッチメント呼び出し 32 回、bulk data credit 800 で、上記の水準なら無人の午後 1 回あたり $480〜$800 の規模になります。

この 32 回は rate limit に対しては何でもありません。文書化された最小パッケージである Builder でも毎秒 5 リクエスト、毎時 10,800、毎日 129,600 を許容します。Standard は毎秒 25、毎時 54,000、毎日 648,000。Scaling は毎秒 35、毎時 75,600、毎日 907,200 です。エンリッチメントエージェントを実際に縛る制約はスループットではなくクレジット残高です。 だからこのスキャフォールドはクレジットを統制し、rate limit については到達したときに報告するだけにしています。

セットアップは約 1 時間で、その大半は API アプリケーションの作成と、実際に保持しているスコープの確認に費やされます。

障害モードとガード

エージェントがループして四半期分のクレジットを使い切る。 リストと目標を与えられたエンリッチメントエージェントは、エンリッチし続けます。ガード: ZI_DAILY_CREDIT_LIMIT(既定値 250、上記水準でおよそ $150〜$250)、各呼び出し前の最悪ケース確保、そして残りいくつのレコードを購入できるかをエージェントに伝える構造化された拒否。

自社のサブスクリプションではホスト版サーバーが動かず、ローンチ当日まで誰も気づかない。 ホスト版 MCP server は bulk data credit を必要とし、月次の繰り返しクレジットでは黙って動作しません。ガード: 初日に zi_credit_status を実行してください。契約が持つクレジット種別を示す ZoomInfo の limitType カウンターを、誰かが誤った前提の上に workflow を組み立てる前に報告します。

モデルが検索結果を検証済みのコンタクトデータとして報告する。 無料検索が返すのは識別用フィールドであって、検証済みメールでも直通番号でもありません。それらは有料のエンリッチメントからのみ得られます。検索ペイロードを丸ごと渡されたモデルは、それを回答として提示します。ガード: server.py_slim_search が結果を id と薄いラベルに削るため、誤って報告する材料自体がありません。

2 つのエージェントが 1 つの台帳を共有し、そろって上限を超える。 確保分はプロセスメモリに、台帳はディスクに置かれるため、同じ ZI_STATE_PATH を指す 2 つのサーバーは互いの精算済み消費は見えても、実行中の確保分は見えません。ガード: 複数同時に走らせる前に、エージェントごとに専用の ZI_STATE_PATH を与えるか、確保分をデータベースへ移してください。これは README の本番前チェックリスト 7 項目中の 4 番目です。

バッチの途中でトークンが期限切れになる。 client credentials のトークンは expires_in およそ 1,000 秒で返ります。ガード: サーバーは期限到来時ではなく、公称寿命の 80% の時点で更新します。これにより、ローカル検査を通過したトークンが通信中に失効することを防ぎます。

代替案との比較

ZoomInfo のホスト版 MCP server は幅、コスト、手間で勝ります。19 ツール、コードなし、ローテーションすべき資格情報なし、サブスクリプションに込みです。負けるのは、呼び出し元が人間ではなくスケジュールジョブになった瞬間です。サービス ID も支出上限も持たないからです。

ZoomInfo CLI はスクリプトからのアクセスに対するベンダー自身の答えで、バッチエクスポートの結果を後から人間が読む用途ではこちらが上です。MCP server ではないため、エージェントがターンごとに推論を重ねることはできません。

代わりに Clay でエンリッチするのは、エンリッチメントが複数プロバイダーにまたがるウォーターフォールを伴うテーブル操作である場合には正解で、200 アカウントのうちどの 12 件が有料参照に値するかをエージェントが会話の途中で判断する必要がある場合には不正解です。このスキャフォールドの形は、その判断がエージェントに属するという前提で組まれています。

スタック

GTM データソース全体で読み取り専用の MCP アクセスを標準化するチームには ApolloAttio のサーバーと、大量のウォーターフォールエンリッチメントが会話ではなくテーブルに属する場合には Clay と組み合わせてください。

Files in this artifact

Download all (.zip)