@sassoftware/sas-score-mcp-serverjs 1.0.1-12 → 1.0.1-13

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.
@@ -2,7 +2,8 @@
2
2
  name: sas-find-resource-strategy
3
3
  description: >
4
4
  Unified strategy for finding SAS Viya resources using find tools only. Supports library, table,
5
- model, job, and jobdef lookup with server-aware behavior for CAS/SAS resources. Use this skill
5
+ mas, job, and jobdef lookup with server-aware behavior for CAS/SAS resources. Treat the generic
6
+ term "model" as an alias that may refer to mas, job, or jobdef resources. Use this skill
6
7
  whenever the task is to verify whether a resource exists.
7
8
  ---
8
9
 
@@ -15,10 +16,16 @@ Use this skill to verify resource existence without using list tools.
15
16
  Supported resource types:
16
17
  - library
17
18
  - table
18
- - model
19
+ - mas
19
20
  - job
20
21
  - jobdef
21
22
 
23
+ Generic model aliases:
24
+ - `model` with no type defaults to `mas`
25
+ - `model mas` or `mas model` -> `mas`
26
+ - `model job` or `job model` -> `job`
27
+ - `model jobdef` or `jobdef model` -> `jobdef`
28
+
22
29
  ## Mandatory rule
23
30
 
24
31
  - Use the sas-find-resource strategy to check for the existence of a resource before attempting to read or use it. This ensures that follow-up actions are based on accurate information about resource availability.
@@ -28,7 +35,7 @@ Supported resource types:
28
35
 
29
36
  - Library -> `sas-score-find-library`
30
37
  - Table -> `sas-score-find-table`
31
- - Model -> `sas-score-find-model`
38
+ - MAS -> `sas-score-find-model`
32
39
  - Job -> `sas-score-find-job`
33
40
  - Jobdef -> `sas-score-find-jobdef`
34
41
 
@@ -60,14 +67,23 @@ If server is not provided:
60
67
  2. If not found, check SAS (uppercase library) - `sas-score-find-table({ lib: "<LIB>", name: "<table>", server: "sas" })`
61
68
  3. If found in both, report both and ask user which server to use for follow-up reads.
62
69
 
63
- ### Find model
70
+ ### Find models by type
64
71
 
65
- Use:
66
- - `sas-score-find-model({ name: "<model>" })`
72
+ Support requests in either form:
73
+ - `find model <name>`
74
+ - `find model <type> <name>`
75
+ - `find <type> model <name>`
76
+
77
+ Type routing rules:
78
+ - If type is omitted, assume `mas`
79
+ - `mas` -> use `sas-score-find-model({ name: "<name>" })`
80
+ - `job` -> use `sas-score-find-job({ name: "<name>" })`
81
+ - `jobdef` -> use `sas-score-find-jobdef({ name: "<name>" })`
67
82
 
68
83
  If a model type suffix is provided (for example `.mas`, `.job`, `.jobdef`, `.scr`):
69
84
  - For MAS model discovery, strip suffix and look up base name with `sas-score-find-model`.
70
- - For `.job` and `.jobdef`, use job and jobdef find tools instead of model find.
85
+ - For `.job` and `.jobdef`, use job and jobdef find tools instead of MAS find.
86
+ - For `.scr`, do not use this strategy; route to SCR-specific model handling.
71
87
 
72
88
  ### Find job
73
89
 
@@ -84,7 +100,7 @@ Use:
84
100
  Ask one focused question if required fields are missing:
85
101
  - Library missing for table lookup: "Which library contains the table?"
86
102
  - Table name missing: "Which table name should I check?"
87
- - Resource type ambiguous: "Do you want me to find a library, table, model, job, or jobdef?"
103
+ - Resource type ambiguous: "Do you want me to find a library, table, mas, job, or jobdef resource?"
88
104
 
89
105
  ## Output format
90
106
 
@@ -101,5 +117,10 @@ For not found resources:
101
117
  - "find library Samples" -> CAS first, then SAS fallback using uppercase.
102
118
  - "find table costchange in Samples" -> CAS first, then SAS fallback using uppercase library.
103
119
  - "find model breastcancer" -> `sas-score-find-model`.
120
+ - "find model mas breastcancer" -> `sas-score-find-model`.
121
+ - "find mas model breastcancer" -> `sas-score-find-model`.
122
+ - "find model job simplejob" -> `sas-score-find-job`.
123
+ - "find job model simplejob" -> `sas-score-find-job`.
124
+ - "find model jobdef daily_run" -> `sas-score-find-jobdef`.
104
125
  - "find job simplejob" -> `sas-score-find-job`.
105
126
  - "find jobdef daily_run" -> `sas-score-find-jobdef`.
@@ -2,7 +2,8 @@
2
2
  name: sas-list-resource-strategy
3
3
  description: >
4
4
  Unified strategy for listing SAS Viya resources using list tools. Supports libraries,
5
- tables, models, jobs, and jobdefs. Always normalize pagination so start and limit are
5
+ tables, mas resources, jobs, and jobdefs. Treat the generic term "model" as an alias that may
6
+ refer to mas, job, or jobdef resources. Always normalize pagination so start and limit are
6
7
  never null: default start=1 and limit=10 when not provided.
7
8
  ---
8
9
 
@@ -15,10 +16,17 @@ Use this skill to list resources with consistent pagination defaults.
15
16
  Supported resource types:
16
17
  - library
17
18
  - table
18
- - model
19
+ - mas
19
20
  - job
20
21
  - jobdef
21
22
 
23
+ Generic model aliases:
24
+ - `model` with no type defaults to `mas`
25
+ - `model mas` or `mas model` -> `mas`
26
+ - `model job` or `job model` -> `job`
27
+ - `model jobdef` or `jobdef model` -> `jobdef`
28
+
29
+
22
30
  ## Mandatory pagination rule
23
31
 
24
32
  For every list operation:
@@ -37,7 +45,7 @@ limit = (limit == null) ? 10 : limit
37
45
 
38
46
  - Library -> `sas-score-list-libraries`
39
47
  - Table -> `sas-score-list-table`
40
- - Model -> `sas-score-list-models`
48
+ - MAS -> `sas-score-list-models`
41
49
  - Job -> `sas-score-list-jobs`
42
50
  - Jobdef -> `sas-score-list-jobdefs`
43
51
 
@@ -75,7 +83,19 @@ If `lib` is missing, ask: "Which library should I list tables from?"
75
83
 
76
84
  ### List models
77
85
 
78
- Use:
86
+ Support requests in either form:
87
+ - `list model`
88
+ - `list models`
89
+ - `list model <type>`
90
+ - `list <type> model`
91
+
92
+ Type routing rules:
93
+ - If type is omitted, assume `mas`
94
+ - `mas` -> use `sas-score-list-models`
95
+ - `job` -> use `sas-score-list-jobs`
96
+ - `jobdef` -> use `sas-score-list-jobdefs`
97
+
98
+ Use for `mas`:
79
99
  ```
80
100
  sas-score-list-models({
81
101
  start: 1,
@@ -83,6 +103,22 @@ sas-score-list-models({
83
103
  })
84
104
  ```
85
105
 
106
+ Use for `job`:
107
+ ```
108
+ sas-score-list-jobs({
109
+ start: 1,
110
+ limit: 10
111
+ })
112
+ ```
113
+
114
+ Use for `jobdef`:
115
+ ```
116
+ sas-score-list-jobdefs({
117
+ start: 1,
118
+ limit: 10
119
+ })
120
+ ```
121
+
86
122
  ### List jobs
87
123
 
88
124
  Use:
@@ -106,7 +142,7 @@ sas-score-list-jobdefs({
106
142
  ## Clarifying prompts
107
143
 
108
144
  Ask one focused question if required context is missing:
109
- - Resource type unclear: "Do you want libraries, tables, models, jobs, or jobdefs?"
145
+ - Resource type unclear: "Do you want libraries, tables, mas resources, jobs, or jobdefs?"
110
146
  - Listing tables without library: "Which library should I list tables from?"
111
147
 
112
148
  ## Output and paging
@@ -118,7 +154,14 @@ Ask one focused question if required context is missing:
118
154
  ## Examples
119
155
 
120
156
  - "list jobs" -> `sas-score-list-jobs({ start: 1, limit: 10 })`
157
+ - "list model" -> `sas-score-list-models({ start: 1, limit: 10 })`
121
158
  - "list models" -> `sas-score-list-models({ start: 1, limit: 10 })`
159
+ - "list model mas" -> `sas-score-list-models({ start: 1, limit: 10 })`
160
+ - "list mas model" -> `sas-score-list-models({ start: 1, limit: 10 })`
161
+ - "list model job" -> `sas-score-list-jobs({ start: 1, limit: 10 })`
162
+ - "list job model" -> `sas-score-list-jobs({ start: 1, limit: 10 })`
163
+ - "list model jobdef" -> `sas-score-list-jobdefs({ start: 1, limit: 10 })`
164
+ - "list jobdef model" -> `sas-score-list-jobdefs({ start: 1, limit: 10 })`
122
165
  - "list jobdefs" -> `sas-score-list-jobdefs({ start: 1, limit: 10 })`
123
166
  - "list tables in Public" -> `sas-score-list-tables({ lib: "Public", start: 1, limit: 10 })`
124
167
  - "next jobs" after `{ start: 1, limit: 10 }` -> `sas-score-list-jobs({ start: 11, limit: 10 })`
@@ -49,6 +49,7 @@ Ask yourself: does the user already have the data in hand?
49
49
  - Simple WHERE filtering (e.g., "where status = 'active'")
50
50
  - Pagination needed ("first 50 rows", "next 10 rows")
51
51
 
52
+
52
53
  **How:**
53
54
  ```
54
55
  sas-score-read-table({
@@ -10,6 +10,7 @@ Use this skill to determine what kind of SAS object, workflow, or environment th
10
10
  ## When to use
11
11
  Use this skill when the request contains ambiguous domain terms such as:
12
12
  - model
13
+ - mas
13
14
  - score
14
15
  - scoring
15
16
  - read
@@ -29,8 +30,8 @@ Map the user request to the most likely SAS domain and hand off to the correct d
29
30
 
30
31
  ## Classification targets
31
32
  Classify the request into one or more of these categories:
32
- - Resource existence lookup (library/table/model/job/jobdef) -> Route to **sas-find-resource-strategy**
33
- - Resource listing (library/table/model/job/jobdef) -> Route to **sas-list-resource-strategy**
33
+ - Resource existence lookup (library/table/mas/job/jobdef, with generic "model" phrasing allowed) -> Route to **sas-find-resource-strategy**
34
+ - Resource listing (library/table/mas/job/jobdef, with generic "model" phrasing allowed) -> Route to **sas-list-resource-strategy**
34
35
  - Reading or querying tables → Route to **sas-read-strategy**
35
36
  - CAS resource, SAS resource, caslib, or table discovery → Route to **sas-find-library-smart**
36
37
  - SAS data, libref, or table discovery → Route to **sas-find-library-smart**
@@ -47,8 +48,8 @@ Classify the request into one or more of these categories:
47
48
  3. Decide the most likely SAS domain and matching skill.
48
49
  4. If confidence is low, ask one focused clarifying question.
49
50
  5. If confidence is high, load and use the relevant skill:
50
- - **sas-find-resource-strategy** — Unified find-only strategy for library/table/model/job/jobdef
51
- - **sas-list-resource-strategy** — Unified list strategy for library/table/model/job/jobdef with non-null pagination defaults
51
+ - **sas-find-resource-strategy** — Unified find-only strategy for library/table/mas/job/jobdef, where "model" may mean mas, job, or jobdef
52
+ - **sas-list-resource-strategy** — Unified list strategy for library/table/mas/job/jobdef, where "model" may mean mas, job, or jobdef, with non-null pagination defaults
52
53
  - **sas-find-library-smart** — Find CAS or SAS libraries
53
54
  - **sas-list-tables-smart** — Browse tables in a library
54
55
  - **sas-read-strategy** — Choose read-table vs. sas-query for data retrieval
@@ -58,7 +59,7 @@ Classify the request into one or more of these categories:
58
59
 
59
60
  ## Disambiguation hints
60
61
  - "Run" often implies job execution, but may also mean scoring or model invocation. Check for "score" or "model" context.
61
- - "Model" may refer to MAS models, SAS jobs, jobdefs, or SCR models. Look for context or type suffix (e.g., `.job`, `.mas`, `.scr`).
62
+ - "Model" is a generic term that may refer to MAS, job, or jobdef resources in find/list requests. Prefer explicit patterns like `model <type>` or `<type> model`; default bare "model" to MAS unless the surrounding request implies job or jobdef.
62
63
  - "Score" may refer to model scoring or job execution. Look for model name or context.
63
64
  - "Table" usually suggests CAS or SAS but confirm library name and server context.
64
65
  - "Find" — resource lookup. Route to sas-find-resource-strategy.
@@ -22,6 +22,7 @@ Users can invoke scoring with a unified syntax that automatically routes to the
22
22
  ```
23
23
  score with model <name>.<type> [scenario =<key=value pairs>]
24
24
  score <name>.<type> [scenario =<key=value pairs>]
25
+ score key=value,... with model <name>.<type>
25
26
  ```
26
27
 
27
28
  **Type determines the routing:**
package/cli.js CHANGED
@@ -9,8 +9,6 @@
9
9
 
10
10
  import coreSSE from './src/coreSSE.js';
11
11
  import expressMcpServer from './src/expressMcpServer.js';
12
- import hapiMcpServer from './src/hapiMcpServer.js';
13
-
14
12
  import createMcpServer from './src/createMcpServer.js';
15
13
  // import dotenvExpand from 'dotenv-expand';
16
14
  import fs from 'fs';
@@ -468,14 +466,8 @@ if (mcpType === 'stdio') {
468
466
 
469
467
  } else {
470
468
  console.error('[Note] Starting HTTP MCP server...');
471
- if (useHapi === true) {
472
- process.env.AUTHTYPE = null;
473
- await hapiMcpServer(mcpServer, sessionCache, appEnvBase);
474
- console.error('[Note] Using HAPI HTTP server...')
475
- } else {
476
- await expressMcpServer(mcpServer, sessionCache, appEnvBase);
477
- console.error('[Note] MCP HTTP express server started on port ' + appEnvBase.PORT);
478
- }
469
+ await expressMcpServer(mcpServer, sessionCache, appEnvBase);
470
+ console.error('[Note] MCP HTTP express server started on port ' + appEnvBase.PORT);
479
471
  }
480
472
 
481
473
  // custom reader for .env file to avoid dotenv logging to console
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sassoftware/sas-score-mcp-serverjs",
3
- "version": "1.0.1-12",
3
+ "version": "1.0.1-13",
4
4
  "description": "A mcp server for SAS Viya",
5
5
  "author": "Deva Kumar <deva.kumar@sas.com>",
6
6
  "license": "Apache-2.0",
@@ -51,8 +51,7 @@
51
51
  "@sassoftware/restaf": "^5.7.2",
52
52
  "@sassoftware/restafedit": "^3.10.5",
53
53
  "@sassoftware/restaflib": "^5.7.2",
54
- "@sassoftware/viya-serverjs": "^0.6.3-0",
55
- "axios": "^1.13.2",
54
+ "axios": "^1.13.5",
56
55
  "body-parser": "^2.2.1",
57
56
  "cors": "^2.8.5",
58
57
  "cross-env": "^10.1.0",
@@ -64,8 +63,8 @@
64
63
  "node-cache": "^5.1.2",
65
64
  "open": "^11.0.0",
66
65
  "selfsigned": "^5.2.0",
67
- "undici": "^7.16.0",
68
- "uuid": "^13.0.0",
66
+ "undici": "^7.24.0",
67
+ "uuid": "^14.0.0",
69
68
  "zod": "^4.2.1"
70
69
  },
71
70
  "devDependencies": {
@@ -17,7 +17,7 @@ DO NOT USE for: find model, model metadata, list models, run programs/jobs, quer
17
17
 
18
18
  PARAMETERS
19
19
  - model: string — model name (required, exact match)
20
- - scenario: string | object | array — input data (required). Accepts: "x=1, y=2", {x:1, y:2}, or array of objects
20
+ - scenario: object — input data as JSON (optional, defaults to {}). Example: {age:45, income:60000}
21
21
  - uflag: boolean (default: false) — prefix model fields with underscore when true
22
22
 
23
23
  ROUTING RULES
@@ -42,34 +42,18 @@ Returns predictions, probabilities, scores merged with input data. Returns error
42
42
  let spec = {
43
43
  name: 'mas-score',
44
44
  description: description,
45
- inputSchema:z.object({
45
+ inputSchema: z.object({
46
46
  model: z.string(),
47
- scenario: z.string(),
47
+ scenario: z.union([z.record(z.any()), z.string()]).optional(),
48
48
  uflag: z.boolean().optional()
49
49
  }),
50
50
 
51
51
  handler: async (iparams) => {
52
- let params = {...iparams};
53
- let scenario = params.scenario;
54
-
55
- // Convert the scenario string to an object
56
- // Example: "x=1, y=2, z=3" to { x: 1, y: 2, z: 3 }
57
- let scenarioObj ={};
58
- let count = 0;
59
- if (typeof scenario === 'object') {
60
- scenarioObj = scenario;
61
- } else if (Array.isArray(scenario)) {
62
- scenarioObj = scenario[0];
63
- } else {
64
- //console.error('Incoming scenario', scenario);
65
- scenarioObj = scenario.split(',').reduce((acc, pair) => {
66
- let [key, value] = pair.split('=');
67
- acc[key.trim()] = value;
68
- count++;
69
- return acc;
70
- }, {});
71
- }
72
- params.scenario= scenarioObj;
52
+ let params = {...iparams};
53
+ if (typeof params.scenario === 'string') {
54
+ try { params.scenario = JSON.parse(params.scenario); } catch { params.scenario = {}; }
55
+ }
56
+ params.scenario = (params.scenario != null && typeof params.scenario === 'object') ? params.scenario : {};
73
57
 
74
58
  // Drop model extension (e.g., .job, .model)
75
59
  if (params.model && params.model.includes('.')) {
@@ -16,7 +16,7 @@ DO NOT USE for: arbitrary SAS code (use run-sas-program), macros (use run-macro)
16
16
 
17
17
  PARAMETERS
18
18
  - name: string — job name (required)
19
- - scenario: string | object — input parameters. Accepts: "x=1, y=2" or {x:1, y:2}
19
+ - scenario: object — input parameters as JSON (optional, defaults to {}). Example: {month:10, year:2025}
20
20
 
21
21
  ROUTING RULES
22
22
  - "run job xyz" → { name: "xyz" }
@@ -41,34 +41,14 @@ Returns log output, listings, tables from job. Error if job not found.
41
41
  description: description,
42
42
  inputSchema: z.object({
43
43
  name: z.string(),
44
- scenario: z.string().optional()
44
+ scenario: z.union([z.record(z.any()), z.string()]).optional()
45
45
  }),
46
46
  handler: async (params) => {
47
- let scenario = params.scenario;
48
- let scenarioObj = {};
49
- let count = 0;
50
- //
51
- if (scenario == null) {
52
- scenarioObj = {};
53
- } else if (typeof scenario === 'object') {
54
- scenarioObj = scenario;
55
- } else if (Array.isArray(scenario)) {
56
- scenarioObj = scenario[0];
57
- } else if (typeof scenario === 'string') {
58
- if (scenario.trim() === '') {
59
- scenarioObj = {};
60
- } else {
61
- // console.error('Incoming scenario', scenario);
62
- scenarioObj = scenario.split(',').reduce((acc, pair) => {
63
- let [key, value] = pair.split('=');
64
- acc[key.trim()] = value;
65
- count++;
66
- return acc;
67
- }, {});
68
- }
47
+ if (typeof params.scenario === 'string') {
48
+ try { params.scenario = JSON.parse(params.scenario); } catch { params.scenario = {}; }
69
49
  }
50
+ params.scenario = (params.scenario != null && typeof params.scenario === 'object') ? params.scenario : {};
70
51
  params.type = 'job';
71
- params.scenario = scenarioObj;
72
52
  // Provide runtime context for auth and server settings
73
53
  let r = await _jobSubmit(params);
74
54
  return r;
@@ -17,7 +17,7 @@ DO NOT USE for: arbitrary SAS code (use run-sas-program), macros (use run-macro)
17
17
 
18
18
  PARAMETERS
19
19
  - name: string — jobdef name (required)
20
- - scenario: string | object — input parameters. Accepts: "x=1, y=2" or {x:1, y:2}
20
+ - scenario: object — input parameters as JSON (optional, defaults to {}). Example: {month:10, year:2025}
21
21
 
22
22
  ROUTING RULES
23
23
  - "run jobdef xyz" → { name: "xyz" }
@@ -42,34 +42,14 @@ Returns log output, listings, tables from jobdef. Error if jobdef not found.
42
42
  description: description,
43
43
  inputSchema: z.object({
44
44
  name: z.string(),
45
- scenario: z.string().optional()
45
+ scenario: z.union([z.record(z.any()), z.string()]).optional()
46
46
  }),
47
47
  handler: async (params) => {
48
- let scenario = params.scenario;
49
- let scenarioObj = {};
50
- let count = 0;
51
- //
52
- if (scenario == null) {
53
- scenarioObj = {};
54
- } else if (typeof scenario === 'object') {
55
- scenarioObj = scenario;
56
- } else if (Array.isArray(scenario)) {
57
- scenarioObj = scenario[0];
58
- } else if (typeof scenario === 'string') {
59
- if (scenario.trim() === '') {
60
- scenarioObj = {};
61
- } else {
62
- // console.error('Incoming scenario', scenario);
63
- scenarioObj = scenario.split(',').reduce((acc, pair) => {
64
- let [key, value] = pair.split('=');
65
- acc[key.trim()] = value;
66
- count++;
67
- return acc;
68
- }, {});
69
- }
48
+ if (typeof params.scenario === 'string') {
49
+ try { params.scenario = JSON.parse(params.scenario); } catch { params.scenario = {}; }
70
50
  }
51
+ params.scenario = (params.scenario != null && typeof params.scenario === 'object') ? params.scenario : {};
71
52
  params.type = 'def';
72
- params.scenario = scenarioObj;
73
53
  // Provide runtime context for auth and server settings
74
54
  let r = await _jobSubmit(params);
75
55
  return r;
@@ -1,70 +1,61 @@
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
-
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 (object, optional): Input values to score as a JSON object (e.g. {age:45, income:60000}). If omitted, defaults to {} and the tool will return the model's input variable definitions.
19
+
20
+ What it returns
21
+ - When scoring: the SCR endpoint response (predictions, probabilities, scores) merged with or alongside the supplied inputs.
22
+ - When \`scenario\` is omitted: metadata describing the model's input variables (names, types, required/optional).
23
+
24
+ Usage notes
25
+ - Run \`scr-info\` first to inspect the expected input variables and types.
26
+ - Prefer structured objects for numeric/date values to avoid type ambiguity; the simple string parser keeps values as strings.
27
+ - Ensure network connectivity and any required credentials for the target SCR service.
28
+
29
+ Examples
30
+ - scrScore with url="loan" and scenario={age:45, income:60000}
31
+ `;
32
+
33
+ let spec = {
34
+ name: 'scr-score',
35
+ description: description,
36
+ inputSchema: z.object({
37
+ url: z.string(),
38
+ scenario: z.union([z.record(z.any()), z.string()]).optional()
39
+ }),
40
+
41
+ handler: async (params) => {
42
+ let {url, _appContext} = params;
43
+ let scenario = params.scenario;
44
+ if (typeof scenario === 'string') {
45
+ try { scenario = JSON.parse(scenario); } catch { scenario = {}; }
46
+ }
47
+ if (url === null) {
48
+ return { status: { statusCode: 2, msg: `SCR model ${url} was not specified` }, results: {} };
49
+ }
50
+
51
+ const scenarioObj = (scenario != null && typeof scenario === 'object') ? scenario : {};
52
+
53
+ let r = await _scrScore({ url: url, scenario: scenarioObj, _appContext: _appContext});
54
+ return r;
55
+ }
56
+ }
57
+
58
+ return spec;
59
+ }
60
+
70
61
  export default scrScore;
File without changes
File without changes
File without changes