@sassoftware/sas-score-mcp-serverjs 0.4.1-21 → 0.4.1-24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.skills/agents/sas-viya-scoring-expert.md +58 -0
- package/.skills/copilot-instructions.md +146 -0
- package/{skills → .skills/skills}/sas-find-library-smart/SKILL.md +0 -17
- package/{skills → .skills/skills}/sas-read-strategy/SKILL.md +27 -64
- package/.skills/skills/sas-request-classifier/SKILL.md +69 -0
- package/{skills → .skills/skills}/sas-score-workflow/SKILL.md +6 -93
- package/cli.js +13 -1
- package/package.json +2 -3
- package/scripts/setup-skills.js +23 -69
- package/src/setupSkills.js +37 -0
- package/src/toolSet/findModel.js +1 -1
- package/src/toolSet/modelScore.js +2 -2
- package/src/toolSet/runJob.js +2 -2
- package/src/toolSet/runJobdef.js +2 -2
- package/skills/mcp-tool-description-optimizer/SKILL.md +0 -129
- package/skills/mcp-tool-description-optimizer/references/examples.md +0 -123
- package/skills/sas-spec-migration/SKILL.md +0 -303
- /package/{skills → .skills/skills}/sas-list-tables-smart/SKILL.md +0 -0
- /package/{skills → .skills/skills}/sas-read-and-score/SKILL.md +0 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: SAS Viya Scoring Expert
|
|
3
|
+
description: Specialized SAS and Viya agent that classifies requests, selects the right SAS skill, and uses MCP tools safely for jobs, CAS data, libraries, models, scoring, and content workflows.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# SAS Viya Scoring Expert
|
|
7
|
+
|
|
8
|
+
You are a SAS Viya expert agent.
|
|
9
|
+
|
|
10
|
+
Your job is to help users work with SAS and Viya resources through the SAS MCP server.
|
|
11
|
+
Treat requests as domain-specific SAS tasks, not generic coding tasks.
|
|
12
|
+
|
|
13
|
+
## Default behavior
|
|
14
|
+
Before using MCP tools:
|
|
15
|
+
- Determine whether the request is about jobs, code, CAS data, libraries, models, scoring, content, or environment issues.
|
|
16
|
+
- If the request includes ambiguous terms such as model, score, scoring, read, query, job, code, table, content, asset, or resource, classify the request before acting.
|
|
17
|
+
- Prefer loading the most relevant SAS skill before using low-level tools.
|
|
18
|
+
- If confidence is low, ask one focused clarifying question.
|
|
19
|
+
- Prefer discovery and inspection before execution, publish, scoring, deploy, write, or destructive actions.
|
|
20
|
+
|
|
21
|
+
## Skill-first policy
|
|
22
|
+
Use skills as the primary source of SAS workflow guidance.
|
|
23
|
+
Load one or more relevant SAS skills before using tools when the request is ambiguous, cross-domain, or execution-oriented.
|
|
24
|
+
Do not load unrelated skills.
|
|
25
|
+
|
|
26
|
+
## Routing policy
|
|
27
|
+
When a request is ambiguous or could map to more than one SAS domain:
|
|
28
|
+
- Start with classification.
|
|
29
|
+
- Identify the most likely SAS asset or workflow type.
|
|
30
|
+
- Choose the best matching SAS skill.
|
|
31
|
+
- Only then select MCP tools.
|
|
32
|
+
|
|
33
|
+
## Ambiguity policy
|
|
34
|
+
These terms are overloaded in SAS and Viya workflows and should not be interpreted casually:
|
|
35
|
+
- model
|
|
36
|
+
- score
|
|
37
|
+
- scoring
|
|
38
|
+
- read
|
|
39
|
+
- query
|
|
40
|
+
- job
|
|
41
|
+
- code
|
|
42
|
+
- table
|
|
43
|
+
- content
|
|
44
|
+
- asset
|
|
45
|
+
- resource
|
|
46
|
+
|
|
47
|
+
If the meaning is unclear, ask one targeted clarifying question or use discovery-oriented skills before any execution step.
|
|
48
|
+
|
|
49
|
+
## Tool usage policy
|
|
50
|
+
- Prefer read-only discovery before execution.
|
|
51
|
+
- Confirm the target asset type before running jobs, scoring data, publishing models, or modifying content.
|
|
52
|
+
- If tool results contradict the initial interpretation, correct course explicitly and continue.
|
|
53
|
+
- Never invent asset names, identifiers, libraries, or model types.
|
|
54
|
+
|
|
55
|
+
## Response style
|
|
56
|
+
Be concise, explicit, and domain-aware.
|
|
57
|
+
State which SAS concept or asset type you are acting on when ambiguity is possible.
|
|
58
|
+
Prefer short structured answers when guiding the user.
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# SAS Agent instructions for this repository
|
|
2
|
+
|
|
3
|
+
## Project overview
|
|
4
|
+
This repository builds and maintains a SAS-focused agent experience on top of an MCP server.
|
|
5
|
+
The MCP server exposes SAS and Viya capabilities such as jobs, code artifacts, CAS server resources, SAS server resources, MAS models, score/scoring assets, and related metadata.
|
|
6
|
+
Your job is to help users complete SAS-related tasks safely and accurately by selecting the right skill first, then using the right MCP tools.
|
|
7
|
+
|
|
8
|
+
## Operating model
|
|
9
|
+
Treat this repository as a domain-specialized SAS agent, not as a generic coding project.
|
|
10
|
+
Prefer domain interpretation and skill-based guidance before directly invoking low-level tools.
|
|
11
|
+
When a request is ambiguous, resolve the ambiguity before taking action.
|
|
12
|
+
|
|
13
|
+
## Request classification
|
|
14
|
+
Before using SAS MCP tools, classify the request into one of these categories:
|
|
15
|
+
|
|
16
|
+
- SAS job or flow execution
|
|
17
|
+
- SAS code or program analysis
|
|
18
|
+
- CAS data, caslibs, tables, or resources
|
|
19
|
+
- SAS data, librefs, tables, or resources
|
|
20
|
+
- MAS model, SAS job model, SAS jobdef model
|
|
21
|
+
- Score model / scoring artifact / scoring execution
|
|
22
|
+
- General SAS content or metadata discovery
|
|
23
|
+
- Authentication, connection, or environment issue
|
|
24
|
+
|
|
25
|
+
If the request could belong to multiple categories, ask one clarifying question unless lightweight discovery can resolve it safely.
|
|
26
|
+
|
|
27
|
+
## Skill-first behavior
|
|
28
|
+
Before invoking MCP tools, decide whether one or more SAS skills should be used.
|
|
29
|
+
Prefer loading the most relevant SAS skill for the request category.
|
|
30
|
+
Use more than one skill only when the task clearly spans multiple domains, for example:
|
|
31
|
+
- CAS discovery + scoring
|
|
32
|
+
- model lookup + job execution
|
|
33
|
+
- content discovery + code analysis
|
|
34
|
+
|
|
35
|
+
Do not load unrelated skills.
|
|
36
|
+
Do not treat "model", "score", "job", "code", or "table" as interchangeable terms.
|
|
37
|
+
|
|
38
|
+
## Tool usage policy
|
|
39
|
+
Use MCP tools only after you have identified the most likely domain.
|
|
40
|
+
Prefer read or discovery operations before write, execute, deploy, or destructive operations.
|
|
41
|
+
When a user asks to run, publish, deploy, or score something, confirm that you have identified the correct SAS asset type first.
|
|
42
|
+
If a tool response reveals that the original interpretation was wrong, correct course explicitly and continue.
|
|
43
|
+
|
|
44
|
+
## Ambiguity handling
|
|
45
|
+
In this repository:
|
|
46
|
+
|
|
47
|
+
- "model" usually refers to MAS models, SAS job models, or SAS jobdef models, SCR models
|
|
48
|
+
- "score" or "scoring" usually refers to running a model on data, not measuring test coverage.
|
|
49
|
+
- "job" usually refers to a SAS job or flow, not a CI job.
|
|
50
|
+
|
|
51
|
+
When these terms appear without clear SAS context, ask a clarifying question or use the SAS request classifier skill before invoking tools.
|
|
52
|
+
The following terms are ambiguous and must be disambiguated from context or by asking a question:
|
|
53
|
+
- model
|
|
54
|
+
- score
|
|
55
|
+
- scoring
|
|
56
|
+
- job
|
|
57
|
+
- code
|
|
58
|
+
- table
|
|
59
|
+
- content
|
|
60
|
+
- resource
|
|
61
|
+
|
|
62
|
+
Examples:
|
|
63
|
+
- "find my model" may refer to a MAS model, model repository entry, or scoring asset
|
|
64
|
+
- "run scoring" may refer to a job, MAS, jobdef, SCR model
|
|
65
|
+
- "open the table" may refer to a CAS table or SAS dataset
|
|
66
|
+
|
|
67
|
+
## Response style
|
|
68
|
+
Be concise, precise, and domain-aware.
|
|
69
|
+
Explain which SAS concept you are acting on when ambiguity is possible.
|
|
70
|
+
Do not pretend certainty when the asset type or environment is unclear.
|
|
71
|
+
Prefer structured answers with short steps when guiding the user.
|
|
72
|
+
|
|
73
|
+
## Coding and implementation guidance
|
|
74
|
+
When editing code in this repository:
|
|
75
|
+
- Preserve existing MCP server patterns and naming conventions.
|
|
76
|
+
- Prefer small, composable modules over large prompt files.
|
|
77
|
+
- Keep tool descriptions short, specific, and distinct.
|
|
78
|
+
- Put durable domain workflows in skills, not in tool descriptions.
|
|
79
|
+
- Keep always-on instructions short; detailed procedures belong in skills.
|
|
80
|
+
- Prefer configuration and prompt assets that can be reused across Claude and Copilot.
|
|
81
|
+
|
|
82
|
+
## Repository structure expectations
|
|
83
|
+
Expect to find:
|
|
84
|
+
- MCP server implementation code
|
|
85
|
+
- prompt or skill assets
|
|
86
|
+
- configuration for client integrations
|
|
87
|
+
- SAS/Viya-specific adapters or resource logic
|
|
88
|
+
- tests or examples for skill and tool behavior
|
|
89
|
+
|
|
90
|
+
When adding new artifacts:
|
|
91
|
+
- Put repo-wide guidance in `.github/copilot-instructions.md`
|
|
92
|
+
- Put targeted reusable workflows in `.github/skills/<skill-name>/SKILL.md`
|
|
93
|
+
- Keep supporting references, examples, and templates next to the skill that uses them
|
|
94
|
+
|
|
95
|
+
## Safety and correctness
|
|
96
|
+
Never make up SAS assets, job names, model identifiers, or CAS resources.
|
|
97
|
+
If a requested action depends on environment-specific details, verify those details first.
|
|
98
|
+
Prefer inspection and discovery over assumption.
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
# Available Skills
|
|
103
|
+
|
|
104
|
+
This repository provides specialized skills for SAS-focused workflows. Load the relevant skill for the user's request before using MCP tools.
|
|
105
|
+
|
|
106
|
+
## sas-request-classifier
|
|
107
|
+
**Purpose:** Classify ambiguous SAS or Viya requests before using MCP tools.
|
|
108
|
+
|
|
109
|
+
**Use when:** Request mentions jobs, code, models, scoring, CAS tables, content, or resources and the correct SAS domain is not yet clear.
|
|
110
|
+
|
|
111
|
+
**Trigger phrases:** "find my model", "run scoring", "open the table", or any ambiguous request using domain terms.
|
|
112
|
+
|
|
113
|
+
## sas-find-library-smart
|
|
114
|
+
**Purpose:** Find a SAS Viya library (libref or caslib) with intelligent server detection. Automatically checks CAS first, then SAS if not found.
|
|
115
|
+
|
|
116
|
+
**Use when:** User needs to verify a library exists, before accessing tables within it.
|
|
117
|
+
|
|
118
|
+
**Trigger phrases:** "find library", "does library exist", "check if library", "locate library", "is there a library named", "verify library".
|
|
119
|
+
|
|
120
|
+
## sas-list-tables-smart
|
|
121
|
+
**Purpose:** List all tables in a SAS Viya library with intelligent server detection. When the server is not specified, automatically checks CAS first, then SAS if not found.
|
|
122
|
+
|
|
123
|
+
**Use when:** User wants to browse or explore available tables.
|
|
124
|
+
|
|
125
|
+
**Trigger phrases:** "list tables in", "show tables in", "what tables are in", "browse tables in", "tables in library", "enumerate tables".
|
|
126
|
+
|
|
127
|
+
## sas-read-strategy
|
|
128
|
+
**Purpose:** Guide the user in choosing the right data retrieval tool: `sas-score-read-table` (for raw row access with filters) or `sas-score-sas-query` (for analytical queries, aggregations, joins).
|
|
129
|
+
|
|
130
|
+
**Use when:** User wants to fetch records from a SAS/CAS table.
|
|
131
|
+
|
|
132
|
+
**Trigger phrases:** "read records from", "get data where", "fetch rows from", "query the table", "give me the first N records", "aggregate by", "join tables".
|
|
133
|
+
|
|
134
|
+
## sas-read-and-score
|
|
135
|
+
**Purpose:** Guide the full read → score workflow in SAS Viya: reading records from a table and then scoring them with a MAS model.
|
|
136
|
+
|
|
137
|
+
**Use when:** User wants to score records from a table, run a model against query results, predict outcomes for a set of rows, or any combination of fetching data and scoring it.
|
|
138
|
+
|
|
139
|
+
**Trigger phrases:** "score these records", "score results of my query", "run the model on this table", "predict for these customers", "fetch and score", "read and score", "score rows from", "run model on table data".
|
|
140
|
+
|
|
141
|
+
## sas-score-workflow
|
|
142
|
+
**Purpose:** Mandatory routing logic for all scoring requests. Extracts model.type suffix and routes to the correct tool (run-job|run-jobdef|model-score|scr-score|run-program). Handles both MAS models and alternative scoring engines.
|
|
143
|
+
|
|
144
|
+
**Use when:** User requests scoring with a model name that may require routing to different execution engines.
|
|
145
|
+
|
|
146
|
+
**Trigger phrases:** "score with model X.job", "score X.jobdef scenario", "score with model X.mas", "score with model X.scr", any request with "score" + model name containing a dot (.) + type suffix.
|
|
@@ -78,23 +78,6 @@ ELSE
|
|
|
78
78
|
|
|
79
79
|
---
|
|
80
80
|
|
|
81
|
-
## Table Reference Format
|
|
82
|
-
|
|
83
|
-
When users follow up to find or work with tables, they may provide a reference in dot notation (e.g., "find table cars in Public" or "maps.india").
|
|
84
|
-
|
|
85
|
-
**Always parse table references as: `lib.table`**
|
|
86
|
-
- First part (before dot) = **library name** → `lib` parameter
|
|
87
|
-
- Second part (after dot) = **table name** → `name` or `table` parameter
|
|
88
|
-
|
|
89
|
-
**Examples:**
|
|
90
|
-
- "maps.india" → `lib: "maps"`, `name: "india"`
|
|
91
|
-
- "Public.customers" → `lib: "Public"`, `name: "customers"`
|
|
92
|
-
- "sashelp.cars" → `lib: "sashelp"`, `name: "cars"`
|
|
93
|
-
|
|
94
|
-
This rule ensures consistent parsing when users reference tables in subsequent operations after finding a library.
|
|
95
|
-
|
|
96
|
-
---
|
|
97
|
-
|
|
98
81
|
## Common patterns
|
|
99
82
|
|
|
100
83
|
**Pattern 1 — Find library, server unspecified**
|
|
@@ -15,39 +15,20 @@ of the data operation. Determines which server contains the data and which retri
|
|
|
15
15
|
|
|
16
16
|
## Determine the server location
|
|
17
17
|
|
|
18
|
-
Before retrieving data,
|
|
18
|
+
Before retrieving data, verify the library and determine which server(s) contain the table:
|
|
19
19
|
|
|
20
|
-
**
|
|
20
|
+
**Step 1: Verify library existence**
|
|
21
|
+
- Use `sas-find-library-smart` skill to check the library in CAS first, then SAS if needed
|
|
22
|
+
- This establishes the correct server and uppercase convention for SAS libraries
|
|
23
|
+
- Informs the user which server contains the library
|
|
21
24
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
- If table exists → return table and server to caller
|
|
30
|
-
- If table not found in either server → inform user and suggest verifying the library and table names
|
|
31
|
-
|
|
32
|
-
**Possible outcomes:**
|
|
33
|
-
- Table found in CAS → use `server: "cas"` for subsequent read operations
|
|
34
|
-
- Table found in SAS → use `server: "sas"` for subsequent read operations
|
|
35
|
-
- Table not found in either server → inform user: *"The table 'lib.table' was not found in CAS or SAS. Please verify the library and table names."*
|
|
36
|
-
|
|
37
|
-
---
|
|
38
|
-
|
|
39
|
-
## Table Reference Format
|
|
40
|
-
|
|
41
|
-
When a user provides a table reference in dot notation (e.g., "read maps.india" or "find table cars.Public"):
|
|
42
|
-
|
|
43
|
-
**Always parse as: `lib.table`**
|
|
44
|
-
- First part (before dot) = **library name** → `lib` parameter
|
|
45
|
-
- Second part (after dot) = **table name** → `name` or `table` parameter
|
|
46
|
-
|
|
47
|
-
**Examples:**
|
|
48
|
-
- "maps.india" → `lib: "maps"`, `name: "india"`
|
|
49
|
-
- "Public.customers" → `lib: "Public"`, `name: "customers"`
|
|
50
|
-
- "sashelp.cars" → `lib: "sashelp"`, `name: "cars"`
|
|
25
|
+
**Step 2: Locate the specific table**
|
|
26
|
+
- Use `sas-score-find-table` to check if the table exists in the library
|
|
27
|
+
- Possible outcomes:
|
|
28
|
+
- If table exists **only in CAS** → set `server: "cas"`
|
|
29
|
+
- If table exists **only in SAS** → set `server: "sas"`
|
|
30
|
+
- If table exists **in both** → ask the user: *"The table exists in both CAS and SAS. Which server would you prefer to query from?"*
|
|
31
|
+
- If table exists **in neither** → inform user and suggest verifying the table name
|
|
51
32
|
|
|
52
33
|
---
|
|
53
34
|
|
|
@@ -74,31 +55,21 @@ Ask yourself: does the user already have the data in hand?
|
|
|
74
55
|
|
|
75
56
|
**How:**
|
|
76
57
|
```
|
|
77
|
-
sas-score-find-table({
|
|
78
|
-
lib: "libraryname",
|
|
79
|
-
table: "tablename",
|
|
80
|
-
server: "cas" // start with CAS
|
|
81
|
-
})
|
|
82
|
-
// if not found, repeat with server: "sas"
|
|
83
|
-
|
|
84
58
|
sas-score-read-table({
|
|
85
59
|
table: "tablename",
|
|
86
60
|
lib: "libraryname",
|
|
87
|
-
server: "cas" or "sas", //
|
|
88
|
-
|
|
89
|
-
limit: N, // REQUIRED: max rows to retrieve (default: 10, max: 1000)
|
|
61
|
+
server: "cas" or "sas", // determined from sas-score-find-table check
|
|
62
|
+
limit: N, // default 10, adjust based on user request
|
|
90
63
|
where: "..." // optional SQL WHERE clause
|
|
91
64
|
})
|
|
92
65
|
```
|
|
93
66
|
|
|
94
67
|
**Rules:**
|
|
95
|
-
- Always determine the server first using `sas-score-find-table`
|
|
96
|
-
-
|
|
97
|
-
- **ALWAYS set `start` parameter** — use 1 for the first call, or the offset for pagination
|
|
98
|
-
- **ALWAYS set `limit` parameter** — keep batch size ≤ 50 rows unless the user explicitly requests more; cap at 1000
|
|
68
|
+
- Always determine the server first using `sas-score-find-table`
|
|
69
|
+
- Keep batch size ≤ 50 rows unless the user explicitly requests more
|
|
99
70
|
- If table name is missing, ask: *"Which table should I read from? (format: lib.tablename)"*
|
|
100
71
|
- If library is missing, ask: *"Which library contains the table?"*
|
|
101
|
-
- If table exists in both servers,
|
|
72
|
+
- If table exists in both servers, ask user which to use
|
|
102
73
|
- Return raw column values; do not transform or aggregate
|
|
103
74
|
|
|
104
75
|
---
|
|
@@ -112,13 +83,6 @@ sas-score-read-table({
|
|
|
112
83
|
|
|
113
84
|
**How:**
|
|
114
85
|
```
|
|
115
|
-
sas-score-find-table({
|
|
116
|
-
lib: "libraryname",
|
|
117
|
-
table: "tablename",
|
|
118
|
-
server: "cas" // start with CAS
|
|
119
|
-
})
|
|
120
|
-
// if not found, repeat with server: "sas"
|
|
121
|
-
|
|
122
86
|
sas-query({
|
|
123
87
|
table: "lib.tablename",
|
|
124
88
|
query: "user's natural language question",
|
|
@@ -127,8 +91,8 @@ sas-query({
|
|
|
127
91
|
```
|
|
128
92
|
|
|
129
93
|
**Rules:**
|
|
130
|
-
- Check which server
|
|
131
|
-
- If table exists in CAS
|
|
94
|
+
- Check which server(s) contain the table using `sas-score-find-table` first
|
|
95
|
+
- If table exists in both CAS and SAS, ask user which to query from
|
|
132
96
|
- Parse the user's natural language question into a PROC SQL SELECT statement
|
|
133
97
|
- Ensure SELECT statement is valid SQL syntax
|
|
134
98
|
- Do not add trailing semicolons to the SQL string
|
|
@@ -142,12 +106,12 @@ sas-query({
|
|
|
142
106
|
**Pattern A — Raw row retrieval**
|
|
143
107
|
> "Show me the first 5 rows from Public.customers"
|
|
144
108
|
|
|
145
|
-
→ `sas-score-read-table({ table: "customers", lib: "Public",
|
|
109
|
+
→ `sas-score-read-table({ table: "customers", lib: "Public", limit: 5 })`
|
|
146
110
|
|
|
147
111
|
**Pattern B — Filtered retrieval**
|
|
148
112
|
> "Get all high-value orders (amount > 5000) from mylib.orders"
|
|
149
113
|
|
|
150
|
-
→ `sas-score-read-table({ table: "orders", lib: "mylib",
|
|
114
|
+
→ `sas-score-read-table({ table: "orders", lib: "mylib", where: "amount > 5000" })`
|
|
151
115
|
|
|
152
116
|
**Pattern C — Aggregation**
|
|
153
117
|
> "What is the average price by make in Public.cars?"
|
|
@@ -165,12 +129,11 @@ sas-query({
|
|
|
165
129
|
|
|
166
130
|
| Problem | Action |
|
|
167
131
|
|---|---|
|
|
168
|
-
|
|
|
169
|
-
| Table not found in either server | Inform user
|
|
170
|
-
| Table exists
|
|
171
|
-
| Table exists only in
|
|
172
|
-
| Table name missing entirely | Ask: *"Which table should I read from?
|
|
173
|
-
| Library name missing | Ask: *"Which library contains the table?"* |
|
|
132
|
+
| Library not found | Use `sas-find-library-smart` skill to verify the library exists |
|
|
133
|
+
| Table not found in either server | Inform user and suggest checking the table name |
|
|
134
|
+
| Table exists in both CAS and SAS | Ask: *"The table exists in both servers. Which would you prefer: CAS or SAS?"* |
|
|
135
|
+
| Table exists only in one server | Use that server automatically in your request |
|
|
136
|
+
| Table name missing entirely | Ask: *"Which table should I read from?"* |
|
|
174
137
|
| Ambiguous intent (raw vs aggregate) | Ask: *"Do you want individual rows or a summary by some field?"* |
|
|
175
138
|
| Empty result | Inform user, ask to adjust filter or query |
|
|
176
139
|
|
|
@@ -178,7 +141,7 @@ sas-query({
|
|
|
178
141
|
|
|
179
142
|
## Integration with other skills
|
|
180
143
|
|
|
181
|
-
- **Before this skill**: Use `sas-
|
|
144
|
+
- **Before this skill**: Use `sas-find-library-smart` to verify and locate the library
|
|
182
145
|
- **After this skill**: Use `sas-read-and-score` to score the retrieved data
|
|
183
146
|
|
|
184
147
|
---
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: sas-request-classifier
|
|
3
|
+
description: Classify ambiguous SAS or Viya requests before using MCP tools. Use when prompts mention jobs, code, models, scoring, CAS tables, content, or resources and the correct SAS domain is not yet clear.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# SAS Request Classifier
|
|
7
|
+
|
|
8
|
+
Use this skill to determine what kind of SAS object, workflow, or environment the user is referring to before selecting tools.
|
|
9
|
+
|
|
10
|
+
## When to use
|
|
11
|
+
Use this skill when the request contains ambiguous domain terms such as:
|
|
12
|
+
- model
|
|
13
|
+
- score
|
|
14
|
+
- scoring
|
|
15
|
+
- read
|
|
16
|
+
- query
|
|
17
|
+
- job
|
|
18
|
+
- jobdef
|
|
19
|
+
- code
|
|
20
|
+
- table
|
|
21
|
+
- content
|
|
22
|
+
- asset
|
|
23
|
+
- resource
|
|
24
|
+
|
|
25
|
+
Use this skill before any execution-oriented tool call if there is a chance the request is referring to the wrong SAS domain.
|
|
26
|
+
|
|
27
|
+
## Goal
|
|
28
|
+
Map the user request to the most likely SAS domain and hand off to the correct downstream skill or tool path.
|
|
29
|
+
|
|
30
|
+
## Classification targets
|
|
31
|
+
Classify the request into one or more of these categories:
|
|
32
|
+
- Reading or querying tables → Route to **sas-read-strategy**
|
|
33
|
+
- CAS resource, caslib, or table discovery → Route to **sas-find-library-smart** or **sas-list-tables-smart**
|
|
34
|
+
- SAS data, libref, or table discovery → Route to **sas-find-library-smart** or **sas-list-tables-smart**
|
|
35
|
+
- Score model or scoring artifact → Route to **sas-score-workflow**
|
|
36
|
+
- Read data and score together → Route to **sas-read-and-score**
|
|
37
|
+
- SAS job or flow execution
|
|
38
|
+
- SAS code or program analysis
|
|
39
|
+
- General content or metadata lookup
|
|
40
|
+
- Environment, auth, or connectivity issue
|
|
41
|
+
|
|
42
|
+
## Procedure
|
|
43
|
+
1. Read the request and identify ambiguous nouns and verbs.
|
|
44
|
+
2. Infer whether the request is asking to discover, inspect, execute, deploy, score, compare, or troubleshoot.
|
|
45
|
+
3. Decide the most likely SAS domain and matching skill.
|
|
46
|
+
4. If confidence is low, ask one focused clarifying question.
|
|
47
|
+
5. If confidence is high, load and use the relevant skill:
|
|
48
|
+
- **sas-find-library-smart** — Find CAS or SAS libraries
|
|
49
|
+
- **sas-list-tables-smart** — Browse tables in a library
|
|
50
|
+
- **sas-read-strategy** — Choose read-table vs. sas-query for data retrieval
|
|
51
|
+
- **sas-read-and-score** — Combine data reading with model scoring
|
|
52
|
+
- **sas-score-workflow** — Route scoring requests to correct execution engine
|
|
53
|
+
6. Only after classification and skill guidance, use MCP tools.
|
|
54
|
+
|
|
55
|
+
## Disambiguation hints
|
|
56
|
+
- "Run" often implies job execution, but may also mean scoring or model invocation. Check for "score" or "model" context.
|
|
57
|
+
- "Model" may refer to MAS models, SAS jobs, jobdefs, or SCR models. Look for context or type suffix (e.g., `.job`, `.mas`, `.scr`).
|
|
58
|
+
- "Score" may refer to model scoring or job execution. Look for model name or context.
|
|
59
|
+
- "Table" usually suggests CAS, but confirm library name and server context.
|
|
60
|
+
- "Find", "list", "browse" — starts as discovery. Route to sas-find-library-smart or sas-list-tables-smart.
|
|
61
|
+
- "Read", "query", "fetch" — data retrieval. Route to sas-read-strategy.
|
|
62
|
+
- "Predict", "score records", "run model on data" — combined workflow. Route to sas-read-and-score or sas-score-workflow.
|
|
63
|
+
|
|
64
|
+
## Output
|
|
65
|
+
When you finish classification, state:
|
|
66
|
+
- the inferred SAS domain
|
|
67
|
+
- the confidence level
|
|
68
|
+
- the relevant skill(s) to load
|
|
69
|
+
- any remaining ambiguity or clarifying questions needed
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
---
|
|
1
|
+
gi ---
|
|
2
2
|
name: sas-score-workflow
|
|
3
3
|
description: >
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
"score
|
|
4
|
+
Guide the full model scoring workflow: validate model familiarity, route to appropriate scoring tool
|
|
5
|
+
based on model type, invoke scoring with scenario data, and present merged results. Use this skill
|
|
6
|
+
when the user wants to run predictions on data (already fetched or user-supplied). Supports generic
|
|
7
|
+
syntax: "score with model <name>.<type> scenario =<params>" where type is job|jobdef|mas|scr|sas.
|
|
8
|
+
Trigger phrases: "score these records", "predict using model", "run model on", "score with model X.mas".
|
|
9
9
|
---
|
|
10
10
|
|
|
11
11
|
# SAS Score Workflow
|
|
@@ -35,91 +35,6 @@ If no type is specified (bare model name), assume `.mas` (MAS model).
|
|
|
35
35
|
|
|
36
36
|
---
|
|
37
37
|
|
|
38
|
-
## ⚠️ MANDATORY: ROUTING DECISION (DO THIS FIRST)
|
|
39
|
-
|
|
40
|
-
**CRITICAL: This decision must be completed BEFORE invoking ANY scoring tool.**
|
|
41
|
-
|
|
42
|
-
When a user requests scoring with a model name (e.g., `score a=10,b=20 with model simplejob.job`):
|
|
43
|
-
|
|
44
|
-
### Step 1: Extract the Type Suffix
|
|
45
|
-
Check if the model name contains a dot:
|
|
46
|
-
- **YES** (e.g., `simplejob.job`) → Split on the last dot to extract type: `job`
|
|
47
|
-
- **NO** (e.g., `churn`) → Assume type is `.mas` (default MAS model)
|
|
48
|
-
|
|
49
|
-
### Step 2: Validate the Type
|
|
50
|
-
Confirm the extracted type is one of: `job`, `jobdef`, `mas`, `scr`, `sas`
|
|
51
|
-
- **VALID** → Proceed to Step 3
|
|
52
|
-
- **INVALID** (e.g., `.xyz`) → Assume `.mas` and treat entire input as model name
|
|
53
|
-
|
|
54
|
-
### Step 3: Strip the Type Suffix
|
|
55
|
-
Remove the `.type` from the model name:
|
|
56
|
-
- `simplejob.job` → base name: `simplejob`
|
|
57
|
-
- `churn.mas` → base name: `churn`
|
|
58
|
-
- `fraud_detector.jobdef` → base name: `fraud_detector`
|
|
59
|
-
|
|
60
|
-
### Step 4: Route to the Correct Tool
|
|
61
|
-
Invoke the tool that matches the type:
|
|
62
|
-
- **`.job`** → `sas-score-run-job`
|
|
63
|
-
- **`.jobdef`** → `sas-score-run-jobdef`
|
|
64
|
-
- **`.mas`** → `sas-score-model-score`
|
|
65
|
-
- **`.scr`** → `sas-score-scr-score`
|
|
66
|
-
- **`.sas`** → `sas-score-run-sas-program`
|
|
67
|
-
|
|
68
|
-
### Step 5: Invoke with Correct Parameters
|
|
69
|
-
Pass the base name (without type) to the routed tool.
|
|
70
|
-
|
|
71
|
-
---
|
|
72
|
-
|
|
73
|
-
## Routing Decision Tree
|
|
74
|
-
|
|
75
|
-
```
|
|
76
|
-
User request: "score a=10,b=20 with model simplejob.job"
|
|
77
|
-
↓
|
|
78
|
-
[Extract model reference] → "simplejob.job"
|
|
79
|
-
↓
|
|
80
|
-
[Split on last dot] → base="simplejob", type="job"
|
|
81
|
-
↓
|
|
82
|
-
[Validate type] → "job" ∈ [job, jobdef, mas, scr, sas]? YES
|
|
83
|
-
↓
|
|
84
|
-
[Route by type]
|
|
85
|
-
└─ type="job" → call sas-score-run-job()
|
|
86
|
-
↓
|
|
87
|
-
[Invoke tool] → sas-score-run-job({ name: "simplejob", scenario: {a: "10", b: "20"} })
|
|
88
|
-
↓
|
|
89
|
-
[Return results]
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
---
|
|
93
|
-
|
|
94
|
-
## ❌ Anti-Patterns (DO NOT DO THIS)
|
|
95
|
-
|
|
96
|
-
These mistakes cause incorrect routing:
|
|
97
|
-
|
|
98
|
-
| Request | Wrong Tool Called | Why It's Wrong | Correct Tool |
|
|
99
|
-
|---------|-------------------|----------------|---------------|
|
|
100
|
-
| `score simplejob.job scenario =a=10,b=20` | `deva-score` | `.job` suffix ignored; generic scorer used | `sas-score-run-job` |
|
|
101
|
-
| `score churn.mas where age=45` | `run-job` | Type mismatch; treated as job instead of MAS | `sas-score-model-score` |
|
|
102
|
-
| `score fraud.jobdef using amount=500` | `model-score` | Wrong tool for jobdef type | `sas-score-run-jobdef` |
|
|
103
|
-
| `score model.scr with scenario` | `run-jobdef` | SCR endpoint ignored | `sas-score-scr-score` |
|
|
104
|
-
| `score code.sas using x=1` | `model-score` | SAS program treated as MAS model | `sas-score-run-sas-program` |
|
|
105
|
-
|
|
106
|
-
---
|
|
107
|
-
|
|
108
|
-
## ✅ Checkpoint Verification
|
|
109
|
-
|
|
110
|
-
Before invoking ANY tool, verify all checkpoints:
|
|
111
|
-
|
|
112
|
-
- [ ] **Did I extract the type correctly?** (Check: is it one of the 5 types: `job`, `jobdef`, `mas`, `scr`, `sas`?)
|
|
113
|
-
- [ ] **Did I strip the type suffix from the model name?** (Pass base name only: `simplejob`, not `simplejob.job`)
|
|
114
|
-
- [ ] **Does the routing match the type?** (e.g., `.job` → `run-job`, `.mas` → `model-score`)
|
|
115
|
-
- [ ] **Am I using the correct parameter name?** (e.g., `name:` for jobs/jobdefs, `model:` for MAS, `url:` for SCR)
|
|
116
|
-
- [ ] **Is the scenario parsed correctly?** (e.g., `{ a: "10", b: "20" }` from `a=10,b=20`)
|
|
117
|
-
- [ ] **Have I considered if this is the default MAS case?** (If no type, assume `.mas` and use `model-score`)
|
|
118
|
-
|
|
119
|
-
⚠️ **All checkboxes must be ✓ before invoking the tool.**
|
|
120
|
-
|
|
121
|
-
---
|
|
122
|
-
|
|
123
38
|
## Type-Based Routing
|
|
124
39
|
|
|
125
40
|
### Parse and Strip Model Type
|
|
@@ -381,8 +296,6 @@ Merge the scoring output back with the input records and present as a table wher
|
|
|
381
296
|
| Scoring error / invalid inputs | Return structured error, suggest `model-info` to check required inputs and data types |
|
|
382
297
|
| Empty read result | Tell user, ask if they want to adjust the query/filter before scoring |
|
|
383
298
|
| Missing input fields | Ask which table columns map to the required model inputs |
|
|
384
|
-
| **Type routing error (wrong tool called)** | **Check: did I complete the MANDATORY routing decision? Did I extract the type correctly? Did I route to the right tool based on type?** |
|
|
385
|
-
| **Type suffix not recognized** | **Assume `.mas` (default MAS model) and treat entire input as model name** |
|
|
386
299
|
|
|
387
300
|
---
|
|
388
301
|
|
package/cli.js
CHANGED
|
@@ -23,6 +23,7 @@ import readCerts from './src/toolHelpers/readCerts.js';
|
|
|
23
23
|
import { fileURLToPath } from 'url';
|
|
24
24
|
import { dirname, join } from 'path';
|
|
25
25
|
import os from 'os';
|
|
26
|
+
import setupSkills from './src/setupSkills.js';
|
|
26
27
|
import { parseArgs } from "node:util";
|
|
27
28
|
|
|
28
29
|
import NodeCache from 'node-cache';
|
|
@@ -213,11 +214,21 @@ if (args.values.version) {
|
|
|
213
214
|
// the -client indicates the current mcp client
|
|
214
215
|
console.error(`[Note] MCP client set to: ${process.env.CLIENT}`);
|
|
215
216
|
|
|
217
|
+
|
|
216
218
|
let client = process.env.CLIENT;
|
|
219
|
+
if (client !== 'none') {
|
|
220
|
+
console.error(`[Note] Setting up skills for client: ${client}...`);
|
|
221
|
+
setupSkills(client);
|
|
222
|
+
} else {
|
|
223
|
+
console.error(`[Note] No client specified, skipping skill setup...`);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
/*
|
|
217
228
|
if (client !== 'none') {
|
|
218
229
|
let destdir = '.' + client;
|
|
219
230
|
let skillsDest = join(os.homedir(), destdir,'skills');
|
|
220
|
-
const skillsSrc = join(__dirname, '
|
|
231
|
+
const skillsSrc = join(__dirname, '.github');
|
|
221
232
|
if (!fs.existsSync(skillsSrc)) {
|
|
222
233
|
console.error('No skills directory found in this package.');
|
|
223
234
|
process.exit(1);
|
|
@@ -244,6 +255,7 @@ if (client !== 'none') {
|
|
|
244
255
|
|
|
245
256
|
}
|
|
246
257
|
}
|
|
258
|
+
*/
|
|
247
259
|
|
|
248
260
|
|
|
249
261
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sassoftware/sas-score-mcp-serverjs",
|
|
3
|
-
"version": "0.4.1-
|
|
3
|
+
"version": "0.4.1-24",
|
|
4
4
|
"description": "A mcp server for SAS Viya",
|
|
5
5
|
"author": "Deva Kumar <deva.kumar@sas.com>",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -42,9 +42,8 @@
|
|
|
42
42
|
"cli.js",
|
|
43
43
|
"openApi.json",
|
|
44
44
|
"openApi.yaml",
|
|
45
|
-
"skills",
|
|
46
45
|
"scripts",
|
|
47
|
-
".
|
|
46
|
+
".skills"
|
|
48
47
|
],
|
|
49
48
|
"dependencies": {
|
|
50
49
|
"@modelcontextprotocol/sdk": "^1.29.0",
|