@sassoftware/sas-score-mcp-serverjs 0.4.1-1 → 0.4.1-15
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/cli.js +111 -31
- package/package.json +4 -2
- package/skills/sas-list-tables-smart/SKILL.md +123 -0
- package/skills/sas-read-and-score/SKILL.md +54 -53
- package/skills/sas-read-strategy/SKILL.md +10 -10
- package/skills/sas-score-workflow/SKILL.md +19 -2
- package/skills/sas-spec-migration/SKILL.md +303 -0
- package/src/authpkce.js +219 -0
- package/src/createMcpServer.js +11 -8
- package/src/expressMcpServer.js +354 -338
- package/src/oauthHandlers/authorize.js +46 -0
- package/src/oauthHandlers/baseUrl.js +8 -0
- package/src/oauthHandlers/callback.js +93 -0
- package/src/oauthHandlers/getMetadata.js +27 -0
- package/src/oauthHandlers/index.js +7 -0
- package/src/oauthHandlers/token.js +37 -0
- package/src/processHeaders.js +88 -0
- package/src/toolHelpers/_listLibrary.js +0 -1
- package/src/toolHelpers/getLogonPayload.js +5 -1
- package/src/toolHelpers/refreshTokenOauth.js +3 -3
- package/src/toolSet/.claude/settings.local.json +13 -0
- package/src/toolSet/devaScore.js +61 -61
- package/src/toolSet/findJob.js +1 -1
- package/src/toolSet/findJobdef.js +2 -2
- package/src/toolSet/findLibrary.js +68 -67
- package/src/toolSet/findModel.js +2 -2
- package/src/toolSet/findTable.js +3 -2
- package/src/toolSet/getEnv.js +8 -4
- package/src/toolSet/listJobdefs.js +61 -61
- package/src/toolSet/listJobs.js +61 -61
- package/src/toolSet/listLibraries.js +78 -78
- package/src/toolSet/listModels.js +56 -56
- package/src/toolSet/listTables.js +66 -65
- package/src/toolSet/modelInfo.js +2 -2
- package/src/toolSet/modelScore.js +6 -5
- package/src/toolSet/readTable.js +63 -65
- package/src/toolSet/runCasProgram.js +7 -6
- package/src/toolSet/runJob.js +81 -81
- package/src/toolSet/runJobdef.js +82 -82
- package/src/toolSet/runMacro.js +81 -80
- package/src/toolSet/runProgram.js +4 -8
- package/src/toolSet/sasQuery.js +77 -78
- package/src/toolSet/scrInfo.js +1 -1
- package/src/toolSet/scrScore.js +69 -68
- package/src/toolSet/setContext.js +65 -65
- package/src/toolSet/superstat.js +61 -59
- package/src/toolSet/tableInfo.js +58 -57
package/src/toolSet/runMacro.js
CHANGED
|
@@ -1,81 +1,82 @@
|
|
|
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 _submitCode from '../toolHelpers/_submitCode.js';
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
function runMacro(_appContext) {
|
|
11
|
-
let description = `
|
|
12
|
-
run-macro — submit and execute a SAS macro on SAS Viya server.
|
|
13
|
-
|
|
14
|
-
USE when: run macro, execute macro with parameters
|
|
15
|
-
DO NOT USE for: arbitrary SAS code (use run-sas-program), jobs, jobdefs
|
|
16
|
-
|
|
17
|
-
PARAMETERS
|
|
18
|
-
- macro: string — macro name without "%" (required)
|
|
19
|
-
- scenario: string — parameters or setup code (optional). Accepts: "x=1, y=abc" or "%let x=1; %let y=abc;"
|
|
20
|
-
|
|
21
|
-
ROUTING RULES
|
|
22
|
-
- "run macro abc" → { macro: "abc", scenario: "" }
|
|
23
|
-
- "run macro abc with x=1, y=2" → { macro: "abc", scenario: "x=1, y=2" }
|
|
24
|
-
- "run macro xyz with %let a=1; %let b=2;" → { macro: "xyz", scenario: "%let a=1; %let b=2;" }
|
|
25
|
-
|
|
26
|
-
EXAMPLES
|
|
27
|
-
- "run macro abc" → { macro: "abc", scenario: "" }
|
|
28
|
-
- "run macro summarize with x=1, y=2" → { macro: "summarize", scenario: "x=1, y=2" }
|
|
29
|
-
|
|
30
|
-
NEGATIVE EXAMPLES (do not route here)
|
|
31
|
-
- "run SAS code" (use run-sas-program)
|
|
32
|
-
- "run job X" (use run-job)
|
|
33
|
-
- "run jobdef X" (use run-jobdef)
|
|
34
|
-
|
|
35
|
-
ERRORS
|
|
36
|
-
Returns log, ods, tables created by macro. Auto-converts "x=1, y=2" to "%let x=1; %let y=2;" format.
|
|
37
|
-
`;
|
|
38
|
-
|
|
39
|
-
let spec = {
|
|
40
|
-
name: 'run-macro',
|
|
41
|
-
description: description,
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
macro: z.string(),
|
|
45
|
-
scenario: z.string()
|
|
46
|
-
}),
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
.
|
|
60
|
-
.
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
.
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
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 _submitCode from '../toolHelpers/_submitCode.js';
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
function runMacro(_appContext) {
|
|
11
|
+
let description = `
|
|
12
|
+
run-macro — submit and execute a SAS macro on SAS Viya server.
|
|
13
|
+
|
|
14
|
+
USE when: run macro, execute macro with parameters
|
|
15
|
+
DO NOT USE for: arbitrary SAS code (use run-sas-program), jobs, jobdefs
|
|
16
|
+
|
|
17
|
+
PARAMETERS
|
|
18
|
+
- macro: string — macro name without "%" (required)
|
|
19
|
+
- scenario: string — parameters or setup code (optional). Accepts: "x=1, y=abc" or "%let x=1; %let y=abc;"
|
|
20
|
+
|
|
21
|
+
ROUTING RULES
|
|
22
|
+
- "run macro abc" → { macro: "abc", scenario: "" }
|
|
23
|
+
- "run macro abc with x=1, y=2" → { macro: "abc", scenario: "x=1, y=2" }
|
|
24
|
+
- "run macro xyz with %let a=1; %let b=2;" → { macro: "xyz", scenario: "%let a=1; %let b=2;" }
|
|
25
|
+
|
|
26
|
+
EXAMPLES
|
|
27
|
+
- "run macro abc" → { macro: "abc", scenario: "" }
|
|
28
|
+
- "run macro summarize with x=1, y=2" → { macro: "summarize", scenario: "x=1, y=2" }
|
|
29
|
+
|
|
30
|
+
NEGATIVE EXAMPLES (do not route here)
|
|
31
|
+
- "run SAS code" (use run-sas-program)
|
|
32
|
+
- "run job X" (use run-job)
|
|
33
|
+
- "run jobdef X" (use run-jobdef)
|
|
34
|
+
|
|
35
|
+
ERRORS
|
|
36
|
+
Returns log, ods, tables created by macro. Auto-converts "x=1, y=2" to "%let x=1; %let y=2;" format.
|
|
37
|
+
`;
|
|
38
|
+
|
|
39
|
+
let spec = {
|
|
40
|
+
name: 'run-macro',
|
|
41
|
+
description: description,
|
|
42
|
+
|
|
43
|
+
inputSchema: z.object({
|
|
44
|
+
macro: z.string(),
|
|
45
|
+
scenario: z.string().optional()
|
|
46
|
+
}),
|
|
47
|
+
|
|
48
|
+
handler: async (params) => {
|
|
49
|
+
const scenarioRaw = (params.scenario || '').trim();
|
|
50
|
+
let setup = '';
|
|
51
|
+
if (scenarioRaw) {
|
|
52
|
+
// If the scenario already contains macro syntax, send it through unchanged
|
|
53
|
+
const hasMacroSyntax = /%let\b|%[a-zA-Z_]\w*\s*\(|%[a-zA-Z_]\w*\s*;/.test(scenarioRaw) || scenarioRaw.includes('%');
|
|
54
|
+
if (hasMacroSyntax) {
|
|
55
|
+
setup = scenarioRaw;
|
|
56
|
+
} else {
|
|
57
|
+
// Convert "x=1,y=abc" -> "%let x=1; %let y=abc;"
|
|
58
|
+
setup = scenarioRaw.split(',')
|
|
59
|
+
.map(p => p.trim())
|
|
60
|
+
.filter(Boolean)
|
|
61
|
+
.map(p => {
|
|
62
|
+
const [k, ...rest] = p.split('=');
|
|
63
|
+
if (!k) return '';
|
|
64
|
+
const key = k.trim();
|
|
65
|
+
const val = rest.join('=').trim();
|
|
66
|
+
return `%let ${key}=${val};`;
|
|
67
|
+
})
|
|
68
|
+
.filter(Boolean)
|
|
69
|
+
.join(' ');
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
const src = `${setup} %${params.macro};`;
|
|
73
|
+
params.src = src;
|
|
74
|
+
let r = await _submitCode(params);
|
|
75
|
+
return r;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return spec;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export default runMacro;
|
|
81
82
|
|
|
@@ -45,15 +45,11 @@ Returns log, ods, tables array, data (if output specified). Error if execution f
|
|
|
45
45
|
description: description,
|
|
46
46
|
inputSchema: z.object({
|
|
47
47
|
src: z.string(),
|
|
48
|
-
scenario: z.
|
|
49
|
-
output: z.string(),
|
|
50
|
-
folder: z.string(),
|
|
51
|
-
limit: z.number()
|
|
48
|
+
scenario: z.string().optional(),
|
|
49
|
+
output: z.string().optional(),
|
|
50
|
+
folder: z.string().optional(),
|
|
51
|
+
limit: z.number().optional()
|
|
52
52
|
}),
|
|
53
|
-
// NOTE: Previously 'required' incorrectly listed 'program' which does not
|
|
54
|
-
// exist in the schema. This prevented execution in some orchestrators that
|
|
55
|
-
// enforce required parameter presence, causing only descriptions to appear.
|
|
56
|
-
// Corrected to 'src'.
|
|
57
53
|
handler: async (params) => {
|
|
58
54
|
let {src, folder, scenario, _appContext} = params;
|
|
59
55
|
// figure out src
|
package/src/toolSet/sasQuery.js
CHANGED
|
@@ -1,78 +1,77 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright © 2025, SAS Institute Inc., Cary, NC, USA. All Rights Reserved.
|
|
3
|
-
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
-
*/
|
|
5
|
-
import {z} from 'zod';
|
|
6
|
-
import _jobSubmit from '../toolHelpers/_jobSubmit.js';
|
|
7
|
-
|
|
8
|
-
function sasQuery() {
|
|
9
|
-
|
|
10
|
-
let description = `
|
|
11
|
-
sas-query — convert natural language questions into SQL queries and execute them.
|
|
12
|
-
|
|
13
|
-
USE when: how many/count/total/average by, aggregated analytics, complex filtering, statistical summaries
|
|
14
|
-
DO NOT USE for: raw reads without filtering (use read-table), table structure (use table-info), SAS programs (use run-sas-program), jobs/jobdefs
|
|
15
|
-
|
|
16
|
-
PARAMETERS
|
|
17
|
-
- table: string — table in lib.table format (required), e.g. "Public.cars" or "sashelp.class"
|
|
18
|
-
- query: string — natural language question (required)
|
|
19
|
-
- sql: string — pre-generated SQL SELECT (optional, LLM generates)
|
|
20
|
-
- job: string (default: 'program') — job name to execute
|
|
21
|
-
|
|
22
|
-
ROUTING RULES
|
|
23
|
-
- "how many cars by make in sashelp.cars" → { table: "sashelp.cars", query: "how many cars by make", sql: "SELECT make, COUNT(*) FROM sashelp.cars GROUP BY make" }
|
|
24
|
-
- "average salary by department in Public.employees" → { table: "Public.employees", query: "average salary by department", sql: "SELECT department, AVG(salary) FROM Public.employees GROUP BY department" }
|
|
25
|
-
|
|
26
|
-
EXAMPLES
|
|
27
|
-
- "how many cars by make in sashelp.cars" → { table: "sashelp.cars", query: "how many cars by make", sql: "SELECT make, COUNT(*) FROM sashelp.cars GROUP BY make" }
|
|
28
|
-
- "total sales by region from mylib.sales" → { table: "mylib.sales", query: "total sales by region", sql: "SELECT region, SUM(amount) FROM mylib.sales GROUP BY region" }
|
|
29
|
-
|
|
30
|
-
NEGATIVE EXAMPLES (do not route here)
|
|
31
|
-
- "read table cars" (use read-table)
|
|
32
|
-
- "show 10 rows" (use read-table)
|
|
33
|
-
- "table structure" (use table-info)
|
|
34
|
-
- "run SAS code" (use run-sas-program)
|
|
35
|
-
- "run job/macro" (use run-job/run-macro)
|
|
36
|
-
|
|
37
|
-
ERRORS
|
|
38
|
-
Returns rows array, columns metadata, log. Returns error if SQL invalid or table not found.
|
|
39
|
-
`;
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
let spec = {
|
|
43
|
-
name: 'sas-query',
|
|
44
|
-
description: description,
|
|
45
|
-
inputSchema: z.object({
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
let
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
1
|
+
/*
|
|
2
|
+
* Copyright © 2025, SAS Institute Inc., Cary, NC, USA. All Rights Reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
import {z} from 'zod';
|
|
6
|
+
import _jobSubmit from '../toolHelpers/_jobSubmit.js';
|
|
7
|
+
|
|
8
|
+
function sasQuery() {
|
|
9
|
+
|
|
10
|
+
let description = `
|
|
11
|
+
sas-query — convert natural language questions into SQL queries and execute them.
|
|
12
|
+
|
|
13
|
+
USE when: how many/count/total/average by, aggregated analytics, complex filtering, statistical summaries
|
|
14
|
+
DO NOT USE for: raw reads without filtering (use read-table), table structure (use table-info), SAS programs (use run-sas-program), jobs/jobdefs
|
|
15
|
+
|
|
16
|
+
PARAMETERS
|
|
17
|
+
- table: string — table in lib.table format (required), e.g. "Public.cars" or "sashelp.class"
|
|
18
|
+
- query: string — natural language question (required)
|
|
19
|
+
- sql: string — pre-generated SQL SELECT (optional, LLM generates)
|
|
20
|
+
- job: string (default: 'program') — job name to execute
|
|
21
|
+
|
|
22
|
+
ROUTING RULES
|
|
23
|
+
- "how many cars by make in sashelp.cars" → { table: "sashelp.cars", query: "how many cars by make", sql: "SELECT make, COUNT(*) FROM sashelp.cars GROUP BY make" }
|
|
24
|
+
- "average salary by department in Public.employees" → { table: "Public.employees", query: "average salary by department", sql: "SELECT department, AVG(salary) FROM Public.employees GROUP BY department" }
|
|
25
|
+
|
|
26
|
+
EXAMPLES
|
|
27
|
+
- "how many cars by make in sashelp.cars" → { table: "sashelp.cars", query: "how many cars by make", sql: "SELECT make, COUNT(*) FROM sashelp.cars GROUP BY make" }
|
|
28
|
+
- "total sales by region from mylib.sales" → { table: "mylib.sales", query: "total sales by region", sql: "SELECT region, SUM(amount) FROM mylib.sales GROUP BY region" }
|
|
29
|
+
|
|
30
|
+
NEGATIVE EXAMPLES (do not route here)
|
|
31
|
+
- "read table cars" (use read-table)
|
|
32
|
+
- "show 10 rows" (use read-table)
|
|
33
|
+
- "table structure" (use table-info)
|
|
34
|
+
- "run SAS code" (use run-sas-program)
|
|
35
|
+
- "run job/macro" (use run-job/run-macro)
|
|
36
|
+
|
|
37
|
+
ERRORS
|
|
38
|
+
Returns rows array, columns metadata, log. Returns error if SQL invalid or table not found.
|
|
39
|
+
`;
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
let spec = {
|
|
43
|
+
name: 'sas-query',
|
|
44
|
+
description: description,
|
|
45
|
+
inputSchema: z.object({
|
|
46
|
+
query: z.string(),
|
|
47
|
+
table: z.string(),
|
|
48
|
+
sql: z.string().optional()
|
|
49
|
+
}),
|
|
50
|
+
handler: async (params) => {
|
|
51
|
+
let {table,query, sql, job, _appContext} = params;
|
|
52
|
+
let sqlinput = (sql == null) ? ' ' : sql.replaceAll(';', ' ').replaceAll('\n', ' ').replaceAll('\r', ' ');
|
|
53
|
+
|
|
54
|
+
let iparams = {
|
|
55
|
+
scenario: {
|
|
56
|
+
table: table,
|
|
57
|
+
prompt: query,
|
|
58
|
+
sql: sqlinput
|
|
59
|
+
},
|
|
60
|
+
name: (job == null) ? 'program' : job,
|
|
61
|
+
type: 'job',
|
|
62
|
+
query: true,
|
|
63
|
+
_appContext: _appContext
|
|
64
|
+
};
|
|
65
|
+
if (sql == null || sql.trim().length === 0) {
|
|
66
|
+
return { content: [{ type: 'text', text: 'Error: The SQL statement generated is blank. Please provide a valid natural language query that can be converted to SQL.' }] };
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
let r = await _jobSubmit(iparams);
|
|
70
|
+
return r;
|
|
71
|
+
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return spec;
|
|
75
|
+
}
|
|
76
|
+
export default sasQuery;
|
|
77
|
+
|
package/src/toolSet/scrInfo.js
CHANGED
package/src/toolSet/scrScore.js
CHANGED
|
@@ -1,69 +1,70 @@
|
|
|
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 _scrScore from '../toolHelpers/_scrScore.js';
|
|
8
|
-
|
|
9
|
-
function scrScore(_appContext) {
|
|
10
|
-
let description = `
|
|
11
|
-
## scr-score
|
|
12
|
-
|
|
13
|
-
Purpose
|
|
14
|
-
Score a scenario using a model deployed as a SCR container in Azure or another host).
|
|
15
|
-
|
|
16
|
-
Inputs
|
|
17
|
-
- url (string, required): SCR model identifier (URL)
|
|
18
|
-
- scenario (string | object | array, optional): Input values to score. Accepts:
|
|
19
|
-
- a comma-separated key=value string (e.g. "x=1, y=2"),
|
|
20
|
-
- a JSON object with field names and values (recommended for typed inputs),
|
|
21
|
-
- an array of objects for batch scoring. If omitted, the tool will return the model's input variable definitions.
|
|
22
|
-
|
|
23
|
-
What it returns
|
|
24
|
-
- When scoring: the SCR endpoint response (predictions, probabilities, scores) merged with or alongside the supplied inputs.
|
|
25
|
-
- When \`scenario\` is omitted: metadata describing the model's input variables (names, types, required/optional).
|
|
26
|
-
|
|
27
|
-
Usage notes
|
|
28
|
-
- Run \`scr-info\` first to inspect the expected input variables and types.
|
|
29
|
-
- Prefer structured objects for numeric/date values to avoid type ambiguity; the simple string parser keeps values as strings.
|
|
30
|
-
- Ensure network connectivity and any required credentials for the target SCR service.
|
|
31
|
-
|
|
32
|
-
Examples
|
|
33
|
-
- scrScore with url="loan" and scenario="age=45, income=60000"
|
|
34
|
-
- scrScore with url="https://scr-host/models/loan" and scenario={age:45, income:60000}
|
|
35
|
-
`;
|
|
36
|
-
|
|
37
|
-
let spec = {
|
|
38
|
-
name: 'scr-score',
|
|
39
|
-
description: description,
|
|
40
|
-
inputSchema: z.object({
|
|
41
|
-
url: z.string(),
|
|
42
|
-
scenario: z.
|
|
43
|
-
}),
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
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 _scrScore from '../toolHelpers/_scrScore.js';
|
|
8
|
+
|
|
9
|
+
function scrScore(_appContext) {
|
|
10
|
+
let description = `
|
|
11
|
+
## scr-score
|
|
12
|
+
|
|
13
|
+
Purpose
|
|
14
|
+
Score a scenario using a model deployed as a SCR container in Azure or another host).
|
|
15
|
+
|
|
16
|
+
Inputs
|
|
17
|
+
- url (string, required): SCR model identifier (URL)
|
|
18
|
+
- scenario (string | object | array, optional): Input values to score. Accepts:
|
|
19
|
+
- a comma-separated key=value string (e.g. "x=1, y=2"),
|
|
20
|
+
- a JSON object with field names and values (recommended for typed inputs),
|
|
21
|
+
- an array of objects for batch scoring. If omitted, the tool will return the model's input variable definitions.
|
|
22
|
+
|
|
23
|
+
What it returns
|
|
24
|
+
- When scoring: the SCR endpoint response (predictions, probabilities, scores) merged with or alongside the supplied inputs.
|
|
25
|
+
- When \`scenario\` is omitted: metadata describing the model's input variables (names, types, required/optional).
|
|
26
|
+
|
|
27
|
+
Usage notes
|
|
28
|
+
- Run \`scr-info\` first to inspect the expected input variables and types.
|
|
29
|
+
- Prefer structured objects for numeric/date values to avoid type ambiguity; the simple string parser keeps values as strings.
|
|
30
|
+
- Ensure network connectivity and any required credentials for the target SCR service.
|
|
31
|
+
|
|
32
|
+
Examples
|
|
33
|
+
- scrScore with url="loan" and scenario="age=45, income=60000"
|
|
34
|
+
- scrScore with url="https://scr-host/models/loan" and scenario={age:45, income:60000}
|
|
35
|
+
`;
|
|
36
|
+
|
|
37
|
+
let spec = {
|
|
38
|
+
name: 'scr-score',
|
|
39
|
+
description: description,
|
|
40
|
+
inputSchema: z.object({
|
|
41
|
+
url: z.string(),
|
|
42
|
+
scenario: z.string().optional()
|
|
43
|
+
}),
|
|
44
|
+
|
|
45
|
+
handler: async (params) => {
|
|
46
|
+
let {url, scenario,_appContext} = params;
|
|
47
|
+
|
|
48
|
+
if (url === null) {
|
|
49
|
+
return { status: { statusCode: 2, msg: `SCR model ${url} was not specified` }, results: {} };
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Normalize simple string scenarios like "x=1, y=2" into an object
|
|
53
|
+
if (typeof scenario === 'string' && scenario.includes('=')) {
|
|
54
|
+
scenario = scenario.split(',').reduce((acc, pair) => {
|
|
55
|
+
const [k, ...rest] = pair.split('=');
|
|
56
|
+
if (!k) return acc;
|
|
57
|
+
acc[k.trim()] = rest.join('=').trim();
|
|
58
|
+
return acc;
|
|
59
|
+
}, {});
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
let r = await _scrScore({ url: url, scenario: scenario , _appContext: _appContext});
|
|
63
|
+
return r;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return spec;
|
|
68
|
+
}
|
|
69
|
+
|
|
69
70
|
export default scrScore;
|
|
@@ -1,65 +1,65 @@
|
|
|
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
|
-
|
|
8
|
-
function setContext(_appContext) {
|
|
9
|
-
let description = `
|
|
10
|
-
set-context — set the CAS and SAS server contexts for subsequent tool calls.
|
|
11
|
-
|
|
12
|
-
USE when: switch to CAS server, change compute context, check current context, set both
|
|
13
|
-
DO NOT USE for: get variables (use get-env), read data (use read-table), run programs (use run-sas-program)
|
|
14
|
-
|
|
15
|
-
PARAMETERS
|
|
16
|
-
- cas: string — CAS server name (optional), e.g. 'cas-shared-default', 'finance-cas-server'
|
|
17
|
-
- sas: string — SAS compute context (optional), e.g. 'SAS Studio Compute Context', 'batch-compute'
|
|
18
|
-
|
|
19
|
-
ROUTING RULES
|
|
20
|
-
- "use finance-cas-server" → { cas: "finance-cas-server" }
|
|
21
|
-
- "switch to SAS Studio Compute Context" → { sas: "SAS Studio Compute Context" }
|
|
22
|
-
- "use finance-cas for CAS and batch-compute for SAS" → { cas: "finance-cas", sas: "batch-compute" }
|
|
23
|
-
- "what context am I using" → { } (no params, returns current)
|
|
24
|
-
|
|
25
|
-
EXAMPLES
|
|
26
|
-
- "use finance-cas-server" → { cas: "finance-cas-server" }
|
|
27
|
-
- "switch to batch-compute" → { sas: "batch-compute" }
|
|
28
|
-
- "what's my current context" → { }
|
|
29
|
-
|
|
30
|
-
NEGATIVE EXAMPLES (do not route here)
|
|
31
|
-
- "read table cars" (use read-table)
|
|
32
|
-
- "what's the value of X" (use get-env)
|
|
33
|
-
- "run program" (use run-sas-program)
|
|
34
|
-
|
|
35
|
-
ERRORS
|
|
36
|
-
Returns current or updated context values {cas, sas}. Error if server not found or invalid name.
|
|
37
|
-
`;
|
|
38
|
-
|
|
39
|
-
let spec = {
|
|
40
|
-
name: 'set-context',
|
|
41
|
-
description: description,
|
|
42
|
-
inputSchema: z.object({
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
handler: async (params) => {
|
|
47
|
-
|
|
48
|
-
let {cas, sas} = params;
|
|
49
|
-
if (typeof cas === 'string' && cas.trim().length > 0) {
|
|
50
|
-
_appContext.contexts.cas = cas.trim();
|
|
51
|
-
}
|
|
52
|
-
if (typeof sas === 'string' && sas.trim().length > 0) {
|
|
53
|
-
_appContext.contexts.sas = sas.trim();
|
|
54
|
-
}
|
|
55
|
-
// Return a structured response without extraneous keys
|
|
56
|
-
return {
|
|
57
|
-
content: [{ type: 'text', text: JSON.stringify(_appContext.contexts) }],
|
|
58
|
-
structuredContent: _appContext.contexts
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
return spec;
|
|
63
|
-
}
|
|
64
|
-
export default setContext;
|
|
65
|
-
|
|
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
|
+
|
|
8
|
+
function setContext(_appContext) {
|
|
9
|
+
let description = `
|
|
10
|
+
set-context — set the CAS and SAS server contexts for subsequent tool calls.
|
|
11
|
+
|
|
12
|
+
USE when: switch to CAS server, change compute context, check current context, set both
|
|
13
|
+
DO NOT USE for: get variables (use get-env), read data (use read-table), run programs (use run-sas-program)
|
|
14
|
+
|
|
15
|
+
PARAMETERS
|
|
16
|
+
- cas: string — CAS server name (optional), e.g. 'cas-shared-default', 'finance-cas-server'
|
|
17
|
+
- sas: string — SAS compute context (optional), e.g. 'SAS Studio Compute Context', 'batch-compute'
|
|
18
|
+
|
|
19
|
+
ROUTING RULES
|
|
20
|
+
- "use finance-cas-server" → { cas: "finance-cas-server" }
|
|
21
|
+
- "switch to SAS Studio Compute Context" → { sas: "SAS Studio Compute Context" }
|
|
22
|
+
- "use finance-cas for CAS and batch-compute for SAS" → { cas: "finance-cas", sas: "batch-compute" }
|
|
23
|
+
- "what context am I using" → { } (no params, returns current)
|
|
24
|
+
|
|
25
|
+
EXAMPLES
|
|
26
|
+
- "use finance-cas-server" → { cas: "finance-cas-server" }
|
|
27
|
+
- "switch to batch-compute" → { sas: "batch-compute" }
|
|
28
|
+
- "what's my current context" → { }
|
|
29
|
+
|
|
30
|
+
NEGATIVE EXAMPLES (do not route here)
|
|
31
|
+
- "read table cars" (use read-table)
|
|
32
|
+
- "what's the value of X" (use get-env)
|
|
33
|
+
- "run program" (use run-sas-program)
|
|
34
|
+
|
|
35
|
+
ERRORS
|
|
36
|
+
Returns current or updated context values {cas, sas}. Error if server not found or invalid name.
|
|
37
|
+
`;
|
|
38
|
+
|
|
39
|
+
let spec = {
|
|
40
|
+
name: 'set-context',
|
|
41
|
+
description: description,
|
|
42
|
+
inputSchema: z.object({
|
|
43
|
+
cas: z.string().optional(),
|
|
44
|
+
sas: z.string().optional()
|
|
45
|
+
}),
|
|
46
|
+
handler: async (params) => {
|
|
47
|
+
|
|
48
|
+
let {cas, sas} = params;
|
|
49
|
+
if (typeof cas === 'string' && cas.trim().length > 0) {
|
|
50
|
+
_appContext.contexts.cas = cas.trim();
|
|
51
|
+
}
|
|
52
|
+
if (typeof sas === 'string' && sas.trim().length > 0) {
|
|
53
|
+
_appContext.contexts.sas = sas.trim();
|
|
54
|
+
}
|
|
55
|
+
// Return a structured response without extraneous keys
|
|
56
|
+
return {
|
|
57
|
+
content: [{ type: 'text', text: JSON.stringify(_appContext.contexts) }],
|
|
58
|
+
structuredContent: _appContext.contexts
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return spec;
|
|
63
|
+
}
|
|
64
|
+
export default setContext;
|
|
65
|
+
|