@sassoftware/sas-score-mcp-serverjs 0.3.11 → 0.3.14
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/package.json +1 -1
- package/src/expressMcpServer.js +19 -11
- package/src/openAPIJson.js +12 -12
package/package.json
CHANGED
package/src/expressMcpServer.js
CHANGED
|
@@ -23,7 +23,7 @@ import { isInitializeRequest } from "@modelcontextprotocol/sdk/types.js";
|
|
|
23
23
|
|
|
24
24
|
async function expressMcpServer(mcpServer, cache, baseAppEnvContext) {
|
|
25
25
|
// setup for change to persistence session
|
|
26
|
-
|
|
26
|
+
cache.set("headerCache", {});
|
|
27
27
|
|
|
28
28
|
const app = express();
|
|
29
29
|
|
|
@@ -120,7 +120,7 @@ function requireBearer(req, res, next) {
|
|
|
120
120
|
headerCache.refreshToken = hdr2;
|
|
121
121
|
headerCache.AUTHFLOW = "refresh";
|
|
122
122
|
}
|
|
123
|
-
|
|
123
|
+
cache.set("headerCache", headerCache);
|
|
124
124
|
next();
|
|
125
125
|
}
|
|
126
126
|
|
|
@@ -128,15 +128,17 @@ function requireBearer(req, res, next) {
|
|
|
128
128
|
const handleRequest = async (req, res) => {
|
|
129
129
|
let transport;
|
|
130
130
|
let transports = cache.get("transports");
|
|
131
|
+
console.error("current transports in cache:", Object.keys(transports));
|
|
131
132
|
try {
|
|
132
133
|
|
|
133
134
|
let sessionId = req.headers["mcp-session-id"];
|
|
134
135
|
|
|
135
136
|
// we have session id, get existing transport
|
|
136
|
-
|
|
137
|
+
console.error('>>>>>>>>>>>>>> Received request for MCP endpoint with session ID:', req.method, sessionId);
|
|
137
138
|
if (sessionId != null) {
|
|
138
|
-
|
|
139
|
+
console.error("Looking for transport with session ID:", sessionId);
|
|
139
140
|
transport = transports[sessionId];
|
|
141
|
+
console.error("Found transport:", transport != null);
|
|
140
142
|
if (transport == null) {
|
|
141
143
|
throw new Error(`No transport found for session ID: ${sessionId}`);
|
|
142
144
|
}
|
|
@@ -151,23 +153,27 @@ const handleRequest = async (req, res) => {
|
|
|
151
153
|
if (_appContext == null) {
|
|
152
154
|
|
|
153
155
|
let appEnvTemplate = cache.get("appEnvTemplate");
|
|
156
|
+
let headerCache = cache.get("headerCache");
|
|
154
157
|
_appContext = Object.assign({}, appEnvTemplate, headerCache);
|
|
155
158
|
cache.set(sessionId, _appContext);
|
|
156
159
|
}
|
|
157
160
|
console.error("[Note] Using existing transport for session ID:", sessionId);
|
|
158
161
|
|
|
159
162
|
await transport.handleRequest(req, res, req.body);
|
|
163
|
+
return;
|
|
160
164
|
}
|
|
161
165
|
|
|
162
166
|
// initialize request
|
|
163
167
|
else if (!sessionId && isInitializeRequest(req.body)) {
|
|
164
168
|
// create transport
|
|
165
|
-
|
|
169
|
+
console.error("[Note] Initializing new transport for MCP session...");
|
|
166
170
|
transport = new StreamableHTTPServerTransport({
|
|
167
171
|
sessionIdGenerator: () => randomUUID(),
|
|
168
172
|
enableJsonResponse: true,
|
|
173
|
+
enableDnsRebindingProtection: true,
|
|
169
174
|
onsessioninitialized: (sessionId) => {
|
|
170
175
|
// Store the transport by session ID
|
|
176
|
+
console.error("++++++++++++++++++++++++++++++ Transport initialized with ID:", sessionId);
|
|
171
177
|
transports[sessionId] = transport;
|
|
172
178
|
},
|
|
173
179
|
});
|
|
@@ -178,14 +184,16 @@ const handleRequest = async (req, res) => {
|
|
|
178
184
|
}
|
|
179
185
|
};
|
|
180
186
|
console.error("[Note] Connecting mcpServer to new transport...");
|
|
187
|
+
console.error('connecting mcp Server with session ID:', transport.sessionId);
|
|
188
|
+
console.error('>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> connecting mcp Server with session ID:', transport.sessionId);
|
|
181
189
|
await mcpServer.connect(transport);
|
|
182
190
|
|
|
183
191
|
// Save transport data and app context for use in tools
|
|
184
|
-
|
|
185
|
-
await transport.handleRequest(req, res, req.body);
|
|
186
|
-
// cache transport
|
|
192
|
+
console.error('connected mcpServer');
|
|
187
193
|
cache.set("transports", transports);
|
|
188
|
-
|
|
194
|
+
return await transport.handleRequest(req, res, req.body);
|
|
195
|
+
// cache transport
|
|
196
|
+
|
|
189
197
|
}
|
|
190
198
|
}
|
|
191
199
|
catch (error) {
|
|
@@ -208,13 +216,13 @@ const handleGetDelete = async (req, res) => {
|
|
|
208
216
|
const sessionId = req.headers["mcp-session-id"];
|
|
209
217
|
console.error("Handling GET/DELETE for session ID:", sessionId);
|
|
210
218
|
let transports = cache.get("transports");
|
|
211
|
-
let transport = transports[sessionId];
|
|
219
|
+
let transport = (sessionId == null) ? null : transports[sessionId];
|
|
212
220
|
if (!sessionId || transport == null) {
|
|
213
221
|
res.status(400).send(`[Error] In ${req.method}: Invalid or missing session ID ${sessionId}`);
|
|
214
222
|
return;
|
|
215
223
|
}
|
|
216
224
|
await transport.handleRequest(req, res);
|
|
217
|
-
if (req.method === "DELETE") {
|
|
225
|
+
if (req.method === "DELETE" && sessionId != null) {
|
|
218
226
|
console.error("Deleting transport and cache for session ID:", sessionId);
|
|
219
227
|
delete transports[sessionId];
|
|
220
228
|
cache.del(sessionId);
|
package/src/openAPIJson.js
CHANGED
|
@@ -7,7 +7,7 @@ function openAPIJson(version) {
|
|
|
7
7
|
"swagger": "2.0",
|
|
8
8
|
"info": {
|
|
9
9
|
"title": "sas-score-mcp-serverjs API",
|
|
10
|
-
"version":
|
|
10
|
+
"version": "1.0.0",
|
|
11
11
|
"description": "sas-score-mcp-serverjs is a mcp server for SAS Viya"
|
|
12
12
|
},
|
|
13
13
|
"host": "localhost:8080",
|
|
@@ -17,9 +17,9 @@ function openAPIJson(version) {
|
|
|
17
17
|
"produces": ["application/json"],
|
|
18
18
|
"paths": {
|
|
19
19
|
"/health": {
|
|
20
|
-
"
|
|
20
|
+
"get": {
|
|
21
21
|
"summary": "Health check",
|
|
22
|
-
"operationId": "
|
|
22
|
+
"operationId": "getHealth",
|
|
23
23
|
"description": "Returns health and version information.",
|
|
24
24
|
"responses": {
|
|
25
25
|
"200": {
|
|
@@ -39,7 +39,7 @@ function openAPIJson(version) {
|
|
|
39
39
|
}
|
|
40
40
|
},
|
|
41
41
|
"/apiMeta": {
|
|
42
|
-
"
|
|
42
|
+
"get": {
|
|
43
43
|
"summary": "API metadata using apiMeta",
|
|
44
44
|
"operationId": "GetApiMeta",
|
|
45
45
|
"responses": {
|
|
@@ -50,8 +50,8 @@ function openAPIJson(version) {
|
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
52
|
},
|
|
53
|
-
|
|
54
|
-
"
|
|
53
|
+
"/openapi.json": {
|
|
54
|
+
"get": {
|
|
55
55
|
"summary": "API metadata using openapi.json",
|
|
56
56
|
"operationId": "GetOpenApiJson",
|
|
57
57
|
"description": "Returns the OpenAPI specification for this server.",
|
|
@@ -64,7 +64,7 @@ function openAPIJson(version) {
|
|
|
64
64
|
}
|
|
65
65
|
},
|
|
66
66
|
"/mcp": {
|
|
67
|
-
"
|
|
67
|
+
"options": {
|
|
68
68
|
"summary": "CORS preflight",
|
|
69
69
|
"operationId": "OptionsMcp",
|
|
70
70
|
"description": "CORS preflight endpoint.",
|
|
@@ -72,7 +72,7 @@ function openAPIJson(version) {
|
|
|
72
72
|
"204": { "description": "No Content" }
|
|
73
73
|
}
|
|
74
74
|
},
|
|
75
|
-
"
|
|
75
|
+
"post": {
|
|
76
76
|
"summary": "MCP request",
|
|
77
77
|
"operationId": "PostMcp",
|
|
78
78
|
"parameters": [
|
|
@@ -122,8 +122,8 @@ function openAPIJson(version) {
|
|
|
122
122
|
}
|
|
123
123
|
}
|
|
124
124
|
},
|
|
125
|
-
"
|
|
126
|
-
"summary": "
|
|
125
|
+
"get": {
|
|
126
|
+
"summary": "get MCP session",
|
|
127
127
|
"operationId": "GetMcp",
|
|
128
128
|
"description": "Retrieves information for an MCP session.",
|
|
129
129
|
"parameters": [
|
|
@@ -145,7 +145,7 @@ function openAPIJson(version) {
|
|
|
145
145
|
}
|
|
146
146
|
}
|
|
147
147
|
},
|
|
148
|
-
"
|
|
148
|
+
"delete": {
|
|
149
149
|
"summary": "Delete MCP session",
|
|
150
150
|
"operationId": "DeleteMcp",
|
|
151
151
|
"parameters": [
|
|
@@ -169,7 +169,7 @@ function openAPIJson(version) {
|
|
|
169
169
|
}
|
|
170
170
|
}
|
|
171
171
|
}
|
|
172
|
-
}
|
|
172
|
+
}
|
|
173
173
|
spec.info.version = version;
|
|
174
174
|
return spec;
|
|
175
175
|
};
|