# django-mcp-discovery

Exposes `/.well-known/mcp-server` on your Django project so AI agents
can discover it via `mcp://`. Implements
[draft-serra-mcp-discovery-uri-04](https://datatracker.ietf.org/doc/draft-serra-mcp-discovery-uri/).

## Installation

```bash
pip install django-mcp-discovery
```

## Setup

**1. Add to INSTALLED_APPS:**

```python
INSTALLED_APPS = [
    ...
    'mcp_discovery',
]
```

**2. Include URLs:**

```python
urlpatterns = [
    ...
    path('', include('mcp_discovery.urls')),
]
```

**3. Done.** Visit `https://yoursite.com/.well-known/mcp-server`.

## Configuration (optional)

```python
MCP_DISCOVERY = {
    # Required
    'NAME':         'My Site MCP Server',
    'ENDPOINT':     'https://mysite.com/mcp/',

    # SHOULD fields
    'DESCRIPTION':  'Natural language description of the server',

    # Auth — draft-04 structured format
    'AUTH': {
        'required': True,
        'methods': ['bearer'],          # none | bearer | mtls | apikey | oauth2 | x-*
        'endpoint': 'https://auth.mysite.com/token',
    },
    # Retrocompatible shorthand still works: 'AUTH': 'none'

    # trust_class — draft-04 new field
    # Values: public | sandbox | enterprise | regulated
    'TRUST_CLASS': 'public',

    # If TRUST_CLASS = 'regulated' — these are REQUIRED
    'COMPLIANCE': {
        'jurisdiction': 'EU',
        'frameworks': ['GDPR', 'ISO27001'],
        'certification_url': 'https://mysite.com/compliance',
    },
    'LOGGING': {
        'required': True,
        'retention_days': 90,
    },
    'CACHE_TTL': 300,                   # seconds — also available for all trust classes

    # If TRUST_CLASS = 'sandbox' — expires generated automatically
    'EXPIRES_DAYS': 30,                 # default: 30

    # MAY fields — unchanged from v0.3.0
    'CAPABILITIES':     ['tools', 'resources'],
    'CATEGORIES':       ['e-commerce', 'fashion'],
    'LANGUAGES':        ['it', 'en'],
    'CONTACT':          'api@mysite.com',
    'DOCS':             'https://mysite.com/mcp/docs/',
    'CRAWL':            True,           # False to opt out of indexing

    # Primitive previews (draft-04 Section 6.10)
    'TOOLS_PREVIEW': [
        {'name': 'search_products', 'description': 'Search by category'},
        {'name': 'check_stock',     'description': 'Real-time availability'},
    ],
    'RESOURCES_PREVIEW': 'dynamic',
    'PROMPTS_PREVIEW':   'dynamic',
}
```

Auto-detected if not set:
- **Name** — from `django.contrib.sites` or `SITE_NAME` setting
- **Endpoint** — from `SITE_URL` or first non-localhost `ALLOWED_HOSTS`
- **Language** — from `LANGUAGE_CODE` setting

## Example output

Minimal (no configuration):

```json
{
  "mcp_version": "2025-06-18",
  "name": "My Shop MCP Server",
  "endpoint": "https://myshop.com/mcp/",
  "transport": "http",
  "auth": { "required": false, "methods": ["none"] },
  "capabilities": ["tools", "resources"],
  "languages": ["it"],
  "last_updated": "2026-03-26T00:00:00+00:00",
  "crawl": true
}
```

With `trust_class = 'enterprise'` and `bearer` auth:

```json
{
  "mcp_version": "2025-06-18",
  "name": "My Shop MCP Server",
  "endpoint": "https://myshop.com/mcp/",
  "transport": "http",
  "auth": {
    "required": true,
    "methods": ["bearer"],
    "endpoint": "https://auth.myshop.com/token"
  },
  "capabilities": ["tools", "resources"],
  "trust_class": "enterprise",
  "categories": ["e-commerce"],
  "languages": ["it"],
  "last_updated": "2026-03-26T00:00:00+00:00",
  "crawl": true
}
```

## Security

- **Endpoint domain validation** — custom endpoint MUST be on same
  domain or subdomain. Invalid endpoints fall back to default.
  (draft-04 Section 6.8)
- **trust_class validation** — `regulated` requires `COMPLIANCE.jurisdiction`;
  `sandbox` auto-generates `expires` field.
  (draft-04)

## Changelog

### v0.4.0
- Implements draft-serra-mcp-discovery-uri-04
- `auth` field restructured: `{'required': bool, 'methods': [...]}` with optional `endpoint` and `scopes`
- Retrocompatible: `AUTH = 'none'` string shorthand still works
- New `trust_class` field: `public | sandbox | enterprise | regulated`
- `sandbox`: auto-generates `expires` from `EXPIRES_DAYS`
- `regulated`: requires `COMPLIANCE.jurisdiction`, adds `compliance`, `logging`, `cache_ttl`
- New `cache_ttl` field (MAY) for all trust classes

### v0.3.0
- Added `tools_preview`, `resources_preview`, `prompts_preview` fields (draft-03 Section 6.10)
- Use a list for static previews, or 'dynamic' for dynamic ones

### v0.2.0
- Security: endpoint domain validation (Section 6.8)
- Security: `expires` field with `EXPIRES_DAYS` setting (Section 6.9)

### v0.1.0
- Initial release

## Links

- [mcpstandard.dev](https://mcpstandard.dev) — specification
- [IETF Draft -04](https://datatracker.ietf.org/doc/draft-serra-mcp-discovery-uri/04/)
- [GitHub Discussion #2462](https://github.com/modelcontextprotocol/modelcontextprotocol/discussions/2462)
- [WordPress plugin](https://github.com/99rig/mcp-wordpress)

## Author

Mumble Group — Milan, Italy — support@mumble.group
