Marking Routes

Routes are exposed to MCP by attaching metadata to their opt dictionary. The plugin scans every handler at startup and treats any route tagged with mcp_tool, mcp_resource, or mcp_prompt as part of the MCP surface. Standalone prompt callables that are not routed under HTTP are registered separately via LitestarMCP(prompts=[...]) — see Prompt Marker below.

Tool Marker

Tools are executable operations - anything that takes arguments and returns structured output. Tag a handler with mcp_tool="<tool_name>" and the plugin publishes it via tools/list and tools/call.

docs/examples/snippets/marking_tools.py
@get("/users/{user_id:int}", mcp_tool="get_user")
async def get_user(user_id: int) -> dict[str, int]:
    """Return a user by ID - exposed as the ``get_user`` MCP tool."""
    return {"id": user_id}

app = Litestar(route_handlers=[get_user], plugins=[LitestarMCP()])

Resource Marker

Resources are read-only payloads such as schemas, capability summaries, or cached projections. Tag a handler with mcp_resource="<resource_name>" to expose it via resources/list and resources/read.

docs/examples/snippets/marking_resources.py
@get("/api/schema", mcp_resource="api_schema")
async def get_schema() -> dict[str, Any]:
    """Return the API JSON schema - exposed as the ``api_schema`` MCP resource."""
    return {"type": "object", "properties": {}}

app = Litestar(route_handlers=[get_schema], plugins=[LitestarMCP()])

Prompt Marker

Prompts are templated instructions for a model. The plugin recognises two registration paths.

Handler-based prompts. Tag a Litestar route handler with mcp_prompt="<prompt_name>". The handler stays a normal HTTP endpoint and is also reachable through prompts/get. Override the description, title, argument list, or icons through dedicated opt keys:

Opt key

Effect

mcp_prompt

Required. The prompt name used in prompts/get.

mcp_prompt_description

LLM-facing description (falls back to the handler's docstring).

mcp_prompt_title

Optional human-readable title for UI clients.

mcp_prompt_arguments

Explicit argument list (a list[dict[str, Any]]). When omitted, the plugin introspects the handler's parsed_fn_signature, filters out DI dependencies and framework-injected parameters (request, headers, state, …), and enriches each entry with Google-style docstring descriptions.

mcp_prompt_icons

Optional list of MCP icon objects (src, mimeType, sizes).

Standalone prompt functions. Decorate a plain callable with mcp_prompt() and pass it to LitestarMCP(prompts=[...]). These never appear in the HTTP route table — they are MCP-only.

docs/examples/snippets/marking_prompts.py
@mcp_prompt(name="summarize", description="Summarise a document in a chosen style.")
async def summarize(text: str, style: str = "concise") -> str:
    """Build a summarisation prompt.

    Args:
        text: The document to summarise.
        style: Summary style, e.g. ``concise`` or ``detailed``.
    """
    return f"Summarise the following in a {style} style:\n\n{text}"

@get(
    "/prompts/code-review",
    mcp_prompt="code_review",
    mcp_prompt_description="Ask the model to review a code diff.",
)
async def code_review(code: str) -> dict[str, object]:
    """Handler-based prompt: routed under HTTP *and* exposed via ``prompts/get``."""
    return {"messages": [{"role": "user", "content": {"type": "text", "text": f"Review: {code}"}}]}

app = Litestar(
    route_handlers=[code_review],
    plugins=[LitestarMCP(prompts=[summarize])],
)

Dependency Injection

Marked routes participate in Litestar's dependency injection system exactly like any other handler. Provide dependencies via dependencies={...} and declare them in the signature; the plugin resolves them for each tools/call.

docs/examples/snippets/marking_dependencies.py
@get("/me", mcp_tool="whoami", dependencies={"current_user": Provide(provide_current_user)})
async def whoami(current_user: "dict[str, Any]") -> "dict[str, Any]":
    """Return the resolved current user - exposed as the ``whoami`` MCP tool."""
    return current_user

app = Litestar(route_handlers=[whoami], plugins=[LitestarMCP()])

Decorator Variant

If you prefer a dedicated decorator over the kwargs form, litestar_mcp ships mcp_tool(), mcp_resource(), and mcp_prompt(). The tool and resource decorators carry the same metadata as the opt kwargs and are interchangeable at discovery time on a route handler.

mcp_prompt is different: the decorator and the mcp_prompt_* opt keys target different registration paths. Use the opt keys to expose a Litestar route handler as a prompt. Use the decorator to mark a plain callable that you hand to LitestarMCP(prompts=[...]). The decorator does not act as the route-handler marker.

Prefer this when you are already passing route options inline:

@get("/users/{user_id:int}", mcp_tool="get_user")
async def get_user(user_id: int) -> dict[str, int]:
    """Return a user by ID - exposed as the ``get_user`` MCP tool."""
    return {"id": user_id}

app = Litestar(route_handlers=[get_user], plugins=[LitestarMCP()])

Note

Both forms end up at the same registry entry. Pick one per project for consistency; mixing is supported but harder to audit.