@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sassoftware/sas-score-mcp-serverjs",
3
- "version": "0.3.16",
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
  },
@@ -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
- // we have session id, get existing transport
137
- console.error('>>>>>>>>>>>>>> Received request for MCP endpoint with session ID:', req.method, sessionId);
138
- if (sessionId != null) {
139
- console.error("Looking for transport with session ID:", sessionId);
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
- else if (!sessionId && isInitializeRequest(req.body)) {
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
- if (appServer == null) {
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
- app.get("/ready", (_req, res) => {
246
- if (appServer == null) {
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
  );