目次

  1. なぜスキーマ設計がMCPサーバーの品質を支配するのか
  2. 原則1: 命名は動詞+目的語、サーバー内で命名規則を統一
  3. 原則2: descriptionは『何を』+『いつ使うか』を200〜400文字で
  4. 原則3: inputSchemaは可能な限りフラットに
  5. 原則4: tool annotationsで挙動を宣言する
  6. 原則5: エラーは result 内に返す、protocol error にしない
  7. 原則6: 巨大ペイロードはURIで返す、result本体に埋め込まない
  8. 原則7: 入力バリデーションと境界での検証を必ず実装
  9. 本番デプロイ前チェックリスト
  10. FAQ

なぜスキーマ設計がMCPサーバーの品質を支配するのか

2026年に入って、MCPサーバーの実装品質は『機能の多さ』ではなく『ツールスキーマ設計の精度』で評価されるようになった。理由はシンプルで、エージェントから見ると ツール定義そのものがプロンプトの一部としてコンテキストに常駐するからだ。

Anthropicのエンジニアリングブログは2026年に 「最適化前のツール定義は134Kトークンを消費していた」と公開し、MCP Tool Search(lazy loading機構)導入後は約5Kトークン、約85%削減を達成したことを示した。MindStudio等の業界調査も「ツール定義1個あたり通常100〜500トークン、5サーバー58ツール構成で55K、Jira単体で約17K」というデータを公表している。スキーマ設計を間違えると、エージェントの会話開始前から100K以上のトークンを焼くサーバーが完成する

スキーマ品質の3つの効果

(1) トークン消費の削減 — verbose descriptionは大幅に高コスト。
(2) tool selection精度の向上 — Anthropic engineering blogでは『tool selection精度43%→14%』のようにスキーマ品質低下で精度が大きく劣化する事例が報告されている。
(3) ホストアプリでの自動承認/手動承認の最適化 — annotationsを付けないとClaude Connector Directoryで30%のrejection原因になる。

原則1: 命名は動詞+目的語、サーバー内で命名規則を統一

MCP公式仕様はnameの命名規則を明示的に強制していないが、業界ベストプラクティスは『snake_case または camelCase で、動詞+目的語』に集約されている。LLMから見ると、動詞先頭の命名は『何をするツールか』の判定を高速化する。

最も重要なのは『サーバー内で命名規則を統一する』こと。同一サーバーで database_querycreateInvoice が混在していると、LLMが暗黙にカテゴリ分けしてしまい、tool selection精度が落ちる。

// ✅ 良い例(snake_case で統一、動詞+目的語)
{
  "name": "search_customers",
  "name": "create_invoice",
  "name": "send_email"
}

// ❌ 悪い例(命名規則がバラバラ、動詞抜け)
{
  "name": "customers",        // 動詞がない
  "name": "InvoiceCreate",    // PascalCase + 語順逆
  "name": "send-email-v2"     // kebab-case + version suffix
}

原則2: descriptionは『何を』+『いつ使うか』を200〜400文字で

descriptionは『機能の説明』だけでなく『いつそのツールを使うべきか』を必ず含める必要がある。LLMはdescriptionからtool selectionを行うため、機能だけ書かれた「APIで顧客一覧を返します」のようなdescriptionでは、似た機能の別ツールと混同される。

長さの目安は1〜3文・200〜400文字。verbose multi-paragraph description はトークン削減ボトルネックの最大要因と認識されている。凝縮する4要素:

// ✅ 良いdescription(4要素を凝縮)
"description": "顧客一覧を検索する。query/limit/offsetをサポート。
              最大100件返却、ページング必須。
              個別顧客の詳細はget_customer_byIdを使うこと。
              新規作成や更新には使えない(read-only)。"

// ❌ 悪いdescription(機能だけ、verbose)
"description": "This tool returns a list of customers from our
              comprehensive customer database management system,
              which has been built with industry-leading technology...
              (200文字以上続く一般論)"

原則3: inputSchemaは可能な限りフラットに

JSON Schemaは深いネストと複雑なバリデーションロジックをサポートするが、MCPツールのinputSchemaでは『可能な限りフラットに』が原則。深くネストするほど(1) トークン数が増え、(2) LLMの認知負荷が増え、(3) パース失敗の確率が上がる。

複雑なオブジェクト階層が必要な場合の選択肢は2つ:

// ❌ 悪い例(深いネスト、トップレベルで複雑なobject)
{
  "type": "object",
  "properties": {
    "filters": {
      "type": "object",
      "properties": {
        "date_range": {
          "type": "object",
          "properties": {
            "start": { "type": "string" },
            "end": { "type": "string" }
          }
        },
        "tags": { "type": "array", "items": {...} }
      }
    }
  }
}

// ✅ 良い例(フラット、必須/任意が明確)
{
  "type": "object",
  "properties": {
    "start_date": { "type": "string", "format": "date" },
    "end_date":   { "type": "string", "format": "date" },
    "tags":       { "type": "array", "items": { "type": "string" } }
  },
  "required": ["start_date", "end_date"]
}

原則4: tool annotationsで挙動を宣言する

2025年に追加され2026年に標準化された tool annotations は、ツールの挙動を宣言するメタデータだ。サブ仕様としては readOnlyHint / destructiveHint / idempotentHint / openWorldHint の4種があり、これらの欠落がClaude Connector Directory rejectionの30%を占めるという公表データもある。

Annotation デフォルト true にすべきツール 用途
readOnlyHintfalsesearch / get / list / fetch系状態を変更しない読み取り専用
destructiveHinttruecreate / update / delete / send系取り消し困難な操作
idempotentHintfalse同じ入力で結果が変わらない操作リトライ安全性の宣言
openWorldHinttrue外部リソース(API/DB/ネット)へ届く全ツール外部影響範囲の宣言
// 検索ツール(read-only)
{
  "name": "search_customers",
  "description": "...",
  "inputSchema": {...},
  "annotations": {
    "readOnlyHint": true,
    "destructiveHint": false,
    "idempotentHint": true,
    "openWorldHint": true
  }
}

// 削除ツール(destructive)
{
  "name": "delete_invoice",
  "annotations": {
    "readOnlyHint": false,
    "destructiveHint": true,
    "idempotentHint": false,
    "openWorldHint": true
  }
}
⚠️ annotationsはhint(契約ではない)

annotationsは情報的シグナルであって強制可能な保証ではない。「このツールはこう動くと主張している」を伝えるだけで、システム側が動作を保証するわけではない。MCPがcontract(契約)ではなくhint(ヒント)を選んだのは、信頼できないサーバーをまたいで契約を強制することが現実的でないため。クライアント側は依然として独自の安全チェックを実装すべき。

注意点: 「検索」を名乗るツールでも、検索クエリを分析用DBに書き込んでいるならreadOnlyHint:trueにしてはいけない。主目的が読み取りでも、副作用で書き込みが発生するなら read-only ではない。同様にdestructiveは「データ削除」だけでなく、ファイル上書き・トークン無効化・issue close など『簡単に取り消せない操作』全般を指す。

原則5: エラーは result 内に返す、protocol error にしない

MCPのエラー設計には大きな落とし穴がある。ツール実行のエラーは、MCPプロトコルレベルのエラー(JSON-RPC errorフィールド)ではなく、result オブジェクト内に isError: true + メッセージで返すのがベストプラクティスだ。

理由は明確で、protocol errorとして返すとLLMはエラー内容を見られず、何が起きたか判断できない。result内のエラーとして返せば、LLMは『どんな失敗だったか』を読み、リカバリーを試みられる。

// ❌ 悪い例(protocol error として返却)
// LLMはこのエラー内容を見られないため、ただ「失敗した」しか分からない
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": { "code": -32603, "message": "Database connection failed" }
}

// ✅ 良い例(result内に isError + 構造化メッセージ)
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "isError": true,
    "content": [{
      "type": "text",
      "text": "Database connection failed. Retry-After: 5 seconds.
              This is a transient error - the agent should retry
              with exponential backoff (recommend 3 attempts)."
    }]
  }
}

原則6: 巨大ペイロードはURIで返す、result本体に埋め込まない

2026年のベストプラクティスとして強調されているのが、『巨大ペイロードはhandle/URIを返し、result本体にメガバイト級のデータを inline しない』というルール。理由は明確で、大量データをinlineするとそのままLLMのコンテキストに流れ込み、トークンを焼く。

典型パターン: ファイル取得・ログ取得・データセットクエリ。これらは件数が増えると一気にレスポンスが膨れる。MCP仕様にはResourcesという仕組みがあり、URIで参照させて必要な時だけ別途取得させる構造を作れる。

// ❌ 悪い例(10万行のログをそのままinline)
{
  "result": {
    "content": [{
      "type": "text",
      "text": "[2026-05-19 00:00] log line 1...
              ... (10万行続く、数MB) ..."
    }]
  }
}

// ✅ 良い例(URIで返し、必要に応じてresourceとして取得)
{
  "result": {
    "content": [{
      "type": "resource",
      "resource": {
        "uri": "logs://2026-05-19/full",
        "mimeType": "text/plain",
        "description": "100K log lines (5.2MB). Use read_resource to fetch."
      }
    }]
  }
}

原則7: 入力バリデーションと境界での検証を必ず実装

JSON Schemaでバリデーションを宣言するだけでは不十分で、サーバー側で必ず実装レベルの検証を行う必要がある。エージェントは時々スキーマを無視した呼び出しをしてくるし、悪意のあるユーザーがエージェント経由で不正入力を送ることもある。

必須の検証項目:

本番デプロイ前チェックリスト

新規MCPサーバーまたは大規模ツールアップデート前に必ず確認するチェック項目:

あなたのMCPサーバーをAEO格付けしませんか?

KanseiLinkはMCPサーバーのスキーマ品質・成功率・レイテンシを自動評価し、AEO格付け(AAA〜D)としてエージェントに公開します。225+のSaaSと並んで、貴社のMCPサーバーもエージェントから発見されやすくなります。

AEO格付けを相談する

FAQ

MCPツール定義1つあたり、何トークン使われるのですか?

通常100〜500トークン、description次第で大きく振れます。10ツールの中堅サーバーで会話開始前から1,500〜3,000トークン消費、5サーバー58ツールで約55K、Jira単体で約17Kに達した実例があります。Anthropic engineering blogは『最適化前のツール定義は134Kトークン消費していた』を公表しています。

name は snake_case と camelCase どちらを使うべきですか?

MCP公式仕様はどちらも禁止していません。業界標準は『動詞+目的語』『サーバー内で統一』。同一サーバーで命名規則が混在するとtool selection精度が落ちるため、どちらを選ぶかよりも『統一すること』が重要です。

description はどれくらい詳しく書けばいいですか?

『何をするか』だけでなく『いつ使うべきか』を必ず含め、1〜3文・200〜400文字を目安にします。動作・入力前提・出力期待・使い分け判断の4要素を凝縮するのが2026年のスイートスポット。verbose multi-paragraph はトークン削減のボトルネック最大要因です。

tool annotations を付けないとどうなりますか?

Claude Connector Directoryの申請rejection の30%が annotation 欠落を理由としていると公表されています。annotations なしだとクライアント側のリスク判定が効かず、(1)読み取り専用ツールが余計な確認ダイアログを出す、(2)破壊的ツールが警告なく実行される、(3)自動承認の最適化が効かない、といった問題が起きます。

エラー返却は protocol error と result の isError どちらを使うべきですか?

ツール実行エラーは result 内に isError:true + 構造化メッセージで返します。protocol error にするとLLMはエラー内容を読めず、リカバリーを試みられません。result 内エラーであればLLMは『どんな失敗だったか』を読んでリトライ判断ができます。

データ開示・免責事項

本記事のトークン数値はAnthropic engineering blog (anthropic.com/engineering/code-execution-with-mcp、anthropic.com/engineering/advanced-tool-use)、MindStudio記事 "Claude Code MCP Servers and Token Overhead"、Webfuse "MCP Cheat Sheet (2026)"、techbuddies.io "How Claude Code's New MCP Tool Search Slashes Context Bloat" 等の公開情報に基づきます。tool annotationsの仕様と『rejection 30%がannotation欠落』はMCP公式ブログ (blog.modelcontextprotocol.io/posts/2026-03-16-tool-annotations/) およびsunpeak.ai "Claude Connector Directory Submission" を参照。スキーマ設計原則は modelcontextprotocol.info公式ドキュメント、thenewstack.io "15 Best Practices for Building MCP Servers in Production"、apxml.com "Tool Definition Schema" 等から統合しました。サンプルコードは説明用の最小例で、実装時は対象言語のSDK公式仕様を必ず確認してください。