🦐

Microsoft Docs の MCP サーバーに接続してみた(Python・PowerShell)

に公開

この記事のゴール
ローカルから Microsoft Docs(Learn)の MCP サーバー に接続し、公式ドキュメント検索(microsoft_docs_search)を叩いて タイトル/URL/抜粋 を取得できるようにする。
※ サーバーを自前で起動するのではなく、公開されている MCP エンドポイントに接続して使います。


1. 概要

  • MCP (Model Context Protocol) はツールやデータを LLM に標準的に渡すためのプロトコルです。
  • Microsoft は Learn Docs 検索用に MCP サーバーを公開しています(Streamable HTTP)。
  • エンドポイント:https://learn.microsoft.com/api/mcp
  • 提供ツール:microsoft_docs_search(入力キーは question

本記事では Python + PowerShell(Windows) 前提で動かす手順をまとめます。


2. 前提(環境)

  • Windows 11
  • Python 3.9+(py -3 --version で確認)
  • PowerShell(標準でOK)

以降は C:\Users\<あなた>\Desktop\MCP_MSdocs\learn-mcp-client を作業フォルダとして進めます。
パスは適宜読み替えてください。


3. セットアップ(仮想環境 + ライブラリ)

# フォルダ作成(作成済みのものを使用してもOKです)
mkdir $HOME\Desktop\MCP_MSdocs\learn-mcp-client
cd $HOME\Desktop\MCP_MSdocs\learn-mcp-client

# 仮想環境を作成&有効化
py -3 -m venv .venv
.\.venv\Scripts\Activate.ps1

# 依存を導入(MCP公式SDKのCLI含む)
python -m pip install --upgrade pip
pip install "mcp[cli]"

PowerShell で有効化できない場合は、最初に一度だけ:

Set-ExecutionPolicy -Scope CurrentUser RemoteSigned

4. サンプルクライアント(main.py

やること

  1. サーバーへ接続 → 2) ツール一覧取得 → 3) microsoft_docs_searchquestion で呼ぶ → 4) 結果表示

main.py を作成して以下を貼り付けます。

import asyncio, argparse, json
from typing import Any, Dict, List
from mcp import ClientSession
from mcp.client.streamable_http import streamablehttp_client

LEARN_MCP_URL = "https://learn.microsoft.com/api/mcp"

def extract_items_from_content(parts) -> List[Dict[str, Any]]:
    """CallToolResult.content(パーツ配列)から結果リストを抽出。"""
    items: List[Dict[str, Any]] = []
    for part in parts or []:
        ptype = getattr(part, "type", None)
        payload = None
        if ptype in {"json", "object"}:
            payload = getattr(part, "content", None)
        elif ptype in {"text", "output_text", "string"}:
            text = getattr(part, "text", None) or getattr(part, "content", None)
            if isinstance(text, str):
                try:
                    payload = json.loads(text)
                except Exception:
                    payload = None
        if isinstance(payload, list):
            items += [x for x in payload if isinstance(x, dict)]
        elif isinstance(payload, dict):
            items.append(payload)

    # Microsoft Learn のキー名合わせ(contentUrl → url)
    for it in items:
        if "url" not in it and "contentUrl" in it:
            it["url"] = it["contentUrl"]
    return items

async def run(query: str, top_k: int):
    async with streamablehttp_client(LEARN_MCP_URL) as (read, write, _):
        async with ClientSession(read, write) as session:
            await session.initialize()

            # ツール検出(将来の変更に強くする)
            tools = await session.list_tools()
            tool = next(t for t in tools.tools if t.name == "microsoft_docs_search")

            # Learn MCP の入力名は "question"
            res = await session.call_tool("microsoft_docs_search", {"question": query})

            items = extract_items_from_content(getattr(res, "content", None))[:top_k]
            if not items:
                print("No results.")
                return

            for i, it in enumerate(items, 1):
                title = it.get("title", "")
                url = it.get("url", "")
                excerpt = it.get("content") or it.get("excerpt") or it.get("summary") or ""
                print(f"\n[{i}] {title}\n{url}\n{str(excerpt)[:200]}...")

if __name__ == "__main__":
    p = argparse.ArgumentParser()
    p.add_argument("--q", required=True, help="search query")
    p.add_argument("--top-k", type=int, default=5)
    a = p.parse_args()
    asyncio.run(run(a.q, a.top_k))

5. 実行

# すでに (.venv) が付いている=仮想環境が有効な状態で
python .\main.py --q "Azure App Service overview" --top-k 5

想定出力(例):

[1] App Service overview
https://learn.microsoft.com/en-us/azure/app-service/overview
Azure App Service is a platform that lets you run web applications, ...

[2] Reliability in Azure App Service
https://learn.microsoft.com/en-us/azure/reliability/reliability-app-service
...

日本語ページについて
Learn MCP の検索は英語優先です。URL の /en-us//ja-jp/ に置き換えると日本語版に切り替わる場合があります(存在しないページもあります)。


6. 便利ワザ

6.1 Markdown に保存(参考文献リストに)

python .\main.py --q "App Service overview" --top-k 5 > results.md

6.2 1件目を自動でブラウザ起動(オプションを追加)

# 先頭付近に追加
import webbrowser

# 引数に追加
p.add_argument("--open", type=int, default=0, help="open Nth result in browser")

# 出力直前に追加
if a.open and 1 <= a.open <= len(items):
    webbrowser.open(items[a.open - 1].get("url", ""))

実行例:

python .\main.py --q "App Service overview" --top-k 5 --open 1

7. トラブルシュート

症状 対処
ModuleNotFoundError: No module named 'mcp' .venv を有効化 → pip install "mcp[cli]" をやり直し
can't open file '...\main.py': [Errno 2] 実行場所と main.py の場所が一致していない。cd とパスを再確認
structuredContent が無い 返却は res.content(パーツ配列)。本記事の実装を使用する
ブラウザでエンドポイント叩くと 405 仕様どおり。MCP クライアントからのみ利用可能
日本語が出ない 検索は英語優先。URL の /en-us//ja-jp/ 置換で日本語版へ(無いページもあり)

8. 参考メモ

  • Learn MCP は Streamable HTTP で公開。クライアントは mcp.client.streamable_http.streamablehttp_client を使用。
  • 毎回 list_tools() でツール・スキーマを検出してから call_tool() する実装が安全。
  • microsoft_docs_search の入力キーは question

9. まとめ

  • ローカルで Python を用意し、mcp[cli] を入れて 公開 Learn MCP に接続すれば、公式ドキュメントのタイトル/URL/抜粋を素早く取得できます。
  • そのまま 参考文献リストの生成や、一括収集スクリプトに発展可能です。

次回はFastMCPを使ってMCPサーバーを作成してみようと思います
改善点・誤りなどあれば、コメントで教えていただけると嬉しいです!

ヘッドウォータース

Discussion