ローカル モデルで SQL MCP Server を使用する

Important

SQL モデル コンテキスト プロトコル (MCP) サーバーは、Data API Builder バージョン 1.7 以降で使用できます。 最新の機能とバグ修正については、最新の 2.0 リリースを使用してください。

SQL モデル コンテキスト プロトコル (MCP) サーバーは、クラウドでホストされる AI サービスだけでなく、MCP と互換性のあるクライアントでも動作します。 医療、防衛、金融、エネルギー、海事業界でよく見られるクラウド 大規模言語モデル (LLM) アクセスが環境によって制限されている場合は、 Ollama または同様のツールを介して提供されるローカル モデルを接続できます。 このガイドでは、小規模なローカル モデルの信頼性を高めるセットアップ、フィールド メタデータの構成、プロンプト パターンについて説明します。

Prerequisites

  • Data API Builder CLI がインストールされ、少なくとも 1 つのエンティティで構成されている。 CLI をインストールします
  • ツール呼び出し (qwen3:8bなど) をサポートするモデルを使用する llama3.1:8b
  • Python 3.10+mcp および ollama パッケージを使用します。
  • データを含む実行中のSQL Server インスタンス。

手順 1: フィールド メタデータを構成する

フィールド メタデータは、ローカル モデルの精度にとって最も重要な構成手順です。 フィールド名と説明がない場合、エージェントではエンティティ名のみが表示され、列名が正しく推測されません。

警告

この手順をスキップすると、技術的には機能するが、ツールの応答を読み取るモデルでは機能的に使用できない MCP サーバーが生成されます。 モデルにはあなたの列に関する情報がありません。

説明を含むエンティティを追加し、制約付き列の有効な値を含むフィールドの説明を追加します。

dab add ServerInventory \
  --source dbo.ServerInventory \
  --permissions "anonymous:read" \
  --description "SQL Server instance inventory with version, environment, and sizing data"

dab update ServerInventory \
  --fields.name InstanceName --fields.primary-key true \
  --fields.description "SQL Server instance name (e.g., YOURSERVER01)"

dab update ServerInventory \
  --fields.name Environment \
  --fields.description "Deployment environment. Valid values: Prod, Dev, Test, UAT"

完全な CLI リファレンスとベスト プラクティス (制約付き値、パラメーターの説明、スクリプト パターンなど) については、「 エンティティに説明を追加する」を参照してください。

Note

dab update CLI は、コンマを引数区切り記号として扱います。 説明にコンマが含まれている場合は、代わりに dab-config.json を直接編集します。

手順 2: SQL MCP サーバーを起動する

dab start

SQL MCP Server は、既定でストリーミング可能な HTTP トランスポートを使用して http://localhost:5000/mcp をリッスンします。 MCP プロトコルを実装するすべてのクライアントは、このエンドポイントに接続できます。

手順 3: ローカル モデルを接続する

Ollama モデルを SQL MCP Server に接続する MCP クライアントを構築します。 次のPython例では、MCP Python SDK および ollama パッケージを使用します。

依存関係のインストール

pip install mcp ollama

最小限のPythonハーネス

import asyncio
import json
from mcp import ClientSession
from mcp.client.streamable_http import streamable_http_client
import ollama

MCP_URL = "http://localhost:5000/mcp"
MODEL = "qwen3:8b"

async def get_schema(session: ClientSession) -> str:
    """Call describe_entities and format results for the system prompt."""
    result = await session.call_tool("describe_entities", arguments={})
    entities = json.loads(result.content[0].text)
    lines = []
    for entity in entities.get("entities", []):
        fields = ", ".join(
            f"{f['name']} ({f.get('description', 'no description')})"
            for f in entity.get("fields", [])
        )
        lines.append(f"- {entity['name']}: {entity.get('description', '')}")
        if fields:
            lines.append(f"  Fields: {fields}")
    return "\n".join(lines)

async def run(user_question: str):
    async with streamable_http_client(MCP_URL) as (read, write, _):
        async with ClientSession(read, write) as session:
            await session.initialize()

            # Preinject schema into the system prompt
            schema_text = await get_schema(session)
            system_prompt = f"""You query a SQL database through MCP tools.

Available entities:
{schema_text}

Rules:
- Use the exact field names shown above.
- Answer count questions with the count only.
- Do not produce summaries unless asked.
- Do not invent example data. Only return data from tool responses.
- If no results, say "No results found" and stop.
"""
            # Get available tools for Ollama
            tools_result = await session.list_tools()
            ollama_tools = [
                {
                    "type": "function",
                    "function": {
                        "name": t.name,
                        "description": t.description or "",
                        "parameters": t.inputSchema,
                    },
                }
                for t in tools_result.tools
            ]

            messages = [
                {"role": "system", "content": system_prompt},
                {"role": "user", "content": user_question},
            ]

            # Chat loop: let the model call tools until it produces a final answer
            while True:
                response = ollama.chat(
                    model=MODEL, messages=messages, tools=ollama_tools
                )
                msg = response["message"]
                messages.append(msg)

                if not msg.get("tool_calls"):
                    print(msg["content"])
                    break

                for tc in msg["tool_calls"]:
                    result = await session.call_tool(
                        tc["function"]["name"],
                        arguments=tc["function"]["arguments"],
                    )
                    messages.append(
                        {
                            "role": "tool",
                            "content": result.content[0].text,
                        }
                    )

asyncio.run(run("How many SQL 2019 servers are in production?"))

このハーネスは、スキーマの事前設定、ツール検出、マルチターン ツール呼び出し、最終回答抽出の完全なサイクルを処理します。 環境に合わせて MODELMCP_URL を調整します。

起動時にスキーマを事前に指定する

小規模なローカル モデル (14B パラメーター未満) では、会話が開始される前にスキーマ メタデータがシステム プロンプトにある場合に、より信頼性の高いツール呼び出しが生成されます。 モデルに依存して会話中に describe_entities を単独で呼び出す代わりに、ハーネスの起動時に呼び出して結果を挿入します。

プレインジェクションが重要な理由

Approach 小さなモデルでの動作
動的発見 モデルは、最初に describe_entities を呼び出し、結果を解釈してから、正しいフィールド名で適切なツールを呼び出す必要があります。 複数の障害発生箇所。
事前注入 モデルでは、エンティティ名、フィールド名、および説明がすぐに表示されます。 最初の試行でツール呼び出しを修正します。

前のセクションのハーネスの例では、このパターンを示します。 get_schema()関数は起動時に 1 回describe_entities呼び出し、結果をシステム プロンプトに書式設定します。

Tip

大規模なクラウド モデル (GPT-4o、Claude) は、通常、事前入力なしで会話中にスキーマを検出します。 このパターンは、14B パラメーターのモデルにとって最も重要です。

モデルの応答を制約する

モデルは、正しいツール呼び出しを行い、適切なデータを取得し、それでも間違った回答を生成できます。 たとえば、モデルが "運用サーバーの数" を確認すると、16 行が正しく取得される可能性があります。その後、 16数ではなく、幻覚的な例を含む 40 行のエグゼクティブサマリーで応答します。

システム プロンプトに明示的な否定規則を追加します。

Rules:
- Answer count questions with the count only.
- Do not produce summaries unless the user asks for one.
- Do not invent example data. Only return data from tool responses.
- If a tool returns no results, say "No results found" and stop.

ツール呼び出しの忠実性と回答の規範は異なる問題です。 DAB は、ツール レイヤーを介して正確なデータ取得を保証します。 プロンプト ハーネスは、モデルが結果を表示する方法を制御します。

Considerations

トピック 詳細情報
ハードウェア ツールの呼び出しは、控えめなハードウェアで動作します。 コンシューマー Nvidia GPU (8 GB ビデオ RAM) 上の 8B パラメーター モデルは、有用な結果を生成します。 バッチ ワークロードに適した、質問ごとに数十秒の待機時間が予想されます。
Batch と対話型 小規模なモデルは、待機時間の許容度が高いバッチ処理 (パフォーマンス レポート、インベントリ クエリ) に適しています。
ツールの可用性 aggregate_records ツールは、バージョン 2.0 以降でのみ使用できます。 バージョン 1.7.x では、カウントクエリと集計クエリにより、モデルは一致するすべての行を強制的に読み取ります。 バージョン別のツールの可用性を参照してください。
輸送 ローカル モデルは、ストリーミング可能な HTTP 経由で /mcpに接続します。 標準入出力 (stdio) トランスポートは、単一プロセスセットアップの代替手段です。
認証 ローカル開発では、 anonymous アクセス許可を使用します。 運用環境では、環境に適した 認証 を構成します。