mcp-demo-aad-viz
mcp-demo-aad-viz
通常は単独で紹介されることが多い2つのMCP機能を組み合わせた実用的な例です。組み合わせるとはるかに興味深いものになります。
Microsoft Entra ID (Azure AD) 認可 — サーバーはOAuth 2.1リソースサーバーです。Entraグループでのメンバーシップが、あなたに存在するデータセットを決定します。「一覧には出るが拒否される」のではなく、そもそも存在しないのです。
インラインアプリ / エクステンション (
io.modelcontextprotocol/ui) — チャートは会話内でレンダリングされるインタラクティブなウィジェットとして届き、それを調整のコストはゼロトークンでsu.
この2つを組みわせた、見る価値のあるもができあがります。Entraグループが許したデータセットだけがドロップダウンに表示されされるAltairチャートビルダーを、ウィジェットとのやりとりのすべての操作でサーバ側が強制します。
MCP 20026-07-28 を対象に、Pyton SDK mcp 2.0 で構築。Azure Container Apps にデプロイします。MITラรู้センスです。
注記: これは実演です。製品ではありません。認可のストーリーが伝わりやすいように、公開サンプルデータセット10件と、意図的にシンプルなティアモデルを同梱しています。

Azure無しで試す
テナント不要、認証不要、デプロイ不要 — ウィジェットの動作を確認するには十分です:
uv sync && uv run python scripts/fetch_datasets.pyMCP_DATAVIZ_AUTH_ENABLED=false MCP_DATAVIZ_PORT=3001 uv run python -m mcp_datavizすべての呼び出しが3つのデータセットテイアLevelを保有するものとして扱われます。任意の MCP Apps ホストを http://localhost:3001/mcp に向けてください — 実際に行われている ui/ プロトコルを全部見ることができるブラウザベースのホストは ローカル開発 を参照してください。
Related MCP server: Vela MCP Server
Azureで試す
# 1. Directory objects (app registration, scopes, app roles, 3 groups)
./scripts/entra-setup.sh# 2. Put yourself in a group to pick a persona
source entra.env
az ad group member add --group "$MCP_DATAVIZ_GROUP_ANALYSTS_ID" \
--member-id "$(az ad signed-in-user show --query id -o tsv)"# 3. Deploy (builds the image in Azure; no local Docker needed)
./scripts/deploy.sh --tag v1スクリプトがMCPエンドポイントを出力します。表示されたとおりにそのままクライアントに追加してください — /mcp パスはOAuthリソース識別子の一部です → docs/CONNECT.md。
デプロイのたびに固有の
--tagを渡してください。同じタグを繰り返すと Bicep テンプレートが現在配備中のものとバイト単位で同一になり、新しいレビジョンが作られず、何も導入されないのにデプロイが成功と表示されます。
デモししていること
MCP 機能 | 場所 | 見えるもの |
Authorization (OAuth 2.1 RS) | グループのメンバーシップでカタログが変える | |
MCP Apps ( | ドロップダウンでチャートが再描画される | |
アプリ専用ツール ( |
| ウィジェットの再描画はゼロトークン |
|
| ウィジェット非対応ホストはその代わりにフォームが出る |
スコープステップアップ ( |
| 最初のエクスポートで再同意が必要になる |
リソースとテンプレート |
| 権限でフィルタリングされる |
補完 | データセットの引数 | 開けないデータセットが補完候補に表示されない |
プロンプト |
| ガイド付きの最初のパス |
このリビジョンで仕様が非推奨にした2つのこと、つまり sampling と logging ケーパビリティ (SEP-2577) は、このサーバーでは避けています。suggest_chart はモデルに聞くのではなく、カラムの型からマークを選びます。
ルールのモデル
独立した2つの軸です。この2つを混同するのがよくあるミスです。
WHO YOU ARE WHAT YOU'RE DOING
Entra group ──► app role ──► dataset tier OAuth scope ──► operation
(roles claim) (scp claim)
analysts → Open ( 4) Datasets.Read → everything
engineers → Open + Operations ( 7) Datasets.Export → export_chart
scientists → Open + Confidential ( 7) ↑ withheld at first, so the
...a *different* 7 first export triggers a step-up
(no group) → nothing ( 0)ティア | ロール | データセット |
open |
| iris, penguins, cars, barley |
operations |
| seattle-weather, us-employment, gapminder |
confidential |
| diamonds, movies, titanic |
エンジニアとサイエンティストは等しい*数のデータセットを持ってしていますが、そのデータは同じではありません。だから、二人の同僚が同じ質問しても、別の答えになる.
./scripts/assign-persona.sh engineer colleague@example.com --now--now はロールをユーザーに直接割り当てます。グループの変更が新しいトークンに反映されるまでEntraでは数分かかる場合がありますが、直接割り当ては約20秒ですでいます。
ルールはハード拒否です。自分をグループに入れるように要求することはできません。自分のティア外のデータセットは tools/list の結果、resources/list、補完候補、ウィジェットのドロップダウンから存在しません — ありますが拒否されるのではありません。
スコープはソフト拒否です。Datasets.Export が欠けている場合、403 に WWW-Authenticate: Bearer error="insufficient_scope" のチャレンジを返し、クライアントはそれを求めて再認可します。
このリポジトリが回避しているEntra特有の問題が2つあります。どちらも手動で設定すると不可解なエラーになります。Entra には ダイナミッククライアント登録 がなく、RFC 8414 のメタデータエンドポイントも存在しません。また、MCP URL は 必ず Application ID URI として登録しなければならず、そうしないとRFC 8707 の resource= が AADSTS9010010 で失敗します。
詳細は docs/AUTHZ.md と docs/CONNECT.md を参照してください。
ウィジェットが面白い理由
インンデータを持つ Vega-Lite スペックは30〜300KBです。これを単純にツールから返すと、チャートのたびにモデルのコンテキストに入ってしまいます。
代わりに:
plot_datasetは約900バイトのハンドルを返します。エンコーディング、行数、警告のみです。スペックはありません。ホストは
ui://アプリをレンダリングし、そのハンドルを渡します。ウィジェットは
render_chart(アプリ専用ツール) を呼び、実際のスペックを取得します。
ステップ3はモデルではなくアプリから発生するため、スペックが会話に入ることは決してありません。ドロップダウンを変えるには、サーバーへの小さなラウンドトリップ1回でトークンは0です。
ルールのストーもここでも成立します。render_chart と app_catalog があるのは、呼び出しが行われるたびに呼び出し元のティアを再導出するからです。モデルがもう登場しなくても、ウィジェットはトークンで許可されていないデータセットに到達することができません。
設計メモ: docs/DESIGN.md。
ローカル開発
「ウィジェットのHTML / JSはでいるか?」と「MCPサーフェスは足りてあるか?」の、2つの異なする質問に対する2つのテスト・ベッドです。
「ウィジェットのHTML/JSは正しい?」 — リアルな ui/ postMessage プロトコルを話す小型ホスト、すべてのメッセージをロギング、MCPクライアントは介しません:
uv run python scripts/preview_widget.py # http://127.0.0.1:8765実際のホストが適用するのと同じ制限的CSPを注入するので、CSPフェイラがそこでも再現します。制作だけではありません。--strip-structured-content は、doc/HOST-COMPATIBILITY.md に記さたホストの欠陥を模倣します。
「MCPのサーフェスは正しい?」 — MCP Appsリポジトリのレフアレ?ンス・ホストで実サーバーをHTTTPを介して動かすというもの。
git clone https://github.com/modelcontextprotocol/ext-apps.git
cd ext-apps && npm install && cd examples/basic-host
SERVERS='["http://localhost:3001/mcp"]' npm start # http://localhost:8080これが最初に使う価値あるハーネす。出荷ホストが黙って飲み込むプトコル違反を報告してくれるからです。MCP_DATAVIZ_AUTH_ENABLED=false でサーバーを起動すると、SDKの Origin チェックを緩和してCORSヘッダーを追加します。ブラウザベースのホストにはこれが必用で、認証がオンの間はオフになりします。
ウィジェットHTMLはサーバー構築時に一度だけ読み込ます。したがて編集時はサーバの再起動が必要です。
ホスト互換性
MCP Appsのサポート具合いはホストごとに異なり、見た目は同一の症状になります — 通常はどこエラーもした空白や折り畳んだウィジェットです。**docs/HOST-COMPATIBILITY.md は、実観察、各原因の切分け方た - サーバサー側で修正可なもの(3うちの1つ)と否定なものの合計を文書化している。
データセット
オープン4つ、オペレーション3つ、.internal 3つ — すべてVega dataset collectionの公開サンプルす。ビルド・タイムにイメージ内にベンダルため、実行中コンテナがデータのオリジンへのネトワークアセスを必要としません。テイアラベは認可セスモデルを具体的にするために用選た標示であり、実際の意味はありま。
オープン | オペレ一如ンズ | コンフイデんシャル (理由は察例) |
|
|
|
|
|
|
|
|
|
レイアウト
src/mcp_dataviz/
server.py tools, resources, prompts, completions
auth.py Entra token verification, roles→tiers, scope challenge
catalog.py the 10 datasets and the tier gate
charts.py Altair → Vega-Lite, with aggregation pushed into pandas
config.py environment settings (nothing hardcoded)
widgets/ the MCP App
infra/ Bicep: ACR, Container Apps, Log Analytics
scripts/ entra-setup.sh, deploy.sh, assign-persona.sh, preview_widget.py
tests/ 168 tests, incl. HTTP-level auth and step-up
docs/ AUTHZ, CONNECT, DESIGN, HOST-COMPATIBILITYPythonパッケージは、リポジトリがmcp-demo-aad-vizであっても、mcp_dataviz (とMCP_ 環境プレフィックス) の名前を保っています。リネームするとAzureのすべてのリソース名と環境変数を無益に無意味に変えてしまうからです。
テスト
uv run pytest # 168 tests, no Azure neededuv run ruff check src tests scriptstess/test_http.py は本物のuvironサーバーを起動して、401チャレンギ、PRM文書、403 insufficient_scopeのステップアップ、input_required のラウンドトップを検証します。
コスと
Container Appsはゼロにスケールので (min`Replicas: 0) 待機デモのコスとはほぼナシ。ACR基本とログ・アナリテイクスのみ定常課金オ月額ユーロ)です。
az group delete --name rg-mcp-dataviz --yes && ./scripts/entra-teardown.shライセンス
MIT.
This server cannot be deployed
Maintenance
Related MCP Connectors
- BasedashOAuthcom.basedash
Governed BI MCP. Ask questions of live company data and list workspace sources via OAuth.
Build multi-tenant apps over MCP. Schemas, CRUD, deploys — access control enforced server-side.
Query your warehouse or a CSV with Claude/ChatGPT over MCP, governed by table-level ACL + audit.
Governed data discovery, exact queries, decisions, simulations, and runtime utilities over MCP.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceEnables AI assistants to interact with Databricks Genie Spaces through MCP tools. Provides secure OAuth-based access to query and interact with Databricks data catalogs and schemas via custom Genie interfaces.-
- AlicenseNot gradedqualityDmaintenanceEnables governed, agent-agnostic data exploration by allowing users to ask natural language questions through MCP-compatible agents, executing safe, permission-scoped queries against data sources and returning interactive charts.18 npmApache 2.0
- AlicenseAqualityBmaintenanceInteractive visualization of Microsoft Entra ID identity relationships, enabling exploration of org charts, groups, attributes, and access assignments through a D3 force-directed graph within MCP clients.860 npmMIT
- FlicenseNot gradedqualityBmaintenanceProvides MCP tools to query Tableau Server/Cloud datasources via REST API and VizQL Data Service, with support for Gemini or OpenAI as the LLM backend. Enables a natural language chat interface that can be embedded in Tableau dashboards, automatically including dashboard filter context.-