@sassoftware/sas-score-mcp-serverjs 0.0.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/.babelrc +6 -0
- package/.env +13 -0
- package/.env.http +29 -0
- package/CHANGES.md +2 -0
- package/CONTRIBUTING.md +14 -0
- package/ContributorAgreement.txt +56 -0
- package/LICENSE +205 -0
- package/LICENSES.json +105 -0
- package/QUICK_REFERENCE.md +378 -0
- package/README.md +267 -0
- package/SECURITY.md +31 -0
- package/SUPPORT.md +3 -0
- package/TOOL_DESCRIPTION_TEMPLATE.md +157 -0
- package/TOOL_UPDATES_SUMMARY.md +208 -0
- package/cli.js +214 -0
- package/labs/.subclass.json +13 -0
- package/labs/README.md +4 -0
- package/mcpConfigurations/README.md +3 -0
- package/mcpConfigurations/http.json +8 -0
- package/mcpConfigurations/stdio.json +20 -0
- package/mcpConfigurations/stdiodev.json +20 -0
- package/mcpserver.png +0 -0
- package/openApi.json +106 -0
- package/openApi.yaml +84 -0
- package/package.json +72 -0
- package/sas-mcp-tools-reference.md +600 -0
- package/sasCode/sas-sql-query.sas +33 -0
- package/sasCode/sas_sql_tool.json +237 -0
- package/scripts/getViyaca.sh +8 -0
- package/src/core.js +19 -0
- package/src/coreSSE.js +14 -0
- package/src/corehttp.js +335 -0
- package/src/createHttpTransport.js +26 -0
- package/src/createMcpServer.js +76 -0
- package/src/db/scrModels.js +23 -0
- package/src/toolSet/devaScore.js +69 -0
- package/src/toolSet/findJob.js +90 -0
- package/src/toolSet/findJobdef.js +95 -0
- package/src/toolSet/findLibrary.js +100 -0
- package/src/toolSet/findModel.js +83 -0
- package/src/toolSet/findTable.js +94 -0
- package/src/toolSet/getEnv.js +72 -0
- package/src/toolSet/listJobdefs.js +96 -0
- package/src/toolSet/listJobs.js +110 -0
- package/src/toolSet/listLibraries.js +90 -0
- package/src/toolSet/listModels.js +83 -0
- package/src/toolSet/listTables.js +95 -0
- package/src/toolSet/makeTools.js +75 -0
- package/src/toolSet/mcp server .png +0 -0
- package/src/toolSet/modelInfo.js +87 -0
- package/src/toolSet/modelScore.js +131 -0
- package/src/toolSet/readTable.js +104 -0
- package/src/toolSet/runCasProgram.js +118 -0
- package/src/toolSet/runJob.js +81 -0
- package/src/toolSet/runJobdef.js +85 -0
- package/src/toolSet/runMacro.js +82 -0
- package/src/toolSet/runProgram.js +145 -0
- package/src/toolSet/sasQuery.js +126 -0
- package/src/toolSet/sasQueryTemplate.js +148 -0
- package/src/toolSet/sasQueryTemplate2.js +140 -0
- package/src/toolSet/scrInfo.js +55 -0
- package/src/toolSet/scrScore.js +71 -0
- package/src/toolSet/searchAssets.js +52 -0
- package/src/toolSet/setContext.js +98 -0
- package/src/toolSet/superstat.js +60 -0
- package/src/toolSet/tableInfo.js +102 -0
- package/src/toolhelpers/_catalogSearch.js +87 -0
- package/src/toolhelpers/_getEnv.js +10 -0
- package/src/toolhelpers/_itemsData.js +28 -0
- package/src/toolhelpers/_jobSubmit.js +78 -0
- package/src/toolhelpers/_listJobdefs.js +59 -0
- package/src/toolhelpers/_listJobs.js +63 -0
- package/src/toolhelpers/_listLibrary.js +56 -0
- package/src/toolhelpers/_listModels.js +41 -0
- package/src/toolhelpers/_listTables.js +52 -0
- package/src/toolhelpers/_masDescribe.js +27 -0
- package/src/toolhelpers/_masScoring.js +64 -0
- package/src/toolhelpers/_readTable.js +69 -0
- package/src/toolhelpers/_scrInfo.js +32 -0
- package/src/toolhelpers/_scrScore.js +49 -0
- package/src/toolhelpers/_submitCasl.js +34 -0
- package/src/toolhelpers/_submitCode.js +96 -0
- package/src/toolhelpers/_submitMacro.js +24 -0
- package/src/toolhelpers/_tableColumns.js +61 -0
- package/src/toolhelpers/_tableInfo.js +72 -0
- package/src/toolhelpers/deleteSession.js +13 -0
- package/src/toolhelpers/getLogonPayload.js +100 -0
- package/src/toolhelpers/getOpts.js +43 -0
- package/src/toolhelpers/getOptsViya.js +38 -0
- package/src/toolhelpers/getStoreOpts.js +18 -0
- package/src/toolhelpers/getToken.js +40 -0
- package/src/toolhelpers/refreshToken.js +48 -0
- package/test/README.md +63 -0
- package/test/listLibraries.test.js +245 -0
- package/tool-developer-guide.md +80 -0
- package/types.js +25 -0
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright © 2025, SAS Institute Inc., Cary, NC, USA. All Rights Reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Test for list-libraries tool using raw HTTP calls to MCP protocol
|
|
8
|
+
* This test connects to an MCP server running at http://localhost:8080/mcp
|
|
9
|
+
* and calls the list-libraries tool using direct HTTP requests.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
//import fetch from 'undici';
|
|
13
|
+
|
|
14
|
+
const MCP_SERVER_URL = 'http://localhost:8080/mcp';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Make an MCP request using HTTP POST
|
|
18
|
+
*/
|
|
19
|
+
async function mcpRequest(method, params = {}) {
|
|
20
|
+
const request = {
|
|
21
|
+
jsonrpc: '2.0',
|
|
22
|
+
id: Date.now(),
|
|
23
|
+
method: method,
|
|
24
|
+
params: params
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const response = await fetch(MCP_SERVER_URL, {
|
|
28
|
+
method: 'POST',
|
|
29
|
+
headers: {
|
|
30
|
+
'Content-Type': 'application/json',
|
|
31
|
+
},
|
|
32
|
+
body: JSON.stringify(request)
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
if (!response.ok) {
|
|
36
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const data = await response.json();
|
|
40
|
+
|
|
41
|
+
if (data.error) {
|
|
42
|
+
throw new Error(`MCP error: ${data.error.message}`);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return data.result;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async function testListLibraries() {
|
|
49
|
+
console.log('='.repeat(60));
|
|
50
|
+
console.log('Testing list-libraries tool via MCP Protocol (HTTP)');
|
|
51
|
+
console.log('Server: ' + MCP_SERVER_URL);
|
|
52
|
+
console.log('='.repeat(60));
|
|
53
|
+
|
|
54
|
+
let testsPassed = 0;
|
|
55
|
+
let testsFailed = 0;
|
|
56
|
+
|
|
57
|
+
try {
|
|
58
|
+
// Test 1: Initialize connection (get server info)
|
|
59
|
+
console.log('\n[1] Initializing connection...');
|
|
60
|
+
try {
|
|
61
|
+
const initResult = await mcpRequest('initialize', {
|
|
62
|
+
protocolVersion: '2024-11-05',
|
|
63
|
+
capabilities: {},
|
|
64
|
+
clientInfo: {
|
|
65
|
+
name: 'test-client',
|
|
66
|
+
version: '1.0.0'
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
console.log('✓ Connected successfully');
|
|
70
|
+
console.log(` Server: ${initResult.serverInfo.name} v${initResult.serverInfo.version}`);
|
|
71
|
+
testsPassed++;
|
|
72
|
+
} catch (error) {
|
|
73
|
+
console.error('✗ Connection failed:', error.message);
|
|
74
|
+
testsFailed++;
|
|
75
|
+
throw error;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Test 2: List available tools
|
|
79
|
+
console.log('\n[2] Listing available tools...');
|
|
80
|
+
try {
|
|
81
|
+
const toolsList = await mcpRequest('tools/list', {});
|
|
82
|
+
console.log(`✓ Found ${toolsList.tools.length} tools`);
|
|
83
|
+
|
|
84
|
+
const listLibrariesTool = toolsList.tools.find(tool =>
|
|
85
|
+
tool.name.includes('sas-score-list-libraries')
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
if (!listLibrariesTool) {
|
|
89
|
+
console.error('✗ list-libraries tool not found');
|
|
90
|
+
testsFailed++;
|
|
91
|
+
throw new Error('list-libraries tool not found');
|
|
92
|
+
} else {
|
|
93
|
+
console.log(`✓ Found tool: ${listLibrariesTool.name}`);
|
|
94
|
+
testsPassed++;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Store tool name for subsequent tests
|
|
98
|
+
global.listLibrariesToolName = listLibrariesTool.name;
|
|
99
|
+
} catch (error) {
|
|
100
|
+
console.error('✗ Error listing tools:', error.message);
|
|
101
|
+
testsFailed++;
|
|
102
|
+
throw error;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Test 3: List CAS libraries with defaults
|
|
106
|
+
console.log('\n[3] Test: List CAS libraries (default parameters)');
|
|
107
|
+
try {
|
|
108
|
+
const result = await mcpRequest('tools/call', {
|
|
109
|
+
name: global.listLibrariesToolName,
|
|
110
|
+
arguments: {}
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
console.log('Response:', JSON.stringify(result, null, 2));
|
|
114
|
+
|
|
115
|
+
if (result.isError) {
|
|
116
|
+
console.error('✗ Request returned error');
|
|
117
|
+
testsFailed++;
|
|
118
|
+
} else {
|
|
119
|
+
console.log('✓ Successfully listed CAS libraries');
|
|
120
|
+
testsPassed++;
|
|
121
|
+
}
|
|
122
|
+
} catch (error) {
|
|
123
|
+
console.error('✗ Error:', error.message);
|
|
124
|
+
testsFailed++;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Test 4: List CAS libraries with custom limit
|
|
128
|
+
console.log('\n[4] Test: List CAS libraries with limit=5');
|
|
129
|
+
try {
|
|
130
|
+
const result = await mcpRequest('tools/call', {
|
|
131
|
+
name: global.listLibrariesToolName,
|
|
132
|
+
arguments: {
|
|
133
|
+
server: 'cas',
|
|
134
|
+
limit: 5
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
console.log('Response:', JSON.stringify(result, null, 2));
|
|
139
|
+
|
|
140
|
+
if (result.isError) {
|
|
141
|
+
console.error('✗ Request returned error');
|
|
142
|
+
testsFailed++;
|
|
143
|
+
} else {
|
|
144
|
+
console.log('✓ Successfully listed CAS libraries with limit');
|
|
145
|
+
testsPassed++;
|
|
146
|
+
}
|
|
147
|
+
} catch (error) {
|
|
148
|
+
console.error('✗ Error:', error.message);
|
|
149
|
+
testsFailed++;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Test 5: List SAS libraries
|
|
153
|
+
console.log('\n[5] Test: List SAS libraries');
|
|
154
|
+
try {
|
|
155
|
+
const result = await mcpRequest('tools/call', {
|
|
156
|
+
name: global.listLibrariesToolName,
|
|
157
|
+
arguments: {
|
|
158
|
+
server: 'sas'
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
console.log('Response:', JSON.stringify(result, null, 2));
|
|
163
|
+
|
|
164
|
+
if (result.isError) {
|
|
165
|
+
console.error('✗ Request returned error');
|
|
166
|
+
testsFailed++;
|
|
167
|
+
} else {
|
|
168
|
+
console.log('✓ Successfully listed SAS libraries');
|
|
169
|
+
testsPassed++;
|
|
170
|
+
}
|
|
171
|
+
} catch (error) {
|
|
172
|
+
console.error('✗ Error:', error.message);
|
|
173
|
+
testsFailed++;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Test 6: List libraries with pagination
|
|
177
|
+
console.log('\n[6] Test: List libraries with pagination (start=1, limit=3)');
|
|
178
|
+
try {
|
|
179
|
+
const result = await mcpRequest('tools/call', {
|
|
180
|
+
name: global.listLibrariesToolName,
|
|
181
|
+
arguments: {
|
|
182
|
+
server: 'cas',
|
|
183
|
+
start: 1,
|
|
184
|
+
limit: 3
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
console.log('Response:', JSON.stringify(result, null, 2));
|
|
189
|
+
|
|
190
|
+
if (result.isError) {
|
|
191
|
+
console.error('✗ Request returned error');
|
|
192
|
+
testsFailed++;
|
|
193
|
+
} else {
|
|
194
|
+
console.log('✓ Successfully listed libraries with pagination');
|
|
195
|
+
testsPassed++;
|
|
196
|
+
}
|
|
197
|
+
} catch (error) {
|
|
198
|
+
console.error('✗ Error:', error.message);
|
|
199
|
+
testsFailed++;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Test 7: Case normalization (uppercase server param)
|
|
203
|
+
console.log('\n[7] Test: Server parameter normalization (CAS → cas)');
|
|
204
|
+
try {
|
|
205
|
+
const result = await mcpRequest('tools/call', {
|
|
206
|
+
name: global.listLibrariesToolName,
|
|
207
|
+
arguments: {
|
|
208
|
+
server: 'CAS',
|
|
209
|
+
limit: 3
|
|
210
|
+
}
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
console.log('Response:', JSON.stringify(result, null, 2));
|
|
214
|
+
|
|
215
|
+
if (result.isError) {
|
|
216
|
+
console.error('✗ Request returned error');
|
|
217
|
+
testsFailed++;
|
|
218
|
+
} else {
|
|
219
|
+
console.log('✓ Successfully normalized server parameter');
|
|
220
|
+
testsPassed++;
|
|
221
|
+
}
|
|
222
|
+
} catch (error) {
|
|
223
|
+
console.error('✗ Error:', error.message);
|
|
224
|
+
testsFailed++;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
} catch (error) {
|
|
228
|
+
console.error('\n✗ Fatal error:', error);
|
|
229
|
+
testsFailed++;
|
|
230
|
+
} finally {
|
|
231
|
+
// Summary
|
|
232
|
+
console.log('\n' + '='.repeat(60));
|
|
233
|
+
console.log('TEST SUMMARY');
|
|
234
|
+
console.log('='.repeat(60));
|
|
235
|
+
console.log(`Tests Passed: ${testsPassed}`);
|
|
236
|
+
console.log(`Tests Failed: ${testsFailed}`);
|
|
237
|
+
console.log(`Total Tests: ${testsPassed + testsFailed}`);
|
|
238
|
+
console.log('='.repeat(60));
|
|
239
|
+
|
|
240
|
+
process.exit(testsFailed > 0 ? 1 : 0);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// Run the test
|
|
245
|
+
testListLibraries();
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# Instructions for modifying or adding new tools
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
## src/toolset
|
|
6
|
+
|
|
7
|
+
This folder contains all the tools defined. The tools must conform to the MCP standards.
|
|
8
|
+
The mcp server will add the branding prefix to the tools. By default it is `sas-score-`.
|
|
9
|
+
|
|
10
|
+
> If you wish to change the branding, edit cli.js and replace the constant BRAND with your own brand.
|
|
11
|
+
Do not specify the branding in the tool definition
|
|
12
|
+
|
|
13
|
+
> See TOOL_DESCRIPTION_TEMPLATE for recommendations on how to write the description for a tool. And obviously this
|
|
14
|
+
document was created with the help of LLM.
|
|
15
|
+
|
|
16
|
+
### Parameters to a tool helper
|
|
17
|
+
|
|
18
|
+
The params to a tool handler is determined by the LLM based on the description of the tool.
|
|
19
|
+
|
|
20
|
+
In this library that params object is extended with the *_appContext* object.
|
|
21
|
+
|
|
22
|
+
A typical handler in the tool spec will now look like this:
|
|
23
|
+
|
|
24
|
+
```js
|
|
25
|
+
{...
|
|
26
|
+
handler: async (params) => {
|
|
27
|
+
let {a,b, _appContext} = params;
|
|
28
|
+
...rest of the code...
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
See the files in src/toolHelpers folder for more examples
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
### src/toolHelpers
|
|
36
|
+
|
|
37
|
+
All code related to handling the prompt request are defined in this folder. This is just a convention of the author and not a hard and fast rule.
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
The _appContext object is shown below
|
|
42
|
+
|
|
43
|
+
```js
|
|
44
|
+
{
|
|
45
|
+
storeConfig: {},/* for restaf users */
|
|
46
|
+
viyaCert: {} /* object with ssl/tsl certificates to connect to viya */
|
|
47
|
+
logonPayload: {}/* viya logon payload to connect to viya */
|
|
48
|
+
sas: string, /* 'SAS compute context' - default: SAS Job Execution compute context */
|
|
49
|
+
cas: string /* name of the cas server (default: cas-shared-default*/,
|
|
50
|
+
ext: {} /* place for tool developers to store information */
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
The logonPayload object has the following information based on the AUTHFLOW value
|
|
55
|
+
|
|
56
|
+
#### AUTHTYPE=sascli|token
|
|
57
|
+
```js
|
|
58
|
+
{
|
|
59
|
+
host: string, /* current Viya Server URL*/
|
|
60
|
+
authType: string /* for restaf users */
|
|
61
|
+
token: string, /* current token */
|
|
62
|
+
tokenType: 'Bearer'
|
|
63
|
+
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
#### AUTHTYPE=pasword
|
|
68
|
+
|
|
69
|
+
```js
|
|
70
|
+
{
|
|
71
|
+
host: viya-host-url
|
|
72
|
+
authType: "password",
|
|
73
|
+
user: string,
|
|
74
|
+
password: string,
|
|
75
|
+
clientID: clientid,
|
|
76
|
+
clientSecret: clientsecret
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
|
package/types.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* logonPayload
|
|
3
|
+
* @typedef {Object} logonPayload
|
|
4
|
+
* @property {string} host - the SAS VIya URL
|
|
5
|
+
* @property {string} auth_type - The authentication type (for restaf users).
|
|
6
|
+
* @property {string} token - The authentication token.
|
|
7
|
+
* @property {string} tokenType - The type of the token (e.g., Bearer).
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* _appContext
|
|
12
|
+
* @typedef {Object} _appContext
|
|
13
|
+
* @property {Object} store - restaf store instance.(for restaf users)
|
|
14
|
+
* @property {Object} storeConfig - Configuration for the restaf store.
|
|
15
|
+
* @property {Object} casSession - restaf cas session instance.(for restaf users)
|
|
16
|
+
* @property {Object} computeSession - restaf compute session instance.(for restaf users)
|
|
17
|
+
* @property {Object} viyaCert - SSL/TSL certificate information.
|
|
18
|
+
* @property {logonPayload} logonPayload - kogonPayload object
|
|
19
|
+
* @property {string|null} casServerId - cas server id. Default is null.(future)
|
|
20
|
+
* @property {string|null} computeServerId - compute server id. Default is null(future).
|
|
21
|
+
* @property {string|null} sas - SAS compute contextModel
|
|
22
|
+
* @property {Object|null} cas - cas server name
|
|
23
|
+
* @property {Object} ext - Additional extensions that a developer may want to add.
|
|
24
|
+
*/
|
|
25
|
+
|