@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,157 @@
|
|
|
1
|
+
# Tool Description Template
|
|
2
|
+
|
|
3
|
+
This template standardizes how all tool descriptions should be written in the MCP Server project. Every tool should follow this structure.
|
|
4
|
+
|
|
5
|
+
## Template Format
|
|
6
|
+
|
|
7
|
+
```javascript
|
|
8
|
+
function toolName(_appContext) {
|
|
9
|
+
let description = `
|
|
10
|
+
## toolName — brief one-line description
|
|
11
|
+
|
|
12
|
+
LLM Invocation Guidance (When to use)
|
|
13
|
+
Use THIS tool when:
|
|
14
|
+
- User request example 1
|
|
15
|
+
- User request example 2
|
|
16
|
+
- User request example 3
|
|
17
|
+
|
|
18
|
+
Do NOT use this tool for:
|
|
19
|
+
- When to use tool X instead
|
|
20
|
+
- When to use tool Y instead
|
|
21
|
+
- Common misconceptions
|
|
22
|
+
|
|
23
|
+
Purpose
|
|
24
|
+
Clear explanation of what this tool does and why someone would use it. Can be 1-3 sentences.
|
|
25
|
+
|
|
26
|
+
Parameters
|
|
27
|
+
[If tool has no required parameters, state "This tool requires no parameters."]
|
|
28
|
+
- paramName (type, default value): Description of what this parameter does and any constraints.
|
|
29
|
+
- anotherParam (type): Required parameter. Description of what it does.
|
|
30
|
+
|
|
31
|
+
Response Contract
|
|
32
|
+
Describe the format and structure of the response. Include:
|
|
33
|
+
- The top-level structure (object, array, etc.)
|
|
34
|
+
- Key fields in the response
|
|
35
|
+
- Possible error conditions
|
|
36
|
+
- Example response structure
|
|
37
|
+
|
|
38
|
+
Disambiguation & Clarification
|
|
39
|
+
- If user says "X" but might mean "Y" → clarify with: "Did you mean...?"
|
|
40
|
+
- If parameter is ambiguous → explain how to handle missing/unclear values
|
|
41
|
+
- List common confusion points with other similar tools
|
|
42
|
+
|
|
43
|
+
Examples (→ mapped params)
|
|
44
|
+
Real-world examples showing user input and how parameters map:
|
|
45
|
+
- "user request example 1" → { param1: "value", param2: 10 }
|
|
46
|
+
- "user request example 2" → { param1: "value" }
|
|
47
|
+
|
|
48
|
+
Negative Examples (should NOT call toolName)
|
|
49
|
+
- "user request that should use tool X" (use toolX instead)
|
|
50
|
+
- "another incorrect usage" (use toolY instead)
|
|
51
|
+
|
|
52
|
+
Related Tools
|
|
53
|
+
Link to other tools in the workflow:
|
|
54
|
+
- First step: listSomething or findSomething
|
|
55
|
+
- Get details: infoTool or detailTool
|
|
56
|
+
- Take action: actionTool or executeTool
|
|
57
|
+
`;
|
|
58
|
+
|
|
59
|
+
let spec = {
|
|
60
|
+
name: 'toolName',
|
|
61
|
+
description: description,
|
|
62
|
+
schema: {
|
|
63
|
+
'paramName': z.string(),
|
|
64
|
+
'anotherParam': z.number().default(10)
|
|
65
|
+
},
|
|
66
|
+
required: ['paramName'],
|
|
67
|
+
handler: async (params) => {
|
|
68
|
+
let r = await _helperFunction(params);
|
|
69
|
+
return r;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return spec;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export default toolName;
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Section Guidelines
|
|
80
|
+
|
|
81
|
+
### LLM Invocation Guidance
|
|
82
|
+
- List 3-5 specific user request patterns that would trigger this tool
|
|
83
|
+
- Use quotes for actual user phrases: `"find model X"`, `"list models"`
|
|
84
|
+
- List 2-4 common misconceptions or tools to use instead
|
|
85
|
+
- Be explicit: "Use THIS tool when..." and "Do NOT use this tool for..."
|
|
86
|
+
|
|
87
|
+
### Purpose
|
|
88
|
+
- 1-3 sentences maximum
|
|
89
|
+
- Explain the business value, not just the mechanics
|
|
90
|
+
- Can reference other tools if relevant
|
|
91
|
+
|
|
92
|
+
### Parameters
|
|
93
|
+
- **Format**: `paramName (type, default): description`
|
|
94
|
+
- Include all parameters (required and optional)
|
|
95
|
+
- Specify defaults clearly
|
|
96
|
+
- Add constraints if applicable: `(1-100)`, `(required)`, `(optional)`, `(read-only)`
|
|
97
|
+
- Be specific about what values are valid
|
|
98
|
+
|
|
99
|
+
### Response Contract
|
|
100
|
+
- Describe JSON structure the LLM will receive
|
|
101
|
+
- Include key field names and their types
|
|
102
|
+
- Mention empty/null cases
|
|
103
|
+
- If applicable, show example response
|
|
104
|
+
|
|
105
|
+
### Disambiguation & Clarification
|
|
106
|
+
- Format as bullet points with possible user input and clarification
|
|
107
|
+
- Include exact clarification question to ask (in quotes)
|
|
108
|
+
- Mention edge cases
|
|
109
|
+
|
|
110
|
+
### Examples
|
|
111
|
+
- Format as: `"user phrase" → { param: "value" }`
|
|
112
|
+
- Show 3-5 real-world examples
|
|
113
|
+
- Include examples with different parameter combinations
|
|
114
|
+
- Must demonstrate parameter mapping clearly
|
|
115
|
+
|
|
116
|
+
### Negative Examples
|
|
117
|
+
- Format as: `"incorrect user request" (use toolX instead)`
|
|
118
|
+
- Show 2-3 common mistakes
|
|
119
|
+
- Always specify which tool to use instead
|
|
120
|
+
|
|
121
|
+
### Related Tools
|
|
122
|
+
- Show workflow chains: listThing → findThing → infoThing → actionThing
|
|
123
|
+
- Mention which tools come before/after in typical usage
|
|
124
|
+
|
|
125
|
+
## Tone & Style Guidelines
|
|
126
|
+
|
|
127
|
+
1. **Be specific**: Use actual examples and parameter values, not abstractions
|
|
128
|
+
2. **Be explicit**: Say "Use THIS tool when" not "Can be used when"
|
|
129
|
+
3. **Be practical**: Focus on when/how LLMs should invoke the tool
|
|
130
|
+
4. **Be complete**: Include all parameters and all guidance sections
|
|
131
|
+
5. **Be concise**: Keep descriptions focused and avoid redundancy
|
|
132
|
+
|
|
133
|
+
## Validation Checklist
|
|
134
|
+
|
|
135
|
+
Before marking a tool as conforming to the template:
|
|
136
|
+
|
|
137
|
+
- [ ] Has "LLM Invocation Guidance" section with "Use THIS" and "Do NOT"
|
|
138
|
+
- [ ] Has "Purpose" section explaining what the tool does
|
|
139
|
+
- [ ] Has "Parameters" section documenting all params with types and defaults
|
|
140
|
+
- [ ] Has "Response Contract" describing the response format
|
|
141
|
+
- [ ] Has "Disambiguation & Clarification" section
|
|
142
|
+
- [ ] Has "Examples" section with 3+ real-world examples showing param mapping
|
|
143
|
+
- [ ] Has "Negative Examples" section with 2+ examples of what NOT to do
|
|
144
|
+
- [ ] Has "Related Tools" section showing workflow context (if applicable)
|
|
145
|
+
- [ ] Uses markdown formatting properly (## headers, - bullets, `code`)
|
|
146
|
+
- [ ] Consistent formatting across all sections
|
|
147
|
+
|
|
148
|
+
## Tools Updated to Template
|
|
149
|
+
|
|
150
|
+
- [x] listModels.js - ✅ Already conforms
|
|
151
|
+
- [x] findModel.js - 🔧 Needs cleanup (remove redundancy)
|
|
152
|
+
- [ ] deval.js - 🔧 Needs major expansion
|
|
153
|
+
- [ ] devaScore.js - 🔧 Needs expansion
|
|
154
|
+
- [ ] setContext.js - 🔧 Needs expansion
|
|
155
|
+
- [ ] modelInfo.js - 🔧 Needs expansion
|
|
156
|
+
- [ ] readTable.js - ✅ Mostly conforms (minor tweaks)
|
|
157
|
+
- [ ] ... (other tools)
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
# Tool Description Standardization - Update Summary
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
All tool descriptions have been standardized to follow a consistent template format. This ensures:
|
|
5
|
+
- Clear, explicit "when to use" guidance for LLMs
|
|
6
|
+
- Consistent structure across all tools
|
|
7
|
+
- Comprehensive parameter and response documentation
|
|
8
|
+
- Real-world examples with parameter mappings
|
|
9
|
+
- Negative examples showing what NOT to do
|
|
10
|
+
- Related tools showing workflow context
|
|
11
|
+
|
|
12
|
+
## Template Reference
|
|
13
|
+
See `TOOL_DESCRIPTION_TEMPLATE.md` for the complete template specification and validation checklist.
|
|
14
|
+
|
|
15
|
+
## Tools Updated
|
|
16
|
+
|
|
17
|
+
### ✅ Tools Fully Conforming to Template
|
|
18
|
+
|
|
19
|
+
#### Major Updates (5 tools)
|
|
20
|
+
|
|
21
|
+
1. **findModel.js** - Cleaned up and standardized
|
|
22
|
+
- ✂️ Removed redundant JSON metadata object
|
|
23
|
+
- ✂️ Removed confusing/error lines (41-47) that listed find lib/table/job incorrectly
|
|
24
|
+
- ✅ Now has all required template sections
|
|
25
|
+
- ✅ Clear LLM invocation guidance
|
|
26
|
+
|
|
27
|
+
2. **deval.js** - Expanded from 2 lines to comprehensive format
|
|
28
|
+
- ➕ Added "LLM Invocation Guidance" section with 4 use cases
|
|
29
|
+
- ➕ Added "Do NOT use this tool for" section (4 items)
|
|
30
|
+
- ➕ Added clear "Purpose" statement
|
|
31
|
+
- ➕ Added "Parameters" documentation
|
|
32
|
+
- ➕ Added "Response Contract" describing return format
|
|
33
|
+
- ➕ Added "Disambiguation & Clarification" section
|
|
34
|
+
- ➕ Added 3 real-world "Examples" with parameter mappings
|
|
35
|
+
- ➕ Added "Negative Examples" section
|
|
36
|
+
- ➕ Added "Related Tools" section
|
|
37
|
+
|
|
38
|
+
3. **setContext.js** - Expanded with comprehensive guidance
|
|
39
|
+
- ➕ Added "LLM Invocation Guidance" section with 4 use cases
|
|
40
|
+
- ➕ Added "Do NOT use" section
|
|
41
|
+
- ➕ Added detailed "Purpose" explaining session context switching
|
|
42
|
+
- ➕ Enhanced "Parameters" with real server examples
|
|
43
|
+
- ➕ Added "Response Contract" with detailed structure
|
|
44
|
+
- ➕ Added "Disambiguation & Clarification" for edge cases
|
|
45
|
+
- ➕ Added 4 real-world "Examples" with parameter mappings
|
|
46
|
+
- ➕ Added "Negative Examples" section
|
|
47
|
+
- ➕ Added "Related Tools" section
|
|
48
|
+
|
|
49
|
+
4. **devaScore.js** - Reformatted with template structure
|
|
50
|
+
- 🔄 Restructured from instruction-heavy to template format
|
|
51
|
+
- ➕ Added "LLM Invocation Guidance" section
|
|
52
|
+
- ➕ Added "Do NOT use" section
|
|
53
|
+
- ➕ Added clear parameter documentation
|
|
54
|
+
- ➕ Added "Response Contract" section
|
|
55
|
+
- ➕ Added "Examples" and "Negative Examples" sections
|
|
56
|
+
- ➕ Added "Notes" section explaining left-to-right fold
|
|
57
|
+
|
|
58
|
+
5. **modelInfo.js** - Expanded with comprehensive structure
|
|
59
|
+
- ➕ Added "LLM Invocation Guidance" with 4 use cases
|
|
60
|
+
- ➕ Added "Do NOT use" section
|
|
61
|
+
- ➕ Enhanced "Purpose" statement
|
|
62
|
+
- ➕ Added detailed "Response Contract" describing metadata fields
|
|
63
|
+
- ➕ Added "Disambiguation & Clarification" section
|
|
64
|
+
- ➕ Added 4 real-world "Examples" with parameter mappings
|
|
65
|
+
- ➕ Added "Negative Examples" section
|
|
66
|
+
- ➕ Added "Related Tools" showing workflow chain
|
|
67
|
+
|
|
68
|
+
#### Moderate Updates (1 tool)
|
|
69
|
+
|
|
70
|
+
6. **readTable.js** - Enhanced to fully conform to template
|
|
71
|
+
- 🔄 Restructured sections for template consistency
|
|
72
|
+
- ➕ Enhanced "LLM Invocation Guidance" with 5 specific use cases
|
|
73
|
+
- ➕ Improved "Do NOT use" section with explanation
|
|
74
|
+
- ➕ Clarified "Parameters" format and added constraints
|
|
75
|
+
- 🔄 Renamed "Output" to "Response Contract" per template
|
|
76
|
+
- ➕ Added "Pagination & Filtering" section with examples
|
|
77
|
+
- ➕ Enhanced "Examples" with 5 detailed parameter mappings
|
|
78
|
+
- ➕ Added comprehensive "Related Tools" section
|
|
79
|
+
|
|
80
|
+
#### Already Conforming (1 tool)
|
|
81
|
+
|
|
82
|
+
7. **listModels.js** - ✅ Already fully compliant
|
|
83
|
+
- Already had comprehensive template format
|
|
84
|
+
- No changes needed
|
|
85
|
+
|
|
86
|
+
## Template Sections Included in All Updated Tools
|
|
87
|
+
|
|
88
|
+
### 1. LLM Invocation Guidance (When to use)
|
|
89
|
+
Explicit "Use THIS tool when" bullet points with real user phrases. Typically 3-5 examples.
|
|
90
|
+
|
|
91
|
+
### 2. Do NOT use this tool for
|
|
92
|
+
Clear list of what NOT to do and which tools to use instead. Prevents misuse.
|
|
93
|
+
|
|
94
|
+
### 3. Purpose
|
|
95
|
+
1-3 sentence explanation of what the tool does and why.
|
|
96
|
+
|
|
97
|
+
### 4. Parameters
|
|
98
|
+
- Name, type, default value, and description for each parameter
|
|
99
|
+
- Constraints and valid value ranges where applicable
|
|
100
|
+
- Required vs optional clearly indicated
|
|
101
|
+
|
|
102
|
+
### 5. Response Contract
|
|
103
|
+
- JSON structure of the response
|
|
104
|
+
- Key fields and their types
|
|
105
|
+
- Edge cases (empty, null, errors)
|
|
106
|
+
- Example response format
|
|
107
|
+
|
|
108
|
+
### 6. Disambiguation & Clarification
|
|
109
|
+
- How to handle missing parameters
|
|
110
|
+
- How to clarify ambiguous requests
|
|
111
|
+
- Exact clarification questions to ask
|
|
112
|
+
|
|
113
|
+
### 7. Examples (→ mapped params)
|
|
114
|
+
- Real-world user phrases
|
|
115
|
+
- Parameter mappings shown
|
|
116
|
+
- Includes various parameter combinations
|
|
117
|
+
- Format: `"user input" → { param: value }`
|
|
118
|
+
|
|
119
|
+
### 8. Negative Examples (should NOT call toolName)
|
|
120
|
+
- Common mistakes showing what NOT to do
|
|
121
|
+
- Specifies which tool to use instead
|
|
122
|
+
- Format: `"bad request" (use toolX instead)`
|
|
123
|
+
|
|
124
|
+
### 9. Related Tools
|
|
125
|
+
- Workflow chains showing which tools work together
|
|
126
|
+
- Dependencies and typical call sequences
|
|
127
|
+
- Links to prerequisite/follow-up tools
|
|
128
|
+
|
|
129
|
+
## Statistics
|
|
130
|
+
|
|
131
|
+
| Metric | Count |
|
|
132
|
+
|--------|-------|
|
|
133
|
+
| Tools with major updates | 5 |
|
|
134
|
+
| Tools with moderate updates | 1 |
|
|
135
|
+
| Tools already conforming | 1 |
|
|
136
|
+
| Total tools standardized | 7 |
|
|
137
|
+
| Template file created | 1 |
|
|
138
|
+
|
|
139
|
+
## Key Improvements
|
|
140
|
+
|
|
141
|
+
### Consistency
|
|
142
|
+
- All tools now follow the same structure
|
|
143
|
+
- Uniform formatting and section ordering
|
|
144
|
+
- Consistent tone and style
|
|
145
|
+
|
|
146
|
+
### Clarity
|
|
147
|
+
- Explicit "when to use" guidance for LLMs
|
|
148
|
+
- Clear parameter documentation with types and defaults
|
|
149
|
+
- Real-world examples instead of abstractions
|
|
150
|
+
|
|
151
|
+
### Completeness
|
|
152
|
+
- All tools include negative examples
|
|
153
|
+
- All tools explain related tools/workflows
|
|
154
|
+
- All tools have response contracts
|
|
155
|
+
|
|
156
|
+
### Usability
|
|
157
|
+
- LLMs can understand tool purpose immediately
|
|
158
|
+
- Clear disambiguation guidance for edge cases
|
|
159
|
+
- Parameter mappings prevent incorrect invocations
|
|
160
|
+
|
|
161
|
+
## Files Modified
|
|
162
|
+
|
|
163
|
+
1. `src/toolSet/findModel.js` - Cleaned up redundancy
|
|
164
|
+
2. `src/toolSet/deval.js` - Expanded description (2 → 47 lines)
|
|
165
|
+
3. `src/toolSet/setContext.js` - Expanded description (9 → 60 lines)
|
|
166
|
+
4. `src/toolSet/devaScore.js` - Reformatted (12 → 54 lines)
|
|
167
|
+
5. `src/toolSet/modelInfo.js` - Expanded description (12 → 69 lines)
|
|
168
|
+
6. `src/toolSet/readTable.js` - Enhanced description (56 → 80 lines)
|
|
169
|
+
|
|
170
|
+
## Files Created
|
|
171
|
+
|
|
172
|
+
1. `TOOL_DESCRIPTION_TEMPLATE.md` - Master template specification
|
|
173
|
+
2. `TOOL_UPDATES_SUMMARY.md` - This file
|
|
174
|
+
|
|
175
|
+
## Next Steps (Optional)
|
|
176
|
+
|
|
177
|
+
Consider updating remaining tools in the toolSet directory to match this template:
|
|
178
|
+
- `listTables.js` - Already fairly complete, minor tweaks possible
|
|
179
|
+
- `listLibraries.js`
|
|
180
|
+
- `listJobs.js`
|
|
181
|
+
- `findJob.js`
|
|
182
|
+
- `findLibrary.js`
|
|
183
|
+
- `findTable.js`
|
|
184
|
+
- `job.js`
|
|
185
|
+
- `jobdef.js`
|
|
186
|
+
- `tableInfo.js`
|
|
187
|
+
- `program.js`
|
|
188
|
+
- `sasQuery.js`
|
|
189
|
+
- `modelScore.js`
|
|
190
|
+
- `scrInfo.js`
|
|
191
|
+
- `scrScore.js`
|
|
192
|
+
- And any others...
|
|
193
|
+
|
|
194
|
+
## Validation Checklist
|
|
195
|
+
|
|
196
|
+
To verify a tool conforms to the template, check:
|
|
197
|
+
|
|
198
|
+
- [ ] Has "LLM Invocation Guidance" section with "Use THIS tool when" list
|
|
199
|
+
- [ ] Has "Do NOT use this tool for" section with specific alternatives
|
|
200
|
+
- [ ] Has "Purpose" section explaining what the tool does
|
|
201
|
+
- [ ] Has "Parameters" section with type, default, and description for each param
|
|
202
|
+
- [ ] Has "Response Contract" describing the return format
|
|
203
|
+
- [ ] Has "Disambiguation & Clarification" section for edge cases
|
|
204
|
+
- [ ] Has "Examples (→ mapped params)" section with 3+ real-world examples
|
|
205
|
+
- [ ] Has "Negative Examples (should NOT call...)" section with what NOT to do
|
|
206
|
+
- [ ] Has "Related Tools" section showing workflow context
|
|
207
|
+
- [ ] Uses proper markdown formatting (## headers, - bullets, `code`)
|
|
208
|
+
- [ ] Consistent formatting and tone throughout
|
package/cli.js
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/*
|
|
3
|
+
* Copyright © 2025, SAS Institute Inc., Cary, NC, USA. All Rights Reserved.
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// Main entry point for MCP server
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
import coreSSE from './src/coreSSE.js';
|
|
11
|
+
import corehttp from './src/corehttp.js';
|
|
12
|
+
import createMcpServer from './src/createMcpServer.js';
|
|
13
|
+
import { config } from 'dotenv';
|
|
14
|
+
// import dotenvExpand from 'dotenv-expand';
|
|
15
|
+
import fs from 'fs';
|
|
16
|
+
import { randomUUID } from 'node:crypto';
|
|
17
|
+
|
|
18
|
+
import refreshToken from './src/toolHelpers/refreshToken.js';
|
|
19
|
+
import getOptsViya from './src/toolHelpers/getOptsViya.js';
|
|
20
|
+
|
|
21
|
+
import { fileURLToPath } from 'url';
|
|
22
|
+
import { dirname } from 'path';
|
|
23
|
+
|
|
24
|
+
import NodeCache from 'node-cache';
|
|
25
|
+
|
|
26
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
27
|
+
|
|
28
|
+
let pkg = fs.readFileSync(__dirname + '/package.json', 'utf8');
|
|
29
|
+
|
|
30
|
+
/********************************* */
|
|
31
|
+
const BRAND = 'sas-score'
|
|
32
|
+
/********************************* */
|
|
33
|
+
let pkgJson = JSON.parse(pkg);
|
|
34
|
+
let version = pkgJson.version;
|
|
35
|
+
let mcpType = process.env.MCPTYPE || 'http';
|
|
36
|
+
console.error(
|
|
37
|
+
`\nStarting MCP ServerJS - Version: ${pkgJson.version} - ${new Date().toISOString()}\n
|
|
38
|
+
brand: ${process.env.BRAND || BRAND}\n
|
|
39
|
+
mcpType: ${mcpType}\n
|
|
40
|
+
viyaServer: ${process.env.VIYA_SERVER}\n`
|
|
41
|
+
);
|
|
42
|
+
// session sessionCache
|
|
43
|
+
// For more robust caching consider products like Redis
|
|
44
|
+
// and storage provided by cloud providers
|
|
45
|
+
|
|
46
|
+
debugger;
|
|
47
|
+
let sessionCache = new NodeCache({ stdTTL: 0, checkperiod: 2 * 60, useClones: false });
|
|
48
|
+
|
|
49
|
+
//
|
|
50
|
+
// Load environment variables from .env file if present
|
|
51
|
+
// swithching to:
|
|
52
|
+
// stdio: set the env in the mcp config
|
|
53
|
+
// http: use dotenv-cli to load env before starting the mcp server
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
// need to tell core what transport to use(http or stdio)
|
|
57
|
+
|
|
58
|
+
// subclasses for sasQuery tool (special use case)
|
|
59
|
+
// to be replaced by the planned adding external tool definition capability
|
|
60
|
+
|
|
61
|
+
let subclassJson = [];
|
|
62
|
+
if (process.env.SUBCLASS != null) {
|
|
63
|
+
console.error(`Using subclass: ${process.env.SUBCLASS}`);
|
|
64
|
+
let subclass = process.env.SUBCLASS;
|
|
65
|
+
if (fs.existsSync(subclass)) {
|
|
66
|
+
console.error(`Loading subclass information from ${subclass}...`);
|
|
67
|
+
let s = fs.readFileSync(subclass, 'utf8');
|
|
68
|
+
subclassJson = JSON.parse(s);
|
|
69
|
+
console.error(`Loaded subclass: ${JSON.stringify(subclassJson, null, 2)}`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
// setup base appEnv
|
|
73
|
+
// for stdio this is the _appContext
|
|
74
|
+
// for http each session a copy of this as appEnvTemplate is created in corehttp
|
|
75
|
+
const appEnvBase = {
|
|
76
|
+
version: version,
|
|
77
|
+
mcpType: mcpType,
|
|
78
|
+
brand: (process.env.BRAND == null) ? BRAND : process.env.BRAND,
|
|
79
|
+
HTTPS:
|
|
80
|
+
process.env.HTTPS != null && process.env.HTTPS.toUpperCase() === 'TRUE'
|
|
81
|
+
? true
|
|
82
|
+
: false,
|
|
83
|
+
SAS_CLI_PROFILE: process.env.SAS_CLI_PROFILE || 'Default',
|
|
84
|
+
SAS_CLI_CONFIG: process.env.SAS_CLI_CONFIG || process.env.HOME, // default to user home directory
|
|
85
|
+
SSLCERT: process.env.SSLCERT || null,
|
|
86
|
+
VIYACERT: process.env.VIYACERT || null,
|
|
87
|
+
|
|
88
|
+
AUTHFLOW: process.env.AUTHFLOW || 'sascli',
|
|
89
|
+
VIYA_SERVER: process.env.VIYA_SERVER,
|
|
90
|
+
PORT: process.env.PORT || 8080,
|
|
91
|
+
USERNAME: process.env.USERNAME || null,
|
|
92
|
+
PASSWORD: process.env.PASSWORD || null,
|
|
93
|
+
CLIENTIDPW: process.env.CLIENTIDPW || null,
|
|
94
|
+
CLIENTSECRET: process.env.CLIENTSECRETPW || null,
|
|
95
|
+
TOKEN: process.env.TOKEN || null,
|
|
96
|
+
REFRESH_TOKEN: process.env.REFRESH_TOKEN || null,
|
|
97
|
+
TOKENFILE: process.env.TOKENFILE || null,
|
|
98
|
+
TLS_CREATE: process.env.TLS_CREATE || null,
|
|
99
|
+
SUBCLASS: process.env.SUBCLASS || null,
|
|
100
|
+
subclassJson: subclassJson,
|
|
101
|
+
// future use for controlling tool list using env variable
|
|
102
|
+
toolsets:
|
|
103
|
+
process.env.TOOLSETS != null
|
|
104
|
+
? process.env.TOOLSETS.split(',')
|
|
105
|
+
: ['default'],
|
|
106
|
+
// user defined tools
|
|
107
|
+
//runtime variables
|
|
108
|
+
tokenRefresh: process.env.TOKENREFRESH === 'FALSE' ? false : true,
|
|
109
|
+
tls: null,
|
|
110
|
+
refreshToken: null,
|
|
111
|
+
transports: {},
|
|
112
|
+
mcpServer: null,
|
|
113
|
+
viyaSessions: {},
|
|
114
|
+
store: null,
|
|
115
|
+
casServer: null,
|
|
116
|
+
casSessionId: null,
|
|
117
|
+
computeSessionId: null,
|
|
118
|
+
logonPayload: null,
|
|
119
|
+
bearerToken: null,
|
|
120
|
+
tlsOpts: null,
|
|
121
|
+
contexts: {
|
|
122
|
+
store: null, /* for restaf users */
|
|
123
|
+
storeConfig: {},
|
|
124
|
+
casSession: null, /* restaf cas session object */
|
|
125
|
+
computeSession: null, /* restaf compute session object */
|
|
126
|
+
viyaCert: null, /* ssl/tsl certificates to connect to viya */
|
|
127
|
+
logonPayload: null, /* viya logon payload to connect to viya */
|
|
128
|
+
casServerId: null,
|
|
129
|
+
computeSessonId: null,
|
|
130
|
+
sas: (process.env.COMPUTECONTEXT == null) ? 'SAS Job Execution compute context' : process.env.COMPUTECONTEXT,
|
|
131
|
+
cas: (process.env.CASSERVER == null) ? 'cas-shared-default' : process.env.CASSERVER,
|
|
132
|
+
ext: {} /* for additional extensions that a developer may want to add */
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
// setup TLS options for viya calls
|
|
137
|
+
|
|
138
|
+
console.error('[Note]Viya SSL dir set to: ' + appEnvBase.VIYACERT);
|
|
139
|
+
await getOptsViya(appEnvBase); /* appEnvBase.contexts.viyaCert is set here */
|
|
140
|
+
appEnvBase.contexts.storeConfig = {
|
|
141
|
+
casProxy: true,
|
|
142
|
+
options: { ns: null, proxyServer: null, httpOptions: appEnvBase.contexts.viyaCert }
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
if (appEnvBase.TOKENFILE != null) {
|
|
146
|
+
try {
|
|
147
|
+
console.error(`[Note]Loading token from file: ${appEnvBase.TOKENFILE}...`);
|
|
148
|
+
appEnvBase.TOKEN = fs.readFileSync(appEnvBase.TOKENFILE, { encoding: 'utf8' });
|
|
149
|
+
appEnvBase.AUTHFLOW = 'token';
|
|
150
|
+
appEnvBase.appContexts.logonPayload = {
|
|
151
|
+
host: appEnvBase.VIYA_SERVER,
|
|
152
|
+
authType: 'server',
|
|
153
|
+
token: appEnvBase.TOKEN,
|
|
154
|
+
tokenType: 'Bearer'
|
|
155
|
+
|
|
156
|
+
}
|
|
157
|
+
} catch (err) {
|
|
158
|
+
console.error(`[Error] Failed to read token file: ${err}`);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// handle refresh token flow
|
|
163
|
+
// use this for testing only.
|
|
164
|
+
if (appEnvBase.REFRESH_TOKEN != null) {
|
|
165
|
+
appEnvBase.refreshToken = appEnvBase.REFRESH_TOKEN;
|
|
166
|
+
appEnvBase.AUTHFLOW = 'refresh';
|
|
167
|
+
let t = await refreshToken(appEnvBase, { token: appEnvBase.REFRESH_TOKEN, host: appEnvBase.VIYA_SERVER });
|
|
168
|
+
appEnvBase.contexts.logonPayload = {
|
|
169
|
+
host: appEnvBase.VIYA_SERVER,
|
|
170
|
+
authType: 'server',
|
|
171
|
+
token: t,
|
|
172
|
+
tokenType: 'Bearer'
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// if authflow is cli, postpone getting logonPayload until needed
|
|
177
|
+
|
|
178
|
+
/*
|
|
179
|
+
if(appEnvBase.AUTHFLOW ==='sascli') {
|
|
180
|
+
let logonPayload = await getLogonPayload(appEnvBase);
|
|
181
|
+
appEnvBase.logonPayload = logonPayload;
|
|
182
|
+
}
|
|
183
|
+
*/
|
|
184
|
+
|
|
185
|
+
// setup mcpServer (both http and stdio use this)
|
|
186
|
+
// this is singleton - best practices recommend this
|
|
187
|
+
|
|
188
|
+
let mcpServer = await createMcpServer(sessionCache, appEnvBase);
|
|
189
|
+
|
|
190
|
+
sessionCache.set('appEnvBase', appEnvBase);
|
|
191
|
+
let appEnvTemplate = Object.assign({}, appEnvBase);
|
|
192
|
+
|
|
193
|
+
sessionCache.set('appEnvTemplate', appEnvTemplate);
|
|
194
|
+
|
|
195
|
+
let transports = {};
|
|
196
|
+
sessionCache.set('transports', transports);
|
|
197
|
+
|
|
198
|
+
// set this for stdio transport use
|
|
199
|
+
// dummy sessionId for use in the tools
|
|
200
|
+
if (mcpType === 'stdio') {
|
|
201
|
+
let sessionId = randomUUID();
|
|
202
|
+
sessionCache.set('currentId', sessionId);
|
|
203
|
+
sessionCache.set(sessionId, appEnvBase);
|
|
204
|
+
console.error('[Note] Setting up stdio transport with sessionId:', sessionId);
|
|
205
|
+
console.error('[Note] Used in setting up tools and some persistence(not all).');
|
|
206
|
+
await coreSSE(mcpServer);
|
|
207
|
+
|
|
208
|
+
} else {
|
|
209
|
+
console.error('[Note] Starting HTTP MCP server...');
|
|
210
|
+
await corehttp(mcpServer, sessionCache, appEnvBase);
|
|
211
|
+
console.error('[Note] MCP HTTP server started on port ' + appEnvBase.PORT);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
[
|
|
2
|
+
|
|
3
|
+
{
|
|
4
|
+
"name": "query-customer-usage",
|
|
5
|
+
"template": "sasQueryTemplate",
|
|
6
|
+
"table": "Public.gidb_current",
|
|
7
|
+
"selectColumns": "opsys, offering, product, rate, quantity, quantype, currency",
|
|
8
|
+
"columns": null,
|
|
9
|
+
"job": "run_sql_query",
|
|
10
|
+
"server": "cas"
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
]
|
package/labs/README.md
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"servers": {
|
|
3
|
+
"sasmcp": {
|
|
4
|
+
"type": "stdio",
|
|
5
|
+
"command": "npx",
|
|
6
|
+
"args": [
|
|
7
|
+
"@sassoftware/sas-score-mcp-serverjs"
|
|
8
|
+
],
|
|
9
|
+
"env": {
|
|
10
|
+
"MCPTYPE": "stdio",
|
|
11
|
+
"AUTHFLOW": "sascli",
|
|
12
|
+
"SAS_CLI_PROFILE": "cis",
|
|
13
|
+
"SAS_CLI_CONFIG": "c:\\Users\\kumar",
|
|
14
|
+
"SSLCERT": "c:\\Users\\kumar\\.tls",
|
|
15
|
+
"COMPUTECONTEXT": "SAS Job Execution compute context",
|
|
16
|
+
"CAS_SERVER": "cas-shared-default"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"servers": {
|
|
3
|
+
"sasmcp": {
|
|
4
|
+
"type": "stdio",
|
|
5
|
+
"command": "node",
|
|
6
|
+
"args": [
|
|
7
|
+
"c:\\dev\\gitlab\\mcp-serverjs\\cli.js"
|
|
8
|
+
],
|
|
9
|
+
"env": {
|
|
10
|
+
"MCPTYPE": "stdio",
|
|
11
|
+
"AUTHFLOW": "sascli",
|
|
12
|
+
"SAS_CLI_PROFILE": "cis",
|
|
13
|
+
"SAS_CLI_CONFIG": "c:\\Users\\kumar",
|
|
14
|
+
"SSLCERT": "c:\\Users\\kumar\\.tls",
|
|
15
|
+
"COMPUTECONTEXT": "SAS Job Execution compute context",
|
|
16
|
+
"CAS_SERVER": "cas-shared-default"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
package/mcpserver.png
ADDED
|
Binary file
|