@sassoftware/sas-score-mcp-serverjs 1.0.1-0 → 1.0.1-2
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/README.md +72 -207
- package/cli.js +34 -66
- package/package.json +1 -1
- package/scripts/setup-skills.js +2 -2
- package/src/setupSkills.js +26 -15
- package/.skills/agents/sas-viya-scoring-expert.md +0 -58
- package/.skills/copilot-instructions.md +0 -155
- package/.skills/skills/sas-find-library-smart/SKILL.md +0 -154
- package/.skills/skills/sas-list-tables-smart/SKILL.md +0 -127
- package/.skills/skills/sas-read-and-score/SKILL.md +0 -111
- package/.skills/skills/sas-read-strategy/SKILL.md +0 -156
- package/.skills/skills/sas-request-classifier/SKILL.md +0 -69
- package/.skills/skills/sas-score-workflow/SKILL.md +0 -314
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
|
@@ -51,11 +51,6 @@ const args = parseArgs({
|
|
|
51
51
|
type: 'boolean',
|
|
52
52
|
description: 'Use HTTPS for the server (default: FALSE)'
|
|
53
53
|
},
|
|
54
|
-
'skills-folder': {
|
|
55
|
-
type: 'string',
|
|
56
|
-
short: 'f',
|
|
57
|
-
description: 'Skills folder name'
|
|
58
|
-
},
|
|
59
54
|
|
|
60
55
|
viya: {
|
|
61
56
|
type: 'string',
|
|
@@ -103,8 +98,13 @@ const args = parseArgs({
|
|
|
103
98
|
short: 'e',
|
|
104
99
|
description: 'Environment file path (default: .env in current working directory)'
|
|
105
100
|
},
|
|
101
|
+
agent: {
|
|
102
|
+
type: 'boolean',
|
|
103
|
+
description: 'Enable agent mode with a pre-configured set of skills based on the client specified (default: false)'
|
|
104
|
+
},
|
|
106
105
|
client: {
|
|
107
106
|
type: 'string',
|
|
107
|
+
alias: 'mcpclient',
|
|
108
108
|
description: 'MCP client name (github, claude...). Defaults to \'github\''
|
|
109
109
|
},
|
|
110
110
|
help: {
|
|
@@ -137,10 +137,13 @@ Options:
|
|
|
137
137
|
MCP server options:
|
|
138
138
|
-t, --mcptype <type> MCP server type: http or stdio (default: http)
|
|
139
139
|
-m, --mcphost <host> MCP server host - can be remote URL - (default: http://localhost:8080)
|
|
140
|
+
|
|
141
|
+
Agent options:
|
|
142
|
+
--agent Enable agent mode with a pre-configured set of skills based on the client specified (default: false)
|
|
140
143
|
--client <name> MCP client name (github, claude...). Defaults to 'github'.Use to install skills
|
|
141
144
|
Authentication options:
|
|
142
145
|
-a, --authflow <flow> Authentication flow: oauth, oauthclient, sascli, code, token(default oauth)
|
|
143
|
-
-s, --clientsecret <secret>
|
|
146
|
+
-s, --clientsecret <secret> Client Secret for oauth authentication (not needed for pkce)
|
|
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
|
|
|
@@ -162,7 +165,7 @@ Environment Variables:
|
|
|
162
165
|
`);
|
|
163
166
|
process.exit(0);
|
|
164
167
|
}
|
|
165
|
-
|
|
168
|
+
console.error('Parsed command line arguments:', args.values);
|
|
166
169
|
// read env file and then override with command line arguments
|
|
167
170
|
if (args.values.env) {
|
|
168
171
|
console.error('Working Directory', process.cwd());
|
|
@@ -184,23 +187,22 @@ if (args.values.env) {
|
|
|
184
187
|
// Apply command line arguments to override environment variables
|
|
185
188
|
|
|
186
189
|
process.env.PORT = process.env.PORT || '8080';
|
|
187
|
-
process.env.HTTPS =
|
|
190
|
+
process.env.HTTPS = args.values.https ? 'TRUE' : (process.env.HTTPS === 'TRUE' ? 'TRUE' : 'FALSE');
|
|
188
191
|
process.env.MCPTYPE = args.values.mcptype || process.env.MCPTYPE || 'http';
|
|
189
192
|
process.env.MCPHOST = args.values.mcphost || process.env.MCPHOST || 'http://localhost:8080';
|
|
190
193
|
process.env.AUTHFLOW = args.values.authflow || process.env.AUTHFLOW || 'oauth';
|
|
191
194
|
process.env.MCPCLIENT = args.values.client || process.env.MCPCLIENT || 'github';
|
|
192
|
-
process.env.VIYA_SERVER = args.values.viya || process.env.VIYA_SERVER
|
|
195
|
+
process.env.VIYA_SERVER = args.values.viya || process.env.VIYA_SERVER;
|
|
193
196
|
process.env.CLIENTID = args.values.clientid || process.env.CLIENTID || 'vscodemcp';
|
|
194
197
|
process.env.CLIENTSECRET = args.values.clientsecret || process.env.CLIENTSECRET || null;
|
|
195
198
|
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 ||
|
|
199
|
+
process.env.SAS_CLI_CONFIG = args.values.config || process.env.SAS_CLI_CONFIG || os.homedir(); // default to user home directory
|
|
197
200
|
process.env.CASSERVER = args.values.casserver || process.env.CASSERVER || 'cas-shared-default';
|
|
198
201
|
process.env.COMPUTECONTEXT = args.values.computecontext || process.env.COMPUTECONTEXT || 'SAS Job Execution compute context';
|
|
199
202
|
process.env.APPHOST = 'localhost';
|
|
203
|
+
process.env.AGENT = args.values.agent ? 'TRUE' : process.env.AGENT;
|
|
200
204
|
process.env.CLIENT = args.values.client || process.env.CLIENT || 'github';
|
|
201
205
|
|
|
202
|
-
|
|
203
|
-
|
|
204
206
|
process.env.SAMESITE = 'Lax,secure';
|
|
205
207
|
process.env.APPHOST = '0.0.0.0';
|
|
206
208
|
process.env.APPNAME = 'sas-score-mcp-serverjs';
|
|
@@ -217,51 +219,6 @@ if (args.values.version) {
|
|
|
217
219
|
console.error(`[Note] MCP client set to: ${process.env.CLIENT}`);
|
|
218
220
|
|
|
219
221
|
|
|
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
|
-
|
|
265
222
|
/********************************* */
|
|
266
223
|
const BRAND = 'sas-score'
|
|
267
224
|
/********************************* */
|
|
@@ -309,7 +266,7 @@ const appEnvBase = {
|
|
|
309
266
|
brand: (process.env.BRAND == null) ? BRAND : process.env.BRAND,
|
|
310
267
|
HTTPS: https,
|
|
311
268
|
SAS_CLI_PROFILE: process.env.SAS_CLI_PROFILE || 'Default',
|
|
312
|
-
SAS_CLI_CONFIG: process.env.SAS_CLI_CONFIG ||
|
|
269
|
+
SAS_CLI_CONFIG: process.env.SAS_CLI_CONFIG || os.homedir(), // default to user home directory
|
|
313
270
|
SSLCERT: process.env.SSLCERT || null,
|
|
314
271
|
VIYACERT: process.env.VIYACERT || null,
|
|
315
272
|
|
|
@@ -414,6 +371,16 @@ if (appEnvBase.TOKENFILE != null) {
|
|
|
414
371
|
// setup mcpServer (both http and stdio use this)
|
|
415
372
|
// this is singleton - best practices recommend this
|
|
416
373
|
|
|
374
|
+
// setup skills based on client before mcp initialization
|
|
375
|
+
//
|
|
376
|
+
if (process.env.AGENT === 'TRUE') {
|
|
377
|
+
if (process.env.CLIENT !== 'none') {
|
|
378
|
+
console.error(`[Note] Setting up skills for client: ${process.env.CLIENT}...`);
|
|
379
|
+
setupSkills(process.env.CLIENT);
|
|
380
|
+
}
|
|
381
|
+
} else {
|
|
382
|
+
console.error(`[Note] Agent mode not enabled`);
|
|
383
|
+
}
|
|
417
384
|
let mcpServer = await createMcpServer(sessionCache, appEnvBase);
|
|
418
385
|
|
|
419
386
|
sessionCache.set('appEnvBase', appEnvBase);
|
|
@@ -470,14 +437,15 @@ Options:
|
|
|
470
437
|
`);
|
|
471
438
|
|
|
472
439
|
console.error('===================================================================');
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
440
|
+
if (process.env.AGENT === 'TRUE') {
|
|
441
|
+
console.error(`
|
|
442
|
+
[Note] The SAS Viya Scoring Expert agent has been installed successfully.
|
|
443
|
+
Depending on the client you are using, the agent might not be active
|
|
444
|
+
If the agent does not appear in the agent dropdown list your options are:
|
|
445
|
+
- use the /subagent command
|
|
446
|
+
- exit this app and issue the npx command to restart the server
|
|
447
|
+
`);
|
|
448
|
+
}
|
|
481
449
|
if (mcpType === 'stdio') {
|
|
482
450
|
console.error('[Note] Setting up stdio transport with sessionId:', sessionId);
|
|
483
451
|
console.error('[Note] Used in setting up tools and some persistence(not all).');
|
package/package.json
CHANGED
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;
|
package/src/setupSkills.js
CHANGED
|
@@ -7,38 +7,49 @@ import { fileURLToPath } from 'url';
|
|
|
7
7
|
function setupSkills(clientName) {
|
|
8
8
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
9
9
|
// Paths
|
|
10
|
-
const source = path.join(__dirname, `../.skills`)
|
|
11
|
-
let client = (clientName == null) ? 'github' : `${clientName.toLowerCase()}`;
|
|
12
10
|
let destination;
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
11
|
+
if (clientName.startsWith('.')) {
|
|
12
|
+
console.error('-----------------------',process.cwd());
|
|
13
|
+
destination = path.join(process.cwd(), clientName);
|
|
14
|
+
clientName = clientName.slice(1);
|
|
17
15
|
} else {
|
|
18
|
-
|
|
19
|
-
destination = path.join(os.homedir(), client);
|
|
16
|
+
destination = path.join(os.homedir(), '.' + clientName);
|
|
20
17
|
}
|
|
21
18
|
|
|
22
|
-
|
|
19
|
+
const source = path.join(__dirname, `../.skills` + '_' + clientName.toLowerCase());
|
|
20
|
+
console.error("==================================================================");
|
|
21
|
+
console.error(` Copying ${source} to ${destination}...`);
|
|
22
|
+
|
|
23
23
|
function copyFolderSync(from, to) {
|
|
24
|
-
if (!fs.existsSync(from)) return;
|
|
25
|
-
if (!fs.existsSync(to)) fs.mkdirSync(to, { recursive: true })
|
|
26
|
-
console.error(`📁 Copying folder: ${from} to ${to}`);
|
|
24
|
+
if (!fs.existsSync(from)) return [];
|
|
25
|
+
if (!fs.existsSync(to)) fs.mkdirSync(to, { recursive: true });;
|
|
27
26
|
fs.readdirSync(from).forEach(element => {
|
|
28
|
-
console.error(`📁 Processing: ${element}`);
|
|
29
27
|
const fromPath = path.join(from, element);
|
|
30
28
|
const toPath = path.join(to, element);
|
|
31
29
|
if (fs.lstatSync(fromPath).isFile()) {
|
|
30
|
+
console.error(` 📄 Copying file: ${element}`);
|
|
32
31
|
fs.copyFileSync(fromPath, toPath);
|
|
33
32
|
} else if (fs.lstatSync(fromPath).isDirectory()) {
|
|
34
|
-
|
|
33
|
+
console.error(`📂 Copying folder: ${element}`);
|
|
34
|
+
copyFolderSync(fromPath, toPath) ;
|
|
35
35
|
}
|
|
36
36
|
});
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
+
function listExpandedFolder(dir, indent = "") {
|
|
40
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
41
|
+
|
|
42
|
+
for (const entry of entries) {
|
|
43
|
+
console.log(indent + entry.name);
|
|
44
|
+
|
|
45
|
+
if (entry.isDirectory()) {
|
|
46
|
+
listExpandedFolder(path.join(dir, entry.name), indent + " ");
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
39
50
|
try {
|
|
40
51
|
copyFolderSync(source, destination);
|
|
41
|
-
|
|
52
|
+
//listExpandedFolder(destination);
|
|
42
53
|
} catch (err) {
|
|
43
54
|
console.error('❌ Error copying files:', err.message);
|
|
44
55
|
}
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: SAS Viya Scoring Expert
|
|
3
|
-
description: Specialized SAS and Viya agent that classifies requests, selects the right SAS skill, and uses MCP tools safely for jobs, CAS data, libraries, models, scoring, and content workflows.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# SAS Viya Scoring Expert
|
|
7
|
-
|
|
8
|
-
You are a SAS Viya expert agent.
|
|
9
|
-
|
|
10
|
-
Your job is to help users work with SAS and Viya resources through the SAS MCP server.
|
|
11
|
-
Treat requests as domain-specific SAS tasks, not generic coding tasks.
|
|
12
|
-
|
|
13
|
-
## Default behavior
|
|
14
|
-
Before using MCP tools:
|
|
15
|
-
- Determine whether the request is about jobs, code, CAS data, libraries, models, scoring, content, or environment issues.
|
|
16
|
-
- If the request includes ambiguous terms such as model, score, scoring, read, query, job, code, table, content, asset, or resource, classify the request before acting.
|
|
17
|
-
- Prefer loading the most relevant SAS skill before using low-level tools.
|
|
18
|
-
- If confidence is low, ask one focused clarifying question.
|
|
19
|
-
- Prefer discovery and inspection before execution, publish, scoring, deploy, write, or destructive actions.
|
|
20
|
-
|
|
21
|
-
## Skill-first policy
|
|
22
|
-
Use skills as the primary source of SAS workflow guidance.
|
|
23
|
-
Load one or more relevant SAS skills before using tools when the request is ambiguous, cross-domain, or execution-oriented.
|
|
24
|
-
Do not load unrelated skills.
|
|
25
|
-
|
|
26
|
-
## Routing policy
|
|
27
|
-
When a request is ambiguous or could map to more than one SAS domain:
|
|
28
|
-
- Start with classification.
|
|
29
|
-
- Identify the most likely SAS asset or workflow type.
|
|
30
|
-
- Choose the best matching SAS skill.
|
|
31
|
-
- Only then select MCP tools.
|
|
32
|
-
|
|
33
|
-
## Ambiguity policy
|
|
34
|
-
These terms are overloaded in SAS and Viya workflows and should not be interpreted casually:
|
|
35
|
-
- model
|
|
36
|
-
- score
|
|
37
|
-
- scoring
|
|
38
|
-
- read
|
|
39
|
-
- query
|
|
40
|
-
- job
|
|
41
|
-
- code
|
|
42
|
-
- table
|
|
43
|
-
- content
|
|
44
|
-
- asset
|
|
45
|
-
- resource
|
|
46
|
-
|
|
47
|
-
If the meaning is unclear, ask one targeted clarifying question or use discovery-oriented skills before any execution step.
|
|
48
|
-
|
|
49
|
-
## Tool usage policy
|
|
50
|
-
- Prefer read-only discovery before execution.
|
|
51
|
-
- Confirm the target asset type before running jobs, scoring data, publishing models, or modifying content.
|
|
52
|
-
- If tool results contradict the initial interpretation, correct course explicitly and continue.
|
|
53
|
-
- Never invent asset names, identifiers, libraries, or model types.
|
|
54
|
-
|
|
55
|
-
## Response style
|
|
56
|
-
Be concise, explicit, and domain-aware.
|
|
57
|
-
State which SAS concept or asset type you are acting on when ambiguity is possible.
|
|
58
|
-
Prefer short structured answers when guiding the user.
|