Completely drop RootModel from types module (#1910)

This commit is contained in:
Marcelo Trylesinski 2026-01-19 14:29:15 +01:00 • committed by GitHub
commit 5fdd48a0d3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 640 additions and 800 deletions

View file

@ -2,7 +2,8 @@ import logging
from dataclasses import dataclass
from typing import Any, Literal
from pydantic import AnyUrl, BaseModel, Field, RootModel, ValidationError
# TODO(Marcelo): We should drop the `RootModel`.
from pydantic import AnyUrl, BaseModel, Field, RootModel, ValidationError # noqa: TID251
from starlette.datastructures import FormData, QueryParams
from starlette.requests import Request
from starlette.responses import RedirectResponse, Response

View file

@ -4,7 +4,7 @@ from dataclasses import dataclass
from typing import Any
from uuid import uuid4
from pydantic import BaseModel, RootModel, ValidationError
from pydantic import BaseModel, ValidationError
from starlette.requests import Request
from starlette.responses import Response
@ -14,11 +14,9 @@ from mcp.server.auth.provider import OAuthAuthorizationServerProvider, Registrat
from mcp.server.auth.settings import ClientRegistrationOptions
from mcp.shared.auth import OAuthClientInformationFull, OAuthClientMetadata
class RegistrationRequest(RootModel[OAuthClientMetadata]):
# this wrapper is a no-op; it's just to separate out the types exposed to the
# provider from what we use in the HTTP handler
root: OAuthClientMetadata
# this alias is a no-op; it's just to separate out the types exposed to the
# provider from what we use in the HTTP handler
RegistrationRequest = OAuthClientMetadata
class RegistrationErrorResponse(BaseModel):
@ -35,6 +33,7 @@ class RegistrationHandler:
# Implements dynamic client registration as defined in https://datatracker.ietf.org/doc/html/rfc7591#section-3.1
try:
# Parse request body as JSON
# TODO(Marcelo): This is unnecessary. We should use `request.body()`.
body = await request.json()
client_metadata = OAuthClientMetadata.model_validate(body)

View file

@ -4,7 +4,7 @@ import time
from dataclasses import dataclass
from typing import Annotated, Any, Literal
from pydantic import AnyHttpUrl, AnyUrl, BaseModel, Field, RootModel, ValidationError
from pydantic import AnyHttpUrl, AnyUrl, BaseModel, Field, TypeAdapter, ValidationError
from starlette.requests import Request
from mcp.server.auth.errors import stringify_pydantic_error
@ -40,18 +40,8 @@ class RefreshTokenRequest(BaseModel):
resource: str | None = Field(None, description="Resource indicator for the token")
class TokenRequest(
RootModel[
Annotated[
AuthorizationCodeRequest | RefreshTokenRequest,
Field(discriminator="grant_type"),
]
]
):
root: Annotated[
AuthorizationCodeRequest | RefreshTokenRequest,
Field(discriminator="grant_type"),
]
TokenRequest = Annotated[AuthorizationCodeRequest | RefreshTokenRequest, Field(discriminator="grant_type")]
token_request_adapter = TypeAdapter[TokenRequest](TokenRequest)
class TokenErrorResponse(BaseModel):
@ -62,11 +52,10 @@ class TokenErrorResponse(BaseModel):
error_uri: AnyHttpUrl | None = None
class TokenSuccessResponse(RootModel[OAuthToken]):
# this is just a wrapper over OAuthToken; the only reason we do this
# is to have some separation between the HTTP response type, and the
# type returned by the provider
root: OAuthToken
# this is just an alias over OAuthToken; the only reason we do this
# is to have some separation between the HTTP response type, and the
# type returned by the provider
TokenSuccessResponse = OAuthToken
@dataclass
@ -107,7 +96,8 @@ class TokenHandler:
try:
form_data = await request.form()
token_request = TokenRequest.model_validate(dict(form_data)).root
# TODO(Marcelo): Can someone check if this `dict()` wrapper is necessary?
token_request = token_request_adapter.validate_python(dict(form_data))
except ValidationError as validation_error: # pragma: no cover
return self.response(
TokenErrorResponse(
@ -186,12 +176,7 @@ class TokenHandler:
# Exchange authorization code for tokens
tokens = await self.provider.exchange_authorization_code(client_info, auth_code)
except TokenError as e:
return self.response(
TokenErrorResponse(
error=e.error,
error_description=e.error_description,
)
)
return self.response(TokenErrorResponse(error=e.error, error_description=e.error_description))
case RefreshTokenRequest(): # pragma: no cover
refresh_token = await self.provider.load_refresh_token(client_info, token_request.refresh_token)
@ -229,11 +214,6 @@ class TokenHandler:
# Exchange refresh token for new tokens
tokens = await self.provider.exchange_refresh_token(client_info, refresh_token, scopes)
except TokenError as e:
return self.response(
TokenErrorResponse(
error=e.error,
error_description=e.error_description,
)
)
return self.response(TokenErrorResponse(error=e.error, error_description=e.error_description))
return self.response(TokenSuccessResponse(root=tokens))
return self.response(tokens)

View file

@ -49,7 +49,7 @@ class ExperimentalServerSessionFeatures:
GetTaskResult containing the task status
"""
return await self._session.send_request(
types.ServerRequest(types.GetTaskRequest(params=types.GetTaskRequestParams(task_id=task_id))),
types.GetTaskRequest(params=types.GetTaskRequestParams(task_id=task_id)),
types.GetTaskResult,
)
@ -68,7 +68,7 @@ class ExperimentalServerSessionFeatures:
The task result, validated against result_type
"""
return await self._session.send_request(
types.ServerRequest(types.GetTaskPayloadRequest(params=types.GetTaskPayloadRequestParams(task_id=task_id))),
types.GetTaskPayloadRequest(params=types.GetTaskPayloadRequestParams(task_id=task_id)),
result_type,
)
@ -120,13 +120,11 @@ class ExperimentalServerSessionFeatures:
require_task_augmented_elicitation(client_caps)
create_result = await self._session.send_request(
types.ServerRequest(
types.ElicitRequest(
params=types.ElicitRequestFormParams(
message=message,
requested_schema=requested_schema,
task=types.TaskMetadata(ttl=ttl),
)
types.ElicitRequest(
params=types.ElicitRequestFormParams(
message=message,
requested_schema=requested_schema,
task=types.TaskMetadata(ttl=ttl),
)
),
types.CreateTaskResult,
@ -185,21 +183,19 @@ class ExperimentalServerSessionFeatures:
validate_tool_use_result_messages(messages)
create_result = await self._session.send_request(
types.ServerRequest(
types.CreateMessageRequest(
params=types.CreateMessageRequestParams(
messages=messages,
max_tokens=max_tokens,
system_prompt=system_prompt,
include_context=include_context,
temperature=temperature,
stop_sequences=stop_sequences,
metadata=metadata,
model_preferences=model_preferences,
tools=tools,
tool_choice=tool_choice,
task=types.TaskMetadata(ttl=ttl),
)
types.CreateMessageRequest(
params=types.CreateMessageRequestParams(
messages=messages,
max_tokens=max_tokens,
system_prompt=system_prompt,
include_context=include_context,
temperature=temperature,
stop_sequences=stop_sequences,
metadata=metadata,
model_preferences=model_preferences,
tools=tools,
tool_choice=tool_choice,
task=types.TaskMetadata(ttl=ttl),
)
),
types.CreateTaskResult,

View file

@ -39,7 +39,6 @@ from mcp.types import (
Result,
SamplingCapability,
SamplingMessage,
ServerNotification,
Task,
TaskMetadata,
TaskStatusNotification,
@ -156,17 +155,15 @@ class ServerTaskContext:
"""Send a task status notification to the client."""
task = self._ctx.task
await self._session.send_notification(
ServerNotification(
TaskStatusNotification(
params=TaskStatusNotificationParams(
task_id=task.task_id,
status=task.status,
status_message=task.status_message,
created_at=task.created_at,
last_updated_at=task.last_updated_at,
ttl=task.ttl,
poll_interval=task.poll_interval,
)
TaskStatusNotification(
params=TaskStatusNotificationParams(
task_id=task.task_id,
status=task.status,
status_message=task.status_message,
created_at=task.created_at,
last_updated_at=task.last_updated_at,
ttl=task.ttl,
poll_interval=task.poll_interval,
)
)
)

View file

@ -6,14 +6,7 @@ from types import GenericAlias
from typing import Annotated, Any, cast, get_args, get_origin, get_type_hints
import pydantic_core
from pydantic import (
BaseModel,
ConfigDict,
Field,
RootModel,
WithJsonSchema,
create_model,
)
from pydantic import BaseModel, ConfigDict, Field, WithJsonSchema, create_model
from pydantic.fields import FieldInfo
from pydantic.json_schema import GenerateJsonSchema, JsonSchemaWarningKind
from typing_extensions import is_typeddict
@ -484,6 +477,8 @@ def _create_wrapped_model(func_name: str, annotation: Any) -> type[BaseModel]:
def _create_dict_model(func_name: str, dict_annotation: Any) -> type[BaseModel]:
"""Create a RootModel for dict[str, T] types."""
# TODO(Marcelo): We should not rely on RootModel for this.
from pydantic import RootModel # noqa: TID251
class DictModel(RootModel[dict_annotation]):
pass
@ -495,9 +490,7 @@ def _create_dict_model(func_name: str, dict_annotation: Any) -> type[BaseModel]:
return DictModel
def _convert_to_content(
result: Any,
) -> Sequence[ContentBlock]:
def _convert_to_content(result: Any) -> Sequence[ContentBlock]:
"""Convert a result to a sequence of content objects.
Note: This conversion logic comes from previous versions of FastMCP and is being

View file

@ -141,16 +141,14 @@ class ExperimentalHandlers:
message=f"Task not found: {req.params.task_id}",
)
)
return ServerResult(
GetTaskResult(
task_id=task.task_id,
status=task.status,
status_message=task.status_message,
created_at=task.created_at,
last_updated_at=task.last_updated_at,
ttl=task.ttl,
poll_interval=task.poll_interval,
)
return GetTaskResult(
task_id=task.task_id,
status=task.status,
status_message=task.status_message,
created_at=task.created_at,
last_updated_at=task.last_updated_at,
ttl=task.ttl,
poll_interval=task.poll_interval,
)
self._request_handlers[GetTaskRequest] = _default_get_task
@ -158,29 +156,29 @@ class ExperimentalHandlers:
# Register get_task_result handler if not already registered
if GetTaskPayloadRequest not in self._request_handlers:
async def _default_get_task_result(req: GetTaskPayloadRequest) -> ServerResult:
async def _default_get_task_result(req: GetTaskPayloadRequest) -> GetTaskPayloadResult:
ctx = self._server.request_context
result = await support.handler.handle(req, ctx.session, ctx.request_id)
return ServerResult(result)
return result
self._request_handlers[GetTaskPayloadRequest] = _default_get_task_result
# Register list_tasks handler if not already registered
if ListTasksRequest not in self._request_handlers:
async def _default_list_tasks(req: ListTasksRequest) -> ServerResult:
async def _default_list_tasks(req: ListTasksRequest) -> ListTasksResult:
cursor = req.params.cursor if req.params else None
tasks, next_cursor = await support.store.list_tasks(cursor)
return ServerResult(ListTasksResult(tasks=tasks, next_cursor=next_cursor))
return ListTasksResult(tasks=tasks, next_cursor=next_cursor)
self._request_handlers[ListTasksRequest] = _default_list_tasks
# Register cancel_task handler if not already registered
if CancelTaskRequest not in self._request_handlers:
async def _default_cancel_task(req: CancelTaskRequest) -> ServerResult:
async def _default_cancel_task(req: CancelTaskRequest) -> CancelTaskResult:
result = await cancel_task(support.store, req.params.task_id)
return ServerResult(result)
return result
self._request_handlers[CancelTaskRequest] = _default_cancel_task
@ -201,9 +199,9 @@ class ExperimentalHandlers:
logger.debug("Registering handler for ListTasksRequest")
wrapper = create_call_wrapper(func, ListTasksRequest)
async def handler(req: ListTasksRequest) -> ServerResult:
async def handler(req: ListTasksRequest) -> ListTasksResult:
result = await wrapper(req)
return ServerResult(result)
return result
self._request_handlers[ListTasksRequest] = handler
return func
@ -226,9 +224,9 @@ class ExperimentalHandlers:
logger.debug("Registering handler for GetTaskRequest")
wrapper = create_call_wrapper(func, GetTaskRequest)
async def handler(req: GetTaskRequest) -> ServerResult:
async def handler(req: GetTaskRequest) -> GetTaskResult:
result = await wrapper(req)
return ServerResult(result)
return result
self._request_handlers[GetTaskRequest] = handler
return func
@ -252,9 +250,9 @@ class ExperimentalHandlers:
logger.debug("Registering handler for GetTaskPayloadRequest")
wrapper = create_call_wrapper(func, GetTaskPayloadRequest)
async def handler(req: GetTaskPayloadRequest) -> ServerResult:
async def handler(req: GetTaskPayloadRequest) -> GetTaskPayloadResult:
result = await wrapper(req)
return ServerResult(result)
return result
self._request_handlers[GetTaskPayloadRequest] = handler
return func
@ -278,9 +276,9 @@ class ExperimentalHandlers:
logger.debug("Registering handler for CancelTaskRequest")
wrapper = create_call_wrapper(func, CancelTaskRequest)
async def handler(req: CancelTaskRequest) -> ServerResult:
async def handler(req: CancelTaskRequest) -> CancelTaskResult:
result = await wrapper(req)
return ServerResult(result)
return result
self._request_handlers[CancelTaskRequest] = handler
return func

View file

@ -271,10 +271,10 @@ class Server(Generic[LifespanResultT, RequestT]):
result = await wrapper(req)
# Handle both old style (list[Prompt]) and new style (ListPromptsResult)
if isinstance(result, types.ListPromptsResult):
return types.ServerResult(result)
return result
else:
# Old style returns list[Prompt]
return types.ServerResult(types.ListPromptsResult(prompts=result))
return types.ListPromptsResult(prompts=result)
self.request_handlers[types.ListPromptsRequest] = handler
return func
@ -289,7 +289,7 @@ class Server(Generic[LifespanResultT, RequestT]):
async def handler(req: types.GetPromptRequest):
prompt_get = await func(req.params.name, req.params.arguments)
return types.ServerResult(prompt_get)
return prompt_get
self.request_handlers[types.GetPromptRequest] = handler
return func
@ -309,10 +309,10 @@ class Server(Generic[LifespanResultT, RequestT]):
result = await wrapper(req)
# Handle both old style (list[Resource]) and new style (ListResourcesResult)
if isinstance(result, types.ListResourcesResult):
return types.ServerResult(result)
return result
else:
# Old style returns list[Resource]
return types.ServerResult(types.ListResourcesResult(resources=result))
return types.ListResourcesResult(resources=result)
self.request_handlers[types.ListResourcesRequest] = handler
return func
@ -325,7 +325,7 @@ class Server(Generic[LifespanResultT, RequestT]):
async def handler(_: Any):
templates = await func()
return types.ServerResult(types.ListResourceTemplatesResult(resource_templates=templates))
return types.ListResourceTemplatesResult(resource_templates=templates)
self.request_handlers[types.ListResourceTemplatesRequest] = handler
return func
@ -376,18 +376,12 @@ class Server(Generic[LifespanResultT, RequestT]):
)
for content_item in contents
]
return types.ServerResult(
types.ReadResourceResult(
contents=contents_list,
)
)
return types.ReadResourceResult(contents=contents_list)
case _: # pragma: no cover
raise ValueError(f"Unexpected return type from read_resource: {type(result)}")
return types.ServerResult( # pragma: no cover
types.ReadResourceResult(
contents=[content],
)
return types.ReadResourceResult( # pragma: no cover
contents=[content],
)
self.request_handlers[types.ReadResourceRequest] = handler
@ -401,7 +395,7 @@ class Server(Generic[LifespanResultT, RequestT]):
async def handler(req: types.SetLevelRequest):
await func(req.params.level)
return types.ServerResult(types.EmptyResult())
return types.EmptyResult()
self.request_handlers[types.SetLevelRequest] = handler
return func
@ -414,7 +408,7 @@ class Server(Generic[LifespanResultT, RequestT]):
async def handler(req: types.SubscribeRequest):
await func(req.params.uri)
return types.ServerResult(types.EmptyResult())
return types.EmptyResult()
self.request_handlers[types.SubscribeRequest] = handler
return func
@ -427,7 +421,7 @@ class Server(Generic[LifespanResultT, RequestT]):
async def handler(req: types.UnsubscribeRequest):
await func(req.params.uri)
return types.ServerResult(types.EmptyResult())
return types.EmptyResult()
self.request_handlers[types.UnsubscribeRequest] = handler
return func
@ -452,7 +446,7 @@ class Server(Generic[LifespanResultT, RequestT]):
for tool in result.tools:
validate_and_warn_tool_name(tool.name)
self._tool_cache[tool.name] = tool
return types.ServerResult(result)
return result
else:
# Old style returns list[Tool]
# Clear and refresh the entire tool cache
@ -460,20 +454,18 @@ class Server(Generic[LifespanResultT, RequestT]):
for tool in result:
validate_and_warn_tool_name(tool.name)
self._tool_cache[tool.name] = tool
return types.ServerResult(types.ListToolsResult(tools=result))
return types.ListToolsResult(tools=result)
self.request_handlers[types.ListToolsRequest] = handler
return func
return decorator
def _make_error_result(self, error_message: str) -> types.ServerResult:
"""Create a ServerResult with an error CallToolResult."""
return types.ServerResult(
types.CallToolResult(
content=[types.TextContent(type="text", text=error_message)],
is_error=True,
)
def _make_error_result(self, error_message: str) -> types.CallToolResult:
"""Create a CallToolResult with an error."""
return types.CallToolResult(
content=[types.TextContent(type="text", text=error_message)],
is_error=True,
)
async def _get_cached_tool_definition(self, tool_name: str) -> types.Tool | None:
@ -541,10 +533,10 @@ class Server(Generic[LifespanResultT, RequestT]):
unstructured_content: UnstructuredContent
maybe_structured_content: StructuredContent | None
if isinstance(results, types.CallToolResult):
return types.ServerResult(results)
return results
elif isinstance(results, types.CreateTaskResult):
# Task-augmented execution returns task info instead of result
return types.ServerResult(results)
return results
elif isinstance(results, tuple) and len(results) == 2:
# tool returned both structured and unstructured content
unstructured_content, maybe_structured_content = cast(CombinationContent, results)
@ -572,12 +564,10 @@ class Server(Generic[LifespanResultT, RequestT]):
return self._make_error_result(f"Output validation error: {e.message}")
# result
return types.ServerResult(
types.CallToolResult(
content=list(unstructured_content),
structured_content=maybe_structured_content,
is_error=False,
)
return types.CallToolResult(
content=list(unstructured_content),
structured_content=maybe_structured_content,
is_error=False,
)
except UrlElicitationRequiredError:
# Re-raise UrlElicitationRequiredError so it can be properly handled
@ -627,12 +617,10 @@ class Server(Generic[LifespanResultT, RequestT]):
async def handler(req: types.CompleteRequest):
completion = await func(req.params.ref, req.params.argument, req.params.context)
return types.ServerResult(
types.CompleteResult(
completion=completion
if completion is not None
else types.Completion(values=[], total=None, has_more=None),
)
return types.CompleteResult(
completion=completion
if completion is not None
else types.Completion(values=[], total=None, has_more=None),
)
self.request_handlers[types.CompleteRequest] = handler
@ -694,11 +682,11 @@ class Server(Generic[LifespanResultT, RequestT]):
):
with warnings.catch_warnings(record=True) as w:
match message:
case RequestResponder(request=types.ClientRequest(root=req)) as responder:
case RequestResponder() as responder:
with responder:
await self._handle_request(message, req, session, lifespan_context, raise_exceptions)
case types.ClientNotification(root=notify):
await self._handle_notification(notify)
await self._handle_request(
message, responder.request, session, lifespan_context, raise_exceptions
)
case Exception(): # pragma: no cover
logger.error(f"Received exception from stream: {message}")
await session.send_log_message(
@ -708,6 +696,8 @@ class Server(Generic[LifespanResultT, RequestT]):
)
if raise_exceptions:
raise message
case _:
await self._handle_notification(message)
for warning in w: # pragma: no cover
logger.info("Warning: %s: %s", warning.category.__name__, warning.message)
@ -715,7 +705,7 @@ class Server(Generic[LifespanResultT, RequestT]):
async def _handle_request(
self,
message: RequestResponder[types.ClientRequest, types.ServerResult],
req: types.ClientRequestType,
req: types.ClientRequest,
session: ServerSession,
lifespan_context: LifespanResultT,
raise_exceptions: bool,
@ -803,4 +793,4 @@ class Server(Generic[LifespanResultT, RequestT]):
async def _ping_handler(request: types.PingRequest) -> types.ServerResult:
return types.ServerResult(types.EmptyResult())
return types.EmptyResult()

View file

@ -92,7 +92,7 @@ class ServerSession(
init_options: InitializationOptions,
stateless: bool = False,
) -> None:
super().__init__(read_stream, write_stream, types.ClientRequest, types.ClientNotification)
super().__init__(read_stream, write_stream)
self._stateless = stateless
self._initialization_state = (
InitializationState.Initialized if stateless else InitializationState.NotInitialized
@ -104,6 +104,14 @@ class ServerSession(
](0)
self._exit_stack.push_async_callback(lambda: self._incoming_message_stream_reader.aclose())
@property
def _receive_request_adapter(self) -> types.TypeAdapter[types.ClientRequest]:
return types.client_request_adapter
@property
def _receive_notification_adapter(self) -> types.TypeAdapter[types.ClientNotification]:
return types.client_notification_adapter
@property
def client_params(self) -> types.InitializeRequestParams | None:
return self._client_params # pragma: no cover
@ -162,29 +170,27 @@ class ServerSession(
await super()._receive_loop()
async def _received_request(self, responder: RequestResponder[types.ClientRequest, types.ServerResult]):
match responder.request.root:
match responder.request:
case types.InitializeRequest(params=params):
requested_version = params.protocol_version
self._initialization_state = InitializationState.Initializing
self._client_params = params
with responder:
await responder.respond(
types.ServerResult(
types.InitializeResult(
protocol_version=requested_version
if requested_version in SUPPORTED_PROTOCOL_VERSIONS
else types.LATEST_PROTOCOL_VERSION,
capabilities=self._init_options.capabilities,
server_info=types.Implementation(
name=self._init_options.server_name,
title=self._init_options.title,
description=self._init_options.description,
version=self._init_options.server_version,
website_url=self._init_options.website_url,
icons=self._init_options.icons,
),
instructions=self._init_options.instructions,
)
types.InitializeResult(
protocol_version=requested_version
if requested_version in SUPPORTED_PROTOCOL_VERSIONS
else types.LATEST_PROTOCOL_VERSION,
capabilities=self._init_options.capabilities,
server_info=types.Implementation(
name=self._init_options.server_name,
title=self._init_options.title,
description=self._init_options.description,
version=self._init_options.server_version,
website_url=self._init_options.website_url,
icons=self._init_options.icons,
),
instructions=self._init_options.instructions,
)
)
self._initialization_state = InitializationState.Initialized
@ -198,7 +204,7 @@ class ServerSession(
async def _received_notification(self, notification: types.ClientNotification) -> None:
# Need this to avoid ASYNC910
await anyio.lowlevel.checkpoint()
match notification.root:
match notification:
case types.InitializedNotification():
self._initialization_state = InitializationState.Initialized
case _:
@ -214,14 +220,12 @@ class ServerSession(
) -> None:
"""Send a log message notification."""
await self.send_notification(
types.ServerNotification(
types.LoggingMessageNotification(
params=types.LoggingMessageNotificationParams(
level=level,
data=data,
logger=logger,
),
)
types.LoggingMessageNotification(
params=types.LoggingMessageNotificationParams(
level=level,
data=data,
logger=logger,
),
),
related_request_id,
)
@ -229,10 +233,8 @@ class ServerSession(
async def send_resource_updated(self, uri: str | AnyUrl) -> None: # pragma: no cover
"""Send a resource updated notification."""
await self.send_notification(
types.ServerNotification(
types.ResourceUpdatedNotification(
params=types.ResourceUpdatedNotificationParams(uri=str(uri)),
)
types.ResourceUpdatedNotification(
params=types.ResourceUpdatedNotificationParams(uri=str(uri)),
)
)
@ -322,21 +324,19 @@ class ServerSession(
validate_sampling_tools(client_caps, tools, tool_choice)
validate_tool_use_result_messages(messages)
request = types.ServerRequest(
types.CreateMessageRequest(
params=types.CreateMessageRequestParams(
messages=messages,
system_prompt=system_prompt,
include_context=include_context,
temperature=temperature,
max_tokens=max_tokens,
stop_sequences=stop_sequences,
metadata=metadata,
model_preferences=model_preferences,
tools=tools,
tool_choice=tool_choice,
),
)
request = types.CreateMessageRequest(
params=types.CreateMessageRequestParams(
messages=messages,
system_prompt=system_prompt,
include_context=include_context,
temperature=temperature,
max_tokens=max_tokens,
stop_sequences=stop_sequences,
metadata=metadata,
model_preferences=model_preferences,
tools=tools,
tool_choice=tool_choice,
),
)
metadata_obj = ServerMessageMetadata(related_request_id=related_request_id)
@ -358,7 +358,7 @@ class ServerSession(
if self._stateless:
raise StatelessModeNotSupported(method="list_roots")
return await self.send_request(
types.ServerRequest(types.ListRootsRequest()),
types.ListRootsRequest(),
types.ListRootsResult,
)
@ -406,13 +406,11 @@ class ServerSession(
if self._stateless:
raise StatelessModeNotSupported(method="elicitation")
return await self.send_request(
types.ServerRequest(
types.ElicitRequest(
params=types.ElicitRequestFormParams(
message=message,
requested_schema=requested_schema,
),
)
types.ElicitRequest(
params=types.ElicitRequestFormParams(
message=message,
requested_schema=requested_schema,
),
),
types.ElicitResult,
metadata=ServerMessageMetadata(related_request_id=related_request_id),
@ -445,14 +443,12 @@ class ServerSession(
if self._stateless:
raise StatelessModeNotSupported(method="elicitation")
return await self.send_request(
types.ServerRequest(
types.ElicitRequest(
params=types.ElicitRequestURLParams(
message=message,
url=url,
elicitation_id=elicitation_id,
),
)
types.ElicitRequest(
params=types.ElicitRequestURLParams(
message=message,
url=url,
elicitation_id=elicitation_id,
),
),
types.ElicitResult,
metadata=ServerMessageMetadata(related_request_id=related_request_id),
@ -461,7 +457,7 @@ class ServerSession(
async def send_ping(self) -> types.EmptyResult: # pragma: no cover
"""Send a ping request."""
return await self.send_request(
types.ServerRequest(types.PingRequest()),
types.PingRequest(),
types.EmptyResult,
)
@ -475,30 +471,28 @@ class ServerSession(
) -> None:
"""Send a progress notification."""
await self.send_notification(
types.ServerNotification(
types.ProgressNotification(
params=types.ProgressNotificationParams(
progress_token=progress_token,
progress=progress,
total=total,
message=message,
),
)
types.ProgressNotification(
params=types.ProgressNotificationParams(
progress_token=progress_token,
progress=progress,
total=total,
message=message,
),
),
related_request_id,
)
async def send_resource_list_changed(self) -> None: # pragma: no cover
"""Send a resource list changed notification."""
await self.send_notification(types.ServerNotification(types.ResourceListChangedNotification()))
await self.send_notification(types.ResourceListChangedNotification())
async def send_tool_list_changed(self) -> None: # pragma: no cover
"""Send a tool list changed notification."""
await self.send_notification(types.ServerNotification(types.ToolListChangedNotification()))
await self.send_notification(types.ToolListChangedNotification())
async def send_prompt_list_changed(self) -> None: # pragma: no cover
"""Send a prompt list changed notification."""
await self.send_notification(types.ServerNotification(types.PromptListChangedNotification()))
await self.send_notification(types.PromptListChangedNotification())
async def send_elicit_complete(
self,
@ -516,10 +510,8 @@ class ServerSession(
related_request_id: Optional ID of the request that triggered this
"""
await self.send_notification(
types.ServerNotification(
types.ElicitCompleteNotification(
params=types.ElicitCompleteNotificationParams(elicitation_id=elicitation_id)
)
types.ElicitCompleteNotification(
params=types.ElicitCompleteNotificationParams(elicitation_id=elicitation_id)
),
related_request_id,
)