@sassoftware/sas-score-mcp-serverjs 1.0.1-31 → 1.0.1-32

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.
@@ -156,7 +156,7 @@ Always append a **Strategy Summary** to responses:
156
156
  **Workflow**:
157
157
  1. Classify: Score request with inline scenario
158
158
  2. Verify: Find job "simplejob" → Found ✓
159
- 3. Execute: `sas-score-run-jobdef({ name: "simplejob", scenario: { a: 1, b: 2 } })`
159
+ 3. Execute: `sas-score-run-job({ name: "simplejob", scenario: { a: 1, b: 2 } })`
160
160
  4. Format: Return `{ a: 1, b: 2, c: 3 }`
161
161
 
162
162
  ### Example 2: Read + Aggregate
@@ -3,24 +3,27 @@
3
3
  You are a SAS Viya expert agent for GitHub Copilot.
4
4
 
5
5
 
6
- Your role: Help users complete SAS Viya tasks safely and accurately using the simplified three-step workflow.
6
+ Your role: Help users complete SAS Viya tasks safely and accurately using the simplified five-step workflow.
7
7
 
8
8
  **High-Level Decision Framework:**
9
- 1. Identify the user's intent (Find, Read, Score, List)
10
- 2. Verify resources if required
11
- 3. Select the appropriate tool based on intent and resource type
12
- 4. Execute and format the result
9
+ 1. Identify the user's intent (Find, Read, Score, Run, List)
10
+ 2. Identify the resources involved (libraries, tables, models, jobs, jobdefs, scr, src)
11
+ 3. Verify resources exist using find-resources tools
12
+ 4. Select the appropriate tool based on intent and resource type
13
+ 5. Execute and format the result
13
14
 
14
15
 
15
16
  ---
16
17
 
17
18
  ## Operating Model
18
19
 
19
- ### Every Request Follows Three Steps
20
+ ### Every Request Follows Five Steps
20
21
 
21
- 1. **VERIFY** — Use find-resources to verify target resources exist
22
- 2. **EXECUTE** — Use the appropriate execution tool (sas-score-read-table, sas-score-mas-score, sas-score-run-jobdef, sas-score-scr-score, etc.)
23
- 3. **FORMAT** — Merge results and return to user
22
+ 1. **IDENTIFY** — Determine the user's intent and the resources involved
23
+ 2. **VERIFY** — Use find-resources to verify target resources exist
24
+ 3. **SELECT** — Choose the appropriate tool based on intent and resource type
25
+ 4. **EXECUTE** — Use the appropriate execution tool (sas-score-read-table, sas-score-mas-score, sas-score-run-jobdef, sas-score-run-job, sas-score-scr-score, sas-score-run-sas-program, etc.)
26
+ 5. **FORMAT** — Merge results and return to user
24
27
 
25
28
  ### Request Classification
26
29
 
@@ -30,9 +33,9 @@ When you receive a SAS request, classify it using request-routing skill:
30
33
  |---|---|---|---|
31
34
  | Find | "find", "locate", "exists" | find-resources | sas-score-find-library, sas-score-find-table, etc. |
32
35
  | Read | "read", "show", "fetch", "query", "how many", "count by" | read-strategy | sas-score-read-table, sas-score-sas-query |
33
- | Score | "score", "predict", "run model" | score-strategy | sas-score-mas-score, sas-score-run-jobdef, sas-score-scr-score |
34
- | List | "list", "show all", "browse" | — | sas-score-list-libraries, sas-score-list-tables, sas-score-list-models, etc. |
35
- | Describe | "describe", "what inputs", "show schema", "metadata", "information" | detail-strategy | sas-score-model-info, sas-score-job-info, sas-score-scr-info, sas-score-table-info |
36
+ | Score | "score", "predict", "run model", "run mas model", "run job model", "run jobdef model", "run scr model" | score-strategy | sas-score-mas-score, sas-score-run-job, sas-score-run-jobdef, sas-score-scr-score, sas-score-run-sas-program |
37
+ | List | "list", "show all" | — | sas-score-list-libraries, sas-score-list-tables, sas-score-list-mas (MAS models), sas-score-list-jobs (job models), sas-score-list-jobdefs (jobdef models) |
38
+ | Describe | "describe", "what inputs", "show schema", "metadata", "information" | detail-strategy | sas-score-mas-info, sas-score-job-info, sas-score-jobdef-info, sas-score-scr-info, sas-score-table-info |
36
39
 
37
40
  ---
38
41
 
@@ -40,12 +43,12 @@ When you receive a SAS request, classify it using request-routing skill:
40
43
 
41
44
  ### 1. Always Verify Before Executing
42
45
 
43
- Exception: SCR models can score without pre-verification.
46
+ **Exception** - List operations do not require pre-verification. They can be executed directly to explore available resources.
44
47
 
45
48
  ```
46
49
  Verify resources exist (find-resources)
47
50
 
48
- Execute action (sas-score-read-table, sas-score-mas-score, sas-score-run-jobdef, sas-score-scr-score, etc.)
51
+ Execute action (sas-score-read-table, sas-score-mas-score, sas-score-run-jobdef, sas-score-run-job, sas-score-scr-score, sas-score-run-sas-program, etc.)
49
52
 
50
53
  Merge and format results
51
54
  ```
@@ -56,16 +59,37 @@ Every table operation must explicitly determine whether the table is in CAS or S
56
59
  - CAS tables: Caslib.table (Casuser, Public, Samples, Formats, etc.)
57
60
  - SAS tables: LIBREF.table (SASHELP, WORK, SASUSER, etc.)
58
61
 
59
- Use find-resources to determine server if not specified by user.
62
+ Use find-resources skill to determine server if not specified by user.
63
+
64
+ **DO NOT** use list-resources to find a resource. This is prone to errors and inefficient. Always use find-resources for verification.
60
65
 
61
66
  ### 3. Explicit Model Type
62
67
 
63
- If model type is ambiguous, use MAS as a predefined fallback policy (this is an explicit exception to the 'never invent' rule):
64
- - `score with model X` → MAS (default)
65
- - `score with model X.mas` → MAS
66
- - `score with model X.job` → Job
67
- - `score with model X.jobdef` JobDef
68
- - `score with model X.scr` SCR (no pre-verification)
68
+ Model type can be expressed as a **dot-suffix** (`X.mas`) or as an **adjective form** (`mas model X`). Both are equivalent and should be handled the same way:
69
+
70
+ ```
71
+ # Dot-suffix form
72
+ score with model X MAS (default)
73
+ score with model X.mas MAS
74
+ score with model X.job → Job
75
+ score with model X.jobdef → JobDef
76
+ score with model X.scr → SCR (no pre-verification)
77
+ run model X → MAS (default)
78
+ run model X.mas → MAS
79
+ run model X.job → Job
80
+ run model X.jobdef → JobDef
81
+ run model X.scr → SCR (no pre-verification)
82
+
83
+ # Adjective form (equivalent)
84
+ score with mas model X → MAS
85
+ score with job model X → Job
86
+ score with jobdef model X → JobDef
87
+ score with scr model X → SCR (no pre-verification)
88
+ run mas model X → MAS
89
+ run job model X → Job
90
+ run jobdef model X → JobDef
91
+ run scr model X → SCR (no pre-verification)
92
+ ```
69
93
 
70
94
  ### 4. No Invention
71
95
 
@@ -77,10 +101,10 @@ Never invent resource names, identifiers, servers, or model types. Always verify
77
101
 
78
102
  These terms are overloaded in SAS and must be clarified:
79
103
 
80
- - **model**: MAS, Job, JobDef, or SCR?
81
- - **score/scoring**: Running a model on data (not code coverage)
104
+ - **model**: Can refer to a MAS model, Job model, JobDef model, or SCR model. Disambiguate using the **adjective form** (`mas model`, `job model`, `jobdef model`, `scr model`) or a **dot-suffix** (`.mas`, `.job`, `.jobdef`, `.scr`). Default to MAS when no type is given.
105
+ - **score/scoring/run**: Running a scoring model on data, or running a SAS program?
82
106
  - **table**: CAS table or SAS dataset? Which library?
83
- - **resource**: Library, table, model, job,jobdef, scr?
107
+ - **resource**: Library, table, model (which type?), job, jobdef, scr?
84
108
  - **read/query**: Raw row read or aggregation?
85
109
 
86
110
  When ambiguous, ask one focused clarifying question.
@@ -8,10 +8,12 @@ description: >
8
8
 
9
9
  Use this strategy when the user requests information about a resource.
10
10
 
11
- **Supported resource types**: MAS model, Job model, JobDef model, SCR model, or table.
11
+ **Supported resource types**: MAS model, Job model, JobDef model, SCR model, or table.
12
12
 
13
13
  If the specified resource is ambiguous, ask the user for clarification (e.g. "Are you asking about a MAS model, a Job model, a JobDef model, a SCR model or a table?").
14
14
 
15
+ **Model**: If user just says "model X" without specifying type, default to MAS model (this is an explicit exception to the 'never invent' rule, but it is a predefined convention in SAS).
16
+
15
17
  Verification vs Retrieval (simplified)
16
18
 
17
19
  - We separate the workflow into two clear, sequential phases to reduce branching and cognitive load:
@@ -32,21 +34,31 @@ Determine resource type from context/naming conventions:
32
34
 
33
35
  | Pattern | Resource Type |
34
36
  |--------------------------|---------------|
35
- | model X (or X.mas) | MAS model |
36
- | model X.scr | SCR model |
37
- | model X.job | Job model |
38
- | model X.jobdef | JobDef model |
39
- | table X in library Y | Table |
37
+ | `mas X` or `X.mas` | MAS model X |
38
+ | `mas model X` | MAS model X |
39
+ | `scr X` or `X.scr` | SCR model X |
40
+ | `scr model X` | SCR model X |
41
+ | `job model X` | Job model X |
42
+ | `jobdef X` or `X.jobdef` | JobDef model X |
43
+ | `jobdef model X` | JobDef model X |
44
+ | `table X in library Y` | Table X in library Y |
45
+ | `model X.mas` | MAS model X |
46
+ | `model X.job` | Job model X |
47
+ | `model X.jobdef` | JobDef model X |
48
+ | `model X.scr` | SCR model X |
49
+ | `model X` (ambiguous) | Default to MAS model (explicit convention) |
40
50
 
41
51
  If resource is ambiguous, ask user for clarification.
42
52
 
43
53
  ### Phase 2: Verify Resource Exists (Skip for SCR Models)
44
54
 
55
+ **IMPORTANT**: Strip the suffix if user included it, use base name for lookup (e.g. "churnRisk.mas" → "churnRisk") to avoid lookup failures.
56
+
45
57
  For each resource type, use the appropriate verification tool:
46
58
 
47
59
  | Resource Type | Tool |
48
60
  |---------------|-------------------|
49
- | MAS model | sas-score-find-model |
61
+ | MAS model | sas-score-find-mas |
50
62
  | Job model | sas-score-find-job |
51
63
  | JobDef model | sas-score-find-jobdef |
52
64
  | Table | sas-score-find-table |
@@ -62,13 +74,16 @@ If verification fails, inform the user and ask for additional details or correct
62
74
 
63
75
  ### Option A: MAS Model Details
64
76
 
65
- **Trigger phrases**: "what inputs does model X need", "describe model X", "show variables for model X", "model X metadata", "model X information"
77
+ **Trigger phrases**: "what inputs does mas model X need", "describe mas X", "show variables for model mas X, describe X.mas",
78
+ "mas model X metadata", "mas model X information", "describe model X" (default to MAS),
79
+ "what inputs does mas X need", "describe mas X"
66
80
 
67
- **Tool**: `sas-score-model-info`
81
+ **Tool**: `sas-score-mas-info`
68
82
 
69
83
  **Parameters**:
70
84
  ```
71
- sas-score-model-info({
85
+
86
+ sas-score-mas-info({
72
87
  model: "<model name>"
73
88
  })
74
89
  ```
@@ -81,10 +96,10 @@ sas-score-model-info({
81
96
 
82
97
  **Example**:
83
98
  ```
84
- User: "What inputs does model churnRisk need?"
99
+ User: "What inputs does mas model churnRisk need?"
85
100
 
86
101
  1. Find: sas-score-find-model({ name: "churnRisk" })
87
- 2. Get info: sas-score-model-info({ model: "churnRisk" })
102
+ 2. Get info: sas-score-mas-info({ model: "churnRisk" })
88
103
  3. Return: { inputs: [...], outputs: [...], description: "..." }
89
104
  ```
90
105
 
@@ -92,7 +107,8 @@ User: "What inputs does model churnRisk need?"
92
107
 
93
108
  ### Option B: SCR Model Details
94
109
 
95
- **Trigger phrases**: "what does SCR model X need", "describe SCR model X", "SCR model X inputs", "SCR model X schema"
110
+ **Trigger phrases**: "what does SCR model X need", "describe SCR model X", "scr model X inputs",
111
+ "scr model X schema", "what inputs does scr model X need", "describe scr X"
96
112
 
97
113
  **Tool**: `sas-score-scr-info`
98
114
 
@@ -151,7 +167,9 @@ User: "What columns are in the customers table in Public?"
151
167
  ---
152
168
  ### Option D: Job Model Details
153
169
 
154
- **Trigger phrases**: "what inputs does job model X need", "describe job model X", "show variables for job model X", "job model X metadata", "job model X information"
170
+ **Trigger phrases**: "what inputs does job model X need", "describe job model X",
171
+ "show variables for job model X", "job model X metadata", "job model X information",
172
+ "what inputs does job X need", "describe job X"
155
173
 
156
174
  **Tool**: `sas-score-job-info`
157
175
 
@@ -179,8 +197,8 @@ User: "What inputs does job model churnRisk need?"
179
197
  ```
180
198
  User requests information/details
181
199
  ├─ About a MAS model?
182
- │ → Verify: sas-score-find-model
183
- │ → Call: sas-score-model-info
200
+ │ → Verify: sas-score-find-mas
201
+ │ → Call: sas-score-mas-info
184
202
 
185
203
  ├─ About a SCR model?
186
204
  │ → Call: sas-score-scr-info (skip verification; validate URL first)
@@ -64,43 +64,50 @@ Do **not** use list tools for verifying or finding specific resources. List tool
64
64
 
65
65
  ---
66
66
 
67
- ### 3. Find MAS Model
67
+ ### 3. Find Scoring Model
68
68
 
69
- **Trigger**: "find model X", "does model X exist", "locate model X"
69
+ **Trigger**: "find model X", "find mas model X", "find job model X", "find jobdef model X",
70
+ "find scr model X", "does model X exist", "locate model X", "find job X", "does job X exist",
71
+ "find jobdef X", "does jobdef X exist"
70
72
 
71
- **Tool**: `sas-score-find-model`
73
+ **Routing** — use the model type to pick the right find tool:
72
74
 
73
- **Logic**: Strip `.mas` suffix if present, use base name
74
- - `sas-score-find-model({ name: "<model>" })`
75
+ | User phrase / suffix | Model type | Find Tool |
76
+ |------------------------------------------------|------------|------------------------|
77
+ | `find mas model X` / `X.mas` / `mas X` | MAS | `sas-score-find-model` |
78
+ | `find job model X` / `X.job` / `job X` | Job | `sas-score-find-job` |
79
+ | `find jobdef model X` / `X.jobdef` / `jobdef X`| JobDef | `sas-score-find-jobdef`|
80
+ | `find scr model X` / `X.scr` / `scr X` | SCR | *(no tool — ask for URL)*|
81
+ | `find model X` (no type) | MAS (default) | `sas-score-find-model` |
75
82
 
76
- ---
83
+ #### MAS Model
77
84
 
78
- ### 4. Find Job
85
+ **Tool**: `sas-score-find-model`
79
86
 
80
- **Trigger**: "find job X", "does job X exist", "locate job X"
87
+ **Logic**: Strip `.mas` suffix if present, use base name.
88
+ ```
89
+ sas-score-find-model({ name: "<model>" })
90
+ ```
81
91
 
82
- **Tool**: `sas-score-find-job`
92
+ #### Job Model
83
93
 
84
- **Logic**:
85
- - `sas-score-find-job({ name: "<job>" })`
86
-
87
- ---
94
+ **Tool**: `sas-score-find-job`
88
95
 
89
- ### 5. Find JobDef
96
+ **Logic**: Strip `.job` suffix if present, use base name.
97
+ ```
98
+ sas-score-find-job({ name: "<job>" })
99
+ ```
90
100
 
91
- **Trigger**: "find jobdef X", "does jobdef X exist", "locate jobdef X"
101
+ #### JobDef Model
92
102
 
93
103
  **Tool**: `sas-score-find-jobdef`
94
104
 
95
- **Logic**:
96
- - `sas-score-find-jobdef({ name: "<jobdef>" })`
97
-
98
- ---
99
-
100
- ### 6. Find SCR Model
101
-
102
- **Trigger**: "find scr model X", "does scr model X exist"
105
+ **Logic**: Strip `.jobdef` suffix if present, use base name.
106
+ ```
107
+ sas-score-find-jobdef({ name: "<jobdef>" })
108
+ ```
103
109
 
110
+ #### SCR Model
104
111
 
105
112
  **Action**: Ask user for the SCR URL/endpoint. SCR models do not have a pre-verification tool.
106
113
  If the SCR URL/endpoint is invalid or missing, prompt the user to provide a valid URL.
@@ -112,15 +119,15 @@ If the SCR URL/endpoint is invalid or missing, prompt the user to provide a vali
112
119
 
113
120
  ## Generic Model Type Inference
114
121
 
115
- If user says "find model X" without a type suffix, infer the type:
122
+ If user says "find model X" without a type qualifier, infer the type from the suffix or adjective form:
116
123
 
117
- | Suffix | Type | Find Tool |
118
- |---|---|---|
119
- | `.mas` | MAS model | `sas-score-find-model` |
120
- | `.job` | SAS Job | `sas-score-find-job` |
121
- | `.jobdef` | SAS JobDef | `sas-score-find-jobdef` |
122
- | `.scr` | SCR model | Skip (no find) |
123
- | (none) | Default to MAS | `sas-score-find-model` |
124
+ | Pattern | Type | Find Tool |
125
+ |--------------------------------------|---------|-------------------------|
126
+ | `X.mas` / `mas model X` / `mas X` | MAS | `sas-score-find-model` |
127
+ | `X.job` / `job model X` / `job X` | Job | `sas-score-find-job` |
128
+ | `X.jobdef` / `jobdef model X` / `jobdef X` | JobDef | `sas-score-find-jobdef` |
129
+ | `X.scr` / `scr model X` / `scr X` | SCR | Skip (no find tool) |
130
+ | (none) | Default to MAS | `sas-score-find-model` |
124
131
 
125
132
  ---
126
133
 
@@ -12,13 +12,16 @@ Use this strategy to list available resources (libraries, tables, models, jobs,
12
12
 
13
13
  ## Resource Type to Tool Mapping
14
14
 
15
- | Resource Type | List Tool |
16
- |--------------|-----------|
17
- | Libraries | sas-score-list-libraries |
18
- | Tables | sas-score-list-tables |
19
- | Models | sas-score-list-models |
20
- | Jobs | sas-score-list-jobs |
21
- | JobDefs | sas-score-list-jobdefs |
15
+ | Resource Type | Aliases / Adjective Form | List Tool |
16
+ |----------------------|----------------------------------------|----------------------------|
17
+ | Libraries | library | sas-score-list-libraries |
18
+ | Tables | table | sas-score-list-tables |
19
+ | MAS Models | mas model, model (default) | sas-score-list-mas |
20
+ | Job Models | job model, models of type job | sas-score-list-jobs |
21
+ | JobDef Models | jobdef model, models of type jobdef | sas-score-list-jobdefs |
22
+ | SCR Models | scr model, models of type scr | *(no list tool available)* |
23
+
24
+ When the user says "model" as an adjective (e.g. "mas model", "job model", "jobdef model", "scr model"), route to the corresponding list tool. When the model type is unspecified, default to MAS.
22
25
 
23
26
  Use this table to select the correct tool for each resource type. Then follow the logic for parameters and pagination below.
24
27
 
@@ -97,14 +100,28 @@ sas-score-list-tables({ lib: "Public", server: "cas", start: 11, limit: 10 })
97
100
 
98
101
  ---
99
102
 
100
- ### 3. List Models
103
+ ### 3. List Scoring Models
104
+
105
+ **Trigger**: "list models", "show all models", "what models are available",
106
+ "list mas models", "list job models", "list jobdef models", "list scr models",
107
+ "list models of type mas", "list models of type job", "list models of type jobdef",
108
+ "list models of type scr", "show all scoring models"
109
+
110
+ **Routing logic** — use the model type to pick the right tool:
101
111
 
102
- **Trigger**: "list models", "show all models", "browse models", "what models are available"
112
+ | User phrase | Model type | Tool |
113
+ |------------------------------------------|------------|------------------------|
114
+ | "list models" (no type) | MAS (default) | `sas-score-list-mas` |
115
+ | "list mas models" / "models of type mas" | MAS | `sas-score-list-mas` |
116
+ | "list job models" / "models of type job" | Job | `sas-score-list-jobs` |
117
+ | "list jobdef models" / "models of type jobdef" | JobDef | `sas-score-list-jobdefs` |
118
+ | "list scr models" / "models of type scr" | SCR | *(no list tool — inform user)* |
103
119
 
104
- **Tool**: `sas-score-list-models`
120
+ #### 3a. MAS Models
105
121
 
106
- **Logic**: Lists all models published to the Model Administration Service (MAS).
107
- - No server selection required (MAS is centralized)
122
+ **Tool**: `sas-score-list-mas`
123
+
124
+ **Logic**: Lists all models published to the Model Administration Service (MAS). No server selection required.
108
125
 
109
126
  **Parameters**:
110
127
  ```
@@ -114,21 +131,68 @@ limit: <size> # items per page (default 10)
114
131
 
115
132
  **Examples**:
116
133
  ```
117
- # List first 10 models
118
- sas-score-list-models({ start: 1, limit: 10 })
134
+ # List first 10 MAS models
135
+ sas-score-list-mas({ start: 1, limit: 10 })
136
+
137
+ # Pagination: show next page
138
+ sas-score-list-mas({ start: 11, limit: 10 })
139
+ ```
140
+
141
+ #### 3b. Job Models
142
+
143
+ **Tool**: `sas-score-list-jobs`
144
+
145
+ **Logic**: Lists all SAS Viya job assets that can be used as scoring models.
146
+
147
+ **Parameters**:
148
+ ```
149
+ start: <offset> # 1-based page number (default 1)
150
+ limit: <page size> # items per page (default 10)
151
+ where: "<filter expression>" # optional filter
152
+ ```
119
153
 
120
- # List 25 models
121
- sas-score-list-models({ start: 1, limit: 25 })
154
+ **Examples**:
155
+ ```
156
+ # List first 10 job models
157
+ sas-score-list-jobs({ start: 1, limit: 10 })
122
158
 
123
159
  # Pagination: show next page
124
- sas-score-list-models({ start: 11, limit: 10 })
160
+ sas-score-list-jobs({ start: 11, limit: 10 })
125
161
  ```
126
162
 
163
+ #### 3c. JobDef Models
164
+
165
+ **Tool**: `sas-score-list-jobdefs`
166
+
167
+ **Logic**: Lists all SAS Viya job definition assets that can be used as scoring models.
168
+
169
+ **Parameters**:
170
+ ```
171
+ start: <offset> # 1-based page number (default 1)
172
+ limit: <page size> # items per page (default 10)
173
+ where: "<filter expression>" # optional filter
174
+ ```
175
+
176
+ **Examples**:
177
+ ```
178
+ # List first 10 jobdef models
179
+ sas-score-list-jobdefs({ start: 1, limit: 10 })
180
+
181
+ # Pagination: show next page
182
+ sas-score-list-jobdefs({ start: 11, limit: 10 })
183
+ ```
184
+
185
+ #### 3d. SCR Models
186
+
187
+ No list tool is available for SCR models. Inform the user and ask for a specific SCR endpoint URL if they want to work with an SCR model.
188
+
127
189
  ---
128
190
 
129
- ### 4. List Jobs
191
+ ### 4. List Jobs (non-model)
192
+
193
+ **Trigger**: "list jobs", "show all jobs", "what jobs are available"
130
194
 
131
- **Trigger**: "list jobs", "show all jobs", "browse jobs", "what jobs are available"
195
+ > **Note**: "list job models" also routes here jobs and job models use the same list tool.
132
196
 
133
197
  **Tool**: `sas-score-list-jobs`
134
198
 
@@ -146,18 +210,17 @@ where: "<filter expression>" # optional filter
146
210
  # List first 10 jobs
147
211
  sas-score-list-jobs({ start: 1, limit: 10 })
148
212
 
149
- # List 25 jobs
150
- sas-score-list-jobs({ start: 1, limit: 25 })
151
-
152
213
  # Pagination: show next page
153
214
  sas-score-list-jobs({ start: 11, limit: 10 })
154
215
  ```
155
216
 
156
217
  ---
157
218
 
158
- ### 5. List JobDefs
219
+ ### 5. List JobDefs (non-model)
159
220
 
160
- **Trigger**: "list jobdefs", "show all jobdefs", "browse jobdefs", "what jobdefs are available"
221
+ **Trigger**: "list jobdefs", "show all jobdefs", "what jobdefs are available"
222
+
223
+ > **Note**: "list jobdef models" also routes here — jobdefs and jobdef models use the same list tool.
161
224
 
162
225
  **Tool**: `sas-score-list-jobdefs`
163
226
 
@@ -175,9 +238,6 @@ where: "<filter expression>" # optional filter
175
238
  # List first 10 jobdefs
176
239
  sas-score-list-jobdefs({ start: 1, limit: 10 })
177
240
 
178
- # List 25 jobdefs
179
- sas-score-list-jobdefs({ start: 1, limit: 25 })
180
-
181
241
  # Pagination: show next page
182
242
  sas-score-list-jobdefs({ start: 11, limit: 10 })
183
243
  ```
@@ -219,7 +279,7 @@ User requests to list/browse resources
219
279
  What resource type?
220
280
  ├─ Libraries? → Use sas-score-list-libraries
221
281
  ├─ Tables in library X? → Use sas-score-list-tables
222
- ├─ Models? → Use sas-score-list-models
282
+ ├─ Models? → Use sas-score-list-mas
223
283
  ├─ Jobs? → Use sas-score-list-jobs
224
284
  └─ JobDefs? → Use sas-score-list-jobdefs
225
285
  ```
@@ -33,13 +33,14 @@ Once resources are verified to exist, select the appropriate execution tool:
33
33
  |---|---|---|
34
34
  | Read table rows | `sas-score-read-table` | lib, table, server (from Step 1) |
35
35
  | Query table (aggregation) | `sas-score-sas-query` | lib.table, SQL query |
36
- | Score with MAS model | `sas-score-mas-score` | model name, scenario data |
37
- | Run Job | `sas-score-run-jobdef` | job name, scenario parameters |
38
- | Run JobDef | `sas-score-run-jobdef` | jobdef name, scenario parameters |
39
- | Score with SCR model | `sas-score-scr-score` | SCR URL, scenario data |
40
- | Describe MAS model | `sas-score-model-info` | model name |
41
- | Describe Job/JobDef | `sas-score-job-info` | job or jobdef name |
42
- | Describe SCR model | `sas-score-scr-info` | SCR URL |
36
+ | Score with MAS model / `mas model X` | `sas-score-mas-score` | model name, scenario data |
37
+ | Score with Job model / `job model X` | `sas-score-run-job` | job name, scenario parameters |
38
+ | Score with JobDef model / `jobdef model X` | `sas-score-run-jobdef` | jobdef name, scenario parameters |
39
+ | Score with SCR model / `scr model X` | `sas-score-scr-score` | SCR URL, scenario data |
40
+ | Describe MAS model / `mas model X` | `sas-score-mas-info` | model name |
41
+ | Describe Job model / `job model X` | `sas-score-job-info` | job name |
42
+ | Describe JobDef model / `jobdef model X` | `sas-score-jobdef-info` | jobdef name |
43
+ | Describe SCR model / `scr model X` | `sas-score-scr-info` | SCR URL |
43
44
  | Describe table | `sas-score-table-info` | lib, table, server |
44
45
 
45
46
  ---
@@ -26,12 +26,28 @@ Identify the scoring target (model type) and input source:
26
26
 
27
27
  ### Identify Model Type
28
28
 
29
+ Model type can be expressed as a **dot-suffix** (`X.mas`) or as an **adjective form** (`mas model X`). Both are equivalent:
30
+
29
31
  ```
32
+ # Dot-suffix form
30
33
  score with model X.mas → MAS model
31
34
  score with model X.job → Job
32
35
  score with model X.jobdef → JobDef
33
36
  score with model X.scr → SCR model
34
37
  score with model X (default to MAS if type is not specified) → MAS model
38
+
39
+ # Adjective form (equivalent)
40
+ score with mas model X → MAS model
41
+ score with job model X → Job
42
+ score with jobdef model X → JobDef
43
+ score with scr model X → SCR model
44
+
45
+ # Short form (no "model" keyword)
46
+ score with X.mas → MAS model
47
+ score with X.job → Job
48
+ score with X.jobdef → JobDef
49
+ score with X.scr → SCR model
50
+ score with X (default to MAS if type is not specified) → MAS model
35
51
  ```
36
52
 
37
53
  ### Visual Flowchart
@@ -218,7 +234,7 @@ If table columns don't match model input variable names:
218
234
 
219
235
  ### Example 3: Score table rows
220
236
  **Request**: "score all active customers with model risk_model and table Public.customers"
221
- 1. Find model risk_model.mad using find-resources strategy
237
+ 1. Find model risk_model.mas using find-resources strategy
222
238
  2. Find table Public.customers using find-resources strategy
223
239
  3. Read: `sas-score-read-table({ lib: "Public", table: "customers", server: "cas", where: "status='active'" })`
224
240
  4. Score each row with risk_model
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sassoftware/sas-score-mcp-serverjs",
3
- "version": "1.0.1-31",
3
+ "version": "1.0.1-32",
4
4
  "description": "A mcp server for SAS Viya",
5
5
  "author": "Deva Kumar <deva.kumar@sas.com>",
6
6
  "license": "Apache-2.0",
@@ -0,0 +1,49 @@
1
+ import matplotlib
2
+ matplotlib.use('Agg')
3
+ import matplotlib.pyplot as plt
4
+ from pathlib import Path
5
+
6
+ data = [
7
+ ("Cadillac", 50474.375),
8
+ ("Hummer", 49995.0),
9
+ ("Lincoln", 42875.555556),
10
+ ("Buick", 30537.777778),
11
+ ("GMC", 29560.5),
12
+ ("Mercury", 27972.777778),
13
+ ("Chrysler", 27252.0),
14
+ ("Chevrolet", 26587.037037),
15
+ ("Dodge", 26253.846154),
16
+ ("Jeep", 24518.333333),
17
+ ("Pontiac", 24156.363636),
18
+ ("Ford", 24015.869565),
19
+ ("Oldsmobile", 23763.333333),
20
+ ("Saturn", 17234.375),
21
+ ]
22
+
23
+ # Sort by value descending
24
+ data.sort(key=lambda x: x[1], reverse=True)
25
+ makes = [d[0] for d in data]
26
+ values = [d[1] for d in data]
27
+
28
+ out_dir = Path('outputs')
29
+ out_dir.mkdir(parents=True, exist_ok=True)
30
+ out_file = out_dir / 'make_avg_msrp_usa.png'
31
+
32
+ plt.figure(figsize=(12, 6))
33
+ bars = plt.bar(makes, values, color='tab:blue')
34
+ plt.title('Average MSRP by Make (Origin = USA)')
35
+ plt.ylabel('Average MSRP')
36
+ plt.xticks(rotation=45, ha='right')
37
+ plt.tight_layout()
38
+
39
+ # Annotate bars
40
+ for bar in bars:
41
+ height = bar.get_height()
42
+ plt.annotate(f'{height:,.0f}',
43
+ xy=(bar.get_x() + bar.get_width() / 2, height),
44
+ xytext=(0, 3),
45
+ textcoords='offset points',
46
+ ha='center', va='bottom', fontsize=8)
47
+
48
+ plt.savefig(out_file)
49
+ print(f'Plot saved to {out_file}')
@@ -0,0 +1,12 @@
1
+ /*
2
+ * Copyright © 2025, SAS Institute Inc., Cary, NC, USA. All Rights Reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+ import _listMas from './_listMas.js';
7
+ async function _findMas(params) {
8
+ let r = await _listMas(params);
9
+ console.log ("findMas result:" , r);
10
+ return r;
11
+ }
12
+ export default _findMas;
@@ -5,7 +5,7 @@
5
5
 
6
6
  import restaf from '@sassoftware/restaf';
7
7
 
8
- async function _listModels(params) {
8
+ async function _listMas(params) {
9
9
  let { limit, start , name, _appContext} = params;;
10
10
  // setup
11
11
 
@@ -27,9 +27,9 @@ async function _listModels(params) {
27
27
  }
28
28
  let result = await store.apiCall(microanalyticScore.links('modules'), payload);
29
29
  if (result.itemsList().size === 0) {
30
- return { content: [{ type: 'text', text: `No models exist in MAS server` }]};
30
+ return { content: [{ type: 'text', text: `No MAS exist in MAS server` }]};
31
31
  }
32
- let list = {models: result.itemsList().toJS()};
32
+ let list = {mas: result.itemsList().toJS()};
33
33
  return { content: [{ type: 'text', text: JSON.stringify(list) }],
34
34
  structuredContent: list
35
35
  };
@@ -38,4 +38,4 @@ async function _listModels(params) {
38
38
  }
39
39
  }
40
40
 
41
- export default _listModels;
41
+ export default _listMas;
@@ -3,7 +3,7 @@
3
3
  * SPDX-License-Identifier: Apache-2.0
4
4
  */
5
5
  import { z } from 'zod';
6
- import _findJobdeg from '../toolHelpers/_findJobdef.js';
6
+ import _findJobdef from '../toolHelpers/_findJobdef.js';
7
7
  function findJobdef(_appContext) {
8
8
  let llmDescription= {
9
9
  "purpose": "Map natural language requests to find a jobdef (job definition) in SAS Viya and return structured results.",
@@ -0,0 +1,59 @@
1
+ /*
2
+ * Copyright © 2025, SAS Institute Inc., Cary, NC, USA. All Rights Reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+ import { z } from 'zod';
7
+ import _findmas from '../toolHelpers/_findmas.js';
8
+
9
+
10
+ function findMas(_appContext) {
11
+ let description = `
12
+ find-mas — locate a specific MAS mas deployed to MAS server
13
+
14
+ USE when: find mas, does mas exist, is mas deployed, lookup mas, verify mas exists
15
+ DO NOT USE for: list mass (use list-mass), mas info/variables (use mas-info), score mas (use mas-score), find table/job/lib (use respective tools), scr mass (use scr-info/scr-score)
16
+
17
+ PARAMETERS
18
+ - name: string (required) — mas name to locate; if multiple supplied, use first
19
+
20
+ ROUTING RULES
21
+ - "find mas <name>" → { name: "<name>" }
22
+ - "does mas <name> exist" → { name: "<name>" }
23
+ - "is mas <name> deployed" → { name: "<name>" }
24
+ - "lookup/verify mas <name>" → { name: "<name>" }
25
+ - "find mas" with no name → ask "Which mas name would you like to find?"
26
+ - "find all mass / list mass" → use list-mass instead
27
+ - "describe mas / mas info" → use mas-info instead
28
+
29
+ EXAMPLES
30
+ - "find mas mymas" → { name: "mymas" }
31
+ - "does mas churn_score exist" → { name: "churn_score" }
32
+ - "is mas riskmas deployed" → { name: "riskmas" }
33
+ - "lookup mas claims_fraud_v1" → { name: "claims_fraud_v1" }
34
+
35
+ NEGATIVE EXAMPLES (do not route here)
36
+ - "list mass" (use list-mass)
37
+ - "score mas mymas" (use mas-score)
38
+ - "mas info for churnRisk" (use mas-info)
39
+
40
+ ERRORS
41
+ Returns { mass: [] } if not found; { mass: [name, ...] } if found. Never hallucinate mas names.
42
+ `;
43
+
44
+ let spec = {
45
+ name: 'find-mas',
46
+ description: description,
47
+ inputSchema: z.object({
48
+ name: z.string()
49
+ }),
50
+ handler: async (params) => {
51
+ let r = await _findmas(params);
52
+ return r;
53
+ }
54
+ }
55
+ return spec;
56
+ }
57
+
58
+ export default findMas;
59
+
@@ -4,14 +4,14 @@
4
4
  */
5
5
 
6
6
  import { z } from 'zod';
7
- import _listModels from '../toolHelpers/_listModels.js';
7
+ import _listMas from '../toolHelpers/_listMas.js';
8
8
 
9
- function listModels(_appContext) {
9
+ function listMas(_appContext) {
10
10
  let description = `
11
- list-models — enumerate models published to MAS.
11
+ list-mas — enumerate models published to MAS.
12
12
 
13
- USE when: list models, show models, browse models, next page
14
- DO NOT USE for: find model, model metadata, score model, list jobs/tables/libraries
13
+ USE when: list models, show models, list mas, show mas next page
14
+ DO NOT USE for: find model, find mas, model metadata, score model, list jobs/tables/libraries
15
15
 
16
16
  PARAMETERS
17
17
  - limit: number (default: 10) — page size
@@ -21,10 +21,15 @@ ROUTING RULES
21
21
  - "list models" → { start:1, limit:10 }
22
22
  - "list 25 models" → { start:1, limit:25 }
23
23
  - "next models" → { start: start+limit, limit:10 }
24
+ - "list mas" → { start:1, limit:10 }
25
+ - "list 25 mas" → { start:1, limit:25 }
26
+ - "next mas" → { start: start+limit, limit:10 }
24
27
 
25
28
  EXAMPLES
26
29
  - "list models" → { start:1, limit:10 }
27
30
  - "list 25 models" → { start:1, limit:25 }
31
+ - "list mas" → { start:1, limit:10 }
32
+ - "list 25 mas" → { start:1, limit:25 }
28
33
 
29
34
  NEGATIVE EXAMPLES (do not route here)
30
35
  - "find model X" (use find-model)
@@ -37,14 +42,14 @@ Returns empty array if no models found.
37
42
  `;
38
43
 
39
44
  let spec = {
40
- name: 'list-models',
45
+ name: 'list-mas',
41
46
  description: description,
42
47
  inputSchema: z.object({
43
48
  limit: z.number().optional(),
44
49
  start: z.number().optional()
45
50
  }),
46
51
  handler: async (params) => {
47
- let r = await _listModels(params);
52
+ let r = await _listMas(params);
48
53
  return r;
49
54
  }
50
55
  }
@@ -52,5 +57,5 @@ Returns empty array if no models found.
52
57
  return spec;
53
58
  }
54
59
 
55
- export default listModels;
60
+ export default listMas;
56
61
 
@@ -3,22 +3,28 @@
3
3
  * SPDX-License-Identifier: Apache-2.0
4
4
  */
5
5
 
6
- import listModels from './listModels.js';
7
- import listTables from './listTables.js';
8
- import modelScore from './modelScore.js';
9
- import modelInfo from './modelInfo.js';
6
+ import listMas from './listMas.js';
7
+
8
+
9
+ import masScore from './masScore.js';
10
+ import masInfo from './masInfo.js';
11
+ import findMas from './findMas.js';
12
+
10
13
  import findLibrary from './findLibrary.js';
11
- import readTable from './readTable.js';
12
- import tableInfo from './tableInfo.js';
13
14
  import listLibraries from './listLibraries.js';
14
15
 
16
+ import listTables from './listTables.js';
17
+ import findTable from './findTable.js';
18
+ import tableInfo from './tableInfo.js';
19
+ import readTable from './readTable.js';
20
+
15
21
  import scrInfo from './scrInfo.js';
16
22
  import scrScore from './scrScore.js';
17
23
 
18
24
  import devaScore from './devaScore.js';
19
25
 
20
- import findTable from './findTable.js';
21
- import findModel from './findModel.js';
26
+
27
+
22
28
  import runProgram from './runProgram.js';
23
29
  import runMacro from './runMacro.js';
24
30
  import runJob from './runJob.js';
@@ -40,11 +46,11 @@ function makeTools(_appContext) {
40
46
 
41
47
  // get the tool definitions and handler
42
48
  let list = [
43
- listModels(_appContext),
49
+ listMas(_appContext),
44
50
 
45
- findModel(_appContext),
46
- modelInfo(_appContext),
47
- modelScore(_appContext),
51
+ findMas(_appContext),
52
+ masInfo(_appContext),
53
+ masScore(_appContext),
48
54
 
49
55
  scrInfo(_appContext),
50
56
  scrScore(_appContext),
@@ -8,9 +8,9 @@ import debug from 'debug';
8
8
  import _masDescribe from '../toolHelpers/_masDescribe.js';
9
9
  const log = debug('tools');
10
10
 
11
- function modelInfo(_appContext) {
11
+ function masInfo(_appContext) {
12
12
  let description = `
13
- model-info — return detailed information about a specific MAS model, including its inputs, outputs, and metadata.
13
+ mas-info — return detailed information about a specific MAS model, including its inputs, outputs, and metadata.
14
14
 
15
15
  USE when: what inputs does model need, describe model, show variables for model, model inputs/outputs
16
16
  DO NOT USE for: find model, list models, score model, table/job operations
@@ -19,26 +19,26 @@ PARAMETERS
19
19
  - model: string — model name (required, exact match)
20
20
 
21
21
  ROUTING RULES
22
- - "what inputs does model X need?" → { model: "X" }
23
- - "describe model Y" → { model: "Y" }
24
- - "show variables for Z" → { model: "Z" }
22
+ - "what inputs does mas X need?" → { model: "X" }
23
+ - "describe mas Y" → { model: "Y" }
24
+ - "show variables for mas Z" → { model: "Z" }
25
25
 
26
26
  EXAMPLES
27
- - "What inputs does model churnRisk need?" → { model: "churnRisk" }
28
- - "Describe model creditScore" → { model: "creditScore" }
27
+ - "What inputs does mas churnRisk need?" → { model: "churnRisk" }
28
+ - "Describe mas creditScore" → { model: "creditScore" }
29
29
  - "Show variables for myModel" → { model: "myModel" }
30
30
 
31
31
  NEGATIVE EXAMPLES (do not route here)
32
- - "list models" (use list-models)
33
- - "find model X" (use find-model)
34
- - "score with model X" (use model-score)
32
+ - "list mas" (use list-models)
33
+ - "find mas X" (use find-model)
34
+ - "score with mas X" (use model-score)
35
35
 
36
36
  ERRORS
37
37
  Returns model metadata: inputs (name, type, role), outputs (name, type, possible_values), model_type, description.
38
38
  `;
39
39
 
40
40
  let spec = {
41
- name: 'model-info',
41
+ name: 'mas-info',
42
42
  description: description,
43
43
  inputSchema: z.object({
44
44
  model: z.string()
@@ -51,5 +51,5 @@ Returns model metadata: inputs (name, type, role), outputs (name, type, possible
51
51
  return spec;
52
52
  }
53
53
 
54
- export default modelInfo;
54
+ export default masInfo;
55
55
 
@@ -8,7 +8,7 @@ import debug from 'debug';
8
8
  import _masScoring from '../toolHelpers/_masScoring.js';
9
9
  const log = debug('tools');
10
10
 
11
- function modelScore(_appContext) {
11
+ function masScore(_appContext) {
12
12
  let description = `
13
13
  mas-score — score data using a deployed model on MAS.
14
14
 
@@ -74,7 +74,7 @@ Returns predictions, probabilities, scores merged with input data. Returns error
74
74
  params.model = params.model.substring(0, params.model.lastIndexOf('.'));
75
75
  }
76
76
 
77
- log('modelScore params', params);
77
+ log('masScore params', params);
78
78
  // Check if the params.scenario is a string and parse it
79
79
  let r = await _masScoring(params)
80
80
  return r;
@@ -83,5 +83,5 @@ Returns predictions, probabilities, scores merged with input data. Returns error
83
83
  return spec;
84
84
  }
85
85
 
86
- export default modelScore;
86
+ export default masScore;
87
87
 
@@ -1,12 +0,0 @@
1
- /*
2
- * Copyright © 2025, SAS Institute Inc., Cary, NC, USA. All Rights Reserved.
3
- * SPDX-License-Identifier: Apache-2.0
4
- */
5
-
6
- import _listModels from './_listModels.js';
7
- async function _findModel(params) {
8
- let r = await _listModels(params);
9
- console.log ("findModel result:" , r);
10
- return r;
11
- }
12
- export default _findModel;
@@ -1,60 +0,0 @@
1
- /*
2
- * Copyright © 2025, SAS Institute Inc., Cary, NC, USA. All Rights Reserved.
3
- * SPDX-License-Identifier: Apache-2.0
4
- */
5
-
6
- import { z } from 'zod';
7
- import _findModel from '../toolHelpers/_findModel.js';
8
-
9
-
10
- function findModel(_appContext) {
11
- let description = `
12
- find-model — locate a specific MAS model deployed to MAS server
13
-
14
- USE when: find model, does model exist, is model deployed, lookup model, verify model exists
15
- DO NOT USE for: list models (use list-models), model info/variables (use model-info), score model (use model-score), find table/job/lib (use respective tools), scr models (use scr-info/scr-score)
16
-
17
- PARAMETERS
18
- - name: string (required) — model name to locate; if multiple supplied, use first
19
-
20
- ROUTING RULES
21
- - "find model <name>" → { name: "<name>" }
22
- - "does model <name> exist" → { name: "<name>" }
23
- - "is model <name> deployed" → { name: "<name>" }
24
- - "lookup/verify model <name>" → { name: "<name>" }
25
- - "find model" with no name → ask "Which model name would you like to find?"
26
- - "find all models / list models" → use list-models instead
27
- - "score model <name>" → use model-score instead
28
- - "describe model / model info" → use model-info instead
29
-
30
- EXAMPLES
31
- - "find model myModel" → { name: "myModel" }
32
- - "does model churn_score exist" → { name: "churn_score" }
33
- - "is model riskModel deployed" → { name: "riskModel" }
34
- - "lookup model claims_fraud_v1" → { name: "claims_fraud_v1" }
35
-
36
- NEGATIVE EXAMPLES (do not route here)
37
- - "list models" (use list-models)
38
- - "score model myModel" (use model-score)
39
- - "model info for churnRisk" (use model-info)
40
-
41
- ERRORS
42
- Returns { models: [] } if not found; { models: [name, ...] } if found. Never hallucinate model names.
43
- `;
44
-
45
- let spec = {
46
- name: 'find-model',
47
- description: description,
48
- inputSchema: z.object({
49
- name: z.string()
50
- }),
51
- handler: async (params) => {
52
- let r = await _findModel(params);
53
- return r;
54
- }
55
- }
56
- return spec;
57
- }
58
-
59
- export default findModel;
60
-