feat: support audio content (#725)

Co-authored-by: Marcelo Trylesinski <marcelotryle@gmail.com>
This commit is contained in:
Luca Chang 2025-06-07 07:32:11 -07:00 • committed by GitHub
commit 7123556a34
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 60 additions and 19 deletions

View file

@ -7,9 +7,9 @@ from typing import Any, Literal
import pydantic_core
from pydantic import BaseModel, Field, TypeAdapter, validate_call
from mcp.types import EmbeddedResource, ImageContent, TextContent
from mcp.types import AudioContent, EmbeddedResource, ImageContent, TextContent
CONTENT_TYPES = TextContent | ImageContent | EmbeddedResource
CONTENT_TYPES = TextContent | ImageContent | AudioContent | EmbeddedResource
class Message(BaseModel):

View file

@ -52,6 +52,7 @@ from mcp.server.streamable_http_manager import StreamableHTTPSessionManager
from mcp.shared.context import LifespanContextT, RequestContext, RequestT
from mcp.types import (
AnyFunction,
AudioContent,
EmbeddedResource,
GetPromptResult,
ImageContent,
@ -275,7 +276,7 @@ class FastMCP:
async def call_tool(
self, name: str, arguments: dict[str, Any]
) -> Sequence[TextContent | ImageContent | EmbeddedResource]:
) -> Sequence[TextContent | ImageContent | AudioContent | EmbeddedResource]:
"""Call a tool by name with arguments."""
context = self.get_context()
result = await self._tool_manager.call_tool(name, arguments, context=context)
@ -875,12 +876,12 @@ class FastMCP:
def _convert_to_content(
result: Any,
) -> Sequence[TextContent | ImageContent | EmbeddedResource]:
) -> Sequence[TextContent | ImageContent | AudioContent | EmbeddedResource]:
"""Convert a result to a sequence of content objects."""
if result is None:
return []
if isinstance(result, TextContent | ImageContent | EmbeddedResource):
if isinstance(result, TextContent | ImageContent | AudioContent | EmbeddedResource):
return [result]
if isinstance(result, Image):

View file

@ -405,7 +405,10 @@ class Server(Generic[LifespanResultT, RequestT]):
...,
Awaitable[
Iterable[
types.TextContent | types.ImageContent | types.EmbeddedResource
types.TextContent
| types.ImageContent
| types.AudioContent
| types.EmbeddedResource
]
],
],

View file

@ -657,11 +657,26 @@ class ImageContent(BaseModel):
model_config = ConfigDict(extra="allow")
class AudioContent(BaseModel):
"""Audio content for a message."""
type: Literal["audio"]
data: str
"""The base64-encoded audio data."""
mimeType: str
"""
The MIME type of the audio. Different providers may support different
audio types.
"""
annotations: Annotations | None = None
model_config = ConfigDict(extra="allow")
class SamplingMessage(BaseModel):
"""Describes a message issued to or received from an LLM API."""
role: Role
content: TextContent | ImageContent
content: TextContent | ImageContent | AudioContent
model_config = ConfigDict(extra="allow")
@ -683,7 +698,7 @@ class PromptMessage(BaseModel):
"""Describes a message returned as part of a prompt."""
role: Role
content: TextContent | ImageContent | EmbeddedResource
content: TextContent | ImageContent | AudioContent | EmbeddedResource
model_config = ConfigDict(extra="allow")
@ -801,7 +816,7 @@ class CallToolRequest(Request[CallToolRequestParams, Literal["tools/call"]]):
class CallToolResult(Result):
"""The server's response to a tool call."""
content: list[TextContent | ImageContent | EmbeddedResource]
content: list[TextContent | ImageContent | AudioContent | EmbeddedResource]
isError: bool = False
@ -965,7 +980,7 @@ class CreateMessageResult(Result):
"""The client's response to a sampling/create_message request from the server."""
role: Role
content: TextContent | ImageContent
content: TextContent | ImageContent | AudioContent
model: str
"""The name of the model that generated the message."""
stopReason: StopReason | None = None