@sassoftware/sas-score-mcp-serverjs 0.4.0 → 0.4.1-1

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 CHANGED
@@ -354,7 +354,6 @@ console.error('[Note] appEnvBase is', JSON.stringify(appEnvBase, null,2));
354
354
  // creat a dummy sessionId for stdio since there is only one session and transport in that case, and tools need a sessionId to access the appEnvBase and contexts
355
355
  let sessionId = randomUUID();
356
356
  sessionCache.set(sessionId, appEnvBase);
357
- useHapi = false; // for now disable hapi for authflow code since it is not working well, and code flow is not commonly used in server side applications, and http transport works better for code flow since it requires multiple back and forth calls to complete the auth process which is not ideal for stdio transport, this will be revisited in the future to either fix the issues with hapi or implement the code flow in a way that works better with stdio transport
358
357
  if (mcpType === 'stdio') {
359
358
  console.error('[Note] Setting up stdio transport with sessionId:', sessionId);
360
359
  console.error('[Note] Used in setting up tools and some persistence(not all).');
@@ -368,7 +367,7 @@ if (mcpType === 'stdio') {
368
367
  console.error('[Note] Using HAPI HTTP server...')
369
368
  } else {
370
369
  await expressMcpServer(mcpServer, sessionCache, appEnvBase);
371
- console.error('[Note] MCP HTTP server started on port ' + appEnvBase.PORT);
370
+ console.error('[Note] MCP HTTP express server started on port ' + appEnvBase.PORT);
372
371
  }
373
372
  }
374
373
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sassoftware/sas-score-mcp-serverjs",
3
- "version": "0.4.0",
3
+ "version": "0.4.1-1",
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,7 @@
43
43
  "skills"
44
44
  ],
45
45
  "dependencies": {
46
- "@modelcontextprotocol/sdk": "^1.25.1",
46
+ "@modelcontextprotocol/sdk": "^1.29.0",
47
47
  "@sassoftware/restaf": "^5.6.0",
48
48
  "@sassoftware/restafedit": "^3.11.1-10",
49
49
  "@sassoftware/restaflib": "^5.6.0",
@@ -57,10 +57,8 @@
57
57
  "express-list-endpoints": "^7.1.1",
58
58
  "express-rate-limit": "^8.2.1",
59
59
  "helmet": "^8.1.0",
60
- "mcp-framework": "^0.2.16",
61
60
  "node-cache": "^5.1.2",
62
61
  "open": "^11.0.0",
63
- "puppeteer": "^24.34.0",
64
62
  "selfsigned": "^5.2.0",
65
63
  "undici": "^7.16.0",
66
64
  "uuid": "^13.0.0",
@@ -33,6 +33,7 @@ score <name>.<type> [scenario =<key=value pairs>]
33
33
 
34
34
  If no type is specified (bare model name), assume `.mas` (MAS model).
35
35
 
36
+
36
37
  ---
37
38
 
38
39
  ## Type-Based Routing
@@ -73,11 +73,18 @@ async function createMcpServer(cache, _appContext) {
73
73
  let toolNames = [];
74
74
  toolSet.forEach((tool, i) => {
75
75
  let toolName = _appContext.brand + '-' + tool.name;
76
- // console.error(`\n[Note] Registering tool ${i + 1} : ${toolName}`);
76
+ tool.inputSchema.additionalProperties = false; // disallow extra properties
77
+ let config = {
78
+ title: toolName,
79
+ description: tool.description,
80
+ inputSchema: tool.inputSchema
81
+ }
82
+ console.error(`[Note] Configuring tool ${toolName} with input schema: ${JSON.stringify(tool.inputSchema)}`);
83
+ console.error(`\n[Note] Registering tool ${i + 1} : ${toolName}`);
77
84
  let toolHandler = wrapf(cache, tool.handler);
78
85
 
79
- mcpServer.tool(toolName, tool.description, tool.schema, toolHandler);
80
-
86
+ let r = mcpServer.registerTool(toolName, config, toolHandler);
87
+ console.error(`[Note] Tool ${toolName} registered with result: ${JSON.stringify(r)}`);
81
88
  toolNames.push(toolName);
82
89
  });
83
90
  console.error(`[Note] Registered ${toolSet.length} tools: ${toolNames}`);
@@ -129,7 +129,7 @@ function requireBearer(req, res, next) {
129
129
  cache.set("headerCache", headerCache);
130
130
  next();
131
131
  console.error("Finished processing headers for /mcp request");
132
- console.log("=======================================================");
132
+ console.error("=======================================================");
133
133
  }
134
134
 
135
135
  // process mcp endpoint requests
@@ -17,7 +17,7 @@ async function handleGetDelete(mcpServer, cache, req, h) {
17
17
  if (req.method === "GET") {
18
18
  // You can customize the response as needed
19
19
  console.error("[Note] Payload:", req.payload);
20
- console.log("======================================================");
20
+ console.error("======================================================");
21
21
  await transport.handleRequest(req.raw.req, req.raw.res, req.payload);
22
22
  return h.abandon;
23
23
  }
@@ -9,23 +9,23 @@ function getCerts(tlsdir) {
9
9
  return null;
10
10
  }
11
11
 
12
- console.log(`[Note] Reading certs from directory: ` + tlsdir);
12
+ console.error(`[Note] Reading certs from directory: ` + tlsdir);
13
13
  if (fs.existsSync(tlsdir) === false) {
14
14
  console.error("[Warning] Specified cert dir does not exist: " + tlsdir);
15
15
  return null;
16
16
  }
17
17
 
18
18
  let listOfFiles = fs.readdirSync(tlsdir);
19
- console.log("[Note] TLS/SSL files found: " + listOfFiles);
19
+ console.error("[Note] TLS/SSL files found: " + listOfFiles);
20
20
  let options = {};
21
21
  for(let i=0; i < listOfFiles.length; i++) {
22
22
  let fname = listOfFiles[i];
23
23
  let name = tlsdir + '/' + listOfFiles[i];
24
24
  let key = fname.split('.')[0];
25
- console.log('Reading TLS file: ' + name + ' as key: ' + key);
25
+ console.error('Reading TLS file: ' + name + ' as key: ' + key);
26
26
  options[key] = fs.readFileSync(name, { encoding: 'utf8' });
27
27
  }
28
- console.log('cert files', Object.keys(options));
28
+ console.error('cert files', Object.keys(options));
29
29
 
30
30
  return options;
31
31
 
@@ -2,7 +2,7 @@
2
2
  * Copyright © 2025, SAS Institute Inc., Cary, NC, USA. All Rights Reserved.
3
3
  * SPDX-License-Identifier: Apache-2.0
4
4
  */
5
- import {z} from 'zod';
5
+ import { z } from 'zod';
6
6
 
7
7
  function devaScore(_appContext) {
8
8
 
@@ -39,23 +39,23 @@ Returns { score: (a + b) * 42 }
39
39
  `;
40
40
  let spec = {
41
41
  name: 'deva-score',
42
- aliases: ['devaScore','deva score','deva_score'],
43
42
  description: description,
44
- schema: {
43
+ inputSchema: z.object({
45
44
  a: z.number(),
46
45
  b: z.number()
47
- },
46
+ }),
48
47
  handler: async ({ a, b }) => {
49
- console.error( a, b);
50
- let r = {score: (a + b) * 42};
48
+ console.error(a, b);
49
+ let r = { score: (a + b) * 42 };
51
50
  console.error('deva score result', r);
52
51
  return {
53
- content: [{type: 'text', text: 'deva score result: ' + JSON.stringify(r)}],
52
+ content: [{ type: 'text', text: 'deva score result: ' + JSON.stringify(r) }],
54
53
  structuredContent: r
55
- };
56
- }
54
+ };
57
55
  }
58
-
56
+ }
57
+
59
58
  return spec;
60
59
  }
61
60
  export default devaScore;
61
+
@@ -5,16 +5,7 @@
5
5
  import { z } from 'zod';
6
6
  import _listJobs from '../toolHelpers/_listJobs.js';
7
7
  function findJob(_appContext) {
8
- let llmDescription= {
9
- "purpose": "Map natural language requests to find a job in SAS Viya and return structured results.",
10
- "param_mapping": {
11
- "name": "required - single name. If missing, ask 'Which job name would you like to find?'.",
12
- "_userPrompt": "the original user prompt that triggered this tool."
13
-
14
- },
15
- "response_schema": "{ jobs: Array<string|object> }",
16
- "behavior": "Return only JSON matching response_schema when invoked by an LLM. If no matches, return { jobs: [] }"
17
- };
8
+
18
9
  let description = `
19
10
  find-job — locate a specific SAS Viya job.
20
11
 
@@ -49,18 +40,20 @@ Returns { jobs: [] } if not found; { jobs: [name, ...] } if found. Never halluci
49
40
 
50
41
  let spec = {
51
42
  name: 'find-job',
52
- aliases: ['findJob','find job','find_job'],
53
43
  description: description,
54
- schema: {
44
+ inputSchema: z.object({
55
45
  name: z.string(),
56
- _userPrompt: z.string()
57
- },
58
- required: ['name'],
46
+ }),
59
47
  handler: async (params) => {
60
48
  let r = await _listJobs(params);
61
49
  return r;
62
50
  }
63
51
  }
52
+
53
+
54
+ /* correct spec for registerTool with inputSchema */
55
+
64
56
  return spec;
65
57
  }
66
58
  export default findJob;
59
+
@@ -49,12 +49,10 @@ Returns { jobdefs: [] } if not found; { jobdefs: [name, ...] } if found. Never h
49
49
 
50
50
  let spec = {
51
51
  name: 'find-jobdef',
52
- aliases: ['findJobdef','find jobdef','find_jobdef'],
53
52
  description: description,
54
- schema: {
53
+ inputSchema: z.object({
55
54
  name: z.string()
56
- },
57
- required: ['name'],
55
+ }),
58
56
  handler: async (params) => {
59
57
  let r = await _listJobdefs(params);
60
58
  return r;
@@ -63,3 +61,4 @@ Returns { jobdefs: [] } if not found; { jobdefs: [name, ...] } if found. Never h
63
61
  return spec;
64
62
  }
65
63
  export default findJobdef;
64
+
@@ -42,13 +42,11 @@ Returns { libraries: [] } if not found; { libraries: [name, ...] } if found. Nev
42
42
 
43
43
  let spec = {
44
44
  name: 'find-library',
45
- aliases: ['findLibrary','find library','find_library'],
46
45
  description: description,
47
- schema: {
46
+ inputSchema: z.object({
48
47
  name: z.string(),
49
- server: z.string().default('cas')
50
- },
51
- required: ['name'],
48
+ server: z.string()
49
+ }),
52
50
  handler: async (params) => {
53
51
  // normalize server to lowercase & default
54
52
  if (!params.server) params.server = 'cas';
@@ -66,3 +64,4 @@ Returns { libraries: [] } if not found; { libraries: [name, ...] } if found. Nev
66
64
  return spec;
67
65
  }
68
66
  export default findLibrary;
67
+
@@ -44,12 +44,10 @@ Returns { models: [] } if not found; { models: [name, ...] } if found. Never hal
44
44
 
45
45
  let spec = {
46
46
  name: 'find-model',
47
- aliases: ['findModel','find model','find_model'],
48
47
  description: description,
49
- schema: {
48
+ inputSchema: z.object({
50
49
  'name': z.string()
51
- },
52
- required: ['name'],
50
+ }),
53
51
  handler: async (params) => {
54
52
  let r = await _listModels(params);
55
53
  return r;
@@ -59,3 +57,4 @@ Returns { models: [] } if not found; { models: [name, ...] } if found. Never hal
59
57
  }
60
58
 
61
59
  export default findModel;
60
+
@@ -45,14 +45,12 @@ Returns { tables: [] } if not found; { tables: [name, ...] } if found. Never hal
45
45
 
46
46
  let spec = {
47
47
  name: 'find-table',
48
- aliases: ['findTable','find table','find_table'],
49
48
  description: description,
50
- schema: {
51
- server: z.string().default('cas'), // default server is 'cas',
49
+ inputSchema: z.object({
50
+ server: z.string(), // default server is 'cas',
52
51
  name: z.string(),
53
52
  lib: z.string()
54
- },
55
- required: ['name', 'lib'],
53
+ }),
56
54
  handler: async (params) => {
57
55
  // Check if the params.scenario is a string and parse it
58
56
  let r = await _listTables(params);
@@ -63,3 +61,4 @@ Returns { tables: [] } if not found; { tables: [name, ...] } if found. Never hal
63
61
  }
64
62
 
65
63
  export default findTable;
64
+
@@ -38,17 +38,16 @@ Returns variable name with current value, or null if not found. Return structure
38
38
  `;
39
39
 
40
40
  let spec = {
41
- name: 'get-env',
42
- aliases: ['get-env','get env','get environment'],
43
- description: description,
44
- schema: {
41
+ name: 'get-env',
42
+ description: description,
43
+ inputSchema: z.object({
45
44
  name: z.string()
46
- },
47
-
48
- handler: async (params) => {
45
+ }),
46
+ handler: async (params) => {
49
47
  return await _getEnv(params);
50
48
  }
51
49
  }
52
50
  return spec;
53
51
  }
54
52
  export default getEnv;
53
+
@@ -42,15 +42,13 @@ Surface backend error directly; never fabricate jobdef names.
42
42
 
43
43
  let spec = {
44
44
  name: 'list-jobdefs',
45
- aliases: ['listJobdefs','list jobdefs','list_jobdefs'],
46
45
  description: description,
47
- schema: {
48
- limit: z.number().default(10),
49
- start: z.number().default(1),
50
- where: z.string().default('')
51
- },
46
+ inputSchema: z.object({
47
+ limit: z.number(),
48
+ start: z.number(),
49
+ where: z.string()
50
+ }),
52
51
  // No 'server' required; backend context is implicit in helper
53
- required: [],
54
52
  handler: async (params) => {
55
53
  // _listJobdefs handles all validation and defaults
56
54
  const result = await _listJobdefs(params);
@@ -60,3 +58,4 @@ Surface backend error directly; never fabricate jobdef names.
60
58
  return spec;
61
59
  }
62
60
  export default listJobdefs;
61
+
@@ -42,15 +42,13 @@ Surface backend error directly; never fabricate job names.
42
42
 
43
43
  let spec = {
44
44
  name: 'list-jobs',
45
- aliases: ['listJobs','list jobs','list_jobs'],
46
45
  description: description,
47
- schema: {
48
- limit: z.number().default(10),
49
- start: z.number().default(1),
50
- where: z.string().default('')
51
- },
46
+ inputSchema: z.object({
47
+ limit: z.number(),
48
+ start: z.number(),
49
+ where: z.string()
50
+ }),
52
51
  // No 'server' required; backend context is implicit in helper
53
- required: [],
54
52
  handler: async (params) => {
55
53
  // _listJob handles all validation and defaults
56
54
  const result = await _listJobs(params);
@@ -60,3 +58,4 @@ Surface backend error directly; never fabricate job names.
60
58
  return spec;
61
59
  }
62
60
  export default listJobs;
61
+
@@ -56,16 +56,14 @@ Return structured error with a message field. Never hallucinate library names.
56
56
 
57
57
  let spec = {
58
58
  name: 'list-libraries',
59
- aliases: ['listLibraries','list libraries','list_libraries'],
60
59
  description: description,
61
- schema: {
62
- server: z.string().default('all'),
63
- limit: z.number().default(10),
64
- start: z.number().default(1), // added default to match documentation
65
- where: z.string().default('')
66
- },
60
+ inputSchema:z.object( {
61
+ server: z.string(),
62
+ limit: z.number(),
63
+ start: z.number(),// added default to match documentation
64
+ where: z.string()
65
+ }),
67
66
  // 'server' has a default so we don't mark it required
68
- required: [],
69
67
  handler: async (params) => {
70
68
  // normalize server just in case caller sends 'CAS'/'SAS'
71
69
  params.server = (params.server || 'all').toLowerCase();
@@ -77,4 +75,4 @@ Return structured error with a message field. Never hallucinate library names.
77
75
  return spec;
78
76
  }
79
77
  export default listLibraries;
80
-
78
+
@@ -38,12 +38,11 @@ Returns empty array if no models found.
38
38
 
39
39
  let spec = {
40
40
  name: 'list-models',
41
- aliases: ['listModels','list models','list_models'],
42
41
  description: description,
43
- schema: {
44
- 'limit': z.number().default(10),
45
- 'start': z.number().default(1)
46
- },
42
+ inputSchema: z.object({
43
+ 'limit': z.number(),
44
+ 'start': z.number()
45
+ }),
47
46
  handler: async (params) => {
48
47
  let r = await _listModels(params);
49
48
  return r;
@@ -54,3 +53,4 @@ Returns empty array if no models found.
54
53
  }
55
54
 
56
55
  export default listModels;
56
+
@@ -44,17 +44,15 @@ Returns empty array if no tables found.
44
44
  `;
45
45
 
46
46
  let spec = {
47
- name: 'list-tables',
48
- aliases: ['listTables','list tables','list_tables'],
47
+ name: 'list-tables',
49
48
  description: description,
50
49
 
51
- schema: {
50
+ inputSchema: z.object({
52
51
  'lib': z.string(),
53
- 'server': z.string().default('cas'),
54
- 'limit': z.number().default(10),
55
- 'start': z.number().default(1)
56
- },
57
- required: ['lib'],
52
+ 'server': z.string(),
53
+ 'limit': z.number(),
54
+ 'start': z.number()
55
+ }),
58
56
  handler: async (params) => {
59
57
  let r = await _listTables(params);
60
58
  return r;
@@ -64,3 +62,4 @@ Returns empty array if no tables found.
64
62
  }
65
63
 
66
64
  export default listTables;
65
+
@@ -30,7 +30,7 @@ import findJobdef from './findJobdef.js';
30
30
 
31
31
  import sasQuery from './sasQuery.js';
32
32
  import setContext from './setContext.js';
33
- //import scoreSkill from './scoreSkill.js';
33
+
34
34
 
35
35
  function makeTools(_appContext) {
36
36
  // wrap all tools with
@@ -65,8 +65,6 @@ function makeTools(_appContext) {
65
65
  findJobdef(_appContext),
66
66
  runJobdef(_appContext),
67
67
 
68
- //scoreSkill(_appContext),
69
-
70
68
  devaScore(_appContext),
71
69
  setContext(_appContext)
72
70
 
@@ -39,12 +39,10 @@ Returns model metadata: inputs (name, type, role), outputs (name, type, possible
39
39
 
40
40
  let spec = {
41
41
  name: 'model-info',
42
- aliases: ['modelInfo','model info','model_info'],
43
42
  description: description,
44
- schema: {
43
+ inputSchema: z.object({
45
44
  'model': z.string()
46
- },
47
- required: ['model'],
45
+ }),
48
46
  handler: async (params) => {
49
47
  let r = await _masDescribe(params);
50
48
  return r;
@@ -54,3 +52,4 @@ Returns model metadata: inputs (name, type, role), outputs (name, type, possible
54
52
  }
55
53
 
56
54
  export default modelInfo;
55
+
@@ -41,14 +41,12 @@ Returns predictions, probabilities, scores merged with input data. Returns error
41
41
 
42
42
  let spec = {
43
43
  name: 'model-score',
44
- aliases: ['modelScore','model score','model_score'],
45
44
  description: description,
46
- schema: {
45
+ inputSchema: z.object({
47
46
  'model': z.string(),
48
47
  'scenario': z.any(),
49
48
  'uflag': z.boolean()
50
- },
51
- required: ['model', 'scenario'],
49
+ }),
52
50
  handler: async (iparams) => {
53
51
  let params = {...iparams};
54
52
  let scenario = params.scenario;
@@ -87,3 +85,4 @@ Returns predictions, probabilities, scores merged with input data. Returns error
87
85
  }
88
86
 
89
87
  export default modelScore;
88
+
@@ -44,24 +44,22 @@ Returns rows array, total count, filtered_count, columns metadata. Empty array i
44
44
 
45
45
  let specs = {
46
46
  name: 'read-table',
47
- aliases: ['readTable','read table','read_table'],
48
47
  description: describe,
49
- schema: {
48
+ inputSchema: z.object({
50
49
  table: z.string(),
51
50
  lib: z.string(),
52
51
  start: z.number(),
53
- limit: z.number().default(10),
54
- server: z.string().default('cas'),
55
- where: z.string().default(''),
56
- format: z.boolean().default(true)
52
+ limit: z.number(),
53
+ server: z.string(),
54
+ where: z.string(),
55
+ format: z.boolean()
57
56
 
58
- },
59
- required: ['table', 'lib'],
60
- handler: async (params) => {
57
+ }),
58
+ handler: async (params) => {
61
59
  let r = await _readTable(params,'query');
62
60
  return r;
63
61
  }
64
62
  }
65
63
  return specs;
66
64
  }
67
- export default readTable;
65
+ export default readTable;
@@ -41,21 +41,19 @@ Log output and CAS results. If output table specified, returned as markdown tabl
41
41
  `;
42
42
 
43
43
  let spec = {
44
- name: 'run-sas-program',
45
- aliases: ['Program','run program'],
44
+ name: 'run-cas-program',
46
45
  description: description,
47
- schema: {
46
+ inputSchema: z.object({
48
47
  src: z.string(),
49
- scenario: z.any().default(''),
50
- output: z.string().default(''),
51
- folder: z.string().default(''),
52
- limit: z.number().default(100)
48
+ scenario: z.any(),
49
+ output: z.string(),
50
+ folder: z.string(),
51
+ limit: z.number()
53
52
  },
54
53
  // NOTE: Previously 'required' incorrectly listed 'program' which does not
55
54
  // exist in the schema. This prevented execution in some orchestrators that
56
55
  // enforce required parameter presence, causing only descriptions to appear.
57
56
  // Corrected to 'src'.
58
- required: ['src'],
59
57
  handler: async (params) => {
60
58
  let {src, folder, scenario, _appContext} = params;
61
59
  // figure out src
@@ -96,3 +94,4 @@ Log output and CAS results. If output table specified, returned as markdown tabl
96
94
  }
97
95
 
98
96
  export default runCasProgram;
97
+
@@ -37,14 +37,12 @@ Returns log output, listings, tables from job. Error if job not found.
37
37
  `;
38
38
 
39
39
  let spec = {
40
- aliases: ['run job', 'run-job', 'runjob'],
41
40
  name: 'run-job',
42
41
  description: description,
43
- schema: {
42
+ inputSchema: z.object({
44
43
  name: z.string(),
45
- scenario: z.any().default(''),
46
- },
47
- required: ['name'],
44
+ scenario: z.any(),
45
+ }),
48
46
  handler: async (params) => {
49
47
  let scenario = params.scenario;
50
48
  let scenarioObj = {};
@@ -80,3 +78,4 @@ Returns log output, listings, tables from job. Error if job not found.
80
78
  }
81
79
 
82
80
  export default runJob;
81
+
@@ -38,14 +38,12 @@ Returns log output, listings, tables from jobdef. Error if jobdef not found.
38
38
  `;
39
39
 
40
40
  let spec = {
41
- name: 'run-jobdef',
42
- aliases: ['jobDef','jobdef','jobdef'],
41
+ name: 'run-jobdef',
43
42
  description: description,
44
- schema: {
43
+ inputSchema: z.object({
45
44
  name: z.string(),
46
- scenario: z.any().default(''),
47
- },
48
- required: ['name'],
45
+ scenario: z.any()
46
+ }),
49
47
  handler: async (params) => {
50
48
  let scenario = params.scenario;
51
49
  let scenarioObj = {};
@@ -81,3 +79,4 @@ Returns log output, listings, tables from jobdef. Error if jobdef not found.
81
79
  }
82
80
 
83
81
  export default runJobdef;
82
+
@@ -38,14 +38,12 @@ Returns log, ods, tables created by macro. Auto-converts "x=1, y=2" to "%let x=1
38
38
 
39
39
  let spec = {
40
40
  name: 'run-macro',
41
- aliases: ['runMacro','run macro','run_macro'],
42
41
  description: description,
43
42
 
44
- schema: {
43
+ inputSchema: z.object({
45
44
  macro: z.string(),
46
45
  scenario: z.string()
47
- },
48
- required: ['macro'],
46
+ }),
49
47
  handler: async (params) => {
50
48
  const scenarioRaw = (params.scenario || '').trim();
51
49
  let setup = '';
@@ -80,3 +78,4 @@ Returns log, ods, tables created by macro. Auto-converts "x=1, y=2" to "%let x=1
80
78
  }
81
79
 
82
80
  export default runMacro;
81
+
@@ -41,21 +41,19 @@ Returns log, ods, tables array, data (if output specified). Error if execution f
41
41
  `;
42
42
 
43
43
  let spec = {
44
- name: 'run-sas-program',
45
- aliases: ['Program','run program'],
44
+ name: 'run-program',
46
45
  description: description,
47
- schema: {
46
+ inputSchema: z.object({
48
47
  src: z.string(),
49
- scenario: z.any().default(''),
50
- output: z.string().default(''),
51
- folder: z.string().default(''),
52
- limit: z.number().default(100)
53
- },
48
+ scenario: z.any(),
49
+ output: z.string(),
50
+ folder: z.string(),
51
+ limit: z.number()
52
+ }),
54
53
  // NOTE: Previously 'required' incorrectly listed 'program' which does not
55
54
  // exist in the schema. This prevented execution in some orchestrators that
56
55
  // enforce required parameter presence, causing only descriptions to appear.
57
56
  // Corrected to 'src'.
58
- required: ['src'],
59
57
  handler: async (params) => {
60
58
  let {src, folder, scenario, _appContext} = params;
61
59
  // figure out src
@@ -96,3 +94,4 @@ Returns log, ods, tables array, data (if output specified). Error if execution f
96
94
  }
97
95
 
98
96
  export default runProgram;
97
+
@@ -40,17 +40,15 @@ Returns rows array, columns metadata, log. Returns error if SQL invalid or table
40
40
 
41
41
 
42
42
  let spec = {
43
- name: 'sas-query',
44
- aliases: ['sasQuery','sas query','sas_query'],
45
- description: description,
46
- schema: {
43
+ name: 'sas-query',
44
+ description: description,
45
+ inputSchema: z.object({
47
46
  query: z.string(),
48
47
  table: z.string(),
49
- sql: z.string().optional(),
50
- job: z.string().default('program')
51
- },
52
- required: ['query', 'table'],
53
- handler: async (params) => {
48
+ sql: z.string(),
49
+ job: z.string()
50
+ }),
51
+ handler: async (params) => {
54
52
  let {table,query, sql, job, _appContext} = params;
55
53
  let sqlinput = (sql == null) ? ' ' : sql.replaceAll(';', ' ').replaceAll('\n', ' ').replaceAll('\r', ' ');
56
54
 
@@ -77,3 +75,4 @@ Returns rows array, columns metadata, log. Returns error if SQL invalid or table
77
75
  return spec;
78
76
  }
79
77
  export default sasQuery;
78
+
@@ -108,13 +108,12 @@ async function sasQueryTemplate(uparams) {
108
108
  name: toolname,
109
109
  description: description,
110
110
 
111
- schema: {
111
+ inputSchema: z.object({
112
112
  query: z.string(),
113
113
  table: z.string().default(uTable),
114
- sql: z.string().optional()
115
- },
116
- required: ['query', 'table'],
117
- handler: async (params) => {
114
+ sql: z.string()
115
+ }),
116
+ handler: async (params) => {
118
117
 
119
118
 
120
119
  let { table, query, sql, _appContext} = params;
@@ -102,14 +102,13 @@ async function sasQueryTemplate2(uparams) {
102
102
  name: toolname,
103
103
  description: description,
104
104
 
105
- schema: {
105
+ inputSchema: z.object({
106
106
  query: z.string(),
107
107
  table: z.string().default(uTable),
108
- sql: z.string().optional(),
108
+ sql: z.string(),
109
109
 
110
- },
111
- required: ['query', 'table'],
112
- handler: async (params) => {
110
+ }),
111
+ handler: async (params) => {
113
112
 
114
113
  let { table, query, sql } = params;
115
114
  let sqlinput = (sql == null) ? ' ' : sql.replaceAll(';', ' ').replaceAll('\n', ' ').replaceAll('\r', ' ');
@@ -33,12 +33,10 @@ Examples
33
33
 
34
34
  let spec = {
35
35
  name: 'scr-info',
36
- aliases: ['scrInfo','scr info','scr_info'],
37
36
  description: description,
38
- schema: {
37
+ inputSchema: z.object({
39
38
  url: z.string(),
40
- },
41
- required: ['url'],
39
+ }),
42
40
  handler: async (params) => {
43
41
  let {url, _appContext} = params;
44
42
  if (url === null) {
@@ -36,13 +36,11 @@ Examples
36
36
 
37
37
  let spec = {
38
38
  name: 'scr-score',
39
- aliases: ['scrScore','scr score','scr_score'],
40
39
  description: description,
41
- schema: {
40
+ inputSchema: z.object({
42
41
  url: z.string(),
43
42
  scenario: z.any()
44
- },
45
- required: ['url'],
43
+ }),
46
44
  handler: async (params) => {
47
45
  let {url, scenario,_appContext} = params;
48
46
 
@@ -30,16 +30,15 @@ function searchAssets(_appContext) {
30
30
  `;
31
31
 
32
32
  let specs = {
33
- name: 'searchAssets',
33
+ name: 'search-assets',
34
34
  description: description,
35
- schema: {
35
+ inputSchema: z.object({
36
36
  searchstring: z.string(),
37
37
  assetType: z.string(),
38
- start: z.number().default(0),
39
- limit: z.number().default(10),
38
+ start: z.number(),
39
+ limit: z.number()
40
40
 
41
- },
42
- required: ['assetType'],
41
+ }),
43
42
  handler: async (params) => {
44
43
  log('searchAssets params', params);
45
44
  return await _catalogSearch(params, 'search');
@@ -37,15 +37,13 @@ Returns current or updated context values {cas, sas}. Error if server not found
37
37
  `;
38
38
 
39
39
  let spec = {
40
- name: 'set-context',
41
- aliases: ['setContext','set context','set_context'],
42
- description: description,
43
- schema: {
44
- cas: z.string().optional(),
45
- sas: z.string().optional()
46
- },
47
-
48
- handler: async (params) => {
40
+ name: 'set-context',
41
+ description: description,
42
+ inputSchema: z.object({
43
+ cas: z.string(),
44
+ sas: z.string()
45
+ }),
46
+ handler: async (params) => {
49
47
 
50
48
  let {cas, sas} = params;
51
49
  if (typeof cas === 'string' && cas.trim().length > 0) {
@@ -64,3 +62,4 @@ Returns current or updated context values {cas, sas}. Error if server not found
64
62
  return spec;
65
63
  }
66
64
  export default setContext;
65
+
@@ -33,11 +33,10 @@ function superstat(_appContext) {
33
33
  let spec = {
34
34
  name: 'superstat',
35
35
  description: desc,
36
- schema: {
36
+ inputSchema: z.object({
37
37
  a: z.number(),
38
38
  b: z.number()
39
- },
40
- required: ['a', 'b'],
39
+ }),
41
40
  handler: async (params) => {
42
41
  let src = `
43
42
  ods html style=barrettsblue;
@@ -40,15 +40,13 @@ Returns columns array (name, type, label, format, length) and tableInfo (rowCoun
40
40
 
41
41
  let specs = {
42
42
  name: 'table-info',
43
- aliases: ['tableInfo','table info','table_info'],
44
43
  description: describe,
45
- schema: {
44
+ inputSchema: z.object({
46
45
  table: z.string(),
47
46
  lib: z.string(),
48
47
  server: z.string()
49
- },
50
- required: ['table', 'lib'],
51
- handler: async (params) => {
48
+ }),
49
+ handler: async (params) => {
52
50
  params.describe = true;
53
51
  let r = await _tableInfo(params);
54
52
  return r;
@@ -56,4 +54,4 @@ Returns columns array (name, type, label, format, length) and tableInfo (rowCoun
56
54
  }
57
55
  return specs;
58
56
  }
59
- export default tableInfo;
57
+ export default tableInfo;