@sassoftware/sas-score-mcp-serverjs 0.4.1-7 → 1.0.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 (46) hide show
  1. package/.skills/agents/sas-viya-scoring-expert.md +58 -0
  2. package/.skills/copilot-instructions.md +147 -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/skills}/sas-read-strategy/SKILL.md +43 -30
  7. package/.skills/skills/sas-request-classifier/SKILL.md +69 -0
  8. package/{skills → .skills/skills}/sas-score-workflow/SKILL.md +49 -35
  9. package/cli.js +222 -140
  10. package/package.json +5 -4
  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 -220
  24. package/src/createMcpServer.js +10 -5
  25. package/src/expressMcpServer.js +54 -186
  26. package/src/oauthHandlers/authorize.js +46 -0
  27. package/src/oauthHandlers/baseUrl.js +8 -0
  28. package/src/oauthHandlers/callback.js +96 -0
  29. package/src/oauthHandlers/getMetadata.js +27 -0
  30. package/src/oauthHandlers/index.js +7 -0
  31. package/src/oauthHandlers/token.js +37 -0
  32. package/src/processHeaders.js +88 -0
  33. package/src/setupSkills.js +37 -0
  34. package/src/toolHelpers/_listLibrary.js +0 -1
  35. package/src/toolHelpers/getLogonPayload.js +5 -1
  36. package/src/toolHelpers/refreshToken.js +3 -2
  37. package/src/toolHelpers/refreshTokenOauth.js +3 -3
  38. package/src/toolSet/.claude/settings.local.json +2 -1
  39. package/src/toolSet/findModel.js +1 -1
  40. package/src/toolSet/findTable.js +3 -3
  41. package/src/toolSet/modelScore.js +2 -2
  42. package/src/toolSet/runJob.js +81 -81
  43. package/src/toolSet/runJobdef.js +82 -82
  44. package/skills/mcp-tool-description-optimizer/SKILL.md +0 -129
  45. package/skills/mcp-tool-description-optimizer/references/examples.md +0 -123
  46. package/skills/sas-read-and-score/SKILL.md +0 -91
package/cli.js CHANGED
@@ -23,9 +23,11 @@ import readCerts from './src/toolHelpers/readCerts.js';
23
23
  import { fileURLToPath } from 'url';
24
24
  import { dirname, join } from 'path';
25
25
  import os from 'os';
26
+ import setupSkills from './src/setupSkills.js';
26
27
  import { parseArgs } from "node:util";
27
28
 
28
29
  import NodeCache from 'node-cache';
30
+ import { be } from 'zod/locales';
29
31
  //import getOpts from './src/toolHelpers/getOpts.js';
30
32
 
31
33
  const __dirname = dirname(fileURLToPath(import.meta.url));
@@ -45,15 +47,40 @@ const args = parseArgs({
45
47
  short: 'm',
46
48
  description: 'MCP server type (http or stdio)'
47
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
+
48
60
  viya: {
49
61
  type: 'string',
50
62
  short: 'v',
51
63
  description: 'Viya server URL'
52
64
  },
65
+ mcphost: {
66
+ type: 'string',
67
+ short: 'm',
68
+ description: 'MCP server host (default: http://localhost:8080)'
69
+ },
53
70
  authflow: {
54
71
  type: 'string',
55
72
  short: 'a',
56
- description: 'Authentication flow (sascli, code, token)'
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'
57
84
  },
58
85
  profile: {
59
86
  type: 'string',
@@ -63,10 +90,22 @@ const args = parseArgs({
63
90
  type: 'string',
64
91
  description: 'SAS CLI config directory'
65
92
  },
66
- envfile: {
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: {
67
102
  type: 'string',
68
103
  short: 'e',
69
- description: 'Environment file path'
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\''
70
109
  },
71
110
  help: {
72
111
  type: 'boolean',
@@ -75,13 +114,9 @@ const args = parseArgs({
75
114
  },
76
115
  version: {
77
116
  type: 'boolean',
78
- short: 'v',
79
117
  description: 'Show version'
80
118
  },
81
- 'install-skills': {
82
- type: 'boolean',
83
- description: 'Install bundled skills to ~/.claude/skills/'
84
- }
119
+
85
120
  },
86
121
  strict: false,
87
122
  allowPositionals: false
@@ -90,27 +125,86 @@ const args = parseArgs({
90
125
  // Handle help flag
91
126
  if (args.values.help) {
92
127
  console.error(`
93
- Usage: sas-score-mcp-serverjs [options]
128
+ SAS Viya Scoring Expert Agent - Version: ${JSON.parse(pkg).version}
129
+
130
+ Usage: npx @sassoftware/sas-score-mcp-serverjs@dev [options]
94
131
 
95
132
  Options:
96
- -p, --port <port> Port to run the server on (default: 8080)
97
- -m, --mcptype <type> MCP server type: http or stdio (default: http)
98
- -v, --viya <url> Viya server URL
99
- -a, --authflow <flow> Authentication flow: sascli, code, or token
100
- --profile <name> SAS CLI profile name
101
- --config <path> SAS CLI config directory
102
- -e, --envfile <path> Environment file path
103
- -h, --help Show this help message
104
- --version Show version
105
- --install-skills Install bundled skills to ~/.claude/skills/
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
+
106
157
 
107
158
  Environment Variables:
108
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.
109
161
  See README.md for more information.
110
162
  `);
111
163
  process.exit(0);
112
164
  }
113
165
 
166
+ // read env file and then override with command line arguments
167
+ if (args.values.env) {
168
+ console.error('Working Directory', process.cwd());
169
+ let envf = process.cwd() + '\\' + args.values.env;
170
+ //__dirname + '\\.env';
171
+ console.error('Env file:', envf);
172
+ if (fs.existsSync(envf)) {
173
+ console.error(`Loading environment variables from ${envf}...`);
174
+ let e = iconfig(envf); // avoid dotenv since it writes to console.error
175
+ console.error('[Note]: Environment variables loaded from .env file...');
176
+ console.error('Loaded env variables:', e);
177
+ // dotenvExpand.expand(e);
178
+ } else {
179
+ console.error(
180
+ '[Note]: No env file found, Using default environment variables...'
181
+ );
182
+ }
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
+
114
208
  // Handle version flag
115
209
  if (args.values.version) {
116
210
  let pkgJson = JSON.parse(pkg);
@@ -118,16 +212,29 @@ if (args.values.version) {
118
212
  process.exit(0);
119
213
  }
120
214
 
121
- // Handle install-skills flag
122
- if (args.values['install-skills']) {
123
- const skillsSrc = join(__dirname, 'skills');
124
- const skillsDest = join(os.homedir(), '.claude', 'skills');
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
+ }
125
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');
126
234
  if (!fs.existsSync(skillsSrc)) {
127
235
  console.error('No skills directory found in this package.');
128
236
  process.exit(1);
129
237
  }
130
-
131
238
  fs.mkdirSync(skillsDest, { recursive: true });
132
239
 
133
240
  const skills = fs.readdirSync(skillsSrc, { withFileTypes: true })
@@ -135,77 +242,26 @@ if (args.values['install-skills']) {
135
242
  .map(d => d.name);
136
243
 
137
244
  if (skills.length === 0) {
138
- console.error('No skills found to install.');
139
- process.exit(1);
140
- }
141
-
142
- for (const skill of skills) {
143
- const src = join(skillsSrc, skill);
144
- const dest = join(skillsDest, skill);
145
- fs.cpSync(src, dest, { recursive: true });
146
- console.error(` installed: ${skill}`);
147
- }
148
-
149
- console.error(`\n${skills.length} skill(s) installed to ${skillsDest}`);
150
- console.error('Restart Claude Code to activate the new skills.');
151
- process.exit(0);
152
- }
153
-
154
- if (process.env.ENVFILE === 'FALSE') {
155
- //use this when using remote mcp server and no .env file is desired
156
- console.error('[Note]: Skipping .env file as ENVFILE is set to FALSE...');
157
- } else {
158
- console.error('Working Directory', process.cwd());
159
- let envf = process.env.ENVFILE || (process.cwd() + '\\.env');
160
- //__dirname + '\\.env';
161
- console.error('Env file:', envf);
162
- if (fs.existsSync(envf)) {
163
- console.error(`Loading environment variables from ${envf}...`);
164
- let e = iconfig(envf); // avoid dotenv since it writes to console.error
165
- console.error('[Note]: Environment variables loaded from .env file...');
166
- console.error('Loaded env variables:', e);
167
- // dotenvExpand.expand(e);
245
+ console.error('[Note]No skills found to install.');
168
246
  } else {
169
- console.error(
170
- '[Note]: No .env file found, Using default environment variables...'
171
- );
172
- }
173
- }
174
-
175
- // Apply command line arguments to override environment variables
176
- if (args.values.port) {
177
- process.env.PORT = args.values.port;
178
- console.error(`[Note] PORT set from command line: ${args.values.port}`);
179
- }
180
-
181
- if (args.values.mcptype) {
182
- process.env.MCPTYPE = args.values.mcptype;
183
- console.error(`[Note] MCPTYPE set from command line: ${args.values.mcptype}`);
184
- }
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.');
185
257
 
186
- if (args.values.viya) {
187
- process.env.VIYA_SERVER = args.values.viya;
188
- console.error(`[Note] VIYA_SERVER set from command line: ${args.values.viya}`);
258
+ }
189
259
  }
260
+ */
190
261
 
191
- if (args.values.authflow) {
192
- process.env.AUTHFLOW = args.values.authflow;
193
- console.error(`[Note] AUTHFLOW set from command line: ${args.values.authflow}`);
194
- }
195
262
 
196
- if (args.values.profile) {
197
- process.env.SAS_CLI_PROFILE = args.values.profile;
198
- console.error(`[Note] SAS_CLI_PROFILE set from command line: ${args.values.profile}`);
199
- }
200
263
 
201
- if (args.values.config) {
202
- process.env.SAS_CLI_CONFIG = args.values.config;
203
- console.error(`[Note] SAS_CLI_CONFIG set from command line: ${args.values.config}`);
204
- }
205
264
 
206
- if (process.env.APPHOST == null) {
207
- process.env.APPHOST = 'localhost';
208
- }
209
265
  /********************************* */
210
266
  const BRAND = 'sas-score'
211
267
  /********************************* */
@@ -214,16 +270,16 @@ let version = pkgJson.version;
214
270
  let mcpType = process.env.MCPTYPE || 'http';
215
271
  console.error(
216
272
  `\nStarting MCP ServerJS - Version: ${pkgJson.version} - ${new Date().toISOString()}\n
217
- brand: ${process.env.BRAND || BRAND}\n
218
- mcpType: ${mcpType}\n
219
- viyaServer: ${process.env.VIYA_SERVER}\n`
273
+ brand: ${process.env.BRAND || BRAND}
274
+ mcpType: ${mcpType}
275
+ viyaServer: ${process.env.VIYA_SERVER}`
220
276
  );
221
277
  // session sessionCache
222
278
  // For more robust caching consider products like Redis
223
279
  // and storage provided by cloud providers
224
- console.error(process.env.COMPUTECONTEXT);
280
+
225
281
  debugger;
226
- let sessionCache = new NodeCache({ stdTTL: 24 *60*60, checkperiod: 2 * 60, useClones: false });
282
+ let sessionCache = new NodeCache({ stdTTL: 24 * 60 * 60, checkperiod: 2 * 60, useClones: false });
227
283
 
228
284
  //
229
285
  // Load environment variables from .env file if present
@@ -231,35 +287,25 @@ let sessionCache = new NodeCache({ stdTTL: 24 *60*60, checkperiod: 2 * 60, useCl
231
287
  // stdio: set the env in the mcp config
232
288
  // http: use dotenv-cli to load env before starting the mcp server
233
289
 
234
-
235
- // need to tell core what transport to use(http or stdio)
236
-
237
- // subclasses for sasQuery tool (special use case)
238
- // to be replaced by the planned adding external tool definition capability
239
-
240
- let subclassJson = [];
241
- if (process.env.SUBCLASS != null) {
242
- console.error(`Using subclass: ${process.env.SUBCLASS}`);
243
- let subclass = process.env.SUBCLASS;
244
- if (fs.existsSync(subclass)) {
245
- console.error(`Loading subclass information from ${subclass}...`);
246
- let s = fs.readFileSync(subclass, 'utf8');
247
- subclassJson = JSON.parse(s);
248
- console.error(`Loaded subclass: ${JSON.stringify(subclassJson, null, 2)}`);
249
- }
250
- }
251
290
  // setup base appEnv
252
291
  // for stdio this is the _appContext
253
292
  // for http each session a copy of this as appEnvTemplate is created in corehttp
254
293
 
255
- // backward compability variables
256
- let clientID = process.env.CLIENTID || process.env.CLIENTIDPW || null;
257
- let clientSecret = process.env.CLIENTSECRET || process.env.CLIENTSECRETPW || null;
258
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
+ }
259
303
  let autoLogon = process.env.AUTOLOGON != null ? process.env.AUTOLOGON.toUpperCase() : "FALSE";
260
304
  const appEnvBase = {
261
305
  version: version,
262
- mcpType: mcpType,
306
+ mcpType: mcpType,
307
+ mcpClient: process.env.MCPCLIENT || 'github',
308
+ mcpHost: (process.env.MCPHOST == null) ? 'http://localhost:8080' : process.env.MCPHOST,
263
309
  brand: (process.env.BRAND == null) ? BRAND : process.env.BRAND,
264
310
  HTTPS: https,
265
311
  SAS_CLI_PROFILE: process.env.SAS_CLI_PROFILE || 'Default',
@@ -267,27 +313,25 @@ const appEnvBase = {
267
313
  SSLCERT: process.env.SSLCERT || null,
268
314
  VIYACERT: process.env.VIYACERT || null,
269
315
 
270
- AUTHFLOW: process.env.AUTHFLOW || 'sascli',
316
+ AUTHFLOW: authFlow,
317
+ AUTHEXTERNAL: authExternal,
318
+ BEARERTOKEN: null,
271
319
  AUTOLOGON: autoLogon,
272
320
  VIYA_SERVER: process.env.VIYA_SERVER,
273
321
  PORT: process.env.PORT || 8080,
274
322
  USERNAME: process.env.USERNAME || null,
275
323
  PASSWORD: process.env.PASSWORD || null,
276
- CLIENTID: clientID,
277
- CLIENTSECRET: clientSecret,
324
+ CLIENTID: process.env.CLIENTID || null,
325
+ CLIENTSECRET: process.env.CLIENTSECRET || null,
278
326
  PKCE: process.env.PKCE || null,
279
327
 
280
328
  TOKEN: process.env.TOKEN || null,
281
329
  REFRESH_TOKEN: process.env.REFRESH_TOKEN || null,
282
330
  TOKENFILE: process.env.TOKENFILE || null,
283
331
  TLS_CREATE: process.env.TLS_CREATE || null,
284
- SUBCLASS: process.env.SUBCLASS || null,
285
- subclassJson: subclassJson,
286
- // future use for controlling tool list using env variable
287
- toolsets:
288
- process.env.TOOLSETS != null
289
- ? process.env.TOOLSETS.split(',')
290
- : ['default'],
332
+ CASSERVER: process.env.CASSERVER,
333
+ COMPUTECONTEXT: process.env.COMPUTECONTEXT,
334
+
291
335
  // command line arguments
292
336
  cliArgs: args.values,
293
337
  // user defined tools
@@ -307,7 +351,8 @@ const appEnvBase = {
307
351
  tlsOpts: null,
308
352
  oauthInfo: null,
309
353
  contexts: {
310
- AUTHFLOW: process.env.AUTHFLOW || 'sascli',
354
+ AUTHFLOW: authFlow,
355
+ AUTHEXTERNAL: authExternal,
311
356
  host: process.env.VIYA_SERVER,
312
357
  APPHOST: process.env.APPHOST || 'localhost',
313
358
  APPNAME: process.env.APPNAME || 'sas-score-mcp-serverjs',
@@ -316,8 +361,8 @@ const appEnvBase = {
316
361
  store: null, /* for restaf users */
317
362
  storeConfig: {},
318
363
  oauthInfo: null,
319
- CLIENTID: clientID,
320
- CLIENTSECRET: clientSecret,
364
+ CLIENTID: process.env.CLIENTID || null,
365
+ CLIENTSECRET: process.env.CLIENTSECRET || null,
321
366
  pkce: process.env.PKCE || null,
322
367
  casSession: null, /* restaf cas session object */
323
368
  computeSession: null, /* restaf compute session object */
@@ -332,15 +377,14 @@ const appEnvBase = {
332
377
  }
333
378
  };
334
379
 
335
- process.env.APPPORT=appEnvBase.PORT;
380
+ process.env.APPPORT = appEnvBase.PORT;
381
+ let useHapi = process.env.USEHAPI === 'TRUE' ? true : false;
382
+ appEnvBase.useHapi = useHapi;
336
383
 
337
384
  // setup TLS options for viya calls
338
- console.error('[Note]Viya SSL dir set to: ' + appEnvBase.VIYACERT);
339
385
  appEnvBase.contexts.viyaCert = readCerts(appEnvBase.VIYACERT); /* appEnvBase.contexts.viyaCert is set here */
340
386
 
341
387
  // setup TLS options for app server (expressMcpServer or hapiMcpServer)
342
-
343
- console.error('[Note]App SSL dir set to: ' + appEnvBase.SSLCERT);
344
388
  appEnvBase.tlsOpts = readCerts(appEnvBase.SSLCERT);
345
389
  appEnvBase.contexts.appCert = appEnvBase.tlsOpts; /* just for completeness */
346
390
 
@@ -354,7 +398,7 @@ if (appEnvBase.TOKENFILE != null) {
354
398
  console.error(`[Note]Loading token from file: ${appEnvBase.TOKENFILE}...`);
355
399
  appEnvBase.TOKEN = fs.readFileSync(appEnvBase.TOKENFILE, { encoding: 'utf8' });
356
400
  appEnvBase.AUTHFLOW = 'token';
357
- appEnvBase.appContexts.logonPayload = {
401
+ appEnvBase.contexts.logonPayload = {
358
402
  host: appEnvBase.VIYA_SERVER,
359
403
  authType: 'server',
360
404
  token: appEnvBase.TOKEN,
@@ -367,10 +411,6 @@ if (appEnvBase.TOKENFILE != null) {
367
411
  }
368
412
 
369
413
 
370
-
371
- // if authflow is cli or code, postpone getting logonPayload until needed
372
-
373
-
374
414
  // setup mcpServer (both http and stdio use this)
375
415
  // this is singleton - best practices recommend this
376
416
 
@@ -381,22 +421,64 @@ let appEnvTemplate = Object.assign({}, appEnvBase);
381
421
 
382
422
  sessionCache.set('appEnvTemplate', appEnvTemplate);
383
423
 
424
+ // prime transport cache
384
425
  let transports = {
385
426
  "dummy": null
386
427
  };
387
428
  sessionCache.set('transports', transports);
429
+ let tokenlist = {
430
+ dummy: null
431
+ }
432
+ sessionCache.set('tokenlist', tokenlist);
388
433
 
389
434
  // set this for stdio transport use
390
435
  // dummy sessionId for use in the tools
391
- let useHapi = process.env.AUTHFLOW === 'code' ? true : false;
392
- console.error('[Note] appEnvBase is', JSON.stringify(appEnvBase, null,2));
436
+
393
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
394
438
  let sessionId = randomUUID();
395
439
  sessionCache.set(sessionId, appEnvBase);
396
440
  sessionCache.set('currentId', sessionId);
397
- useHapi = false;
398
- if (mcpType === 'stdio') {
399
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
+
481
+ if (mcpType === 'stdio') {
400
482
  console.error('[Note] Setting up stdio transport with sessionId:', sessionId);
401
483
  console.error('[Note] Used in setting up tools and some persistence(not all).');
402
484
  await coreSSE(mcpServer);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sassoftware/sas-score-mcp-serverjs",
3
- "version": "0.4.1-7",
3
+ "version": "1.0.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": [
@@ -40,7 +41,8 @@
40
41
  "cli.js",
41
42
  "openApi.json",
42
43
  "openApi.yaml",
43
- "skills"
44
+ "scripts",
45
+ ".skills"
44
46
  ],
45
47
  "dependencies": {
46
48
  "@modelcontextprotocol/sdk": "^1.29.0",
@@ -71,7 +73,6 @@
71
73
  "@babel/preset-env": "^7.28.5",
72
74
  "@types/debug": "^4.1.12",
73
75
  "@types/node": "^25.0.3",
74
- "npm-check-updates": "^19.2.0",
75
76
  "rimraf": "^6.1.2",
76
77
  "typescript": "^5.9.3"
77
78
  }