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
8 changed files with 253 additions and 326 deletions

View file

@ -13,7 +13,7 @@ from typing import Any
from mcp.server.experimental.task_context import ServerTaskContext
from mcp.server.experimental.task_support import TaskSupport
from mcp.server.session import ServerSession
from mcp.shared.exceptions import McpError
from mcp.shared.exceptions import MCPError
from mcp.shared.experimental.tasks.helpers import MODEL_IMMEDIATE_RESPONSE_KEY, is_terminal
from mcp.types import (
METHOD_NOT_FOUND,
@ -72,13 +72,13 @@ class Experimental:
Args:
tool_task_mode: The tool's execution.taskSupport value
("forbidden", "optional", "required", or None)
raise_error: If True, raises McpError on validation failure. If False, returns ErrorData.
raise_error: If True, raises MCPError on validation failure. If False, returns ErrorData.
Returns:
None if valid, ErrorData if invalid and raise_error=False
Raises:
McpError: If invalid and raise_error=True
MCPError: If invalid and raise_error=True
"""
mode = tool_task_mode or TASK_FORBIDDEN
@ -86,18 +86,12 @@ class Experimental:
error: ErrorData | None = None
if mode == TASK_REQUIRED and not self.is_task:
error = ErrorData(
code=METHOD_NOT_FOUND,
message="This tool requires task-augmented invocation",
)
error = ErrorData(code=METHOD_NOT_FOUND, message="This tool requires task-augmented invocation")
elif mode == TASK_FORBIDDEN and self.is_task:
error = ErrorData(
code=METHOD_NOT_FOUND,
message="This tool does not support task-augmented invocation",
)
error = ErrorData(code=METHOD_NOT_FOUND, message="This tool does not support task-augmented invocation")
if error is not None and raise_error:
raise McpError(error)
raise MCPError(code=error.code, message=error.message)
return error
@ -113,7 +107,7 @@ class Experimental:
Args:
tool: The Tool definition
raise_error: If True, raises McpError on validation failure.
raise_error: If True, raises MCPError on validation failure.
Returns:
None if valid, ErrorData if invalid and raise_error=False

View file

@ -114,7 +114,7 @@ class ExperimentalServerSessionFeatures:
The client's elicitation response
Raises:
McpError: If client doesn't support task-augmented elicitation
MCPError: If client doesn't support task-augmented elicitation
"""
client_caps = self._session.client_params.capabilities if self._session.client_params else None
require_task_augmented_elicitation(client_caps)
@ -174,7 +174,7 @@ class ExperimentalServerSessionFeatures:
The sampling result from the client
Raises:
McpError: If client doesn't support task-augmented sampling or tools
MCPError: If client doesn't support task-augmented sampling or tools
ValueError: If tool_use or tool_result message structure is invalid
"""
client_caps = self._session.client_params.capabilities if self._session.client_params else None

View file

@ -13,7 +13,7 @@ import anyio
from mcp.server.experimental.task_result_handler import TaskResultHandler
from mcp.server.session import ServerSession
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.shared.experimental.tasks.capabilities import (
require_task_augmented_elicitation,
require_task_augmented_sampling,
@ -32,7 +32,6 @@ from mcp.types import (
ElicitationCapability,
ElicitRequestedSchema,
ElicitResult,
ErrorData,
IncludeContext,
ModelPreferences,
RequestId,
@ -173,22 +172,12 @@ class ServerTaskContext:
def _check_elicitation_capability(self) -> None:
"""Check if the client supports elicitation."""
if not self._session.check_client_capability(ClientCapabilities(elicitation=ElicitationCapability())):
raise McpError(
ErrorData(
code=INVALID_REQUEST,
message="Client does not support elicitation capability",
)
)
raise MCPError(code=INVALID_REQUEST, message="Client does not support elicitation capability")
def _check_sampling_capability(self) -> None:
"""Check if the client supports sampling."""
if not self._session.check_client_capability(ClientCapabilities(sampling=SamplingCapability())):
raise McpError(
ErrorData(
code=INVALID_REQUEST,
message="Client does not support sampling capability",
)
)
raise MCPError(code=INVALID_REQUEST, message="Client does not support sampling capability")
async def elicit(
self,
@ -213,7 +202,7 @@ class ServerTaskContext:
The client's response
Raises:
McpError: If client doesn't support elicitation capability
MCPError: If client doesn't support elicitation capability
"""
self._check_elicitation_capability()
@ -281,7 +270,7 @@ class ServerTaskContext:
The client's response indicating acceptance, decline, or cancellation
Raises:
McpError: If client doesn't support elicitation capability
MCPError: If client doesn't support elicitation capability
RuntimeError: If handler is not configured
"""
self._check_elicitation_capability()
@ -361,7 +350,7 @@ class ServerTaskContext:
The sampling result from the client
Raises:
McpError: If client doesn't support sampling capability or tools
MCPError: If client doesn't support sampling capability or tools
ValueError: If tool_use or tool_result message structure is invalid
"""
self._check_sampling_capability()
@ -436,7 +425,7 @@ class ServerTaskContext:
The client's elicitation response
Raises:
McpError: If client doesn't support task-augmented elicitation
MCPError: If client doesn't support task-augmented elicitation
RuntimeError: If handler is not configured
"""
client_caps = self._session.client_params.capabilities if self._session.client_params else None
@ -529,7 +518,7 @@ class ServerTaskContext:
The sampling result from the client
Raises:
McpError: If client doesn't support task-augmented sampling or tools
MCPError: If client doesn't support task-augmented sampling or tools
ValueError: If tool_use or tool_result message structure is invalid
RuntimeError: If handler is not configured
"""

View file

@ -15,7 +15,7 @@ from typing import Any
import anyio
from mcp.server.session import ServerSession
from mcp.shared.exceptions import McpError
from mcp.shared.exceptions import MCPError
from mcp.shared.experimental.tasks.helpers import RELATED_TASK_METADATA_KEY, is_terminal
from mcp.shared.experimental.tasks.message_queue import TaskMessageQueue
from mcp.shared.experimental.tasks.resolver import Resolver
@ -106,7 +106,7 @@ class TaskResultHandler:
while True:
task = await self._store.get_task(task_id)
if task is None:
raise McpError(ErrorData(code=INVALID_PARAMS, message=f"Task not found: {task_id}"))
raise MCPError(code=INVALID_PARAMS, message=f"Task not found: {task_id}")
await self._deliver_queued_messages(task_id, session, request_id)
@ -216,6 +216,6 @@ class TaskResultHandler:
"""
resolver = self._pending_requests.pop(request_id, None)
if resolver is not None and not resolver.done():
resolver.set_exception(McpError(error))
resolver.set_exception(MCPError.from_error_data(error))
return True
return False

View file

@ -11,7 +11,7 @@ from typing import TYPE_CHECKING
from mcp.server.experimental.task_support import TaskSupport
from mcp.server.lowlevel.func_inspection import create_call_wrapper
from mcp.shared.exceptions import McpError
from mcp.shared.exceptions import MCPError
from mcp.shared.experimental.tasks.helpers import cancel_task
from mcp.shared.experimental.tasks.in_memory_task_store import InMemoryTaskStore
from mcp.shared.experimental.tasks.message_queue import InMemoryTaskMessageQueue, TaskMessageQueue
@ -20,7 +20,6 @@ from mcp.types import (
INVALID_PARAMS,
CancelTaskRequest,
CancelTaskResult,
ErrorData,
GetTaskPayloadRequest,
GetTaskPayloadResult,
GetTaskRequest,
@ -135,12 +134,7 @@ class ExperimentalHandlers:
async def _default_get_task(req: GetTaskRequest) -> ServerResult:
task = await support.store.get_task(req.params.task_id)
if task is None:
raise McpError(
ErrorData(
code=INVALID_PARAMS,
message=f"Task not found: {req.params.task_id}",
)
)
raise MCPError(code=INVALID_PARAMS, message=f"Task not found: {req.params.task_id}")
return GetTaskResult(
task_id=task.task_id,
status=task.status,

View file

@ -101,7 +101,7 @@ from mcp.server.streamable_http import EventStore
from mcp.server.streamable_http_manager import StreamableHTTPASGIApp, StreamableHTTPSessionManager
from mcp.server.transport_security import TransportSecuritySettings
from mcp.shared.context import RequestContext
from mcp.shared.exceptions import McpError, UrlElicitationRequiredError
from mcp.shared.exceptions import MCPError, UrlElicitationRequiredError
from mcp.shared.message import ServerMessageMetadata, SessionMessage
from mcp.shared.session import RequestResponder
from mcp.shared.tool_name_validation import validate_and_warn_tool_name
@ -407,9 +407,7 @@ class Server(Generic[LifespanResultT, RequestT]):
case _: # pragma: no cover
raise ValueError(f"Unexpected return type from read_resource: {type(result)}")
return types.ReadResourceResult( # pragma: no cover
contents=[content],
)
return types.ReadResourceResult(contents=[content]) # pragma: no cover
self.request_handlers[types.ReadResourceRequest] = handler
return func
@ -781,13 +779,10 @@ class Server(Generic[LifespanResultT, RequestT]):
)
)
response = await handler(req)
except McpError as err:
except MCPError as err:
response = err.error
except anyio.get_cancelled_exc_class():
logger.info(
"Request %s cancelled - duplicate response suppressed",
message.request_id,
)
logger.info("Request %s cancelled - duplicate response suppressed", message.request_id)
return
except Exception as err:
if raise_exceptions: # pragma: no cover

View file

@ -314,7 +314,7 @@ class ServerSession(
The sampling result from the client.
Raises:
McpError: If tools are provided but client doesn't support them.
MCPError: If tools are provided but client doesn't support them.
ValueError: If tool_use or tool_result message structure is invalid.
StatelessModeNotSupported: If called in stateless HTTP mode.
"""

View file

@ -4,15 +4,8 @@ This module provides validation logic for sampling and elicitation requests
that is shared across normal and task-augmented code paths.
"""
from mcp.shared.exceptions import McpError
from mcp.types import (
INVALID_PARAMS,
ClientCapabilities,
ErrorData,
SamplingMessage,
Tool,
ToolChoice,
)
from mcp.shared.exceptions import MCPError
from mcp.types import INVALID_PARAMS, ClientCapabilities, SamplingMessage, Tool, ToolChoice
def check_sampling_tools_capability(client_caps: ClientCapabilities | None) -> bool:
@ -46,11 +39,11 @@ def validate_sampling_tools(
tool_choice: The tool choice setting, if provided
Raises:
McpError: If tools/tool_choice are provided but client doesn't support them
MCPError: If tools/tool_choice are provided but client doesn't support them
"""
if tools is not None or tool_choice is not None:
if not check_sampling_tools_capability(client_caps):
raise McpError(ErrorData(code=INVALID_PARAMS, message="Client does not support sampling tools capability"))
raise MCPError(code=INVALID_PARAMS, message="Client does not support sampling tools capability")
def validate_tool_use_result_messages(messages: list[SamplingMessage]) -> None: