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:
Marcelo Trylesinski 2026-01-26 14:37:44 +01:00 • committed by GitHub
commit acba5478a9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 253 additions and 326 deletions

View file

@ -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")

View file

@ -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

View file

@ -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

View file

@ -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,

View file

@ -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)