API VEGA

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 в разные инструменты и что можно построить с его помощью:

Установка и запуск

Требования

Установка

  • Клонируйте репозиторий:
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

HTTPStdioDockerKubernetes
Как запускаетсяДолгоживущий сервер, запускаемый отдельноMCP-клиент запускает его по требованиюКонтейнеризованный HTTP-серверКонтейнеризированный, за ingress
АутентификацияOAuth2 PKCE flow (browser popup)Кэшированный токен через sas-viya CLI или sas-mcp-loginOAuth2 PKCE flow (browser popup)PKCE и/или raw Viya bearer token
Лучше дляМультитпользовательские или общие наборы; окружения, близкие к продакшенуЛокальная разработка под одного пользователя; быстрая экспериментацияКомандные развёртывания; CI/CD; окружения без установленного PythonСовместные/корпоративные развёртывания наряду с Viya
ТребуетсяPython + uvPython + 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); если не задан — возвращает все уровни.

УровеньГруппа
0Compute Contexts & Code Execution
1Data Discovery
2Data Operations & Files
3Reports & Visualization
4Batch Jobs & Async Execution
5Automated Machine Learning
6Model Management & Scoring
7Decisioning (SAS Intelligent Decisioning)
8Workbench (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 casManagement uploadTable — 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_objectsget_castable_columnsapply_report_operationsget_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-направление, опрашивая до завершения и возвращая сгенерированный сервером moduleId MAS (напрямую годится для использования с 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 с) рекомендуется. Укажите абсолютный путь к директории вашего checkout sas-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 принадлежат их владельцам и используются здесь исключительно для идентификации и ссылок, без какого-либо намёка на аффилированность или одобрение владельцами товарного знака.

Зависимости третьих лиц

В проекте используются следующие зависимости.

ЗависимостьЛицензия
PythonPython Software License
FastMCPApache License 2.0
uvicornBSD 3-Clause License
starletteBSD 3-Clause License
httpxMIT License