11"""Flask route setup, Streamable HTTP transport, and MCP message handling."""
22
3+ # pylint: disable=cyclic-import
4+ # The MCP server imports dash primitives to dispatch callbacks, and dash
5+ # lazy-imports this module to wire the MCP endpoint. Cycle is managed here.
6+
37from __future__ import annotations
48
59import json
610import logging
711from typing import TYPE_CHECKING , Any
812
913from flask import Response , request
10-
11- from dash .mcp .types import MCPError
12-
13- if TYPE_CHECKING :
14- from dash import Dash
15-
16- from dash import get_app
17-
1814from mcp .types import (
1915 LATEST_PROTOCOL_VERSION ,
2016 ErrorData ,
2723 ToolsCapability ,
2824)
2925
30- from dash .version import __version__
26+ from dash import get_app
27+ from dash ._get_app import with_app_context_factory
3128from dash .mcp .primitives import (
3229 call_tool ,
3330 list_resource_templates ,
3835from dash .mcp .primitives .tools .callback_adapter_collection import (
3936 CallbackAdapterCollection ,
4037)
38+ from dash .mcp .types import MCPError
39+ from dash .version import __version__
40+
41+ if TYPE_CHECKING :
42+ from dash import Dash
4143
4244logger = logging .getLogger (__name__ )
4345
@@ -77,9 +79,8 @@ def _handle_post() -> Response:
7779 status = 415 ,
7880 )
7981
80- try :
81- data = request .get_json ()
82- except Exception :
82+ data = request .get_json (silent = True )
83+ if data is None :
8384 return Response (
8485 json .dumps ({"error" : "Invalid JSON" }),
8586 content_type = "application/json" ,
@@ -107,8 +108,7 @@ def _handle_delete() -> Response:
107108
108109 # -- Register routes -----------------------------------------------------
109110
110- from dash ._get_app import with_app_context_factory
111-
111+ # pylint: disable-next=protected-access
112112 app ._add_url (
113113 mcp_path , with_app_context_factory (mcp_handler , app ), ["GET" , "POST" , "DELETE" ]
114114 )
@@ -156,12 +156,12 @@ def _process_mcp_message(data: dict[str, Any]) -> dict[str, Any] | None:
156156
157157 mcp_methods = {
158158 "initialize" : _handle_initialize ,
159- "tools/list" : lambda : list_tools () ,
159+ "tools/list" : list_tools ,
160160 "tools/call" : lambda : call_tool (
161161 params .get ("name" , "" ), params .get ("arguments" , {})
162162 ),
163- "resources/list" : lambda : list_resources () ,
164- "resources/templates/list" : lambda : list_resource_templates () ,
163+ "resources/list" : list_resources ,
164+ "resources/templates/list" : list_resource_templates ,
165165 "resources/read" : lambda : read_resource (params .get ("uri" , "" )),
166166 }
167167
@@ -188,7 +188,7 @@ def _process_mcp_message(data: dict[str, Any]) -> dict[str, Any] | None:
188188 id = request_id ,
189189 error = ErrorData (code = e .code , message = str (e )),
190190 ).model_dump (exclude_none = True )
191- except Exception as e :
191+ except Exception as e : # pylint: disable=broad-exception-caught
192192 logger .error ("MCP error: %s" , e , exc_info = True )
193193 return JSONRPCError (
194194 jsonrpc = "2.0" ,
0 commit comments