Conversation
…vs light-gateway mcp rotuer
There was a problem hiding this comment.
Pull request overview
This PR implements gateway-managed MCP sessions in light-pingora so the gateway can issue its own frontend mcp-session-id, map it to backend MCP session IDs per target, and properly tear down backend sessions—addressing the session-id mismatch between calling an MCP server directly vs via the light-gateway MCP router (fixes #118).
Changes:
- Added an in-memory frontend session store with a 30-minute idle timeout, validation on non-
initializemethods, andDELETE /mcpsession teardown. - Implemented backend MCP session initialization (
initialize+notifications/initialized), per-frontend/per-target backend session reuse, and backend session termination on purge/delete. - Updated MCP router design docs and expanded tests to cover session requirements, backend session mapping/reuse, and teardown.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| frameworks/light-pingora/src/mcp.rs | Adds frontend session issuance/validation, backend MCP session mapping & lazy initialization, DELETE teardown, idle expiry purge, and expanded test coverage. |
| docs/src/design/mcp-router.md | Updates the design/status to reflect the implemented in-memory session store, lazy expiry purge, and backend session mapping/teardown behavior. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
Reviewed PR #119 comments. There are two Copilot comments, and both were valid, so I patched them locally. In light-fabric/frameworks/light-pingora/src/mcp.rs:1242, backend MCP session teardown now sends both mcp-session-id and mcp-protocol-version. In light-fabric/frameworks/light-pingora/src/mcp.rs:1892, 405 Method Not Allowed now advertises Allow: POST, DELETE since DELETE /mcp is supported. I also updated the existing tests to assert both behaviors. |
|
What changed in light-fabric/frameworks/light-pingora/src/mcp.rs:23:
|
|
| let mut outbound = outbound_headers(headers)?; | ||
| if !outbound.contains_key(ACCEPT) { | ||
| outbound.insert( | ||
| ACCEPT, | ||
| HeaderValue::from_static("application/json, text/event-stream"), | ||
| ); | ||
| } |
| let client_sessions = sessions | ||
| .values() | ||
| .filter(|session| session.client_key == client_key) | ||
| .count(); |
|
| async fn terminate_backend_session(&self, backend_session: McpBackendSession) { | ||
| let Some(session_id) = backend_session.session_id.as_deref() else { | ||
| return; | ||
| }; | ||
| let mut headers = HeaderMap::new(); | ||
| let Ok(value) = HeaderValue::from_str(session_id) else { | ||
| return; | ||
| }; | ||
| headers.insert(HeaderName::from_static(MCP_SESSION_ID_HEADER), value); | ||
| if let Ok(value) = HeaderValue::from_str(backend_session.protocol_version.as_str()) { | ||
| headers.insert(HeaderName::from_static(MCP_PROTOCOL_VERSION_HEADER), value); | ||
| } | ||
| if let Err(error) = self | ||
| .client | ||
| .delete(backend_session.target_url.as_str()) | ||
| .headers(headers) | ||
| .send() |
| } else if !outbound.contains_key(MCP_PROTOCOL_VERSION_HEADER) { | ||
| let value = HeaderValue::from_static(DEFAULT_PROTOCOL_VERSION); | ||
| outbound.insert(HeaderName::from_static(MCP_PROTOCOL_VERSION_HEADER), value); | ||
| } |
|
|
Change made: aliased Tokio’s mutex as AsyncMutex in frameworks/light-pingora/src/mcp.rs, then updated the runtime session fields and constructor initializers. The test module can keep |
…vs light-gateway mcp rotuer