mirror of
https://github.com/PrefectHQ/fastmcp.git
synced 2026-08-23 22:14:18 +02:00
Update classes to inherit from FastMCPBaseModel instead of BaseModel (#2739)
This commit is contained in:
parent
5a6f71503b
commit
a39ab0734e
7 changed files with 47 additions and 30 deletions
|
|
@ -68,7 +68,6 @@ class Message(pydantic.BaseModel):
|
|||
self,
|
||||
content: Any,
|
||||
role: Literal["user", "assistant"] = "user",
|
||||
**kwargs: Any,
|
||||
):
|
||||
"""Create Message with automatic serialization.
|
||||
|
||||
|
|
@ -88,7 +87,7 @@ class Message(pydantic.BaseModel):
|
|||
serialized = pydantic_core.to_json(content, fallback=str).decode()
|
||||
normalized_content = TextContent(type="text", text=serialized)
|
||||
|
||||
super().__init__(role=role, content=normalized_content, **kwargs)
|
||||
super().__init__(role=role, content=normalized_content)
|
||||
|
||||
def to_mcp_prompt_message(self) -> PromptMessage:
|
||||
"""Convert to MCP PromptMessage."""
|
||||
|
|
@ -148,7 +147,6 @@ class PromptResult(pydantic.BaseModel):
|
|||
messages: str | list[Message],
|
||||
description: str | None = None,
|
||||
meta: dict[str, Any] | None = None,
|
||||
**kwargs: Any,
|
||||
):
|
||||
"""Create PromptResult.
|
||||
|
||||
|
|
@ -158,9 +156,7 @@ class PromptResult(pydantic.BaseModel):
|
|||
meta: Optional metadata about the prompt result.
|
||||
"""
|
||||
normalized = self._normalize_messages(messages)
|
||||
super().__init__(
|
||||
messages=normalized, description=description, meta=meta, **kwargs
|
||||
)
|
||||
super().__init__(messages=normalized, description=description, meta=meta)
|
||||
|
||||
@staticmethod
|
||||
def _normalize_messages(
|
||||
|
|
|
|||
|
|
@ -29,9 +29,7 @@ from typing_extensions import Self
|
|||
from fastmcp.server.dependencies import without_injected_parameters
|
||||
from fastmcp.server.tasks.config import TaskConfig
|
||||
from fastmcp.utilities.components import FastMCPComponent
|
||||
from fastmcp.utilities.types import (
|
||||
get_fn_name,
|
||||
)
|
||||
from fastmcp.utilities.types import get_fn_name
|
||||
|
||||
|
||||
class ResourceContent(pydantic.BaseModel):
|
||||
|
|
@ -65,7 +63,6 @@ class ResourceContent(pydantic.BaseModel):
|
|||
content: Any,
|
||||
mime_type: str | None = None,
|
||||
meta: dict[str, Any] | None = None,
|
||||
**kwargs: Any,
|
||||
):
|
||||
"""Create ResourceContent with automatic serialization.
|
||||
|
||||
|
|
@ -88,9 +85,7 @@ class ResourceContent(pydantic.BaseModel):
|
|||
normalized_content = pydantic_core.to_json(content, fallback=str).decode()
|
||||
mime_type = mime_type or "application/json"
|
||||
|
||||
super().__init__(
|
||||
content=normalized_content, mime_type=mime_type, meta=meta, **kwargs
|
||||
)
|
||||
super().__init__(content=normalized_content, mime_type=mime_type, meta=meta)
|
||||
|
||||
def to_mcp_resource_contents(
|
||||
self, uri: AnyUrl | str
|
||||
|
|
@ -162,7 +157,6 @@ class ResourceResult(pydantic.BaseModel):
|
|||
self,
|
||||
contents: str | bytes | list[ResourceContent],
|
||||
meta: dict[str, Any] | None = None,
|
||||
**kwargs: Any,
|
||||
):
|
||||
"""Create ResourceResult.
|
||||
|
||||
|
|
@ -171,7 +165,7 @@ class ResourceResult(pydantic.BaseModel):
|
|||
meta: Optional metadata about the resource result.
|
||||
"""
|
||||
normalized = self._normalize_contents(contents)
|
||||
super().__init__(contents=normalized, meta=meta, **kwargs)
|
||||
super().__init__(contents=normalized, meta=meta)
|
||||
|
||||
@staticmethod
|
||||
def _normalize_contents(
|
||||
|
|
|
|||
|
|
@ -16,14 +16,14 @@ from key_value.aio.stores.memory import MemoryStore
|
|||
from mcp.server.streamable_http import EventCallback, EventId, EventMessage, StreamId
|
||||
from mcp.server.streamable_http import EventStore as SDKEventStore
|
||||
from mcp.types import JSONRPCMessage
|
||||
from pydantic import BaseModel
|
||||
|
||||
from fastmcp.utilities.logging import get_logger
|
||||
from fastmcp.utilities.types import FastMCPBaseModel
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
class EventEntry(BaseModel):
|
||||
class EventEntry(FastMCPBaseModel):
|
||||
"""Stored event entry."""
|
||||
|
||||
event_id: str
|
||||
|
|
@ -31,7 +31,7 @@ class EventEntry(BaseModel):
|
|||
message: dict | None # JSONRPCMessage serialized to dict
|
||||
|
||||
|
||||
class StreamEventList(BaseModel):
|
||||
class StreamEventList(FastMCPBaseModel):
|
||||
"""List of event IDs for a stream."""
|
||||
|
||||
event_ids: list[str]
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ from key_value.aio.wrappers.statistics import StatisticsWrapper
|
|||
from key_value.aio.wrappers.statistics.wrapper import (
|
||||
KVStoreCollectionStatistics,
|
||||
)
|
||||
from pydantic import BaseModel, Field
|
||||
from pydantic import Field
|
||||
from typing_extensions import NotRequired, Self, override
|
||||
|
||||
from fastmcp.prompts.prompt import Message, Prompt, PromptResult
|
||||
|
|
@ -22,6 +22,7 @@ from fastmcp.resources.resource import Resource, ResourceContent, ResourceResult
|
|||
from fastmcp.server.middleware.middleware import CallNext, Middleware, MiddlewareContext
|
||||
from fastmcp.tools.tool import Tool, ToolResult
|
||||
from fastmcp.utilities.logging import get_logger
|
||||
from fastmcp.utilities.types import FastMCPBaseModel
|
||||
|
||||
logger: Logger = get_logger(name=__name__)
|
||||
|
||||
|
|
@ -34,7 +35,7 @@ ONE_MB_IN_BYTES = 1024 * 1024
|
|||
GLOBAL_KEY = "__global__"
|
||||
|
||||
|
||||
class CachableResourceContent(BaseModel):
|
||||
class CachableResourceContent(FastMCPBaseModel):
|
||||
"""A wrapper for ResourceContent that can be cached."""
|
||||
|
||||
content: str | bytes
|
||||
|
|
@ -42,7 +43,7 @@ class CachableResourceContent(BaseModel):
|
|||
meta: dict[str, Any] | None = None
|
||||
|
||||
|
||||
class CachableResourceResult(BaseModel):
|
||||
class CachableResourceResult(FastMCPBaseModel):
|
||||
"""A wrapper for ResourceResult that can be cached."""
|
||||
|
||||
contents: list[CachableResourceContent]
|
||||
|
|
@ -75,7 +76,7 @@ class CachableResourceResult(BaseModel):
|
|||
)
|
||||
|
||||
|
||||
class CachableToolResult(BaseModel):
|
||||
class CachableToolResult(FastMCPBaseModel):
|
||||
content: list[mcp.types.ContentBlock]
|
||||
structured_content: dict[str, Any] | None
|
||||
meta: dict[str, Any] | None
|
||||
|
|
@ -96,14 +97,14 @@ class CachableToolResult(BaseModel):
|
|||
)
|
||||
|
||||
|
||||
class CachableMessage(BaseModel):
|
||||
class CachableMessage(FastMCPBaseModel):
|
||||
"""A wrapper for Message that can be cached."""
|
||||
|
||||
role: str
|
||||
content: mcp.types.TextContent | mcp.types.EmbeddedResource
|
||||
|
||||
|
||||
class CachablePromptResult(BaseModel):
|
||||
class CachablePromptResult(FastMCPBaseModel):
|
||||
"""A wrapper for PromptResult that can be cached."""
|
||||
|
||||
messages: list[CachableMessage]
|
||||
|
|
@ -168,7 +169,7 @@ class GetPromptSettings(SharedMethodSettings):
|
|||
"""Configuration options for Prompt-related caching."""
|
||||
|
||||
|
||||
class ResponseCachingStatistics(BaseModel):
|
||||
class ResponseCachingStatistics(FastMCPBaseModel):
|
||||
list_tools: KVStoreCollectionStatistics | None = Field(default=None)
|
||||
list_resources: KVStoreCollectionStatistics | None = Field(default=None)
|
||||
list_prompts: KVStoreCollectionStatistics | None = Field(default=None)
|
||||
|
|
|
|||
|
|
@ -7,12 +7,13 @@ from collections.abc import Callable
|
|||
from typing import Any
|
||||
|
||||
from mcp.types import Tool as SDKTool
|
||||
from pydantic import BaseModel, ConfigDict
|
||||
from pydantic import ConfigDict
|
||||
|
||||
from fastmcp.tools.tool import ParsedFunction
|
||||
from fastmcp.utilities.types import FastMCPBaseModel
|
||||
|
||||
|
||||
class SamplingTool(BaseModel):
|
||||
class SamplingTool(FastMCPBaseModel):
|
||||
"""A tool that can be used during LLM sampling.
|
||||
|
||||
SamplingTools bundle a tool's schema (name, description, parameters) with
|
||||
|
|
|
|||
|
|
@ -117,9 +117,7 @@ class ToolResult(BaseModel):
|
|||
)
|
||||
|
||||
super().__init__(
|
||||
content=converted_content,
|
||||
structured_content=structured_content,
|
||||
meta=meta,
|
||||
content=converted_content, structured_content=structured_content, meta=meta
|
||||
)
|
||||
|
||||
def to_mcp_result(
|
||||
|
|
|
|||
|
|
@ -432,3 +432,30 @@ class TestMCPServerConfig:
|
|||
if field != "type"
|
||||
)
|
||||
assert config.deployment.transport == "http"
|
||||
|
||||
|
||||
class TestMCPServerConfigRoundtrip:
|
||||
"""Test that MCPServerConfig survives model_dump() -> reconstruct pattern.
|
||||
|
||||
This is used by the CLI to apply overrides immutably.
|
||||
"""
|
||||
|
||||
def test_roundtrip_preserves_schema(self):
|
||||
"""Ensure schema_ field survives dump/reconstruct cycle."""
|
||||
config = MCPServerConfig(source=FileSystemSource(path="server.py"))
|
||||
config_dict = config.model_dump()
|
||||
reconstructed = MCPServerConfig(**config_dict)
|
||||
assert reconstructed.schema_ == config.schema_
|
||||
|
||||
def test_roundtrip_with_all_fields(self):
|
||||
"""Full config survives dump/reconstruct."""
|
||||
config = MCPServerConfig(
|
||||
source=FileSystemSource(path="server.py", entrypoint="app"),
|
||||
environment=UVEnvironment(python="3.11"),
|
||||
deployment=Deployment(transport="http", port=8080),
|
||||
)
|
||||
config_dict = config.model_dump()
|
||||
reconstructed = MCPServerConfig(**config_dict)
|
||||
assert reconstructed.source.path == "server.py"
|
||||
assert reconstructed.environment.python == "3.11"
|
||||
assert reconstructed.deployment.port == 8080
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue