From litestar
Exposes Litestar route handlers as MCP tools, resources, and prompts over Streamable HTTP and JSON-RPC 2.0. Auto-activates for Litestar MCP patterns.
How this skill is triggered — by the user, by Claude, or both
Slash command
/litestar:litestar-mcpThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
`litestar-mcp` exposes explicitly marked Litestar route handlers as [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) tools, resources, and prompts over MCP Streamable HTTP and JSON-RPC 2.0.
litestar-mcp exposes explicitly marked Litestar route handlers as Model Context Protocol (MCP) tools, resources, and prompts over MCP Streamable HTTP and JSON-RPC 2.0.
Mark routes by passing mcp_tool="name", mcp_resource="name", or mcp_prompt="name" directly to the Litestar route decorator — Litestar funnels unknown kwargs into handler.opt, so no opt={...} wrapper is needed. The @mcp_tool / @mcp_resource / @mcp_prompt decorators (importable from litestar_mcp) still exist and are worth reaching for when you need the extra fields they expose — output_schema, annotations, scopes, task_support, prompt arguments. There is no opt={"mcp_tool_name": ...} form and no mcp_exclude key; neither is read. To hide a route, simply leave it unmarked (discovery is opt-in).
T | None, never Optional[T]from __future__ import annotationsasync defpip install litestar-mcp
from litestar import Litestar, get, post
from litestar.openapi.config import OpenAPIConfig
from litestar_mcp import LitestarMCP, MCPConfig
@get("/users", mcp_tool="list_users")
async def list_users() -> list[dict]:
return [{"id": 1, "name": "Alice"}]
@post("/analyze", mcp_tool="analyze_data")
async def analyze_data(data: dict) -> dict:
return {"count": len(data)}
@get("/config", mcp_resource="app_config")
async def get_app_config() -> dict:
return {"debug": False}
app = Litestar(
route_handlers=[list_users, analyze_data, get_app_config],
plugins=[LitestarMCP(MCPConfig(name="My API"))],
openapi_config=OpenAPIConfig(title="My API", version="1.0.0"),
)
The default MCP surface is:
| Endpoint | Purpose |
|---|---|
GET /mcp | Server-Sent Events stream when requested by the client |
POST /mcp | JSON-RPC endpoint for initialize, ping, tools/*, resources/*, prompts/*, completion/complete, and optional task methods |
DELETE /mcp | Terminate the current MCP session |
GET /.well-known/mcp-server.json | MCP server manifest |
GET /.well-known/agent-card.json | Agent card metadata |
GET /.well-known/oauth-protected-resource | OAuth protected-resource metadata (always registered; populated from auth) |
| Option | Type | Default | Description |
|---|---|---|---|
base_path | str | "/mcp" | URL prefix for the MCP Streamable HTTP endpoint |
include_in_schema | bool | False | Include MCP routes in OpenAPI |
name | str | None | None | Server name; defaults to OpenAPI title |
guards | list[Any] | None | None | Litestar guards applied to the MCP router |
allowed_origins | list[str] | None | None | Restrict accepted Origin headers |
include_operations | list[str] | None | None | Only expose matching operation names |
exclude_operations | list[str] | None | None | Exclude matching operation names |
include_tags | list[str] | None | None | Only expose routes with matching OpenAPI tags |
exclude_tags | list[str] | None | None | Exclude routes with matching OpenAPI tags |
auth | MCPAuthConfig | None | None | OAuth protected-resource metadata |
tasks | bool | MCPTaskConfig | False | Enable experimental in-memory MCP task support |
list_page_size | int | 100 | Page size for tools/list, resources/list, resources/templates/list, prompts/list (clients page via opaque cursors) |
opt_keys | MCPOptKeys | MCPOptKeys() | Rename the handler.opt keys the plugin reads (e.g. to avoid collisions) |
session_store | Store | None | None | Litestar Store backing MCP sessions; defaults to an in-memory store |
session_max_idle_seconds | float | 3600.0 | Idle timeout before an MCP session is evicted |
sse_max_streams | int | 10000 | Max concurrent SSE streams |
sse_max_idle_seconds | float | 3600.0 | Idle timeout for an SSE stream |
Filters (
include_tags/exclude_tags/include_operations/exclude_operations) gate what is advertised intools/list/resources/list/prompts/list. As oflitestar-mcp0.7.0 they do not gatetools/call/resources/read(cofin/litestar-mcp#62), so they are an advertisement filter, not an access boundary — useguards/ auth to actually restrict invocation.
from litestar import get, post
@get("/products", mcp_resource="product_list")
async def list_products() -> list[dict]: ...
@post("/cart/items", mcp_tool="add_to_cart")
async def add_to_cart(data: CartItem) -> Cart: ...
@get(
"/products/{product_id:int}",
mcp_resource="product",
mcp_resource_template="shop://products/{product_id}",
)
async def get_product(product_id: int) -> dict: ...
@get("/products/{product_id:int}/blurb", mcp_prompt="product_blurb")
async def product_blurb(product_id: int) -> str:
"""Write a short marketing blurb for a product."""
...
mcp_resource_template only takes effect alongside mcp_resource — the resource supplies the name the template binds to. A handler can expose more than one MCP role (a tool and a resource) at once; the description-override keys (mcp_description vs mcp_resource_description) are kind-specific so each surface can carry its own prose.
Register prompts not bound to a route with the @mcp_prompt decorator plus LitestarMCP(prompts=[...]):
from litestar_mcp import LitestarMCP, mcp_prompt
@mcp_prompt("summarize", description="Summarize a document for the user.")
def summarize(text: str) -> str:
return f"Summarize the following:\n\n{text}"
app = Litestar(plugins=[LitestarMCP(prompts=[summarize])])
Use structured metadata when the agent needs sharper tool selection:
@post(
"/reports",
mcp_tool="generate_report",
mcp_description="Generate a report for an existing account.",
mcp_when_to_use="Use after the user has confirmed the account and date range.",
mcp_returns="A report id and queued status.",
)
async def generate_report(data: ReportRequest) -> ReportQueued: ...
Discovery is opt-in: a handler that carries no mcp_* marker never appears in MCP. There is no per-route exclude flag — opt={"mcp_exclude": True} is ignored.
@get("/internal/metrics") # unmarked — never exposed to MCP clients
async def metrics() -> dict: ...
To drop marked routes from discovery in bulk, use the MCPConfig filters (exclude_tags / exclude_operations, or an include_tags / include_operations allowlist). Remember these gate advertisement only (cofin/litestar-mcp#62) — enforce real access control with guards or auth.
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "add_to_cart",
"arguments": { "product_id": 42, "quantity": 3 }
}
}
LitestarMCP exposes the app OpenAPI schema as:
litestar://openapiapplication/jsonresources/readAuthentication is a Litestar middleware concern. Apps with existing auth middleware get request.user / request.auth before tool handlers run.
For OIDC-backed MCP endpoints, pair MCPAuthConfig metadata with token validation:
from litestar import Litestar
from litestar.middleware import DefineMiddleware
from litestar_mcp import LitestarMCP, MCPAuthBackend, MCPConfig, OIDCProviderConfig
from litestar_mcp.auth import MCPAuthConfig
app = Litestar(
route_handlers=[...],
plugins=[
LitestarMCP(
MCPConfig(
auth=MCPAuthConfig(
issuer="https://company.okta.com",
audience="api://mcp-tools",
)
)
)
],
middleware=[
DefineMiddleware(
MCPAuthBackend,
providers=[
OIDCProviderConfig(
issuer="https://company.okta.com",
audience="api://mcp-tools",
)
],
user_resolver=lambda claims, app: MyUser(sub=claims["sub"]),
)
],
)
pip install litestar-mcp
List only the routes that should be callable by AI clients. Mark those routes with mcp_tool=, mcp_resource=, or mcp_prompt= (add mcp_resource_template= next to mcp_resource= for templated resources). There are no method-based defaults — unmarked routes are never exposed.
Wire LitestarMCP(MCPConfig(name=...)) into Litestar(plugins=[...]). Use include_tags or include_operations when you need a second allowlist.
For public endpoints, configure bearer-token validation and MCPAuthConfig metadata. For internal deployments, use guards=[...] or existing app auth middleware.
Hit POST /mcp with tools/list and resources/list. Confirm only marked routes appear. Call one representative tool and read one representative resource.
include_tags / include_operations keep the advertised tool set small as route counts grow, but they only filter discovery — pair them with guards / auth, which actually gate invocation.dict[str, Any] request schemas produce weak tool contracts.MCPAuthConfig plus token validation for public MCP - metadata alone does not authenticate requests.allowed_origins for browser-accessible MCP clients - leave it None only for trusted server-to-server deployments.Before delivering an MCP integration, verify:
LitestarMCP is in app.pluginsmcp_tool=, mcp_resource=, or mcp_resource_template=include_* / inside exclude_* — with guards or auth enforcing accessPOST /mcp tools/list returns only intended toolsPOST /mcp resources/list includes only intended resources plus litestar://openapiasync def and return JSON-serializable typesTask: 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
@get("/products", mcp_resource="product_list", tags=["public"])
async def list_products() -> list[dict]:
return [{"id": 1, "name": "Widget"}]
@post("/cart/items", mcp_tool="add_to_cart", tags=["public"])
async def add_to_cart(data: CartItem) -> Cart: ...
@get("/internal/metrics") # unmarked — stays out of MCP
async def metrics() -> dict: ...
app = Litestar(
route_handlers=[list_products, add_to_cart, metrics],
plugins=[
LitestarMCP(
MCPConfig(
name="E-Commerce API",
include_tags=["public"],
)
)
],
)
npx claudepluginhub litestar-org/litestar-skills --plugin litestarSearches MemPalace before answering questions about past work, people, projects, or prior decisions. Returns verbatim stored content instead of guessing from model memory.
Guides Payload CMS config (payload.config.ts), collections, fields, hooks, access control, APIs. Debugs validation errors, security, relationships, queries, transactions, hook behavior.
Implements vector databases with Pinecone, Weaviate, Qdrant, Milvus, pgvector for semantic search, RAG, recommendations, and similarity systems. Optimizes embeddings, indexing, and hybrid search.