@sassoftware/sas-score-mcp-serverjs 1.0.0 → 1.0.1-10
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/{.skills/agents/sas-viya-scoring-expert.md → .agents/sas-score-mcp-serverjs-agent.md} +1 -1
- package/{.skills → .instructions}/copilot-instructions.md +56 -2
- package/.instructions/enforce-find-resource-strategy.md +35 -0
- package/.skills/{skills/sas-find-library-smart → sas-find-library-smart}/SKILL.md +10 -9
- package/.skills/sas-find-resource-strategy/SKILL.md +105 -0
- package/.skills/sas-list-resource-strategy/SKILL.md +124 -0
- package/.skills/{skills/sas-list-tables-smart → sas-list-tables-smart}/SKILL.md +4 -3
- package/.skills/{skills/sas-read-and-score → sas-read-and-score-strategy}/SKILL.md +8 -6
- package/.skills/{skills/sas-read-strategy → sas-read-strategy}/SKILL.md +12 -14
- package/.skills/{skills/sas-request-classifier → sas-request-classifier}/SKILL.md +14 -9
- package/.skills/{skills/sas-score-workflow → sas-score-workflow-strategy}/SKILL.md +9 -9
- package/README.md +72 -207
- package/cli.js +58 -75
- package/package.json +7 -5
- package/scripts/setup-skills.js +2 -2
- package/src/oauthHandlers/callback.js +1 -1
- package/src/processHeaders.js +1 -1
- package/src/setupSkills.js +53 -11
- package/src/toolHelpers/_listLibrary.js +1 -1
- package/src/toolHelpers/_listTables.js +1 -1
- package/src/toolSet/.claude/settings.local.json +0 -13
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
name: sas-score-workflow
|
|
1
|
+
---
|
|
2
|
+
name: sas-score-workflow-strategy
|
|
3
3
|
description: >
|
|
4
4
|
Guide the full model scoring workflow: validate model familiarity, route to appropriate scoring tool
|
|
5
5
|
based on model type, invoke scoring with scenario data, and present merged results. Use this skill
|
|
@@ -108,8 +108,8 @@ Accepted formats:
|
|
|
108
108
|
|
|
109
109
|
## Integration with other skills
|
|
110
110
|
|
|
111
|
-
- **Before scoring table data**: Use `sas-find-
|
|
112
|
-
- **For read + score workflows**: Use `sas-read-and-score` for the complete end-to-end pattern
|
|
111
|
+
- **Before scoring table data**: Use `sas-find-resource-strategy` to verify library/table/model resources, then `sas-read-strategy` to fetch records
|
|
112
|
+
- **For read + score workflows**: Use `sas-read-and-score-strategy` for the complete end-to-end pattern
|
|
113
113
|
|
|
114
114
|
---
|
|
115
115
|
|
|
@@ -124,7 +124,7 @@ Pause and suggest investigation if:
|
|
|
124
124
|
- The user seems unsure of the required input variable names
|
|
125
125
|
|
|
126
126
|
**Suggested message:**
|
|
127
|
-
> "I don't recognize that model — want me to
|
|
127
|
+
> "I don't recognize that model — want me to use `sas-find-resource-strategy` to confirm it exists,
|
|
128
128
|
> or `model-info` to check its required inputs first?"
|
|
129
129
|
|
|
130
130
|
---
|
|
@@ -272,7 +272,7 @@ Merge the scoring output back with the input records and present as a table wher
|
|
|
272
272
|
> "Score Public.applicants with the creditRisk2 model"
|
|
273
273
|
|
|
274
274
|
1. Pause — "creditRisk2" is new
|
|
275
|
-
2. Suggest: `find-
|
|
275
|
+
2. Suggest: `sas-find-resource-strategy` to confirm resource existence, `model-info` to get input variables
|
|
276
276
|
3. Once confirmed → `sas-score-read-table` + `sas-score-model-score`
|
|
277
277
|
|
|
278
278
|
**Flow H — Generic score syntax with type routing**
|
|
@@ -291,7 +291,7 @@ Merge the scoring output back with the input records and present as a table wher
|
|
|
291
291
|
|
|
292
292
|
| Problem | Action |
|
|
293
293
|
|---|---|
|
|
294
|
-
| Model not found |
|
|
294
|
+
| Model not found | Use `sas-find-resource-strategy` to verify the model (or job/jobdef type) exists |
|
|
295
295
|
| Input field name mismatch | Show the mismatch (table has X, model expects Y), ask user to confirm mapping |
|
|
296
296
|
| Scoring error / invalid inputs | Return structured error, suggest `model-info` to check required inputs and data types |
|
|
297
297
|
| Empty read result | Tell user, ask if they want to adjust the query/filter before scoring |
|
|
@@ -310,5 +310,5 @@ Merge the scoring output back with the input records and present as a table wher
|
|
|
310
310
|
|
|
311
311
|
## Integration with other skills
|
|
312
312
|
|
|
313
|
-
- **Before scoring table data**: Use `sas-find-
|
|
314
|
-
- **For read + score workflows**: Use `sas-read-and-score` for the complete end-to-end pattern
|
|
313
|
+
- **Before scoring table data**: Use `sas-find-resource-strategy` to verify resources, then `sas-read-strategy` to fetch records
|
|
314
|
+
- **For read + score workflows**: Use `sas-read-and-score-strategy` for the complete end-to-end pattern
|
package/README.md
CHANGED
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
# sas-score-mcp-serverjs
|
|
2
2
|
A Model Context Protocol (MCP) Server for Scoring with SAS Viya
|
|
3
3
|
|
|
4
|
+
## Major changes in release 1.0.0
|
|
5
|
+
|
|
6
|
+
- Authentication: Oauth flow is now supported.
|
|
7
|
+
- Note that for Claude the mcp server must be remote. (ex: as a Azure Client App, Azure Container App etc...).
|
|
8
|
+
|
|
9
|
+
- Agent - can be deployed as an agent
|
|
10
|
+
|
|
11
|
+
|
|
4
12
|
## Overview
|
|
5
13
|
This MCP server is designed for scoring with SAS Viya.
|
|
6
14
|
|
|
@@ -24,257 +32,114 @@ See this [quick reference](sas-mcp-tools-reference.md) for details.
|
|
|
24
32
|
### MCP tool developers
|
|
25
33
|
SAS developers who want to extend the capabilities of the server with their own tools. See the [guide](tool-developer-guide.md) for details.
|
|
26
34
|
|
|
27
|
-
## Configuration Variables
|
|
28
|
-
Typically these are set either in the .env file or as environment variables (or both). This is full list of the configuration variables used the mcp server. You will need only a subset of these for the different [transport,authentication] schemes
|
|
29
|
-
|
|
30
|
-
```env
|
|
31
|
-
|
|
32
|
-
# Indicate what type of transport(stdio|http)
|
|
33
|
-
# http is useful for remote mcp servers
|
|
34
|
-
# If running locally, recommend stdio
|
|
35
|
-
|
|
36
|
-
MCPTYPE=<stdio|http>
|
|
37
|
-
|
|
38
|
-
# Port for http transport(default is 8080)
|
|
39
35
|
|
|
40
|
-
|
|
36
|
+
## Transport Protocol supported
|
|
41
37
|
|
|
42
|
-
|
|
43
|
-
|
|
38
|
+
- http
|
|
39
|
+
- stdio
|
|
44
40
|
|
|
45
|
-
HTTPS=TRUE|FALSE
|
|
46
41
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
# * sascli * will look for tokens created with sas-viya cli
|
|
51
|
-
# * token * a custom token
|
|
52
|
-
# * password * userid/password
|
|
53
|
-
# * code * Oauth using authorization_code flow(pkce not supported in this release)
|
|
54
|
-
|
|
55
|
-
AUTHFLOW=sascli|token|password|code
|
|
42
|
+
## Configuration Variables
|
|
43
|
+
Typically these are set either in the .env file or as environment variables or as command line options(if using npx). You will need only a subset of these for the different [transport,authentication] schemes
|
|
56
44
|
|
|
57
|
-
|
|
58
|
-
SAS_CLI_PROFILE=your-sas-cli-profile
|
|
45
|
+
### Required Options
|
|
59
46
|
|
|
60
|
-
|
|
47
|
+
VIYA_SERVER=<url for Viya server>
|
|
48
|
+
MCPTYPE=http|stdio
|
|
49
|
+
MCPHOST=<url for the mcp server = http://localhost:8080 or some remote mcp server>
|
|
61
50
|
|
|
62
|
-
|
|
51
|
+
>Recommended authflow is oauth - the most secure of all the options since all oauth flow occurs in the server and the actual token is never sent to the client. Bearer authflow is useful when the mcp server is remote with its own authentication process
|
|
63
52
|
|
|
64
|
-
|
|
65
|
-
TOKENFILE=
|
|
53
|
+
AUTHFLOW=oauth|oauthclient|bearer|sascli|token|password
|
|
66
54
|
|
|
67
|
-
|
|
68
|
-
CLIENTID=
|
|
69
|
-
CLIENTSECRET=
|
|
55
|
+
> Options for oauth. The clientid must have a redirect of http://localhost:8080/callback,https://localhost:8080/callback
|
|
70
56
|
|
|
71
|
-
|
|
72
|
-
PASSWORD=
|
|
57
|
+
CLIENTID=<pkce clientid>
|
|
73
58
|
|
|
74
|
-
# When HTTPS is TRUE, specify the folder with SSL certificates for the mcp server
|
|
75
|
-
# All files in that folder will be loaded and used in the TLS connection
|
|
76
|
-
# If not set and HTTPS is true, the server will create a self-signed certificate
|
|
77
59
|
|
|
78
|
-
|
|
60
|
+
> OauthClient Flow. Clientid with redirect appropriate for the client. Some examples are shown below. Note that the explicit port used by github copilot is not guaranteed.
|
|
79
61
|
|
|
62
|
+
- github copilot: http://127.0.0.1:33418/
|
|
63
|
+
- claude: https://claude.ai/api/mcp/auth_callback,https://claude.ai/api/auth/callback
|
|
80
64
|
|
|
81
|
-
|
|
82
|
-
# Used in restaf (ultimately axios and fetch)
|
|
83
|
-
# All files in the folder will be loaded and used in the TLS connection
|
|
84
|
-
# if not set, no ssl certificates will be used
|
|
85
|
-
# See the script in scripts/getViyaca.sh to get this certificate from the SAS Viya server
|
|
65
|
+
> bearer - Use this when the remote mcp server sends the token in the header.
|
|
86
66
|
|
|
87
|
-
VIYACERT=<some folder>
|
|
88
67
|
|
|
89
|
-
|
|
90
|
-
# These are for the CAS and SAS sessions
|
|
91
|
-
# Defaults are:
|
|
92
|
-
COMPUTECONTEXT=SAS Job Execution compute context
|
|
93
|
-
CASSERVER=cas-shared-default
|
|
68
|
+
> sascli - Use sas-viya cli to create the token information. It is stored in ~/.sas folder by default
|
|
94
69
|
|
|
70
|
+
```env
|
|
71
|
+
PROFILE=<profile name used by sas-cli to store the tokens in ~/.sas>
|
|
95
72
|
```
|
|
96
73
|
|
|
97
|
-
|
|
98
|
-
The server supports multiple ways to authenticate.
|
|
99
|
-
|
|
100
|
-
### sas-viya cli
|
|
101
|
-
|
|
102
|
-
> Note: To use this, set `AUTHFLOW=sascli`
|
|
103
|
-
|
|
104
|
-
This MCP server CLI works similar to SAS supplied sas-viya CLI commands.
|
|
105
|
-
Use the following command to create the necessary token and refresh token.
|
|
106
|
-
|
|
107
|
-
`create a default auth Profile`.
|
|
108
|
-
Issue this command and follow instruction: `sas-viya profile init`
|
|
109
|
-
|
|
110
|
-
`create token`
|
|
111
|
-
Issue this command and follow the instructions: `sas-viya auth loginCode`
|
|
112
|
-
|
|
113
|
-
You need to do this once every 90 days or whenever the refresh token expires.
|
|
114
|
-
|
|
115
|
-
At this point the tools can make authenticated calls to SAS Viya.
|
|
116
|
-
|
|
117
|
-
### Password
|
|
118
|
-
|
|
119
|
-
> Note: To use this, set `AUTHTYPE=password`
|
|
120
|
-
|
|
121
|
-
Ths requires additional setup:
|
|
122
|
-
|
|
123
|
-
- Create a clientid and client password for Oauth password flow.
|
|
124
|
-
- Set these in the .env file or the mcp configuration file
|
|
125
|
-
|
|
126
|
-
### Custom token
|
|
127
|
-
|
|
128
|
-
> Note: To use this, set `AUTHTYPE=token`
|
|
129
|
-
|
|
130
|
-
Set the env TOKENFILE to a file containing the token.
|
|
131
|
-
|
|
132
|
-
There seems to be a pattern of using a long-lived token.
|
|
133
|
-
If this is your use case, set the TOKENFILE to a file containing this token.
|
|
134
|
-
|
|
135
|
-
### Oauth - (experimental) Authentication handled by the mcp server
|
|
136
|
-
|
|
137
|
-
In this approach, the mcp client does not participate in the Oauth authentication process. It is handled by the mcp server at startup.
|
|
138
|
-
|
|
139
|
-
> This is marked as experimental since the testing is not complete
|
|
140
|
-
|
|
141
|
-
#### SAS viya setup.
|
|
142
|
-
|
|
143
|
-
Create a Oauth client with the following properties
|
|
144
|
-
|
|
145
|
-
```js
|
|
146
|
-
{
|
|
147
|
-
auth flow: authorization_code|password
|
|
148
|
-
clientid: <your client id>
|
|
149
|
-
clientsecret: <some client secret - pkce not supported at this time>
|
|
150
|
-
redirect: https://localhost:8080/mcpserver
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
#### Use an .env file as follows(sample values shown)
|
|
74
|
+
### Other options
|
|
154
75
|
|
|
155
76
|
```env
|
|
156
|
-
PORT
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
CAS_SERVER=cas-shared-default
|
|
161
|
-
COMPUTECONTEXT=SAS Job Execution compute context
|
|
162
|
-
|
|
163
|
-
PORT=8080
|
|
164
|
-
HTTPS=true
|
|
165
|
-
MCPTYPE=http
|
|
166
|
-
USELOGON=FALSE
|
|
167
|
-
USETOKEN=TRUE
|
|
168
|
-
APPNAME=sas-score-mcp-serverjs
|
|
169
|
-
|
|
170
|
-
CLIENTID=mcpserver
|
|
171
|
-
CLIENTSECRET=xxxxxx
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
# SAMESITE=Lax,secure
|
|
175
|
-
|
|
77
|
+
PORT=<default is 8080>
|
|
78
|
+
HTTPS=FALSE
|
|
79
|
+
CASSERVER=CAS server name (default: cas-shared-default)
|
|
80
|
+
COMPUTECONTEXT=Compute session name or context (default: SAS Job Execution compute context)
|
|
176
81
|
```
|
|
177
82
|
|
|
178
|
-
|
|
83
|
+
## Agent
|
|
179
84
|
|
|
180
|
-
|
|
85
|
+
> The mcp server can be deployed as an agent in github copilot
|
|
86
|
+
> The configuration files for claude can be installed locally. You have to move the files to the appriopiate place.
|
|
181
87
|
|
|
182
|
-
|
|
183
|
-
npx @sassoftware/sas-score-mcp-serverjs@latest
|
|
184
|
-
```
|
|
88
|
+
Specify the following configuration values to enable agent mode
|
|
185
89
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
https://localhost:8080/mcpserver
|
|
90
|
+
```env
|
|
91
|
+
AGENT=TRUE
|
|
92
|
+
MCPCLIENT=github|claude
|
|
190
93
|
```
|
|
191
94
|
|
|
192
|
-
|
|
193
|
-
A dialog will be displayed if the logon was successful.
|
|
194
|
-
Icon this window and proceed to your mcp client
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
## Transport Methods
|
|
198
|
-
This server supports both stdio and http transport methods.
|
|
95
|
+
By default the agent information is installed in the user's home directory as .github or .claude} To install it where the mcp server is running do the following:
|
|
199
96
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
The env variables can be specified in two ways:
|
|
97
|
+
```env
|
|
98
|
+
MCPCLIENT=.github|.claude
|
|
99
|
+
```
|
|
205
100
|
|
|
206
|
-
1. As part of the mcp configuration as shown below.
|
|
207
|
-
2. Create a .env file and specify the env variables in that file.
|
|
208
101
|
|
|
102
|
+
## Configure the mcp client for localhost
|
|
209
103
|
|
|
210
|
-
|
|
104
|
+
The mcp configuration is show below
|
|
211
105
|
|
|
212
106
|
```json
|
|
213
|
-
|
|
214
|
-
"type": "
|
|
215
|
-
"
|
|
216
|
-
"
|
|
217
|
-
"
|
|
218
|
-
"@sassoftware/sas-score-mcp-serverjs@latest",
|
|
219
|
-
],
|
|
220
|
-
"env": {
|
|
221
|
-
"MCPTYPE": "stdio",
|
|
222
|
-
"AUTHFLOW": "sascli", // sascli|password|token|none
|
|
223
|
-
"SAS_CLI_PROFILE": "cli profile name or Default",
|
|
224
|
-
"SAS_CLI_CONFIG":"where sas-cli stores authentication information",
|
|
225
|
-
"SSLCERT": "where you have stored the tls information(see below)",
|
|
226
|
-
"VIYACERT": "where you have stored the viya server ssl certificates for calls to Viya server",
|
|
227
|
-
"VIYA_SERVER": "viya server if AUTHFLOW=password|token|refresh",
|
|
228
|
-
"PASSWORD": "password if AUTHFLOW is password",
|
|
229
|
-
"USERNAME": "username if AUTHFLOW is password",
|
|
230
|
-
"CLIENTID": "client password if AUTHFLOW is password",
|
|
231
|
-
"CLIENTSECRET": "client id if AUTHFLOW is password",
|
|
232
|
-
"TOKENFILE": "file if AUTHFLOW is token",
|
|
233
|
-
"COMPUTECONTEXT": "SAS Job Execution compute context",
|
|
234
|
-
"CASSERVER": "cas-shared-default",
|
|
107
|
+
"sasmcp": {
|
|
108
|
+
"type": "http",
|
|
109
|
+
"url": "http://localhost:8080/mcp"``
|
|
110
|
+
"oauth: {
|
|
111
|
+
"type": "oauth2"
|
|
235
112
|
}
|
|
236
|
-
|
|
237
|
-
|
|
113
|
+
}
|
|
238
114
|
```
|
|
239
115
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
This is an alternate to using stdio.
|
|
243
|
-
This requires the .env file, which has the necessary configuration values described earlier in this document.
|
|
244
|
-
It also requires the MCP server to be running (see step 2).
|
|
245
|
-
|
|
246
|
-
> Remote MCP servers: This is under development
|
|
247
|
-
|
|
248
|
-
#### Step 1: Configure the mcp client for localhost
|
|
249
|
-
|
|
250
|
-
The mcp configuration is show below
|
|
251
|
-
|
|
116
|
+
For remote mcp servers:
|
|
252
117
|
```json
|
|
253
118
|
"sasmcp": {
|
|
254
119
|
"type": "http",
|
|
255
|
-
"url": "
|
|
120
|
+
"url": "your remote mcp server`,
|
|
121
|
+
"oauth": {
|
|
122
|
+
"type": 'oauth2
|
|
123
|
+
}
|
|
256
124
|
}
|
|
257
125
|
```
|
|
258
126
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
```env
|
|
262
|
-
|
|
263
|
-
PORT=8080
|
|
264
|
-
HTTPS=FALSE
|
|
265
|
-
MCPTYPE=http
|
|
266
|
-
VIYA_SERVER=https://myviya.com
|
|
267
|
-
AUTHFLOW=sascli
|
|
268
|
-
SAS_CLI_PROFILE=00m
|
|
269
|
-
SAS_CLI_CONFIG=c:\Users\<yourusername>
|
|
270
|
-
SSLCERT=c:\Users\yourusername\.tls
|
|
271
|
-
VIYACERT=c:\Users\yourusername\viyaCert
|
|
272
|
-
CAS_SERVER=cas-shared-default
|
|
273
|
-
COMPUTECONTEXT=SAS Job Execution compute context
|
|
127
|
+
For transport protocol stdio. For claude drop the type
|
|
274
128
|
|
|
129
|
+
```json
|
|
130
|
+
"sas-mcp-server": {
|
|
131
|
+
"type: "stdio"
|
|
132
|
+
"command": "npx",
|
|
133
|
+
"args": [
|
|
134
|
+
"-y",
|
|
135
|
+
"@sassoftware/sas-score-mcp-serverjs@1.0.0"
|
|
136
|
+
-v "<your viya url>"
|
|
137
|
+
-m "stdio"
|
|
138
|
+
--profile "dtl"
|
|
139
|
+
-a "sascli"
|
|
140
|
+
]
|
|
141
|
+
}
|
|
275
142
|
```
|
|
276
|
-
Use https if the environment variables HTTPS=TRUE
|
|
277
|
-
|
|
278
143
|
|
|
279
144
|
#### Step 2: Start the mcp server
|
|
280
145
|
|
|
@@ -286,7 +151,7 @@ But this step is necessary of using http transport.
|
|
|
286
151
|
npx @sassoftware/sas-score-mcp-serverjs@latest
|
|
287
152
|
```
|
|
288
153
|
|
|
289
|
-
Make sure that the .env file is in the current working directory
|
|
154
|
+
Make sure that the .env file is in the current working directory or specify the options in the command line
|
|
290
155
|
|
|
291
156
|
|
|
292
157
|
## Notes
|
package/cli.js
CHANGED
|
@@ -16,8 +16,6 @@ import createMcpServer from './src/createMcpServer.js';
|
|
|
16
16
|
import fs from 'fs';
|
|
17
17
|
import { randomUUID } from 'node:crypto';
|
|
18
18
|
|
|
19
|
-
//import refreshToken from './src/toolHelpers/refreshToken.js';
|
|
20
|
-
//import getOptsViya from './src/toolHelpers/getOptsViya.js';
|
|
21
19
|
import readCerts from './src/toolHelpers/readCerts.js';
|
|
22
20
|
|
|
23
21
|
import { fileURLToPath } from 'url';
|
|
@@ -51,11 +49,6 @@ const args = parseArgs({
|
|
|
51
49
|
type: 'boolean',
|
|
52
50
|
description: 'Use HTTPS for the server (default: FALSE)'
|
|
53
51
|
},
|
|
54
|
-
'skills-folder': {
|
|
55
|
-
type: 'string',
|
|
56
|
-
short: 'f',
|
|
57
|
-
description: 'Skills folder name'
|
|
58
|
-
},
|
|
59
52
|
|
|
60
53
|
viya: {
|
|
61
54
|
type: 'string',
|
|
@@ -77,11 +70,6 @@ const args = parseArgs({
|
|
|
77
70
|
short: 'c',
|
|
78
71
|
description: 'Client ID for authentication'
|
|
79
72
|
},
|
|
80
|
-
clientsecret: {
|
|
81
|
-
type: 'string',
|
|
82
|
-
short: 's',
|
|
83
|
-
description: 'Client Secret for authentication'
|
|
84
|
-
},
|
|
85
73
|
profile: {
|
|
86
74
|
type: 'string',
|
|
87
75
|
description: 'SAS CLI profile name'
|
|
@@ -103,10 +91,26 @@ const args = parseArgs({
|
|
|
103
91
|
short: 'e',
|
|
104
92
|
description: 'Environment file path (default: .env in current working directory)'
|
|
105
93
|
},
|
|
94
|
+
agent: {
|
|
95
|
+
type: 'boolean',
|
|
96
|
+
description: 'Enable agent mode with a pre-configured set of skills based on the client specified (default: false)'
|
|
97
|
+
},
|
|
106
98
|
client: {
|
|
107
99
|
type: 'string',
|
|
100
|
+
alias: 'mcpclient',
|
|
108
101
|
description: 'MCP client name (github, claude...). Defaults to \'github\''
|
|
109
102
|
},
|
|
103
|
+
folder: {
|
|
104
|
+
type: 'string',
|
|
105
|
+
short: 'f',
|
|
106
|
+
description: 'Subfolder under the client folder to copy the skills to, used to have different set of skills for different agents under the same client'
|
|
107
|
+
|
|
108
|
+
},
|
|
109
|
+
skills: {
|
|
110
|
+
type: 'string',
|
|
111
|
+
short: 's',
|
|
112
|
+
description: 'Copies the skills for .github and .claude to the user home directory under .clientname (e.g. .github) or current directory if client name starts with dot (e.g. ./.github), used to have different set of skills for different clients'
|
|
113
|
+
},
|
|
110
114
|
help: {
|
|
111
115
|
type: 'boolean',
|
|
112
116
|
short: 'h',
|
|
@@ -125,25 +129,28 @@ const args = parseArgs({
|
|
|
125
129
|
// Handle help flag
|
|
126
130
|
if (args.values.help) {
|
|
127
131
|
console.error(`
|
|
128
|
-
|
|
132
|
+
sas-score-mcp-serverjs - Version: ${JSON.parse(pkg).version}
|
|
129
133
|
|
|
130
134
|
Usage: npx @sassoftware/sas-score-mcp-serverjs@dev [options]
|
|
131
135
|
|
|
132
136
|
Options:
|
|
133
137
|
Minimal options:
|
|
134
138
|
-v, --viya <url> Viya server URL
|
|
135
|
-
-c, --clientid <id> Client ID for oauth authentication(pkce preferred. default: vscodemcp)
|
|
136
139
|
|
|
137
140
|
MCP server options:
|
|
138
141
|
-t, --mcptype <type> MCP server type: http or stdio (default: http)
|
|
139
142
|
-m, --mcphost <host> MCP server host - can be remote URL - (default: http://localhost:8080)
|
|
140
|
-
|
|
143
|
+
|
|
141
144
|
Authentication options:
|
|
145
|
+
-c, --clientid <id> Client ID for oauth authentication(pkce preferred. default: vscodemcp)
|
|
142
146
|
-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
147
|
--profile <name> SAS CLI profile name for sascli flow (default: Default)
|
|
145
148
|
--config <path> SAS CLI config directory for sascli flow (default: user home directory)
|
|
146
149
|
|
|
150
|
+
Agent/skills options:
|
|
151
|
+
-s, --skills <name> Copies the skills for .github and .claude
|
|
152
|
+
-f, --folder <folder> Subfolder to copy the skills to. ex: ./github/<folder>, used to have different set of skills for different agents under the same client.
|
|
153
|
+
|
|
147
154
|
Other options:
|
|
148
155
|
-p, --port <port> Port to run the server on (default: 8080)
|
|
149
156
|
--https Use HTTPS for the server (default: false)
|
|
@@ -162,7 +169,14 @@ Environment Variables:
|
|
|
162
169
|
`);
|
|
163
170
|
process.exit(0);
|
|
164
171
|
}
|
|
172
|
+
if (args.values.skills) {
|
|
173
|
+
console.error(`[Note] Settings up skills for ${args.values.skills }`);
|
|
174
|
+
setupSkills(args.values.skills, args.values.folder);;
|
|
175
|
+
console.error(`[Note] Skills setup completed. `);
|
|
176
|
+
process.exit(0);
|
|
177
|
+
}
|
|
165
178
|
|
|
179
|
+
console.error('Parsed command line arguments:', args.values);
|
|
166
180
|
// read env file and then override with command line arguments
|
|
167
181
|
if (args.values.env) {
|
|
168
182
|
console.error('Working Directory', process.cwd());
|
|
@@ -184,23 +198,22 @@ if (args.values.env) {
|
|
|
184
198
|
// Apply command line arguments to override environment variables
|
|
185
199
|
|
|
186
200
|
process.env.PORT = process.env.PORT || '8080';
|
|
187
|
-
process.env.HTTPS =
|
|
201
|
+
process.env.HTTPS = args.values.https ? 'TRUE' : (process.env.HTTPS === 'TRUE' ? 'TRUE' : 'FALSE');
|
|
188
202
|
process.env.MCPTYPE = args.values.mcptype || process.env.MCPTYPE || 'http';
|
|
189
203
|
process.env.MCPHOST = args.values.mcphost || process.env.MCPHOST || 'http://localhost:8080';
|
|
190
204
|
process.env.AUTHFLOW = args.values.authflow || process.env.AUTHFLOW || 'oauth';
|
|
191
205
|
process.env.MCPCLIENT = args.values.client || process.env.MCPCLIENT || 'github';
|
|
192
|
-
process.env.VIYA_SERVER = args.values.viya || process.env.VIYA_SERVER
|
|
206
|
+
process.env.VIYA_SERVER = args.values.viya || process.env.VIYA_SERVER;
|
|
193
207
|
process.env.CLIENTID = args.values.clientid || process.env.CLIENTID || 'vscodemcp';
|
|
194
|
-
process.env.CLIENTSECRET =
|
|
208
|
+
process.env.CLIENTSECRET = null;
|
|
195
209
|
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 ||
|
|
210
|
+
process.env.SAS_CLI_CONFIG = args.values.config || process.env.SAS_CLI_CONFIG || os.homedir(); // default to user home directory
|
|
197
211
|
process.env.CASSERVER = args.values.casserver || process.env.CASSERVER || 'cas-shared-default';
|
|
198
212
|
process.env.COMPUTECONTEXT = args.values.computecontext || process.env.COMPUTECONTEXT || 'SAS Job Execution compute context';
|
|
199
213
|
process.env.APPHOST = 'localhost';
|
|
214
|
+
process.env.AGENT = args.values.agent ? 'TRUE' : process.env.AGENT;
|
|
200
215
|
process.env.CLIENT = args.values.client || process.env.CLIENT || 'github';
|
|
201
216
|
|
|
202
|
-
|
|
203
|
-
|
|
204
217
|
process.env.SAMESITE = 'Lax,secure';
|
|
205
218
|
process.env.APPHOST = '0.0.0.0';
|
|
206
219
|
process.env.APPNAME = 'sas-score-mcp-serverjs';
|
|
@@ -217,50 +230,6 @@ if (args.values.version) {
|
|
|
217
230
|
console.error(`[Note] MCP client set to: ${process.env.CLIENT}`);
|
|
218
231
|
|
|
219
232
|
|
|
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
|
-
|
|
264
233
|
|
|
265
234
|
/********************************* */
|
|
266
235
|
const BRAND = 'sas-score'
|
|
@@ -309,7 +278,7 @@ const appEnvBase = {
|
|
|
309
278
|
brand: (process.env.BRAND == null) ? BRAND : process.env.BRAND,
|
|
310
279
|
HTTPS: https,
|
|
311
280
|
SAS_CLI_PROFILE: process.env.SAS_CLI_PROFILE || 'Default',
|
|
312
|
-
SAS_CLI_CONFIG: process.env.SAS_CLI_CONFIG ||
|
|
281
|
+
SAS_CLI_CONFIG: process.env.SAS_CLI_CONFIG || os.homedir(), // default to user home directory
|
|
313
282
|
SSLCERT: process.env.SSLCERT || null,
|
|
314
283
|
VIYACERT: process.env.VIYACERT || null,
|
|
315
284
|
|
|
@@ -414,6 +383,19 @@ if (appEnvBase.TOKENFILE != null) {
|
|
|
414
383
|
// setup mcpServer (both http and stdio use this)
|
|
415
384
|
// this is singleton - best practices recommend this
|
|
416
385
|
|
|
386
|
+
// setup skills based on client before mcp initialization
|
|
387
|
+
//
|
|
388
|
+
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
if (process.env.AGENT === 'TRUE') {
|
|
392
|
+
if (process.env.CLIENT !== 'none') {
|
|
393
|
+
console.error(`[Note] Setting up skills for client: ${process.env.CLIENT}...`);
|
|
394
|
+
setupSkills(process.env.CLIENT, args.values.folder);
|
|
395
|
+
}
|
|
396
|
+
} else {
|
|
397
|
+
console.error(`[Note] Agent mode not enabled`);
|
|
398
|
+
}
|
|
417
399
|
let mcpServer = await createMcpServer(sessionCache, appEnvBase);
|
|
418
400
|
|
|
419
401
|
sessionCache.set('appEnvBase', appEnvBase);
|
|
@@ -470,14 +452,15 @@ Options:
|
|
|
470
452
|
`);
|
|
471
453
|
|
|
472
454
|
console.error('===================================================================');
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
455
|
+
if (process.env.AGENT === 'TRUE') {
|
|
456
|
+
console.error(`
|
|
457
|
+
[Note] The SAS Viya Scoring Expert agent has been installed successfully.
|
|
458
|
+
Depending on the client you are using, the agent might not be active
|
|
459
|
+
If the agent does not appear in the agent dropdown list your options are:
|
|
460
|
+
- use the /subagent command
|
|
461
|
+
- exit this app and issue the npx command to restart the server
|
|
462
|
+
`);
|
|
463
|
+
}
|
|
481
464
|
if (mcpType === 'stdio') {
|
|
482
465
|
console.error('[Note] Setting up stdio transport with sessionId:', sessionId);
|
|
483
466
|
console.error('[Note] Used in setting up tools and some persistence(not all).');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sassoftware/sas-score-mcp-serverjs",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1-10",
|
|
4
4
|
"description": "A mcp server for SAS Viya",
|
|
5
5
|
"author": "Deva Kumar <deva.kumar@sas.com>",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -42,13 +42,15 @@
|
|
|
42
42
|
"openApi.json",
|
|
43
43
|
"openApi.yaml",
|
|
44
44
|
"scripts",
|
|
45
|
-
".skills"
|
|
45
|
+
".skills",
|
|
46
|
+
".agents",
|
|
47
|
+
".instructions"
|
|
46
48
|
],
|
|
47
49
|
"dependencies": {
|
|
48
50
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
49
|
-
"@sassoftware/restaf": "^5.
|
|
50
|
-
"@sassoftware/restafedit": "^3.
|
|
51
|
-
"@sassoftware/restaflib": "^5.
|
|
51
|
+
"@sassoftware/restaf": "^5.7.2",
|
|
52
|
+
"@sassoftware/restafedit": "^3.10.5",
|
|
53
|
+
"@sassoftware/restaflib": "^5.7.2",
|
|
52
54
|
"@sassoftware/viya-serverjs": "^0.6.3-0",
|
|
53
55
|
"axios": "^1.13.2",
|
|
54
56
|
"body-parser": "^2.2.1",
|
package/scripts/setup-skills.js
CHANGED
|
@@ -7,8 +7,8 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
|
7
7
|
// Paths
|
|
8
8
|
let client = (process.env.CLIENTNAME == null) ? '.github' : `.${process.env.CLIENTNAME.toLowerCase()}`;
|
|
9
9
|
const source = path.join(__dirname, `../.skills`);
|
|
10
|
-
|
|
11
|
-
const destination = path.join(os.homedir(), client)
|
|
10
|
+
const destination = path.join(process.cwd(), client);
|
|
11
|
+
// const destination = path.join(os.homedir(), client)
|
|
12
12
|
console.error(`📁 Copying ${source} to ${destination}...`);
|
|
13
13
|
function copyFolderSync(from, to) {
|
|
14
14
|
if (!fs.existsSync(from)) return;
|