@sassoftware/sas-score-mcp-serverjs 0.4.1-19 → 0.4.1-21
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/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-21",
|
|
4
4
|
"description": "A mcp server for SAS Viya",
|
|
5
5
|
"author": "Deva Kumar <deva.kumar@sas.com>",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -43,7 +43,8 @@
|
|
|
43
43
|
"openApi.json",
|
|
44
44
|
"openApi.yaml",
|
|
45
45
|
"skills",
|
|
46
|
-
"scripts"
|
|
46
|
+
"scripts",
|
|
47
|
+
".claude"
|
|
47
48
|
],
|
|
48
49
|
"dependencies": {
|
|
49
50
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
@@ -78,6 +78,23 @@ 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
|
+
|
|
81
98
|
## Common patterns
|
|
82
99
|
|
|
83
100
|
**Pattern 1 — Find library, server unspecified**
|
|
@@ -36,6 +36,21 @@ Use `sas-score-find-table` with intelligent server detection:
|
|
|
36
36
|
|
|
37
37
|
---
|
|
38
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"`
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
39
54
|
## Determine the read strategy
|
|
40
55
|
|
|
41
56
|
Ask yourself: does the user already have the data in hand?
|
|
@@ -69,15 +84,18 @@ sas-score-find-table({
|
|
|
69
84
|
sas-score-read-table({
|
|
70
85
|
table: "tablename",
|
|
71
86
|
lib: "libraryname",
|
|
72
|
-
server: "cas" or "sas", // determined from sas-score-find-table check
|
|
73
|
-
|
|
87
|
+
server: "cas" or "sas", // REQUIRED: determined from sas-score-find-table check
|
|
88
|
+
start: 1, // REQUIRED: 1-based row offset (default: 1)
|
|
89
|
+
limit: N, // REQUIRED: max rows to retrieve (default: 10, max: 1000)
|
|
74
90
|
where: "..." // optional SQL WHERE clause
|
|
75
91
|
})
|
|
76
92
|
```
|
|
77
93
|
|
|
78
94
|
**Rules:**
|
|
79
95
|
- Always determine the server first using `sas-score-find-table` with smart detection (CAS → SAS)
|
|
80
|
-
-
|
|
96
|
+
- **ALWAYS set `server` parameter** — never omit it; use the result from `sas-score-find-table` to determine "cas" or "sas"
|
|
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
|
|
81
99
|
- If table name is missing, ask: *"Which table should I read from? (format: lib.tablename)"*
|
|
82
100
|
- If library is missing, ask: *"Which library contains the table?"*
|
|
83
101
|
- If table exists in both servers, prefer CAS (already determined by smart detection)
|
|
@@ -124,12 +142,12 @@ sas-query({
|
|
|
124
142
|
**Pattern A — Raw row retrieval**
|
|
125
143
|
> "Show me the first 5 rows from Public.customers"
|
|
126
144
|
|
|
127
|
-
→ `sas-score-read-table({ table: "customers", lib: "Public", limit: 5 })`
|
|
145
|
+
→ `sas-score-read-table({ table: "customers", lib: "Public", server: "cas", start: 1, limit: 5 })`
|
|
128
146
|
|
|
129
147
|
**Pattern B — Filtered retrieval**
|
|
130
148
|
> "Get all high-value orders (amount > 5000) from mylib.orders"
|
|
131
149
|
|
|
132
|
-
→ `sas-score-read-table({ table: "orders", lib: "mylib", where: "amount > 5000" })`
|
|
150
|
+
→ `sas-score-read-table({ table: "orders", lib: "mylib", server: "sas", start: 1, limit: 50, where: "amount > 5000" })`
|
|
133
151
|
|
|
134
152
|
**Pattern C — Aggregation**
|
|
135
153
|
> "What is the average price by make in Public.cars?"
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
|
|
1
|
+
---
|
|
2
2
|
name: sas-score-workflow
|
|
3
3
|
description: >
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
MANDATORY routing logic for all scoring requests. Extract model.type suffix, route to correct tool
|
|
5
|
+
(run-job|run-jobdef|model-score|scr-score|run-program). Complete routing decision BEFORE invoking
|
|
6
|
+
any tool. Handles both MAS models and alternative scoring engines (jobs, jobdefs, SCR, SAS programs).
|
|
7
|
+
Trigger phrases: "score with model X.job", "score X.jobdef scenario", "score with model X.mas",
|
|
8
|
+
"score with model X.scr", any request with "score" + model name containing a dot (.) + type suffix.
|
|
9
9
|
---
|
|
10
10
|
|
|
11
11
|
# SAS Score Workflow
|
|
@@ -35,6 +35,91 @@ 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
|
+
|
|
38
123
|
## Type-Based Routing
|
|
39
124
|
|
|
40
125
|
### Parse and Strip Model Type
|
|
@@ -296,6 +381,8 @@ Merge the scoring output back with the input records and present as a table wher
|
|
|
296
381
|
| Scoring error / invalid inputs | Return structured error, suggest `model-info` to check required inputs and data types |
|
|
297
382
|
| Empty read result | Tell user, ask if they want to adjust the query/filter before scoring |
|
|
298
383
|
| 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** |
|
|
299
386
|
|
|
300
387
|
---
|
|
301
388
|
|
package/src/toolSet/findTable.js
CHANGED