@sassoftware/sas-score-mcp-serverjs 0.4.1-18 → 0.4.1-20
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/.claude/mcp-tool-description-optimizer/SKILL.md +129 -0
- package/.claude/mcp-tool-description-optimizer/references/examples.md +123 -0
- package/.claude/sas-find-library-smart/SKILL.md +154 -0
- package/.claude/sas-list-tables-smart/SKILL.md +127 -0
- package/.claude/sas-read-and-score/SKILL.md +111 -0
- package/.claude/sas-read-strategy/SKILL.md +178 -0
- package/.claude/sas-score-workflow/SKILL.md +314 -0
- package/.claude/sas-spec-migration/SKILL.md +303 -0
- package/package.json +3 -2
- package/skills/sas-read-strategy/SKILL.md +49 -27
- package/src/toolSet/findTable.js +2 -2
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: sas-spec-migration
|
|
3
|
+
description: >
|
|
4
|
+
Migrate or clean up SAS MCP tool spec objects. Use this skill whenever the user asks
|
|
5
|
+
to migrate, convert, update, or clean up tool specs. Covers two patterns:
|
|
6
|
+
(1) Old Zod-based format (z.string(), z.number(), top-level schema/required) → new
|
|
7
|
+
JSON Schema inputSchema format.
|
|
8
|
+
(2) Existing JSON Schema specs that need cleanup: removing $schema, fixing required
|
|
9
|
+
arrays (optional fields like "where" should not be in required), typing untyped fields
|
|
10
|
+
like scenario. Also trigger on: "migrate my tools", "update my specs", "clean up my
|
|
11
|
+
specs", "remove $schema", "fix required", or any request to standardize tool specs.
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# SAS Tool Spec Migration
|
|
15
|
+
|
|
16
|
+
Covers two migration scenarios:
|
|
17
|
+
|
|
18
|
+
- **Zod → JSON Schema**: Old format using `z.string()`, `z.number()` etc. with top-level `schema` and `required`
|
|
19
|
+
- **JSON Schema cleanup**: Existing `inputSchema` specs that need `$schema` removed, `required` fixed, or untyped fields corrected
|
|
20
|
+
|
|
21
|
+
Identify which pattern applies before proceeding.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Pattern 1 — JSON Schema cleanup
|
|
26
|
+
|
|
27
|
+
Use when the tool already has `inputSchema` but needs tidying. Apply all of these fixes:
|
|
28
|
+
|
|
29
|
+
### Remove `$schema`
|
|
30
|
+
|
|
31
|
+
Drop the `$schema` declaration entirely — the MCP SDK and LLMs ignore it at runtime and
|
|
32
|
+
it wastes tokens.
|
|
33
|
+
|
|
34
|
+
```js
|
|
35
|
+
// Before
|
|
36
|
+
inputSchema: {
|
|
37
|
+
$schema: "http://json-schema.org/draft-07/schema#",
|
|
38
|
+
type: "object",
|
|
39
|
+
...
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// After
|
|
43
|
+
inputSchema: {
|
|
44
|
+
type: "object",
|
|
45
|
+
...
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Fix `required` arrays
|
|
50
|
+
|
|
51
|
+
Only include a field in `required` if it is truly mandatory. Common mistakes:
|
|
52
|
+
|
|
53
|
+
| Field | Rule |
|
|
54
|
+
|---|---|
|
|
55
|
+
| `where` (filter expression) | Optional — remove from `required`, default to `""` in handler |
|
|
56
|
+
| `scenario` (job params) | Optional — not all jobs need parameters; remove from `required` |
|
|
57
|
+
| `name` | Required — always include |
|
|
58
|
+
| `limit`, `start` | Required for list tools — include |
|
|
59
|
+
|
|
60
|
+
### Type untyped fields
|
|
61
|
+
|
|
62
|
+
If a field has `{}` or no type, infer the correct type:
|
|
63
|
+
|
|
64
|
+
| Field | Type |
|
|
65
|
+
|---|---|
|
|
66
|
+
| `scenario` | `{ type: "string" }` — handler already parses it as JSON |
|
|
67
|
+
| `where` | `{ type: "string" }` |
|
|
68
|
+
| Any flexible input | `{ type: "string" }` with note to parse in handler |
|
|
69
|
+
|
|
70
|
+
### Full cleanup example
|
|
71
|
+
|
|
72
|
+
**Before:**
|
|
73
|
+
```js
|
|
74
|
+
inputSchema: {
|
|
75
|
+
$schema: "http://json-schema.org/draft-07/schema#",
|
|
76
|
+
type: "object",
|
|
77
|
+
properties: {
|
|
78
|
+
name: { type: "string" },
|
|
79
|
+
scenario: {}
|
|
80
|
+
},
|
|
81
|
+
required: ["name", "scenario"]
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
**After:**
|
|
86
|
+
```js
|
|
87
|
+
inputSchema: {
|
|
88
|
+
type: "object",
|
|
89
|
+
properties: {
|
|
90
|
+
name: { type: "string" },
|
|
91
|
+
scenario: { type: "string" }
|
|
92
|
+
},
|
|
93
|
+
required: ["name"]
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## Pattern 2 — Zod → JSON Schema
|
|
100
|
+
|
|
101
|
+
## What changes
|
|
102
|
+
|
|
103
|
+
**Old format:**
|
|
104
|
+
```js
|
|
105
|
+
let spec = {
|
|
106
|
+
name: 'find-job',
|
|
107
|
+
aliases: [...],
|
|
108
|
+
description: description,
|
|
109
|
+
schema: {
|
|
110
|
+
name: z.string(),
|
|
111
|
+
limit: z.number().optional(),
|
|
112
|
+
},
|
|
113
|
+
required: ['name'],
|
|
114
|
+
handler: async (params) => { ... }
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
**New format:**
|
|
119
|
+
```js
|
|
120
|
+
let spec = {
|
|
121
|
+
name: 'find-job',
|
|
122
|
+
aliases: [...],
|
|
123
|
+
description: description,
|
|
124
|
+
inputSchema: {
|
|
125
|
+
type: "object",
|
|
126
|
+
properties: {
|
|
127
|
+
name: { type: "string", description: "Job name to locate" },
|
|
128
|
+
limit: { type: "number", description: "Max results to return" }
|
|
129
|
+
},
|
|
130
|
+
required: ['name']
|
|
131
|
+
},
|
|
132
|
+
handler: async (params) => { ... }
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
**Summary of changes:**
|
|
137
|
+
- `schema` → `inputSchema`
|
|
138
|
+
- `inputSchema` gains `type: "object"` and `properties: {}`
|
|
139
|
+
- Each Zod field moves inside `properties` as a JSON Schema object
|
|
140
|
+
- Top-level `required` array moves inside `inputSchema`
|
|
141
|
+
- Fields with `.optional()` are NOT included in `required`
|
|
142
|
+
- Fields without `.optional()` ARE included in `required` (unless already excluded)
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## Zod → JSON Schema type mapping
|
|
147
|
+
|
|
148
|
+
| Zod | JSON Schema |
|
|
149
|
+
|---|---|
|
|
150
|
+
| `z.string()` | `{ type: "string" }` |
|
|
151
|
+
| `z.number()` | `{ type: "number" }` |
|
|
152
|
+
| `z.boolean()` | `{ type: "boolean" }` |
|
|
153
|
+
| `z.array(z.string())` | `{ type: "array", items: { type: "string" } }` |
|
|
154
|
+
| `z.array(z.number())` | `{ type: "array", items: { type: "number" } }` |
|
|
155
|
+
| `z.object({...})` | `{ type: "object", properties: {...} }` |
|
|
156
|
+
| `z.enum(['a','b'])` | `{ type: "string", enum: ["a", "b"] }` |
|
|
157
|
+
| `.describe("text")` | Add `description: "text"` to the property |
|
|
158
|
+
| `.optional()` | Omit field from `required` array |
|
|
159
|
+
| `.optional().describe("text")` | Omit from `required`, add `description` |
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## Step-by-step migration
|
|
164
|
+
|
|
165
|
+
### Step 1 — Identify the fields
|
|
166
|
+
|
|
167
|
+
Read the existing `schema` object. For each key, note:
|
|
168
|
+
- Its Zod type (string, number, boolean, array, enum, object)
|
|
169
|
+
- Whether it has `.optional()`
|
|
170
|
+
- Whether it has `.describe("...")` — extract the description text
|
|
171
|
+
- Whether it appears in the top-level `required` array
|
|
172
|
+
|
|
173
|
+
### Step 2 — Build `properties`
|
|
174
|
+
|
|
175
|
+
For each field in `schema`, create a JSON Schema property object:
|
|
176
|
+
|
|
177
|
+
```js
|
|
178
|
+
// Old
|
|
179
|
+
fieldName: z.string().describe("The name of the thing")
|
|
180
|
+
|
|
181
|
+
// New
|
|
182
|
+
fieldName: { type: "string", description: "The name of the thing" }
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
If no `.describe()` is present, infer a short description from the field name and tool context.
|
|
186
|
+
Keep descriptions concise — one sentence, imperative style ("Job name to locate", not "This is the name of the job").
|
|
187
|
+
|
|
188
|
+
### Step 3 — Build `required`
|
|
189
|
+
|
|
190
|
+
Include a field in `required` if:
|
|
191
|
+
- It appeared in the old top-level `required` array, OR
|
|
192
|
+
- It has no `.optional()` in its Zod definition
|
|
193
|
+
|
|
194
|
+
Exclude a field from `required` if:
|
|
195
|
+
- It has `.optional()` in its Zod definition
|
|
196
|
+
|
|
197
|
+
### Step 4 — Assemble `inputSchema`
|
|
198
|
+
|
|
199
|
+
```js
|
|
200
|
+
inputSchema: {
|
|
201
|
+
type: "object",
|
|
202
|
+
properties: {
|
|
203
|
+
// one entry per field from Step 2
|
|
204
|
+
},
|
|
205
|
+
required: [/* field names from Step 3 */]
|
|
206
|
+
}
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
If `required` would be empty, omit it entirely rather than including `required: []`.
|
|
210
|
+
|
|
211
|
+
### Step 5 — Remove old fields
|
|
212
|
+
|
|
213
|
+
Remove `schema` and the top-level `required` from the spec object.
|
|
214
|
+
Leave everything else unchanged: `name`, `aliases`, `description`, `handler`.
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
## Edge cases
|
|
219
|
+
|
|
220
|
+
**Field in `required` but also `.optional()` in Zod:**
|
|
221
|
+
Trust `.optional()` — exclude from `required`. The old `required` array may be stale.
|
|
222
|
+
|
|
223
|
+
**Nested `z.object()`:**
|
|
224
|
+
```js
|
|
225
|
+
// Old
|
|
226
|
+
config: z.object({ host: z.string(), port: z.number() })
|
|
227
|
+
|
|
228
|
+
// New
|
|
229
|
+
config: {
|
|
230
|
+
type: "object",
|
|
231
|
+
properties: {
|
|
232
|
+
host: { type: "string", description: "Host address" },
|
|
233
|
+
port: { type: "number", description: "Port number" }
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
**`z.union()` / `z.any()` / `z.unknown()`:**
|
|
239
|
+
Use `{}` (empty schema, accepts anything) or `{ type: "string" }` with a note that the
|
|
240
|
+
field accepts flexible input. Flag this to the user for review.
|
|
241
|
+
|
|
242
|
+
**No `schema` field at all:**
|
|
243
|
+
The tool takes no inputs. Set `inputSchema: { type: "object", properties: {} }` or omit
|
|
244
|
+
`inputSchema` entirely — both are valid. Omitting is cleaner for zero-input tools.
|
|
245
|
+
|
|
246
|
+
**`schema` is already a plain JSON object (not Zod):**
|
|
247
|
+
Check if values use `z.` prefix. If not, the schema may already be partially migrated —
|
|
248
|
+
wrap it in `{ type: "object", properties: { ... } }` and move `required` inside.
|
|
249
|
+
|
|
250
|
+
---
|
|
251
|
+
|
|
252
|
+
## Output format
|
|
253
|
+
|
|
254
|
+
- Preserve the existing code style (quote style, indentation, trailing commas)
|
|
255
|
+
- Output the full updated spec object, not just the diff
|
|
256
|
+
- If migrating multiple specs at once, process them all and output each in full
|
|
257
|
+
- After outputting, note any fields that used `z.union()`, `z.any()`, or other ambiguous
|
|
258
|
+
types that the user should review manually
|
|
259
|
+
|
|
260
|
+
---
|
|
261
|
+
|
|
262
|
+
## Example — full migration
|
|
263
|
+
|
|
264
|
+
**Input:**
|
|
265
|
+
```js
|
|
266
|
+
let spec = {
|
|
267
|
+
name: 'find-job',
|
|
268
|
+
aliases: ['findJob', 'find job'],
|
|
269
|
+
description: description,
|
|
270
|
+
schema: {
|
|
271
|
+
name: z.string(),
|
|
272
|
+
caslib: z.string().optional().describe("CAS library name"),
|
|
273
|
+
limit: z.number().optional(),
|
|
274
|
+
},
|
|
275
|
+
required: ['name'],
|
|
276
|
+
handler: async (params) => {
|
|
277
|
+
let r = await _listJobs(params);
|
|
278
|
+
return r;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
**Output:**
|
|
284
|
+
```js
|
|
285
|
+
let spec = {
|
|
286
|
+
name: 'find-job',
|
|
287
|
+
aliases: ['findJob', 'find job'],
|
|
288
|
+
description: description,
|
|
289
|
+
inputSchema: {
|
|
290
|
+
type: "object",
|
|
291
|
+
properties: {
|
|
292
|
+
name: { type: "string", description: "Job name to locate" },
|
|
293
|
+
caslib: { type: "string", description: "CAS library name" },
|
|
294
|
+
limit: { type: "number", description: "Max results to return" }
|
|
295
|
+
},
|
|
296
|
+
required: ['name']
|
|
297
|
+
},
|
|
298
|
+
handler: async (params) => {
|
|
299
|
+
let r = await _listJobs(params);
|
|
300
|
+
return r;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
```
|
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-20",
|
|
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",
|
|
@@ -15,20 +15,24 @@ 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, locate the table and determine which server contains it:
|
|
19
19
|
|
|
20
|
-
**
|
|
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
|
|
20
|
+
**Smart table lookup with server detection**
|
|
24
21
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
22
|
+
Use `sas-score-find-table` with intelligent server detection:
|
|
23
|
+
|
|
24
|
+
1. **First attempt**: Check CAS server (`server: "cas"`)
|
|
25
|
+
- If table exists → return table and server to caller
|
|
26
|
+
- If table not found → proceed to step 2
|
|
27
|
+
|
|
28
|
+
2. **Second attempt**: Check SAS server (`server: "sas"`)
|
|
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."*
|
|
32
36
|
|
|
33
37
|
---
|
|
34
38
|
|
|
@@ -55,21 +59,31 @@ Ask yourself: does the user already have the data in hand?
|
|
|
55
59
|
|
|
56
60
|
**How:**
|
|
57
61
|
```
|
|
62
|
+
sas-score-find-table({
|
|
63
|
+
lib: "libraryname",
|
|
64
|
+
table: "tablename",
|
|
65
|
+
server: "cas" // start with CAS
|
|
66
|
+
})
|
|
67
|
+
// if not found, repeat with server: "sas"
|
|
68
|
+
|
|
58
69
|
sas-score-read-table({
|
|
59
70
|
table: "tablename",
|
|
60
71
|
lib: "libraryname",
|
|
61
|
-
server: "cas" or "sas", // determined from sas-score-find-table check
|
|
62
|
-
|
|
72
|
+
server: "cas" or "sas", // REQUIRED: determined from sas-score-find-table check
|
|
73
|
+
start: 1, // REQUIRED: 1-based row offset (default: 1)
|
|
74
|
+
limit: N, // REQUIRED: max rows to retrieve (default: 10, max: 1000)
|
|
63
75
|
where: "..." // optional SQL WHERE clause
|
|
64
76
|
})
|
|
65
77
|
```
|
|
66
78
|
|
|
67
79
|
**Rules:**
|
|
68
|
-
- Always determine the server first using `sas-score-find-table`
|
|
69
|
-
-
|
|
80
|
+
- Always determine the server first using `sas-score-find-table` with smart detection (CAS → SAS)
|
|
81
|
+
- **ALWAYS set `server` parameter** — never omit it; use the result from `sas-score-find-table` to determine "cas" or "sas"
|
|
82
|
+
- **ALWAYS set `start` parameter** — use 1 for the first call, or the offset for pagination
|
|
83
|
+
- **ALWAYS set `limit` parameter** — keep batch size ≤ 50 rows unless the user explicitly requests more; cap at 1000
|
|
70
84
|
- If table name is missing, ask: *"Which table should I read from? (format: lib.tablename)"*
|
|
71
85
|
- If library is missing, ask: *"Which library contains the table?"*
|
|
72
|
-
- If table exists in both servers,
|
|
86
|
+
- If table exists in both servers, prefer CAS (already determined by smart detection)
|
|
73
87
|
- Return raw column values; do not transform or aggregate
|
|
74
88
|
|
|
75
89
|
---
|
|
@@ -83,6 +97,13 @@ sas-score-read-table({
|
|
|
83
97
|
|
|
84
98
|
**How:**
|
|
85
99
|
```
|
|
100
|
+
sas-score-find-table({
|
|
101
|
+
lib: "libraryname",
|
|
102
|
+
table: "tablename",
|
|
103
|
+
server: "cas" // start with CAS
|
|
104
|
+
})
|
|
105
|
+
// if not found, repeat with server: "sas"
|
|
106
|
+
|
|
86
107
|
sas-query({
|
|
87
108
|
table: "lib.tablename",
|
|
88
109
|
query: "user's natural language question",
|
|
@@ -91,8 +112,8 @@ sas-query({
|
|
|
91
112
|
```
|
|
92
113
|
|
|
93
114
|
**Rules:**
|
|
94
|
-
- Check which server
|
|
95
|
-
- If table exists in
|
|
115
|
+
- Check which server contains the table using `sas-score-find-table` with smart detection (CAS → SAS) first
|
|
116
|
+
- If table exists in CAS, query from CAS; if only in SAS, query from SAS
|
|
96
117
|
- Parse the user's natural language question into a PROC SQL SELECT statement
|
|
97
118
|
- Ensure SELECT statement is valid SQL syntax
|
|
98
119
|
- Do not add trailing semicolons to the SQL string
|
|
@@ -106,12 +127,12 @@ sas-query({
|
|
|
106
127
|
**Pattern A — Raw row retrieval**
|
|
107
128
|
> "Show me the first 5 rows from Public.customers"
|
|
108
129
|
|
|
109
|
-
→ `sas-score-read-table({ table: "customers", lib: "Public", limit: 5 })`
|
|
130
|
+
→ `sas-score-read-table({ table: "customers", lib: "Public", server: "cas", start: 1, limit: 5 })`
|
|
110
131
|
|
|
111
132
|
**Pattern B — Filtered retrieval**
|
|
112
133
|
> "Get all high-value orders (amount > 5000) from mylib.orders"
|
|
113
134
|
|
|
114
|
-
→ `sas-score-read-table({ table: "orders", lib: "mylib", where: "amount > 5000" })`
|
|
135
|
+
→ `sas-score-read-table({ table: "orders", lib: "mylib", server: "sas", start: 1, limit: 50, where: "amount > 5000" })`
|
|
115
136
|
|
|
116
137
|
**Pattern C — Aggregation**
|
|
117
138
|
> "What is the average price by make in Public.cars?"
|
|
@@ -129,11 +150,12 @@ sas-query({
|
|
|
129
150
|
|
|
130
151
|
| Problem | Action |
|
|
131
152
|
|---|---|
|
|
132
|
-
|
|
|
133
|
-
| Table not found in either server | Inform user
|
|
134
|
-
| Table exists in
|
|
135
|
-
| Table exists only in
|
|
136
|
-
| Table name missing entirely | Ask: *"Which table should I read from?"* |
|
|
153
|
+
| Table not found in CAS | Try SAS server using `sas-score-find-table` with `server: "sas"` |
|
|
154
|
+
| 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."* |
|
|
155
|
+
| Table exists only in CAS | Use `server: "cas"` automatically for read operations |
|
|
156
|
+
| Table exists only in SAS | Use `server: "sas"` automatically for read operations |
|
|
157
|
+
| Table name missing entirely | Ask: *"Which table should I read from? (format: lib.tablename)"* |
|
|
158
|
+
| Library name missing | Ask: *"Which library contains the table?"* |
|
|
137
159
|
| Ambiguous intent (raw vs aggregate) | Ask: *"Do you want individual rows or a summary by some field?"* |
|
|
138
160
|
| Empty result | Inform user, ask to adjust filter or query |
|
|
139
161
|
|
|
@@ -141,7 +163,7 @@ sas-query({
|
|
|
141
163
|
|
|
142
164
|
## Integration with other skills
|
|
143
165
|
|
|
144
|
-
- **Before this skill**: Use `sas-find-
|
|
166
|
+
- **Before this skill**: Use `sas-score-find-table` to verify the table exists and determine the server location
|
|
145
167
|
- **After this skill**: Use `sas-read-and-score` to score the retrieved data
|
|
146
168
|
|
|
147
169
|
---
|
package/src/toolSet/findTable.js
CHANGED
|
@@ -17,7 +17,7 @@ DO NOT USE for: list tables (use list-tables), table schema/columns (use table-i
|
|
|
17
17
|
PARAMETERS
|
|
18
18
|
- lib: string (required) — library name (e.g., 'Public', 'sashelp')
|
|
19
19
|
- name: string (required) — table name to locate
|
|
20
|
-
- server: 'cas' | 'sas'
|
|
20
|
+
- server: 'cas' | 'sas' . If not specified set it to 'cas' — target environment
|
|
21
21
|
|
|
22
22
|
ROUTING RULES
|
|
23
23
|
- "find table <name> in <lib>" → { lib: "<lib>", name: "<name>", server: "cas" }
|
|
@@ -49,7 +49,7 @@ Returns { tables: [] } if not found; { tables: [name, ...] } if found. Never hal
|
|
|
49
49
|
inputSchema: z.object({
|
|
50
50
|
name: z.string(),
|
|
51
51
|
lib: z.string(),
|
|
52
|
-
server: z.string()
|
|
52
|
+
server: z.string()
|
|
53
53
|
}),
|
|
54
54
|
|
|
55
55
|
handler: async (params) => {
|