> ## Documentation Index
> Fetch the complete documentation index at: https://docs.celesto.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Build a custom MCP Server

> Build a custom MCP server with LiteMCP so agents can access your internal data sources and APIs through the Model Context Protocol over FastAPI.

`Agentor` enables you to build a custom MCP Server as a FastAPI app. You can integrate it with your existing FastAPI app or deploy it as a standalone MCP Server.

<img src="https://mintcdn.com/celestoai/5-8o3cvomMxZ7MlE/assets/undraw_mcp-server_7kvc.png?fit=max&auto=format&n=5-8o3cvomMxZ7MlE&q=85&s=6cf19441b2772787fc06a77f7d28effb" alt="LiteMCP" className="rounded-lg" width="500" data-path="assets/undraw_mcp-server_7kvc.png" />

## LiteMCP - Lightweight MCP Server

To build MCP Servers with `Agentor`, you can use the `LiteMCP` class.

```python theme={null}
from agentor.mcp import LiteMCP

# Create the app
app = LiteMCP()

# Register a tool
@app.tool(description="Get weather")
def get_weather(location: str) -> str:
    return f"Weather in {location}: Sunny"

# Run the server
if __name__ == "__main__":
    app.run()
```

## LiteMCP vs FastMCP

LiteMCP has a more transparent design and FastAPI primitives such as middlewares and dependency injection are immediately available, while FastMCP requires mounting as a sub-application, diverging from standard FastAPI primitives.

| Feature               | LiteMCP             | FastMCP               |
| --------------------- | ------------------- | --------------------- |
| Integration Pattern   | Native ASGI app     | Requires mounting     |
| FastAPI Primitives    | ✅ Standard patterns | ⚠️ Diverges (sub-app) |
| With Existing Backend | ✅ Easy              | ⚠️ Complex            |
| Decorator API         | ✅ Yes               | ✅ Yes                 |
| Custom Methods        | ✅ Full support      | ⚠️ Limited            |
| Lightweight           | ✅ Minimal deps      | ⚠️ More deps          |

<Card title="Connecting MCP endpoint to existing FastAPI app">
  **Using FastMCP**

  ```python theme={null}
  from starlette.applications import Starlette
  from starlette.routing import Mount
  from mcp.server.fastmcp import FastMCP

  mcp = FastMCP("My App")
  app = Starlette(
      routes=[
          Mount("/mcp", app=mcp.streamable_http_app())  # Separate ASGI app
      ]
  )
  ```

  **Using LiteMCP**

  ```python theme={null}
  from agentor.mcp import LiteMCP
  from fastapi import FastAPI

  # Create the app
  app = FastAPI()
  mcp = LiteMCP()
  app.include_router(mcp.get_fastapi_router())  # Include MCP endpoints like a regular APIRouter
  ```
</Card>

### When to Use Each

**Use LiteMCP when:**

* You want to serve MCP tools alongside your existing FastAPI/Starlette backend
* You prefer standard FastAPI patterns and routing
* You want full control over custom JSON-RPC methods
* You want minimal dependencies

**Use FastMCP when:**

* You're building a standalone MCP server
* You want the official SDK implementation
* You don't need to integrate with existing web services

## Configuration

### Constructor Parameters

```python theme={null}
LiteMCP(
    host="0.0.0.0",  # Host to bind (for run() method)
    port=8000,  # Port to bind (for run() method)
    enable_cors=True,  # Enable CORS middleware
    name="mcp-server",  # Server name
    version="1.0.0",  # Server version
    instructions="...",  # Server instructions
    website_url="...",  # Website URL
    icons=[...],  # Server icons
    prefix="/mcp",  # MCP endpoint prefix
)
```

## Decorators

### @app.tool()

Register a tool that can be called by MCP clients:

```python theme={null}
@app.tool(
    name="custom_name",  # Optional: defaults to function name
    description="Tool description",
    input_schema={...},  # Optional: auto-generated from function signature
)
def my_tool(param1: str, param2: int = 10) -> str:
    return f"Result: {param1} {param2}"
```

### @app.prompt()

Register a prompt template:

```python theme={null}
@app.prompt(
    name="custom_name",  # Optional: defaults to function name
    description="Prompt description",
    arguments=[...],  # Optional: auto-generated from function signature
)
def my_prompt(context: str, style: str = "formal") -> str:
    return f"Generate a {style} response about {context}"
```

### @app.resource()

Register a resource that can be read by MCP clients:

```python theme={null}
@app.resource(
    uri="resource://path",
    name="Resource Name",
    description="Resource description",
    mime_type="text/plain",
)
def my_resource(uri: str) -> str:
    return "Resource content"
```
