@sassoftware/sas-score-mcp-serverjs 0.3.16 → 0.3.18
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 +2 -2
- package/src/expressMcpServer.js +60 -41
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sassoftware/sas-score-mcp-serverjs",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.18",
|
|
4
4
|
"description": "A mcp server for SAS Viya",
|
|
5
5
|
"author": "Deva Kumar <deva.kumar@sas.com>",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"debug": "cross-env NODE_TLS_REJECT_UNAUTHORIZED=0 node --inspect-brk cli.js",
|
|
17
17
|
"getViyatls": "bash ./scripts/getViyaca.sh",
|
|
18
18
|
"deploy": "bash ./deploy.sh",
|
|
19
|
-
"push2acr": "bash ./push2acr.sh",
|
|
19
|
+
"push2acr": "cd docker && bash ./push2acr.sh",
|
|
20
20
|
"bump": "npm version prerelease",
|
|
21
21
|
"pub": "npm publish --tag dev --access public"
|
|
22
22
|
},
|
package/src/expressMcpServer.js
CHANGED
|
@@ -26,6 +26,7 @@ async function expressMcpServer(mcpServer, cache, baseAppEnvContext) {
|
|
|
26
26
|
cache.set("headerCache", {});
|
|
27
27
|
|
|
28
28
|
const app = express();
|
|
29
|
+
let appStatus = false;
|
|
29
30
|
|
|
30
31
|
app.use(express.json({ limit: "50mb" }));
|
|
31
32
|
app.use(
|
|
@@ -49,6 +50,9 @@ async function expressMcpServer(mcpServer, cache, baseAppEnvContext) {
|
|
|
49
50
|
// setup routes
|
|
50
51
|
app.get("/health", (req, res) => {
|
|
51
52
|
console.error("Received request for health endpoint");
|
|
53
|
+
if (appStatus === false) {
|
|
54
|
+
return res.status(500).json({ status: "not healthy" });
|
|
55
|
+
}
|
|
52
56
|
let health = {
|
|
53
57
|
name: "@sassoftware/mcp-server",
|
|
54
58
|
version: baseAppEnvContext.version,
|
|
@@ -132,14 +136,46 @@ const handleRequest = async (req, res) => {
|
|
|
132
136
|
try {
|
|
133
137
|
|
|
134
138
|
let sessionId = req.headers["mcp-session-id"];
|
|
139
|
+
console.error("========================================================");
|
|
140
|
+
console.error("post /mcp called with session ID:", sessionId);
|
|
141
|
+
let body = (req.body == null) ? 'no body' : JSON.stringify(req.body);
|
|
142
|
+
console.error('[Note] Payload is ', body);
|
|
143
|
+
if (/*!sessionId &&*/ isInitializeRequest(req.body)) {
|
|
144
|
+
// create transport
|
|
145
|
+
console.error("[Note] Initializing new transport for MCP session...");
|
|
146
|
+
|
|
147
|
+
transport = new StreamableHTTPServerTransport({
|
|
148
|
+
sessionIdGenerator: () => randomUUID(),
|
|
149
|
+
enableJsonResponse: true,
|
|
150
|
+
enableDnsRebindingProtection: true,
|
|
151
|
+
onsessioninitialized: (sessionId) => {
|
|
152
|
+
// Store the transport by session ID
|
|
153
|
+
console.error('Session initialized');
|
|
154
|
+
console.error("[Note] Transport initialized with ID:", sessionId);
|
|
155
|
+
transports[sessionId] = transport;
|
|
156
|
+
},
|
|
157
|
+
});
|
|
158
|
+
// Clean up transport when closed
|
|
159
|
+
transport.onclose = () => {
|
|
160
|
+
if (transport.sessionId) {
|
|
161
|
+
delete transports[transport.sessionId];
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
console.error("[Note] Connecting mcpServer to new transport...");
|
|
165
|
+
await mcpServer.connect(transport);
|
|
135
166
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
167
|
+
// Save transport data and app context for use in tools
|
|
168
|
+
console.error('connected mcpServer');
|
|
169
|
+
cache.set("transports", transports);
|
|
170
|
+
return await transport.handleRequest(req, res, req.body);
|
|
171
|
+
// cache transport
|
|
172
|
+
|
|
173
|
+
} else if (sessionId != null) {
|
|
174
|
+
console.error('[Note] Incoming session ID:', sessionId);
|
|
140
175
|
transport = transports[sessionId];
|
|
141
|
-
console.error("Found transport:", transport != null);
|
|
176
|
+
console.error("[Note] Found transport:", transport != null);
|
|
142
177
|
if (transport == null) {
|
|
178
|
+
// this can happen if client is holding on to old session id
|
|
143
179
|
console.error("[Error] No transport found for session ID:", sessionId, "Returning a 400 error with instructions for the user");
|
|
144
180
|
res.status(400).send(`Invalid or missing session ID ${sessionId}. Please ensure your MCP client is configured to use the correct session ID returned in the 'mcp-session-id' header of the response from the /mcp endpoint.`);
|
|
145
181
|
return;
|
|
@@ -166,38 +202,7 @@ const handleRequest = async (req, res) => {
|
|
|
166
202
|
}
|
|
167
203
|
|
|
168
204
|
// initialize request
|
|
169
|
-
|
|
170
|
-
// create transport
|
|
171
|
-
console.error("[Note] Initializing new transport for MCP session...");
|
|
172
|
-
console.error({body: JSON.stringify(req.body)});
|
|
173
|
-
transport = new StreamableHTTPServerTransport({
|
|
174
|
-
sessionIdGenerator: () => randomUUID(),
|
|
175
|
-
enableJsonResponse: true,
|
|
176
|
-
enableDnsRebindingProtection: true,
|
|
177
|
-
onsessioninitialized: (sessionId) => {
|
|
178
|
-
// Store the transport by session ID
|
|
179
|
-
console.error("++++++++++++++++++++++++++++++ Transport initialized with ID:", sessionId);
|
|
180
|
-
transports[sessionId] = transport;
|
|
181
|
-
},
|
|
182
|
-
});
|
|
183
|
-
// Clean up transport when closed
|
|
184
|
-
transport.onclose = () => {
|
|
185
|
-
if (transport.sessionId) {
|
|
186
|
-
delete transports[transport.sessionId];
|
|
187
|
-
}
|
|
188
|
-
};
|
|
189
|
-
console.error("[Note] Connecting mcpServer to new transport...");
|
|
190
|
-
console.error('connecting mcp Server with session ID:', transport.sessionId);
|
|
191
|
-
console.error('>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> connecting mcp Server with session ID:', transport.sessionId);
|
|
192
|
-
await mcpServer.connect(transport);
|
|
193
|
-
|
|
194
|
-
// Save transport data and app context for use in tools
|
|
195
|
-
console.error('connected mcpServer');
|
|
196
|
-
cache.set("transports", transports);
|
|
197
|
-
return await transport.handleRequest(req, res, req.body);
|
|
198
|
-
// cache transport
|
|
199
|
-
|
|
200
|
-
}
|
|
205
|
+
|
|
201
206
|
}
|
|
202
207
|
catch (error) {
|
|
203
208
|
console.error("Error handling MCP request:", error);
|
|
@@ -237,18 +242,28 @@ app.post("/mcp", requireBearer, handleRequest);
|
|
|
237
242
|
app.get("/mcp", handleGetDelete);
|
|
238
243
|
app.delete("/mcp", handleGetDelete);
|
|
239
244
|
app.get("/startup", (_req, res) => {
|
|
240
|
-
|
|
245
|
+
console.error("Received request for startup endpoint");
|
|
246
|
+
if (appStatus === false) {
|
|
241
247
|
return res.status(500).json({ status: "starting" });
|
|
242
248
|
}
|
|
243
249
|
return res.status(200).json({ status: "started" });
|
|
244
250
|
});
|
|
245
|
-
|
|
246
|
-
|
|
251
|
+
|
|
252
|
+
app.get("/status", (_req, res) => {
|
|
253
|
+
console.error("Received request for status endpoint. Current app status:", appStatus);
|
|
254
|
+
if (appStatus === false) {
|
|
247
255
|
return res.status(500).json({ status: "not ready" });
|
|
248
256
|
}
|
|
249
257
|
return res.status(200).json({ status: "ready" });
|
|
250
258
|
});
|
|
251
259
|
|
|
260
|
+
app.get("/ready", (_req, res) => {
|
|
261
|
+
console.error("Received request for ready endpoint. Current app status:", appStatus);
|
|
262
|
+
if (appStatus === false) {
|
|
263
|
+
return res.status(500).json({ status: "not ready" });
|
|
264
|
+
}
|
|
265
|
+
return res.status(200).json({ status: "ready" });
|
|
266
|
+
});
|
|
252
267
|
// Start the server
|
|
253
268
|
let appEnvBase = cache.get("appEnvBase");
|
|
254
269
|
|
|
@@ -279,7 +294,10 @@ if (appEnvBase.HTTPS === 'TRUE') {
|
|
|
279
294
|
console.error("[Note] Press Ctrl+C to stop the server");
|
|
280
295
|
|
|
281
296
|
appServer = https.createServer(appEnvBase.tlsOpts, app);
|
|
282
|
-
appServer.listen(PORT, "0.0.0.0", () => {
|
|
297
|
+
appServer.listen(PORT, "0.0.0.0", () => {
|
|
298
|
+
console.error( `[Note] Express server successfully bound to 0.0.0.0:${PORT}` );
|
|
299
|
+
appStatus= true;
|
|
300
|
+
});
|
|
283
301
|
} else {
|
|
284
302
|
console.error(`[Note] MCP Server listening on port ${PORT}`);
|
|
285
303
|
console.error("[Note] Visit http://localhost:8080/health for health check");
|
|
@@ -289,6 +307,7 @@ if (appEnvBase.HTTPS === 'TRUE') {
|
|
|
289
307
|
console.error("[Note] Press Ctrl+C to stop the server");
|
|
290
308
|
try {
|
|
291
309
|
appServer = app.listen(PORT, "0.0.0.0", () => {
|
|
310
|
+
appStatus = true;
|
|
292
311
|
console.error(
|
|
293
312
|
`[Note] Express server successfully bound to 0.0.0.0:${PORT}`
|
|
294
313
|
);
|