# DevRev Python SDK & MCP Server - Full Context for AI Agents

## Overview

A modern, type-safe Python SDK and MCP Server for the DevRev API with:
- Full async support (sync and async clients)
- Pydantic v2 models for all requests/responses
- Comprehensive error handling with typed exceptions
- Connection pooling and circuit breaker pattern
- ETag caching for conditional requests

**Requirements**: Python 3.11+
**Install**: `pip install devrev-python-sdk`
**Install with MCP**: `pip install devrev-python-sdk[mcp]`
**Docs**: https://mgmonteleone.github.io/py-dev-rev/
**Version**: 2.7.0

## Authentication

### Environment Variable (Recommended)
```bash
export DEVREV_API_TOKEN="your-api-token"
```

```python
from devrev import DevRevClient
client = DevRevClient()  # Reads from environment
```

### Direct Token
```python
client = DevRevClient(api_token="your-token")
```

### Configuration Object
```python
from devrev import DevRevClient, DevRevConfig

config = DevRevConfig(
    api_token="your-token",
    timeout=60,
    max_retries=3
)
client = DevRevClient(config=config)
```

## Sync Client Usage

```python
from devrev import DevRevClient

# Using context manager (recommended)
with DevRevClient() as client:
    accounts = client.accounts.list(limit=10)
    for account in accounts.accounts:
        print(f"{account.id}: {account.display_name}")

# Or create and close manually
client = DevRevClient()
try:
    response = client.works.get(id="don:core:dvrv-us-1:devo/1:ticket/123")
    print(f"Title: {response.work.title}")
finally:
    client.close()
```

## Async Client Usage

```python
import asyncio
from devrev import AsyncDevRevClient

async def main():
    async with AsyncDevRevClient() as client:
        # Single request
        accounts = await client.accounts.list(limit=10)
        
        # Parallel requests
        accounts, works, users = await asyncio.gather(
            client.accounts.list(limit=10),
            client.works.list(limit=50),
            client.dev_users.list()
        )
        
        print(f"Accounts: {len(accounts.accounts)}")
        print(f"Works: {len(works.works)}")
        print(f"Users: {len(users.dev_users)}")

asyncio.run(main())
```

## Available Services

Access via `client.<service>.<method>()`:

### Account Management
- `accounts.list(limit, cursor)` → `AccountsListResponse`
- `accounts.get(id)` → `AccountsGetResponse`
- `accounts.create(display_name, ...)` → `AccountsCreateResponse`
- `accounts.update(id, display_name, ...)` → `AccountsUpdateResponse`
- `accounts.delete(id)` → None

### Work Items (Tickets, Issues)
- `works.list(limit, cursor, type, stage_name, ...)` → `WorksListResponse`
- `works.get(id)` → `WorksGetResponse`
- `works.create(type, title, applies_to_part, body, ...)` → `WorksCreateResponse`
- `works.update(id, title, body, ...)` → `WorksUpdateResponse`
- `works.count(type, ...)` → `WorksCountResponse`
- `works.export(type, first, ...)` → `WorksExportResponse`

### Users
- `dev_users.list(limit, cursor)` → `DevUsersListResponse`
- `dev_users.get(id)` → `DevUsersGetResponse`
- `rev_users.list(limit, cursor)` → `RevUsersListResponse`
- `rev_users.get(id)` → `RevUsersGetResponse`
- `rev_users.create(email, display_name, ...)` → `RevUsersCreateResponse`

### Parts & Articles
- `parts.list(limit, cursor, type)` → `PartsListResponse`
- `parts.get(id)` → `PartsGetResponse`
- `articles.list(limit, cursor)` → `ArticlesListResponse`
- `articles.get(id)` → `ArticlesGetResponse`
- `articles.create(title, resource, ...)` → `ArticlesCreateResponse`

### Other Services
- `conversations.list/get/create` - Customer conversations
- `tags.list/get/create` - Tag management
- `groups.list/get/create` - Group management
- `webhooks.list/get/create/delete` - Webhook configuration
- `slas.list/get` - Service level agreements
- `timeline_entries.list/create` - Activity log
- `links.list/create/delete` - Object relationships
- `code_changes.list` - Code change tracking

## Models

Import from `devrev.models`:

```python
from devrev.models import (
    WorkType,          # TICKET, ISSUE, OPPORTUNITY, etc.
    AccountType,       # CUSTOMER, PROSPECT, etc.
    PartType,          # PRODUCT, CAPABILITY, FEATURE, etc.
    Visibility,        # INTERNAL, EXTERNAL, PRIVATE
)
```

## Creating Work Items

```python
from devrev import DevRevClient
from devrev.models import WorkType

client = DevRevClient()

# Create a ticket
response = client.works.create(
    type=WorkType.TICKET,
    title="Customer cannot access dashboard",
    applies_to_part="don:core:dvrv-us-1:devo/1:part/1",
    body="Customer reports 500 error when loading the dashboard.",
    owned_by=["don:identity:dvrv-us-1:devo/1:devu/123"]
)
print(f"Created: {response.work.display_id}")

# Create an issue
response = client.works.create(
    type=WorkType.ISSUE,
    title="Fix dashboard loading error",
    applies_to_part="don:core:dvrv-us-1:devo/1:part/1",
    body="Investigate and fix 500 error on dashboard load."
)
```

## Pagination

DevRev uses cursor-based pagination:

```python
cursor = None
all_works = []

while True:
    response = client.works.list(cursor=cursor, limit=100)
    all_works.extend(response.works)
    
    cursor = response.next_cursor
    if not cursor:
        break

print(f"Total: {len(all_works)} works")
```

## Error Handling

Exception hierarchy from `devrev.exceptions`:

```
DevRevError (base)
├── AuthenticationError (401) - Invalid/missing API token
├── ForbiddenError (403) - Permission denied
├── NotFoundError (404) - Resource not found
├── ValidationError (400) - Invalid request data
├── ConflictError (409) - Resource conflict
├── RateLimitError (429) - Rate limit exceeded (.retry_after seconds)
├── ServerError (500) - Server error
├── ServiceUnavailableError (503) - Service unavailable
├── TimeoutError - Request timeout
├── NetworkError - Network connectivity issue
├── CircuitBreakerError - Circuit breaker is open
└── ConfigurationError - Invalid configuration
```

### Error Handling Pattern

```python
from devrev import DevRevClient
from devrev.exceptions import (
    DevRevError,
    NotFoundError,
    ValidationError,
    RateLimitError,
    AuthenticationError
)
import time

client = DevRevClient()

try:
    work = client.works.get(id="don:core:dvrv-us-1:devo/1:ticket/123")
    print(f"Title: {work.work.title}")
except NotFoundError as e:
    print(f"Work not found: {e.message}")
except ValidationError as e:
    print(f"Invalid request: {e.message}")
except RateLimitError as e:
    print(f"Rate limited, retry after {e.retry_after} seconds")
    time.sleep(e.retry_after)
except AuthenticationError as e:
    print(f"Auth failed: {e.message}")
except DevRevError as e:
    print(f"API error: {e.message}, status: {e.status_code}")
```

## Beta API

Enable beta features for incidents, engagements, brands, search, recommendations:

```python
from devrev import DevRevClient, APIVersion

# Enable beta API
client = DevRevClient(api_version=APIVersion.BETA)

# Or via environment variable:
# export DEVREV_API_VERSION=beta

# Beta-only services
incidents = client.incidents.list()
engagements = client.engagements.list()
brands = client.brands.list()
search_results = client.search.hybrid(query="dashboard error")
```

### Beta Services
- `incidents` - Incident management with SLA integration
- `engagements` - Customer interaction tracking
- `brands` - Multi-brand support
- `uoms` - Unit of measurement and metering
- `question_answers` - Q&A for knowledge base
- `recommendations` - AI-powered chat completions
- `search` - Hybrid search (keyword + semantic)

## Framework Integrations

### FastAPI

```python
from contextlib import asynccontextmanager
from fastapi import FastAPI, Depends
from devrev import AsyncDevRevClient

@asynccontextmanager
async def lifespan(app: FastAPI):
    app.state.devrev = AsyncDevRevClient()
    yield
    await app.state.devrev.close()

app = FastAPI(lifespan=lifespan)

def get_client() -> AsyncDevRevClient:
    return app.state.devrev

@app.get("/accounts")
async def list_accounts(client: AsyncDevRevClient = Depends(get_client)):
    response = await client.accounts.list(limit=10)
    return {"accounts": [a.model_dump() for a in response.accounts]}
```

### Flask

```python
from flask import Flask, g
from devrev import DevRevClient

app = Flask(__name__)

def get_client() -> DevRevClient:
    if "devrev" not in g:
        g.devrev = DevRevClient()
    return g.devrev

@app.teardown_appcontext
def close_client(error):
    client = g.pop("devrev", None)
    if client:
        client.close()

@app.route("/accounts")
def list_accounts():
    client = get_client()
    response = client.accounts.list(limit=10)
    return {"accounts": [a.model_dump() for a in response.accounts]}
```

## Important Notes for AI Code Generation

1. **Environment Variables**: Always use `DEVREV_API_TOKEN` env var, never hardcode tokens
2. **Context Managers**: Use `with`/`async with` for automatic resource cleanup
3. **Response Structure**: Data is nested (e.g., `response.accounts`, `response.work`)
4. **ID Format**: DevRev uses DON IDs: `don:core:dvrv-us-1:devo/1:ticket/123`
5. **Pagination**: Cursor-based using `cursor` and `next_cursor`, not page numbers
6. **Type Safety**: Use `WorkType`, `AccountType` enums from `devrev.models`
7. **Imports**: Models from `devrev.models`, exceptions from `devrev.exceptions`
8. **Async**: Use `AsyncDevRevClient` with `await` for all API calls
9. **Error Properties**: All exceptions have `.message`, `.status_code`, `.request_id`
10. **Rate Limits**: `RateLimitError` has `.retry_after` attribute in seconds

## MCP Server

The DevRev MCP Server exposes the full DevRev platform as AI-accessible tools, resources, and prompts through the Model Context Protocol (MCP).

### Installation & Quick Start

```bash
# Install with MCP extras
pip install devrev-python-sdk[mcp]

# Set your DevRev API token
export DEVREV_API_TOKEN="your-token"

# Run the server (stdio transport for local use)
devrev-mcp-server

# Run with HTTP transport for production
devrev-mcp-server --transport streamable-http --host 0.0.0.0 --port 8080
```

### Client Configuration

#### Augment Code (VS Code / JetBrains)
```json
{
  "mcpServers": {
    "devrev": {
      "command": "devrev-mcp-server",
      "env": {
        "DEVREV_API_TOKEN": "<your-token>",
        "MCP_ENABLE_BETA_TOOLS": "true",
        "MCP_ENABLE_DESTRUCTIVE_TOOLS": "false",
        "MCP_LOG_LEVEL": "INFO"
      }
    }
  }
}
```

#### Claude Desktop
```json
{
  "mcpServers": {
    "devrev": {
      "command": "devrev-mcp-server",
      "env": { "DEVREV_API_TOKEN": "your-token" }
    }
  }
}
```

#### Remote (Cloud Run with per-user PAT)
```json
{
  "mcpServers": {
    "devrev": {
      "type": "http",
      "url": "https://devrev-mcp-server-<hash>-uc.a.run.app/mcp",
      "headers": {
        "Authorization": "Bearer <your-devrev-personal-access-token>"
      }
    }
  }
}
```

### Environment Variables

| Variable | Default | Description |
|----------|---------|-------------|
| `DEVREV_API_TOKEN` | Required | DevRev API token |
| `MCP_TRANSPORT` | `stdio` | Transport: `stdio`, `streamable-http`, `sse` |
| `MCP_HOST` | `127.0.0.1` | Bind host (HTTP transports) |
| `MCP_PORT` | `8080` | Bind port (HTTP transports) |
| `MCP_ENABLE_BETA_TOOLS` | `true` | Enable beta tools |
| `MCP_ENABLE_DESTRUCTIVE_TOOLS` | `true` | Enable create/update/delete |
| `MCP_LOG_LEVEL` | `INFO` | Logging level |
| `MCP_LOG_FORMAT` | `json` | Log format: `text` or `json` |
| `MCP_AUTH_MODE` | `devrev-pat` | Auth: `devrev-pat` or `static-token` |
| `MCP_AUTH_TOKEN` | — | Bearer token (static-token mode) |
| `MCP_AUTH_ALLOWED_DOMAINS` | `augmentcode.com` | Allowed email domains (devrev-pat mode) |
| `MCP_RATE_LIMIT_RPM` | `120` | Max requests per minute per session |
| `MCP_DEFAULT_PAGE_SIZE` | `25` | Default page size |
| `MCP_MAX_PAGE_SIZE` | `100` | Maximum page size |

### Tools (78+)

#### Core Tools (always available)
- Works: `devrev_works_list`, `devrev_works_get`, `devrev_works_create`, `devrev_works_update`, `devrev_works_delete`, `devrev_works_count`, `devrev_works_export`
- Accounts: `devrev_accounts_list`, `devrev_accounts_get`, `devrev_accounts_create`, `devrev_accounts_update`, `devrev_accounts_delete`
- Dev Users: `devrev_dev_users_list`, `devrev_dev_users_get`
- Rev Users: `devrev_rev_users_list`, `devrev_rev_users_get`, `devrev_rev_users_create`, `devrev_rev_users_update`
- Articles: `devrev_articles_list`, `devrev_articles_get`, `devrev_articles_create`, `devrev_articles_update`, `devrev_articles_delete`, `devrev_articles_count`
- Conversations: `devrev_conversations_list`, `devrev_conversations_get`, `devrev_conversations_create`, `devrev_conversations_update`
- Parts: `devrev_parts_list`, `devrev_parts_get`, `devrev_parts_create`, `devrev_parts_update`
- Tags: `devrev_tags_list`, `devrev_tags_get`, `devrev_tags_create`, `devrev_tags_update`
- Groups: `devrev_groups_list`, `devrev_groups_get`, `devrev_groups_create`, `devrev_groups_update`
- Timeline: `devrev_timeline_entries_list`, `devrev_timeline_entries_create`
- Links: `devrev_links_list`, `devrev_links_create`, `devrev_links_delete`
- SLAs: `devrev_slas_list`, `devrev_slas_get`

#### Beta Tools (require MCP_ENABLE_BETA_TOOLS=true)
- Search: `devrev_search` — Hybrid search across DevRev objects
- Recommendations: `devrev_recommendations` — AI-powered recommendations
- Incidents: `devrev_incidents_list`, `devrev_incidents_get`
- Engagements: `devrev_engagements_list`, `devrev_engagements_get`

### Resources (6)

URI-addressable DevRev objects:
- `devrev://tickets/{id}` — Ticket details
- `devrev://accounts/{id}` — Account details
- `devrev://articles/{id}` — Article content
- `devrev://users/{id}` — User profile
- `devrev://parts/{id}` — Part details
- `devrev://conversations/{id}` — Conversation history

### Prompts (8)

Pre-built workflow prompts:
- `triage_ticket(ticket_id)` — Analyze and triage a support ticket
- `draft_response(ticket_id, tone)` — Draft a customer response
- `escalate_ticket(ticket_id, reason)` — Prepare escalation summary
- `summarize_account(account_id)` — Generate account health summary
- `investigate_issue(ticket_id)` — Deep-dive into a technical issue
- `weekly_report(date_range)` — Generate weekly support metrics
- `find_similar(ticket_id)` — Find similar past tickets
- `onboard_customer(account_id)` — Generate onboarding checklist

### Production Deployment (Cloud Run)

```bash
# Deploy with Cloud Build
gcloud builds submit --config deploy/cloudbuild.yaml

# Test
SERVICE_URL=$(gcloud run services describe devrev-mcp-server \
  --region=us-central1 --format='value(status.url)')
curl $SERVICE_URL/health
```

### Security Features
- Bearer token authentication on all MCP endpoints
- Per-user DevRev PAT validation (recommended for teams)
- Rate limiting (configurable RPM per session)
- DNS rebinding protection for HTTP transports
- Destructive tool gating (enabled by default, set MCP_ENABLE_DESTRUCTIVE_TOOLS=false to disable)
- Domain restrictions via MCP_AUTH_ALLOWED_DOMAINS

### Important Notes for AI Agents Using MCP

1. **IDs are DON format**: `don:core:dvrv-us-1:devo/1:ticket/123`
2. **Pagination**: Use `cursor` and `limit` parameters, check for `next_cursor` in response
3. **Creating tickets**: Requires `type` (ticket/issue), `title`, and `applies_to_part`
4. **Beta tools**: Need `MCP_ENABLE_BETA_TOOLS=true` for search, recommendations, incidents, engagements
5. **Destructive tools**: Need `MCP_ENABLE_DESTRUCTIVE_TOOLS=true` for delete operations
6. **Per-user auth**: With `MCP_AUTH_MODE=devrev-pat`, each user sends their own DevRev PAT as Bearer token
7. **Transports**: Use stdio for local dev, streamable-http for production
