Spanly Docs
Python SDK

Quickstart

Instrument a Python MCP server with spanly in one line.

This walks through wiring spanly into a Python MCP server. The same pattern applies whether your server uses the high-level MCPServer from the mcp package or the low-level Server class.

1. Install

pip install spanly

2. Add monitoring

from spanly import SpanlyClientspanly_client = SpanlyClient(    api_key=os.environ["SPANLY_API_KEY"],)# server = MCPServer("your-mcp-server-name", version="1.0.0")# Monitor your MCP server (one line!)spanly_client.monitor(server)# server.run()

That's it – all MCP traffic on server is now reported to your Spanly project.

SpanlyClient.monitor() patches the server's run() method to wrap the underlying read/write streams. Call it before server.run() so the initialize handshake is captured.

3. Set the API key

export SPANLY_API_KEY=spanly_us_xxxxxxxxxxxxxxxxxxxxxxxxxxxxx

SpanlyClient() reads SPANLY_API_KEY automatically. The region is encoded in the key prefix and auto-detected.

Full example – stdio MCP server

import asyncio
import os
from mcp.server import Server
from mcp.server.stdio import stdio_server
from mcp.types import TextContent, Tool

from spanly import SpanlyClient


server = Server("demo-server")


@server.list_tools()
async def list_tools() -> list[Tool]:
    return [Tool(name="echo", description="Echo input back", inputSchema={
        "type": "object",
        "properties": {"input": {"type": "string"}},
        "required": ["input"],
    })]


@server.call_tool()
async def call_tool(name: str, arguments: dict) -> list[TextContent]:
    return [TextContent(type="text", text=arguments.get("input", ""))]


async def main() -> None:
    spanly = SpanlyClient(api_key=os.environ["SPANLY_API_KEY"])
    spanly.monitor(server)

    async with stdio_server() as (read, write):
        await server.run(read, write, server.create_initialization_options())


if __name__ == "__main__":
    asyncio.run(main())

Full example – high-level MCPServer

import asyncio
import os
from mcp.server.fastmcp import FastMCP
from spanly import SpanlyClient

mcp = FastMCP("demo-fastmcp")


@mcp.tool()
async def echo(input: str) -> str:
    return input


spanly = SpanlyClient(api_key=os.environ["SPANLY_API_KEY"])
spanly.monitor(mcp)

if __name__ == "__main__":
    mcp.run()  # stdio by default

The SDK detects both MCPServer / FastMCP (which expose a _lowlevel_server attribute) and the low-level Server class directly, so the same monitor(server) call works in both cases.

Next steps

  • The API reference covers the full SpanlyClient API and MonitorOptions.
  • Examples cover async context, multi-tenant tagging, and integration with httpx / FastAPI hosts.
  • If you'd rather not change code, the CLI wraps the same server with the same capture behavior.

On this page