Configuration

The Litestar MCP plugin is configured through MCPConfig. This page walks through each knob the plugin exposes, from a default registration to task-lifecycle support.

Minimal Setup

The plugin registers with sensible defaults when no configuration is passed. Every marked route is picked up and served from /mcp.

docs/examples/snippets/configuration_minimal.py
app = Litestar(route_handlers=[], plugins=[LitestarMCP()])

Custom Configuration

Override the base path, server name, or OpenAPI visibility via MCPConfig.

docs/examples/snippets/configuration_custom.py
config = MCPConfig(
    base_path="/api/mcp",
    name="My MCP Server",
    include_in_schema=True,
)
app = Litestar(route_handlers=[], plugins=[LitestarMCP(config)])

Auth-Enabled Configuration

Attach an MCPAuthConfig to require bearer tokens on MCP endpoints and publish /.well-known/oauth-protected-resource. See Authentication for the full authentication story.

docs/examples/snippets/configuration_auth.py
auth = MCPAuthConfig(
    issuer="https://auth.example.com",
    audience="https://api.example.com/mcp",
    scopes={"mcp:read": "Read access to MCP resources"},
)
config = MCPConfig(auth=auth)
app = Litestar(route_handlers=[], plugins=[LitestarMCP(config)])

Standalone Prompts

Prompt callables that are not bound to an HTTP route are registered by passing them to LitestarMCP(prompts=[...]). Each function must first be decorated with mcp_prompt(); the plugin rejects plain callables to keep prompt metadata explicit.

docs/examples/snippets/configuration_prompts.py
app = Litestar(
    route_handlers=[],
    plugins=[
        LitestarMCP(
            MCPConfig(name="prompt-demo"),
            prompts=[greet],
        ),
    ],
)

See Marking Routes for the handler-based mcp_prompt opt-key form, which routes a prompt under HTTP and publishes it via prompts/get.

Task Lifecycle

Enable the experimental in-memory task endpoints by passing an MCPTaskConfig. Tasks let MCP clients submit long-running work and poll for completion.

docs/examples/snippets/configuration_tasks.py
config = MCPConfig(
    tasks=MCPTaskConfig(enabled=True, default_ttl=300_000),
)
app = Litestar(route_handlers=[], plugins=[LitestarMCP(config)])

Configuration Options

Option

Default

Description

base_path

"/mcp"

Base path for the MCP Streamable HTTP endpoint.

include_in_schema

False

Whether to include MCP routes in the OpenAPI schema.

name

None

Server name override (falls back to the OpenAPI title).

guards

None

Litestar guards applied to the MCP router.

allowed_origins

None

Restrict accepted Origin header values.

include_operations / exclude_operations

None

Filter exposure by Litestar operation name.

include_tags / exclude_tags

None

Filter exposure by OpenAPI tags.

auth

None

Enable bearer-token validation and OAuth protected-resource metadata.

tasks

False

Enable experimental in-memory MCP task support.

before_tool_call

None

Optional callback invoked once before each tools/call dispatch.

after_tool_call

None

Optional callback invoked once after each tools/call dispatch with the result or exception and elapsed duration.

list_page_size

100

Server-chosen page size for the */list methods (see below).

The LitestarMCP constructor also accepts a top-level prompts argument — a sequence of @mcp_prompt-decorated callables — for standalone prompt registration (see above).

Filters apply both to list responses and direct invocation. A filtered tool or resource is omitted from tools/list, resources/list, or resources/templates/list and a direct tools/call / resources/read returns the same not-found response as an unknown name or URI. Filters narrow the MCP exposure surface; use guards or auth middleware for access control.

Tool-Call Callbacks

Use before_tool_call and after_tool_call when you need audit, metrics, or tracing hooks that are independent of route ownership layers. Both callbacks receive the MCP tool name, a shallow copy of the submitted arguments, and the synthesized litestar.Request used for the handler dispatch. after_tool_call also receives result, exception, and duration keyword-only values, and fires for successes, guard failures, error responses, and unhandled exceptions. Callback exceptions are logged and swallowed so observability code does not alter tool-call behavior.

docs/examples/snippets/configuration_tool_callbacks.py
async def after_tool_call(
    tool_name: str,
    arguments: dict[str, Any],
    request: Request[Any, Any, Any],
    *,
    result: Any,
    exception: Exception | None,
    duration: float,
) -> None:
    request.app.logger.info(
        "mcp tool=%s duration=%0.4f failed=%s",
        tool_name,
        duration,
        exception is not None,
    )


config = MCPConfig(after_tool_call=after_tool_call)

List Pagination

tools/list, resources/list, resources/templates/list, and prompts/list are paginated per the MCP spec's opaque-cursor model. Each accepts an optional cursor parameter and returns nextCursor when another page is available; treat nextCursor as an opaque token and pass it back as params.cursor until the response omits it. An invalid cursor returns INVALID_PARAMS (-32602).

The MCP spec lets the server pick the page size — clients cannot request a limit on these methods. Set it with the MCPConfig.list_page_size option (e.g. MCPConfig(list_page_size=25)); it defaults to 100 and must be a positive integer.

These methods enumerate the catalog of registered primitives, which is built once at startup; the cursor is a base64-encoded offset into that stable list. For paginating application data, see tasks/list (which accepts a client limit and delegates to a task store) or implement paging inside an individual tool.

Environment Overrides

MCPConfig is a plain dataclass, so the ordinary Litestar pattern applies: read the environment before constructing it and pass the resolved values through. For example, to keep base_path and name configurable at deploy time:

export MCP_BASE_PATH=/api/mcp
export MCP_SERVER_NAME="My MCP Server"

Then build MCPConfig using os.getenv for each option - the shape is identical to the Custom Configuration snippet above, just with environment lookups replacing literal values.