@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
package/cli.js CHANGED
@@ -21,39 +21,247 @@ import { randomUUID } from 'node:crypto';
21
21
  import readCerts from './src/toolHelpers/readCerts.js';
22
22
 
23
23
  import { fileURLToPath } from 'url';
24
- import { dirname } from 'path';
24
+ import { dirname, join } from 'path';
25
+ import os from 'os';
26
+ import setupSkills from './src/setupSkills.js';
27
+ import { parseArgs } from "node:util";
25
28
 
26
29
  import NodeCache from 'node-cache';
30
+ import { be } from 'zod/locales';
27
31
  //import getOpts from './src/toolHelpers/getOpts.js';
28
32
 
29
33
  const __dirname = dirname(fileURLToPath(import.meta.url));
30
34
 
31
35
  let pkg = fs.readFileSync(__dirname + '/package.json', 'utf8');
32
36
 
33
- if (process.env.ENVFILE === 'FALSE') {
34
- //use this when using remote mcp server and no .env file is desired
35
- console.error('[Note]: Skipping .env file as ENVFILE is set to FALSE...');
36
- } else {
37
+ // Parse command line arguments
38
+ const args = parseArgs({
39
+ options: {
40
+ port: {
41
+ type: 'string',
42
+ short: 'p',
43
+ description: 'Port to run the server on'
44
+ },
45
+ mcptype: {
46
+ type: 'string',
47
+ short: 'm',
48
+ description: 'MCP server type (http or stdio)'
49
+ },
50
+ https: {
51
+ type: 'boolean',
52
+ description: 'Use HTTPS for the server (default: FALSE)'
53
+ },
54
+ 'skills-folder': {
55
+ type: 'string',
56
+ short: 'f',
57
+ description: 'Skills folder name'
58
+ },
59
+
60
+ viya: {
61
+ type: 'string',
62
+ short: 'v',
63
+ description: 'Viya server URL'
64
+ },
65
+ mcphost: {
66
+ type: 'string',
67
+ short: 'm',
68
+ description: 'MCP server host (default: http://localhost:8080)'
69
+ },
70
+ authflow: {
71
+ type: 'string',
72
+ short: 'a',
73
+ description: 'Authentication flow (sascli, code, token, oauth, oauth,oauthclient)'
74
+ },
75
+ clientid: {
76
+ type: 'string',
77
+ short: 'c',
78
+ description: 'Client ID for authentication'
79
+ },
80
+ clientsecret: {
81
+ type: 'string',
82
+ short: 's',
83
+ description: 'Client Secret for authentication'
84
+ },
85
+ profile: {
86
+ type: 'string',
87
+ description: 'SAS CLI profile name'
88
+ },
89
+ config: {
90
+ type: 'string',
91
+ description: 'SAS CLI config directory'
92
+ },
93
+ casserver: {
94
+ type: 'string',
95
+ description: 'CAS server name (default: cas-shared-default)'
96
+ },
97
+ computecontext: {
98
+ type: 'string',
99
+ description: 'Compute session name or context (default: SAS Job Execution compute context)'
100
+ },
101
+ env: {
102
+ type: 'string',
103
+ short: 'e',
104
+ description: 'Environment file path (default: .env in current working directory)'
105
+ },
106
+ client: {
107
+ type: 'string',
108
+ description: 'MCP client name (github, claude...). Defaults to \'github\''
109
+ },
110
+ help: {
111
+ type: 'boolean',
112
+ short: 'h',
113
+ description: 'Show help message'
114
+ },
115
+ version: {
116
+ type: 'boolean',
117
+ description: 'Show version'
118
+ },
119
+
120
+ },
121
+ strict: false,
122
+ allowPositionals: false
123
+ });
124
+
125
+ // Handle help flag
126
+ if (args.values.help) {
127
+ console.error(`
128
+ SAS Viya Scoring Expert Agent - Version: ${JSON.parse(pkg).version}
129
+
130
+ Usage: npx @sassoftware/sas-score-mcp-serverjs@dev [options]
131
+
132
+ Options:
133
+ Minimal options:
134
+ -v, --viya <url> Viya server URL
135
+ -c, --clientid <id> Client ID for oauth authentication(pkce preferred. default: vscodemcp)
136
+
137
+ MCP server options:
138
+ -t, --mcptype <type> MCP server type: http or stdio (default: http)
139
+ -m, --mcphost <host> MCP server host - can be remote URL - (default: http://localhost:8080)
140
+ --client <name> MCP client name (github, claude...). Defaults to 'github'.Use to install skills
141
+ Authentication options:
142
+ -a, --authflow <flow> Authentication flow: oauth, oauthclient, sascli, code, token(default oauth)
143
+ -s, --clientsecret <secret> Client Secret for authentication(if necessary). See clientid option as well.
144
+ --profile <name> SAS CLI profile name for sascli flow (default: Default)
145
+ --config <path> SAS CLI config directory for sascli flow (default: user home directory)
146
+
147
+ Other options:
148
+ -p, --port <port> Port to run the server on (default: 8080)
149
+ --https Use HTTPS for the server (default: false)
150
+ --casserver <name> CAS server name (default: cas-shared-default)
151
+ --computecontext <name> Compute session name or context (default: SAS Job Execution compute context)
152
+
153
+ -e, --envfile <path> Environment file path
154
+ -h, --help Show this help message
155
+ --version Show version
156
+
157
+
158
+ Environment Variables:
159
+ Use .env file or set environment variables for configuration.
160
+ A alternative to cmd line arguments, and in some cases required for sensitive information like client secrets.
161
+ See README.md for more information.
162
+ `);
163
+ process.exit(0);
164
+ }
165
+
166
+ // read env file and then override with command line arguments
167
+ if (args.values.env) {
37
168
  console.error('Working Directory', process.cwd());
38
- let envf = process.cwd() + '\\.env';
169
+ let envf = process.cwd() + '\\' + args.values.env;
39
170
  //__dirname + '\\.env';
40
- console.error('Env file:', envf);
171
+ console.error('Env file:', envf);
41
172
  if (fs.existsSync(envf)) {
42
- console.error(`Loading environment variables rom ${envf}...`);
43
- let e = iconfig(envf); // avoid dotenv since it writes to console.log
173
+ console.error(`Loading environment variables from ${envf}...`);
174
+ let e = iconfig(envf); // avoid dotenv since it writes to console.error
44
175
  console.error('[Note]: Environment variables loaded from .env file...');
45
176
  console.error('Loaded env variables:', e);
46
177
  // dotenvExpand.expand(e);
47
178
  } else {
48
179
  console.error(
49
- '[Note]: No .env file found, Using default environment variables...'
180
+ '[Note]: No env file found, Using default environment variables...'
50
181
  );
51
182
  }
52
183
  }
184
+ // Apply command line arguments to override environment variables
185
+
186
+ process.env.PORT = process.env.PORT || '8080';
187
+ process.env.HTTPS = (args.values.https) ? 'TRUE' : 'FALSE';
188
+ process.env.MCPTYPE = args.values.mcptype || process.env.MCPTYPE || 'http';
189
+ process.env.MCPHOST = args.values.mcphost || process.env.MCPHOST || 'http://localhost:8080';
190
+ process.env.AUTHFLOW = args.values.authflow || process.env.AUTHFLOW || 'oauth';
191
+ process.env.MCPCLIENT = args.values.client || process.env.MCPCLIENT || 'github';
192
+ process.env.VIYA_SERVER = args.values.viya || process.env.VIYA_SERVER || null;
193
+ process.env.CLIENTID = args.values.clientid || process.env.CLIENTID || 'vscodemcp';
194
+ process.env.CLIENTSECRET = args.values.clientsecret || process.env.CLIENTSECRET || null;
195
+ process.env.SAS_CLI_PROFILE = args.values.profile || process.env.SAS_CLI_PROFILE || 'Default';
196
+ process.env.SAS_CLI_CONFIG = args.values.config || process.env.SAS_CLI_CONFIG || process.env.HOME; // default to user home directory
197
+ process.env.CASSERVER = args.values.casserver || process.env.CASSERVER || 'cas-shared-default';
198
+ process.env.COMPUTECONTEXT = args.values.computecontext || process.env.COMPUTECONTEXT || 'SAS Job Execution compute context';
199
+ process.env.APPHOST = 'localhost';
200
+ process.env.CLIENT = args.values.client || process.env.CLIENT || 'github';
201
+
202
+
203
+
204
+ process.env.SAMESITE = 'Lax,secure';
205
+ process.env.APPHOST = '0.0.0.0';
206
+ process.env.APPNAME = 'sas-score-mcp-serverjs';
207
+
208
+ // Handle version flag
209
+ if (args.values.version) {
210
+ let pkgJson = JSON.parse(pkg);
211
+ console.error(pkgJson.version);
212
+ process.exit(0);
213
+ }
214
+
215
+ // copy the skills to directory based on the client name, so that different MCP clients can have different sets of skills if needed
216
+ // the -client indicates the current mcp client
217
+ console.error(`[Note] MCP client set to: ${process.env.CLIENT}`);
218
+
219
+
220
+ let client = process.env.CLIENT;
221
+ if (client !== 'none') {
222
+ console.error(`[Note] Setting up skills for client: ${client}...`);
223
+ setupSkills(client);
224
+ } else {
225
+ console.error(`[Note] No client specified, skipping skill setup...`);
226
+ }
227
+
228
+
229
+ /*
230
+ if (client !== 'none') {
231
+ let destdir = '.' + client;
232
+ let skillsDest = join(os.homedir(), destdir,'skills');
233
+ const skillsSrc = join(__dirname, '.github');
234
+ if (!fs.existsSync(skillsSrc)) {
235
+ console.error('No skills directory found in this package.');
236
+ process.exit(1);
237
+ }
238
+ fs.mkdirSync(skillsDest, { recursive: true });
239
+
240
+ const skills = fs.readdirSync(skillsSrc, { withFileTypes: true })
241
+ .filter(d => d.isDirectory())
242
+ .map(d => d.name);
243
+
244
+ if (skills.length === 0) {
245
+ console.error('[Note]No skills found to install.');
246
+ } else {
247
+ console.error(`Installing ${skills.length} skill(s) to ${skillsDest}...`);
248
+ for (const skill of skills) {
249
+ const src = join(skillsSrc, skill);
250
+ const dest = join(skillsDest, skill);
251
+ fs.cpSync(src, dest, { recursive: true });
252
+ console.error(` installed: ${skill}`);
253
+ }
254
+ console.error(`\n installed in cli. ${client}`);
255
+ console.error(`\n${skills.length} skill(s) installed to ${skillsDest}`);
256
+ console.error('[Note] Skills are ready for use.');
257
+
258
+ }
259
+ }
260
+ */
261
+
262
+
263
+
53
264
 
54
- if (process.env.APPHOST == null) {
55
- process.env.APPHOST = 'localhost';
56
- }
57
265
  /********************************* */
58
266
  const BRAND = 'sas-score'
59
267
  /********************************* */
@@ -62,16 +270,16 @@ let version = pkgJson.version;
62
270
  let mcpType = process.env.MCPTYPE || 'http';
63
271
  console.error(
64
272
  `\nStarting MCP ServerJS - Version: ${pkgJson.version} - ${new Date().toISOString()}\n
65
- brand: ${process.env.BRAND || BRAND}\n
66
- mcpType: ${mcpType}\n
67
- viyaServer: ${process.env.VIYA_SERVER}\n`
273
+ brand: ${process.env.BRAND || BRAND}
274
+ mcpType: ${mcpType}
275
+ viyaServer: ${process.env.VIYA_SERVER}`
68
276
  );
69
277
  // session sessionCache
70
278
  // For more robust caching consider products like Redis
71
279
  // and storage provided by cloud providers
72
- console.error(process.env.COMPUTECONTEXT);
280
+
73
281
  debugger;
74
- let sessionCache = new NodeCache({ stdTTL: 60*60, checkperiod: 2 * 60, useClones: false });
282
+ let sessionCache = new NodeCache({ stdTTL: 24 * 60 * 60, checkperiod: 2 * 60, useClones: false });
75
283
 
76
284
  //
77
285
  // Load environment variables from .env file if present
@@ -79,35 +287,25 @@ let sessionCache = new NodeCache({ stdTTL: 60*60, checkperiod: 2 * 60, useClones
79
287
  // stdio: set the env in the mcp config
80
288
  // http: use dotenv-cli to load env before starting the mcp server
81
289
 
82
-
83
- // need to tell core what transport to use(http or stdio)
84
-
85
- // subclasses for sasQuery tool (special use case)
86
- // to be replaced by the planned adding external tool definition capability
87
-
88
- let subclassJson = [];
89
- if (process.env.SUBCLASS != null) {
90
- console.error(`Using subclass: ${process.env.SUBCLASS}`);
91
- let subclass = process.env.SUBCLASS;
92
- if (fs.existsSync(subclass)) {
93
- console.error(`Loading subclass information from ${subclass}...`);
94
- let s = fs.readFileSync(subclass, 'utf8');
95
- subclassJson = JSON.parse(s);
96
- console.error(`Loaded subclass: ${JSON.stringify(subclassJson, null, 2)}`);
97
- }
98
- }
99
290
  // setup base appEnv
100
291
  // for stdio this is the _appContext
101
292
  // for http each session a copy of this as appEnvTemplate is created in corehttp
102
293
 
103
- // backward compability variables
104
- let clientID = process.env.CLIENTID || process.env.CLIENTIDPW || null;
105
- let clientSecret = process.env.CLIENTSECRET || process.env.CLIENTSECRETPW || null;
106
294
  let https = process.env.HTTPS != null ? process.env.HTTPS.toUpperCase() : "FALSE";
295
+ let authExternal = false;
296
+ let authFlow = process.env.AUTHFLOW;
297
+ let mcpHost = process.env.MCPHOST;
298
+
299
+ if (authFlow === 'oauth' || authFlow === 'oauthclient') {
300
+ authFlow = 'bearer';
301
+ authExternal = (authFlow === 'oauthclient') ? true : false;
302
+ }
107
303
  let autoLogon = process.env.AUTOLOGON != null ? process.env.AUTOLOGON.toUpperCase() : "FALSE";
108
304
  const appEnvBase = {
109
305
  version: version,
110
- mcpType: mcpType,
306
+ mcpType: mcpType,
307
+ mcpClient: process.env.MCPCLIENT || 'github',
308
+ mcpHost: (process.env.MCPHOST == null) ? 'http://localhost:8080' : process.env.MCPHOST,
111
309
  brand: (process.env.BRAND == null) ? BRAND : process.env.BRAND,
112
310
  HTTPS: https,
113
311
  SAS_CLI_PROFILE: process.env.SAS_CLI_PROFILE || 'Default',
@@ -115,27 +313,27 @@ const appEnvBase = {
115
313
  SSLCERT: process.env.SSLCERT || null,
116
314
  VIYACERT: process.env.VIYACERT || null,
117
315
 
118
- AUTHFLOW: process.env.AUTHFLOW || 'sascli',
316
+ AUTHFLOW: authFlow,
317
+ AUTHEXTERNAL: authExternal,
318
+ BEARERTOKEN: null,
119
319
  AUTOLOGON: autoLogon,
120
320
  VIYA_SERVER: process.env.VIYA_SERVER,
121
321
  PORT: process.env.PORT || 8080,
122
322
  USERNAME: process.env.USERNAME || null,
123
323
  PASSWORD: process.env.PASSWORD || null,
124
- CLIENTID: clientID,
125
- CLIENTSECRET: clientSecret,
324
+ CLIENTID: process.env.CLIENTID || null,
325
+ CLIENTSECRET: process.env.CLIENTSECRET || null,
126
326
  PKCE: process.env.PKCE || null,
127
327
 
128
328
  TOKEN: process.env.TOKEN || null,
129
329
  REFRESH_TOKEN: process.env.REFRESH_TOKEN || null,
130
330
  TOKENFILE: process.env.TOKENFILE || null,
131
331
  TLS_CREATE: process.env.TLS_CREATE || null,
132
- SUBCLASS: process.env.SUBCLASS || null,
133
- subclassJson: subclassJson,
134
- // future use for controlling tool list using env variable
135
- toolsets:
136
- process.env.TOOLSETS != null
137
- ? process.env.TOOLSETS.split(',')
138
- : ['default'],
332
+ CASSERVER: process.env.CASSERVER,
333
+ COMPUTECONTEXT: process.env.COMPUTECONTEXT,
334
+
335
+ // command line arguments
336
+ cliArgs: args.values,
139
337
  // user defined tools
140
338
  //runtime variables
141
339
  tokenRefresh: process.env.TOKENREFRESH === 'FALSE' ? false : true,
@@ -153,7 +351,8 @@ const appEnvBase = {
153
351
  tlsOpts: null,
154
352
  oauthInfo: null,
155
353
  contexts: {
156
- AUTHFLOW: process.env.AUTHFLOW || 'sascli',
354
+ AUTHFLOW: authFlow,
355
+ AUTHEXTERNAL: authExternal,
157
356
  host: process.env.VIYA_SERVER,
158
357
  APPHOST: process.env.APPHOST || 'localhost',
159
358
  APPNAME: process.env.APPNAME || 'sas-score-mcp-serverjs',
@@ -162,8 +361,8 @@ const appEnvBase = {
162
361
  store: null, /* for restaf users */
163
362
  storeConfig: {},
164
363
  oauthInfo: null,
165
- CLIENTID: clientID,
166
- CLIENTSECRET: clientSecret,
364
+ CLIENTID: process.env.CLIENTID || null,
365
+ CLIENTSECRET: process.env.CLIENTSECRET || null,
167
366
  pkce: process.env.PKCE || null,
168
367
  casSession: null, /* restaf cas session object */
169
368
  computeSession: null, /* restaf compute session object */
@@ -178,15 +377,14 @@ const appEnvBase = {
178
377
  }
179
378
  };
180
379
 
181
- process.env.APPPORT=appEnvBase.PORT;
380
+ process.env.APPPORT = appEnvBase.PORT;
381
+ let useHapi = process.env.USEHAPI === 'TRUE' ? true : false;
382
+ appEnvBase.useHapi = useHapi;
182
383
 
183
384
  // setup TLS options for viya calls
184
- console.error('[Note]Viya SSL dir set to: ' + appEnvBase.VIYACERT);
185
385
  appEnvBase.contexts.viyaCert = readCerts(appEnvBase.VIYACERT); /* appEnvBase.contexts.viyaCert is set here */
186
386
 
187
387
  // setup TLS options for app server (expressMcpServer or hapiMcpServer)
188
-
189
- console.error('[Note]App SSL dir set to: ' + appEnvBase.SSLCERT);
190
388
  appEnvBase.tlsOpts = readCerts(appEnvBase.SSLCERT);
191
389
  appEnvBase.contexts.appCert = appEnvBase.tlsOpts; /* just for completeness */
192
390
 
@@ -200,7 +398,7 @@ if (appEnvBase.TOKENFILE != null) {
200
398
  console.error(`[Note]Loading token from file: ${appEnvBase.TOKENFILE}...`);
201
399
  appEnvBase.TOKEN = fs.readFileSync(appEnvBase.TOKENFILE, { encoding: 'utf8' });
202
400
  appEnvBase.AUTHFLOW = 'token';
203
- appEnvBase.appContexts.logonPayload = {
401
+ appEnvBase.contexts.logonPayload = {
204
402
  host: appEnvBase.VIYA_SERVER,
205
403
  authType: 'server',
206
404
  token: appEnvBase.TOKEN,
@@ -213,10 +411,6 @@ if (appEnvBase.TOKENFILE != null) {
213
411
  }
214
412
 
215
413
 
216
-
217
- // if authflow is cli or code, postpone getting logonPayload until needed
218
-
219
-
220
414
  // setup mcpServer (both http and stdio use this)
221
415
  // this is singleton - best practices recommend this
222
416
 
@@ -227,17 +421,64 @@ let appEnvTemplate = Object.assign({}, appEnvBase);
227
421
 
228
422
  sessionCache.set('appEnvTemplate', appEnvTemplate);
229
423
 
230
- let transports = {'dummy': null};
424
+ // prime transport cache
425
+ let transports = {
426
+ "dummy": null
427
+ };
231
428
  sessionCache.set('transports', transports);
429
+ let tokenlist = {
430
+ dummy: null
431
+ }
432
+ sessionCache.set('tokenlist', tokenlist);
232
433
 
233
434
  // set this for stdio transport use
234
435
  // dummy sessionId for use in the tools
235
- let useHapi = (process.env.USEHAPI === 'TRUE') ? true : false;
236
- console.error('[Note] appEnvBase is', JSON.stringify(appEnvBase, null,2));
436
+
437
+ // 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
438
+ let sessionId = randomUUID();
439
+ sessionCache.set(sessionId, appEnvBase);
440
+ sessionCache.set('currentId', sessionId);
441
+
442
+ console.error('===================================================================');
443
+ console.error(`MCP ServerJS - Version: ${pkgJson.version} - ${new Date().toISOString()}`);
444
+ console.error(`
445
+ Usage: sas-score-mcp-serverjs [options]
446
+
447
+ Options:
448
+ Minimal options:
449
+ VIYA_SERVER ${appEnvBase.VIYA_SERVER}
450
+ CLIENTID ${appEnvBase.CLIENTID}
451
+
452
+ MCP server options:
453
+ MCPTYPE ${appEnvBase.mcpType}
454
+ MCPHOST ${appEnvBase.mcpHost}
455
+ PORT ${appEnvBase.PORT}
456
+ HTTPS ${appEnvBase.contexts.HTTPS}
457
+ CLIENT ${appEnvBase.mcpClient}
458
+
459
+ Authentication options:
460
+ AUTHFLOW ${process.env.AUTHFLOW}
461
+ CLIENTSECRET ${appEnvBase.CLIENTSECRET}
462
+ PROFILE ${appEnvBase.SAS_CLI_PROFILE}
463
+ CONFIG ${appEnvBase.SAS_CLI_CONFIG}
464
+
465
+ Other options:
466
+ CASSERVER ${appEnvBase.CASSERVER}
467
+ COMPUTECONTEXT ${appEnvBase.COMPUTECONTEXT}
468
+ }
469
+
470
+ `);
471
+
472
+ console.error('===================================================================');
473
+ console.error(`
474
+ [Note] The SAS Viya Scoring Expert agent has been installed successfully.
475
+ Depending on the client you are using, the agent might not be active
476
+ If the agent does not appear in the agent dropdown list your options are:
477
+ - use the /subagent command
478
+ - exit this app and issue the npx command to restart the server
479
+ `);
480
+
237
481
  if (mcpType === 'stdio') {
238
- let sessionId = randomUUID();
239
- sessionCache.set('currentId', sessionId);
240
- sessionCache.set(sessionId, appEnvBase);
241
482
  console.error('[Note] Setting up stdio transport with sessionId:', sessionId);
242
483
  console.error('[Note] Used in setting up tools and some persistence(not all).');
243
484
  await coreSSE(mcpServer);
@@ -245,12 +486,12 @@ if (mcpType === 'stdio') {
245
486
  } else {
246
487
  console.error('[Note] Starting HTTP MCP server...');
247
488
  if (useHapi === true) {
248
- process.env.AUTHFLOW = null;;
489
+ process.env.AUTHTYPE = null;
249
490
  await hapiMcpServer(mcpServer, sessionCache, appEnvBase);
250
491
  console.error('[Note] Using HAPI HTTP server...')
251
492
  } else {
252
493
  await expressMcpServer(mcpServer, sessionCache, appEnvBase);
253
- console.error('[Note] MCP HTTP server started on port ' + appEnvBase.PORT);
494
+ console.error('[Note] MCP HTTP express server started on port ' + appEnvBase.PORT);
254
495
  }
255
496
  }
256
497
 
@@ -273,7 +514,7 @@ function iconfig(envFile) {
273
514
  });
274
515
  return envData;
275
516
  } catch (err) {
276
- console.log(err);
517
+ console.error(err);
277
518
  process.exit(0);
278
519
  }
279
520
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sassoftware/sas-score-mcp-serverjs",
3
- "version": "0.4.1",
3
+ "version": "1.0.1-0",
4
4
  "description": "A mcp server for SAS Viya",
5
5
  "author": "Deva Kumar <deva.kumar@sas.com>",
6
6
  "license": "Apache-2.0",
@@ -18,7 +18,8 @@
18
18
  "deploy": "bash ./deploy.sh",
19
19
  "push2acr": "cd docker && bash ./push2acr.sh",
20
20
  "bump": "npm version prerelease",
21
- "pub": "npm publish --tag dev --access public"
21
+ "pub": "npm publish --tag dev --access public",
22
+ "setup-skills": "node scripts/setup-skills.js"
22
23
  },
23
24
  "repository": "https://github.com/sassoftware/sas-score-mcp-serverjs",
24
25
  "keywords": [
@@ -39,10 +40,12 @@
39
40
  "src",
40
41
  "cli.js",
41
42
  "openApi.json",
42
- "openApi.yaml"
43
+ "openApi.yaml",
44
+ "scripts",
45
+ ".skills"
43
46
  ],
44
47
  "dependencies": {
45
- "@modelcontextprotocol/sdk": "^1.25.1",
48
+ "@modelcontextprotocol/sdk": "^1.29.0",
46
49
  "@sassoftware/restaf": "^5.6.0",
47
50
  "@sassoftware/restafedit": "^3.11.1-10",
48
51
  "@sassoftware/restaflib": "^5.6.0",
@@ -56,10 +59,8 @@
56
59
  "express-list-endpoints": "^7.1.1",
57
60
  "express-rate-limit": "^8.2.1",
58
61
  "helmet": "^8.1.0",
59
- "mcp-framework": "^0.2.16",
60
62
  "node-cache": "^5.1.2",
61
63
  "open": "^11.0.0",
62
- "puppeteer": "^24.34.0",
63
64
  "selfsigned": "^5.2.0",
64
65
  "undici": "^7.16.0",
65
66
  "uuid": "^13.0.0",
@@ -72,7 +73,6 @@
72
73
  "@babel/preset-env": "^7.28.5",
73
74
  "@types/debug": "^4.1.12",
74
75
  "@types/node": "^25.0.3",
75
- "npm-check-updates": "^19.2.0",
76
76
  "rimraf": "^6.1.2",
77
77
  "typescript": "^5.9.3"
78
78
  }