mcp-tool-discovery について
ServiceNow MCP サーバーを使うエージェント向けに、ツール検索から呼び出し成功までを解説するガイドです。セッション単位の遅延ツールの有効化、検索の仕組み、呼び出し方法、よくある失敗要因を扱います。
主な機能
- 01遅延ツールの検索と有効化
- 02ツールの利用状態の確認
- 03セッション ID と保存の説明
- 04検索順位とクエリ方法の解説
- 05呼び出しと安全フラグのトラブル対応
活用シーン
- 01ServiceNow ツールの発見と呼び出し
- 02遅延状態が続くツールの診断
- 03ドメインやテーブル名でツールを検索
- 04実行結果と呼び出し設定の確認
MCP 対応
ServiceNow MCP サーバーの検索・実行メタツールを取り上げ、stdio と HTTP の各トランスポートでのツール発見、有効化、呼び出しの違いを説明します。
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ serac-labs/ serac --skill mcp-tool-discoveryインストール後、Claude Code で/mcp-tool-discoveryを入力して読み込まれたか確認します。
詳細
MCP ツールの検出
このサーバーは、80 のドメインにわたる 440 個を超える snow_* ツールを登録していますが、その一覧は表示しません。初回のツール一覧には 2 つのメタツールしかなく、それ以外はすべて tool_search 経由で利用できます。このガイドでは、「こういうツールがありそうだ」という状態から、実際に動作する呼び出しにたどり着く方法を説明します。
正確な合計数はここでは記載しません。合計数が 2 つあり、一致しないためです。ドキュメントサイトに公開されるのは packages/servicenow-mcp/tools.json の内容ですが、実行中のサーバーが呼び出せるのはレジストリに登録されたツールです。公開されているツールのうち 9 個はレジストリにありません(「ドキュメントにはあるのにサーバーにはない 9 つのツール」を参照)。
起動直後に使えるのは 2 つのツール
stdio トランスポートに対する初回の tools/list は、ツールがいくつ存在していても、必ず次の内容を返します。
tool_search
tool_execute
これは意図的な動作です。サーバーの注記によると、完全なカタログのスキーマは約 71k トークンで、2 つのメタツールは約 2k トークンです。インデックスではすべてのツールが遅延読み込みに設定されており、handlers/list-tools.ts はメタツールと、現在のセッションで有効化されたツールだけを返します。
HTTP トランスポート(ポータル)は逆の動作をします。カタログを遅延読み込みなしで登録するため、tools/list はすべてのツールを返し、有効化も不要です。どちらを使っているかは、tool_search の結果にあるステータスで判別できます。[AVAILABLE] は、サーバーが有効化済みのツール一覧による制限をまったく行っていないことを意味します。
一連の流れ
// 1. Search. Found tools are enabled for this session by default.
tool_search({ query: "update-sets" })
// 2. Read the status on each hit:
// [AVAILABLE] — callable now, nothing had to be enabled
// [ENABLED] — deferred, and enabled for this session. Callable now.
// [DEFERRED] — NOT callable. Nothing was enabled; see the next section.
// 3. Execute.
tool_execute({ tool: "snow_ensure_active_update_set", args: { name: "Feature: SLA fix" } })
確認だけしたい場合は、enable: false を指定します。セッションの状態を変更せずに検索できます。
セッション ID がなければ、ツールは使えません
ここで午後の大半を無駄にしてしまうことがあります。有効化の状態は (tenant, session) ごとに保存されます。セッション ID がなければ、その状態を紐付ける先がないため、tool_search は何も有効化できず、すべての検索結果が [DEFERRED] のままになり、すべての呼び出しが拒否されます。
⚠ 5 deferred tool(s) were NOT enabled: this request carries no session id, so there is nothing to
attach the enablement to. They stay [DEFERRED] and tool_execute will refuse them.
{
"success": false,
"error": "Tool \"snow_query_table\" is [DEFERRED] and must be enabled first",
"hint": "Use tool_search({query: \"query table\"}) to enable this tool",
"status": "[DEFERRED]"
}
もう一度検索しても解決しません。セッション ID は、JWT ペイロードの sessionId、x-session-id ヘッダー、SNOW_SESSION_ID 環境変数、Serac CLI が書き込む current-session.json ファイルの順に取得されます。通常の stdio では最初の 2 つは存在せず、ファイルもこのマシンで Serac TUI を実行した場合にしか存在しません。そのため、サーバーを直接起動するクライアント(Claude Code プラグインの npx … servicenow-mcp-stdio など)では、セッション ID を指定しないかぎりセッション ID がありません。
{
"mcpServers": {
"servicenow": {
"type": "stdio",
"command": "npx",
"args": ["-y", "--package=@serac-labs/servicenow-mcp", "servicenow-mcp-stdio"],
"env": { "SNOW_SESSION_ID": "my-session" }
}
}
}
これは、プラグインが packages/skills/.mcp.json に同梱しているエントリに、env を追加したものです。編集するときは command と args も残してください。env だけのエントリでは、何も起動できません。ID には、変わらない文字列であれば何でも使えます。知っておくべき点は次の 2 つです。
- 有効化されたツール一覧はセッションごとにディスクへ永続化され、再起動後に復元されます。macOS では
~/Library/Application Support/snow-code/enabled-tools/stdio/<session>.json、Linux では~/.local/share/snow-code/enabled-tools/、Windows では%APPDATA%\snow-code\に保存されます。ディレクトリ名がsnow-codeのままなのは、名称変更前から使われているためです。同じSNOW_SESSION_IDを再利用すれば、前日に有効化したツールがすでに使えます。最初からやり直すには、ファイルを削除してください。 - HTTP トランスポートでは、ストアはメモリ上にあり、テナントごとに管理されます。テナントに割り当てられないリクエストはプールされずに拒否されます。その場合、ヒントに
no tenant scopeと表示されます。
名前による呼び出しと、tool_execute のほうが安全な理由
ツールを有効にすると、サーバーは名前でディスパッチします。handlers/call-tool.ts は
snow_query_table を直接受け付け、エージェントへの指示でもそのように呼び出すよう伝えています。
サーバーが行わないのは、リストが増えたことをクライアントに通知することです。サーバーは
listChanged のない capabilities: { tools: {} } を宣言し、
notifications/tools/list_changed を送信することもありません
(https://modelcontextprotocol.io/specification/2025-06-18/server/tools)。仕様によると、この通知を受けて
クライアントは tools/list を再度リクエストします。そのため、新たに有効にしたツールがコンテキスト内で呼び出し可能なツールとして表示されるかどうかは、
クライアントが独自にリストを再取得するかどうかに完全に依存します。
tool_execute はコールドスタート時のリストに含まれているため、常に動作します。検索後の最初の呼び出しにはこれを使用してください。
名前による呼び出しは便利な方法ですが、保証されているわけではありません。
外側のフラグだけでなく、エンベロープを確認する
tool_execute が報告するのは、ディスパッチしたかどうかであり、操作が成功したかどうかではありません。ツール自体の判定は
内側にネストされています。
{
"success": true,
"tool": "snow_query_table",
"result": { "success": false, "error": "undefined is not an object (evaluating 'context.instanceUrl.replace')" }
}
外側の success: true と内側の success: false の組み合わせは、操作が失敗したことを示します。result.success を確認してください。
この特定の内側のエラーはツールの不具合ではありません。インスタンスがまったく設定されていない場合に、すべてのツールが返すエラーです。
SNOW_INSTANCE が未設定です。エグゼキューターを読むのではなく、設定してください。
ガードフラグは args の内側に指定する
本番環境として分類されたインスタンスへの書き込みと、アクティブな更新セットがない状態での構成の書き込みは、
名前による呼び出しと同様に、tool_execute 経由でもツール層でブロックされます。再試行フラグ
__confirmProd と __skipUpdateSet は、args オブジェクトの内側に指定してください。外側に置くことはできません。
これらは内側の引数から読み取られ、エグゼキューターに渡される前に取り除かれます。
tool_execute({
tool: "snow_create_business_rule",
args: { table: "incident", name: "Auto-assign", __confirmProd: true },
})
検索:一致するものと、気づかないうちに一致しないもの
インデックスには、各ツールについて、snow_ を取り除いて _ で分割した名前(2 文字を超える部分のみ保持)と、説明文の重要な単語の先頭 10 個が格納されています。長い説明文の後半に出てくる、他と区別する名詞はキーワード検索では見つかりません。
スコアは部分文字列ではなく、単語全体を基準に計算されます。クエリはインデックスと同じ方法で分割され、英語のストップワードが除外され、通常の複数形は単数形に統一されます。残った各単語には、カタログ全体での希少性に応じた重みが付きます。半数のツールに含まれる単語ではスコアはほとんど上がりませんが、3 つのツールにしか含まれない単語ならスコアを左右します。その後、スコアには、一致した単語数をクエリ内の単語数で割った割合が掛けられます。そのため、リクエストの 3 分の 2 に応えるツールは、3 分の 1 にしか応えないツールを大きく上回ります。インデックス内のトークンの接頭辞も、割り引かれたスコアで一致します。これにより、「syntax」で「SyntaxErrors」と書かれた説明を検索できます。
ドメイン名が最適なクエリです。 まとまりのあるグループ全体を、ほかのものを含めずに検索できます。
tool_search({ query: "update-sets" }) // all three: snow_update_set_query, snow_ensure_active_update_set, snow_update_set_manage
tool_search({ query: "blast-radius" }) // the whole impact-analysis family
tool_search({ query: "local-sync" }) // the pull/push/status/cleanup family
tool_search({ query: "atf" }) // test, test step, test suite, discover, execute, results
ドメイン名は、packages/servicenow-mcp/src/servicenow-mcp-unified/tools/ 以下のディレクトリ名から、ドメインではないものをいくつか除いた名前です。__tests__ はテスト用、meta は tool_search と tool_execute 自体の配置場所で、意図的にレジストリの対象外です。adapters は空のプレースホルダーです。それ以外はすべて検索できます。
limit のデフォルト値は 10 で、7 つのドメインがそれを超えるツールを含みます:security、integration、automation、operations、agile、cmdb、ui-builder。ドメインごとの正確な数を覚える必要はありません。ツールが追加されるたびに変わるため、検索結果がちょうど 10 件の場合は途中で切れていると考え、limit を増やしてください。
テーブル名も使えます。テーブル名は単語で構成されているからです。 sys_script_include は sys、script、include に分割され、希少な単語に基づいてスコアが計算されます。
| クエリ | 最初の結果 |
|---|---|
"sys_script_include" | snow_create_script_include |
"sysevent_email_action" | snow_email_notification_manage |
"sp_widget" | snow_create_sp_widget |
"sys_user" | snow_impersonate_user — 4 つの中で最も弱い結果です。user はどこにでもあるためです |
最後の行は、残る検索失敗の典型です。区別に必要な部分がカタログ内で頻繁に使われる単語であるテーブルを検索すると、もっともらしいノイズばかりが並びます。代わりに操作内容を説明してください。"deactivate a user" なら snow_user_manage が見つかります。
平易な英語でも検索できます。通常はこちらのほうが適しています。ランキングは、現実的な表現で書かれた 101 件のリクエスト(tool-search-eval.test.ts)を使って評価されており、その 3 分の 2 で、上位 5 件以内に適切なツールが見つかります。また、カタログにない一部の語彙も把握しています。たとえば、「ticket」ではインシデントも、「column」ではフィールドも検索されます。また、「shift」中の担当者を尋ねると、オンコール用のツールが検索されます。
一致するものがない場合、レスポンスには「available domains」を列挙する suggestion が含まれます。このリストは、アルファベット順で最初の 15 個のドメイン名、つまり access-control から calculators までです。ドメイン全体の一覧ではなく、ランキングされた候補でもありません。このリストにないからといって、operations や update-sets が存在しないと判断しないでください。
インデックスが実際に返すもの
同梱インデックスの上位ヒットを、このチェックアウトに対して再実行した結果です。スコアは安定ソートされるため、同点のツールは登録順に返され、ツールが追加されるたびに正確な順位が変わります。順位ではなく、含まれているツールを確認してください。
| クエリ | 上位ヒット |
|---|---|
"query table" | snow_query_table、snow_validate_query、snow_graphql_query、snow_record_manage |
"incident" | snow_analyze_incident、snow_auto_resolve_incident、snow_create_security_incident |
"cmdb" | snow_cmdb_identify_reconcile、snow_search_cmdb、snow_cmdb_search |
"business rule" | snow_create_business_rule、snow_disable_business_rule |
"attachment" | snow_get_attachments、snow_delete_attachment、snow_upload_attachment |
"acl" | snow_acl_explain、snow_create_acl_role、snow_create_acl — および回答を捏造する snow_test_acl。下記を参照してください |
"flow" | snow_start_workflow、snow_workflow_manage、snow_manage_flow |
"jira" | snow_create_oauth_profile、snow_install_spoke — 最後のセクションを参照してください |
"incident" では、インシデントの CRUD に必要なツールが返されないことに注意してください。それは snow_record_manage
({ action, table: "incident", … })で、クエリ "record" または "query table" で見つかります。また、
snow_search_cmdb と snow_cmdb_search は、異なるドメインにある別々のツールですが、ほぼ同じ処理を行います。
名前の重複はよくあります。選ぶ前に両方の説明を読んでください。
ランキングは品質ではなく関連性を示します
tool_search は文字列の一致度で順位付けします。ツールが動作するかどうかは判断できず、このカタログには
2種類の誤りがあります。どちらか一方への対策では、もう一方を検出できないため、両方を把握する必要があります。
パターン1:インスタンスに一切接続しません。 エグゼキューターは、渡した引数から成功オブジェクトを組み立てて返します。わかりやすいクエリでは、次の2つが上位に返されます。
tool_search({ query: "artifact" })では、snow_clone_instance_artifactが最初に表示されます。接続を開くことはありません。"message": "Cross-instance cloning requires additional authentication setup"と、snow_export_artifactおよびsnow_import_artifactの名前を挙げた手順の一覧を含むsuccessを返しますが、これらのツールはどちらもこのサーバーには存在しません。インスタンス間の昇格には更新セットを使用するか、ローカル間の往復にはsnow_pull_artifact/snow_push_artifactを使用してください。tool_search({ query: "incident" })では、snow_create_security_incidentが3番目に表示されます。これは未実装のスタブで、引数を検証してそのまま返し、"summary": "Security incident \"…\" prepared with priority: …"を返します。インスタンスには何も送信されません。「prepared」という語に注意してください。securityドメインにある6つのsnow_create_*ツールは、すべて同じ種類のスタブです。実際に動作する SIR ツールはsnow_sir_*ファミリー(sn_si_incidentを読み書きするsnow_sir_incident_manageなど)であり、テーブルに直接アクセスするsnow_record_manageも常に動作します。
説明が根拠にならないことを示す最も明確な例は、security の snow_create_access_control です。
「sys_security_acl に書き込む」と説明されていますが、接続を開くことはありません。実際に /api/now/table/sys_security_acl に POST するのは、access-control の snow_create_acl です。
パターン2:インスタンスには接続しますが、誤った処理を要求します。 より大きなツール群が /api/now/table/sys_script_execution にレコードを POST し、Table API が挿入した行を返す応答を、スクリプトの実行結果であるかのように読み取ります。Table API はレコードを挿入しますが、実行はしません。そのため何も実行されません。また、パターン1の確認方法ではすべて問題なく見えてしまいます。実際の HTTP 呼び出しがあり、実際の 201 が返り、実際の sys_id があり、result.success は true です。
上記の「acl」の検索結果で上位に表示される snow_test_acl は、知っておくべきツールです。has_access: response.data.result を返します。ここでの result は挿入された行で、呼び出すたびに truthy なオブジェクトとなるため、常にアクセス可能と報告し、ACL を評価しません。指定した operation と user も無視します。ACL を扱う場合は、snow_acl_explain で一致するルールとユーザーが持つロールを確認し、snow_create_acl でルールを作成してください。実際の判定を確認するには、UI でユーザーになりすましてください。プラットフォームは特定のレコードに対して ACL を判定するため、Table API ではその判定を行えません。
このグループのツールがすべて結果を捏造するわけではありません。エコーに出力がない場合に例外をスローするツールもあり、これは明確で正直な失敗です。見分ける際に常に確認すべきなのは、応答が依頼した内容を示しているのか、それとも送信したリクエストを示しているのか、という点です。
コストのかからない習慣が 2 つあります。
- 説明にテーブル名または API エンドポイントが記載されたツールを優先し、その後で確認してください。説明だけでは何の証拠にもなりません。「認証、依存関係の解決、データ移行を処理する」といった曖昧な説明は、信頼できない兆候です。テーブル名が明記されていれば出発点にはなりますが、保証にはなりません。
- 重要な書き込みの後は、
snow_query_tableまたはsnow_record_manageで読み戻してください。さらに、変更するつもりだった成果物を、変更するつもりだったテーブルから読み戻してください。応答に含まれる sys_id だけでは証拠になりません。sys_script_executionツールは、完全に再クエリ可能な sys_id を返しますが、それは依頼していない行のものです。ビジネスルールを作成した場合、成功の証明となるのはsys_scriptの行であり、返された ID の検索が成功したことではありません。
参考までに、信頼できる中核ツールは次のとおりです。レコードには snow_query_table と snow_record_manage、成果物には snow_artifact_manage と snow_pull_artifact/snow_push_artifact、変更追跡には snow_update_set_manage/snow_ensure_active_update_set、認証中のユーザーの確認には snow_session_context、原因がわかりにくい理由で呼び出しが失敗する場合には snow_diagnose_setup を使います。
結果はスキーマではなく、概要です
各検索結果は一部が省略されています。説明は 200 文字で切り詰められ、表示されるパラメーターは最大 5 つで、各パラメーターの説明は 80 文字で切り詰められます。has_more_params: true は、ほかにもパラメーターがあることを示しますが、検索結果には表示されません。snow_artifact_manage には 56 個のパラメーターがあり、表示されるのは 5 個です。
スキーマ全体を確認するには、ツールを有効にしてクライアントに再度一覧表示させてください(tools/list には完全な inputSchema が含まれます)。または、ツールを呼び出して検証エラーを確認してください。tool_search に表示されなかったという理由で、パラメーターが存在しないと判断しないでください。
ドキュメントの一覧とサーバーの一覧は照合されています
ドキュメントサイトとポータルが表示するマニフェスト tools.json は、ツールファイルをたどって生成されます。実行中のサーバーは、shared/tool-registry.ts にハードコードされたドメインマップからレジストリを構築します。同じツリーを異なる 2 つの方法で読み取っており、以前はその内容にずれがありました。9 つのツールが公開されているのに利用できない状態でした(tools/fsm/、tools/predictive-intelligence/、snow_create_catalog_variable は、いずれもマップにも再エクスポートにも含まれていませんでした)。逆に、snow_comprehensive_search は呼び出せるのにマニフェストにはありませんでした。これは serac-labs/serac#307 で修正済みです。再発した場合は、packages/servicenow-mcp/src/__tests__/registry-manifest-parity.test.ts がどちらの方向の不一致でも失敗します。
つまり、tools.json に名前があれば、そのツールを呼び出せます。ツールが次のように応答する場合:
{
"success": false,
"error": "Tool not found: snow_something",
"suggestion": "Use tool_search to find available tools"
}
名前が間違っているのであって、存在しないわけではありません。再検索するのではなく、tools.json と照合してください。
ただし、マニフェストに記載されていても呼び出すべきではない項目が 1 つあります。"deprecated": true と記され、説明の冒頭が [DEPRECATED - use <replacement>] となっている項目です。snow_comprehensive_search がその一例です。これは後方互換性のための snow_search_artifacts のエイリアスです。説明に記載された置き換え先を使用してください。
説明と実際の動作が異なる環境変数が2つあります
SNOW_LAZY_TOOLS=falseは、起動時にカタログ全体を読み込むと説明されています。しかし、stdio ではそうなりません。 トランスポートはこの変数にかかわらず、すべてのツールを遅延読み込みとしてマークしてインデックスを構築するため、tools/listが返すのはtool_searchとtool_executeだけです。起動ログには異なる内容が表示されます。 どちらの場合も、tool_searchでツールを検索してください。SNOW_TOOL_DOMAINS=cmdb,operationsがフィルタリングするのはtools/listだけです。tool_executeはこの変数を 参照しないため、除外されたドメインのツールでも有効化されていれば実行できます。制限ではなく、表示フィルターとして扱ってください。
エンタープライズ連携は別のサーバーです
jira_*、azdo_*、confluence_*、github_*、gitlab_* は実在しますが、このサーバーにはありません。このサーバーのレジストリにあるすべてのツール名は
snow_ で始まります。例外は tool_search と tool_execute ですが、これらはレジストリのツールではなく、レジストリに付属する2つのメタツールです。連携機能は
別のバイナリである
servicenow-mcp-enterprise-proxy の背後で動作し、Serac ライセンスサーバーからカタログを取得して、独自のメタツールのペアである
enterprise_tool_search と enterprise_tool_execute を公開します。名前の先頭に正確に別のプレフィックスを付けることで、このサーバーの2つのメタツールと衝突しないようにしています。
そのため、tool_search({ query: "jira" }) は、存在しないツールを探す呼び出しではなく、誤った呼び出しです。このサーバーでは、
snow_create_oauth_profile と snow_install_spoke が返されます。ツール一覧に enterprise_tool_search がなければ、このセッションではそのサーバーが設定されていません。プラグインの .mcp.json が起動するのは
servicenow-mcp-stdio だけであり、どのようなクエリを指定しても、エンタープライズ側のツールには到達しません。
検索中は何も言わないでください
検索について説明しないでください。「まずツールを有効にします」や「適切なツールを探しています」とは言わず、検索し、有効化し、呼び出して、結果を報告してください。呼び出しに失敗した場合は、別の用語で再検索し、何も言わずに続けてください。
問題がツールの検索ではない場合
ツールの解決と有効化はできるのに、すべての呼び出しが失敗する場合(401、JSON であるべき箇所に HTML が返る、「有効な JSON ではありません」など)は、検索を中止して snow_diagnose_setup を呼び出してください。使用された認証情報の取得元、インスタンスが起動しているかどうか、OAuth の交換に成功するかどうかを報告します。休止状態の開発者インスタンスは HTML のログインページを返すため、すべてのツールで解析エラーが発生しているように見えます。
| 症状 | 原因 |
|---|---|
すべての結果が [DEFERRED] で、有効化できない | セッション ID がありません — SNOW_SESSION_ID を設定してください |
Tool "x" is [DEFERRED] and must be enabled first | このセッションで有効化されていません。まず tool_search で検索してください |
ドキュメント検索が成功した後に Tool not found: x と表示される | 公開済みですが、登録されていません — serac-labs/serac#307 を参照してください |
No tools found matching "sys_..." | テーブル名で検索しています — 代わりに操作を検索してください |
| 有効化したツールがクライアントのツール一覧に表示されない | listChanged 通知がありません — tool_execute を使用してください |
success: true なのにインスタンスに何も反映されない | result.success を確認してください。それも true の場合は、アーティファクトをそれ自体のテーブルで再クエリしてください — ツールがスタブか sys_script_execution のエコーである可能性があります |
| HTTP ではツールに拒否されるが、ローカルでは動作する | トランスポートの許可リスト — そのツールはローカルファイルシステムにアクセスします |