关于 SAS Viya
SAS Viya MCP 服务让分析人员和 Agent 通过 MCP 操作 SAS Viya,涵盖代码执行、数据、报表及模型生命周期。它提供分层工具、只读过滤和 OAuth 2.0 PKCE 认证。
主要功能
- 01执行 SAS 代码与计算任务
- 02发现和操作数据、文件及报表
- 03运行 AutoML、管理模型并评分
- 04按层级筛选工具并启用只读模式
- 05提供交互视图和提示词模板
适用场景
- 01通过 Agent 执行 SAS 分析代码
- 02检查数据、日志及可视化报表
- 03训练 AutoML 项目并对模型评分
MCP 相关
通过 HTTP 或 stdio 向 MCP 客户端提供 SAS Viya 工具、资源和提示词;支持 OAuth 2.0 PKCE,并可限制工具层级或启用只读模式。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
docker run -i --rm -e VIYA_ENDPOINT -e SSL_VERIFY -e CLIENT_ID -e COMPUTE_CONTEXT_NAME -e MCP_TIERS -e MCP_READ_ONLY -e MCP_APPS -e MCP_STATELESS_HTTP -e VIYA_CLIENT_TIMEOUT ghcr.io/sassoftware/sas-mcp-server:1.19.0VIYA_ENDPOINTBase URL of your SAS Viya environment, e.g. https://viya.example.com. No trailing slash.SSL_VERIFYSet false only for a self-signed Viya certificate. Disables verification for the whole process, so prefer a trusted certificate.CLIENT_IDSASLogon OAuth client id used for the token refresh exchange.COMPUTE_CONTEXT_NAMECompute context that backs SAS code execution.MCP_TIERSExpose only some tool tiers, e.g. 0-4 or 0,1,7. Empty exposes all 92 tools. Tiers: 0 Compute, 1 Data Discovery, 2 Data Operations, 3 Reports, 4 Batch Jobs, 5 AutoML, 6 Models, 7 Decisioning, 8 Workbench, 9 Business Glossary.MCP_READ_ONLYExpose only tools that neither change server-side state nor cause server-side work (51 of 92). Composes with MCP_TIERS.MCP_APPSRegister interactive views (MCP Apps) for the data, SAS log and glossary tools. Additive: text-only clients are unaffected. Set false to register none.MCP_STATELESS_HTTPServe HTTP requests without an MCP session. Needed by clients that speak only the sessionless 2026-07-28 protocol revision (claude.ai custom connectors); the legacy handshake works either way.VIYA_CLIENT_TIMEOUTTimeout in seconds for every SAS Viya REST call the tools make.本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。
ghcr.io/sassoftware/sas-mcp-server:1.19.0stdio工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
SAS Viya MCP 服务
适用于 SAS Viya 环境的模型上下文协议(MCP)服务,可用于执行 SAS 代码、训练 AutoML 项目、对模型进行评分,以及更多功能。
功能
- 提供 115 个工具,分为 11 个可选层级,覆盖 SAS Viya 上的分析生命周期
- 在支持渲染的客户端中提供数据、SAS 日志和术语表编辑的交互式视图(MCP Apps)——Claude、ChatGPT、Microsoft 365 Copilot、VS Code、Cursor
- 用于改进 SAS 代码的提示词模板
- 使用 PKCE 流程进行 OAuth2 身份验证
- 基于 HTTP 的 MCP 服务,与 MCP 客户端兼容
文章与视频
在这里可以找到关于如何在不同工具中使用和集成 SAS MCP 服务,以及如何利用它进行构建的文章:
- 从 REST API 到 AI Agent:SAS Viya MCP 服务为何重要
- 使用 SAS Viya MCP 服务将 GitHub Copilot 连接到 SAS Viya
- 自带密钥:使用 GitHub Copilot CLI 配合 SAS Viya MCP 服务
- 在 GitHub Copilot 中使用 SAS Viya MCP 服务
- 使用 SAS Viya MCP 服务将 Claude Code CLI 连接到 SAS Viya
- 在 Claude Code CLI 中使用 SAS Viya MCP 服务
- 与 SAS Retrieval Agent Manager(RAM)集成
- 以视频形式介绍使用 SAS Viya MCP 服务的五个行业用例
开始使用
前提条件
-
必需
- Python 3.12+
- uv 0.8+
- 提供计算服务的 SAS Viya 环境
- 为 MCP 设置 Viya 环境
- 请参阅 configuration.md
-
可选
安装
- 克隆仓库:
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 服务(参见下文的选择部署模式):
选项 A:HTTP 模式(预先运行服务,从 MCP 客户端连接)
uv run app
默认情况下,服务将在 http://localhost:8134/mcp 上可用。身份验证通过浏览器中的 OAuth2 PKCE 流程处理。
选项 B:Stdio 模式(MCP 客户端按需启动服务)
只需认证一次。以下两种方式等效:
# Option B1 — if you have the SAS Viya CLI installed:
sas-viya auth loginCode
# Option B2 — built-in helper, no external CLI needed (Viya 2022.11+):
uv run sas-mcp-login
两种流程都会将访问令牌写入本地缓存(分别为 ~/.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 令牌的程序化客户端
如果调用方已持有 Viya 访问令牌(例如,通过 SAS Viya CLI 获取令牌的自动化脚本),请使用 ALLOW_RAW_BEARER=true 启动 HTTP 模式服务,并直接传递该令牌:
curl -H "Authorization: Bearer $VIYA_TOKEN" http://localhost:8134/mcp ...
服务会根据 Viya 的 JWKS 验证令牌,并在上游原样使用该令牌,绕过 MCP JWT 交换。默认的 OAuth2 PKCE 流程仍可正常使用;两种客户端类型共用同一个 /mcp 端点。
如果有意在不进行身份验证的情况下公开 Viya API(例如本地或开发环境中的 Compute API 端点),请设置 VIYA_AUTH=false,以在 HTTP 和 Stdio 模式下绕过所有 SASLogon/OAuth 流程。在此模式下,服务发送的上游请求不会包含 Authorization 标头。
如果计算部署未公开 /compute/contexts,且仅支持固定会话,请设置 COMPUTE_SESSION_ID=<session_id>。计算工具将直接使用该会话,而不是创建基于上下文的会话。
选择部署模式
| HTTP | Stdio | Docker | Kubernetes | |
|---|---|---|---|---|
| 运行方式 | 单独启动的长驻服务 | MCP 客户端按需启动 | 容器化 HTTP 服务 | 容器化服务,位于入口后方 |
| 身份验证 | OAuth2 PKCE 流程(浏览器弹窗) | 通过 sas-viya CLI 或 sas-mcp-login 缓存令牌 | OAuth2 PKCE 流程(浏览器弹窗) | PKCE 和/或原始 Viya bearer token |
| 适用场景 | 多用户或共享部署;类似生产环境的环境 | 单用户本地开发;快速试验 | 团队部署;CI/CD;未安装 Python 的环境 | 与 Viya 一起进行共享/组织级部署 |
| 要求 | Python + uv | Python + uv(+ 可选的 sas-viya CLI) | 仅需 Docker 或 Podman | 集群、入口控制器、TLS 密钥 |
| 是否存储凭据? | 否——用户交互式进行身份验证 | 否——仅缓存访问令牌(不缓存密码) | 否——用户交互式进行身份验证 | 否——在 Secret 中存储签名密钥;用户自行进行身份验证 |
| MCP 客户端配置 | 将客户端指向 http://localhost:8134/mcp | 客户端运行 uv run app-stdio | 将客户端指向 http://host:8134/mcp | 将客户端指向 https://<viya-host>/mcp |
快速指南:
- 刚开始使用或想探索? 使用 stdio——运行
sas-viya auth loginCode或uv run sas-mcp-login,然后由 MCP 客户端管理服务生命周期。 - 需要安全的交互式身份验证? 使用 HTTP——不存储密码,每位用户都通过浏览器进行身份验证。
- 要为团队或服务器部署? 使用 Docker——便于移植,主机无需安装 Python,且易于与编排工具集成。
- 要为整个组织运行? 使用 Kubernetes——deploy/ 中提供了示例清单和 Helm chart,其中包含 OAuth 流程所需的路由配置,可使用 Contour(该 chart 的默认选项,也是唯一能在现有主机名下通过路径前缀挂载服务的选项)或 ingress-nginx。
- 使用 Gemini CLI? 使用 stdio——Gemini CLI 不支持 HTTP 模式或基于浏览器的 OAuth。请参阅 Gemini CLI configuration。
- 要与 Microsoft 365 Copilot 集成? 使用 Kubernetes(或任何远程 HTTPS 部署)——Copilot 声明式 Agent 只能访问远程托管的 MCP 服务。可直接侧载的 Agent 包和操作指南见 examples/m365-copilot/。
- 要将其添加到 Microsoft Copilot Studio Agent? 同样使用远程 HTTPS 部署,并设置
MCP_TOOL_RENAME=catalog_=infocat_——Copilot Studio 的 Agent 运行时无法处理以catalog_开头的工具名称。具体步骤见 examples/copilot-studio/。 - 不确定该选择哪种 Microsoft 方案? examples/microsoft-copilot.md 对比了声明式 Agent 和 Copilot Studio Agent,并展示了同时支持两者的部署配置。
- 要从客户端的服务目录安装? 这种方式会以 stdio 模式(
app-stdio)运行已发布的容器,而非作为 HTTP 服务运行,因此会使用~/.sas令牌缓存进行身份验证——必须将该缓存挂载到容器的/app/.sas。
限制公开的工具(分层)
工具按编号分层。默认情况下,服务会公开所有工具;设置 MCP_TIERS 可仅公开部分工具层,便于精简客户端的工具列表,或隐藏部署不应提供的功能。支持范围和逗号分隔列表(例如 MCP_TIERS=0-4 或 MCP_TIERS=0,1,6,7);未设置时表示所有层。
| 层 | 分组 |
|---|---|
| 0 | 计算上下文与代码执行 |
| 1 | 数据发现 |
| 2 | 数据操作与文件 |
| 3 | 报告与可视化 |
| 4 | 批处理作业与异步执行 |
| 5 | 自动化机器学习 |
| 6 | 模型管理与评分 |
| 7 | 决策基础(SAS Intelligent Decisioning) |
| 8 | Workbench(仅执行代码) |
| 9 | 业务术语表(SAS Data Governance) |
| 10 | 高级决策(SAS Intelligent Decisioning)——需要第 7 层 |
# Example: expose only compute/discovery/data-ops and reporting
MCP_TIERS=0-3 uv run app
只读模式
设置 MCP_READ_ONLY=true,仅公开不会更改服务端状态或触发服务端工作的工具——共 115 个工具中的 57 个。被排除的工具不会注册,因此会完全从客户端的工具列表中消失:模型看不到它们,也就无法尝试调用。
这是对工具层的筛选,而非独立的一层——读写划分横跨每一层(第 3 层同时包含 get_report 和 delete_report)。这两个设置可以组合使用:
# Every read tool, all tiers
MCP_READ_ONLY=true uv run app
# Read tools of the reporting and decisioning tiers only
MCP_TIERS=3,7 MCP_READ_ONLY=true uv run app
定义采用严格标准:只有既不会写入也不会启动工作的工具才符合条件。除显而易见的创建、更新和删除工具外,以下工具也会被排除:
| 排除的工具 | 原因 |
|---|---|
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,并且有测试断言该列表涵盖所有已注册工具,因此新添加的工具不会在只读模式下被悄然放行。
工具注解(告知客户端的信息)
同一分类会通过每个 tools/list 条目上的 MCP 工具注解告知所有客户端,无论是否启用只读模式:
| 提示 | 来源 |
|---|---|
readOnlyHint | 与上述只读工具集合完全一致——统一使用同一张表,因此告知客户端的信息与 MCP_READ_ONLY 的执行规则不会出现偏差 |
destructiveHint | 能移除或覆盖现有状态的工具:任意代码(execute_sas_code、submit_batch_job)、delete_*、cancel_job、reset_compute_session、update_* PUT 请求、apply_report_operations、create_report/copy_report(其 replace 冲突策略)、publish_ml_champion_model |
idempotentHint | 读取操作、update_* PUT 请求、删除操作、cancel_job、reset_compute_session、promote_table_to_memory |
openWorldHint | 仅限可访问 Viya 外部资源的工具:任意代码和上传工具的 url 来源 |
客户端会利用这些提示来设计审批体验,例如,Claude 会将只读工具归为一组,以便一键审批,并在调用破坏性工具前发出警告;也会据此决定何时中断用户。这些只是提示,并非强制措施:规范要求客户端除非信任服务端,否则应将这些提示视为不可信信息;MCP_READ_ONLY 仍是服务端控制手段。如果没有注解,客户端必须对每个工具采用规范中较为保守的默认假设(可写、具破坏性、可访问开放世界),因此这些注解只会减少操作阻碍。浏览器落地页也会根据相同的提示为每个工具标记 read-only / write / destructive。
交互式视图(MCP Apps)
有些结果即使用工具精心整理,作为文本阅读起来仍然很糟:一百行表格、SAS 日志,或一整张表单的类型化属性。因此,有十个工具还带有一个小型 HTML 视图,使用 MCP Apps 扩展,由支持该扩展的客户端在结果旁的沙盒框架中渲染:
| 视图 | 工具 | 功能 |
|---|---|---|
| 数据网格 | query_data、get_castable_data、get_compute_table_data | 对行排序、筛选和分页。分页会从视图再次调用同一工具,因此用户可以浏览大型表格,而模型只需保留第一页。 |
| SAS 日志 | execute_sas_code、get_job_log、submit_batch_job | 为 ERROR / WARNING / NOTE 行着色,跳转到下一个问题,提供仅显示问题和隐藏提示的筛选器;可在单独的标签页中查看 listing,并在 Results 标签页中查看 SAS 自带的 HTML 输出(参见 HTML 结果)。提交批处理作业后,视图会持续轮询,直到作业结束,然后获取其日志。 |
| 术语表术语编辑器 | get_glossary_term_type、get_glossary_term | 根据术语类型生成表单——布尔值使用真正的复选框,日期使用日期选择器,多选值使用多选控件——从而避免属性值输入错误。创建或更新术语,并告知助手已保存的内容。仍处于草稿状态的术语可以在此发布,这是 API 允许发布术语的唯一方式。 |
| 术语表浏览器 | list_glossary_terms | 在详情窗格旁显示可浏览的完整术语表树:可搜索名称、定义、描述和属性值;可按术语类型或“有资产”筛选;还可查看面包屑、子项卡片、属性、已分配的资产,以及层级旭日图。拖动分隔线即可调整树形窗格的大小,也可以将其完全隐藏。列表工具自带的筛选条件会作为初始筛选条件;其余术语表内容由视图分页加载,因此模型仍只保留第一页。草稿只有作者能看到,因此你通常会在树中发现它;之后可在详情窗格中发布。 |
| 术语表导入 | import_glossary_terms | 当 dry_run=true 时,按即将提交的顺序显示各行,并解析父级路径,将 CSV 自带的 Definition 和 Description 列分别保留,同时提供导入按钮。实际导入后,会显示每行的处理结果以及该行对应术语的 ID,包括术语是新建的还是已存在的;无论哪种情况,导入作业本身都会将其计为成功。 |
每个视图都有一个 ⤢ 按钮,可在宿主支持时(Claude 支持)将视图全屏打开;宽表格或长日志就适合在全屏模式下阅读。不支持该功能的宿主不会显示此按钮。
这些功能都是增补性质的。工具的返回值保持不变,因此没有该扩展的客户端——Claude Code、脚本或旧版客户端——看到的内容与之前完全相同。视图发出的每个请求都会经由宿主,以携带会话令牌的普通工具调用形式发送到此服务;浏览器不会直接与 Viya 通信。部署通过 MCP_TIERS 或 MCP_READ_ONLY 禁用的工具也不会提供视图;视图中任何原本会调用该工具的控件也同样不会显示。因此,只读部署会显示术语表浏览器,但不显示 Publish 按钮,而不会显示一个注定失败的按钮。页面内容全部内嵌——包括供应的 @modelcontextprotocol/ext-apps 桥接代码——因此即使宿主忽略 CSP 声明,或 Viya 处于气隙环境中,也能正常渲染。MCP_APPS=false 时不会注册任何视图。
视图是否渲染,取决于客户端以及客户端的连接方式:
| 客户端 | 视图 |
|---|---|
| ChatGPT、Microsoft 365 Copilot、VS Code with GitHub Copilot、Cursor、Goose | 可渲染 — 这些客户端实现了该扩展。 |
| 通过 自定义连接器 连接到 HTTP 服务的 Claude(Web、Desktop、Cowork) | 可渲染,包括 SAS 日志视图的 Results 选项卡。该连接器使用 2026 年协议修订版,其握手不包含会话,因此服务需要设置 MCP_STATELESS_HTTP=true,并使用 Anthropic 的服务器可以访问的 URL。 |
在 claude_desktop_config.json 中配置了该服务的 Claude Desktop(仅接受 stdio 服务) | 自 Claude Desktop 2.2553(2026 年 9 月 22 日)起不再渲染。 Desktop 会通过一个桥接程序将本地服务的工具传递给聊天,而该桥接程序会重新构建每个工具的元数据并丢弃视图绑定,因此聊天不会请求该页面。工具仍照常工作;结果为文本,execute_sas_code 仍会返回其 HTML 结果链接。已在 anthropics/claude-ai-mcp#1069 报告。 |
| Microsoft Copilot Studio Agents | 不可渲染 — Agent 运行时未实现该扩展(它不会声明任何 UI 功能,也不会读取视图)。execute_sas_code 仍会返回 HTML 结果链接。 |
| Claude Code | 不可渲染 — 按设计仅提供文本。 |
视图自身的控件会调用其他工具(Results 选项卡通过 download_file(Tier 2)读取页面),因此,屏蔽这些层级的部署会提供视图,但不包含该控件。视图 URI 包含页面的指纹(ui://sas-viya/sas-log/execute_sas_code.<hash>.html),会随着服务版本、页面文件和层级选择而变化,因为主机会按 URI 缓存页面 — claude.ai 甚至会在移除并重新添加连接器后继续缓存;同时也会提供普通 URI,以供持有较早工具列表的主机使用。
HTML 结果
execute_sas_code 会以文本形式返回 SAS 日志和列表输出,供模型读取。默认情况下,它还会生成 SAS Data and AI Studio 会显示的页面(其中的表格由 ODS 设置样式,图表也会绘制),并返回该页面的链接:
- 原理。 计算上下文不会自行打开 HTML 目标,因此服务会在
ods html5语句与其关闭语句之间运行代码。在关闭语句之前会插入;*';*";*/;run;quit;,以结束代码中任何未关闭的内容(未终止的语句、引号或注释,或未执行run;的步骤),确保关闭语句仍能运行。模型读取的日志中不会出现这些内容。html_results=false则会按原样提交代码。 - 链接。 代码有输出时,页面会保存到 Viya Files 服务,结果中会增加
html_results_url。在浏览器中打开链接时,系统会要求你登录 SAS Viya;该文件不属于任何文件夹,因此 Viya 的默认规则只允许运行代码的用户(以及管理员)打开它。页面会以 Files 服务的默认设置保存,不设过期时间,因此会一直保留,直到有人将其删除。 - 在 SAS 日志视图中,该页面会显示为 Results 选项卡;如果代码运行成功,它会首先显示。视图通过
download_file获取页面,因此不包含 Tier 2 的部署会提供链接,但不会显示该选项卡。 - 成本。 打开和关闭目标会使作业耗时增加约十分之一秒,保存页面则会多产生一个请求。页面大小为 40–70 KB,且大部分内容是 ODS 样式表;它不会进入模型的上下文,只有链接会进入。
可用工具
以下标题与上文编号的 层级 相对应,因此 MCP_TIERS 可直接映射到你公开的工具(例如,MCP_TIERS=0-3 会启用 Tier 0–3)。
第 0 层 — 计算上下文与代码执行
- execute_sas_code:执行 SAS 代码片段并获取执行结果(日志和列表输出),还会提供指向 HTML 结果 的链接,除非设置
html_results=false。在可复用的用户专属计算会话中运行,该会话会在多次调用之间保持活跃,因此 SAS 状态(WORK 表、宏变量、已分配的 libref)会在连续调用之间保留——使用 reset_compute_session 可重新开始。 - list_compute_contexts:列出可用的计算上下文
- reset_compute_session:删除指定上下文的缓存计算会话,丢弃其 SAS 状态,并强制下次调用时启动新会话
第 1 层 — 数据发现
SAS 数据治理(元数据发现与分析):
- catalog_search:使用 SAS 目录搜索语法(自由文本、
AssetType:Report等分面、范围)搜索目录中的资产(表、列、报告等)。每个结果都包含resource_uri,可传递给匹配的工具(例如get_report、get_castable_data)。 - catalog_search_helper:了解如何查询目录——列出可用分面,或列出某个分面的有效值,以便构建精确的
catalog_search查询。 - catalog_find_instance:根据源资产的
resource_uri解析目录 实例,将搜索结果连接到分析和下载工具,无需手动处理实例 ID。 - catalog_run_adhoc_analysis:为表提交临时分析任务。默认启用 NLP 增强(语言、情感、语义 ID),并填充
informationPrivacy、nlpTerms、nlpTags和mostImportantFields。 - catalog_get_adhoc_analysis:轮询分析任务并交叉核对目标实例;当结果已写入资产后报告
profile_ready,避免过早启动下载。 - catalog_download_table_profile:以 CSV 格式下载表的数据字典和列分析,可通过
instance_id或resource_uri指定表。 - catalog_list_agents:列出目录的发现 Agent(用于填充元数据的爬虫)。
- catalog_run_agent:启动发现 Agent 运行(异步),以爬取其数据源并刷新目录元数据。
- catalog_get_agent_history:检查 Agent 的运行历史,包括状态以及每次运行枚举/添加/更新/删除了多少元数据。
CAS 数据(内存中):
- list_cas_servers:列出可用的 CAS 服务
- list_caslibs:列出服务器上的 CAS 库
- list_castables:列出 CAS 库中的表
- list_source_tables:列出尚未加载到内存的源表(可提升的候选项)
- get_castable_info:获取表元数据(行数、列、大小)
- get_castable_columns:获取列名、类型、标签和格式
- get_castable_data:从 CAS 表中获取样例行
- query_data:针对 CAS 或计算数据运行 FedSQL
SELECT并获取结果行——统一查询两种存储层的 SQL 接口。通过target选择存储层(cas对应caslib.table,compute对应libref.table);支持联接、子查询、聚合和UNION,且工具会在服务端应用行数上限(你编写的LIMIT会被忽略,因为 CAS 会静默丢弃格式错误的LIMIT)。也可选择返回CREATE VIEW形式的查询文本,供你自行运行。仅支持读取:写入操作会在预检阶段被拒绝;由于宏处理器会在 SQL 外展开 SAS 宏,因此也会拒绝 SAS 宏触发符(%/&)。请注意,不能在一条语句中联接这两个存储层。
计算库(SAS/Compute,在计算上下文中):
- list_compute_libraries:列出计算上下文中已分配的 SAS 库(libref)
- list_compute_tables:列出计算上下文中 SAS 库的表
- list_compute_columns:列出 SAS 库中某个表的列
- get_compute_table_data:从 SAS 库中的表获取一页行,值的格式与 SAS 显示的格式一致——这是计算层对应的
get_castable_data
第 2 级 — 数据操作与文件
- upload_data:将数据文件上传到 CAS 表 — 在服务端读取,因此数据不会经过模型的上下文 — 文件来源可以是
file_path(服务端从磁盘读取)或url(服务端获取文件,并将其转换为端点要求的 multipart 上传格式)。支持 casManagementuploadTableAPI 接受的格式 — csv、tsv(csv + 制表符分隔符)、xls、xlsx(单个工作表)、sas7bdat、sashdat — 根据扩展名自动检测格式,也可以通过data_format指定。该端点不接受 parquet,会提前拒绝并提供说明(通过基于路径的 caslib 加载,再使用promote_table_to_memory,或转换为 csv/sas7bdat)。 - upload_inline_data:根据以内联字符串传入的 csv/tsv 文本创建一个小型 CAS 表(例如,模型即时构建的查找/映射表,或用于快速测试的表)。载荷会经过模型的上下文,因此仅适用于极小的表 — 对于文件或更大的内容,请使用 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:下载文件内容
- find_folder:按路径(
/Public/Content/Decisions、My Folder、My Folder/Risk)、ID 或 URI 查找 SAS Content 文件夹,并返回其 ID、URI、名称和完整路径 — 可用于确认用户指定的文件夹,或获取upload_file和MCP_DEFAULT_FOLDER所需的 URI
第 3 层 — 报告与可视化
- list_reports:列出 Visual Analytics 报告
- get_report:获取报告元数据和定义
- export_report:以 VA 服务支持的任意格式导出报告(或特定报告对象)——
package(zip)、pdf、png、svg、csv、tsv、xlsx或summary。文本格式会以内嵌形式返回,png作为图像内容返回,二进制格式(package/pdf/xlsx)则作为带有正确 MIME 类型的嵌入文件返回。 - 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)。使用addPage的title字段为页面指定标题(页面主体顶部的文本区——VA 页眉仅支持控件);添加时通过options.object.title为每个图表指定标题;使用放置方式排列对象——page、relativeToObject(用于列、行和网格的左/右/上/下位置)、container(将对象分组到standardContainer中),或report(new_page可在行内创建并命名页面,用于在单批处理中构建多页报告)。该批操作是原子的。操作前会根据目录验证每项操作、对象键和放置方式(一次报告所有错误);支持dry_run,处理 ETag 并发握手;并且使用save_as=true和result_report_name/result_folder时,会将该批操作另存为新报告,源报告保持不变。仅标志本身决定模式:不带该标志时会就地编辑报告;未带标志却提供名称或文件夹时会拒绝执行,而不会采取操作。典型循环:describe_report_objects→get_castable_columns→apply_report_operations→get_report_outline/export_report(逐页导出 png)以进行验证。 - get_report_outline:读取报告结构——页面 → 对象,并返回其他工具所需的标识(对象
name用于放置/updateObject目标,label用于export_report,页面label用于页面放置)。 - copy_report:将报告复制为新报告(可选重命名/更改文件夹)。与
changeData操作配合使用,可实现复制并替换模式。 - delete_report:删除报告及其内容。
第 4 层 — 批处理作业与异步执行
- submit_batch_job:提交 SAS 作业以异步执行
- get_job_status:检查作业状态
- list_jobs:列出最近的/正在运行的作业
- cancel_job:取消正在运行的作业
- get_job_log:获取作业日志
第 5 层 — 自动化机器学习
- list_ml_projects:列出 AutoML 项目
- create_ml_project:从已加载的全局作用域 CAS 表(caslib + table + 可选 CAS 服务器)创建新的 AutoML 项目
- run_ml_project:运行管道自动化
- register_ml_champion_model:将 AutoML 项目的冠军模型注册到 Model Repository
- publish_ml_champion_model:将 AutoML 项目的冠军模型发布到评分目标
第 6 层 — 模型管理与评分
- list_registered_models:列出仓库中的模型
- list_publishing_destinations:列出可用的评分/发布目标,供 publish_ml_champion_model 使用
- list_mas_modules:列出已发布的 MAS 模块
- get_mas_module_step_signature:在评分前检查已发布 MAS 模块步骤的输入/输出变量签名
- score_data:根据已发布的模型或决策对数据评分;对于从 Intelligent Decisioning UI 发布、输入变量名带有结尾下划线的决策,可使用不带下划线的名称,系统会进行映射(
inputs_renamed)
第 7 层 — 决策基础(SAS Intelligent Decisioning)
构建并运行 SAS Intelligent Decisioning 决策——包括查询查找表的规则集,以及结合模型、分支、条件、赋值和子决策的决策流——然后将决策流发布到 Micro Analytic Score(MAS),以便 score_data 执行。生命周期工具可读取、锁定、复制和删除各种决策内容。分段树、代码文件、值列表和自定义函数使用 第 10 层编写;如需使用全部功能,请同时启用两层(MCP_TIERS=...,7,10)——启用第 10 层而未启用第 7 层时,服务器会记录警告。
规则集和决策流始终存储在 SAS Content 文件夹中。创建工具接受 folder 参数——可以是 /Public/Content/Decisions、My Folder 或 My Folder/Risk 这样的路径、文件夹 ID 或文件夹 URI;如果未提供,则使用部署的 MCP_DEFAULT_FOLDER。两者都未提供时,工具会拒绝创建,并要求模型询问用户将资源存储在哪里。更新不会改变资源所在的文件夹;对于以前无需指定文件夹即可创建的资源,下次更新时会将其归入指定文件夹或默认文件夹。每个创建和更新结果都包含 folder,其中记录资源所在的路径。
业务规则 — 规则集:
- 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 目标,轮询直至完成,并返回服务器生成的 MAS
moduleId(可直接用于 get_mas_module_step_signature / score_data)。代码按 MAS 要求生成,符合 SAS Intelligent Decisioning 的发布方式,因此查找表可以正常工作;模块的输入保留决策中的变量名称(UI 会在变量名末尾添加下划线,例如credit_score_) create_decision_flow 和 update_decision_flow 接受steps,每个步骤都会说明自身类型,由服务端负责接入:{"type": "rule_set" | "segmentation_tree" | "code_file" | "decision", "id": ...}(子决策也是decision)、{"type": "model", "id": <model repository id>}、{"type": "assignment", "assignments": {"band": "GOLD"}}、{"type": "condition", "expression": "score >= 630", "on_true": [...], "on_false": [...]}和{"type": "branch", "branch_type": "range" | "equals" | "like", ...}。引用对象的最新锁定修订版会被使用(如果没有锁定修订版,则会锁定一个);步骤术语会映射到同名决策变量。若决策中没有对应术语的变量,则会将该术语添加为具有相应类型和方向的变量,因为只有映射了所有术语,Intelligent Decisioning 才会验证并发布步骤。映射不会跨类型系列。赋值用于设置常量(在规则集或代码文件中计算);模型通过其模型存储库 ID 引用,其输出会成为决策变量;范围分支采用包含边界的比较(>= min、<= max),且各个案例的值不得重复;步骤可以嵌套在分支案例和条件中。工具描述中包含每种情况的完整示例。rule_set_steps仍可用于仅包含规则集的流程。结果中的steps_report会列出所用修订版、新增变量以及需要检查的内容。
内容 — 所有类型共用一个生命周期: asset_type 可以是 rule_set、decision、segmentation_tree、code_file、value_list、lookup_table、custom_function 或 function_category。
- list_decisioning_assets / get_decisioning_asset / delete_decisioning_asset:列出、读取(包括所在文件夹;规则集包含其规则,代码文件包含其代码,值列表包含其条目,查找表包含其版本和活动条目;超过 150,000 个字符的内容会被摘要)和删除上述任意类型的资源——如果规则集正在使用某个查找表,则会拒绝删除并列出相关规则集,因为 Viya 会删除该查找表,导致这些规则失效
- get_decisioning_asset_code:获取 Viya 为规则集、决策或分段树生成的 DS2,或获取代码文件的源代码
- list_decisioning_asset_revisions / lock_decisioning_asset_revision:列出规则集、决策、分段树和代码文件的修订版。锁定会冻结当前状态并开启下一个修订版;结果会说明锁定的是哪个修订版
- copy_decisioning_asset:将规则集(及其规则)、决策、分段树、代码文件、值列表或查找表复制到某个文件夹
- validate_decision_expression:根据签名编译 DS2 表达式(规则条件或操作、分支、条件步骤),并返回编译器报告的错误行,以便在将其加入规则集或决策之前进行检查
查找表 — 键及其对应的值,以及规则如何使用这些值:
lookup条件用于测试变量的值是否为某个键,lookupValue操作用于为某个键赋值。create_business_rule / update_business_rule 按名称接收查找表并解析其 ID(没有 ID 的引用会被存储为无效),并在problems中报告 Viya 存储为无效的条件或操作。规则会读取查找表的活动版本;激活操作会将其发布到 MAS 和 CAS;已发布的决策在下次调用时会使用新激活的条目,无需再次发布。 - get_lookup_table:版本(当前活动版本、激活失败的版本及失败原因)、某个版本的条目(支持分页和按键筛选),以及使用该表的规则集
- create_lookup_table:在文件夹中通过
{"key": "value"}或条目列表创建查找表,可选设置列标签;activate会立即发布 - update_lookup_table:添加或覆盖条目、移除键,或替换全部条目;重命名;重新标记。活动版本永远不会被修改——系统会以该版本为基础创建新版本,而规则会继续使用活动版本,直到新版本被激活(
activate会在同一次调用中完成此操作) - activate_lookup_table:将某个版本设为活动版本,并等待发布完成(状态为
active、running或failed,并附带失败原因);较早的版本(回滚)或激活失败的版本会作为新版本,连同其条目一起激活;republish会将活动版本再次复制到 MAS 和 CAS
第 8 层 — Workbench(仅执行代码)
- execute_sas_code:执行 SAS 代码片段并获取执行结果(日志和列表输出);除非设置
html_results=false,还会提供HTML 结果链接。代码在可复用的计算会话中运行,该会话会在多次调用之间保持运行状态,因此 SAS 状态(WORK 表、宏变量、已分配的 libref)会在连续调用之间保留
第 9 层 — 业务词汇表(SAS 数据治理)
阅读和编写 SAS 业务词汇表,并将术语关联到其描述的列。第 1 层会告诉你某列名为 CD_NAC_RSK;本层会告诉你它的含义以及由谁定义。
开始之前,有关词汇表的两点值得了解,因为它们在原始 API 中都不可见,并且这里会为你处理:
- 一个术语有两个 ID。 它既是一个 Glossary 对象,也是一个 Catalog 实体,两者的标识符不同。每个工具都会返回两者——
term_id(词汇表)和catalog_entity_id(目录)——因此你不必判断手中的 ID 属于哪一类。 - 自定义属性以 UUID 键存储。 这些工具会按词汇表 UI 显示的标签读取和写入属性(
{"Scope": "Group"}),并在调用前验证必填属性和单选值。
字典:
- search_glossary_terms:按术语名称和定义进行自由文本排序搜索——知道词语但不知道 ID 时可从这里入手。会报告
assigned_asset_count,以便查看某个术语是否确实在使用中 - list_glossary_terms:精确的结构化列表——可按术语类型、父级(权威层级)或名称片段筛选。
include_attributes会返回每个术语的属性值(免费——列表本身已包含这些值),而attribute_filter仅保留匹配条件的术语,例如{"Used in Risk": true}。词汇表无法在服务器端按属性筛选,因此此筛选会在此处应用,结果还会报告扫描了多少词条 - get_glossary_term:完整返回单个术语,自定义属性以名称而非哈希值显示
- list_glossary_term_types / get_glossary_term_type:可用的术语类型,以及该类型术语必须满足的属性约定——编写术语前请调用后者。每个属性都会注明 Viya 接受的唯一值格式,而 API 本身对此没有任何说明 让术语与数据关联:
- list_term_assets:术语关联到的列及其所属表。回答“此术语用在何处?”的权威依据。
- list_table_terms:反向查看——列出表中的每一列及其关联术语,并内联显示术语定义。最快了解一张表是否受治理的方式
编写:
- create_glossary_term:创建术语。默认发布——底层 API 除非另有说明,否则会创建不可见的草稿;之后可通过
update_glossary_term(publish=true)将其发布 - import_glossary_terms:一次调用即可创建多个术语及其层级关系。子术语通过名称指定父术语,无需提供父术语的 ID,因此行可以按任意顺序提供,层级之间也无需传递 ID;每行的失败会单独报告。返回每行术语的
term_id,因此下一步无需查询;同时区分真正新建的行和术语已存在的行——导入任务会将两者都计为成功。每行会整体写入,因此update_existing会替换该路径下的术语,而不是合并。dry_run=true会显示解析后的行,但不执行导入——交互视图会将其显示为带有 Import 按钮的表格 - update_glossary_term:更改术语文本、父级或属性。会合并到当前术语中,因此省略的字段会保持不变,而不会被清空;
parent_id会将其移至层级中的其他位置,publish会发布草稿。由于草稿在 API 中是独立资源,此操作会据此路由写入——否则编辑草稿只会失败并返回一个没有详细信息的 404 - delete_glossary_term:永久删除术语及所有引用它的关联。不会级联删除——若术语还有子项,则会拒绝删除,因此请从子树末端开始逐层删除
- assign_glossary_term / unassign_glossary_term:将术语关联到表列,或解除关联。这一步会让术语开始治理数据——没有关联资产的术语不会治理任何内容
设计词汇:
- create_glossary_term_type / update_glossary_term_type / delete_glossary_term_type:定义创建术语所依据的模板——包含哪些自定义属性、哪些属性为必填,以及每个属性接受哪些值。编辑时会根据标签匹配属性,并保留每个属性的标识符,因此已携带某个值的术语不会丢失该值——若要重命名某个属性,请同时提供其
attribute_id和新标签,因为新标签无法匹配任何内容,否则会创建一个新的属性;只要仍有术语使用该类型,就会拒绝删除
通过这种方式关联的术语也可以通过 Tier 1 的 catalog_search 搜索:在 datasets 索引上使用 Column.term:"<term name>" 分面,即可返回带有该术语的表,无需解析具体列。
Tier 10 — 决策高级功能(SAS Intelligent Decisioning)
SAS Intelligent Decisioning 中超出规则集范围的内容,可用于 Tier 7 的决策流:分段树(手动编写或根据策略表构建)、值列表、DS2、Python 和 SQL 代码文件,以及规则表达式调用的 DS2 自定义函数。所有内容都存储在文件夹中,与 Tier 7 一样。要将此层创建的内容用作决策步骤,并读取、锁定、复制或删除这些内容,需要启用 Tier 7,因此请同时启用两者;如果只启用 Tier 10,服务器会在启动时记录警告。
分段树:
- create_segmentation_tree / update_segmentation_tree:编写一棵树:节点按顺序将变量与值(
"A;B")、比较条件(">=630")、范围("600<=v<630")或"Other"进行比较;结果可为变量赋值或运行 DS2。更新时仅替换所提供的部分 - create_segmentation_tree_from_table:根据策略表构建一棵树——每个分支对应一行,每个决策键对应一列——与 FICO 风格的策略导出文件(TRIAD、Blaze)所描述的策略相同。按列顺序测试键,且仅测试会产生分支的键;值为范围下界(
split="lower_bound")或精确值。可读取内联行、CSV 或 CAS 表(使用 upload_data 加载 Excel 工作表),可为每个变量创建值列表,并报告叶节点、结果,以及路径相同但结果不同的行
值列表、代码文件和自定义函数:
- create_value_list / update_value_list_entries:值列表可包含值或数值范围(
"v>=630");生产环境中的版本保持不变,新版本会使用这些条目 - create_code_file / update_code_file:DS2、Python 或 SQL 代码文件;Viya 会从代码中读取签名,而
signature用于提供 Python 无法声明的类型 - create_custom_function / update_custom_function:供规则表达式调用的 DS2 自定义函数;先检查能否编译。如果指定的类别不存在,则会创建该类别
- validate_custom_function:编译自定义函数但不保存,并返回编译器报错的行
提示词模板
- debug_sas_log:分析 SAS 日志并解释错误的根本原因
- 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:指导你从 CAS 表构建精美的多页 Visual Analytics 仪表板,采用“发现 → 整理 → 组织 → 润色 → 验证”的方法,涵盖报表创作工具
MCP 客户端配置
examples/ 文件夹中提供了配置示例。下面是常用客户端的快速入门代码片段。
提示——在浏览器中打开端点。 在 HTTP 模式下,将浏览器指向 MCP URL(例如
http://localhost:8134/mcp,或已部署服务的https://<host>/mcp),会显示一个落地页,而不是单纯的401:页面会说明服务是什么、连接到哪个 SAS Viya、此部署开放的工具层级(每个工具附有一行摘要),并提供 Claude Code、VS Code、Cursor、Claude connectors 和通用mcp.json客户端可直接复制的配置——其中已填入部署的实际 URL。只有普通浏览器GET(Accept: text/html)请求会以这种方式响应;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 调用可能比 Gemini CLI 默认的 10 秒更耗时。建议设置为60000(60 秒)。将cwd设置为sas-mcp-server检出目录的绝对路径。
示例
通过 MCP 工具执行 SAS 代码:
data work.students;
input Name $ Age Grade $;
datalines;
Alice 20 A
Bob 22 B
;
run;
proc print data=work.students;
run;
如需了解更多详情、配置选项和部署选项,请参阅 examples 文件夹,并按照其中列出的说明操作。
采集模式(使用情况遥测)
一种自愿选择加入、默认关闭的模式,用于记录服务器的实际使用情况——使用了哪些工具、实现什么目标、输入了什么,以及哪些方面还不够完善。它服务于两类用户:
- 向维护者提供结构化反馈的贡献者。 无需提交文字版错误报告,你可以暂时启用此模式,然后分享生成的日志,让维护者了解哪些工具正在使用、哪些工具会失败,以及哪些目标还没有合适的工具——这些信息可以直接用于改进现有工具和发现新工具。
- 为自己的用户运行服务器的组织。 在内部部署 MCP 服务的团队可以启用此模式,了解用户如何使用该服务以及使用目的,同时所有数据都留在自己的基础设施内。
该模式通过 FastMCP 中间件封装器(telemetry.py + usage_logger.py)实现,无需更改任何工具。
🔒 任何数据都不会自动发送到其他地方。 采集模式只会将内容追加到运行服务器的机器上的本地日志文件中。除非你明确启用,否则该模式处于关闭状态;即使启用,数据也只会保留在你的磁盘上——与任何人分享数据(包括维护者)都需要你主动手动发送文件。此模式不会自动连接回传数据,不会通过网络传输数据,也不涉及任何第三方。
启用后,此模式会执行两项操作:
-
向每个工具的架构注入必需的
goal参数,要求模型用一句话说明它在当前请求中为何选择该工具。实际工具运行前,goal会从参数中移除,因此工具不会看到它。 -
每次工具调用都会向本地日志文件追加一行 JSON(JSON Lines / NDJSON,架构 v3):时间戳、运行 ID、每次运行的序列号、工具名称、目标、参数(以及用于重试分析的稳定
args_hash)、结果、状态、错误、延迟,以及调用该工具的客户端的client_name/client_version。当工具将失败声明为数据时(例如{"status": "apply_failed"},MCP 层会将其视为成功),记录中还会包含tool_status/is_tool_error/tool_message/failed_operation_index,因此可以在所有模式下分析工具层面的失败率。run_start标头记录(传输方式、pid、服务器版本、结果模式,以及可选的COLLECTION_RUN_TAG标签,用于标记 A/B 运行)会开启日志,并且每 1000 条记录重新写入一次,这样即使发生日志轮转,也不会出现一段没有标头可供解析的日志;每次写入的内容都逐字节相同,因此使用其中任意一条即可。密钥形式的键和行内 Bearer/JWT 令牌会被遮盖,错误/结果文本中的 Viya 主机名会被遮盖,并且每个字段的大小都有限制。记录按
run_id分组——每个服务器进程对应一个run_id,而不是按 MCP 会话分组。 协议正转向无会话模式(FastMCP 4 将其设为默认模式),在此模式下,session_id不存在,或按请求生成;按它分组会将每条跟踪记录拆成单次调用的片段。使用 stdio 时,一个进程服务一个客户端,因此一次运行就是该客户端的跟踪记录。使用 HTTP 时,一次运行会涵盖该进程服务过的所有客户端,而client_name/client_version是区分它们的唯一依据——使用相同客户端软件的两个用户会共用一个run_id和一个seq计数器。这是移除会话键后可接受的局限,并非设置进程级COLLECTION_LOG_PATH就能解决的问题(该设置按进程拆分,而run_id已经涵盖了这一维度)。
启用
在 .env 中设置开关(所有选项均记录在 .env.sample 中):
COLLECTION_MODE=true
# optional overrides (defaults shown):
# COLLECTION_LOG_PATH=~/.sas-mcp-server/tool-usage.log
# COLLECTION_LOG_RESULTS=failures # never | failures | always (see below)
# COLLECTION_RUN_TAG= # free-text label stamped into run_start
工具结果会根据 COLLECTION_LOG_RESULTS 记录——这是一个三态选项:never 只记录不含内容的结构摘要(类型 + 键名,例如 {"_type":"object","_keys":["status","report_id"]});failures(默认值)仅在调用出错或工具声明失败时,记录完整(经过截断和脱敏的)结果内容——这是折中方案,因为失败诊断是价值最高的跟踪数据,而且很少包含表格行;此外,在 never 模式下,成功和工具声明的失败在日志中无法区分;always 则会记录每次调用的结果内容。所有模式都会捕获参数、目标、状态、错误文本和工具声明的结果字段。(true/false 仍可分别作为 always/never 的别名使用。)
⚠️ **隐私:**启用后,日志会捕获你的工具输入(例如你提交的 SAS 代码和查询),并且在
failures/always模式下,还会记录可能包含表格行、SAS 列表和个人身份信息(PII)的实际结果数据。脱敏采用启发式规则(凭据格式的键 + Bearer/JWT + Viya 主机名),无法检测数据值中的 PII。**分享前请检查日志。**该文件仅供你的用户访问(POSIX 系统上使用 chmod 0600;Windows 上使用 icacls,尽力而为)。
性能影响
采集模式的设计目标是足够轻量,可以保持开启。在此代码库上测得的数据(已注册 45 个工具,FastMCP 3.4.2):
- 提示词 token。 注入的
goal字段会使模型看到的tools/list架构每轮增加约 +2,400 个输入 token(约 29%)。由于工具列表在会话期间保持稳定,首轮之后会从提示词缓存中提供(稳定状态下每轮约增加 240 个 token),此外模型每次调用还需输出约 15–30 个 token 来编写goal句子。这是唯一对客户端可见的开销,且仅在启用采集模式时产生。 - 每次调用的延迟。 中间件和日志记录在仅记录结构摘要的默认模式下每次调用增加 ≈1.4 毫秒(
COLLECTION_LOG_RESULTS=always时为 ≈5.3 毫秒)。JSONL 写入会交由工作线程处理,因此不会阻塞事件循环。与实际 Viya 调用(通常耗时数百毫秒至数秒)相比,这点开销可以忽略不计——启用和关闭采集模式时,实时集成测试套件的结果完全相同,开销淹没在正常的网络波动中。 - 磁盘。 仅记录结构摘要的默认模式下,每次工具调用约占 0.5–0.7 KB。日志会在达到
COLLECTION_MAX_LOG_BYTES时轮换(默认 10 MiB,约 16k 次调用),并保留COLLECTION_LOG_BACKUPS个轮换文件(默认 3 个),因此磁盘占用有上限。
服务端日志
服务端日志以一行说明运行内容开头:服务端和 FastMCP 版本、传输方式以及 SAS Viya 端点。此后,每次工具调用都会记录工具名称以及运行时所使用的 SAS Viya 用户:
Tool call: execute_sas_code (user: sasdemo)
用户是通过调用方自己的 token 请求 GET /identities/users/@currentUser 得到的 id,因此这正是 Viya 授权该调用所依据的身份;对于客户端凭据 token,该用户就是客户端的 id。每个 token 只查询一次,而非每次调用都查询;若查询失败,则记录 user: unknown,工具仍会继续运行。在共享 HTTP 部署中,这一信息可将现场报告与触发该报告的人员关联起来。
HTTP 调试跟踪
当工具失败时,模型给出的错误摘要很少会显示导致错误的请求——可能是路径错误、缺少媒体类型,或请求体格式不正确——而一次工具调用可能会发出多个请求(分页、轮询计算作业、获取其日志)。在 .env 中设置 HTTP_DEBUG=true,即可将服务器发送到 SAS Viya API 的每个请求及其响应写入单独的文件:
HTTP_DEBUG=true
# The defaults; `docker --env-file` keeps a trailing comment as part of the value, so none here.
HTTP_DEBUG_LOG_PATH=~/.sas-mcp-server/http-debug.log
# Cap per recorded body in bytes; 0 records no bodies.
HTTP_DEBUG_MAX_BODY_BYTES=4096
每次交互由两行 JSON 组成,且具有相同的 id:一条 request 记录(方法、URL、请求头、请求体)和一条 response 记录(状态码、elapsed_ms、请求头、请求体)。没有对应响应的请求表示传输过程中失败,例如超时、连接被拒绝或 TLS 错误。跟踪内容不会写入服务器日志,因此在 stdout 用于承载协议的 stdio 模式下也是安全的。
Authorization、Cookie 及其他类似凭据的请求头、查询参数和请求体键都会被脱敏,内嵌的 Bearer/JWT 字符串也会脱敏。但数据值不会脱敏:表格行和 SAS 代码会出现在请求体中,因此分享文件前请先检查。二进制请求体会记录其大小和类型,请求体大小限制为 HTTP_DEBUG_MAX_BODY_BYTES,文件轮转方式与收集日志相同。跟踪启用期间,服务器会在启动时记录警告;此功能用于故障排查,不适合在共享部署中长期启用。OAuth 登录和令牌刷新调用不会被跟踪。
测试
项目包含两类测试:单元测试(速度快,无需凭据)和集成测试(针对真实的 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外无需其他设置。
运行单元测试
单元测试会验证工具架构、请求负载和内部逻辑,不会发起任何网络调用:
./run_tests.sh # Linux/macOS (also runs ruff + pyright)
uv run python -m pytest -m "not integration" -v # any platform, incl. Windows PowerShell
此命令会运行单元测试套件并排除集成测试,这些测试随后会在摘要中显示为例如 28 deselected。这是预期行为——这些测试不应在仅运行单元测试时执行。它们只会在下方的集成测试模式中执行,因为需要连接运行中的 Viya 实例;在 not integration 运行模式下,没有任何标志可以“启用”它们。
运行集成测试
集成测试会针对实时 Viya 环境调用每个工具。测试需要凭据,可通过 .env 或 CLI 参数提供。
uv sync 会安装集成测试套件所需的所有依赖项,包括 openpyxl(用于构建 Excel upload_data 测试夹具)。它属于 test-formats 依赖组,而 [tool.uv] default-groups 默认会同步该组,因此无需额外安装。
完整测试套件(单元测试 + 集成测试) — 从 .env 读取 VIYA_ENDPOINT、VIYA_USERNAME、VIYA_PASSWORD:
./run_tests.sh --integration # Linux/macOS
uv run python -m pytest -v # any platform
通过命令行传递凭据(仅适用于封装脚本):
./run_tests.sh --integration \
--endpoint https://your-viya-server.com \
--username youruser \
--password yourpassword
使用直接的 pytest 命令时,请改为在 .env 中设置这三个变量(或在 shell 中导出)。
仅运行集成测试(跳过单元测试):
./run_tests.sh --integration-only # Linux/macOS
uv run python -m pytest -m integration --no-cov -v # any platform
pytest 标记是
integration,而不是integration-only。--integration-only是run_tests.sh封装脚本的标志;底层 pytest 标记只有integration。 运行pytest -m "integration-only"不会匹配任何标记,并会静默取消选择所有测试(0 selected)。请使用-m integration。为什么要用
--no-cov?pytest.ini强制要求覆盖率达到 90%,只有完整的单元测试套件才能达到该门槛。仅运行集成测试时,执行的代码要少得多(约 65%),因此不加--no-cov时,即使所有选中的测试都通过,pytest 也会因覆盖率不达标而以非零状态退出。run_tests.sh --integration-only会自动添加--no-cov;直接调用 pytest 时请自行添加(或使用--cov-fail-under=0)。
二进制上传格式。 Excel upload_data 集成测试使用 openpyxl 生成 .xlsx 测试夹具;它属于 uv sync 默认安装的 test-formats 组(见上文)。如果你特意不安装该组(例如运行 uv sync --no-default-groups),测试会使用 importorskip 跳过——你会看到测试标记为已跳过,而非失败。csv、tsv 和 file_path/data_format 覆盖无需额外依赖。生成 sas7bdat/sashdat 测试夹具需要 SAS 本身,因此这两种格式仅通过单元级载荷测试覆盖,不会在实时环境中测试。
115 个工具和 9 个提示词模板中的每一个都有集成测试,并由 test_every_tool_has_integration_coverage / test_every_prompt_has_integration_coverage 守卫强制检查——新增工具或提示词却未添加集成测试覆盖,会导致测试套件失败。依赖资源的测试会在实例中查找实际目标:score_data 会为最近修改的 MAS 模块评分(查找实际步骤及其输入),而 run_ml_project 会重新运行最近修改且状态为 completed 的 ML 项目。仅当实例完全没有这类资源时,它们才会 skip。同样,在未配置名为 Public 的发现 Agent 的实例上,test_catalog_agents_workflow 会以 "No discovery agent named 'Public'" 为由 skip;这是预期的跳过,并非失败。如果需要运行该测试,请让 Viya 管理员配置一个此类 Agent。
在 CI 中: .github/workflows/integration.yml 工作流会按需运行此测试套件(手动触发,或为 PR 添加 run-integration 标签),使用仓库机密,并将结果作为状态检查、固定评论和可下载的 JUnit 制品发布到 PR。结果文件会写入 reports/(已加入 git 忽略),且绝不会提交。
在本地运行(自行将结果附加到 PR): 使用 --report 运行,将 JUnit XML 和 Markdown 摘要写入 reports/(已加入 git 忽略),然后通过 GitHub CLI 将其发布到 PR——无需提交,也无需 CI:
./run_tests.sh --integration-only --report
gh pr comment <PR> --body-file reports/integration-summary.md # summary table as a comment
gh gist create reports/integration.xml # full XML as a linkable gist
GitHub 没有可将二进制文件附加到 PR 的 API/CLI(只能在浏览器中拖放上传),因此摘要会作为评论发布,原始 XML 则通过 gist 链接分享,或粘贴到折叠的
<details>区块中。若要改为从你的机器生成标准的 Actions 制品,请远程触发工作流:gh workflow run integration.yml。
测试结构
| 文件 | 说明 |
|---|---|
tests/test_tool_payloads.py | 针对所有 75 个 Tier 0-8 工具的负载断言(URL 路径、JSON 请求体、查询参数、标头),以及错误路径覆盖 |
tests/test_integration.py | 针对真实 Viya 实例的端到端工作流测试 |
tests/test_tools.py | viya_client 中通用 Viya REST 助手函数(get_json、post_json、make_client,……)的单元测试 |
tests/test_viya_utils.py | Viya 计算会话和作业编排的单元测试 |
tests/test_mcp_server.py | HTTP 身份验证中间件、健康路由和令牌获取器的单元测试 |
tests/test_config.py | 配置加载的单元测试 |
tests/test_config_oauth.py | PermissiveOAuthProxy 原始 bearer 令牌处理的单元测试 |
tests/test_auth_login.py | sas-mcp-login OAuth/PKCE 助手的单元测试 |
tests/test_stdio_server.py | 标准输入/输出令牌解析和设备代码流程的单元测试 |
tests/test_env.py | env_bool 助手函数的单元测试 |
tests/test_prompts.py | 提示词模板渲染的单元测试 |
贡献
维护者欢迎为本项目提交补丁和贡献。请阅读 CONTRIBUTING.md,了解如何为本项目提交贡献。
许可证与归属
除 /static 文件夹中的内容外,本项目采用 Apache 2.0 许可证授权。
/static 文件夹中的元素归 SAS 所有,且未依据开源许可证发布。
SAS 以及其他所有 SAS Institute Inc. 产品或服务名称均为 SAS Institute Inc. 在美国及其他国家/地区的注册商标或商标。® 表示在美国注册。
使用 SAS 软件的这些功能需另行购买 SAS 软件(例如 SAS Viya)的商业许可证,本项目不包含此类许可证。
与任何容器映像一样,直接和间接依赖项均受其各自许可证的约束。 已发布容器映像的用户有责任确保其使用符合所有适用许可证的要求。
此处提及的所有第三方商标均归其各自所有者所有,仅用于识别和参考,不表示与商标所有者存在任何关联,也不代表获得其认可。
第三方依赖项
本项目需要以下依赖项。
| 依赖项 | 许可证 |
|---|---|
| Python | Python 软件许可证 |
| FastMCP | Apache 许可证 2.0 |
| uvicorn | BSD 3-Clause 许可证 |
| starlette | BSD 3-Clause 许可证 |
| httpx | MIT 许可证 |
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。