refactor: McpError renamed to MCPError and flatten parameters (#1956)
Co-authored-by: Max Isbey <224885523+maxisbey@users.noreply.github.com>
This commit is contained in:
parent
65c614e48e
commit
acba5478a9
5 changed files with 253 additions and 326 deletions
|
|
@ -16,7 +16,7 @@ from mcp.server.mcpserver.resources import FileResource, FunctionResource
|
|||
from mcp.server.mcpserver.utilities.types import Audio, Image
|
||||
from mcp.server.session import ServerSession
|
||||
from mcp.server.transport_security import TransportSecuritySettings
|
||||
from mcp.shared.exceptions import McpError
|
||||
from mcp.shared.exceptions import MCPError
|
||||
from mcp.types import (
|
||||
AudioContent,
|
||||
BlobResourceContents,
|
||||
|
|
@ -1469,7 +1469,7 @@ class TestServerPrompts:
|
|||
"""Test error when getting unknown prompt."""
|
||||
mcp = MCPServer()
|
||||
async with Client(mcp) as client:
|
||||
with pytest.raises(McpError, match="Unknown prompt"):
|
||||
with pytest.raises(MCPError, match="Unknown prompt"):
|
||||
await client.get_prompt("unknown")
|
||||
|
||||
@pytest.mark.anyio
|
||||
|
|
@ -1482,7 +1482,7 @@ class TestServerPrompts:
|
|||
return f"Hello, {name}!"
|
||||
|
||||
async with Client(mcp) as client:
|
||||
with pytest.raises(McpError, match="Missing required arguments"):
|
||||
with pytest.raises(MCPError, match="Missing required arguments"):
|
||||
await client.get_prompt("prompt_fn")
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,16 +1,17 @@
|
|||
"""Test that UrlElicitationRequiredError is properly propagated as MCP error."""
|
||||
|
||||
import pytest
|
||||
from inline_snapshot import snapshot
|
||||
|
||||
from mcp import Client, types
|
||||
from mcp import Client, ErrorData, types
|
||||
from mcp.server.mcpserver import Context, MCPServer
|
||||
from mcp.server.session import ServerSession
|
||||
from mcp.shared.exceptions import McpError, UrlElicitationRequiredError
|
||||
from mcp.shared.exceptions import MCPError, UrlElicitationRequiredError
|
||||
|
||||
|
||||
@pytest.mark.anyio
|
||||
async def test_url_elicitation_error_thrown_from_tool():
|
||||
"""Test that UrlElicitationRequiredError raised from a tool is received as McpError by client."""
|
||||
"""Test that UrlElicitationRequiredError raised from a tool is received as MCPError by client."""
|
||||
mcp = MCPServer(name="UrlElicitationErrorServer")
|
||||
|
||||
@mcp.tool(description="A tool that raises UrlElicitationRequiredError")
|
||||
|
|
@ -28,28 +29,30 @@ async def test_url_elicitation_error_thrown_from_tool():
|
|||
)
|
||||
|
||||
async with Client(mcp) as client:
|
||||
# Call the tool - it should raise McpError with URL_ELICITATION_REQUIRED code
|
||||
with pytest.raises(McpError) as exc_info:
|
||||
with pytest.raises(MCPError) as exc_info:
|
||||
await client.call_tool("connect_service", {"service_name": "github"})
|
||||
|
||||
# Verify the error details
|
||||
error = exc_info.value.error
|
||||
assert error.code == types.URL_ELICITATION_REQUIRED
|
||||
assert error.message == "URL elicitation required"
|
||||
|
||||
# Verify the error data contains elicitations
|
||||
assert error.data is not None
|
||||
assert "elicitations" in error.data
|
||||
elicitations = error.data["elicitations"]
|
||||
assert len(elicitations) == 1
|
||||
assert elicitations[0]["mode"] == "url"
|
||||
assert elicitations[0]["url"] == "https://github.example.com/oauth/authorize"
|
||||
assert elicitations[0]["elicitationId"] == "github-auth-001"
|
||||
assert exc_info.value.error == snapshot(
|
||||
ErrorData(
|
||||
code=types.URL_ELICITATION_REQUIRED,
|
||||
message="URL elicitation required",
|
||||
data={
|
||||
"elicitations": [
|
||||
{
|
||||
"mode": "url",
|
||||
"message": "Authorization required to connect to github",
|
||||
"url": "https://github.example.com/oauth/authorize",
|
||||
"elicitationId": "github-auth-001",
|
||||
}
|
||||
]
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.anyio
|
||||
async def test_url_elicitation_error_from_error():
|
||||
"""Test that client can reconstruct UrlElicitationRequiredError from McpError."""
|
||||
"""Test that client can reconstruct UrlElicitationRequiredError from MCPError."""
|
||||
mcp = MCPServer(name="UrlElicitationErrorServer")
|
||||
|
||||
@mcp.tool(description="A tool that raises UrlElicitationRequiredError with multiple elicitations")
|
||||
|
|
@ -73,12 +76,12 @@ async def test_url_elicitation_error_from_error():
|
|||
|
||||
async with Client(mcp) as client:
|
||||
# Call the tool and catch the error
|
||||
with pytest.raises(McpError) as exc_info:
|
||||
with pytest.raises(MCPError) as exc_info:
|
||||
await client.call_tool("multi_auth", {})
|
||||
|
||||
# Reconstruct the typed error
|
||||
mcp_error = exc_info.value
|
||||
assert mcp_error.error.code == types.URL_ELICITATION_REQUIRED
|
||||
assert mcp_error.code == types.URL_ELICITATION_REQUIRED
|
||||
|
||||
url_error = UrlElicitationRequiredError.from_error(mcp_error.error)
|
||||
|
||||
|
|
@ -98,7 +101,7 @@ async def test_normal_exceptions_still_return_error_result():
|
|||
raise ValueError("Something went wrong")
|
||||
|
||||
async with Client(mcp) as client:
|
||||
# Normal exceptions should be returned as error results, not McpError
|
||||
# Normal exceptions should be returned as error results, not MCPError
|
||||
result = await client.call_tool("failing_tool", {})
|
||||
assert result.is_error is True
|
||||
assert len(result.content) == 1
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import pytest
|
|||
import mcp.types as types
|
||||
from mcp import Client
|
||||
from mcp.server.lowlevel.server import Server
|
||||
from mcp.shared.exceptions import McpError
|
||||
from mcp.shared.exceptions import MCPError
|
||||
from mcp.types import (
|
||||
CallToolRequest,
|
||||
CallToolRequestParams,
|
||||
|
|
@ -61,7 +61,7 @@ async def test_server_remains_functional_after_cancel():
|
|||
CallToolResult,
|
||||
)
|
||||
pytest.fail("First request should have been cancelled") # pragma: no cover
|
||||
except McpError:
|
||||
except MCPError:
|
||||
pass # Expected
|
||||
|
||||
# Start first request
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ from mcp.server import Server
|
|||
from mcp.server.lowlevel import NotificationOptions
|
||||
from mcp.server.models import InitializationOptions
|
||||
from mcp.server.session import ServerSession
|
||||
from mcp.shared.exceptions import McpError
|
||||
from mcp.shared.exceptions import MCPError
|
||||
from mcp.shared.message import SessionMessage
|
||||
from mcp.shared.session import RequestResponder
|
||||
from mcp.types import (
|
||||
|
|
@ -397,7 +397,7 @@ async def test_create_message_tool_result_validation():
|
|||
|
||||
@pytest.mark.anyio
|
||||
async def test_create_message_without_tools_capability():
|
||||
"""Test that create_message raises McpError when tools are provided without capability."""
|
||||
"""Test that create_message raises MCPError when tools are provided without capability."""
|
||||
server_to_client_send, server_to_client_receive = anyio.create_memory_object_stream[SessionMessage](1)
|
||||
client_to_server_send, client_to_server_receive = anyio.create_memory_object_stream[SessionMessage | Exception](1)
|
||||
|
||||
|
|
@ -426,8 +426,8 @@ async def test_create_message_without_tools_capability():
|
|||
tool = types.Tool(name="test_tool", input_schema={"type": "object"})
|
||||
text = types.TextContent(type="text", text="hello")
|
||||
|
||||
# Should raise McpError when tools are provided but client lacks capability
|
||||
with pytest.raises(McpError) as exc_info:
|
||||
# Should raise MCPError when tools are provided but client lacks capability
|
||||
with pytest.raises(MCPError) as exc_info:
|
||||
await session.create_message(
|
||||
messages=[types.SamplingMessage(role="user", content=text)],
|
||||
max_tokens=100,
|
||||
|
|
@ -435,8 +435,8 @@ async def test_create_message_without_tools_capability():
|
|||
)
|
||||
assert "does not support sampling tools capability" in exc_info.value.error.message
|
||||
|
||||
# Should also raise McpError when tool_choice is provided
|
||||
with pytest.raises(McpError) as exc_info:
|
||||
# Should also raise MCPError when tool_choice is provided
|
||||
with pytest.raises(MCPError) as exc_info:
|
||||
await session.create_message(
|
||||
messages=[types.SamplingMessage(role="user", content=text)],
|
||||
max_tokens=100,
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ from mcp.server.validation import (
|
|||
validate_sampling_tools,
|
||||
validate_tool_use_result_messages,
|
||||
)
|
||||
from mcp.shared.exceptions import McpError
|
||||
from mcp.shared.exceptions import MCPError
|
||||
from mcp.types import (
|
||||
ClientCapabilities,
|
||||
SamplingCapability,
|
||||
|
|
@ -55,16 +55,16 @@ def test_validate_sampling_tools_no_error_when_tools_none() -> None:
|
|||
|
||||
|
||||
def test_validate_sampling_tools_raises_when_tools_provided_but_no_capability() -> None:
|
||||
"""Raises McpError when tools provided but client doesn't support."""
|
||||
"""Raises MCPError when tools provided but client doesn't support."""
|
||||
tool = Tool(name="test", input_schema={"type": "object"})
|
||||
with pytest.raises(McpError) as exc_info:
|
||||
with pytest.raises(MCPError) as exc_info:
|
||||
validate_sampling_tools(None, [tool], None)
|
||||
assert "sampling tools capability" in str(exc_info.value)
|
||||
|
||||
|
||||
def test_validate_sampling_tools_raises_when_tool_choice_provided_but_no_capability() -> None:
|
||||
"""Raises McpError when tool_choice provided but client doesn't support."""
|
||||
with pytest.raises(McpError) as exc_info:
|
||||
"""Raises MCPError when tool_choice provided but client doesn't support."""
|
||||
with pytest.raises(MCPError) as exc_info:
|
||||
validate_sampling_tools(None, None, ToolChoice(mode="auto"))
|
||||
assert "sampling tools capability" in str(exc_info.value)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue