SAS MCP Server
OfficialThe SAS MCP Server enables AI models to interact with a SAS Viya environment, executing SAS code and managing data, reports, jobs, and machine learning workflows.
Code Execution
Execute SAS code snippets and retrieve results (log and listing output)
Data Discovery (CAS Management)
List available CAS servers, caslibs, and tables
List source tables not yet loaded into memory
Get table metadata (row count, column count, size)
Get column metadata (names, types, labels, formats)
Fetch sample rows from a CAS table
Data Operations & Files
Upload CSV data into a CAS table
Promote a CAS table to global scope
List, upload, and download files in the Viya Files Service
Reports & Visualization
List Visual Analytics reports
Get report metadata and definition
Render a report section as an image (PNG or SVG)
Batch Jobs
Submit SAS jobs for asynchronous execution
Check status, list recent/running jobs, cancel a job, or retrieve its log
Model Management & Scoring
List, create, and run AutoML pipeline automation projects
List models in the Model Repository
List published scoring models and decisions (MAS modules)
Score data against a published model or decision
Prompt Templates (code generation & analysis)
Analyze SAS logs for errors with root-cause explanations
Generate data profiling, data quality, and statistical workflow code
Review, optimize, and explain SAS code block-by-block
Build production-quality SAS macros and ODS/PROC REPORT output
Enables GitHub Copilot to interact with SAS Viya, allowing AI-assisted SAS code development, execution, and analytics workflows.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@SAS MCP Serverrun a SAS program to summarize sales data by region"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
SAS MCP Server
A Model Context Protocol (MCP) server for executing SAS code, training AutoML projects, scoring models and so much more for SAS Viya environments.
Features
40+ Tools spanning the Analytics Life Cycle across SAS Viya
Prompt Templates for improving your SAS Code
OAuth2 authentication with PKCE flow
HTTP-based MCP server compatible with MCP clients
Related MCP server: Lab Virtual MCP Server
Articles & Videos
Here you can find getting articles on how to use and integrate the SAS MCP Server in different tools and what to build with it:
Connecting GitHub Copilot to SAS Viya with the SAS MCP Server
Connecting Claude Code CLI to SAS Viya with the SAS MCP Server
Getting Started
Prerequisites
Required
SAS Viya environment with compute service
Setup the Viya environment for MCP
See configuration.md
Optional
Docker: refer to docker setup
Installation
Clone the repository:
git clone <repository-url>
cd sas-mcp-serverInstall dependencies
uv syncNOTE: This will by default create a virtual environment called .venv in the project's root directory.
If for some reason the virtual environment is not created, please run uv venv and then re-run uv sync.
Usage
Configure environment variables:
cp .env.sample .envEdit .env and set
VIYA_ENDPOINT=https://your-viya-server.comStart the MCP server (see Choosing a deployment mode below):
Option A: HTTP mode (pre-run the server, connect from MCP client)
uv run appThe server will be available at http://localhost:8134/mcp by default. Authentication is handled via OAuth2 PKCE flow in the browser.
Option B: Stdio mode (MCP client starts the server on demand)
Authenticate once. Two equivalent options:
# 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-loginBoth flows write an access token to a local cache (~/.sas/credentials.json and ~/.sas-mcp-server/credentials.json respectively); the stdio server reads whichever it finds. When the token expires, re-run the same command.
Then configure your MCP client to launch the server directly (see below).
Option C: Docker / Podman (containerized deployment)
Pull the pre-built image from 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:latestOr build locally from source:
docker build -t sas-mcp-server .
docker run -e VIYA_ENDPOINT=https://your-viya-server.com -p 8134:8134 sas-mcp-serverAvailable image tags:
latest— most recent tagged release<major>.<minor>.<patch>(e.g.1.0.0) — specific release<major>.<minor>(e.g.1.0) — latest patch of a minor releaseedge— tip ofmain(unreleased, for testing)sha-<short>— pinned to a specific commit
Programmatic clients with a pre-existing Viya token
If your caller already holds a Viya access token (e.g. an automation script that obtained one via the SAS Viya CLI), start the HTTP-mode server with ALLOW_RAW_BEARER=true and pass the token directly:
curl -H "Authorization: Bearer $VIYA_TOKEN" http://localhost:8134/mcp ...The server validates the token against Viya's JWKS and uses it upstream as-is, bypassing the MCP JWT swap. The default OAuth2 PKCE flow keeps working alongside — both client types share the same /mcp endpoint.
Choosing a deployment mode
HTTP | Stdio | Docker | |
How it runs | Long-running server you start separately | MCP client spawns it on demand | Containerized HTTP server |
Authentication | OAuth2 PKCE flow (browser popup) | Cached token via | OAuth2 PKCE flow (browser popup) |
Best for | Multi-user or shared setups; production-like environments | Single-user local development; quick experimentation | Team deployments; CI/CD; environments without Python installed |
Requires | Python + uv | Python + uv (+ optional | Docker or Podman only |
Credentials stored? | No — user authenticates interactively | No — only an access token (not a password) is cached | No — user authenticates interactively |
MCP client config | Point client to | Client runs | Point client to |
Quick guidance:
Starting out or exploring? Use stdio — one
sas-viya auth loginCodeoruv run sas-mcp-login, then your MCP client manages the server lifecycle.Need secure, interactive auth? Use HTTP — no stored passwords, each user authenticates via browser.
Deploying for a team or on a server? Use Docker — portable, no Python dependency on the host, easy to integrate with orchestrators.
Using Gemini CLI? Use stdio — Gemini CLI does not support HTTP mode or browser-based OAuth. See Gemini CLI configuration.
Available Tools
Code Execution
execute_sas_code: Execute SAS code snippets and retrieve execution results (log and listing output). Runs in a reusable, per-user compute session that is kept warm across calls, so SAS state (WORK tables, macro variables, assigned librefs) persists between successive calls — use reset_compute_session to start fresh.
Data Governance (Metadata Discovery & Profiling)
catalog_search: Search the catalog for assets (tables, columns, reports, …) using the SAS catalog search grammar (free text, facets like
AssetType:Report, ranges). Each hit carries aresource_uriyou can hand to the matching tool (e.g.get_report,get_castable_data).catalog_search_helper: Discover how to query the catalog — list the available facets, or the valid values for one facet — so you can build precise
catalog_searchqueries.catalog_find_instance: Resolve the catalog instance for a source-asset
resource_uri, bridging a search hit to the profiling and download tools without handling an instance id by hand.catalog_run_adhoc_analysis: Submit an ad-hoc profiling job for a table. NLP enrichment (language, sentiment, semantic IDs) is on by default, populating
informationPrivacy,nlpTerms,nlpTags, andmostImportantFields.catalog_get_adhoc_analysis: Poll a profiling job and cross-check the target instance, reporting
profile_readyonce results have landed on the asset — so a download isn't fired too early.catalog_download_table_profile: Download a table's data dictionary and column profile as CSV, identified by either
instance_idorresource_uri.catalog_list_agents: List the catalog's discovery agents (the crawlers that populate metadata).
catalog_run_agent: Start a discovery agent run (asynchronous) to crawl its data source and refresh catalog metadata.
catalog_get_agent_history: Inspect an agent's run history — status and how much metadata each run enumerated/added/updated/removed.
Data Discovery (CAS Management)
list_cas_servers: List available CAS servers
list_caslibs: List CAS libraries on a server
list_castables: List tables in a CAS library
list_source_tables: List source tables not yet loaded into memory (candidates for promotion)
get_castable_info: Get table metadata (row count, columns, size)
get_castable_columns: Get column names, types, labels, formats
get_castable_data: Fetch sample rows from a CAS table
Data Operations & Files
upload_data: Upload a data file into a CAS table — read server-side so the data never passes through the model's context — from
file_path(the server reads it off disk) orurl(the server fetches it and converts it to the multipart upload the endpoint requires). Ingests the formats the casManagementuploadTableAPI accepts — csv, tsv (csv + tab delimiter), xls, xlsx (single sheet), sas7bdat, sashdat — auto-detected from the extension or set withdata_format. parquet is not accepted by that endpoint and is rejected up front with guidance (load via a path-based caslib +promote_table_to_memory, or convert to csv/sas7bdat).upload_inline_data: Create a small CAS table from inline csv/tsv text passed as a string (a lookup/mapping table the model builds on the fly, or a quick test table). The payload travels through the model's context, so it's for tiny tables only — use upload_data for files or anything larger.
promote_table_to_memory: Load a source table into memory at global scope (idempotent)
list_files: List files in the Viya Files Service
upload_file: Upload a file to Viya Files Service
download_file: Download file content
Reports & Visualization
list_reports: List Visual Analytics reports
get_report: Get report metadata and definition
export_report: export a report (or specific report objects) in any format the VA service supports —
package(zip),pdf,png,svg,csv,tsv,xlsx, orsummary. Text formats come back inline,pngas image content, and binary formats (package/pdf/xlsx) as an embedded file with the right MIME type.
Batch Jobs
submit_batch_job: Submit a SAS job for async execution
get_job_status: Check job state
list_jobs: List recent/running jobs
cancel_job: Cancel a running job
get_job_log: Retrieve job log
Model Management & Scoring
list_ml_projects: List AutoML projects
create_ml_project: Create a new AutoML project from a loaded, global-scope CAS table (caslib + table + optional CAS server)
run_ml_project: Run pipeline automation
register_ml_champion_model: Register an AutoML project's champion model to the Model Repository
list_publishing_destinations: List available scoring/publishing destinations, for use with publish_ml_champion_model
publish_ml_champion_model: Publish an AutoML project's champion model to a scoring destination
list_registered_models: List models in repository
list_models_and_decisions: List published MAS modules
get_mas_module_step_signature: Inspect a published MAS module step's input/output variable signature before scoring
score_data: Score data against a published model or decision
Decisioning (SAS Intelligent Decisioning)
Build and manage SAS Intelligent Decisioning rule sets and decision flows end to end, then publish a flow to Micro Analytic Score (MAS) so score_data can execute it.
Business rules — rule sets:
create_business_ruleset / update_business_ruleset / get_business_ruleset / list_business_rulesets / delete_business_ruleset: Manage rule sets (the input/output signature the rules operate on)
lock_business_ruleset_revision: Lock the current rule set state as an immutable revision (what a decision step references)
list_business_ruleset_revisions: List a rule set's locked revisions
Business rules — rules:
create_business_rule / update_business_rule / get_business_rule / list_business_rules / delete_business_rule: Manage the conditional rules inside a rule set
Decision flows:
create_decision_flow / update_decision_flow / get_decision_flow / list_decision_flows / delete_decision_flow: Manage decision flows that chain rule set steps
get_decision_flow_code: Retrieve the generated DS2 execution code for a flow
lock_decision_flow_revision / list_decision_flow_revisions / get_decision_flow_revision: Lock, list, and fetch immutable decision revisions
publish_decision_flow: Publish a locked decision revision to a MAS destination, polling to completion and returning the server-generated MAS
moduleId(directly usable with get_mas_module_step_signature / score_data)
Compute Contexts & Code Execution
list_compute_contexts: List available compute contexts
list_compute_libraries: List the SAS libraries (librefs) assigned in a compute context
list_compute_tables: List the tables in a SAS library within a compute context
list_compute_columns: List the columns of a table in a SAS library
reset_compute_session: Delete the cached compute session for a context, discarding its SAS state and forcing a fresh session on the next call
Prompt Templates
debug_sas_log: Analyze SAS log for errors with root-cause explanations
explore_dataset: Generate data-profiling SAS code
data_quality_check: Generate DQ assessment code
statistical_analysis: Set up a statistical workflow with diagnostics
optimize_sas_code: Review and optimize SAS code
explain_sas_code: Block-by-block code explanation
sas_macro_builder: Build production-quality SAS macros
generate_report: Generate ODS/PROC REPORT code
MCP Client Configuration
Example configurations are provided in the examples/ folder. Below are quick-start snippets for common clients.
VS Code / Cursor / Claude Code (.vscode/mcp.json)
HTTP mode (requires uv run app running separately):
{
"servers": {
"sas-execution-mcp": {
"url": "http://localhost:8134/mcp",
"type": "http"
}
}
}Stdio mode (starts the server on demand):
{
"servers": {
"sas-execution-mcp": {
"command": "uv",
"args": ["run", "app-stdio"],
"cwd": "${workspaceFolder}"
}
}
}Gemini CLI (.gemini/settings.json)
Gemini CLI only supports stdio mode. Add to your ~/.gemini/settings.json or project-level .gemini/settings.json:
{
"mcpServers": {
"sas-viya-mcp": {
"command": "uv",
"args": ["run", "app-stdio"],
"cwd": "/path/to/sas-mcp-server",
"timeout": 60000
}
}
}Note: The
timeoutfield (in milliseconds) is important — SAS Viya API calls can take longer than the Gemini CLI default of 10 seconds. A value of60000(60s) is recommended. Setcwdto the absolute path of yoursas-mcp-servercheckout.
Example
Execute SAS code through the MCP tool:
data work.students;
input Name $ Age Grade $;
datalines;
Alice 20 A
Bob 22 B
;
run;
proc print data=work.students;
run;For more details, configuration options, and deployment options, please refer to the examples folder and follow the instructions listed there.
Collection Mode (Usage Telemetry)
An opt-in, off-by-default mode that records how the server is actually used — which tools, for what goals, with what inputs, and where they fall short. It serves two audiences:
Contributors giving structured feedback to the maintainers. Rather than filing prose bug reports, you can turn it on for a while and share the resulting log so maintainers can see which tools are used, which fail, and what goals have no good tool yet — a direct signal for improving existing tools and identifying new ones.
Organizations running the server for their own users. Teams that deploy the MCP server internally can enable it to understand what their users do with it and why, entirely within their own infrastructure.
It is implemented as a FastMCP middleware wrapper (telemetry.py + usage_logger.py) and requires no changes to any tool.
🔒 Nothing is ever sent anywhere automatically. Collection mode only appends to a local log file on the machine running the server. It is disabled unless you explicitly enable it, and even when enabled the data stays on your disk — sharing it with anyone (including the maintainers) is a deliberate, manual step you take by sending the file yourself. There is no phone-home, no network transmission, and no third party involved.
When enabled it does two things:
Injects a required
goalparameter into every tool's schema, asking the model to state in one sentence why it chose that tool for the current request. Thegoalis stripped from the arguments before the real tool runs, so tools never see it.Appends one JSON line per tool call (JSON Lines / NDJSON) to a local log file: timestamp, session id, tool name, goal, arguments, result, status, error, and latency. Secret-shaped keys and inline Bearer/JWT tokens are redacted and every field is size-capped.
Enabling it
Set the toggle in .env (all options are documented in .env.sample):
COLLECTION_MODE=true
# optional overrides (defaults shown):
# COLLECTION_LOG_PATH=~/.sas-mcp-server/tool-usage.log
# COLLECTION_LOG_RESULTS=false # false = record result shape only, not contentsBy default (COLLECTION_LOG_RESULTS=false) tool results are recorded only as a content-free shape summary (e.g. {"_type":"array","_items":500}) — arguments, goal, status, and error text are still captured. Set it to true to capture (capped + redacted) result contents for richer analysis.
⚠️ Privacy: when enabled, the log captures your tool inputs (e.g. the SAS code and queries you submit) and — if
COLLECTION_LOG_RESULTS=true— real result data that may include table rows, SAS listings, and PII. Redaction is heuristic (credential-shaped keys + Bearer/JWT only) and does not detect PII in data values. Review the log before sharing it. The file is locked to your user (chmod 0600 on POSIX; icacls on Windows, best-effort).
Performance impact
Collection mode is designed to be cheap enough to leave on. Measured on this repo (45 registered tools, FastMCP 3.4.2):
Prompt tokens. The injected
goalfield grows thetools/listschema the model sees by roughly +2,400 input tokens (~29%) per turn. Because the tool list is stable within a session it is served from the prompt cache after the first turn (steady-state ≈ +240 tokens/turn), plus ~15–30 output tokens per call for the model to write thegoalsentence. This is the only client-visible cost and it applies only while collection mode is enabled.Per-call latency. Middleware + logging adds ≈1.4 ms per call at the shape-only default (≈5.3 ms with
COLLECTION_LOG_RESULTS=true). The JSONL write is offloaded to a worker thread so it never blocks the event loop. Against real Viya calls (typically hundreds of milliseconds to seconds) this is negligible — the live integration suite passed identically with collection mode off and on, the overhead lost in normal network variance.Disk. Roughly 0.5–0.7 KB per tool call at the shape-only default. The log rotates at
COLLECTION_MAX_LOG_BYTES(default 10 MiB, ≈16k calls) and keepsCOLLECTION_LOG_BACKUPS(default 3) rotated files, so on-disk growth is bounded.
Testing
The project includes two layers of tests: unit tests (fast, no credentials required) and integration tests (run against a real SAS Viya instance).
Running Unit Tests
Unit tests verify tool schemas, request payloads, and internal logic without making any network calls:
./run_tests.shOr directly via pytest:
uv run python -m pytest -m "not integration" -vRunning Integration Tests
Integration tests call every tool against a live Viya environment. They require credentials, which can be provided via CLI arguments or .env:
Using .env (set VIYA_ENDPOINT, VIYA_USERNAME, VIYA_PASSWORD):
./run_tests.sh --integrationUsing CLI arguments:
./run_tests.sh --integration \
--endpoint https://your-viya-server.com \
--username youruser \
--password yourpasswordIntegration tests only (skip unit tests):
./run_tests.sh --integration-onlyBinary upload formats. The upload_data Excel integration test generates its .xlsx
fixture with openpyxl. Install the optional group so it runs instead of importorskip-ing:
uv sync --group test-formats. (csv, tsv, and file_path/data_format coverage needs no
extra deps.) Generating a sas7bdat/sashdat fixture requires SAS itself, so those two
formats are covered by unit-level payload tests only, not live.
Every one of the 68 tools and 8 prompt templates has an integration test, enforced by the
test_every_tool_has_integration_coverage / test_every_prompt_has_integration_coverage
guards — adding a new tool or prompt without integration coverage fails the suite. The
resource-dependent tests discover real targets on the instance: score_data scores the most
recently modified MAS module (discovering a real step and its inputs), and run_ml_project
re-runs the most recently modified completed ML project. They skip only if the instance
has no such resource at all.
In CI: the .github/workflows/integration.yml workflow runs this suite on demand
(manual dispatch, or by adding the run-integration label to a PR) using repository
secrets, and publishes the results back to the PR as a status check, a sticky comment, and
a downloadable JUnit artifact. Result files are written to reports/ (git-ignored) and are
never committed.
Locally (attach results to a PR yourself): run with --report to write the JUnit XML
and a Markdown summary into reports/ (git-ignored), then post them to a PR with the GitHub
CLI — no commit, no CI required:
./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 gistGitHub has no API/CLI to attach a binary file to a PR (drag-and-drop upload is browser-only), so the summary is posted as a comment and the raw XML is shared via a gist link or pasted in a collapsed
<details>block. To produce the canonical Actions artifact from your machine instead, trigger the workflow remotely:gh workflow run integration.yml.
Test Structure
File | Description |
| Payload assertions for all 68 tools (URL paths, JSON body, query params, headers) plus error-path coverage |
| End-to-end workflow tests against a real Viya instance |
| Unit tests for the generic Viya REST helpers in |
| Unit tests for Viya compute session and job orchestration |
| Unit tests for the HTTP auth middleware, health route, and token getter |
| Unit tests for configuration loading |
| Unit tests for |
| Unit tests for the |
| Unit tests for stdio token resolution and the device-code flow |
| Unit tests for the |
| Unit tests for prompt template rendering |
Contributing
Maintainers are accepting patches and contributions to this project. Please read CONTRIBUTING.md for details about submitting contributions to this project.
License & Attribution
Except for the the contents of the /static folder, this project is licensed under the Apache 2.0 License.
Elements in the /static folder are owned by SAS and are not released under an open source license.
SAS and all other SAS Institute Inc. product or service names are registered trademarks or trademarks of SAS Institute Inc. in the USA and other countries. ® indicates USA registration.
Separate commercial licenses for SAS software (e.g., SAS Viya) are not included and are required to use these capabilities with SAS software.
As with any container image, direct and indirect dependencies are governed by their own licenses. Users of the published container image are responsible for ensuring that their use complies with all applicable licenses.
All third-party trademarks referenced belong to their respective owners and are only used here for identification and reference purposes, and not to imply any affiliation or endorsement by the trademark owners.
Third-Party Dependencies
This project requires the following dependencies.
Dependency | License |
Python | |
FastMCP | |
uvicorn | |
starlette | |
httpx |
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Appeared in Searches
Latest Blog Posts
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/sassoftware/sas-mcp-server'
If you have feedback or need assistance with the MCP directory API, please join our Discord server