@@ -164,10 +164,12 @@ async def handler(request: Request):
164164
165165 return handler
166166
167- def make_streamable_http_app (active_app_key : str ):
167+ def make_streamable_http_handler (active_app_key : str ):
168168 """
169- Returns an ASGI app wrapper + its StreamableHTTPSessionManager,
169+ Returns a Route-compatible endpoint function + its StreamableHTTPSessionManager,
170170 both bound to a specific MCP app.
171+
172+ Uses Route instead of Mount to avoid 307 trailing slash redirects.
171173 """
172174 active_app = MCP_APPS [active_app_key ]
173175
@@ -178,36 +180,30 @@ def make_streamable_http_app(active_app_key: str):
178180 stateless = True ,
179181 )
180182
181- class StreamableHTTPHandler :
182- """ASGI app wrapper for StreamableHTTP that handles credential injection."""
183-
184- async def __call__ (self , scope , receive , send ):
185- if scope ["type" ] != "http" :
186- return
187-
188- request = Request (scope , receive , send )
189-
190- logging .info (
191- f"New StreamableHTTP request from: { request .client } - { request .method } { request .url .path } "
192- )
193-
194- # Choose correct set_juspay_request_credentials based on which app is active
195- if JUSPAY_MCP_TYPE == "DASHBOARD" :
196- if active_app_key == "dashboard" :
197- from juspay_dashboard_mcp .tools import set_juspay_request_credentials
198- elif active_app_key == "docs" :
199- from juspay_docs_mcp .tools import set_juspay_request_credentials
200- else :
201- from juspay_mcp .tools import set_juspay_request_credentials
183+ async def handle_streamable_http (request : Request ):
184+ """Route-compatible endpoint for StreamableHTTP that handles credential injection."""
185+ logging .info (
186+ f"New StreamableHTTP request from: { request .client } - { request .method } { request .url .path } "
187+ )
188+
189+ # Choose correct set_juspay_request_credentials based on which app is active
190+ if JUSPAY_MCP_TYPE == "DASHBOARD" :
191+ if active_app_key == "dashboard" :
192+ from juspay_dashboard_mcp .tools import set_juspay_request_credentials
193+ elif active_app_key == "docs" :
194+ from juspay_docs_mcp .tools import set_juspay_request_credentials
202195 else :
203196 from juspay_mcp .tools import set_juspay_request_credentials
197+ else :
198+ from juspay_mcp .tools import set_juspay_request_credentials
204199
205- juspay_creds = getattr (request .state , "juspay_credentials" , None )
206- set_juspay_request_credentials (juspay_creds )
200+ juspay_creds = getattr (request .state , "juspay_credentials" , None )
201+ set_juspay_request_credentials (juspay_creds )
207202
208- await session_manager .handle_request (scope , receive , send )
203+ # Call session manager with the request's scope, receive, send
204+ await session_manager .handle_request (request .scope , request .receive , request ._send )
209205
210- return StreamableHTTPHandler () , session_manager
206+ return handle_streamable_http , session_manager
211207
212208 routes = [
213209 Route ("/health" , endpoint = health_check , methods = ["GET" ]),
@@ -218,25 +214,27 @@ async def __call__(self, scope, receive, send):
218214 if JUSPAY_MCP_TYPE == "DASHBOARD" :
219215 # Dashboard MCP
220216 dashboard_sse_handler = make_sse_handler ("dashboard" )
221- dashboard_http_app , dashboard_session_mgr = make_streamable_http_app ("dashboard" )
217+ dashboard_http_handler , dashboard_session_mgr = make_streamable_http_handler ("dashboard" )
222218
223219 # Docs MCP
224220 docs_sse_handler = make_sse_handler ("docs" )
225- docs_http_app , docs_session_mgr = make_streamable_http_app ("docs" )
221+ docs_http_handler , docs_session_mgr = make_streamable_http_handler ("docs" )
226222
227223 routes .extend (
228224 [
229225 # Dashboard MCP endpoints
230226 Route (sse_dashboard_endpoint_path , endpoint = dashboard_sse_handler ),
231- Mount (
227+ Route (
232228 streamable_dashboard_endpoint_path ,
233- app = dashboard_http_app ,
229+ endpoint = dashboard_http_handler ,
230+ methods = ["GET" , "POST" , "DELETE" ],
234231 ),
235232 # Docs MCP endpoints
236233 Route (sse_docs_endpoint_path , endpoint = docs_sse_handler ),
237- Mount (
234+ Route (
238235 streamable_docs_endpoint_path ,
239- app = docs_http_app ,
236+ endpoint = docs_http_handler ,
237+ methods = ["GET" , "POST" , "DELETE" ],
240238 ),
241239 ]
242240 )
@@ -251,12 +249,16 @@ async def lifespan(app):
251249
252250 else :
253251 default_sse_handler = make_sse_handler ("default" )
254- default_http_app , default_session_mgr = make_streamable_http_app ("default" )
252+ default_http_handler , default_session_mgr = make_streamable_http_handler ("default" )
255253
256254 routes .extend (
257255 [
258256 Route (sse_endpoint_path , endpoint = default_sse_handler ),
259- Mount (streamable_endpoint_path , app = default_http_app ),
257+ Route (
258+ streamable_endpoint_path ,
259+ endpoint = default_http_handler ,
260+ methods = ["GET" , "POST" , "DELETE" ],
261+ ),
260262 ]
261263 )
262264
0 commit comments