sas-mcp
This server lets coding agents write, run, and validate SAS 9.4 code through SASPy, with log triage, schema discovery, safety guardrails, SAS environment management, and file transfer.
Run and validate SAS code: submit arbitrary SAS code via
run_sasand get a triaged verdict (ok,suspicious, orerror) with extracted notes, warnings, row counts, and output.Inspect data and libraries: list librefs, list datasets, describe columns, and sample rows to avoid hallucinated table/column names.
Compare datasets: use
compare_datasets(PROC COMPARE) to verify that a rewritten step reproduces the original result.Run assertions: use
run_sas_testswith macros like%assert_rows,%assert_no_missing, and%assert_equal_datasetsto get structured pass/fail results.Manage SAS configurations: list available SASPy configs and switch between them (
list_sas_configs,use_sas_config), plus diagnose setup withsas_doctor.Transfer files: download files written on the SAS server (
download_from_sas) and upload files from the local transfer directory (upload_to_sas), withlist_sas_filesto locate outputs.Reset and monitor sessions: check
session_status, reset WORK datasets withreset_session, and fetch the full raw log when triage isn’t enough (get_last_log).Safety controls: writes are restricted to WORK by default; guardrails block OS escapes, destructive DDL, and libref rebinding unless explicitly enabled.
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-mcprun this SAS code and check the log for errors"
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
An MCP server that lets coding agents — Claude Code, Claude Desktop, GitHub Copilot, Cursor — write, run, and validate SAS 9.4 code through SASPy.
It runs locally as a stdio subprocess on your own machine. Nothing is hosted, and your code and data never leave your environment: SASPy connects to whatever SAS you already have.
Why not just let the agent call sas.submit()?
Wrapping submit() is thirty lines. The reason this package exists is the
three layers around it:
Log triage. SAS logs are enormous and the signal is buried. Worse, SAS routinely succeeds while being semantically wrong. A misspelled variable, a many-to-many merge, a silent character-to-numeric conversion — all of these return zero errors and a wrong answer.
run_sasreturnsstatus: "suspicious"for exactly that class, so an agent can't mistake it for success.Schema discovery. Hallucinated column names are the most common way an LLM writes broken SAS.
describe_datasetremoves the guessing.Guardrails. An agent improvising
proc datasets lib=prod kill;against a production libref is a career event. Writes are restricted toWORKby default.
Related MCP server: python-executor-mcp
Install
pip install sas-mcp # or: uv tool install sas-mcpFirst run: create your SAS configuration
SASPy needs a sascfg_personal.py describing where your SAS lives. If you
already run SASPy you have one and can skip ahead — this uses it as-is.
If you don't, don't hand-write it. Run:
sas-mcp initIt asks where your SAS runs, finds a working Java runtime for you, and writes a correct config to the right place:
Where does your SAS run?
1. SAS OnDemand for Academics (free, cloud)
2. SAS installed locally on this Linux/UNIX machine
3. SAS installed locally on this Windows machine
4. SAS server on my network (IOM / Workspace Server)
5. SAS on a remote UNIX host over SSH
Choice [1-5]: 1
Which ODA home region? (shown at welcome.oda.sas.com)
1. United States (Home Region 1)
...
Found a working Java runtime: /Library/Java/.../bin/java
Wrote /Users/you/.config/saspy/sascfg_personal.py
Save your SAS credentials to /Users/you/.authinfo now? [Y/n]:For ODA and intranet IOM servers it also offers to write your credentials to
~/.authinfo (_authinfo on Windows). The password is prompted without echo
and the file is created owner-only — SASPy needs it in the clear, so
permissions are the only thing protecting it, and init sets them rather than
trusting you to remember.
Then verify:
sas-mcp doctor # is the configuration sane? (never connects)
sas-mcp check # does it actually work? (starts a real SAS session)doctor is deliberately offline, so it still works when the connection is
exactly what's broken. check runs those same checks and then connects:
[PASS] connect: Connected (SAS 9.04.01M8P02222023, encoding utf-8)
[PASS] submit: DATA step ran; WORK._SASMCP_PROBE = 19 rows.
[PASS] log_notes: Log triage is working: flagged suspicious
(missing_values_generated, uninitialized_variable).
[PASS] schema: Schema discovery works (5 columns, 19 rows).
[PASS] encoding: Non-ASCII round-trip is clean ('café').The log_notes probe is the important one. It submits code with a misspelled
variable — code that must be flagged — and fails if it isn't. A session
with NONOTES set runs everything successfully while the triage layer sees
nothing, so results look like clean successes while being wrong. A passing
submit does not prove triage works; only this does.
The encoding probe round-trips a non-ASCII string, since an encoding
mismatch corrupts character data silently rather than raising.
check uses a real SAS session, which counts against concurrency limits on
ODA and licensed servers, and it cleans up the WORK tables it creates.
sas-mcp doctor --connect is the same thing.
It can also run unattended, for scripted or team setup:
sas-mcp init --deployment oda --region us1Regions are us1, us2, eu1, ap1, ap2; your home region is shown at
welcome.oda.sas.com. init never overwrites an
existing config or credential entry without --force.
Where the config goes
init writes to your home directory, which works the same on every platform:
Platform | Location |
macOS / Linux |
|
Windows |
|
SASPy calls expanduser("~/.config/saspy/") on all platforms, so Windows uses
that same .config folder under your user directory — not AppData.
Be aware that this is the lowest-priority location SASPy searches:
An explicit
cfgfilepath (what--config-filepasses)The saspy package directory inside site-packages
The working directory (
sys.path[0])~/.config/saspy/
So a sascfg_personal.py left in site-packages or in your project folder will
silently win over your home copy. Two consequences worth knowing:
A config inside site-packages is deleted when you rebuild your virtualenv or reinstall saspy. Keep it in your home directory instead.
There is no environment variable for this. SASPy reads none when resolving a config, so
--config-fileis the only unambiguous way to pin it:sas-mcp serve --config-file ~/.config/saspy/sascfg_personal.py --config oda
sas-mcp doctor reports which file actually wins, warns when several exist,
and flags a config living somewhere a reinstall will destroy.
Check your setup first
sas-mcp doctorThis is the fastest way past the usual configuration problems, and it runs
without connecting to SAS — so it still works when the connection is what's
broken. It checks the config file and access method, the Java runtime that IOM
requires, ~/.authinfo presence and permissions, ODA hostname validity,
network reachability, and encoding. Every failure comes with the fix.
[FAIL] java: /usr/bin/java exists but no Java runtime is installed.
fix: On macOS /usr/bin/java is only a stub. Install a real JRE, e.g.
`brew install --cask temurin`, then set 'java' to the full path
from `/usr/libexec/java_home`.
[FAIL] authinfo_permissions: ~/.authinfo is readable by group or others
(mode 0o644). SASPy refuses to use it and your SAS password is exposed
to other local accounts.
fix: chmod 600 ~/.authinfoWhen anything fails, the report also links SASPy's troubleshooting guide, which covers the IOM, Java, and encryption problems this tool can detect but not fix for you.
If your password "doesn't work"
SASPy parses ~/.authinfo by requiring a line to split into exactly five
whitespace-separated fields:
<key> user <username> password <password>A password containing a space produces six fields, so SASPy skips the line entirely and reports "did not find key" — which sends you looking for a missing entry rather than a mis-parsed one. Trailing comments break it the same way.
Two fixes:
Use a password with no spaces, or
Store a SAS
PWENCODEvalue instead —{SAS004}...is always a single token, so it sidesteps the problem. These authenticate fine against both ODA and intranet IOM servers. Note it's obfuscation, not encryption: the file still needschmod 600.
sas-mcp doctor checks the field count directly and names this cause.
On Windows, also check the file's encoding. SASPy opens _authinfo with
open(pwf, mode='r') — the locale default, typically cp1252, not UTF-8. If
your editor saved it as UTF-8 and the password contains a non-ASCII character,
the bytes decode into something longer: à becomes à + \xa0, and \xa0
(NBSP) counts as whitespace to split(), so the line gains a field and is
skipped. Save the file as ANSI/cp1252, or use an ASCII-only password.
SAS encryption jars (needed for ODA)
SASPy does not ship the SAS encryption jars — sas.rutil.jar,
sas.rutil.nls.jar, and sastpj.rutil.jar are absent from a clean install,
though SASPy puts them on the IOM classpath regardless. They are a manual
download.
Whether you need them depends on the server:
SAS ODA always requires an encrypted connection. Without these jars it fails even when everything else is correct — as a Java error that never mentions a missing file.
sas-mcp doctorreports this as a failure.An intranet IOM server may not require encryption, so doctor reports it as information rather than treating a fresh install as broken.
Either way, doctor names the missing files, links the
SAS download,
and prints the exact destination. They must go in SASPy's own
saspy/java/iomclient/ directory — that path is hardcoded where SASPy builds
the IOM classpath, so no other location will be found. Doctor prints the
resolved absolute path for your install.
Connect your agent
Claude Code
claude mcp add sas -- sas-mcp serveClaude Desktop — in claude_desktop_config.json:
{
"mcpServers": {
"sas": { "command": "sas-mcp", "args": ["serve"] }
}
}VS Code / GitHub Copilot — in .vscode/mcp.json:
{
"servers": {
"sas": { "type": "stdio", "command": "sas-mcp", "args": ["serve"] }
}
}Add policy flags to args as needed, e.g.
["serve", "--config", "oda", "--writable-libs", "STAGE"].
Choosing between multiple SAS environments
If your sascfg_personal.py defines more than one configuration, decide who
picks:
Pin it in the client config — the agent uses this one and cannot switch:
{
"servers": {
"sas": { "command": "sas-mcp", "args": ["serve", "--config", "oda"] }
}
}Add --allow-config-switch to make it a starting point the agent may change
instead of a restriction.
Or leave --config off, and the agent chooses: list_sas_configs shows
what's available with each one's access method and target server, and
use_sas_config selects one. With exactly one configuration defined it's used
automatically and nothing is asked.
Either way the server never blocks waiting for an answer. Left to itself,
SASPy prompts on stdin for a configuration name — and on a stdio MCP
server stdin is the JSON-RPC stream, so the prompt would consume protocol
bytes and hang the client. sas-mcp disables SASPy's prompting entirely and
returns the choice as data instead.
Tools
Tool | Purpose |
| Diagnose configuration without connecting |
| Connection, SAS version, librefs, WORK contents, policy |
| Submit code; returns triaged status, findings, row counts, output |
| Full raw log, when triage isn't enough |
| Clear WORK |
| Assigned librefs with paths and writability |
| Tables in a library with row/column counts |
| Columns with type, length, format, label |
| First N rows as records |
| PROC COMPARE as a structured diff |
| Run code with assertion macros; report pass/fail |
What run_sas returns
Not a log — a verdict:
{
"status": "suspicious",
"summary": "Ran, but results may be wrong: 2 suspicious notes; created WORK.B=19 obs.",
"suspicious_notes": [
{
"rule": "uninitialized_variable",
"text": "NOTE: Variable weigth is uninitialized.",
"explanation": "Variable was read before being assigned, so it evaluates to missing. Almost always a misspelled variable name.",
"line_no": 5
}
],
"steps": [{"step": "DATA statement", "dataset": "WORK.B", "obs_out": 19}],
"output": "..."
}status is ok, suspicious, or error. suspicious means the code ran
and the answer is probably wrong — it is not a success.
Every result also carries log_file: a path to a saved file holding the
findings and the complete SAS log, so "check the log" is something you can
actually act on. Logs go to a temporary directory by default; --log-dir PATH
puts them somewhere you choose, and the 25 most recent are kept.
Validating code
Rather than teach an agent a niche SAS test framework, this builds on the tool
SAS developers already use — and which happens to be machine-readable.
PROC COMPARE sets &SYSINFO to a bitmask where each bit names a specific
kind of difference, so compare_datasets can distinguish "the values
disagree" from "only a format differs":
{
"identical": false,
"data_differs": true,
"metadata_only": false,
"findings": [
{"code": "base_obs", "meaning": "Base data set has observations not in comparison"},
{"code": "value", "meaning": "At least one value comparison was unequal"}
],
"summary": "Data sets differ: ..."
}That makes it a real assertion an agent can iterate against — the natural way to verify that a rewritten step reproduces the original result.
run_sas_tests adds a small assertion macro library, loaded into the session
on first use:
%assert_exists(work.out);
%assert_rows(work.out, 19);
%assert_not_empty(work.out);
%assert_no_missing(work.out, age);
%assert_unique(work.out, id);
%assert_equal_datasets(work.expected, work.out);
%assert_condition(&n > 0, detail=n must be positive);Each writes a marker to the log that comes back as structured pass/fail. A
failed assertion sets status: "assertions_failed" even when the log itself
is clean — a green log with a red assertion is not a pass.
Getting files out of SAS
SAS ODA runs in AWS and an intranet SAS server sits on another machine, so neither can see your local disk. SASPy transfers over the SAS connection itself, which works regardless:
run_sas: proc export data=sashelp.class
outfile="~/report.xlsx" dbms=xlsx replace; run;
list_sas_files: ~ -> report.xlsx
download_from_sas: ~/report.xlsx -> /tmp/sas-mcp-files-xxxx/report.xlsxupload_to_sas goes the other way, for sending a CSV or workbook in.
Everything the server writes for you lands in your working folder, so it shows up in the editor's file tree:
sas-mcp/
.gitignore excludes this directory automatically
files/ downloads land here; uploads may only read from here
logs/ one annotated log per submissionOverride with --file-dir PATH and --log-dir PATH. If the client starts
the server somewhere unwritable, both fall back to a temporary directory.
Transfers are confined to that one directory, so the agent can neither overwrite arbitrary local files nor send arbitrary local files to a remote server. To upload something else, copy it in first.
Safety
Writes are restricted to WORK by default. Also blocked unless you opt in:
OS escapes —
X,%SYSEXEC,SYSTASK COMMAND,CALL SYSTEM,FILENAME PIPE,PROC PYTHON/LUA/GROOVYDestructive DDL —
PROC DATASETS KILL/DELETE,DROP TABLE,PROC DELETE,FDELETELibref rebinding — re-pointing an allowlisted libref somewhere else
Reads are never restricted; an agent can set prod.sales freely.
sas-mcp serve --writable-libs STAGE,SCRATCH # widen the write allowlist
sas-mcp serve --allow-destructive # permit DROP/KILL/DELETE
sas-mcp serve --allow-os-escape # permit X, PIPE, etc.Scope of the guarantee
This is a defense against model error, not a security boundary. SAS can
generate code at run time through CALL EXECUTE, DOSUBL, and macro
expansion, so no static scan can be complete, and a determined bypass is
always possible. It reliably stops the common accident. Do not rely on it as
your only control on a system where an agent could do real damage — use a SAS
account whose own permissions match what you want to allow.
Two known gaps, stated plainly:
Filesystem writes (
PROC EXPORT ... OUTFILE=,ODSto a path) are not restricted, only SAS library writes.Code assembled at run time from fragments that are individually innocuous will not be caught.
Supported deployments
The SAS 9.4 setups SASPy handles, selected by your sascfg_personal.py:
Deployment | Access method | Needs | Verified |
SAS OnDemand for Academics | IOM | Java, | ✅ macOS + Windows |
Intranet SAS server | IOM | Java, | ✅ Windows |
Intranet SAS server | SSH | SSH keys | not yet |
Local Windows install | COM | pywin32 (no Java) | not yet |
Local Windows install | IOM | Java | not yet |
Local Linux/UNIX install | STDIO |
| not yet |
"Not yet" means generated and unit-tested but not exercised against a running
SAS — run sas-mcp check and it will tell you whether your setup works. If
one of these fails for you, that's a bug worth
reporting.
SAS ODA is free but its terms are academic and non-commercial use only.
Note that each MCP client starts its own server process and therefore its own SAS session, which counts against concurrent-session limits on both ODA and licensed servers.
Development
uv pip install -e ".[dev]"
pytestThe log parser and guardrails are pure functions with no SAS dependency, and the server tests run against a fake session — so the full suite runs anywhere. CI runs them on Linux, macOS, and Windows against Python 3.10, 3.12, and 3.14.
Testing on Windows
CI runs the suite on Windows, but that cannot reach a SAS installation. To test against real Windows SAS, on the Windows machine:
# No PyPI release needed -- install straight from the repo
pip install git+https://github.com/matise-joe-norc/sas-mcp
sas-mcp init # choose the COM option first; it needs no Java
sas-mcp doctorLocal Windows SAS has two access methods, and COM is worth trying first:
it needs no Java at all, which removes the most common Windows setup failure.
It does need pip install pywin32. The IOM option is the fallback if COM
gives trouble.
Then exercise the server end to end:
python -c "from sas_mcp.session import SASSessionManager as M; m=M(cfgname='wincom'); r=m.submit('data work.a; set sashelp.class; run;'); print(r.triage.status, r.triage.summary)"Expect ok Ran: created WORK.A=19 obs. A result of ok with no steps
reported means the log has no NOTEs — see the options notes note below.
The two things most likely to differ from the verified Linux/ODA path:
Encoding. Windows SAS 9.4 typically runs
wlatin1, not UTF-8. A mismatch shows up as mojibake in character columns rather than an error.sas-mcp doctorreports the configured value.NONOTES. SASPy's IOM sessions suppress theNOTE:lines that log triage depends on. The session manager setsoptions notes source;on connect; if a Windows session somehow overrides that,run_saswould returnokwith emptystepsand nosuspicious_notes.
To confirm triage is really working rather than silently blind, run something that should be flagged:
python -c "from sas_mcp.session import SASSessionManager as M; m=M(cfgname='wincom'); r=m.submit('data work.b; set sashelp.class; bmi=weigth/height; run;'); print(r.triage.status, [n.rule for n in r.triage.suspicious_notes])"Expect suspicious ['uninitialized_variable', 'missing_values_generated'].
If that returns ok with an empty list, triage is not seeing NOTEs and the
result is untrustworthy — report it as a bug.
Releasing
The version lives in exactly one place: __version__ in
src/sas_mcp/__init__.py. Packaging metadata reads
it from there, so the two can't drift.
Bump
__version__and add aCHANGELOG.mdentry.Commit, and confirm CI is green on
main.Publish a GitHub Release tagged
vX.Y.Z.
That triggers release.yml, which builds,
runs twine check, installs the built wheel into a clean virtualenv to
confirm it actually runs, verifies the tag matches __version__, and only
then publishes. The tag check matters because PyPI will not let you re-upload
a filename — a mismatched tag is not recoverable.
workflow_dispatch runs the same build and verification without publishing,
if you want a dry run first.
One-time PyPI setup
Publishing uses Trusted Publishing, so there is no API token to store or rotate. Before the first release, add a pending publisher at pypi.org/manage/account/publishing:
Field | Value |
PyPI project name |
|
Owner |
|
Repository name |
|
Workflow name |
|
Environment name |
|
Then create a pypi environment under the repository's
Settings → Environments. Adding a required reviewer there gives you a manual
approval gate before anything reaches PyPI.
License
MIT
Available Tools
16 toolscompare_datasetsARead-only
Run PROC COMPARE between two data sets and return a structured diff: whether they are identical, whether the difference is in the data or only in metadata (labels, formats, lengths), and the specific kinds of difference found. This is the primary way to validate that a rewrite produces the same result as the original.
| Name | Required | Description | Default |
|---|---|---|---|
| by | No | ||
| base | Yes | ||
| compare | Yes | ||
| criterion | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, so the safety profile is covered. The description adds behavioral detail beyond that by specifying the structured output: whether data sets are identical, whether differences are in data or metadata, and the specific kinds of differences. It does not contradict the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences with no unnecessary words. The first sentence front-loads the core function and output; the second provides the key use case. It is concise, structured, and every clause earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description covers the tool's purpose, output, and primary use case, and the output schema can define the return structure. However, given 0% schema parameter coverage, the optional `by` and `criterion` parameters are left unexplained, and there is no mention of SAS session prerequisites or behavior when the session is unavailable.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate for parameter meaning. It clarifies that base and compare are the two data sets, but it gives no explanation of `by` or `criterion`. These optional parameters are left ambiguous despite being important for controlling how the comparison is performed.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb and resource: 'Run PROC COMPARE between two data sets' and clearly states what the tool returns: a structured diff with identity, data-vs-metadata distinction, and difference kinds. It distinguishes itself from sibling tools like run_sas and describe_dataset by focusing on comparison-based validation.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives a clear primary use case: 'the primary way to validate that a rewrite produces the same result as the original.' This provides meaningful context for when to choose this tool, though it does not explicitly name alternatives or state when not to use it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
describe_datasetARead-only
Return the columns of a SAS data set with type, length, format, informat, and label, plus the row count. Call this before writing code against a table you have not already inspected.
| Name | Required | Description | Default |
|---|---|---|---|
| table | Yes | ||
| libref | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already provide readOnlyHint=true, and the description aligns by describing a non-mutating inspection operation. It adds useful behavioral context by specifying the returned information and framing the tool as a preliminary inspection step. No contradiction.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences with no filler. The primary output is stated first, and the second sentence provides a practical usage guideline. Every sentence earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a small read-only tool with an output schema, the description covers what it returns and when to call it. The main gap is parameter semantics, but the simple required parameters and the output schema keep it sufficiently complete for invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema documentation coverage is 0%, and the description does not explain what 'libref' and 'table' mean beyond the phrase 'SAS data set.' An agent must rely on parameter names and SAS domain knowledge to understand that libref is the library reference and table is the dataset name.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific action ('Return the columns of a SAS data set') and a specific resource, enumerating the metadata fields plus row count. This distinguishes it from sibling tools like list_datasets or sample_rows by describing a metadata introspection operation.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives an explicit usage recommendation: 'Call this before writing code against a table you have not already inspected.' It does not name alternative tools or explicitly state when not to use it, so it stops short of full routing guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
download_from_sasA
Copy a file from the SAS server's filesystem to this machine, over the SAS connection. Works even when the two share no filesystem -- for example a workbook written by PROC EXPORT on SAS ODA. Returns the local path, which the user can open. Files land in this server's transfer directory; arbitrary local paths are not accepted.
| Name | Required | Description | Default |
|---|---|---|---|
| overwrite | No | ||
| local_name | No | ||
| remote_path | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With annotations all false, the description carries the burden and adds meaningful behavior: it returns the local path, writes into the server's transfer directory, and rejects arbitrary local paths. It also clarifies that the operation is a copy over the SAS connection, consistent with destructiveHint=false, and no contradiction exists.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four short sentences, with the core action and destination front-loaded. Every sentence earns its place: what it does, when it works, what it returns, and where files are placed.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description covers the essential workflow, return value, and a critical path restriction. Because an output schema exists, omitting a return format is acceptable; it could add overwrite behavior, but the remaining gaps are minor.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate. It clarifies that remote_path is a file on the SAS server's filesystem and constrains local destination behavior (transfer directory only, no arbitrary paths), but it does not mention overwrite or explain the local_name parameter explicitly.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource: 'Copy a file from the SAS server's filesystem to this machine, over the SAS connection.' It makes the transfer direction unmistakable and clearly differentiates this tool from upload_to_sas and list_sas_files.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives clear contextual guidance: it is the right choice when a file must cross from SAS to this machine, especially when there is no shared filesystem (e.g., PROC EXPORT output on SAS ODA). It does not explicitly name exclusion conditions or alternatives, but the transfer direction and cross-filesystem note are enough for an agent to select it appropriately.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_last_logARead-only
Return the full raw SAS log from the most recent submit. Use only when the triaged output from run_sas was not enough to diagnose the problem, since logs consume a lot of context.
| Name | Required | Description | Default |
|---|---|---|---|
| from_end | No | ||
| max_lines | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already mark readOnlyHint=true, so the safety profile is covered. The description adds behavioral context: the log is 'full raw' (not triaged), it's from the 'most recent submit', and it warns that logs 'consume a lot of context' — a useful cost signal beyond the annotations. It does not describe output format, but that is covered by the output schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences with zero waste. The primary action is front-loaded, and the advisory note is concise. Every word earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool is simple (two optional parameters), and an output schema exists, but the complete lack of parameter guidance is a notable gap. The description clearly states purpose, usage, and cost, so the agent can decide when to call it, but may not know how to tailor calls (e.g., max_lines) without additional information.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the schema provides no parameter documentation. The description does not mention 'from_end' or 'max_lines' at all, leaving the agent to guess their meaning. While the names are somewhat self-explanatory, the tool description adds no value beyond the schema, failing to compensate for the low coverage.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: 'Return the full raw SAS log from the most recent submit.' It clearly distinguishes itself from run_sas by contrasting the raw log with the 'triaged output' from run_sas, so an agent can tell them apart.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly states when to use this tool: 'Use only when the triaged output from run_sas was not enough to diagnose the problem.' It also gives a reason (logs consume a lot of context), which helps the agent avoid unnecessary calls. This directly addresses usage guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_datasetsARead-only
List the data sets in a SAS library, with row counts, column counts, and modification dates.
| Name | Required | Description | Default |
|---|---|---|---|
| libref | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already provide readOnlyHint=true, and the description adds useful context by specifying exactly what the listing includes (row counts, column counts, modification dates). This goes beyond the schema and gives the agent a clearer picture of the tool's output behavior.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single, front-loaded sentence with no filler. Every word contributes to the tool's purpose.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description covers the core action and details of the output, and an output schema is present to define return format. It does not mention practical caveats like requiring an active session or behavior on invalid libref, but these are minor for a simple read-only listing tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate. It indirectly describes the only parameter (libref) by mentioning 'SAS library', but it does not explicitly define libref as the library name or clarify any formatting requirements.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb ('List'), a clear resource ('data sets in a SAS library'), and adds distinguishing detail (row counts, column counts, modification dates). This makes it easy to differentiate from siblings like list_libraries (libraries) and describe_dataset (single dataset).
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies usage when an agent needs an inventory of datasets in a library, but it does not explicitly state when to use it versus alternatives like list_libraries or describe_dataset, nor does it mention any prerequisites or exclusions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_librariesARead-only
List assigned SAS libraries with path, engine, whether SAS considers them read-only, and whether this server's policy allows writing to them.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The readOnlyHint annotation already establishes this as a safe read operation, and the description aligns with that. It adds meaningful behavioral nuance by distinguishing between what SAS considers read-only and what the server policy permits writing to, which is valuable context beyond the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single, well-structured sentence communicates the action, resource, and returned fields without unnecessary words. The key verb and resource are front-loaded, making the description scannable and efficient.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given that the tool is parameterless, has an output schema, and is annotated as read-only, the description provides sufficient context for correct invocation. The mention of assigned libraries and policy details helps the agent understand the scope and semantics without needing additional explanation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters, so there are no parameter semantics to clarify. The description appropriately focuses on what the tool returns rather than on inputs, and no parameter documentation burden exists.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states that the tool lists assigned SAS libraries and enumerates the specific attributes returned: path, engine, SAS read-only status, and server policy write access. This is a specific verb+resource combination that distinguishes it from sibling tools like list_datasets, which operate on datasets rather than libraries.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description makes the tool's purpose clear, so an agent can infer it is appropriate when needing an overview of available libraries. However, it does not explicitly mention when not to use it or contrast it with sibling tools such as list_datasets or describe_dataset, leaving usage boundaries implied rather than stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_sas_configsARead-only
List the SAS configurations available in the user's SASPy setup, with the access method and target server for each. Call this when connecting reports that a configuration must be chosen, or when the user mentions a specific SAS environment by name.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and openWorldHint=false, so the read-only nature is established. The description adds value by mentioning the output contains access method and target server, which is useful context. There is no contradiction with annotations, but the description does not disclose any other behavioral traits beyond what annotations provide.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences with no redundancy. The first sentence states the core function and output, the second gives usage guidance. Every word earns its place; it's tightly written and well-structured.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a parameter-less tool with an output schema (present), the description fully covers purpose and usage. There is no missing information that would impede an agent from correctly deciding when to call this tool and what to expect from it.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters, and the input schema is empty with 100% coverage. Per the baseline for 0 params, the score is 4. The description does not need to elaborate on parameter semantics.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the verb 'list' and the resource 'SAS configurations', and specifies the information returned (access method and target server). It distinguishes this tool from siblings like use_sas_config (which selects a config) and list_sas_files (which lists files).
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides clear usage context: 'Call this when connecting reports that a configuration must be chosen, or when the user mentions a specific SAS environment by name.' It does not explicitly list alternatives or exclusions, but the trigger conditions are concrete and actionable.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_sas_filesARead-only
List a directory on the SAS server's filesystem. Use it to confirm where a step actually wrote its output before downloading.
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The readOnlyHint annotation already signals safety, and the description adds useful context about the tool's role in verifying actual output locations on the server filesystem. It does not contradict the annotations and gives enough behavioral framing for a read-only list operation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two sentences with no filler. The first sentence states the core function, and the second provides actionable usage guidance. Every word earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple single-parameter read-only tool with an output schema present, the description covers what the tool does and when to use it. The only notable gap is the lack of path specification details, but the presence of an output schema mitigates the need for describing return values.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, and the description does not explain the 'path' parameter's expected format, whether it is absolute/relative, or any constraints. Saying 'directory on the SAS server's filesystem' is only minimally helpful; the description should compensate for the lack of schema documentation but does not.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb ('List') and resource ('a directory on the SAS server's filesystem'), clearly distinguishing this from siblings like list_libraries and list_datasets, which operate on SAS logical structures rather than the filesystem. It also connects the tool to a concrete workflow: confirming where a step wrote output before downloading.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The second sentence gives a clear use case: 'Use it to confirm where a step actually wrote its output before downloading.' This provides context for when to invoke the tool, though it does not explicitly state when not to use it or name alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
reset_sessionADestructive
Delete every data set in WORK to clear accumulated state. Librefs and the connection itself are preserved. Use when earlier intermediate tables are causing confusion.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true and readOnlyHint=false, so the destructive nature is known. The description adds valuable behavioral detail beyond the annotation: it specifies that librefs and the connection are preserved, and clarifies the exact scope (only WORK datasets). This extra context helps the agent understand side effects.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two concise sentences, with the action and scope front-loaded. Every word earns its place: the operation, what is preserved, and the rationale for use. No redundancy or filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-parameter destructive tool, the description covers purpose, scope, preservation behavior, and when to use it. The output schema exists, so no need to explain return values. The description is complete for an agent to call it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters, so the baseline is 4. The description adds no parameter-specific information, but none is needed. Schema coverage is trivially 100% since there are no parameters.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the action (delete every data set in WORK) and the resource (WORK library), plus the purpose (clear accumulated state). It is distinct from sibling tools like run_sas or session_status, leaving no ambiguity about what the tool does.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly gives a use case: 'Use when earlier intermediate tables are causing confusion.' This provides clear context for when to invoke the tool. It does not mention alternatives or when not to use, but the guidance is sufficient for an agent to decide appropriately.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
run_sasA
Submit SAS code to the live session and return a triaged result: status (ok / suspicious / error), extracted errors and warnings, the NOTEs that mean the code ran but the answer may be wrong, per-step row counts, and the listing output. Writes outside WORK are blocked by policy. The session keeps state between calls.
| Name | Required | Description | Default |
|---|---|---|---|
| code | Yes | ||
| include_log | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations provide no positive safety hints (readOnlyHint is false and destructiveHint is false), so the description carries the burden. It adds important behavioral context by stating 'Writes outside WORK are blocked by policy' and 'The session keeps state between calls,' plus it explains the meaningful triage categories. It could mention side effects on WORK data more explicitly, but the policy boundary significantly clarifies risk.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is compact and well-structured: purpose and output details come first, followed by the safety constraint and statefulness note. Every sentence contributes useful information without repetition or filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a code-execution tool, the description covers the core action, output shape, safety boundary, and session statefulness, and an output schema handles return-value details. The main gap is the undocumented include_log parameter and the lack of explicit relationships to session-management siblings, but the overall picture is sufficient for correct use in most cases.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must explain the parameters. The 'code' parameter is covered implicitly by 'Submit SAS code,' but 'include_log' is never described beyond its schema title and default value. An agent gets little help understanding when or why to set include_log to true.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description begins with a specific verb and target: 'Submit SAS code to the live session.' It then details what the tool returns, including triaged status, errors/warnings, NOTEs, row counts, and listing output. This clearly distinguishes it from siblings like get_last_log or run_sas_tests, even without naming them.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The intended use is implied: when you need to run SAS code against the live session, use this tool. However, there is no explicit guidance about when to prefer run_sas over run_sas_tests, or when not to use it, and no alternatives are mentioned.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
run_sas_testsA
Run SAS code with the assertion macro library available, and return each assertion's pass/fail result alongside the usual log triage. Available macros: %assert_exists(ds), %assert_rows(ds, n), %assert_not_empty(ds), %assert_no_missing(ds, var), %assert_unique(ds, key), %assert_equal_datasets(base, compare), and %assert_condition(condition, detail=...). Use this to validate code you have written.
| Name | Required | Description | Default |
|---|---|---|---|
| code | Yes | ||
| include_log | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description discloses the key behavioral trait: assertions are returned as pass/fail results along with log triage, and the assertion macro library is available. However, annotations provide no safety profile (all hints false), and the description does not address side effects, session state, error behavior, or whether execution is isolated.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The opening sentence front-loads the purpose and return behavior, and the macro list is useful despite being somewhat lengthy. Every element earns its place, though the macro enumeration could be trimmed or summarized without much loss.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, the return values do not need full explanation in the description. The description is complete enough for selecting and invoking the tool: it covers purpose, available macros, and the intended validation use case. Minor gaps remain around `include_log` and interaction with session state, but these are not blocking.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate. It implicitly clarifies that `code` holds SAS code with assertions, but `include_log` is never mentioned or explained. The description adds meaning for only one of the two parameters and leaves the boolean parameter's behavior to inference.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific verb and resource: 'Run SAS code' with the assertion macro library available, and states the distinct return of assertion pass/fail results alongside log triage. This clearly separates it from sibling tools like run_sas, which lacks the assertion-specific output.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives clear context: 'Use this to validate code you have written.' It lists the available assertion macros, so an agent knows what kinds of validation are supported. It does not explicitly say when not to use it or name run_sas as the alternative for plain execution, but the intended use case is reasonably clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
sample_rowsARead-only
Return the first N rows of a SAS data set as records, to inspect actual values, coding schemes, and missingness.
| Name | Required | Description | Default |
|---|---|---|---|
| n | No | ||
| table | Yes | ||
| libref | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The readOnlyHint annotation already declares the operation is safe, and the description's 'Return' is consistent with that. Beyond the annotation, the description adds that the result is a prefix of rows ('first N') and that it exposes raw content like actual values and missingness, helping the agent anticipate the output nature.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, action-first sentence with no filler. It states what the tool returns and why, earning every word.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a low-complexity, read-only sampling tool with an output schema and readOnlyHint annotation, the description covers the essential invocation intent and expected return. The main gap is explicit libref/table semantics, but the schema names both as required string fields, so an agent can still invoke the tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
With schema description coverage at 0%, the description carries the burden of explaining parameters. It clarifies that 'n' is the number of rows to return, but it does not explain 'libref' or 'table' beyond naming a SAS data set generally. The two required parameters remain under-specified.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb ('Return'), a concrete resource ('first N rows of a SAS data set as records'), and an explicit purpose ('inspect actual values, coding schemes, and missingness'). It is clearly distinguishable from sibling tools like describe_dataset, which would describe metadata rather than raw data.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description communicates when to use this tool: when an agent needs to inspect actual data values, coding schemes, or missingness. It does not explicitly name alternatives or exclusion conditions, but the context is clear enough for selection among the listed siblings.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
sas_doctorARead-only
Diagnose SASPy configuration without connecting: config file and connection method, Java runtime for IOM, ~/.authinfo presence and permissions, ODA hostname validity, network reachability, and encoding. Run this first whenever a connection fails.
| Name | Required | Description | Default |
|---|---|---|---|
| probe_network | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, and the description adds relevant behavioral context by stating the tool diagnoses 'without connecting' and listing the diagnostic areas it inspects. There is no mutation implied and no contradiction with annotations. It does not describe output details, but an output schema exists to carry that burden.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is compact and front-loaded: one dense sentence enumerates the diagnostic scope, and a short imperative sentence gives usage guidance. There is no filler, and every phrase adds distinctive information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a read-only diagnostic tool with an output schema, the description covers scope and usage well: it names the diagnostic categories, says to run it first on connection failure, and clarifies it does not connect. The only notable gap is that the optional probe_network parameter is only implied rather than explicitly tied to the parameter name, but the schema and default mitigate this.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate for the single probe_network parameter. The phrase 'network reachability' maps plausibly to probe_network, but the parameter is never named and its effect when set to false is left to inference. The schema's default helps, but the description adds only partial semantic value.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb ('Diagnose') and a clear resource ('SASPy configuration'), then enumerates exactly what is checked: config file, connection method, Java runtime, .authinfo, ODA hostname, network reachability, and encoding. It also distinguishes itself from siblings with 'Run this first whenever a connection fails,' so an agent can separate it from run_sas or session_status.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives an explicit when-to-use instruction: 'Run this first whenever a connection fails.' It also clarifies that it operates 'without connecting,' which sets expectations for pre-connection diagnostics. It does not name alternatives or explicitly state when not to use it, so it stops short of a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
session_statusARead-only
Report whether a SAS session is live, the SAS version and encoding, the assigned librefs, the data sets currently in WORK, and the active write policy. Useful for reorienting after a long conversation.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The annotations already declare readOnlyHint=true, and the description's verb 'Report' aligns with that. The description adds useful output-scope context, such as the active write policy and WORK datasets, but does not disclose deeper behavioral details like connection behavior or side effects; the read-only annotation lowers the burden and the description does not contradict it.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two sentences with no wasted words. The first sentence front-loads the complete list of reported items, and the second sentence adds a practical use case. Every part earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no parameters and an output schema available, the description covers the essential context: what the tool reports and when to use it. Nothing an agent needs to decide whether to invoke this tool is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters, so there is nothing for the description to clarify beyond what the schema already shows. Baseline 4 applies because no parameter documentation is needed.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb ('Report') and clearly identifies the resource: the SAS session. It enumerates the exact facets reported (liveness, version, encoding, librefs, WORK datasets, write policy), which distinguishes it from siblings like list_libraries and list_datasets that cover only subsets.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly states when to use it: 'Useful for reorienting after a long conversation.' It provides clear context but does not explicitly mention alternatives or when not to use it, so it stops short of the strongest guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
upload_to_sasA
Send a file from this server's transfer directory to the SAS server's filesystem, over the SAS connection. Only files already in the transfer directory can be sent; to upload something else, ask the user to copy it there first.
| Name | Required | Description | Default |
|---|---|---|---|
| overwrite | No | ||
| local_name | Yes | ||
| remote_path | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already communicate non-read-only, non-idempotent, non-destructive behavior. The description adds useful context about the transfer-directory constraint and the SAS connection, but does not disclose overwrite behavior, collision handling, or failure modes. With annotations present, the bar is lower, and the description provides reasonable but not rich extra context.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences with no filler: the first states the operation, the second states the boundary and fallback. The key constraint is front-loaded, and every sentence earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description covers the source constraint and the transfer direction, and an output schema is present. However, it omits important operational details such as remote_path format, what overwrite=true actually does, and what happens on failure, leaving an agent to guess in realistic scenarios.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must carry the burden of explaining parameters. It clarifies that local_name refers to a file in the transfer directory, but remote_path and overwrite semantics are not addressed at all. The schema only provides names and a default, which is insufficient for reliable invocation.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific action—'Send a file from this server's transfer directory to the SAS server's filesystem'—with clear directionality, source, and destination. It distinguishes itself from sibling tools like download_from_sas by making the upload direction explicit.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives clear context and a hard precondition: only files already in the transfer directory can be sent, and other files must be copied there first. It does not explicitly name alternatives, but the constraint and fallback instruction effectively guide an agent on when this tool applies.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
use_sas_configADestructive
Select which SAS configuration to connect to, by name. Ends any current SAS session, so WORK data sets and librefs from the previous configuration are lost. Use when the user names a SAS environment, or after list_sas_configs shows several.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Discloses a critical side effect: 'Ends any current SAS session, so WORK data sets and librefs from the previous configuration are lost.' This goes beyond the destructiveHint annotation by specifying exactly what is lost, which is essential for an agent to warn the user or verify intent.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences with no filler. The purpose is front-loaded, followed by the side effect, then usage guidance. Every sentence earns its place and is highly efficient.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-parameter, destructive tool with an output schema, the description covers purpose, usage, and side effects. No additional information is needed for an agent to invoke it correctly; the side-effect warning is particularly valuable for safety.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
With 0% schema description coverage, the description compensates by implying the 'name' parameter is the configuration name ('by name', 'names a SAS environment'). It does not explicitly state 'name' is the config name, but the context is strong enough for an agent to infer it. Slight deduction for not being fully explicit.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific action (select/connect) on a specific resource (SAS configuration) by name, which clearly distinguishes it from siblings like list_sas_configs (listing) and run_sas (execution). It is not a tautology and provides precise scope.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly states when to use: 'Use when the user names a SAS environment, or after list_sas_configs shows several.' This gives direct invocation conditions and references a sibling tool for context, making the decision clear without ambiguity.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
TDQS
Most tools target a distinct resource and action: config selection, code execution, dataset metadata, file transfer, and comparison. A few overlapping boundaries exist—session_status overlaps with list_libraries/list_datasets for a quick overview, and run_sas vs. run_sas_tests both submit code—but the descriptions make the intended use clear.
The majority follow a clear verb_noun pattern such as list_datasets, describe_dataset, compare_datasets, and download_from_sas. The exceptions are session_status and sas_doctor, which are noun-led and break the otherwise predictable scheme.
Sixteen tools is slightly above the typical 3–15 sweet spot, but each tool maps to a distinct part of the SAS workflow: connection management, session state, code execution, file transfer, metadata inspection, and validation. The count feels justified rather than bloated.
The surface covers the core SAS lifecycle well: configure/connect, inspect session and datasets, run code, retrieve logs, transfer files, compare tables, and run tests. Minor gaps exist—no explicit disconnect tool or direct file deletion—but these do not create dead ends since run_sas and session management cover most of them.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Build, validate, and deploy multi-agent AI solutions from any AI environment.
Build, deploy, and sell AI agents for local-service businesses - from your IDE.
Deterministic runtime safety for AI agents: scan PII, gate tool actions, verify LLM output.
Related MCP Servers
- AlicenseNot gradedqualityAmaintenanceProvides sandboxed code execution for AI agents with support for Python, JavaScript, and shell commands. Includes comprehensive safety features like destructive pattern blocking, timeout protection, and restricted file access for secure production use.22MIT
- FlicenseNot gradedqualityDmaintenanceEnables coding agents to execute Python code, run script files, and install pip packages locally via MCP.
- AlicenseNot gradedqualityDmaintenanceEnables AI agents to detect development environments, install missing tools, scan local code projects, and generate visual reports.16MIT
- FlicenseNot gradedqualityDmaintenanceActs as the 'Hands and Eyes' for an Autonomous AI Agent, bridging Large Language Models and your local development environment to enable safe file manipulation, context reading, command execution, and documentation verification.2
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- 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/matise-joe-norc/sas-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server