feat(trinity-core): v2.5.0 — resilient session handling, /health endpoint

- Add unauthenticated /health endpoint (kills AUTH FAILED spam from health checks)
- Stale session + initialize request: ignore stale header, create fresh session
- Stale session + tool call: return 400 instead of 404 so client reads JSON-RPC payload
- Gemini-consulted architecture (gemini-trinity-core-mcp-sessions-2026-04-14.md)
This commit is contained in:
Claude
2026-04-15 00:38:12 +00:00
parent 222188edf8
commit 86f87e71e6

View File

@@ -52,6 +52,16 @@ app.use(cors({ origin: '*', credentials: true }));
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
// ─── Health endpoint (no auth required) ───
app.get('/health', (req, res) => {
res.status(200).json({
status: 'ok',
version: '2.5.0',
uptime: Math.floor(process.uptime()),
sessions: activeSessions.size
});
});
function auth(req, res, next) {
if (req.method === 'OPTIONS') return next();
const token = req.headers.authorization?.replace('Bearer ', '');
@@ -157,7 +167,7 @@ const activeSessions = new Map();
// Create a fresh MCP server instance with tool handlers
function createMcpServer() {
const mcpServer = new Server(
{ name: "trinity-core", version: "2.4.0" },
{ name: "trinity-core", version: "2.5.0" },
{ capabilities: { tools: {} } }
);
setupToolHandlers(mcpServer);
@@ -215,8 +225,13 @@ app.all('/mcp', auth, async (req, res) => {
id: null
});
}
} else if (!sessionId && req.method === 'POST' && isInitializeRequest(req.body)) {
log(`StreamableHTTP new session (initialize)`);
} else if (req.method === 'POST' && isInitializeRequest(req.body)) {
// Accept initialize requests even if they carry a stale session header
if (sessionId) {
log(`StreamableHTTP re-initialize (stale session ${sessionId} ignored)`);
} else {
log(`StreamableHTTP new session (initialize)`);
}
transport = new StreamableHTTPServerTransport({
sessionIdGenerator: () => randomUUID(),
onsessioninitialized: (sid) => {
@@ -234,12 +249,12 @@ app.all('/mcp', auth, async (req, res) => {
const mcpServer = createMcpServer();
await mcpServer.connect(transport);
} else if (sessionId && !activeSessions.has(sessionId)) {
// Stale session (e.g. after service restart) — tell client to re-initialize
log(`StreamableHTTP stale session ${sessionId} — returning 404`);
return res.status(404).json({
// Stale session with non-initialize request — return 400 so client reads the JSON-RPC payload
log(`StreamableHTTP stale session ${sessionId} — returning 400`);
return res.status(400).json({
jsonrpc: '2.0',
error: { code: -32001, message: 'Session not found. Please re-initialize.' },
id: null
id: req.body?.id || null
});
} else if (!sessionId && req.method === 'GET') {
// Legacy SSE client connecting via GET /mcp
@@ -289,7 +304,7 @@ app.post('/mcp/messages', auth, async (req, res) => {
const transport = activeSessions.get(sessionId);
if (!transport || !(transport instanceof SSEServerTransport)) {
log(`Legacy session not found: ${sessionId}`);
return res.status(404).json({ error: "Session not found" });
return res.status(400).json({ error: "Session not found. Please re-initialize." });
}
try {
@@ -301,4 +316,4 @@ app.post('/mcp/messages', auth, async (req, res) => {
}
});
app.listen(PORT, () => log(`Trinity Core MCP v2.4.0 started on port ${PORT}`));
app.listen(PORT, () => log(`Trinity Core MCP v2.5.0 started on port ${PORT}`));