diff --git a/Dockerfile b/Dockerfile index d775052..343a7c9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -18,8 +18,9 @@ RUN --mount=type=cache,target=/root/.cache/uv \ UV_LINK_MODE=copy uv sync --frozen --no-install-project || \ UV_LINK_MODE=copy uv sync --no-install-project -# Copy application source code and README (required by pyproject.toml) +# Copy application source code, assets, and README (required by pyproject.toml) COPY src/ ./src/ +COPY assets/ ./assets/ COPY README.md ./ # Install the project with optimizations diff --git a/assets/favicon.ico b/assets/favicon.ico new file mode 100644 index 0000000..2a10b62 Binary files /dev/null and b/assets/favicon.ico differ diff --git a/assets/favicon.png b/assets/favicon.png new file mode 100644 index 0000000..9adf66f Binary files /dev/null and b/assets/favicon.png differ diff --git a/assets/logo-flame.png b/assets/logo-flame.png new file mode 100644 index 0000000..6c723fe Binary files /dev/null and b/assets/logo-flame.png differ diff --git a/logo.svg b/logo.svg new file mode 100644 index 0000000..e69de29 diff --git a/src/lampyrid/server.py b/src/lampyrid/server.py index 38cb126..8122386 100644 --- a/src/lampyrid/server.py +++ b/src/lampyrid/server.py @@ -4,10 +4,13 @@ from fastmcp.server.auth.auth import AuthProvider from fastmcp.server.auth.providers.google import GoogleProvider from fastmcp.utilities.logging import configure_logging +from fastmcp.utilities.types import Image +from mcp.types import Icon from .clients.firefly import FireflyClient from .config import settings from .tools import register_all_tools +from .utils import get_assets_path, register_custom_routes def _create_auth_provider() -> Optional[AuthProvider]: @@ -32,7 +35,11 @@ def _create_auth_provider() -> Optional[AuthProvider]: # Initialize FastMCP with optional authentication auth_provider = _create_auth_provider() -mcp = FastMCP('lampyrid', auth=auth_provider) + +# Load favicon icon +favicon_icon = Icon(src=Image(path=str(get_assets_path('favicon.png'))).to_data_uri()) + +mcp = FastMCP('lampyrid', auth=auth_provider, icons=[favicon_icon]) _client = FireflyClient() # Configure logging @@ -40,3 +47,6 @@ def _create_auth_provider() -> Optional[AuthProvider]: # Register all MCP tools register_all_tools(mcp, _client) + +# Register custom HTTP routes +register_custom_routes(mcp) diff --git a/src/lampyrid/utils.py b/src/lampyrid/utils.py new file mode 100644 index 0000000..1965941 --- /dev/null +++ b/src/lampyrid/utils.py @@ -0,0 +1,42 @@ +""" +Custom HTTP routes and utilities for LamPyrid MCP server. + +This module provides custom HTTP route handlers that are served at the root level, +alongside the MCP protocol endpoints. +""" + +from pathlib import Path + +from fastmcp import FastMCP +from starlette.requests import Request +from starlette.responses import FileResponse, JSONResponse + + +def get_project_root() -> Path: + return Path(__file__).parent.parent.parent + + +def get_assets_path(filename: str) -> Path: + return get_project_root() / 'assets' / filename + + +async def serve_favicon(request: Request): + """Serve favicon.ico file at the root level.""" + favicon_path = get_assets_path('favicon.ico') + if favicon_path.exists(): + return FileResponse(favicon_path, media_type='image/x-icon') + return JSONResponse({'error': 'Not found'}, status_code=404) + + +def register_custom_routes(mcp: FastMCP) -> None: + """ + Register custom HTTP routes with the FastMCP server. + + These routes are served at the root level (e.g., /favicon.ico), + not nested under the MCP protocol path (e.g., /mcp). + + Args: + mcp: The FastMCP server instance + """ + # Register favicon route + mcp.custom_route('/favicon.ico', methods=['GET'])(serve_favicon)