Commit c85751e1 authored by Kostas Chartsias's avatar Kostas Chartsias
Browse files

mount MCP server to FastAPI

parent 0f82c344
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -20,4 +20,4 @@ ENV MCP_HOST=0.0.0.0
ENV MCP_PORT=8004

# Run the app
CMD ["python", "-m", "MCP_module.app"]
 No newline at end of file
CMD ["sh", "-c", "uvicorn MCP_module.app:fastapi_app --host ${MCP_HOST:-0.0.0.0} --port ${MCP_PORT:-8004}"]
 No newline at end of file
+2 −2
Original line number Diff line number Diff line
@@ -3,9 +3,9 @@

##  Overview

This project implements an MCP server that exposes **CAMARA-compliant APIs** through the [`fastmcp`](https://pypi.org/project/fastmcp/) framework allowing integration with AI agents and enabled agentic workflows.
This project implements an MCP server that exposes **CAMARA-compliant APIs** through the [`FastMCP`](https://pypi.org/project/fastmcp/) framework integrated with [`FastAPI`](https://fastapi.tiangolo.com/), allowing integration with AI agents and enabled agentic workflows.

It serves as a proxy and validation layer between **CAMARA APIs** and **MCP tools**, allowing interoperability and experimentation with CAMARA API models, or custom Pydantic models when no CAMARA equivalent exists.
The MCP server is mounted on FastAPI at `/mcp` endpoint, allowing you to serve both MCP tools and standard REST API endpoints from the same application.

---

+29 −14
Original line number Diff line number Diff line
import logging
from fastmcp import FastMCP
from fastapi import FastAPI
from fastapi.responses import PlainTextResponse
from MCP_module.tools.qod import create_qod_session, get_qod_session, delete_qod_session, list_qod_sessions
from MCP_module.tools.edge_application import get_app_definitions
from dotenv import load_dotenv
import os
from starlette.requests import Request
from starlette.responses import PlainTextResponse

logging.basicConfig(level=logging.DEBUG, format="%(asctime)s [%(levelname)s] %(message)s")
logger = logging.getLogger("MCP server")

app = FastMCP("MCP Server")
load_dotenv()

# Create FastMCP server instance
mcp = FastMCP("MCP Server")

# Add health check endpoint
@app.custom_route("/health", methods=["GET"])
async def health_check(request: Request) -> PlainTextResponse:
    return PlainTextResponse("healthy")

# Register tools - only audited functions are exposed — no wildcard imports or dynamic inclusion.
# Register tools - only audited functions are exposed
SAFE_TOOLS = [create_qod_session, get_qod_session, delete_qod_session, list_qod_sessions, get_app_definitions]

for tool in SAFE_TOOLS:
    app.tool()(tool)
    mcp.tool()(tool)

mcp_app = mcp.http_app(path="")

app = FastAPI(
    title="MCP Server",
    description="MCP Server with CAMARA-compliant APIs",
    lifespan=mcp_app.router.lifespan_context,
    redirect_slashes=False,
)

# Health check endpoint
@app.get("/health", response_class=PlainTextResponse)
async def health_check():
    return "healthy"

# Mount MCP server
app.mount("", mcp_app)

if __name__ == "__main__":
    logger.info("Starting MCP Server (proxy mode)...")
    import uvicorn

    logger.info("Starting MCP Server with FastAPI...")
    host = os.getenv("MCP_HOST", "127.0.0.1")
    port = int(os.getenv("MCP_PORT", "8000"))

    try:
        # default IP:127.0.0.1 and port 8000
        app.run(transport="streamable-http", host=host, port=port)
        uvicorn.run(app, host=host, port=port)
    except Exception as e:
        logger.critical("MCP server crashed: %s", e, exc_info=True)
 No newline at end of file
+2 −0
Original line number Diff line number Diff line
@@ -2,4 +2,6 @@ fastmcp==2.12.5
pydantic==2.12.3
python-dotenv==1.1.1
Requests==2.32.5
fastapi==0.115.0
uvicorn==0.32.0