@sassoftware/sas-score-mcp-serverjs 0.4.1 → 1.0.1-0

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.
Files changed (72) hide show
  1. package/.skills/agents/sas-viya-scoring-expert.md +58 -0
  2. package/.skills/copilot-instructions.md +155 -0
  3. package/.skills/skills/sas-find-library-smart/SKILL.md +154 -0
  4. package/.skills/skills/sas-list-tables-smart/SKILL.md +127 -0
  5. package/.skills/skills/sas-read-and-score/SKILL.md +111 -0
  6. package/.skills/skills/sas-read-strategy/SKILL.md +156 -0
  7. package/.skills/skills/sas-request-classifier/SKILL.md +69 -0
  8. package/.skills/skills/sas-score-workflow/SKILL.md +314 -0
  9. package/cli.js +311 -70
  10. package/package.json +7 -7
  11. package/scripts/docs/SCORE_SKILL_REFERENCE.md +142 -0
  12. package/scripts/docs/TOOL_DESCRIPTION_TEMPLATE.md +157 -0
  13. package/scripts/docs/TOOL_UPDATES_SUMMARY.md +208 -0
  14. package/scripts/docs/mcp-localhost-config-guide.md +184 -0
  15. package/scripts/docs/oauth-http-transport.md +96 -0
  16. package/scripts/docs/sas-mcp-tools-reference.md +600 -0
  17. package/scripts/getViyaca.sh +1 -0
  18. package/scripts/optimize_final.py +140 -0
  19. package/scripts/optimize_tools.py +99 -0
  20. package/scripts/setup-skills.js +34 -0
  21. package/scripts/update_descriptions.py +46 -0
  22. package/scripts/viyatls.sh +3 -0
  23. package/src/authpkce.js +219 -0
  24. package/src/createMcpServer.js +16 -5
  25. package/src/expressMcpServer.js +350 -308
  26. package/src/handleGetDelete.js +6 -3
  27. package/src/hapiMcpServer.js +10 -18
  28. package/src/oauthHandlers/authorize.js +46 -0
  29. package/src/oauthHandlers/baseUrl.js +8 -0
  30. package/src/oauthHandlers/callback.js +96 -0
  31. package/src/oauthHandlers/getMetadata.js +27 -0
  32. package/src/oauthHandlers/index.js +7 -0
  33. package/src/oauthHandlers/token.js +37 -0
  34. package/src/processHeaders.js +88 -0
  35. package/src/setupSkills.js +46 -0
  36. package/src/toolHelpers/_jobSubmit.js +2 -0
  37. package/src/toolHelpers/_listLibrary.js +55 -39
  38. package/src/toolHelpers/getLogonPayload.js +7 -1
  39. package/src/toolHelpers/readCerts.js +4 -4
  40. package/src/toolHelpers/refreshToken.js +3 -2
  41. package/src/toolHelpers/refreshTokenOauth.js +3 -3
  42. package/src/toolSet/.claude/settings.local.json +13 -0
  43. package/src/toolSet/devaScore.js +61 -69
  44. package/src/toolSet/findJob.js +38 -71
  45. package/src/toolSet/findJobdef.js +28 -59
  46. package/src/toolSet/findLibrary.js +68 -100
  47. package/src/toolSet/findModel.js +35 -58
  48. package/src/toolSet/findTable.js +31 -60
  49. package/src/toolSet/getEnv.js +30 -45
  50. package/src/toolSet/listJobdefs.js +61 -96
  51. package/src/toolSet/listJobs.js +61 -110
  52. package/src/toolSet/listLibraries.js +78 -90
  53. package/src/toolSet/listModels.js +56 -83
  54. package/src/toolSet/listTables.js +66 -95
  55. package/src/toolSet/makeTools.js +1 -0
  56. package/src/toolSet/modelInfo.js +22 -54
  57. package/src/toolSet/modelScore.js +35 -77
  58. package/src/toolSet/readTable.js +63 -104
  59. package/src/toolSet/runCasProgram.js +32 -52
  60. package/src/toolSet/runJob.js +24 -24
  61. package/src/toolSet/runJobdef.js +26 -29
  62. package/src/toolSet/runMacro.js +82 -82
  63. package/src/toolSet/runProgram.js +32 -84
  64. package/src/toolSet/sasQuery.js +77 -126
  65. package/src/toolSet/sasQueryTemplate.js +4 -5
  66. package/src/toolSet/sasQueryTemplate2.js +4 -5
  67. package/src/toolSet/scrInfo.js +4 -7
  68. package/src/toolSet/scrScore.js +69 -70
  69. package/src/toolSet/searchAssets.js +5 -6
  70. package/src/toolSet/setContext.js +65 -92
  71. package/src/toolSet/superstat.js +61 -60
  72. package/src/toolSet/tableInfo.js +58 -102
@@ -8,74 +8,53 @@ import _submitCode from '../toolHelpers/_submitCode.js';
8
8
 
9
9
  function runCasProgram(_appContext) {
10
10
  let description = `
11
- ## run-cas-program
11
+ run-cas-program — execute a CAS program on SAS Viya server.
12
12
 
13
- Execute a cas program on a SAS Viya server
13
+ USE when: run cas program, execute cas, submit cas, cas action
14
+ DO NOT USE for: macros (use run-macro), sas code (use run-sas-program), jobs (use run-job), jobdefs (use run-jobdef)
14
15
 
15
- Required Parameters
16
- - src(string, required): The cas program to execute.
16
+ PARAMETERS
17
+ - src: string (required) CAS program to execute verbatim
18
+ - scenario: string or object (optional) — input parameters
19
+ - folder: string — server folder path for .sas files
20
+ - output: string — table name to return in response
21
+ - limit: number (default: 100) — max rows to return
17
22
 
18
- Optional Parameters:
23
+ ROUTING RULES
24
+ - run cas program action echo → { src: action echo }
25
+ - execute cas action simple.summary → { src: action simple.summary }
19
26
 
20
- - scenario (string | object ,optional): Input values to program/ Accepts:
21
- - a comma-separated key=value string (e.g. "x=1, y=2"),
22
- - a JSON object with field names and values (recommended for typed inputs),
27
+ EXAMPLES
28
+ - run cas program action echo { src: action echo }
29
+ - cas program sample folder=/Public/models { src: sample, folder: /Public/models }
23
30
 
24
- LLM Invocation Guidance
25
- Use THIS tool when the user wants to run a Cas program on the server:
26
- - "run cas program 'action echo / code='aaaa'"
27
- - "cas program 'action echo / code='aaaa'"
28
- - 'submit cas "action echo / code='aaaa'"'
31
+ NEGATIVE EXAMPLES (do not route here)
32
+ - run sas macro (use run-macro)
33
+ - submit sas code (use run-sas-program)
34
+ - run job X (use run-job)
29
35
 
36
+ NOTES
37
+ Sends src verbatim without validation. For SAS macros use run-macro. For arbitrary SAS code use run-sas-program.
30
38
 
31
- Do NOT use this tool when the user wants:
32
- - run macro -> use run-macro
33
- - submit sas -> use run-sas-program
34
- - run job -> use run-job
35
- - run sas -> use run-sas-program
36
- - run jobdef -> use run-jobdef
37
- - run job -> use run-job
38
- - list jobs -> use list-jobs
39
- - list jobdefs -> use list-jobdefs
40
- - find job -> use find-job
41
- - find jobdef -> use find-jobdef
42
- - find model -> use find-model
43
-
44
-
45
- Behavior & usage notes
46
- - This tool sends the supplied \`src\` verbatim to the SAS execution helper. It does not modify or validate the SAS code.
47
- - For invoking pre-defined SAS macros, prefer the \`runMacro\` helper which converts simple parameter formats into \`%let\` statements and invokes the macro cleanly.
48
- - Be cautious when executing arbitrary code — validate or sanitize inputs in untrusted environments.
49
-
50
- Response
51
- - If output is specified and the specified table exists in the response, display the data as a markdown table.
52
- Examples
53
- - run program "data a; x=1; run;" - this is the simplest usage -- {src= "data a; x=1; run;", folder=" ", output=" ", limit=100}
54
- - program "data work.a; x=1; run;" output=a limit=50 -- {src= "data work.a; x=1; run;", folder=" ", output="a", limit=50}
55
-
56
- - run program sample folder=/Public/models output=A limit=50 -- {src= "sample", folder="/Public/models", output="A", limit=50}
57
- - run program sample folder=/Public/models scenario="name='John', age=45" output=a limit=50 -- {src= "sample", folder="/Public/models", scenario: {name: "John", age: 45}, output="a", limit=50}
58
- - run program sample folder=/Public/models with scenario name=John,age=45 output=a limit=50 -- {src= "sample.sas", folder="/Public/models", scenario: {name: "John", age: 45}, output="a", limit=50}
59
- - this should be the same as the previous example and is just a different syntax. The result should be
60
- {program: "sample", folder: "/Public/models", scenario: {name: "John", age: 45}, output: "a", limit: 50}
39
+ RESPONSE
40
+ Log output and CAS results. If output table specified, returned as markdown table.
61
41
  `;
62
42
 
63
43
  let spec = {
64
- name: 'run-sas-program',
65
- aliases: ['Program','run program'],
44
+ name: 'run-cas-program',
66
45
  description: description,
67
- schema: {
46
+ inputSchema:z.object({
68
47
  src: z.string(),
69
- scenario: z.any().default(''),
70
- output: z.string().default(''),
71
- folder: z.string().default(''),
72
- limit: z.number().default(100)
73
- },
48
+ scenario: z.string(),
49
+ output: z.string().optional,
50
+ folder: z.string().optional,
51
+ limit: z.number().optional
52
+ }),
53
+
74
54
  // NOTE: Previously 'required' incorrectly listed 'program' which does not
75
55
  // exist in the schema. This prevented execution in some orchestrators that
76
56
  // enforce required parameter presence, causing only descriptions to appear.
77
57
  // Corrected to 'src'.
78
- required: ['src'],
79
58
  handler: async (params) => {
80
59
  let {src, folder, scenario, _appContext} = params;
81
60
  // figure out src
@@ -116,3 +95,4 @@ Examples
116
95
  }
117
96
 
118
97
  export default runCasProgram;
98
+
@@ -9,41 +9,40 @@ import _jobSubmit from '../toolHelpers/_jobSubmit.js';
9
9
  function runJob(_appContext) {
10
10
 
11
11
  let description = `
12
- ## run-job — execute a deployed SAS Viya job
12
+ run-job — score with a deployed SAS Viya job.
13
13
 
14
- LLM Invocation Guidance (When to use)
15
- Use THIS tool when:
16
- - You want to run a registered Job Execution asset by name
17
- - You have simple parameter inputs to pass to the job
14
+ USE when: score with job, run job, execute job
15
+ DO NOT USE for: arbitrary SAS code (use run-sas-program), macros (use run-macro), list/find jobs
18
16
 
19
- Do NOT use this tool for:
20
- - Running arbitrary SAS code (use run-sas-program)
21
- - Invoking pre-defined SAS macros (use run-macro)
22
- - Listing or finding jobs (use list-jobs / find-job)
17
+ PARAMETERS
18
+ - name: string job name (required)
19
+ - scenario: string | object input parameters. Accepts: "x=1, y=2" or {x:1, y:2}
23
20
 
24
- Parameters
25
- - name (string, required): The job name to execute
26
- - scenario (string | object, optional): Input values to the job. Accepts:
27
- - a comma-separated key=value string (e.g. "x=1, y=2")
28
- - a JSON object with field names and values (recommended)
21
+ ROUTING RULES
22
+ - "run job xyz" { name: "xyz" }
23
+ - "run job xyz with param1=10, param2=val2" { name: "xyz", scenario: {param1:10, param2:"val2"} }
29
24
 
30
- Response
31
- - Log output, listings, and tables depending on the job’s design. Table outputs will be displayed when present.
25
+ EXAMPLES
26
+ - "run job xyz" { name: "xyz" }
27
+ - "run job monthly_etl with month=10, year=2025" → { name: "monthly_etl", scenario: {month:10, year:2025} }
32
28
 
33
- Examples ( mapped params)
34
- - "run job xyz param1=10,param2=val2" { name: "xyz", scenario: { param1: 10, param2: "val2" } }
35
- - "run-job name=monthly_etl, scenario=month=10,year=2025" { name: "monthly_etl", scenario: { month: 10, year: 2025 } }
29
+ NEGATIVE EXAMPLES (do not route here)
30
+ - "run SAS code" (use run-sas-program)
31
+ - "run macro X" (use run-macro)
32
+ - "list jobs" (use list-jobs)
33
+ - "find job X" (use find-job)
34
+
35
+ ERRORS
36
+ Returns log output, listings, tables from job. Error if job not found.
36
37
  `;
37
38
 
38
39
  let spec = {
39
- aliases: ['run job', 'run-job', 'runjob'],
40
40
  name: 'run-job',
41
41
  description: description,
42
- schema: {
42
+ inputSchema: z.object({
43
43
  name: z.string(),
44
- scenario: z.any().default(''),
45
- },
46
- required: ['name'],
44
+ scenario: z.string().optional()
45
+ }),
47
46
  handler: async (params) => {
48
47
  let scenario = params.scenario;
49
48
  let scenarioObj = {};
@@ -79,3 +78,4 @@ Examples (→ mapped params)
79
78
  }
80
79
 
81
80
  export default runJob;
81
+
@@ -6,48 +6,44 @@
6
6
  import { z } from 'zod';
7
7
  import _jobSubmit from '../toolHelpers/_jobSubmit.js';
8
8
 
9
-
10
9
  function runJobdef(_appContext) {
11
10
  // JSON object for LLM/tooling
12
11
 
13
12
  let description = `
14
- ## run-jobdef — execute a SAS Viya job definition
13
+ run-jobdef — score with a deployed SAS Viya job definition.
14
+
15
+ USE when: score with jobdef, run jobdef, execute jobdef
16
+ DO NOT USE for: arbitrary SAS code (use run-sas-program), macros (use run-macro), list/find jobdefs
15
17
 
16
- LLM Invocation Guidance (When to use)
17
- Use THIS tool when:
18
- - You want to run a registered Job Definition by name
19
- - You can pass parameters to the job definition
18
+ PARAMETERS
19
+ - name: string — jobdef name (required)
20
+ - scenario: string | object input parameters. Accepts: "x=1, y=2" or {x:1, y:2}
20
21
 
21
- Do NOT use this tool for:
22
- - Running arbitrary SAS code (use run-program tool)
23
- - Invoking SAS macros (use run-macro tool)
24
- - Listing or finding jobdefs (use list-jobdefs tool / find-jobdef tool)
22
+ ROUTING RULES
23
+ - "run jobdef xyz" { name: "xyz" }
24
+ - "run jobdef xyz with param1=10, param2=val2" → { name: "xyz", scenario: {param1:10, param2:"val2"} }
25
25
 
26
- Parameters
27
- - name (string, required): The job definition name to execute
28
- - scenario (string | object, optional): Input values. Accepts:
29
- - a comma-separated key=value string (e.g. "x=1, y=2")
30
- - a JSON object with field names and values (recommended)
26
+ EXAMPLES
27
+ - "run jobdef xyz" { name: "xyz" }
28
+ - "run jobdef monthly_report with month=10, year=2025" → { name: "monthly_report", scenario: {month:10, year:2025} }
31
29
 
32
- Response
33
- - Log output, listings, and tables depending on the job definition's design. Table outputs will be displayed when present.
30
+ NEGATIVE EXAMPLES (do not route here)
31
+ - "run SAS code" (use run-sas-program)
32
+ - "run macro X" (use run-macro)
33
+ - "list jobdefs" (use list-jobdefs)
34
+ - "find jobdef X" (use find-jobdef)
34
35
 
35
- Examples (→ mapped params)
36
- - "jobdef xyz param1=10,param2=val2" → { name: "xyz", scenario: { param1: 10, param2: "val2" } }
37
- - "run jobdef name=monthly_report, scenario=month=10,year=2025" → { name: "monthly_report", scenario: { month: 10, year: 2025 } }
38
- - "run-jobdef xyz param1=10,param2=val2" → { name: "xyz", scenario: { param1: 10, param2: "val2" } }
39
- - "jobdef name=monthly_report, scenario=month=10,year=2025" → { name: "monthly_report", scenario: { month: 10, year: 2025 }
40
- `;
36
+ ERRORS
37
+ Returns log output, listings, tables from jobdef. Error if jobdef not found.
38
+ `;
41
39
 
42
40
  let spec = {
43
- name: 'run-jobdef',
44
- aliases: ['jobDef','jobdef','jobdef'],
41
+ name: 'run-jobdef',
45
42
  description: description,
46
- schema: {
43
+ inputSchema: z.object({
47
44
  name: z.string(),
48
- scenario: z.any().default(''),
49
- },
50
- required: ['name'],
45
+ scenario: z.string().optional()
46
+ }),
51
47
  handler: async (params) => {
52
48
  let scenario = params.scenario;
53
49
  let scenarioObj = {};
@@ -83,3 +79,4 @@ Examples (→ mapped params)
83
79
  }
84
80
 
85
81
  export default runJobdef;
82
+
@@ -1,82 +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
13
-
14
- Submit and execute a SAS macro on a SAS Viya server by generating and sending SAS code.
15
-
16
- Inputs
17
- - macro (string, required): The name of the macro to execute (provide the macro identifier without the leading "%").
18
- - scenario (string, optional): Parameters or SAS setup code to send before invoking the macro. Accepted formats:
19
- - Comma-separated key=value pairs (e.g. "x=1, y=abc") converted to SAS %let statements.
20
- - Raw SAS macro code (e.g. "%let x=1; %let y=abc;") — passed through unchanged when it already contains SAS macro syntax.
21
-
22
- Behavior
23
- - If \`scenario\` contains SAS macro syntax (contains \`%let\` or other macro markers), it is sent unchanged.
24
- - Otherwise the tool converts comma-separated parameters into \`%let\` statements (e.g. "x=1,y=abc" "%let x=1; %let y=abc;") and appends a macro invocation \`%<macro>;\`.
25
- - The resulting SAS code is submitted via the internal \`_submitCode\` helper and the submission result is returned.
26
-
27
- Output
28
- - Returns the response produced by \`_submitCode\`, typically including ods, log, list of tables created by the macro
29
-
30
- Usage notes
31
- - Ensure the target SAS environment has the macro defined
32
- - This helper does not perform advanced input validation or type coercion — validate parameters before calling when needed.
33
-
34
- Examples
35
- - run macro \`abc\` with scenario \`x=1, y=2\`
36
- - run macro \`summarize\` with raw SAS code \`%let x=1; %let y=2;\` (the helper will pass it through unchanged)
37
- `;
38
-
39
- let spec = {
40
- name: 'run-macro',
41
- aliases: ['runMacro','run macro','run_macro'],
42
- description: description,
43
-
44
- schema: {
45
- macro: z.string(),
46
- scenario: z.string()
47
- },
48
- required: ['macro'],
49
- handler: async (params) => {
50
- const scenarioRaw = (params.scenario || '').trim();
51
- let setup = '';
52
- if (scenarioRaw) {
53
- // If the scenario already contains macro syntax, send it through unchanged
54
- const hasMacroSyntax = /%let\b|%[a-zA-Z_]\w*\s*\(|%[a-zA-Z_]\w*\s*;/.test(scenarioRaw) || scenarioRaw.includes('%');
55
- if (hasMacroSyntax) {
56
- setup = scenarioRaw;
57
- } else {
58
- // Convert "x=1,y=abc" -> "%let x=1; %let y=abc;"
59
- setup = scenarioRaw.split(',')
60
- .map(p => p.trim())
61
- .filter(Boolean)
62
- .map(p => {
63
- const [k, ...rest] = p.split('=');
64
- if (!k) return '';
65
- const key = k.trim();
66
- const val = rest.join('=').trim();
67
- return `%let ${key}=${val};`;
68
- })
69
- .filter(Boolean)
70
- .join(' ');
71
- }
72
- }
73
- const src = `${setup} %${params.macro};`;
74
- params.src = src;
75
- let r = await _submitCode(params);
76
- return r;
77
- }
78
- }
79
- return spec;
80
- }
81
-
82
- export default runMacro;
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;
82
+
@@ -8,101 +8,48 @@ import _submitCode from '../toolHelpers/_submitCode.js';
8
8
 
9
9
  function runProgram(_appContext) {
10
10
  let description = `
11
- ## run-sas-program — execute SAS code or programs on SAS Viya server
11
+ run-sas-program — execute SAS code or programs on SAS Viya server.
12
12
 
13
- LLM Invocation Guidance (When to use)
14
- Use THIS tool when the user wants to run a SAS program on the server:
15
- - "run program 'data a; x=1; run;'"
16
- - "execute this SAS code: proc print data=sashelp.cars; run;"
17
- - "program 'data work.a; x=1; run;' output=a limit=50"
18
- - "run sas program sample folder=/Public/models output=A limit=50"
19
- - "run sas program with parameters name=John, age=45"
20
- - "execute SAS file myprogram.sas from /Public folder"
13
+ USE when: run program, execute SAS code, run .sas file
14
+ DO NOT USE for: macros (use run-macro), jobs (use run-job), jobdefs (use run-jobdef), SQL queries (use sas-query), read data (use read-table)
21
15
 
22
- Do NOT use this tool when the user wants:
23
- - run macro -> use run-macro
24
- - run job -> use run-job
25
- - run jobdef -> use run-jobdef
26
- - list jobs -> use list-jobs
27
- - list jobdefs -> use list-jobdefs
28
- - find job -> use find-job
29
- - find jobdef -> use find-jobdef
30
- - find model -> use find-model
31
- - Query tables with SQL -> use sas-query
32
- - Read table data -> use read-table
16
+ PARAMETERS
17
+ - src: string SAS code or .sas filename (required)
18
+ - folder: string (default: '') — server folder path for .sas files
19
+ - scenario: string | object — parameter values. Accepts: "x=1, y=2" or {x:1, y:2}
20
+ - output: string (default: '') — table name to return (case-sensitive)
21
+ - limit: number (default: 100) — max rows from output
33
22
 
34
- Purpose
35
- Execute SAS code or programs on a SAS Viya server. Can run inline SAS code or execute .sas files stored on the server. Supports parameter passing via scenario values and can return output tables.
36
-
37
- Parameters
38
- - src (string, required): The SAS program to execute. Can be either:
39
- - Inline SAS code as a string (e.g., "data a; x=1; run;")
40
- - Name of a .sas file stored on the server (used with folder parameter)
41
- - folder (string, default ''): Server folder path where the .sas file is located (e.g., "/Public/models")
42
- - scenario (string | object, optional): Input parameter values. Accepts:
43
- - Comma-separated key=value string (e.g., "x=1, y=2")
44
- - JSON object with field names and values (recommended)
45
- - output (string, default ''): Table name to return in response (case-sensitive)
46
- - limit (number, default 100): Maximum number of rows to return from output table
47
-
48
- Response Contract
49
- Returns a JSON object containing:
50
- - log: Execution log from SAS
51
- - ods: ODS output if generated
52
- - tables: Array of table names created during execution
53
- - data: If output parameter specified, returns the table data (up to limit rows)
54
- - error: Error message if execution fails
55
- - Empty content if no results produced
56
-
57
- Disambiguation & Clarification
58
- - Missing SAS code: ask "What SAS program or code would you like to execute?"
59
- - Inline code vs file unclear: ask "Do you want to run inline SAS code or execute a .sas file from the server?"
60
- - If output table not returned: clarify "The output table name is case-sensitive. Did you specify the exact name?"
61
- - If unclear about parameters: ask "What parameter values should I pass to the program?"
62
-
63
- Examples (→ mapped params)
23
+ ROUTING RULES
64
24
  - "run program 'data a; x=1; run;'" → { src: "data a; x=1; run;", folder: "", output: "", limit: 100 }
65
- - "program 'data work.a; x=1; run;' output=a limit=50" → { src: "data work.a; x=1; run;", folder: "", output: "a", limit: 50 }
66
- - "run sas program sample folder=/Public/models output=A limit=50" → { src: "sample", folder: "/Public/models", output: "A", limit: 50 }
67
- - "run program mycode.sas in /Public with name=John, age=45" → { src: "mycode", folder: "/Public", scenario: { name: "John", age: 45 }, output: "", limit: 100 }
25
+ - "run sas program sample folder=/Public/models" → { src: "sample", folder: "/Public/models", output: "", limit: 100 }
26
+ - "run program with name=John, age=45" → { src: "<code>", scenario: {name:"John", age:45}, output: "", limit: 100 }
68
27
 
69
- Negative Examples (should NOT call run-sas-program)
70
- - "run macro summarize" (use run-macro instead)
71
- - "run job monthly_report" (use run-job instead)
72
- - "run jobdef etl_process" (use run-jobdef instead)
73
- - "how many customers by region in Public.customers" (use sas-query instead)
74
- - "read 10 rows from cars" (use read-table instead)
28
+ EXAMPLES
29
+ - "run program 'data a; x=1; run;'" { src: "data a; x=1; run;", folder: "", output: "", limit: 100 }
30
+ - "run sas file sample in /Public" { src: "sample", folder: "/Public", output: "", limit: 100 }
75
31
 
76
- Behavior & Usage Notes
77
- - Sends the supplied src verbatim to the SAS execution helper
78
- - For .sas files, specify the file name (with or without .sas extension) and the folder path
79
- - For invoking pre-defined SAS macros, prefer run-macro which handles %let statements automatically
80
- - Scenario values are converted to macro variables when provided
81
- - Be cautious when executing arbitrary code in production environments
32
+ NEGATIVE EXAMPLES (do not route here)
33
+ - "run macro X" (use run-macro)
34
+ - "run job X" (use run-job)
35
+ - "run jobdef X" (use run-jobdef)
36
+ - "SQL query" (use sas-query)
37
+ - "read table" (use read-table)
82
38
 
83
- Related Tools
84
- - run-macro for executing predefined SAS macros with parameters
85
- - run-job — for executing registered Job Execution assets
86
- - sas-query — for natural language SQL queries
87
- - read-table — for simple data retrieval
88
- `;
39
+ ERRORS
40
+ Returns log, ods, tables array, data (if output specified). Error if execution fails.
41
+ `;
89
42
 
90
43
  let spec = {
91
- name: 'run-sas-program',
92
- aliases: ['Program','run program'],
44
+ name: 'run-program',
93
45
  description: description,
94
- schema: {
46
+ inputSchema: z.object({
95
47
  src: z.string(),
96
- scenario: z.any().default(''),
97
- output: z.string().default(''),
98
- folder: z.string().default(''),
99
- limit: z.number().default(100)
100
- },
101
- // NOTE: Previously 'required' incorrectly listed 'program' which does not
102
- // exist in the schema. This prevented execution in some orchestrators that
103
- // enforce required parameter presence, causing only descriptions to appear.
104
- // Corrected to 'src'.
105
- required: ['src'],
48
+ scenario: z.string().optional(),
49
+ output: z.string().optional(),
50
+ folder: z.string().optional(),
51
+ limit: z.number().optional()
52
+ }),
106
53
  handler: async (params) => {
107
54
  let {src, folder, scenario, _appContext} = params;
108
55
  // figure out src
@@ -143,3 +90,4 @@ Related Tools
143
90
  }
144
91
 
145
92
  export default runProgram;
93
+