[DEVELOPER DOCS]

Instrument your MCP server

The SDK captures Model Context Protocol traffic from inside your server process. Install it, call instrument() once after your tools are registered, and set what gets captured. Python and TypeScript, over stdio, streamable HTTP or SSE.

[QUICKSTART]

Install and call it

Call instrument() once, after your tools are registered and before the server starts serving. Pick your language and framework, or hand the job to your coding agent.

[01]

Install

shell
pip install vesta-analytics

Requires Python 3.12 or newer. The only runtime dependency is OpenTelemetry.

[02]

Instrument your server

server.py
import os

import vesta
from mcp.server.lowlevel import Server

server = Server("my-server")
# register your tools, then:

vesta.instrument(
    server,
    api_key=os.environ["VESTA_API_KEY"],
    session_context=lambda request: {
        # who the end user is. Omit on authenticated servers; Vesta
        # derives a pseudonymous user_id from the token automatically.
        "user_id": user_id_from(request),
    },
)

Call instrument() after your tools are registered and before the server starts serving. The call is idempotent and fail-open; an error in the SDK never reaches the request path. session_context is optional and attaches per-session dimensions.

[Checking it worked]

Call get_status on the Vesta MCP server, or open the console — both report whether your server is receiving.

Analysis runs daily, so a first day that says receiving with nothing analysed yet is correct.

[PRIVACY]

What leaves your process

Redaction runs inside your own process, before anything is sent. Raw payloads never leave your environment. By default Vesta redacts every tool argument and response value, so you get the shape of each call, the tool name, the timing and the errors, but not the contents.

If you open capture up, a built-in denylist still scrubs common sensitive fields by name, like email, password, ssn, credit_card, api_keyand auth tokens. It's the lowest-precedence rule, so widening capture doesn't quietly start sending PII unless you name a sensitive field yourself.

Set your own rules for tighter control: capture the non-sensitive fields you want to analyse, hash the ones you need joinable but not readable, redact or truncate the rest. Rules apply per field.

redaction.py
import os

from vesta import RedactionConfig, Field

# arguments and responses are redacted by default.
# capture only the non-sensitive fields you want to analyse.
args = RedactionConfig(
    default="redact",
    rules=[
        Field("query").capture(),       # the agent's search text
        Field("category").capture(),
        Field("account_id").hash(),     # joinable, not readable
    ],
)

vesta.instrument(server, api_key=os.environ["VESTA_API_KEY"], args=args)

Selectors: Field, Tool, Prompt, Resource, Method. Actions: capture(), redact(), hash(), truncate(n). Pass responses= for response payloads.

[SUPPORT]

Support and guarantees

Python, on the official mcp SDK and FastMCP. TypeScript, on the official MCP SDK. Transport — stdio, streamable HTTP or SSE — is auto-detected, so there is no transport-specific code to write.

The call is fail-open, so an error inside Vesta never reaches your request path, and idempotent, so a second call is a no-op. It runs in your process and exports traces asynchronously over OpenTelemetry.

Sending data needs an API key. Request access to get one.