Litestar Mcp — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited Litestar Mcp (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
A lightweight plugin that integrates Litestar web applications with the Model Context Protocol (MCP) by exposing marked routes as MCP tools, resources, and prompts over MCP Streamable HTTP and JSON-RPC.
This plugin automatically discovers Litestar routes marked for MCP and exposes them through an MCP-native transport surface. Pass mcp_tool="name", mcp_resource="name", or mcp_prompt="name" straight through to @get / @post / etc. — Litestar funnels unknown kwargs into handler.opt, so no second decorator or opt={...} wrapper is needed. Standalone prompt callables that are not bound to an HTTP route can be registered through LitestarMCP(prompts=[...]).
prompts/list and prompts/get driven by the same handler discovery as the rest of the surface.mcp_tool / mcp_resource / mcp_prompt kwargs straight through to Litestar's route decorators, or register standalone prompts via LitestarMCP(prompts=[...]).mcp_resource_template="app://…/{var}" dispatches concrete URIs to handlers with extracted vars.mcp_description, mcp_agent_instructions, mcp_when_to_use, mcp_returns kwargs.msgspec-powered tool-argument validation.MCPAuthBackend or a composable create_oidc_validator() factory; injectable JWKSCache protocol for shared document caches.pip install litestar-mcp
# or
uv add litestar-mcpfrom litestar import Litestar, get, post
from litestar.openapi.config import OpenAPIConfig
from litestar_mcp import LitestarMCP
# Mark routes for MCP exposure using the opt attribute
@get("/users", mcp_tool="list_users")
async def get_users() -> list[dict]:
"""List all users in the system."""
return [{"id": 1, "name": "Alice"}, {"id": 2, "name": "Bob"}]
@post("/analyze", mcp_tool="analyze_data")
async def analyze_data(data: dict) -> dict:
"""Analyze the provided data and return insights."""
return {"result": f"Analyzed {len(data)} items"}
@get("/config", mcp_resource="app_config")
async def get_app_config() -> dict:
"""Get the current application configuration."""
return {"debug": True, "version": "1.0.0"}
# Add the MCP plugin to your Litestar app
app = Litestar(
route_handlers=[get_users, analyze_data, get_app_config],
plugins=[LitestarMCP()],
openapi_config=OpenAPIConfig(title="My API", version="1.0.0"),
)from litestar_mcp import LitestarMCP, MCPConfig
config = MCPConfig(
base_path="/api/mcp", # Change the base path
name="Custom Server Name", # Override server name
include_in_schema=True, # Include MCP routes in OpenAPI schema
)
app = Litestar(
route_handlers=[get_users, analyze_data, get_app_config],
plugins=[LitestarMCP(config)],
openapi_config=OpenAPIConfig(title="My API", version="1.0.0"),
)mcp_resource) forExamples:
@get("/schema", mcp_resource="database_schema")
async def get_schema() -> dict:
"""Database schema information."""
return {"tables": ["users", "orders"], "relationships": [...]}
@get("/docs", mcp_resource="api_docs")
async def get_documentation() -> dict:
"""API documentation and usage examples."""
return {"endpoints": [...], "examples": [...]}mcp_tool) forExamples:
@post("/users", mcp_tool="create_user")
async def create_user(user_data: dict) -> dict:
"""Create a new user account."""
# Perform user creation logic
return {"id": 123, "created": True}
@get("/search", mcp_tool="search_data")
async def search(query: str, limit: int = 10) -> dict:
"""Search through application data."""
# Perform search with parameters
return {"results": [...], "total": 42}opt attributemcp_tool or mcp_resource are automatically exposed/mcp)Once configured, your application exposes these MCP-compatible endpoints:
GET /mcp - Server-Sent Events stream when Accept: text/event-stream is providedPOST /mcp - JSON-RPC endpoint for initialize, ping, tools/*, resources/*, and optional task methodsGET /.well-known/mcp-server.json - MCP server manifestGET /.well-known/agent-card.json - Agent metadata cardGET /.well-known/oauth-protected-resource - OAuth protected resource metadata when auth is configuredBuilt-in Resources:
litestar://openapi - Your application's OpenAPI schema (always available via resources/read)Configure the plugin using MCPConfig:
from litestar_mcp import MCPConfig
config = MCPConfig()Configuration Options:
| Option | Type | Default | Description | |
|---|---|---|---|---|
base_path | str | "/mcp" | Base path for the MCP Streamable HTTP endpoint | |
include_in_schema | bool | False | Whether to include MCP routes in OpenAPI schema | |
name | `str \ | None` | None | Override server name. If None, uses OpenAPI title |
guards | `list[Any] \ | None` | None | Litestar guards applied to the MCP router |
allowed_origins | `list[str] \ | None` | None | Restrict accepted Origin header values |
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 | Metadata for /.well-known/oauth-protected-resource discovery |
tasks | `bool \ | MCPTaskConfig` | False | Enable experimental in-memory MCP task support |
before_tool_call | `BeforeToolCallHook \ | None` | None | Observe each tools/call before dispatch |
after_tool_call | `AfterToolCallHook \ | None` | None | Observe each tools/call result, exception, and duration |
from litestar import Litestar, get, post, delete
from litestar.openapi.config import OpenAPIConfig
from litestar_mcp import LitestarMCP, MCPConfig
# Resources - read-only reference data
@get("/users/schema", mcp_resource="user_schema")
async def get_user_schema() -> dict:
"""User data model schema."""
return {
"type": "object",
"properties": {
"id": {"type": "integer"},
"name": {"type": "string"},
"email": {"type": "string"}
}
}
@get("/api/info", mcp_resource="api_info")
async def get_api_info() -> dict:
"""API capabilities and information."""
return {
"version": "2.0.0",
"features": ["user_management", "data_analysis"],
"rate_limits": {"requests_per_minute": 1000}
}
# Tools - actionable operations
@get("/users", mcp_tool="list_users")
async def list_users(limit: int = 10) -> dict:
"""List users with optional limit."""
# Fetch users from database
return {"users": [{"id": 1, "name": "Alice"}], "total": 1}
@post("/users", mcp_tool="create_user")
async def create_user(user_data: dict) -> dict:
"""Create a new user account."""
# Create user logic
return {"id": 123, "created": True, "user": user_data}
@post("/analyze", mcp_tool="analyze_dataset")
async def analyze_dataset(config: dict) -> dict:
"""Analyze data with custom configuration."""
# Analysis logic
return {"insights": [...], "metrics": {...}}
# Regular routes (not exposed to MCP)
@get("/health")
async def health_check() -> dict:
return {"status": "healthy"}
# MCP configuration
mcp_config = MCPConfig(
name="User Management API",
base_path="/mcp"
)
# Create Litestar app
app = Litestar(
route_handlers=[
get_user_schema, get_api_info, # Resources
list_users, create_user, analyze_dataset, # Tools
health_check # Regular route
],
plugins=[LitestarMCP(mcp_config)],
openapi_config=OpenAPIConfig(
title="User Management API",
version="2.0.0"
),
)Authentication is a Litestar middleware concern. Apps with an existing auth middleware get MCP authentication for free — request.user and request.auth are populated before tool handlers run. Three integration paths:
If your Litestar app already ships an AbstractAuthenticationMiddleware (or Litestar's built-in JWT backends), MCP inherits it automatically:
from litestar import Litestar
from litestar.middleware import DefineMiddleware
from litestar_mcp import LitestarMCP, MCPConfig
app = Litestar(
route_handlers=[...],
plugins=[LitestarMCP(MCPConfig())],
middleware=[DefineMiddleware(YourAuthMiddleware)], # MCP gets this for free
)See docs/examples/notes/sqlspec/google_iap.py for a runnable example.
For OIDC workloads, install the built-in MCPAuthBackend:
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"]),
)],
)JWKS auto-discovery, caching, and clock_skew tolerance are built in. See docs/examples/notes/sqlspec/cloud_run_jwt.py for the full pattern.
create_oidc_validator() returns an async callable for use as MCPAuthBackend(token_validator=...) or inside your own middleware:
from litestar_mcp import create_oidc_validator
validator = create_oidc_validator(
"https://cloud.google.com/iap",
"/projects/PROJECT_NUMBER/global/backendServices/SERVICE_ID",
algorithms=("ES256",),
jwks_cache_ttl=1800,
)# Clone the repository
git clone https://github.com/litestar-org/litestar-mcp.git
cd litestar-mcp
# Install with development dependencies
uv sync --all-extras --dev
# Run tests
make test
# Run example
uv run python docs/examples/hello_world/main.pyMIT License. See LICENSE for details.
Contributions welcome! Please see our contribution guide for details.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.