litestar-mcp
Auto-activate for litestar_mcp imports, LitestarMCP, MCPConfig, MCPController, @mcp_tool, @mcp_resource, JSON-RPC route exposure, route filtering, or OAuth/Guard-protected MCP endpoints. Use when exposing Litestar routes as MCP tools or resources. Not for non-Litestar MCP servers
What it does
litestar-mcp
litestar-mcp exposes Litestar route handlers as Model Context Protocol (MCP) tools and resources over JSON-RPC 2.0. The plugin discovers routes via the Litestar OpenAPI schema and serves them at POST /mcp/ (configurable).
GET handlers become resources (read-only); POST/PUT/PATCH/DELETE handlers become tools (mutations). Per-route overrides via @mcp_tool, @mcp_resource, or opt={...} dicts.
Code Style Rules
- PEP 604 unions:
T | None, neverOptional[T] - Consumer Litestar app modules MAY use
from __future__ import annotations - Async all I/O — handlers exposed via MCP must be
async def
Quick Reference
Install
pip install litestar-mcp
Basic Setup
from litestar import Litestar, get
from litestar_mcp import LitestarMCP, MCPConfig
@get("/users", name="list_users")
async def get_users() -> list[dict]: ...
app = Litestar(
route_handlers=[get_users],
plugins=[LitestarMCP(MCPConfig(name="My API"))],
)
The MCP endpoint is mounted at POST /mcp/ by default.
MCPConfig
| Option | Type | Default | Description |
|---|---|---|---|
name | str | "litestar" | Server name reported in initialize response |
base_path | str | "/mcp" | URL prefix for the MCP controller |
guards | list[Guard] | [] | Litestar guards applied to the MCP controller |
allowed_origins | list[str] | ["*"] | CORS origins for the MCP endpoint |
auth | OAuthConfig | None | None | OAuth 2.1 configuration |
include_operations | list[str] | None | None | Whitelist of operation names to expose |
exclude_operations | list[str] | None | None | Blacklist of operation names to suppress |
include_tags | list[str] | None | None | Only expose routes with these OpenAPI tags |
exclude_tags | list[str] | None | None | Suppress routes with these OpenAPI tags |
Default Route Discovery
| HTTP Method | Default MCP Type |
|---|---|
GET | resource |
POST / PUT / PATCH / DELETE | tool |
Override per route with decorators (below).
@mcp_tool — explicit tool
from litestar import post
from litestar_mcp import mcp_tool
@mcp_tool("create_order")
@post("/orders")
async def create_order(data: OrderCreate) -> Order: ...
The string argument sets the MCP tool name. Omit it to use the route's name attribute.
@mcp_resource — explicit resource
from litestar import get
from litestar_mcp import mcp_resource
@mcp_resource("orders_list")
@get("/orders", name="list_orders")
async def list_orders() -> list[Order]: ...
opt dict (no decorator import)
@get("/internal/health", opt={"mcp_exclude": True})
async def health_check() -> dict: ...
@post("/orders", opt={"mcp_tool_name": "place_order"})
async def create_order(data: OrderCreate) -> Order: ...
opt key | Type | Description |
|---|---|---|
mcp_exclude | bool | Exclude this route from MCP entirely |
mcp_tool_name | str | Override MCP tool name |
mcp_resource_name | str | Override MCP resource name; implies resource type |
JSON-RPC Methods
| Method | Description |
|---|---|
initialize | Handshake; returns server name, version, capabilities |
ping | Health check; returns pong |
resources/list | List all discoverable MCP resources |
resources/read | Read (call) a specific resource by URI |
tools/list | List all discoverable MCP tools |
tools/call | Invoke a tool by name with arguments |
Example JSON-RPC Call
POST /mcp/
Content-Type: application/json
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "create_order",
"arguments": { "product_id": 42, "quantity": 3 }
}
}
Response:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [{ "type": "text", "text": "{\"id\": 99, \"status\": \"pending\"}" }]
}
}
Built-in OpenAPI Resource
LitestarMCP automatically exposes the Litestar OpenAPI schema as an MCP resource:
- URI:
openapi://schema - MIME type:
application/json - Content: Full OpenAPI 3.x schema from
/schema/openapi.json
AI agents read this resource to understand the full API surface before calling tools.
OAuth 2.1 Auth
from litestar_mcp import MCPConfig, OAuthConfig
config = MCPConfig(
name="My Secured API",
auth=OAuthConfig(
issuer="https://auth.example.com",
client_id="mcp-client",
scopes=["read", "write"],
),
)
PKCE is enforced. Token validation uses the issuer's JWKS endpoint.
Guard-based Auth (simpler)
config = MCPConfig(
name="My API",
guards=[requires_api_key],
)
Filtering
config = MCPConfig(
name="Public API",
include_tags=["public"],
exclude_operations=["admin:delete_user", "admin:list_users"],
)
include_operations / exclude_operations match against route name attributes.
Workflow
Step 1: Install
pip install litestar-mcp
Step 2: Decide What to Expose
List the routes that should be callable by AI agents. Use OpenAPI tags to group them (e.g., tags=["public"]). Routes that touch admin operations, internal metrics, or sensitive data should NOT be exposed.
Step 3: Add the Plugin
Wire LitestarMCP(MCPConfig(name=...)) into Litestar(plugins=[...]). Set include_tags or include_operations to start with an explicit allowlist.
Step 4: Annotate Per-Route (optional)
For routes that need explicit MCP names or type overrides, use @mcp_tool("name"), @mcp_resource("name"), or opt={"mcp_tool_name": "..."}.
Step 5: Add Auth
For public-facing MCP endpoints, set OAuthConfig. For internal use, set guards=[...] with API-key or session-based guards.
Step 6: Verify
Hit POST /mcp/ with a tools/list request. Confirm only intended routes appear. Hit tools/call for a sample mutation; confirm input validation works.
Guardrails
- Default to allowlists, not blocklists —
include_tagsis safer thanexclude_*. Adding a new route shouldn't accidentally expose it to AI. - Never expose admin / destructive routes by default — use
opt={"mcp_exclude": True}or filter by tag. - Prefer resources for idempotent reads — AI agents may call resources speculatively during reasoning. Tools have side effects; gate them behind explicit confirmation.
- Tool argument validation runs against the OpenAPI request schema — keep DTOs precise; loose
dict[str, Any]schemas let agents pass anything. - Use
OAuthConfigfor public MCP endpoints — JSON-RPC over HTTP is reachable from anywhere; raw API keys leak. - Pin
base_path— default/mcpis fine but document if changed. - Don't expose internal metrics, debug, or system routes —
opt={"mcp_exclude": True}orexclude_tags=["internal"]. - Guard the MCP controller with the same Guards as your normal API if it shares user context.
Validation Checkpoint
Before delivering an MCP integration, verify:
-
LitestarMCPis inapp.plugins -
MCPConfig.nameis meaningful (used in agent UIs) - An allowlist (
include_tagsorinclude_operations) is set, not a pure blocklist - Admin / internal routes are excluded
- Auth is configured (
auth=OAuthConfigorguards=[...]) -
POST /mcp/tools/listreturns only intended routes - All exposed handlers are
async defand return JSON-serializable types - Tool arg schemas (DTOs) are precise — no loose
dict[str, Any]
Example
Task: Expose product listing as a resource and "add to cart" as a tool. Hide internal metrics.
from litestar import Litestar, get, post
from litestar_mcp import LitestarMCP, MCPConfig, mcp_tool, mcp_resource
@mcp_resource("product_list")
@get("/products", name="list_products", tags=["public"])
async def list_products() -> list[dict]:
return [{"id": 1, "name": "Widget"}]
@mcp_tool("add_to_cart")
@post("/cart/items", name="cart:add", tags=["public"])
async def add_to_cart(data: CartItem) -> Cart: ...
@get("/internal/metrics", opt={"mcp_exclude": True})
async def metrics() -> dict: ...
app = Litestar(
route_handlers=[list_products, add_to_cart, metrics],
plugins=[LitestarMCP(MCPConfig(
name="E-Commerce API",
include_tags=["public"],
))],
)
</example>
Notes
tools/callarguments are validated against the route's OpenAPI request schema before dispatch.- Response content is serialized to JSON string and wrapped in MCP
TextContent. LitestarMCPdoes not affect normal HTTP routing — all existing endpoints continue to work unchanged.- Use
exclude_operationsoropt={"mcp_exclude": True}to keep internal/admin routes hidden from MCP clients.
Cross-References
- litestar — Litestar app, Guards, OpenAPI, plugin lifecycle.
Official References
- https://github.com/litestar-org/litestar-mcp
- https://modelcontextprotocol.io/
- https://spec.modelcontextprotocol.io/
Shared Styleguide Baseline
Capabilities
Install
Quality
deterministic score 0.45 from registry signals: · indexed on github topic:agent-skills · 7 github stars · SKILL.md body (9,454 chars)