From 2d8f08d6482a56f6d877cba8c6e2c66c438b4ceb Mon Sep 17 00:00:00 2001 From: David Soria Parra Date: Fri, 3 Jan 2025 15:23:58 +0000 Subject: [PATCH] fix: Address formatting and type checking issues --- examples/fastmcp/unicode_example.py | 41 +++++++++++++++------------ tests/client/test_config.py | 24 +++++++--------- tests/issues/test_100_tool_listing.py | 19 +++++++++---- tests/server/fastmcp/test_server.py | 5 +++- tests/server/test_session.py | 8 ++++-- 5 files changed, 56 insertions(+), 41 deletions(-) diff --git a/examples/fastmcp/unicode_example.py b/examples/fastmcp/unicode_example.py index 401b788..a69f586 100644 --- a/examples/fastmcp/unicode_example.py +++ b/examples/fastmcp/unicode_example.py @@ -8,7 +8,10 @@ from mcp.server.fastmcp import FastMCP mcp = FastMCP() -@mcp.tool(description="🌟 A tool that uses various Unicode characters in its description: á é í ó ú ñ 漢字 🎉") +@mcp.tool( + description="🌟 A tool that uses various Unicode characters in its description: " + "á é í ó ú ñ 漢字 🎉" +) def hello_unicode(name: str = "世界", greeting: str = "¡Hola") -> str: """ A simple tool that demonstrates Unicode handling in: @@ -31,29 +34,31 @@ def list_emoji_categories() -> list[str]: "🌍 Travel & Places", "💡 Objects", "❤️ Symbols", - "🚩 Flags" + "🚩 Flags", ] @mcp.tool(description="🔤 Tool that returns text in different scripts") def multilingual_hello() -> str: """Returns hello in different scripts and writing systems.""" - return "\n".join([ - "English: Hello!", - "Spanish: ¡Hola!", - "French: Bonjour!", - "German: Grüß Gott!", - "Russian: Привет!", - "Greek: Γεια σας!", - "Hebrew: !שָׁלוֹם", - "Arabic: !مرحبا", - "Hindi: नमस्ते!", - "Chinese: 你好!", - "Japanese: こんにちは!", - "Korean: 안녕하세요!", - "Thai: สวัสดี!", - ]) + return "\n".join( + [ + "English: Hello!", + "Spanish: ¡Hola!", + "French: Bonjour!", + "German: Grüß Gott!", + "Russian: Привет!", + "Greek: Γεια σας!", + "Hebrew: !שָׁלוֹם", + "Arabic: !مرحبا", + "Hindi: नमस्ते!", + "Chinese: 你好!", + "Japanese: こんにちは!", + "Korean: 안녕하세요!", + "Thai: สวัสดี!", + ] + ) if __name__ == "__main__": - mcp.run() \ No newline at end of file + mcp.run() diff --git a/tests/client/test_config.py b/tests/client/test_config.py index 2a8273e..b8371e4 100644 --- a/tests/client/test_config.py +++ b/tests/client/test_config.py @@ -1,6 +1,5 @@ import json import subprocess -from pathlib import Path from unittest.mock import patch import pytest @@ -15,42 +14,39 @@ def temp_config_dir(tmp_path): config_dir.mkdir() return config_dir + @pytest.fixture def mock_config_path(temp_config_dir): """Mock get_claude_config_path to return our temporary directory.""" - with patch('mcp.cli.claude.get_claude_config_path', return_value=temp_config_dir): + with patch("mcp.cli.claude.get_claude_config_path", return_value=temp_config_dir): yield temp_config_dir + def test_command_execution(mock_config_path): """Test that the generated command can actually be executed.""" # Setup server_name = "test_server" file_spec = "test_server.py:app" - + # Update config success = update_claude_config( file_spec=file_spec, server_name=server_name, ) assert success - + # Read the generated config config_file = mock_config_path / "claude_desktop_config.json" config = json.loads(config_file.read_text()) - + # Get the command and args server_config = config["mcpServers"][server_name] command = server_config["command"] args = server_config["args"] test_args = [command] + args + ["--help"] - - result = subprocess.run( - test_args, - capture_output=True, - text=True, - timeout=5 - ) - + + result = subprocess.run(test_args, capture_output=True, text=True, timeout=5) + assert result.returncode == 0 - assert "usage" in result.stdout.lower() \ No newline at end of file + assert "usage" in result.stdout.lower() diff --git a/tests/issues/test_100_tool_listing.py b/tests/issues/test_100_tool_listing.py index 2810a02..4bc6d63 100644 --- a/tests/issues/test_100_tool_listing.py +++ b/tests/issues/test_100_tool_listing.py @@ -3,25 +3,32 @@ from mcp.server.fastmcp import FastMCP pytestmark = pytest.mark.anyio + async def test_list_tools_returns_all_tools(): mcp = FastMCP("TestTools") - + # Create 100 tools with unique names num_tools = 100 for i in range(num_tools): + @mcp.tool(name=f"tool_{i}") def dummy_tool_func(): f"""Tool number {i}""" return i - globals()[f'dummy_tool_{i}'] = dummy_tool_func # Keep reference to avoid garbage collection - + + globals()[f"dummy_tool_{i}"] = ( + dummy_tool_func # Keep reference to avoid garbage collection + ) + # Get all tools tools = await mcp.list_tools() - + # Verify we get all tools assert len(tools) == num_tools, f"Expected {num_tools} tools, but got {len(tools)}" - + # Verify each tool is unique and has the correct name tool_names = [tool.name for tool in tools] expected_names = [f"tool_{i}" for i in range(num_tools)] - assert sorted(tool_names) == sorted(expected_names), "Tool names don't match expected names" \ No newline at end of file + assert sorted(tool_names) == sorted( + expected_names + ), "Tool names don't match expected names" diff --git a/tests/server/fastmcp/test_server.py b/tests/server/fastmcp/test_server.py index 5d2380f..63841af 100644 --- a/tests/server/fastmcp/test_server.py +++ b/tests/server/fastmcp/test_server.py @@ -35,7 +35,9 @@ class TestServer: """Test that FastMCP handles non-ASCII characters in descriptions correctly""" mcp = FastMCP() - @mcp.tool(description="🌟 This tool uses emojis and UTF-8 characters: á é í ó ú ñ 漢字 🎉") + @mcp.tool( + description="🌟 This tool uses emojis and UTF-8 characters: á é í ó ú ñ 漢字 🎉" + ) def hello_world(name: str = "世界") -> str: return f"¡Hola, {name}! 👋" @@ -43,6 +45,7 @@ class TestServer: tools = await client.list_tools() assert len(tools.tools) == 1 tool = tools.tools[0] + assert tool.description is not None assert "🌟" in tool.description assert "漢字" in tool.description assert "🎉" in tool.description diff --git a/tests/server/test_session.py b/tests/server/test_session.py index 67d7d48..333196c 100644 --- a/tests/server/test_session.py +++ b/tests/server/test_session.py @@ -18,8 +18,12 @@ from mcp.types import ( @pytest.mark.anyio async def test_server_session_initialize(): - server_to_client_send, server_to_client_receive = anyio.create_memory_object_stream[JSONRPCMessage](1) - client_to_server_send, client_to_server_receive = anyio.create_memory_object_stream[JSONRPCMessage](1) + server_to_client_send, server_to_client_receive = anyio.create_memory_object_stream[ + JSONRPCMessage + ](1) + client_to_server_send, client_to_server_receive = anyio.create_memory_object_stream[ + JSONRPCMessage + ](1) async def run_client(client: ClientSession): async for message in client_session.incoming_messages: