Metadata-Version: 2.4
Name: agnost-mcp
Version: 0.2.0
Summary: Analytics SDK for Model Context Protocol Servers
Home-page: https://github.com/agnost-ai/agnost-ai
Author: Agnost AI
Author-email: Agnost AI <founders@agnost.ai>
License: MIT
Project-URL: Homepage, https://agnost.ai
Project-URL: BugTracker, https://github.com/agnost-ai/agnost-ai/issues
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Operating System :: OS Independent
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Requires-Dist: requests>=2.25.0
Requires-Dist: mcp>=1.10
Provides-Extra: dev
Requires-Dist: pytest>=6.0; extra == "dev"
Requires-Dist: tomli>=1.1.0; python_version < "3.11" and extra == "dev"
Dynamic: author
Dynamic: home-page
Dynamic: requires-python

# Agnost Analytics SDK

[![PyPI version](https://badge.fury.io/py/agnost-mcp.svg)](https://badge.fury.io/py/agnost-mcp)
[![Python](https://img.shields.io/pypi/pyversions/agnost-mcp.svg)](https://pypi.org/project/agnost-mcp/)

Analytics SDK for tracking and analyzing Model Context Protocol (MCP) server interactions. Get insights into how your MCP servers are being used, monitor performance, and optimize user experiences.

## Installation

```bash
pip install agnost-mcp
```

## Basic Usage

```python
import agnost_mcp
from fastmcp import FastMCP

# Create FastMCP server
mcp = FastMCP("My Server")

@mcp.tool()
def calculate(operation: str, a: float, b: float) -> float:
    """Perform mathematical operations."""
    if operation == "add":
        return a + b
    elif operation == "multiply":
        return a * b
    return 0

# Enable analytics tracking
agnost_mcp.track(mcp, org_id="your-organization-id")
```

Analytics delivery runs on a bounded background queue so tool calls do not wait
for the Agnost API. Call `shutdown()` during application teardown to flush
queued events on a best-effort basis and close the worker:

```python
try:
    mcp.run()
finally:
    agnost_mcp.shutdown()
```

## Configuration

You can customize the SDK behavior using the configuration object:

```python
import agnost_mcp

# Create a custom configuration
config = agnost_mcp.config(
    endpoint="https://api.agnost.ai",
    disable_input=False,    # Set to True to disable input tracking
    disable_output=False,   # Set to True to disable output tracking
    log_level="INFO",
)

# Apply the configuration
agnost_mcp.track(
    server=server,
    org_id="your-organization-id",
    config=config
)
```

### Configuration Options

| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `endpoint` | `str` | `"https://api.agnost.ai"` | Agnost API base URL |
| `disable_input` | `bool` | `False` | Disable tracking of input arguments |
| `disable_output` | `bool` | `False` | Disable tracking of output results |
| `log_level` | `str` | `"INFO"` | SDK logging level |
| `identify` | `callable \| None` | `None` | Resolve per-session user identity from request context |

Without a custom `identify` callback, HTTP transports resolve identity from the
request's `Authorization: Bearer ...` header, falling back to the MCP server's
validated auth token when headers are unavailable. JWT claims are checked in
this order: `sub`, `user_id`, `userId`, `email`, `preferred_username`, then
`username`. An `email` claim is preserved as user metadata, and opaque bearer
tokens or `x-api-key` credentials are represented by a stable one-way hash; raw
credentials are never sent to Agnost.

The `identify` callback may be synchronous or asynchronous. It must return a
dictionary containing `userId`, or `None` to skip attribution for that attempt.
Failed or anonymous results are retried instead of being cached for the process.

Stateful Streamable HTTP and SSE calls reuse their MCP session. Stateless
Streamable HTTP groups calls by OAuth token/grant ID when available, then by
resolved user, then by one bounded anonymous bucket. Stdio remains scoped to
the server process. Multiple server instances in one process are supported when
they use the same organization and config; mismatches are rejected rather than
silently misattributed.

## Contact

For support or questions, contact the founders: [founders@agnost.ai](mailto:founders@agnost.ai)
