# lauren-mcp > Model Context Protocol (MCP) server and client for the Lauren web framework. ## What is lauren-mcp? `lauren-mcp` extends the Lauren Python web framework with support for the Model Context Protocol. It provides two capabilities: **Server**: Expose any Lauren service as an MCP server. AI clients (Claude, custom agents, etc.) can discover and call your service's tools over WebSocket, HTTP+SSE, or Streamable HTTP. **Client**: Connect to any remote MCP server (stdio, WebSocket, HTTP+SSE, Streamable HTTP) and wire its tools into a Lauren AI agent with automatic namespacing. ## Installation ``` pip install lauren-mcp # core pip install "lauren-mcp[ws]" # WebSocket client pip install "lauren-mcp[http]" # HTTP+SSE client (legacy 2024-11-05) pip install "lauren-mcp[pydantic]" # Pydantic schema generation pip install "lauren-mcp[msgspec]" # msgspec.Struct schema generation pip install "lauren-mcp[cli]" # lmcp CLI (typer + uvicorn) pip install "lauren-mcp[otel]" # OpenTelemetry tracing pip install "lauren-mcp[all]" # everything ``` ## Protocol versions Supported: `2024-11-05`, `2025-03-26`, `2025-06-18`, `2025-11-25` (LATEST) ## Server API - `@mcp_server(path, *, transport="ws")` — transport: `"ws"` | `"sse"` | `"streamable"` | `"both"` | `"all"` - `@mcp_tool(*, name, description, annotations, timeout, tags, meta, output_schema, structured_output)` - `@mcp_resource(uri_template, *, name, description, mime_type)` — RFC 6570: `{+p}`, `{p*}`, `{?p1,p2}` - `@mcp_prompt(name, *, description)`, `@mcp_completion(target, argument)`, `@mcp_lifespan` - `McpToolContext` — injected via type annotation in tool methods - `ctx.report_progress()`, `ctx.log()`, `ctx.sample()`, `ctx.elicit()`, `ctx.cancel_requested` - `ctx.lifespan_context` — dict yielded by `@mcp_lifespan` - `McpServerModule.for_root(cls, *, transport, log_level, mounts, proxies, event_store, instrument_otel, stateless_http)` - `ToolAnnotations(readOnlyHint, destructiveHint, idempotentHint, openWorldHint)` - Schema: Pydantic, `msgspec.Struct`, `@dataclass`, `TypedDict`, `Literal`, `Annotated+Field` all supported - Binary resources: `bytes` → blob; `BlobResource(data, mime_type)`; `ResourceResult(contents)` - Server composition: `mounts=[(OtherCls, "prefix_")]`, `proxies=[(client, "prefix_")]` - Built-in resources: `FileResource`, `HttpResource`, `DirectoryResource` - `build_openapi_server_class(spec, http_client=...)` — OpenAPI → MCP ## Per-method decorators (from Lauren framework) Order: `@mcp_tool()` outermost, Lauren decorators inside (closer to `async def`). - `@use_guards(GuardClass)` — runs before the method; guard receives `McpExecutionContext`; return `False` → `INTERNAL_ERROR` with `data.type="FORBIDDEN"` - `@use_interceptors(InterceptorClass)` — wraps the method call; call `await call_handler.handle()` to proceed; receives `McpExecutionContext` + `McpCallHandler` - `@use_exception_handlers(HandlerClass)` — catches domain exceptions and returns `isError: True` in the tool result - `@set_metadata(key, value)` — per-tool metadata; read via `ctx.get_metadata(key)` inside the tool body - `@use_middlewares` on `@mcp_tool` → `TypeError` (not meaningful at dispatch level) New types: `McpExecutionContext`, `McpForbiddenError`, `McpCallHandler` ## Client API - `McpServer.stdio(command)` — subprocess stdin/stdout, no extra deps - `McpServer.ws(url)` — WebSocket (requires `[ws]`) - `McpServer.http(url)` — legacy HTTP+SSE 2024-11-05 (requires `[http]`) - `McpServer.streamable_http(url)` — Streamable HTTP, recommended (requires `[http]`) All factories accept: `protocol_version=`, `roots=[Root(...)]`, `progress_handler=`, `log_handler=`, `list_changed_handler=`, `resource_updated_handler=`, `sampling_handler=`, `elicitation_handler=` Post-connect: `client.protocol_version`, `client.on_progress/on_log/on_list_changed()` → unsubscribe callable Additional methods: `client.subscribe_resource(uri)`, `client.unsubscribe_resource(uri)`, `client.complete(ref, argument)`, `client.set_logging_level(level)` OAuth: `ClientCredentialsProvider(token_endpoint, client_id, client_secret, scopes=)` ## Wire types (selected) `TextContent`, `ImageContent`, `AudioContent`, `EmbeddedResource`, `ResourceLink`, `AnyContent`, `ToolUseContent`, `ToolResultContent`, `ResourceAnnotations`, `UrlElicitResult`, `CompletionResult`, `validate_sampling_messages` ## Quick example ```python from lauren_mcp import mcp_server, mcp_tool, McpToolContext, McpServerModule, McpServer from lauren_mcp.server import mcp_lifespan from lauren import LaurenFactory, module @mcp_server("/mcp") class MyServer: @mcp_lifespan async def lifespan(self): db = await init_db() try: yield {"db": db} finally: await db.close() @mcp_tool(timeout=30.0) async def search(self, query: str, ctx: McpToolContext) -> list: """Search items. Args: query: Search terms.""" await ctx.report_progress(0, 100, "searching") return await ctx.lifespan_context["db"].search(query) @module(imports=[McpServerModule.for_root(MyServer, transport="all")]) class App: pass app = LaurenFactory.create(App) # Client client = McpServer.streamable_http("http://localhost:8000/mcp", progress_handler=lambda p: print(p["message"])) await client.connect() result = await client.call_tool("search", {"query": "coffee"}) ``` ## Wire protocol JSON-RPC 2.0 over four transports: | Transport | Extra | Endpoint | |---|---|---| | stdio | (none) | subprocess stdin/stdout | | WebSocket | `[ws]` | `{path}/ws` | | HTTP+SSE (legacy) | `[http]` | `GET {path}/sse` + `POST {path}/` | | Streamable HTTP | `[http]` | `POST/GET/DELETE {path}/` | ## Key utility types - `McpCallError` — raised when the server returns a JSON-RPC error response - `McpServerConfig(alias, client)` — config for one remote MCP server - `McpToolBridge([configs])` — lifecycle manager for a list of McpServerConfig - Tool namespacing: `{alias}__{tool_name}` prevents collisions - `LATEST`, `STABLE`, `SUPPORTED` — protocol version constants ## Links - Documentation: https://lauren-framework.github.io/lauren-mcp/ - Source: https://github.com/lauren-framework/lauren-mcp - PyPI: https://pypi.org/project/lauren-mcp/ - llms-full.txt: https://raw.githubusercontent.com/lauren-framework/lauren-mcp/refs/heads/main/llms-full.txt