SAS Viya MCP Server
Сервер Model Context Protocol (MCP) для выполнения SAS-кода, обучения проектов AutoML, скоринга моделей и многого другого в средах SAS Viya.
Особенности
- 75 инструментов в 9 доступных уровнях, охватывающих Analytics Life Cycle на SAS Viya
- Шаблоны подсказок (Prompt Templates) для улучшения вашего SAS-кода
- Аутентификация OAuth2 с потоком PKCE
- HTTP-основанный MCP-сервер, совместимый с MCP-клиентами
Статьи и видео
Здесь вы найдёте статьи о том, как использовать и интегрировать SAS MCP Server в разные инструменты и что можно построить с его помощью:
- From REST APIs to AI Agents: Why the SAS Viya MCP Server Matters → [От REST API к AI-агентам: почему SAS Viya MCP Server важен]
- Connecting GitHub Copilot to SAS Viya with the SAS Viya MCP Server → [Подключение GitHub Copilot к SAS Viya с SAS Viya MCP Server]
- Bring Your Own Key: SAS Viya MCP Server with GitHub Copilot CLI → [Собственный ключ: SAS Viya MCP Server с GitHub Copilot CLI]
- Putting the SAS Viya MCP Server to Work in GitHub Copilot → [Использование SAS Viya MCP Server в GitHub Copilot]
- Connecting Claude Code CLI to SAS Viya with the SAS Viya MCP Server → [Подключение Claude Code CLI к SAS Viya с SAS Viya MCP Server]
- Putting the SAS Viya MCP Server to Work in Claude Code CLI → [Использование SAS Viya MCP Server в Claude Code CLI]
- Integration with SAS Retrieval Agent Manager (RAM) → [Интеграция с SAS Retrieval Agent Manager (RAM)]
Установка и запуск
Требования
- Обязательные
- Python 3.12+
- uv 0.8+
- SAS Viya environment с вычислительным сервисом
- Настройка среды Viya для MCP
- См. configuration.md
- Необязательные
- Docker: см. container setup
- Kubernetes: примеры манифестов (Contour или nginx) и Helm-чарт в deploy/
Установка
- Клонируйте репозиторий:
git clone <repository-url>
cd sas-mcp-server
- Установите зависимости
uv sync
ПРИМЕЧАНИЕ: По умолчанию будет создано виртуальное окружение с названием .venv в корневой директории проекта.
Если по каким-либо причинам виртуальное окружение не создаётся, запустите uv venv, а затем повторно выполните uv sync.
Использование
- Настройте переменные окружения:
cp .env.sample .env
Откройте .env и задайте
VIYA_ENDPOINT=https://your-viya-server.com
- Запустите MCP-сервер (см. ниже [Choosing a deployment mode]):
Вариант A: HTTP-режим (предварительно запущен сервер, подключение из MCP-клиента)
uv run app
Сервер будет доступен по умолчанию по адресу http://localhost:8134/mcp. Аутентификация осуществляется через OAuth2 PKCE во времени браузера.
Вариант B: Режим stdio (MCP-клиент запускает сервер по требованию)
Аутентифицируйтесь один раз. Два эквивалентных варианта:
# Вариант B1 — если установлен SAS Viya CLI:
sas-viya auth loginCode
# Вариант B2 — встроенный помощник, внешний CLI не нужен (Viya 2022.11+):
uv run sas-mcp-login
Оба потока записывают access token в локальный кэш (~/.sas/credentials.json и ~/.sas-mcp-server/credentials.json соответственно); stdio-сервер читает тот, который найдёт. При истечении срока действия токена повторно запустите ту же команду.
Затем настройте ваш MCP-клиент на непосредственный запуск сервера (см. ниже).
Вариант C: Docker / Podman (контейнеризованное развёртывание)
Получите готовый образ из GitHub Container Registry:
docker pull ghcr.io/sassoftware/sas-mcp-server:latest
docker run -e VIYA_ENDPOINT=https://your-viya-server.com -p 8134:8134 ghcr.io/sassoftware/sas-mcp-server:latest
Или соберите локально из исходников:
docker build -t sas-mcp-server .
docker run -e VIYA_ENDPOINT=https://your-viya-server.com -p 8134:8134 sas-mcp-server
Доступные теги образов:
latest— последняя помеченная версия<major>.<minor>.<patch>(например,1.0.0) — конкретная сборка<major>.<minor>(например,1.0) — последняя патч-версия минорной серииedge— вершинаmain(незрелая версия, для тестирования)sha-<short>— привязан к конкретному коммиту
Программные клиенты с предсуществующим токеном Viya
Если ваш caller уже имеет токен доступа Viya (например, скрипт автоматизации, получивший его через SAS Viya CLI), запустите HTTP-режим сервера с ALLOW_RAW_BEARER=true и передавайте токен напрямую:
curl -H "Authorization: Bearer $VIYA_TOKEN" http://localhost:8134/mcp ...
Сервер валидирует токен против JWKS Viya и пропускает его как есть upstream, обходя обмен JWT MCP. По умолчанию процесс OAuth2 PKCE продолжает работать — оба типа клиентов используют единый /mcp endpoint.
Если ваши Viya API специально доступны без аутентификации (например, локальный/разработчик Compute API endpoint), установите VIYA_AUTH=false, чтобы отключить все потоки SASLogon/OAuth в HTTP и в режиме stdio. В таком режиме сервер отправляет upstream-запросы без заголовка Authorization.
Если ваше вычислительное развёртывание не открывает /compute/contexts и поддерживает только фиксированную сессию, задайте COMPUTE_SESSION_ID=<session_id>. Инструменты вычисления будут использовать эту сессию напрямую, вместо создания сессий на основе контекста.
Choosing a deployment mode
| HTTP | Stdio | Docker | Kubernetes | |
|---|---|---|---|---|
| Как запускается | Долгоживущий сервер, запускаемый отдельно | MCP-клиент запускает его по требованию | Контейнеризованный HTTP-сервер | Контейнеризированный, за ingress |
| Аутентификация | OAuth2 PKCE flow (browser popup) | Кэшированный токен через sas-viya CLI или sas-mcp-login | OAuth2 PKCE flow (browser popup) | PKCE и/или raw Viya bearer token |
| Лучше для | Мультитпользовательские или общие наборы; окружения, близкие к продакшену | Локальная разработка под одного пользователя; быстрая экспериментация | Командные развёртывания; CI/CD; окружения без установленного Python | Совместные/корпоративные развёртывания наряду с Viya |
| Требуется | Python + uv | Python + uv (+ необязательно sas-viya CLI) | Только Docker или Podman | Кластер, ingress-контроллер, TLS-секрет |
| Хранятся ли учётные данные? | Нет — пользователь аутентифицируется интерактивно | Нет — только access token (не пароль) кэшируется | Нет — пользователь аутентифицируется интерактивно | Нет — ключ подписи в Secret; пользователи аутентифицируются сами |
| Конфигурация MCP-клиента | Укажите клиенту http://localhost:8134/mcp | Клиент запускает uv run app-stdio | Укажите клиенту http://host:8134/mcp | Укажите клиенту https:///mcp |
Краткие рекомендации:
-
Для начала или исследований выберите stdio — один вызов
sas-viya auth loginCodeилиuv run sas-mcp-login, затем MCP-клиент сам управляет жизненным циклом сервера. -
Нужна безопасная, интерактивная аутентификация? Используйте HTTP — без сохранённых паролей, каждый пользователь аутентифицируется через браузер.
-
Развёртывание для команды или сервера? Используйте Docker — переносимость, без зависимостей Python на хосте, проще интеграция с оркестраторами.
-
Для всей организации? Используйте Kubernetes — примеры манифестов и Helm-чарт находятся в deploy/, включая маршрутизацию OAuth-потока для Contour (по умолчанию в чартe; единственный вариант, который может разместить сервер под префиксом пути на существующем hostname) или ingress-nginx.
-
Используете Gemini CLI? Выберите stdio — Gemini CLI не поддерживает HTTP-режим и браузер-based OAuth. См. Gemini CLI configuration.
-
Установка из сервиса каталога клиента? Этот путь запускает опубликованный контейнер в режиме stdio (
app-stdio), а не HTTP-сервер, поэтому он аутентифицируется через ваш кэш токенов в~/.sas— который нужно монтировать в контейнер по пути/app/.sas.
Ограничение экспонируемых инструментов (типы)
Инструменты сгруппированы по нумерованым уровням (tiers). По умолчанию сервер exposes все они; задайте MCP_TIERS, чтобы открыть только подмножество — удобно, чтобы у клиента был небольшой и целевой набор инструментов, или скрыть функции, которые развёртывание не должно предоставлять. Принимает диапазоны и списки через запятую (например, MCP_TIERS=0-4 или MCP_TIERS=0,1,6,7); если не задан — возвращает все уровни.
| Уровень | Группа |
|---|---|
| 0 | Compute Contexts & Code Execution |
| 1 | Data Discovery |
| 2 | Data Operations & Files |
| 3 | Reports & Visualization |
| 4 | Batch Jobs & Async Execution |
| 5 | Automated Machine Learning |
| 6 | Model Management & Scoring |
| 7 | Decisioning (SAS Intelligent Decisioning) |
| 8 | Workbench (Execute Code Only) |
# Пример: открыть только compute/discovery/data-ops и reporting
MCP_TIERS=0-3 uv run app
Режим только для чтения (Read-only)
Установите MCP_READ_ONLY=true, чтобы открыть только те инструменты, которые не могут изменять состояние сервера и не запускают работу на стороне сервера — 43 из 75 инструментов. Отложенные инструменты не регистрируются и, следовательно, отсутствуют в списке инструментов клиента полностью: модель не увидит их и не сможет попробовать.
Это фильтр по уровням, а не собственный уровень — разделение read/write охватывает каждый уровень (например, Tier 3 содержит и get_report, и delete_report). Сочетание двух настроек действует вместе:
# Все чтение инструментов, все уровни
MCP_READ_ONLY=true uv run app
# Чтение инструментов только из уровней reporting и decisioning
MCP_TIERS=3,7 MCP_READ_ONLY=true uv run app
Определение строгие: инструмент считается чтением, если он не может писать или запускать работу. Кроме очевидных инструментов create/update/delete, он также скрывает:
| Пропущено | Почему |
|---|---|
| execute_sas_code, submit_batch_job | Запуск произвольного кода — может выполнять любые операции, включая удаление |
| score_data, catalog_run_agent, catalog_run_adhoc_analysis | Запуск серверных заданий и сохранение записей результатов, хотя возвращают данные |
| promote_table_to_memory | Изменяет состояние CAS в памяти |
| cancel_job, reset_compute_session | Уничтожение того, чем владеет вызывающий |
Классификация носит закрытый характер: инструмент не явно помечен как чтение — будет скрыт. Список находится в src/sas_mcp_server/tools/_access.py, и тест подтверждает охват каждого зарегистрированного инструмента, чтобы новому инструменту не позволить бесшумно попасть в режим чтения.
Аннотации инструментов (что получают клиенты)
Та же классификация аннотируется для каждого клиента как MCP tool annotations в каждом элементе tools/list — независимо от того, включён ли режим read-only или нет:
| Подсказка | Происхождение |
|---|---|
| readOnlyHint | точно из набора для чтения выше — таблица одна, поэтому что сообщает клиенту и что MCP_READ_ONLY обеспечивает, не может дрейфовать |
| destructiveHint | инструменты, которые могут удалить или перезаписать существующее состояние: произвольный код (execute_sas_code, submit_batch_job), delete_*, cancel_job, reset_compute_session, обновление PUT-ов, apply_report_operations, create_report/copy_report (их политика замены конфликта), publish_ml_champion_model |
| idempotentHint | чтение, обновление PUT-ов, удаление, cancel_job, reset_compute_session, promote_table_to_memory |
| openWorldHint | только инструменты, которые могут выйти за пределы Viya: произвольный код и источники URL для загрузки инструментов |
Клиенты используют эти подсказки для формирования UX утверждения — например, Claude группирует инструменты только для чтения и предупреждает перед опасными инструментами — и чтобы решить, когда прервать пользователя. Это подсказки, а не контроль: спецификация советует клиентам воспринимать их как ненадёжные, если сервер ненадёжен, и MCP_READ_ONLY остаётся контролем на стороне сервера. Без аннотаций клиент должен считать стандартные пессимистические настройки (письменные, destructive, open-world) для каждого инструмента, поэтому это снижает трение. На браузерной целевой странице каждый инструмент помечается как read-only / write / destructive по тем же подсказкам.
Доступные инструменты
Заголовки ниже соответствуют номерной группе tiers выше, поэтому MCP_TIERS напрямую определяет инструменты, которые вы expose (например, MCP_TIERS=0-3 даёт Tier 0–3).
Tier 0 — Compute Contexts & Code Execution
- execute_sas_code: Выполнять фрагменты SAS-кода и возвращать результаты выполнения (лог, listing). Выполнение в повторяемой вычислительной сессии на пользователя, сохраняющей SAS-состояние между вызовами (WORK-таблицы, макропеременные, назначенные librefs) — используйте reset_compute_session для начала с чистого листа.
- list_compute_contexts: Перечислять доступные compute contexts
- reset_compute_session: Удалить кэшированную compute-сессию для контекста, сбросив SAS-состояние и принудив новую сессию при следующем вызове
Tier 1 — Data Discovery
Information Catalog (метаданные и профилирование):
- catalog_search: Поиск активов в каталоге (таблицы, столбцы, отчёты и т. п.) с использованием синтаксиса SAS catalog search (свободный текст, фасеты типа
AssetType:Report, диапазоны). Каждый результат имеетresource_uri, который можно передать соответствующему инструменту (например,get_report,get_castable_data). - catalog_search_helper: Узнать, как формировать запросы к каталогу — перечислить доступные фасеты или допустимые значения для одного фасета — чтобы строить точные запросы
catalog_search. - catalog_find_instance: Разрешить экземпляр каталога для исходного ресурса
resource_uri, связывая результат поиска с инструментами профилирования и загрузки без ручного handling instance id. - catalog_run_adhoc_analysis: Отправить произвольный профильный анализ таблицы. NLP-обогащение (язык, настроение, семантические идентификаторы) включено по умолчанию, заполняя
informationPrivacy,nlpTerms,nlpTags, иmostImportantFields. - catalog_get_adhoc_analysis: Опрашивать задачу профилирования и сопоставлять целевой экземпляр, сообщая
profile_readyпосле попадания результатов на актив. - catalog_download_table_profile: Скачать словарь данных таблицы и профиль столбца в CSV, по
instance_idилиresource_uri. - catalog_list_agents: Перечислить агенты каталогов (краулеры, заполняющие метаданные).
- catalog_run_agent: Запустить асинхронный агент-поиск, чтобы просканировать источник данных и обновить метаданные каталога.
- catalog_get_agent_history: Просмотреть историю работ агента — статус и объём метаданных, которые каждая итерация перечислила/ добавила/ обновила/удалила.
Данные CAS (в памяти):
- list_cas_servers: Перечислить доступные CAS-сервера
- list_caslibs: Перечислить CAS-библиотеки на сервере
- list_castables: Перечислить таблицы в CAS-библиотеке
- list_source_tables: Перечислить исходные таблицы, которые ещё не загружены в память (кандидаты на promotion)
- get_castable_info: Получить метаданные таблицы (количество строк, столбцы, размер)
- get_castable_columns: Получить имена столбцов, типы, подписи, форматы
- get_castable_data: Получить выборку строк из CAS-таблицы
- query_data: Выполнить FedSQL
SELECTпо CAS или вычислительным данным и вернуть строки — единая SQL-поверхность для обоих уровней хранения. Выбрать нужный слой черезtarget(casдляcaslib.table,computeдляlibref.table); соединения, подзапросы, агрегации иUNIONработают, ограничение по количеству строк применяется инструментом (написанный вамиLIMITигнорируется CAS). По желанию возвращает текстCREATE VIEWдля самостоятельного исполнения. Чтение только: записи на запись запрещены на предварительном этапе, триггеры SAS макросов (%/&) отвергаются, потому что макропроцессор расширит их вне SQL. Обратите внимание: два слоя не могут быть объединены в одном запросе.
Вычислительные библиотеки (SAS/Compute, внутри compute context):
- list_compute_libraries: Перечислить SAS-библиотеки (librefs), назначенные в compute context
- list_compute_tables: Перечислить таблицы в SAS-библиотеке внутри compute context
- list_compute_columns: Перечислить столбцы таблицы в SAS-библиотеке
Tier 2 — Data Operations & Files
- upload_data: Загрузить файл данных в CAS-таблицу — выполняется на сервере (read server-side), чтобы данные не проходили через контекст модели — через
file_path(сервер читает с диска) илиurl(сервер получает и конвертирует в multipart upload, требуемый endpoint). Поддерживает форматы, принимаемые API casManagementuploadTable— csv, tsv (csv с разделитель табуляции), xls, xlsx (один лист), sas7bdat, sashdat — автоматически определяются по расширению или задаются черезdata_format. Parquet не принимается этим endpoint и отклоняется заранее с инструкциями (загружайте через путь в caslib +promote_table_to_memory, или конвертируйте в csv/sas7bdat). - upload_inline_data: Создать небольшую CAS-таблицу из текста CSV/TSV, переданного как строка (таблица сопоставления, которая строится моделью on-the-fly, или тестовая таблица). Передача данных идёт через контекст модели, поэтому такие таблицы подходят только для маленьких объёмов — используйте upload_data для файлов и прочего крупнее.
- promote_table_to_memory: Загрузить исходную таблицу в память в глобальной области видимости (идемпотентно)
- list_files: Перечень файлов в Viya Files Service
- upload_file: Загрузить файл в Viya Files Service, при желании в Content-папку (
parent_folder_uri). Контент может поступать из одного изcontent(встроенный текст),file_path(чтение на сервере, двоично-безопасное — xlsx, zip, изображения — ограниченоALLOW_LOCAL_FILE_UPLOAD), илиurl(серверная загрузка) - download_file: Скачать содержимое файла
Tier 3 — Reports & Visualization
- list_reports: Перечень Visual Analytics отчетов
- get_report: Получить метаданные и определение отчета
- export_report: экспорт отчета (или отдельных объектов отчета) в любой формат, который поддерживает VA service —
package(zip),pdf,png,svg,csv,tsv,xlsx, илиsummary. Текстовые форматы возвращаются как встроенный текст,png— как изображение, бинарные форматы (package/pdf/xlsx) — как вложенный файл с правильным MIME-type. - describe_report_objects: Исследовать, что может содержать отчет — восемь операций отчетов и все добавляемые объекты (график, таблица, гео-карта, ключевое значение и т. п.) с одной строкой описания, ролями данных, общими опциями и примером полезной нагрузки. Вызывайте без аргументов для каталога (включая отображение объектов по назначениям, руководство по размещению, рецепты макета и жесткие пределы API),
object_type=для контракта конкретного объекта (удобные псевдонимы вродеkpiприводят к разрешению),category=для фильтрации, илиoperation=для полной формы одной операции —operation="addData"документируетdataItems(переименования столбцов, SAS-форматы, агрегации, классификация географии). Поддерживает циклapply_report_operations. - create_report: Создать Visual Analytics-отчет и вернуть его id. При необходимости можно передать массив
operations, чтобы построить весь отчет в одном атомарном вызове; результат содержит созданные имена страниц/объектов и подсказку по верификации. - apply_report_operations: Главный механизм автора — применить упорядоченную пакетную серию нативных VA-операций (
addData,addPage,addObject,updateObject,setParameterValue,updateData,changeData,applyDataView) к отчету. Присвоьте странице заголовок через полеtitleвaddPage(текстовая полоса вверху тела страницы — заголовки VA — это только элементы управления); подпишите каждый график во время добавления черезoptions.object.title; разместите объекты с помощью размещения —page,relativeToObject(left/right/top/bottom для колонок, строк и сеток),container(объединение вstandardContainer), илиreport(new_pageсоздаёт и называет страницу внутри одного пакета для многостраничных отчетов). Пакет атомарен. Валидирует каждую операцию, ключ объекта и размещение по каталогу заранее (сообщает все ошибки сразу), поддерживаетdry_run, осуществляет конвейер ETag, и — сresult_report_name/result_folder— сохраняет пакет в новый отчет, не затрагивая источник. Типичный цикл:describe_report_objects→get_castable_columns→apply_report_operations→get_report_outline/export_report(png, по страницам) для верификации. - get_report_outline: Прочитать структуру отчета — страницы → объекты с именами, которые необходимы другим инструментам (имя объекта для placement/целей
updateObject, подпись дляexport_report, подпись страниц для размещения). - copy_report: Скопировать отчет в новый (опционально переименовать/переложить). В паре с операцией
changeDataдля паттерна копирования и замены. - delete_report: Удалить отчет и его содержимое.
Tier 4 — Batch Jobs & Async Execution
- submit_batch_job: Отправить SAS-задачу на асинхронное выполнение
- get_job_status: Проверить состояние задачи
- list_jobs: Перечислить недавние/активные задачи
- cancel_job: Отменить выполняющуюся задачу
- get_job_log: Получить журнал задачи
Tier 5 — Automated Machine Learning
- list_ml_projects: Перечислить проекты AutoML
- create_ml_project: Создать новый проект AutoML из загруженной CAS-таблицы глобального уровня (caslib + table + необязательный CAS server)
- run_ml_project: Запуск пайплайна автоматизации
- register_ml_champion_model: Зарегистрировать чемпион-модель проекта AutoML в Model Repository
- publish_ml_champion_model: Опубликовать чемпион-модель AutoML в место скоринга
Tier 6 — Model Management & Scoring
- list_registered_models: Перечислить модели в репозитории
- list_publishing_destinations: Перечислить доступные назначения скоринга/публикации, для использования с publish_ml_champion_model
- list_mas_modules: Перечислить опубликованные MAS-модули
- get_mas_module_step_signature: Просмотреть сигнатуру входных/выходных переменных шага опубликованного MAS-модуля перед скорингом
- score_data: Оценить данные против опубликованной модели или решения
Tier 7 — Decisioning (SAS Intelligent Decisioning)
Построение и управление наборами правил SAS Intelligent Decisioning и потоками решений полностью, затем опубликование потока в Micro Analytic Score (MAS), чтобы score_data мог выполнить его.
Бизнес-правила — наборы правил:
- create_business_ruleset / update_business_ruleset / get_business_ruleset / list_business_rulesets / delete_business_ruleset: Управление наборами правил (входной/выходной сигнатуры, на которых работают правила)
- lock_business_ruleset_revision: Заблокировать текущее состояние набора правил как неизменяемую ревизию
- list_business_ruleset_revisions: Перечислить заблокированные ревизии набора правил
Бизнес-правила — правила:
- create_business_rule / update_business_rule / get_business_rule / list_business_rules / delete_business_rule: Управление условными правилами внутри набора правил
Потоки решений:
- create_decision_flow / update_decision_flow / get_decision_flow / list_decision_flows / delete_decision_flow: Управление потоками решений, объединяющими шаги наборов правил
- get_decision_flow_code: Получить сгенерированный DS2-код исполнения для потока
- lock_decision_flow_revision / list_decision_flow_revisions / get_decision_flow_revision: Блокировать, перечислять и получать неизменяемые ревизии решений
- publish_decision_flow: Опубликовать заблокированную ревизию решения на MAS-направление, опрашивая до завершения и возвращая сгенерированный сервером
moduleIdMAS (напрямую годится для использования с get_mas_module_step_signature / score_data)
Tier 8 — Workbench (Execute Code Only)
- execute_sas_code: Выполнять фрагменты SAS-кода и получать результаты выполнения (лог и вывод). Выполнение в повторяемой вычислительной сессии, сохраняющей SAS-состояние между вызовами
Шаблоны подсказок (Prompt Templates)
- debug_sas_log: Анализировать SAS log на наличие ошибок с объяснением корневой причины
- explore_dataset: Генерировать SAS-код для профилирования данных
- data_quality_check: Генерировать код для проверки качества данных (DQ)
- statistical_analysis: Настроить статистический рабочий процесс с диагностикой
- optimize_sas_code: Рассмотреть и оптимизировать SAS-код
- explain_sas_code: Пошаговое объяснение кода
- sas_macro_builder: Создать готовые к производству SAS-макросы
- generate_report: Сгенерировать код ODS/PROC REPORT
- build_va_dashboard: Руководство по созданию-polished многостраничной панели Visual Analytics на основе CAS-таблицы — метод «обнаружить → сформировать → структура → полировка → проверка» через инструменты authoring для отчетов
Конфигурация MCP Client
Примеры конфигураций приведены в папке examples/. Ниже краткие стартовые фрагменты для популярных клиентов.
Подсказка — открыть конечную точку в браузере. В HTTP-режиме, открыть URL MCP в браузере (например,
http://localhost:8134/mcpилиhttps://<host>/mcpдля развернутого сервера) покажет landing page — это страница с описанием того, что сервер есть, к какой Viya он подключается, какие уровни инструментов доступны одним кликом, и готовые конфигурации для Claude Code, VS Code, Cursor, Claude connectors и общегоmcp.jsonклиента — с полным URL развертывания в заполненном виде. Только простой GET в браузере возвращает такую страницу; MCP-клиенты и curl увидят ровно то, что было ранее. Страница не требует аутентификации и показывает лишь форму развертывания (никогда не пользовательские данные); администратор может отключить её черезMCP_LANDING_PAGE=false.
VS Code / Cursor / Claude Code (.vscode/mcp.json)
HTTP-режим (требуется запуск uv run app отдельно):
{
"servers": {
"sas-execution-mcp": {
"url": "http://localhost:8134/mcp",
"type": "http"
}
}
}
Stdio-режим (сервис запускается по требованию):
{
"servers": {
"sas-execution-mcp": {
"command": "uv",
"args": ["run", "app-stdio"],
"cwd": "${workspaceFolder}"
}
}
}
Gemini CLI (.gemini/settings.json)
Gemini CLI поддерживает только stdio-режим. Добавьте в файл ~/.gemini/settings.json или в проектный .gemini/settings.json:
{
"mcpServers": {
"sas-viya-mcp": {
"command": "uv",
"args": ["run", "app-stdio"],
"cwd": "/path/to/sas-mcp-server",
"timeout": 60000
}
}
}
Примечание: поле
timeout(в миллисекундах) важно — вызовы SAS Viya API могут занимать дольше, чем стандартные 10 секунд Gemini CLI. Значение60000(60 с) рекомендуется. Укажите абсолютный путь к директории вашего checkoutsas-mcp-serverвcwd.
Пример
Выполнить SAS-код через MCP-инструмент:
data work.students;
input Name $ Age Grade $;
datalines;
Alice 20 A
Bob 22 B
;
run;
proc print data=work.students;
run;
Для получения дополнительных сведений, опций конфигурации и вариантов развёртывания смотрите в примеры в папке examples и следуйте инструкциям там.
Режим сбора данных (Usage Telemetry)
Опциональный режим по умолчанию выключен, который регистрирует, как фактически используется сервер — какие инструменты, для каких целей, какие входные данные и где они не подходят. Он служит двум аудиториям:
- Контрибьюторам, дающим структурированную обратную связь разработчикам. Вместо длинных баг-репортов можно включить на время и передать лог, чтобы понять, какие инструменты используются, какие не работают и какие цели для них ещё не имеют хорошего инструмента — прямой сигнал на улучшение существующих инструментов и выявление новых.
- Организациям, запускающим сервер для своих пользователей. Команды, развёртывающие MCP сервер внутри своей инфраструктуры, могут включить это, чтобы понимать, что делают их пользователи и зачем — внутри собственной инфраструктуры.
Это реализовано как middleware FastMCP (telemetry.py + usage_logger.py) и не требует изменений в каком-либо инструменте.
🔒 Ничего никогда не отправляется автоматически. Режим сбора данных просто добавляет локальный лог-файл на машину, на которой запущен сервер. Он отключён, если вы явно не включили его, и даже при включении данные остаются на диске — делиться ими с кем-либо (включая разработчиков) нужно вручную, отправляя файл. Нет «phone-home», никакой сетевой передачи и третьих сторон.
При включении он выполняет две задачи:
- Внедряет обязательный параметр
goalв каждую схему инструмента, чтобы модель сформулировала одной фразой, почему был выбран данный инструмент для текущего запроса.goalудаляется из аргументов перед фактическим запуском инструмента, чтобы инструменты его не видели. - Добавляет одну строку JSON за каждый вызов инструмента (JSON Lines / NDJSON, схема v3) в локальный лог: временная метка, идентификатор запуска, по-ринку последовательности, имя инструмента, цель, аргументы (плюс стабильный
args_hashдля анализа повторной попытки), результат, статус, ошибка, задержка и имя клиента, версия клиента. Когда инструмент объявляет неуспех как данные (например,{"status": "apply_failed"}), запись также содержитtool_status/is_tool_error/tool_message/failed_operation_index— чтобы можно было анализировать уровень ошибок по инструментам в любом режиме. Заголовокrun_startоткрывает лог и повторяется каждые 1000 записей, поэтому ротация не может оставить участок лога без заголовка для разрешения; каждая выдача идентична по байтам, поэтому любая из них подойдёт. Секрето-образные ключи и встроенные Bearer/JWT-токены скрыты, имя Viya-хоста маскировано в тексте ошибок/результатов, и каждое поле имеет ограничение по размеру.
Записи группируются по run_id — один запуск на серверный процесс — а не по MCP-сессии. Протокол переходит к безсессийной модели (FastMCP 4 делает это по умолчанию), где session_id отсутствует или создаётся заново для каждого запроса, чтобы группировка по нему не распадала трассировку на фрагменты одной вызов-по-вызову.
По режиму stdio один процесс обслуживает одного клиента, поэтому запуск — это трассировка именно этого клиента. По HTTP запуск охватывает всех клиентов, обслуженных процессом, и client_name/client_version — единственные различия между ними. Два пользователя на одном клиентском ПО разделяют один run_id и один счётчик seq — это ограничение «drop-сессий»; это не то, что можно исправить в рамках COLLECTION_LOG_PATH, которое делится по процессам, а ось run_id уже это покрывает.
Включение
Установите переключатель в .env (все параметры задокументированы в .env.sample):
COLLECTION_MODE=true
# необязательные переопределения (значения по умолчанию указаны):
# COLLECTION_LOG_PATH=~/.sas-mcp-server/tool-usage.log
# COLLECTION_LOG_RESULTS=failures # never | failures | always (см. ниже)
# COLLECTION_RUN_TAG= # произвольная текстовая метка в run_start
Результаты инструмента регистрируются согласно COLLECTION_LOG_RESULTS — три состояния:
neverрегистрирует только общую форму (тип + ключевые имена, например{"_type":"object","_keys":["status","report_id"]});failures(по умолчанию) регистрирует полные (ограниченные и замаскированы) содержимое результатов только для вызовов, завершившихся ошибкой или объявивших неудачу инструментом — компромисс между производительностью и диагностикой;alwaysрегистрирует содержимое результатов при каждом вызове. Аргументы, цель, статус, текст ошибки и вывод инструмента — фиксируются в любом режиме. (true/falseмогут использоваться как алиасы дляalways/never.)
⚠️ Конфиденциальность: при включении логи содержат ваши входные данные инструментов (например, SAS-код и запросы), и — в режимах
failures/always— реальные данные результатов, которые могут включать строки таблиц, вывод SAS listings и PII. Маскирование — эвристика (ключи, подобныеCredential, Bearer/JWT, и имя Viya-хоста) — не обнаруживает PII в значениях данных. Перед обменом логом обязательно проверьте его. Файл доступен только вашему пользователю (POSIX chmod 0600; Windows icacls).
Производительность
Режим сбора предназначен быть дешёвым для постоянного включения. По измерениям в этом репозитории (45 зарегистрированных инструментов, FastMCP 3.4.2):
- Прокинутые токены запроса. Внедряемое поле
goalувеличивает схемуtools/listдля модели примерно на +2 400 входных токенов (~29%) за оборот. Поскольку список инструментов стабилен в рамках одной сессии, он подаётся из кэширования подсказок после первого оборота (постоянная нагрузка ≈ +240 токенов/оборот), плюс примерно 15–30 выходных токенов на запросам модели на формирование предложенияgoal. Это единственная видимоя клиенту стоимость и применяется только пока включён режим сбора. - Задержка на вызов. Middleware + логирование добавляют примерно 1.4 мс на вызов в базовом виде (примерно 5.3 мс при
COLLECTION_LOG_RESULTS=always). Запись JSONL вынесена в отдельный поток, чтобы не блокировать цикл событий. По сравнению с настоящими вызовами Viya (обычно сотни миллисекунд до секунд) это незначительно — тестовый набор интеграции прошёл идентично как с включённым, так и с выключенным режимом. - Диск. Примерно 0.5–0.7 КБ на инструмент в базовом виде. Лог ротируется по
COLLECTION_MAX_LOG_BYTES(значение по умолчанию 10 МиБ, ≈16k вызовов) и хранитCOLLECTION_LOG_BACKUPS(значение по умолчанию 3) ротированных файлов, так что рост на диске ограничен.
Тестирование
Проект включает два уровня тестирования: модульные тесты (unit tests) — быстрые, без учётных данных, и интеграционные тесты — на реальном SAS Viya.
Различие между запуском
run_tests.shи прямым запускомpytest— платформа влияет.run_tests.sh— Bash-обёртка, добавляющая проверки через ruff + pyright, связку учётных данных и формирование JUnit-отчётов. Она работает на Linux/macOS и на Windows только через Git Bash или WSL. В Windows PowerShell илиcmdиспользуйте командыuv run python -m pytest ..., указанные под каждым режимом ниже. Они работают на любой платформе, делают тот же отбор тестов и не требуют дополнительной настройки кромеuv sync.
Запуск модульных тестов
Модульные тесты проверяют схемы инструментов, payload-запросов и внутреннюю логику без сетевых вызовов:
./run_tests.sh # Linux/macOS (также запускает ruff + pyright)
uv run python -m pytest -m "not integration" -v # любая платформа, включая Windows PowerShell
Это запускает набор модульных тестов и исключает интеграционные тесты, которые показываются в резюме как, например, 28 deselected. Это ожидаемо — эти тесты не предназначены для модульных прогонов. Они выполняются только в интеграционных режимах, потому что требуют реального Viya; флага, который активирует их в not integration прогоне, нет.
Запуск интеграционных тестов
Интеграционные тесты вызывают каждый инструмент против реального окружения Viya. Требуют учётные данные, которые задаются через .env или аргументы CLI.
uv sync устанавливает всё, что нужно интеграционному набору, включая openpyxl (используется для создания Excel upload_data фикстуры). Он находится в группе зависимостей test-formats, которая устанавливается по умолчанию через [tool.uv] default-groups — поэтому дополнительной установки не требуется.
Полный набор (модульные + интеграционные) — считывает VIYA_ENDPOINT, VIYA_USERNAME, VIYA_PASSWORD из .env:
./run_tests.sh --integration # Linux/macOS
uv run python -m pytest -v # любая платформа
Передача учётных данных через командную строку (обёртка):
./run_tests.sh --integration \
--endpoint https://your-viya-server.com \
--username youruser \
--password yourpassword
С помощью прямого pytest аналогично можно задать три переменные в .env (или экспортировать их в вашей оболочке).
Только интеграционные тесты (пропустить модульные):
./run_tests.sh --integration-only # Linux/macOS
uv run python -m pytest -m integration --no-cov -v # любая платформа
Примечание: маркер pytest —
integration, а неintegration-only. Флаг--integration-only— это флаг обёрткиrun_tests.sh. Реальный маркер pytest — толькоintegration. Вызовpytest -m "integration-only"не найдёт никаких тестов. Используйте-m integration.
Почему
--no-cov?pytest.iniтребует порог покрытия на уровне 90% для всего набора тестов модуля; интеграционные тесты охватывают гораздо меньший объём кода (~65%), поэтому без--no-covтестовый прогон может завершиться с ошибкой по покрытию, даже если все выбранные тесты прошли.run_tests.sh --integration-onlyдобавляет--no-cov; добавляйте его вручную, если запускаете pytest напрямую (или используйте--cov-fail-under=0).
Форматы бинарной загрузки. Интеграционный тест загрузки Excel upload_data генерирует свой .xlsx-фикстуру через openpyxl, из группы test-formats, которую устанавливает uv sync по умолчанию (см. выше). Если вы специально синхронизируете без неё (например, uv sync --no-default-groups), тест importorskip пропустит, а не упадёт. Coverage форматов csv, tsv и file_path/data_format не требует дополнительных зависимостей. Формат sas7bdat/sashdat требует SAS, поэтому покрывается тестами на уровне unit, а не live.
Каждый из 75 инструментов и 9 шаблонов подсказок имеет интеграционный тест, который проверяется охватом через guards test_every_tool_has_integration_coverage / test_every_prompt_has_integration_coverage — добавление нового инструмента или шаблона без интеграционного тестирования приведёт к сбою набора. Тесты, зависящие от ресурсов, находят реальные цели на инстансе: score_data оценивает наиболее недавно изменённый MAS-модуль, а run_ml_project повторно запускает недавно изменённый завершённый ML-проект. Они skip-аются только если на экземпляре отсутствует такой ресурс. Аналогично, тест test_catalog_agents_workflow skip-ится если на экземпляре нет discovery-агента с именем 'Public' — ожидаемо пропускается, а не ошибка; попросите администратора Viya настроить его, если нужно, чтобы тест прошёл.
В CI: workflow .github/workflows/integration.yml запускает этот набор тестов по запросу (ручной запуск или прикрепление ярлыка run-integration к PR) с использованием секретов репозитория и публикует результаты обратно в PR как статус-чек, прикреплённый комментарий и артефакт JUnit. Файлы результатов записываются в reports/ (git-игнорируемый) и не попадают в репозиторий.
Локальная публикация результатов в PR: --report для записи JUnit XML и сводки в reports/ (git-ignored), затем публикация в PR через GitHub CLI:
./run_tests.sh --integration-only --report
gh pr comment <PR> --body-file reports/integration-summary.md # сводная таблица как комментарий
gh gist create reports/integration.xml # полный XML как ссылка на gist
GitHub не предоставляет API/CLI для привязки бинарного файла к PR (перетащить файл можно только через браузер), поэтому сводка публикуется как комментарий, а XML — через gist или вставлен в collapsible <details> block. Чтобы получить канонический артефакт Actions прямо на вашей машине, запустите workflow удаленно: gh workflow run integration.yml.
Структура тестов
| Файл | Описание |
|---|---|
| tests/test_tool_payloads.py | Проверка payload для всех 75 инструментов (пути URL, JSON-тело, параметры запроса, заголовки) плюс покрытие путей ошибок |
| tests/test_integration.py | Интеграционные тесты конвея для реального Viya |
| tests/test_tools.py | Юнит-тесты для общих REST-хелперов Viya в viya_client (get_json, post_json, make_client, …) |
| tests/test_viya_utils.py | Юнит-тесты для управления сессиями вычислений Viya и обработки задач |
| tests/test_mcp_server.py | Юнит-тесты для HTTP-аутентификационного middleware, маршрутизации health и получения токена |
| tests/test_config.py | Юнит-тесты загрузки конфигурации |
| tests/test_config_oauth.py | Юнит-тесты обработки PermissiveOAuthProxy raw-bearer |
| tests/test_auth_login.py | Юнит-тесты для SAS-MCP-login OAuth/PKCE-helper |
| tests/test_stdio_server.py | Юнит-тесты разрешения токена stdio и flow устройства-code |
| tests/test_env.py | Юнит-тесты для помощника env_bool |
| tests/test_prompts.py | Юнит-тесты рендеринга шаблонов подсказок |
Вклад
Поддерживающие разработчики принимают патчи и вклад в этот проект. Подробности о внесении вкладов смотрите в CONTRIBUTING.md.
Лицензия и атрибуция
За исключением содержания папки /static, проект лицензирован под Apache 2.0 License.
Элементы в папке /static принадлежат SAS и не распространяются по открытой лицензии.
SAS и названия всех продуктов и сервисов SAS Institute Inc. являются зарегистрированными товарными знаками или товарными знаками SAS Institute Inc. в США и других странах. ® означает регистрацию в США.
Отдельные коммерческие лицензии на SAS-программное обеспечение (например, SAS Viya) не включены и необходимы для использования этих возможностей с SAS-программным обеспечением.
Как и любая контейнерная образ — прямые и косвенные зависимости регулируются их собственными лицензиями.
Пользователи опубликованного образа несут ответственность за соответствие использования лицензионным требованиям.
Все упомянутые terceiros-трademarks принадлежат их владельцам и используются здесь исключительно для идентификации и ссылок, без какого-либо намёка на аффилированность или одобрение владельцами товарного знака.
Зависимости третьих лиц
В проекте используются следующие зависимости.
| Зависимость | Лицензия |
|---|---|
| Python | Python Software License |
| FastMCP | Apache License 2.0 |
| uvicorn | BSD 3-Clause License |
| starlette | BSD 3-Clause License |
| httpx | MIT License |