@@ -201,10 +201,48 @@ def test_returns_tool_instance(self, simple_app):
201201 assert isinstance (tool , Tool )
202202 assert tool .name == "update"
203203
204- def test_description_includes_docstring (self , simple_app ):
205- with simple_app .server .test_request_context ():
206- tool = app_context .get ().mcp_callback_map [0 ].as_mcp_tool
207- assert "Update output." in tool .description
204+ def test_docstring_hidden_by_default (self ):
205+ """Callback docstrings are not exposed to MCP by default."""
206+ app = Dash (__name__ )
207+ app .layout = html .Div ([dcc .Input (id = "inp" ), html .Div (id = "out" )])
208+
209+ @app .callback (Output ("out" , "children" ), Input ("inp" , "value" ))
210+ def update (val ):
211+ """sensitive callback docstring text that must not leak to LLMs"""
212+ return val
213+
214+ app_context .set (app )
215+ app .mcp_callback_map = CallbackAdapterCollection (app )
216+
217+ with app .server .test_request_context ():
218+ tool = app .mcp_callback_map [0 ].as_mcp_tool
219+ assert (
220+ "sensitive callback docstring text that must not leak to LLMs"
221+ not in tool .description
222+ )
223+
224+ def test_docstring_exposed_when_opted_in_per_callback (self ):
225+ app = Dash (__name__ )
226+ app .layout = html .Div ([dcc .Input (id = "inp" ), html .Div (id = "out" )])
227+
228+ @app .callback (
229+ Output ("out" , "children" ),
230+ Input ("inp" , "value" ),
231+ mcp_expose_docstring = True ,
232+ )
233+ def update (val ):
234+ """intentionally-exposed callback docstring text for the LLM"""
235+ return val
236+
237+ app_context .set (app )
238+ app .mcp_callback_map = CallbackAdapterCollection (app )
239+
240+ with app .server .test_request_context ():
241+ tool = app .mcp_callback_map [0 ].as_mcp_tool
242+ assert (
243+ "intentionally-exposed callback docstring text for the LLM"
244+ in tool .description
245+ )
208246
209247 def test_description_includes_output_target (self , simple_app ):
210248 with simple_app .server .test_request_context ():
0 commit comments