Added Audio to FastMCP (#1130)
This commit is contained in:
parent
09e3a05e13
commit
f4b2957a20
3 changed files with 130 additions and 12 deletions
|
|
@ -3,7 +3,7 @@
|
|||
from importlib.metadata import version
|
||||
|
||||
from .server import Context, FastMCP
|
||||
from .utilities.types import Image
|
||||
from .utilities.types import Audio, Image
|
||||
|
||||
__version__ = version("mcp")
|
||||
__all__ = ["FastMCP", "Context", "Image"]
|
||||
__all__ = ["FastMCP", "Context", "Image", "Audio"]
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ from pydantic_core import PydanticUndefined
|
|||
|
||||
from mcp.server.fastmcp.exceptions import InvalidSignature
|
||||
from mcp.server.fastmcp.utilities.logging import get_logger
|
||||
from mcp.server.fastmcp.utilities.types import Image
|
||||
from mcp.server.fastmcp.utilities.types import Audio, Image
|
||||
from mcp.types import ContentBlock, TextContent
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
|
@ -506,6 +506,9 @@ def _convert_to_content(
|
|||
if isinstance(result, Image):
|
||||
return [result.to_image_content()]
|
||||
|
||||
if isinstance(result, Audio):
|
||||
return [result.to_audio_content()]
|
||||
|
||||
if isinstance(result, list | tuple):
|
||||
return list(
|
||||
chain.from_iterable(
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
import base64
|
||||
from pathlib import Path
|
||||
|
||||
from mcp.types import ImageContent
|
||||
from mcp.types import AudioContent, ImageContent
|
||||
|
||||
|
||||
class Image:
|
||||
|
|
@ -52,3 +52,50 @@ class Image:
|
|||
raise ValueError("No image data available")
|
||||
|
||||
return ImageContent(type="image", data=data, mimeType=self._mime_type)
|
||||
|
||||
|
||||
class Audio:
|
||||
"""Helper class for returning audio from tools."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
path: str | Path | None = None,
|
||||
data: bytes | None = None,
|
||||
format: str | None = None,
|
||||
):
|
||||
if not bool(path) ^ bool(data):
|
||||
raise ValueError("Either path or data can be provided")
|
||||
|
||||
self.path = Path(path) if path else None
|
||||
self.data = data
|
||||
self._format = format
|
||||
self._mime_type = self._get_mime_type()
|
||||
|
||||
def _get_mime_type(self) -> str:
|
||||
"""Get MIME type from format or guess from file extension."""
|
||||
if self._format:
|
||||
return f"audio/{self._format.lower()}"
|
||||
|
||||
if self.path:
|
||||
suffix = self.path.suffix.lower()
|
||||
return {
|
||||
".wav": "audio/wav",
|
||||
".mp3": "audio/mpeg",
|
||||
".ogg": "audio/ogg",
|
||||
".flac": "audio/flac",
|
||||
".aac": "audio/aac",
|
||||
".m4a": "audio/mp4",
|
||||
}.get(suffix, "application/octet-stream")
|
||||
return "audio/wav" # default for raw binary data
|
||||
|
||||
def to_audio_content(self) -> AudioContent:
|
||||
"""Convert to MCP AudioContent."""
|
||||
if self.path:
|
||||
with open(self.path, "rb") as f:
|
||||
data = base64.b64encode(f.read()).decode()
|
||||
elif self.data is not None:
|
||||
data = base64.b64encode(self.data).decode()
|
||||
else:
|
||||
raise ValueError("No audio data available")
|
||||
|
||||
return AudioContent(type="audio", data=data, mimeType=self._mime_type)
|
||||
|
|
|
|||
Loading…
Reference in a new issue