Skip to main content
Glama
sinanpl

mcp-demo-aad-viz

by sinanpl

mcp-demo-aad-viz

Рабочий пример двух возможностей MCP, которые обычно демонстрируют по отдельности, а вместе они становятся гораздо интереснее:

  • Авторизация Microsoft Entra ID (Azure AD) — сервер является ресурсным сервером OAuth 2.1. Членство в ваших группах Entra определяет, какие наборы данных для вас существуют. Не «перечислены, а потом закрыты» — их просто нет.

  • Встроенные приложения / расширения (io.modelcontextprotocol/ui) — графики приходят в виде интерактивного виджета, отображаемого прямо в беседе, а его изменение стоит ноль токенов.

Вместе они образуют то, на что стоит посмотреть: конструктор графиков Altair, в выпадающем списке наборов данных которого находятся ровно те наборы, которые разрешают ваши группы Entra, — проверка выполняется на стороне сервера при каждом взаимодействии с виджетом.

Сделано против спецификации MCP 2026-07-28 с Python SDK mcp 2.0. Разворачивается в Azure Container Apps. Лицензия MIT.

Внимание: это демонстрация, а не продукт. В репозитории десять публичных демонстрационных наборов данных и намеренно простая модель уровней, чтобы сценарий авторизации был понятен.

Интерактивный виджет конструктора графиков Altair: элементы управления набором данных, осями и типом маркера рядом с точечной диаграммой набора данных Palmer penguins


Попробуйте без Azure

Без тенанта, без авторизации, без деплоя — достаточно, чтобы увидеть работу виджета:

uv sync && uv run python scripts/fetch_datasets.py
MCP_DATAVIZ_AUTH_ENABLED=false MCP_DATAVIZ_PORT=3001 uv run python -m mcp_dataviz

В этом режиме каждый вызывающий считается обладателем всех трёх уровней наборов данных. Подключите любой хост MCP Apps к адресу http://localhost:3001/mcp — см. Локальная разработка для браузерного хоста, который показывает весь протокол ui/ в реальном времени.

Попробуйте с 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-endpoint. Добавьте его в клиент точно в том виде, как он выведен — путь /mcp является частью идентификатора ресурса OAuth → docs/CONNECT.md.

Используйте уникальный --tag при каждом деплое. При повторном теге шаблон Bicep становится байт-в-байт идентичен текущему, новая ревизия не создаётся, и деплой сообщает об успехе, хотя ничего не выкатывает.


Что здесь демонстрируется

Возможность MCP

Где это видно

Что вы видите

Авторизация (OAuth 2.1 RS)

auth.py

Членство в группе меняет размер каталога

MCP Apps (io.modelcontextprotocol/ui)

chart_builder.html

Выпадающие списки перерисовывают график на месте

Инструменты только для приложений (visibility: ["app"])

render_chart

Перерисовка виджета стоит ноль токенов

input_required

plot_dataset

Хосты без виджетов получают форму вместо виджета

Повышение объёма прав (403 insufficient_scope)

export_chart

Первый экспорт запускает повторное подтверждение прав

Ресурсы и шаблоны

data://catalog

Отфильтровано по правам доступа

Автодополнение

аргументы набора данных

Автодополнение никогда не называет недоступный вам набор данных

Промпты

explore_dataset

Управляемый первый вход

Две возможности, которые спецификация в этой ревизии объявила устаревшими и которых этот сервер поэтому избегает: sampling и capability logging (SEP-2577). Вместо запросов к модели suggest_chart выбирает маркер графика на основе типов столбцов.


Модель авторизации

Две независимые оси. Их путаница — обычная ошибка.

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

Datasets.Open

iris, penguins, cars, barley

operations

Datasets.Operations

seattle-weather, us-employment, gapminder

confidential

Datasets.Confidential

diмаmonds, movies, titanic

Инженеры и учёные владеют одинаковым количеством наборов данных, но не одними и теми же наборами, поэтому два коллеги с одним и тем же вопросом получают два разных ответа.

GXP1 += "GXP7"

--now также назначит роли непосредственно пользователю: изменение группы в Entra может занимать несколько минут, прежде чем попадёет в новый токен, а прямое назначение — около двадцати секунд.

Роли — это жёсткий отказ. Вы не можете запросить себе путь в группу. Наборы данных за пределами вашего уровня отсутствуют в результатах tools/list, опепуляциях завершения и выпадающем списке виджета — это происходит не после «показано, потом отказано», а они просто не доступны.

Scope — мягкий отказ. Если не достаёт Datasets.Export, сервер отвечает 403 со WWW-Authenticate: Bearer error="insufficient_scope", и клиент авторизовается заново, запросавая этот scope.

У Entra есть две ловушки, которые этот репозиторий обходит: у него нет динамической регистрации клита и нет endpoint метаданных RFC 8414, а URL должен быть обязательно зарегистрирован как URI идентификатора приложения иначе resource= по RFC 8707 упадёт с AADSTS9010010.

Подробнее: docs/AUTHZ.md · docs/CONNECT.md.


Почему виджет интересен

Спецификация Vega-Lite с встроенными данными занимает 30–300 КБ. Если просто отдавить её из инструмента, она окажется в контексте модели на каждом графике.

Вместо этого:

  1. plot_dataset возвращает дескриптор ~900 байт — кодировка, число строк, предупреждения. Без спецификации.

  2. Хост отображает приложение ui:// и передаёт ему дескриптор.

  3. Виджет вызывает render_chart (инструмент только для приложений) для получения уже конкретной спецификации.

Поскольку шаг 3 выполняется приложением, а не моделью, спецификация никогда не попадает в диалог. Изменение выпадающего списка — это лишь один небольшой цикл запроса к серверу и ноль токенов.

История с авторизацией сохраняется и здесь: render_chart и app_catalogue заново определяют уровень доступа на каждый вызов, поэтому виджет не может обратиться к набору, который не разрешён токеном, — даже когда модель уже не участвует в цикле.

Заметки по дизайну: docs/DESIGN.md.


Локальная разработка

Два стенда, для двух разных задач.

«Корректны ли HTML/JS моего виджета?» — миниатюрный хост, который говорит на реальном протоколе ui/ postMessage и протоколирует каждое событие, без участия MCP-клиента:

uv run python scripts/preview_widget.py     # http://127.0.0.1:8765

Он внедряет ту же строгую CSP, что и настоящий хост, поэтому сбои CSP воспроизводятся здесь, а не только в проде. --strip-structured-content эмулирует дефект хоста, описанный в docs/HOST-COMPATIBILITY.md.

«Корректна ли моя MCP-поверхность?» — эталонный хост из репозитория MCP Apps, который управляет сервером напрямую по HTTP:

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 также ослабид, повышает ограничение Origin в SDK и добавляет CORS-заголовки, необходимыми браузерному хосту; эти механизмы отключены всегда, когда включена авторизация.

Обратите внимание: HTML-файл виджета читается один раз при создании сервера, поэтому его правка требует перезапуска сервера.


Совместимость с хостами

Поддержка MCP Apps отличается от хоста к хосту и приводит к одинаковым по внешнему виду симптомам — обычно это пустой или свёрнутый виджет без каких-либо ошибок. docs/HOST-COMPATIBILITY.md документирует, что наблюдалось в реальности, как была выявлена каждая причина, и какие из них можно исправить на стороне сервера (одна из трёх), а какие нельзя.


Наборы данных

Четыре открытых, три операции, три конфиденциальных — все это публичные демонстрационные наборы из коллекции Vega. Они зашиты в образ при сборке, поэтому работающий контейнер не требует сетевого доступа к источнику данных. Идентификаторы уровней являются наглядными и выбраны для того, чтобы модель прав доступа была конкретной.

open

operations

confident (пояснительная причина)

iris

sea-weather

diamonds — цены, используемые в разных регионах

penguins

us-employment

movies — доходы от продаж

cars

gapminder

titanic — персональные записи

barley


Структура репозитория

```bash

uv sync && uv run python scripts/fetch_datasets.py


Wait, GXP10. Correction: "GXP10".

Пакет Python сохраняет имя `mcp-datatool` даже если репозиторий называется `mcp-demo-aad-viz`; переименование привело бы к массовой перетасовке всех имён ресурсов Azure и переменных окружения без какой-либо пользы.

## Секции

```bash
uv run pytest          # 168 tests, no Azure needed
uv run ruff check src tests scripts

tests/test_http.py запускает настоящий uvicorn-сервер и проверяет 401 challenge, PRM-документ, 403 insufficient_scope step-up и цикл input_required.

Стоимость

Azure Container Apps масштабируются до нуля (minReplicas: 0), поэтому неиспользуемое демо практически ничего не не стоит; единственные постоянные статьи расходов — ACR Basic и Log Analytics (несколько € / месяц).

az group delete --name rg-mcp-dataviz --yes && ./scripts/entra-teardown.sh

Лицензия

MIT.

-
license - not tested
Not graded
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

  • MCP Hub: AI service discovery, per-user OAuth, and multi-service workflow orchestration

  • Official Microsoft MCP Server to query Microsoft Entra data using natural language

  • Manage SRG+ hubs, channels, content, assets, users, and workspaces from any MCP-aware AI agent.

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/sinanpl/mcp-demo-aad-viz'

If you have feedback or need assistance with the MCP directory API, please join our Discord server