@@ -274,6 +274,53 @@ async def test_replace_note_failed(
274274 assert len (ctx .request_context .lifespan_context .futures ) == 0
275275
276276
277+ @pytest .mark .anyio
278+ @pytest .mark .parametrize (
279+ "argument,expect" ,
280+ [
281+ ("title" , "# title" ),
282+ ("# title" , "# title" ),
283+ ],
284+ )
285+ async def test_add_title (
286+ temp_socket : Path ,
287+ mcp_server : Tuple [FastMCP , Context ],
288+ mock_webbrowser : MagicMock ,
289+ argument : str ,
290+ expect : str ,
291+ ) -> None :
292+ s , ctx = mcp_server
293+ mock_webbrowser .stubbed_queries = {}
294+
295+ await s ._tool_manager .call_tool ("add_title" , arguments = {"id" : "123" , "title" : argument }, context = ctx )
296+ assert len (ctx .request_context .lifespan_context .futures ) == 0
297+
298+ req_params = {
299+ "id" : "123" ,
300+ "text" : expect ,
301+ "mode" : "prepend" ,
302+ "open_note" : "no" ,
303+ "new_window" : "no" ,
304+ "show_window" : "no" ,
305+ "edit" : "no" ,
306+ "x-success" : f"xfwder://{ temp_socket .stem } /{ ctx .request_id } /success" ,
307+ "x-error" : f"xfwder://{ temp_socket .stem } /{ ctx .request_id } /error" ,
308+ }
309+ mock_webbrowser .assert_called_once_with (f"{ BASE_URL } /add-text?{ urlencode (req_params , quote_via = quote )} " )
310+
311+
312+ @pytest .mark .anyio
313+ async def test_add_title_failed (
314+ mcp_server : Tuple [FastMCP , Context [Any , AppContext ]], mock_webbrowser_error : MagicMock
315+ ) -> None :
316+ s , ctx = mcp_server
317+ with pytest .raises (ToolError ) as excinfo :
318+ await s ._tool_manager .call_tool ("add_title" , arguments = {"id" : "123456" , "title" : "new title" }, context = ctx )
319+
320+ assert "test error message" in str (excinfo .value )
321+ assert len (ctx .request_context .lifespan_context .futures ) == 0
322+
323+
277324@pytest .mark .anyio
278325@pytest .mark .parametrize (
279326 "arguments,expect_req_params" ,
0 commit comments