Skip to main content
Glama
sassoftware

SAS MCP Server

Official
by sassoftware

Server Configuration

Describes the environment variables required to run the server.

NameRequiredDescriptionDefault
VIYA_ENDPOINTYesThe URL of your SAS Viya server

Instructions

Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.

This server publishes no instructions, or was last inspected before Glama recorded them.

Capabilities

Features and capabilities supported by this server

Protocol revision2025-11-25

CapabilityDetails
tools
{
  "listChanged": true
}
logging
{}
prompts
{
  "listChanged": false
}
resources
{
  "subscribe": false,
  "listChanged": false
}

Tools

Functions exposed to the LLM to take actions

NameDescription
execute_sas_codeA

Executes the provided SAS code in the Viya environment and returns information about the completed Job. This will create a job definition for the SAS code, execute it, and then retrieve the results.

IMPORTANT — state persists between calls: the code runs in a reusable compute session that is kept warm and shared across calls (per user), so SAS state — WORK tables, macro variables, and assigned librefs — survives between successive execute_sas_code calls. A re-run can therefore see leftovers from earlier calls (e.g. a check that counts results twice). Pass fresh_session=True (or call reset_compute_session) when the code must start from a clean slate.

Tip: to reach CAS data, prefer libname casuser cas; (or a targeted caslib statement) over caslib _all_ assign; — on tenants with many caslibs the latter floods the log with assignment NOTEs.

list_compute_contextsB

List available compute contexts on the Viya environment.

reset_compute_sessionA

Reset (delete) the cached compute session for a compute context.

The server keeps one reusable SAS compute session per user and compute context so repeat calls skip the slow session spin-up; SAS state (WORK tables, macro variables, assigned librefs) therefore persists across execute_sas_code and list_compute_* calls. Call this to discard that state — the next compute tool call transparently creates a fresh session.

catalog_searchA

Search the SAS Information Catalog for assets (tables, columns, reports, ...).

The catalog is a metadata index across the whole Viya environment, so this finds assets without needing to know their server/library first. Each hit includes the asset's resource_uri — the URI you can hand to the matching tool (e.g. get_report, get_castable_data) to act on the live asset — and an attributes map with whatever metadata the catalog holds for it (commonly library, rowCount, columnCount, completenessPercent, reviewStatus, informationPrivacy, and analysisTimeStamp).

The query uses the SAS catalog search grammar:

  • Free text matches names, with wildcards * (0+ chars) and ? (1 char): cust*.

  • Facets constrain fields, e.g. AssetType:Report, Name:sales, Library.name:PUBLIC, Column.informationPrivacy:Sensitive.

  • Ranges DateModified:[2024-01-01 TO 2024-12-31] and + to require a term. Combine freely: AssetType:"CAS Table" +Name:cust*. Use catalog_search_helper to discover valid facet names and values.

catalog_search_helperA

Discover how to search the catalog: list facets, or values for one facet.

Call with no facet to list the available facets — the fields you can constrain in a catalog_search query. Call with a facet name to get the suggested/valid values for that facet (e.g. the asset types or review statuses that actually exist). Use the results to build precise catalog_search queries.

catalog_find_instanceA

Resolve the catalog instance for a source-asset URI.

catalog_search finds assets by free text and facets, but the profiling and download tools key off a catalog instance id. When you already hold a resource URI — the resource_uri from a search hit, or a CAS table path — this looks the instance up directly by resourceId (the same filter the profiling workflow uses) and returns its id plus the key profile attributes. Use it to tell at a glance whether the asset has been profiled (analysisTimeStamp) and what semantic metadata it carries (informationPrivacy, nlpTerms, nlpTags, mostImportantFields) before calling catalog_download_table_profile.

catalog_list_agentsA

List SAS Information Catalog discovery agents.

Agents crawl a data source (server/library) to discover assets and collect their metadata into the catalog. Use catalog_run_agent to start one and catalog_get_agent_history to see what a run produced.

catalog_run_agentA

Start a catalog discovery agent run (asynchronous).

Triggers the agent to crawl its data source and populate/refresh catalog metadata. The run is asynchronous — results are applied to the catalog in the background; poll catalog_get_agent_history to track completion. Note: the Catalog API can only start an agent, not stop one already running.

catalog_get_agent_historyA

Get the execution history of a catalog agent's runs.

Each record reports a run's status and how much metadata it populated (tables enumerated/added/updated/removed), so you can confirm a run started by catalog_run_agent finished and what it changed.

catalog_run_adhoc_analysisA

Submit an ad-hoc analysis (profiling) job for a table in the catalog.

Profiles the table — computing the data dictionary, column statistics, and data-quality metrics that catalog_download_table_profile returns. The job runs asynchronously and may take a while; poll catalog_get_adhoc_analysis with the returned job id until the profile is ready.

The three NLP job parameters are enabled by default — they drive the semantic enrichment that populates an asset's informationPrivacy, nlpTerms, nlpTags, and mostImportantFields (the privacy and keyword signals the catalog is most useful for). Leave them on unless you only need a plain column profile and want the job to finish faster.

catalog_get_adhoc_analysisA

Get the status of an ad-hoc analysis job, and whether its profile is ready.

The job reaching a terminal status is not sufficient: the profile attributes are written onto the asset a little later, so a download fired the instant the job completes can come back empty. To close that gap, when the job carries a resource this also resolves the target catalog instance and reports profile_ready (the asset's analysisTimeStamp is populated — the same gate catalog_download_table_profile uses) and information_privacy (non-empty once the NLP semantic enrichment has landed). Poll until profile_ready is true, then download.

catalog_download_table_profileA

Download a catalog table's data dictionary and profile as CSV.

Returns the table's column metadata plus, by default, its profile (column statistics and data-quality metrics). If the table has not been profiled yet, this returns a recommendation to run catalog_run_adhoc_analysis (pre-filled with the table's URI and type) instead of an empty profile.

Identify the table by either instance_id or resource_uri (give one). Passing resource_uri lets you run search → profile → download without ever handling an instance id: the asset is resolved by resourceId the same way catalog_find_instance does. instance_id takes precedence if both are given.

list_compute_librariesA

List the SAS libraries (librefs) assigned in a compute context.

Runs in the reusable per-user compute session for the context, so it also sees libraries created by prior execute_sas_code calls.

list_compute_tablesA

List the tables in a SAS library within a compute context.

These are SAS/Compute tables (e.g. WORK or an assigned libref), distinct from in-memory CAS tables (see list_castables). Runs in the reusable per-user compute session for the context.

list_compute_columnsA

List the columns of a table in a SAS library within a compute context.

Runs in the reusable per-user compute session for the context.

list_cas_serversA

List available CAS servers on the Viya environment.

list_caslibsA

List CAS libraries (caslibs) available on a CAS server.

list_castablesC

List tables in a CAS library.

list_source_tablesA

List source tables that are NOT yet loaded into memory in a CAS library.

These are the candidates for promote_table_to_memory — tables that exist on the caslib's data source but are not in CAS memory yet.

get_castable_infoA

Get metadata for a CAS table (row count, column count, size, etc.).

get_castable_columnsA

Get column metadata for a CAS table (names, types, labels, formats).

A missing table returns a structured not_found with the two usual causes (unloaded source table vs session-scoped table) instead of a raw HTTP error.

get_castable_dataB

Fetch rows from a CAS table with column names.

get_compute_table_dataA

Fetch rows from a table in a SAS library, with column names.

The compute-tier counterpart of get_castable_data: a plain page of rows from libref.table as the session sees it, read through the compute session's data API rather than by running SQL. Values arrive formatted the way SAS displays them (dates as text, numbers with their format applied), which is what a person browsing a table expects; use query_data with target='compute' when you need raw numerics, a WHERE clause, or a join.

Runs in the reusable per-user compute session for the context, so WORK tables from earlier execute_sas_code calls are visible.

query_dataA

Run a FedSQL SELECT against CAS or compute data and return the rows.

One SQL surface over both storage tiers, so exploring a caslib table and a SAS library table use the same tool and the same dialect. The query runs in the reusable compute session; nothing is persisted — the result is materialised into session scratch, read back, and dropped.

Pick the tier with target — it selects the namespace, and the two cannot be mixed in one statement (a caslib table and a libref table cannot be joined; stage one side first with execute_sas_code):

  • target='cas' (default) — qualify as caslib.table (e.g. Public.HMEQ); see list_caslibs / list_castables.

  • target='compute' — qualify as libref.table (e.g. WORK.SALES); see list_compute_libraries / list_compute_tables. Concatenated librefs — several directories under one name, which is what SASHELP and MAPS are — are invisible to FedSQL, because its BASE driver maps one schema to one directory. Copy such a table into WORK first (data work.cars; set sashelp.cars; run;) and query WORK.CARS.

Dialect notes (FedSQL, not PROC SQL): joins (inner/left/right/full/ cross), subqueries, UNION, GROUP BY/HAVING/ORDER BY, and scalar functions work. There is no WITH/CTE — use a derived table (select ...) "t" — and no MERGE; express a merge as a join (a full join with COALESCE gives upsert semantics). Double-quote identifiers that are reserved words or contain spaces; SAS name literals ('x'n) are not FedSQL.

Row capping is done by this tool, not by your SQL: any LIMIT you write is ignored in favour of limit (a malformed LIMIT is silently discarded by CAS and would return the whole table). Add ORDER BY for stable paging.

upload_dataA

Upload a data file into a CAS table — read by the server, not the model.

Provide the data by reference through exactly one of:

  • file_path — the server reads the file off its own disk (in stdio mode that's your machine). Disable with ALLOW_LOCAL_FILE_UPLOAD=false.

  • url — the server fetches it over HTTP.

Either way the bytes are read server-side and never pass through the calling model's context window. Sources larger than MAX_UPLOAD_BYTES (default 100 MiB — SAS Viya's own default file-upload limit) are refused. To create a small table you are building inline (no file or URL), use the upload_inline_data tool instead.

The casManagement uploadTable endpoint only accepts an uploaded file (multipart form-data) and has no URL parameter, so url is fetched and sent on as the multipart file part.

Formats. Per the uploadTable API: csv, xls, xlsx (single sheet), sas7bdat, sashdat; tsv is csv with a tab delimiter. parquet is not accepted and is rejected up front with guidance (load via a path-based caslib + promote_table_to_memory, or convert to csv/sas7bdat). The format is auto-detected from the file_path/url extension; pass data_format to override (needed for URLs with no clean suffix).

upload_inline_dataA

Create a small CAS table from inline delimited text passed as a string.

Use this only for tiny, hand-built tables — a lookup/mapping table the model constructs on the fly, or a quick test table — because the whole payload travels through the model's context as a tool argument. For anything larger, or any file you already have, use upload_data (file_path/url), which reads the bytes server-side instead.

Text formats only: csv (default) or tsv (tab-separated). For binary formats (Excel, sas7bdat, sashdat) use upload_data.

promote_table_to_memoryA

Load a source table into CAS memory at global scope (visible to all sessions).

Loads the table from its caslib data source and promotes it to global scope via the casManagement updateTableState API. Idempotent: if the table is already loaded in global scope it is left untouched. Use list_source_tables to discover unloaded tables that can be promoted.

list_filesA

List files in the Viya Files Service.

upload_fileA

Upload a file to the Viya Files Service, optionally into a Content folder.

Provide the file content through exactly one of:

  • content — inline text (the original behaviour; text files only).

  • file_path — a path the server reads directly from its own disk (in stdio mode that's your machine). Handles binary files (xlsx, zip, images) untouched. Disable with ALLOW_LOCAL_FILE_UPLOAD=false.

  • url — an HTTP(S) URL the server fetches the file from. Also binary-safe.

file_path and url sources larger than MAX_UPLOAD_BYTES (default 100 MiB — SAS Viya's own default file-upload limit) are refused.

parent_folder_uri files the upload into a Content folder (e.g. /folders/folders/{folderId}) — the location %include/filesrvc ingestion and other folder-scoped consumers need. Without it the file lands unfiled under the caller's user context.

download_fileA

Download file content from the Viya Files Service.

list_reportsB

List Visual Analytics reports.

get_reportA

Get a Visual Analytics report's metadata and definition.

export_reportA

Export a Visual Analytics report (or specific report objects) in any format the VA service exposes, via its synchronous export endpoints.

Formats (export_format):

  • package — full report bundle as a .zip (source files, query results, and rendered content); whole report or selected objects.

  • pdf — rendered PDF; whole report or selected objects. Pass rendering overrides (e.g. orientation, paperSize, margin, includeCoverPage) via options.

  • png / svg — image of the report or a single object; image_size is required, e.g. "1200px,800px".

  • csv / tsv / xlsx — the data behind a single report object; exactly one object label is required.

  • summary — the report's text summary.

describe_report_objectsA

Discover what a Visual Analytics report can contain — operations and objects.

Call this to learn how to build a report before calling apply_report_operations. It reads a bundled catalog (no network), so it is the cheap way to look up an object's data roles instead of guessing.

create_reportA

Create a Visual Analytics report and return its id for further edits.

Creates an empty report shell, or — if you pass operations — builds the whole report in one atomic call (bind data, add pages, add objects). Building at creation avoids leaving an empty report behind if a later edit fails. Returns {"status": "created", "id": ..., "name": ...} plus a created summary whose object names/labels are what follow-up placement and exports target; feed the id to apply_report_operations to keep editing. Note: VA prepends an empty default "Page 1" before any pages your operations add, so verify page-by-page with export_report (see the result's verify_hint) rather than a whole-report export.

apply_report_operationsA

Apply an ordered batch of operations to a report — the authoring workhorse.

This is how you add pages, add objects (any of the ~60 VA visual, control, and content types), set parameters, and swap data sources. operations is the native SAS Visual Analytics operations array; the whole batch is applied atomically (all succeed or nothing changes).

Operation keys (one per array element): addData, addPage, addObject, updateObject, setParameterValue, updateData, changeData, applyDataView. Call describe_report_objects for each operation's shape (operation="addData" covers formats, aggregations, and geography via dataItems) and each object's data roles, and get_castable_columns to map columns onto those roles.

Layout & titles (see describe_report_objects → placement / layout_recipes for details):

  • Page title — give addPage a title (e.g. {"addPage": {"pageName": "Overview", "title": "Sales Overview"}}); it becomes a text band at the top of that page's body. Page/report headers accept ONLY control objects — never text or visuals.

  • Chart titles — pass {"options": {"object": {"title": "..."}}} inside the object spec at add time (all types except standardContainer, which takes no options at add time).

  • One-batch multi-page — create pages inline with placement {"report": {"context": "new_page", "pageName": "Trends", "pagePosition": 1}} (numeric position) and target that pageName from later operations in the same batch.

  • Grids/columns — relativeToObject with left/right/top/bottom (geometric) or before/after (flow order) against an EXISTING object's name; same-batch forward references fail, so chain across calls using the names each result returns. Objects are auto-named and auto-sized; placement and dataRoles are write-once (updateObject changes options only).

  • Read structure back anytime with get_report_outline; verify visually with export_report page-by-page (see verify_hint in the result).

The tool validates every operation against the object catalog before any HTTP call (unknown/typo'd object type, non-addable object, bad data-role names or arity, disallowed object/placement keys) and reports ALL invalid operations at once. It also handles the ETag optimistic-concurrency handshake for you, retrying once transparently on a concurrent edit.

get_report_outlineA

Read a report's structure: pages → objects with the handles other tools need.

Reduces the stored report definition to a compact outline — per page its internal name and label, per object its name (ve*), label, type, and any text content. Use it to edit an existing report, to recover object names after an apply, or to check what a batch actually produced:

  • object name → the target for relativeToObject/container placement and updateObject;

  • object label → what export_report report_objects takes;

  • page label → the page placement target.

Returns {"status": "ok", "pages": [...], "hint": ...} (or not_found / outline_failed).

copy_reportA

Copy a Visual Analytics report to a new report, returning the copy's id.

Useful for tailoring a report to a new audience or for the copy-and-replace pattern — copy, then apply_report_operations with a changeData op to point the copy at a different table. Returns {"status": "copied", "id": ..., "name": ..., "source_report_id": ...}.

delete_reportA

Delete a Visual Analytics report and its content.

There is no per-object undo in the report API, so deleting and rebuilding (or copying first) is how you discard an unwanted report. Returns {"status": "deleted", "report_id": ...} (or not_found / delete_failed).

submit_batch_jobA

Submit a SAS job for asynchronous execution via the Job Execution service.

get_job_statusA

Check the status of a submitted job.

list_jobsA

List recent jobs from the Job Execution service.

cancel_jobA

Cancel a running job.

get_job_logA

Retrieve the log of a completed job.

list_ml_projectsB

List AutoML pipeline automation projects.

create_ml_projectA

Create a new AutoML pipeline automation project from a CAS table.

The training table must already be loaded into CAS memory at global scope. This tool verifies that first and returns an actionable error otherwise (use promote_table_to_memory to load + promote a source table, and list_source_tables to find one). The data-table URI is built from server_id/caslib_name/table_name.

register_ml_champion_modelB

Register the champion model from an AutoML pipeline automation project to the Model Repository.

publish_ml_champion_modelB

Publish the champion model from an AutoML pipeline automation project to the Model Repository.

run_ml_projectC

Run an AutoML pipeline automation project.

list_registered_modelsB

List models in the Model Repository.

list_publishing_destinationsB

List available publishing destinations.

list_mas_modulesA

List published scoring models and decisions (MAS modules).

get_mas_module_step_signatureA

Fetch a MAS module step's input/output variable signature.

Call before score_data to know the exact variable names, types, and order to pass as inputs, and what outputs to expect.

score_dataB

Score data against a published model or decision (MAS module).

create_business_rulesetA

Create a new SAS Business Rules rule set.

A rule set with no rules cannot be used in a decision flow — follow up with create_business_rule to populate it.

update_business_rulesetA

Update an existing SAS Business Rules rule set's name/description/signature.

Changing the signature can invalidate existing rules that reference removed variables — check with get_business_ruleset first if unsure.

get_business_rulesetA

Fetch a single SAS Business Rules rule set by ID.

list_business_rulesetsA

List SAS Business Rules rule sets, optionally filtered by name substring.

delete_business_rulesetA

Permanently delete a SAS Business Rules rule set.

Only call this once the rule set is confirmed unused by any decision flow — deleting a rule set still referenced by a decision fails.

lock_business_ruleset_revisionA

Lock the current state of a rule set as an immutable revision.

Decision steps reference a specific rule set revision (versionId), not the live working copy, so a revision must exist before wiring a rule set into a decision flow — call again after editing rules if a decision needs to pick up the changes.

The revision-creation request replaces the rule set's full content from the body sent, so this fetches the rule set with its rules included (application/vnd.sas.business.rule.set.integral+json) and resends them — omitting them would wipe the live rule set's rules, not just the new revision.

list_business_ruleset_revisionsA

List all locked revisions of a rule set.

create_business_ruleA

Create a new rule inside an existing SAS Business Rules rule set.

A rule set can hold multiple rules, each evaluated per its conditional type. Condition/action expressions must include the variable name directly (e.g. "credit_score < 650", not just "< 650") — the API accepts the latter as valid but generates DS2 code with a missing left-hand operand. Boolean signature variables must be compared with = 0/= 1 in expressions, not = false/= true.

update_business_ruleA

Update an existing rule inside a SAS Business Rules rule set.

get_business_ruleA

Fetch a single rule's definition from a SAS Business Rules rule set.

list_business_rulesA

List all rules inside a SAS Business Rules rule set.

delete_business_ruleA

Permanently delete a rule from a SAS Business Rules rule set.

create_decision_flowB

Create a new SAS Intelligent Decisioning flow chaining rule set steps.

update_decision_flowA

Update an existing SAS Intelligent Decisioning flow.

Pass ALL rule set steps (existing + new) — the full flow is replaced on update, it is not a partial patch.

get_decision_flowA

Fetch the current state of a SAS Intelligent Decisioning flow.

list_decision_flowsA

List SAS Intelligent Decisioning flows, optionally filtered by name substring.

delete_decision_flowA

Permanently delete a SAS Intelligent Decisioning flow.

get_decision_flow_codeA

Retrieve the generated DS2 execution code for a decision flow.

lock_decision_flow_revisionA

Lock the current state of a decision flow as an immutable revision.

Call after a successful create/update to freeze the approved state as a point-in-time snapshot referenceable by publish_decision_flow.

list_decision_flow_revisionsA

List all locked revisions of a decision flow.

get_decision_flow_revisionA

Fetch the content of a specific locked decision revision.

publish_decision_flowA

Publish a locked decision revision to a Micro Analytic Score (MAS) destination.

Required before score_data can execute the decision — MAS runs published modules, not decision flows directly. Requires the DS2 code generation service to be healthy for this decision's rule sets; an error mentioning rule set code generation is an environment-level issue, not a bad payload.

Publishing is asynchronous and the resulting MAS module ID is server-generated — it is NOT publish_name. This polls the publish job (properties.masModules[0].jobUri) until it reaches a terminal state and returns the real moduleId alongside the publish record, so the result is directly usable with get_mas_module_step_signature/score_data without a separate lookup via list_mas_modules.

list_glossary_term_typesA

List the term types defined in the SAS Business Glossary.

A term type is the template a term is created from: it fixes which custom attributes the term carries and which of them are mandatory. Every term belongs to exactly one, and the choice is immutable after creation — so pick the type before calling create_glossary_term, then read its attribute contract with get_glossary_term_type.

usage_count is how many terms already use the type, which is the quickest way to tell a deployment's working vocabulary from types that were created once and abandoned.

get_glossary_term_typeA

Get a term type and the attribute contract its terms must satisfy.

Call this before creating or updating a term: it names every custom attribute, its data type, whether it is required, the exact values a single- or multi-select accepts, and value_format — the one spelling Viya takes for that type, which the API itself documents nowhere. create_glossary_term takes attributes keyed by the label shown here, so this is also the vocabulary to write in.

create_glossary_term_typeA

Create a term type — the template that fixes what a term must carry.

A term type declares the custom attributes every term of that type holds, and which are mandatory. Without this tool a deployment's types can only be created in the SAS UI, so a glossary could be read and populated through MCP but never designed through it.

Each attribute is {"label": ..., "type": ...} plus, optionally, required, allowed_values, default and description:

  • single-line, multi-line — free text

  • single-select, multi-select — need allowed_values

  • boolean, date, date-time, time

The attribute identifiers the API demands are generated here, since it will not mint them itself and rejects the omission with a message that names neither the attribute nor the real problem.

update_glossary_term_typeA

Change a term type: rename it, or add, edit and remove its attributes.

Attributes are matched to the existing ones by label, and an edit keeps that attribute's identifier — which matters more than it looks, because every term's stored values are filed under it. An attribute the caller does not mention is left alone; a label that does not exist yet is added.

To rename one, give its attribute_id alongside the new label. Matching by label alone cannot express a rename: the new label matches nothing, so the attribute is added afresh under a new identifier and every term's value stays behind under the old one, no longer readable as that attribute. get_glossary_term_type returns the id of each.

Making an attribute required applies to terms created afterwards and to every later edit of the ones already there: an update rewrites the whole term, so older terms must be given a value for it before they can be saved again. update_glossary_term reports that by name.

delete_glossary_term_typeA

Delete a term type.

Refuses while terms still use the type, because deleting it takes their attribute definitions with it. Check with list_glossary_terms (term_type=) and move or delete those terms first — or pass force if you have already decided.

search_glossary_termsA

Free-text search of the business glossary — the way in when you know a word, not an id.

Runs against the Information Catalog's terms index, so it is ranked and matches definitions as well as names, unlike list_glossary_terms' exact structural filters. Supports the catalog grammar: wildcards (rev*), field constraints (Name:revenue, Status:Published) and + to require a word.

Each hit carries both identifiers — term_id for every other glossary tool, catalog_entity_id for catalog relationships — plus assigned_asset_count, so you can tell whether a term is actually in use before spending a call on list_term_assets. A term with a count of 0 exists in the dictionary and is attached to no data.

list_glossary_termsA

List glossary terms by structure — term type, parent, or name fragment.

The counterpart to search_glossary_terms: exact filters instead of ranked text. Use it to walk the hierarchy (parent_id returns a term's direct children, which is the authoritative parent/child relationship), to inventory one term type, or to page the whole dictionary with no arguments at all.

get_glossary_termA

Get one business term in full, with its custom attributes named rather than hashed.

The raw API returns attributes keyed by attribute-definition UUID, which is unreadable on its own. This resolves each key to the label the glossary UI shows and drops the ones left empty, so what comes back is the term as a person would read it. attribute_ids is the raw map, unfiltered — so an attribute the term leaves unset is absent from attributes but present as "" there. The two disagree by design: one says what the term holds, the other what was stored.

Also returns catalog_entity_id — the other id this term has, the one asset relationships point at.

list_term_assetsA

List the data assets a business term is attached to — the columns that mean it.

The authoritative answer to "where is this term actually used?", read from the glossaryTermAsset relationships rather than inferred from names. Each entry names the column and the table it belongs to.

An empty result means the term is assigned to nothing, which is not the same as no matching column existing — assign_glossary_term is what creates the link. For a looser, name-based sweep, catalog_search accepts the Column.term:"<term name>" facet on the datasets index, which returns matching tables without resolving columns.

list_table_termsA

List the business terms assigned to a table's columns.

The reverse of list_term_assets, and the fastest way to judge whether a table is governed: it reports each column's term together with the term's own definition, so a caller can read what a cryptically named column actually holds.

Terms come from glossaryTermAsset relationships, so a column with no term here has genuinely never been assigned one — the catalog does not guess from column names.

create_glossary_termA

Create a business term in the SAS Business Glossary.

attributes is keyed by the attribute labels from get_glossary_term_type — call that first, because a term type can make attributes mandatory and a term missing one is rejected. Pass each value in its natural Python form and it is converted to the one spelling the glossary accepts:

  • boolean — True / False (the strings "true"/"false" are rejected by Viya; that conversion happens here)

  • multi-select — a list, e.g. ["Retail", "Wholesale"]

  • date — "2026-09-04"

  • date-time — "2026-09-04T13:41:24Z"; a bare date or a numeric offset is normalised to UTC rather than rejected

  • time — "15:41:28Z"; seconds and the Z are required, and a numeric offset is converted to UTC rather than dropped

Values are validated before the call, so a mistake comes back naming the attribute and what it expected, instead of as an opaque HTTP 400.

Terms are published by default. The underlying API defaults to creating a draft, which nobody but its author can see; that is almost never what a caller asking to "create a term" means, so this publishes unless publish is set false. A draft is promoted afterwards with update_glossary_term(publish=true), and is visible to list_glossary_terms only under include_drafts.

A term's name must be unique among its siblings (case-insensitively) and differ from its parent's; a clash is rejected, not merged.

update_glossary_termA

Update a business term's text, parent or custom attributes — and publish a draft.

The glossary API replaces the whole term on update, so this reads the current one first and merges your changes into it: omitting an argument leaves that field alone rather than blanking it. attributes merges the same way, per attribute — pass only the ones you are changing, and set one to "" to clear it. A boolean is the exception: the glossary has no empty boolean and rejects "", so set it to True/False rather than trying to clear it.

Because the whole term is rewritten, every attribute the type marks required must hold a value — including ones made required after this term was created. That is checked before the call, and reported by name.

A term's type cannot be changed after creation. Its parent can: pass parent_id to move it, or "" to make it a root term.

A draft is a different resource. A term left unpublished by create_glossary_term(publish=false) can be read and deleted at the ordinary path, but not written there — the service answers a plain PUT on a draft with a 404. This routes the write to the draft instead, so editing one works; and publish then promotes it to a published term, which nothing else here could do. Publishing a term that is already published is reported, not attempted: there is no draft to promote and the service answers that with a 404 too.

import_glossary_termsA

Create many business terms, and their hierarchy, in one call.

Building a hierarchy one term at a time means a call per term and a wait between levels, because a child needs the parent's id from the previous response. This uses the glossary's own bulk import instead: one request for the whole tree, with parents resolved by name rather than by id, so nothing has to be threaded through.

Give each row a name and, for a child, a parent — the name of another row in the same batch, or the path of a term that already exists (levels separated by a backslash). Rows may be given in any order; they are sorted so every parent is created before its children.

Attribute values take the same forms as create_glossary_term — True/False for a boolean, a list for a multi-select — and are validated here, per term type, before anything is sent. So are the term type's required attributes: a row missing one fails inside the job with a message naming only the field, so the batch is refused here instead, before any of it is committed.

The import runs as a job and reports rows individually. A row can fail while the rest succeed, so the result carries created, failed and a failures list naming each bad row and why. Treat a non-empty failures as a partial import: the successful rows are already committed.

The result names the term each row became. terms carries {name, path, term_id, existed} per row, so the next step — assigning an asset, re-parenting, reading one back — needs no lookup. This costs one filtered request per 40 distinct names, not one per term.

Two things the import does that a per-term create does not:

  • A row is written whole. With update_existing the term at that path is replaced, so an attribute the row omits is reset — not left as it was. Without it the existing term is left alone. Either way the job counts the row as successful, so created counts rows the job accepted; new is the count of terms that did not exist before, with already_existed the rest and existed saying which is which per row.

  • Omitted attributes take the term type's default, on new rows as well as replaced ones — the same as creating a term through the API.

delete_glossary_termA

Permanently delete a business term.

The term goes, and with it every assignment to a column that referenced it — the data keeps its columns but loses the documented meaning. Check list_term_assets first: a term with assigned assets is in use.

There is no cascade. A term that has children cannot be deleted at all: the glossary refuses with Cannot delete a term/draft with existing children. Delete the subtree leaf-first — list a term's children with list_glossary_terms(parent_id=...) — or re-parent them with update_glossary_term before deleting this one.

assign_glossary_termA

Assign a business term to a table column — the step that makes a term govern data.

Creating a term only defines a word. This attaches it to the column that carries it, and it is what list_table_terms, list_term_assets and the catalog's Column.term facet all read. Assigning the same term to the same column twice is reported, not duplicated.

unassign_glossary_termA

Remove a business term's assignment from a table column.

Deletes only the link: the term and the column both survive. Use delete_glossary_term to remove the term from the dictionary itself.

Prompts

Interactive templates invoked by user choice

NameDescription
debug_sas_logAnalyze a SAS log for errors, warnings, and notes with root-cause explanations and suggested fixes.
explore_datasetGenerate comprehensive SAS data-profiling code (CONTENTS, MEANS, FREQ, UNIVARIATE).
data_quality_checkGenerate SAS code for a data quality assessment (completeness, uniqueness, validity).
statistical_analysisSet up a complete SAS statistical analysis workflow with diagnostics.
optimize_sas_codeReview and optimize SAS code for performance, readability, or both.
explain_sas_codeProvide a block-by-block explanation of SAS code, tailored to skill level.
sas_macro_builderBuild a production-quality reusable SAS macro.
generate_reportGenerate SAS ODS/PROC REPORT code for formatted output.
build_va_dashboardBuild a polished multi-page Visual Analytics dashboard from a CAS table, using the report-authoring tools (discover → shape → structure → polish → verify).

Resources

Contextual data attached and managed by the client

NameDescription
sas-log:execute_sas_codeSAS log view for the execute_sas_code tool (MCP Apps).
data-grid:get_castable_dataData grid view for the get_castable_data tool (MCP Apps).
data-grid:get_compute_table_dataData grid view for the get_compute_table_data tool (MCP Apps).
term-editor:get_glossary_termGlossary term editor view for the get_glossary_term tool (MCP Apps).
term-editor:get_glossary_term_typeGlossary term editor view for the get_glossary_term_type tool (MCP Apps).
sas-log:get_job_logSAS log view for the get_job_log tool (MCP Apps).
import-preview:import_glossary_termsGlossary import view for the import_glossary_terms tool (MCP Apps).
term-tree:list_glossary_termsGlossary browser view for the list_glossary_terms tool (MCP Apps).
data-grid:query_dataData grid view for the query_data tool (MCP Apps).
sas-log:submit_batch_jobSAS log view for the submit_batch_job tool (MCP Apps).

TDQS

A3.7/5.0

Scored across 92 tools

Disambiguation5/5

Each tool targets a distinct resource and action, with near-zero ambiguity even in dense areas. Overlapping data-access tools (query_data, get_castable_data, get_compute_table_data, execute_sas_code) are precisely differentiated and even cross-reference each other in descriptions. Catalog search vs glossary search, and upload_data vs upload_inline_data vs upload_file, all have clear boundaries.

Naming Consistency4/5

The dominant verb_noun pattern (list_*, get_*, create_*, update_*, delete_*, lock_*, publish_*) is followed consistently within each domain, and CRUD families are easy to predict. The only deviation is the catalog_* group, which inverts the convention by placing the domain prefix first (catalog_search, catalog_run_agent) rather than as the object noun.

Tool Count2/5

At 92 tools, the surface is far beyond the ideal range and well past the 25+ threshold for heaviness; it would take an agent many calls just to enumerate candidates. That said, the count is defensible: the server spans roughly a dozen genuinely distinct SAS Viya domains (rules, decision flows, CAS, compute, reports, catalog, glossary, ML), each of which is reasonably scoped on its own.

Completeness4/5

Every major domain has a closed lifecycle: full CRUD plus revisions and locking for business rules and decision flows, complete glossary management including term types and assignments, and report authoring with copy/delete/export. Minor gaps exist — CAS table alteration/removal is absent and MAS module management is read-only — but finding a table, scoring it, or tracing a governed term all have no dead ends.

Maintenance

ActivityActive
ResponsivenessSlow