---
title: Phoenix MCP API Integration Guide
version: 1.4
last_updated: 2026-08-14
audience: External integrators, AI agents, automation systems
---

# Phoenix MCP API Integration Guide

This guide provides complete specifications for integrating with Phoenix CVE Intelligence via the Model Context Protocol (MCP) JSON-RPC API. It covers both **Normal API** (customer-facing) and **PAPI** (Privileged API for Phoenix Global Admins).

## Table of Contents

- [Overview](#overview)
- [API Planes](#api-planes)
- [Authentication](#authentication)
- [Endpoint Structure](#endpoint-structure)
- [Request/Response Format](#requestresponse-format)
- [Available Methods](#available-methods)
- [Resources](#resources)
- [Tools](#tools)
- [Tiered Access Control](#tiered-access-control)
- [Examples](#examples)
- [Error Handling](#error-handling)
- [Rate Limits](#rate-limits)
- [Integration Patterns](#integration-patterns)

---

## Overview

Phoenix MCP API provides:

- **CVE Intelligence**: Enriched CVE data with Phoenix proprietary scoring (PS-HP, PS-EW)
- **EOL Intelligence**: End-of-life product tracking and CVE correlation
- **Threat Intelligence**: Threat actor mappings, KEV catalog, enterprise watchlist
- **Scoring Services**: Phoenix scoring algorithms with component breakdown
- **JSON-RPC 2.0**: Standard protocol for LLM integrations (Claude, ChatGPT, custom agents)

**Protocol**: JSON-RPC 2.0 (MCP specification)  
**Transport**: HTTP POST  
**Content-Type**: `application/json`

---

## API Planes

Phoenix exposes two API planes with different access levels:

| Plane | Path Prefix | Audience | Auth Method | Data Access |
|-------|-------------|----------|-------------|-------------|
| **Normal API** | `/api/v1/mcp` | Customers, external agents | API Key (x-api-key) | Tier-filtered responses |
| **PAPI** (Privileged) | `/internal/v1/mcp` | Phoenix Global Admins | PAI Key (x-pai-key) + IP allowlist | Full unredacted data |

### Normal API

- **Endpoint**: `POST /api/v1/mcp`
- **Aliases**: 
  - `POST /api/v1/mcp/claude` (Claude Desktop connector)
  - `POST /api/v1/mcp/chatgpt` (ChatGPT Desktop connector)
- **Access**: Public (with API key — Pro / Enterprise tiers). Generate one self-service under **My Account → Platform API Keys → MCP Client**. Full walkthrough: [Platform API Keys](PLATFORM_API_KEYS.md).
- **Response Filtering**: Tier-based (Registered/Pro/Enterprise)

### PAPI (Privileged API)

- **Endpoint**: `POST /internal/v1/mcp`
- **Access**: Restricted to Phoenix Global Admins
- **Response Filtering**: None (full data access)
- **Additional Security**: IP allowlist + PAI key validation

---

## Authentication

### Normal API Authentication

**Header**: `x-api-key: <your_api_key>`

**Allowed Scopes**:
- `mcp` - Basic MCP access (Registered tier)
- `api_power` - Enhanced access (Pro tier)
- `api_integration` - Integration access (Pro tier)
- `api_unlimited` - Full access (Enterprise tier)

**Example**:
```bash
curl -X POST https://phoenix.example.com/api/v1/mcp \
  -H "Content-Type: application/json" \
  -H "x-api-key: <your_api_key>" \
  -d '{"jsonrpc":"2.0","id":"1","method":"initialize","params":{}}'
```

### PAPI Authentication

**Headers**:
- `x-pai-key: <your_pai_key>` (or `x-api-key`)
- Source IP must be in `PAI_IP_ALLOWLIST`

**Example**:
```bash
curl -X POST https://phoenix-internal.example.com/internal/v1/mcp \
  -H "Content-Type: application/json" \
  -H "x-pai-key: pai_admin_xyz789..." \
  -d '{"jsonrpc":"2.0","id":"1","method":"initialize","params":{}}'
```

**PAI Key Generation** (Global Admin only, no email step):
1. Generate the pair: `POST /api/v1/admin/pai/keys`
2. Copy the api key + companion token shown once (send both on calls: `x-api-key` + `x-pai-token`)
3. Manage: `GET /api/v1/admin/pai/keys` (list), `POST /api/v1/admin/pai/keys/{key_id}/revoke` (revoke)

---

## Endpoint Structure

### Base URLs

| Environment | Normal API | PAPI |
|-------------|-----------|------|
| Production | `https://api.phoenix.example.com/api/v1/mcp` | `https://internal.phoenix.example.com/internal/v1/mcp` |
| Staging | `https://staging-api.phoenix.example.com/api/v1/mcp` | `https://staging-internal.phoenix.example.com/internal/v1/mcp` |
| Local Dev | `http://localhost:8000/api/v1/mcp` | `http://localhost:8000/internal/v1/mcp` |

---

## Request/Response Format

### JSON-RPC 2.0 Structure

**Request**:
```json
{
  "jsonrpc": "2.0",
  "id": "unique-request-id",
  "method": "method_name",
  "params": {
    "param1": "value1",
    "param2": "value2"
  }
}
```

**Success Response**:
```json
{
  "jsonrpc": "2.0",
  "id": "unique-request-id",
  "result": {
    "data": "..."
  }
}
```

**Error Response**:
```json
{
  "jsonrpc": "2.0",
  "id": "unique-request-id",
  "error": {
    "code": -32000,
    "message": "Error description",
    "data": {
      "details": "Additional context"
    }
  }
}
```

### Standard Error Codes

| Code | Meaning |
|------|---------|
| `-32600` | Invalid Request (malformed JSON or missing required fields) |
| `-32601` | Method Not Found |
| `-32602` | Invalid Params |
| `-32000` | Server Error (generic) |
| `-32001` | Permission Denied (tier restriction) |

---

## Available Methods

### Core Methods

| Method | Description | Auth Required |
|--------|-------------|---------------|
| `initialize` | Get server info and capabilities | Yes |
| `resources/list` | List available read-only resources | Yes |
| `resources/read` | Fetch resource data by URI | Yes |
| `tools/list` | List available tools and input schemas | Yes |
| `tools/call` | Execute a tool with arguments | Yes |

---

## Resources

Resources are read-only data endpoints accessed via `resources/read` method.

### Resource URIs

| URI Pattern | Description | Example |
|-------------|-------------|---------|
| `phoenix://cve/{cve_id}` | CVE intelligence with PS-HP scoring | `phoenix://cve/CVE-2024-27198` |
| `phoenix://kev/catalog` | CISA Known Exploited Vulnerabilities | `phoenix://kev/catalog` |
| `phoenix://threat-actors` | Threat actor to CVE mappings | `phoenix://threat-actors` |
| `phoenix://high-profile/tier/{tier}` | High-profile CVEs by tier (1-3) | `phoenix://high-profile/tier/1` |
| `phoenix://enterprise-watchlist` | Enterprise watchlist (PS-EW) | `phoenix://enterprise-watchlist` |
| `phoenix://enterprise-cpe/{category}` | Enterprise CPE registry | `phoenix://enterprise-cpe/all` |
| `phoenix://eol/products` | EOL product catalog | `phoenix://eol/products` |
| `phoenix://eol/products/{slug}` | EOL product detail | `phoenix://eol/products/ubuntu` |
| `phoenix://eol/cve-correlation` | CVE/EOL correlation data | `phoenix://eol/cve-correlation` |
| `phoenix://eol/replacements` | EOL replacement recommendations | `phoenix://eol/replacements` |
| `phoenix://eol/statistics` | EOL summary statistics | `phoenix://eol/statistics` |
| `phoenix://eol/timeline` | Upcoming EOL events | `phoenix://eol/timeline` |

### Example: Read CVE Resource

**Request**:
```json
{
  "jsonrpc": "2.0",
  "id": "res-1",
  "method": "resources/read",
  "params": {
    "uri": "phoenix://cve/CVE-2024-27198"
  }
}
```

**Response (Normal API - Registered Tier)**:
```json
{
  "jsonrpc": "2.0",
  "id": "res-1",
  "result": {
    "contents": [
      {
        "uri": "phoenix://cve/CVE-2024-27198",
        "mimeType": "application/json",
        "text": "{\"cve\":{\"cve_id\":\"CVE-2024-27198\",\"description\":\"...\",\"cvss_score\":9.8,\"severity\":\"CRITICAL\"},\"phoenix_score\":{\"ps_hp_score\":8.7,\"ps_hp_tier\":1,\"ps_hp_tier_name\":\"Confirmed High-Profile\",\"hp_summary\":\"Critical vulnerability with active exploitation\",\"hp_reasons\":[\"In CISA KEV catalog\",\"CVSS 9.8 (Critical)\",\"Active exploitation detected\"],\"is_enterprise_watchlist\":false}}"
      }
    ]
  }
}
```

**Response (PAPI - Full Access)**:
```json
{
  "jsonrpc": "2.0",
  "id": "res-1",
  "result": {
    "contents": [
      {
        "uri": "phoenix://cve/CVE-2024-27198",
        "mimeType": "application/json",
        "text": "{\"cve\":{\"cve_id\":\"CVE-2024-27198\",\"description\":\"...\",\"cvss_score\":9.8,\"severity\":\"CRITICAL\"},\"phoenix_score\":{\"ps_hp_score\":8.7,\"ps_hp_tier\":1,\"ps_hp_tier_name\":\"Confirmed High-Profile\",\"components\":{\"cvss\":0.98,\"epss\":0.85,\"kev\":1.0,\"ransomware\":0.0,\"exploit\":0.92,\"enterprise\":0.88,\"github\":0.65,\"bugbounty\":0.0},\"hp_summary\":\"Critical vulnerability with active exploitation\",\"hp_reasons\":[\"In CISA KEV catalog\",\"CVSS 9.8 (Critical)\",\"Active exploitation detected\",\"Enterprise-critical vendor (JetBrains)\",\"High EPSS score (85th percentile)\"],\"hp_rationale\":\"This CVE scores 8.7/10 due to confirmed exploitation (KEV), critical CVSS, and enterprise impact. The vulnerability affects JetBrains TeamCity, a widely-used CI/CD platform in enterprise environments. Exploitation is trivial and has been observed in the wild.\",\"executive_summary\":\"Immediate patching required for all JetBrains TeamCity instances. Active exploitation confirmed by CISA.\",\"is_enterprise_watchlist\":false,\"enterprise_category\":\"DevOps Tools\",\"enterprise_risk_score\":9.2}}"
      }
    ]
  }
}
```

---

## Tools

Tools are executable functions accessed via `tools/call` method.

### Standard Tools (All Tiers)

| Tool Name | Description | Input Schema |
|-----------|-------------|--------------|
| `search_cves` | Search CVEs with filters | `{query?, year?, severity?, kev_only?, ps_hp_min?, ps_hp_tier?, enterprise_watchlist?, limit?, offset?}` |
| `get_cve_intelligence` | Get comprehensive CVE intelligence | `{cve_id: string}` (required) |
| `get_phoenix_score` | Calculate PS-HP score with breakdown | `{cve_id: string, include_rationale?: boolean}` |
| `get_high_profile_cves` | Get high-profile CVEs by tier | `{tier?: 1\|2\|3, limit?: number, enterprise_category?: string}` |
| `get_enterprise_watchlist` | Get PS-EW flagged CVEs | `{category?: string, limit?: number}` |
| `get_threat_actors_by_cve` | Get threat actors for CVE | `{cve_id: string}` |
| `check_enterprise_critical` | Check if vendor/product is enterprise-critical | `{vendor: string, product: string}` |
| `list_eol_products` | List EOL products | `{status?, category?, vendor?, search?, limit?, offset?}` |
| `get_eol_product` | Get EOL product detail | `{product_slug: string}` |
| `get_eol_cve_correlations` | Get CVE/EOL correlations | `{non_fixable_only?, kev_only?, min_cvss?, limit?, offset?}` |
| `get_cve_eol_status` | Get EOL status for CVE | `{cve_id: string}` |
| `get_eol_replacements` | List EOL replacement recommendations | `{category?, limit?}` |
| `get_eol_replacement` | Get replacement for product | `{product_slug: string}` |
| `get_eol_statistics` | Get EOL summary statistics | `{}` |
| `get_eol_timeline` | Get upcoming EOL events | `{days?: number, category?: string}` |
| `get_eol_risk_score` | Calculate SLR risk score | `{product_slug: string}` |
| `get_ai_attributed_cves` | Returns CVEs discovered or co-reported by frontier AI models (Claude/GPT/Gemini/Llama/Grok) or AI-native security firms (AISLE) | `{provider?: string[], program?: string[], min_cvss?: number, since?: string, limit?: number}` |
| `intel_get` | Get deterministic Phoenix intelligence for one entity of the Unified Intelligence Query Surface. `include` composes the licence-gated `expanded` block for `library`/`library_version` (Plan D, 2026-08-14) | `{entity: string, id: string, include?: string[]}` (`entity` and `id` required) |
| `intel_search` | Search one Unified Intelligence Query Surface entity. Returns a list of envelopes | `{entity: string, q?: string, vendor?: string, product?: string, purl?: string, limit?: number}` (`entity` required) |
| `intel_vocabularies` | List the published enumerated vocabularies and cutpoints (confidence classes, severity classes, MPI signal categories, taxonomy versions) | `{}` |
| `intel_research_start` | Trigger Phoenix research on a package or CVE (Pro/Enterprise, quota-metered). Hidden from `tools/list` when `enable_intel_research_triggers` is off | `{kind: "PACKAGE_SCAN"\|"CVE_ANALYSIS"\|"PACKAGE_HISTORY_REFRESH", target: string}` (both required) |
| `intel_research_status` | Poll a research job triggered by `intel_research_start`. Hidden from `tools/list` when `enable_intel_research_triggers` is off | `{job_id: string}` (required) |

### `intel_get` — expanded intelligence via `include`

> Added 2026-08-14 (Plan D). Requires `enable_intel_query_surface` **and**
> `enable_global_intel_license`, both default `false`. When `enable_intel_query_surface` is off all
> three `intel_*` tools are **hidden from `tools/list`** and `tools/call` raises "Unknown tool".

`include` accepts the same tokens as REST and PAI — `vulnerabilities`, `malware`, `exploitation`,
`campaign`, `licensing`, plus `advisory` and `all` — validated by the same registry helper, so the four
transports cannot drift on what a token means. An unrecognised token is a tool error, never a silent
no-op that would read as missing data.

Three MCP-specific behaviours, all deliberate:

- **The Global Intel bundle is read from the calling API key's own `global_intel_tier` stamp.** MCP
  *user tier* confers nothing: `enterprise` MCP access is not a Global Intel licence, exactly as
  Enterprise REST access is not. An unlicensed caller receives the **base envelope** with
  `license_required: true` and a note appended to `summary_markdown` — JSON-RPC has no 403, and losing
  the bundle must narrow the answer rather than delete it.
- **This handler never references `allow_clean`, at any tier including `enterprise`.** Whether a caller
  can resolve a scanned-but-not-confirmed (`SUSPECT`-band) malware package at all is a separate,
  human-decided authorization boundary from field shaping. An MCP caller is identified only by a plain
  tier string — no admin flag, no `CognitoUser`, no PAI credential — which is not the verified
  higher-trust signal that gate requires. Composition reuses the malware resolver in-process, so this
  is precisely where a product entitlement could become a side door; it does not.

- **The daily `intel_expanded` quota is enforced here too**, through the same shared helper REST and
  PAI use, charged only when a licence was actually resolved and **before** composition runs. A caller
  over cap gets a tool error rather than a fan-out. A licensed response carries
  `provenance.intel_license` (classified `REGISTERED`, so `data_shield` decides who sees it).
- **...and since 2026-08-14 MCP also WRITES the counter that quota reads.** MCP requests are classified
  as `mcp` by `usage_metering.classify_request` and never reach the intel branch, so the cap was being
  compared against `intel_expanded_lookups` values that only REST and PAI ever wrote — composition
  served, billing zero, the Pro cap unreachable through this door. `intel_get`/`intel_search` now record
  `intel_query_lookups`, plus `intel_expanded_lookups` when the composition was actually served, using
  `usage_metering.intel_usage_keys()` — the same definition the REST/PAI classifier uses.
  `api_calls_total`/`api_calls_mcp` still come from the usage middleware, so nothing is double-counted,
  and an unlicensed caller is billed the base lookup only, never the expansion they were refused.

Full field-level tier matrix and status-code table: [PUBLIC_API.md](PUBLIC_API.md).

### `get_ai_attributed_cves` — Frontier Model Attribution

> Added 2026-04-26 as part of PRD-FMA-001 (v1.0).
> Gated by feature flag `enable_frontier_model_cve_intel` (default `false`). When the flag is off the tool is **hidden from `tools/list`** and `tools/call` returns a "tool not found" error.

**Input schema**:

```json
{
  "name": "get_ai_attributed_cves",
  "description": "Returns CVEs discovered or co-reported by frontier AI models (Claude, GPT, Gemini, Llama, Grok) or AI-native security firms (AISLE). Filters by provider, program (Glasswing, QuiltWorks, MADBugs), and confidence.",
  "inputSchema": {
    "type": "object",
    "properties": {
      "provider": {"type": "array", "items": {"enum": ["anthropic","openai","google","meta","xai","aisle"]}},
      "program":  {"type": "array", "items": {"enum": ["glasswing","quiltworks","madbugs"]}},
      "min_cvss": {"type": "number"},
      "since":    {"type": "string", "format": "date"},
      "limit":    {"type": "integer", "default": 50, "maximum": 200}
    }
  }
}
```

**Example call**:

```json
{
  "jsonrpc": "2.0",
  "id": "fma-1",
  "method": "tools/call",
  "params": {
    "name": "get_ai_attributed_cves",
    "arguments": {
      "provider": ["anthropic", "aisle"],
      "min_cvss": 9.0,
      "since": "2026-01-01",
      "limit": 20
    }
  }
}
```

**Tier-restricted fields**: same projection as the REST endpoint `GET /api/v1/ai-attributed-model-cves` — Free / Registered users see provider and basic CVE fields; Pro adds `confidence_tier`, `credit_text`, `collaboration_chain`; Enterprise adds the numeric `confidence_score`.

Cross-reference: REST endpoint and full field tier table in [PUBLIC_API.md](PUBLIC_API.md). Feature doc: [docs/Individual_Feature/frontier-model-attribution-intelligence.md](../Individual_Feature/frontier-model-attribution-intelligence.md).

### `intel_get` / `intel_search` / `intel_vocabularies` — Unified Intelligence Query Surface

> Added 2026-07-25. Gated by feature flag `enable_intel_query_surface` (default `false`). When the flag is off these three tools are **hidden from `tools/list` entirely** (not merely erroring on `tools/call`) — `backend/app/mcp/intel_tools.py`'s `is_intel_mcp_enabled()` gate is checked before `MCPServer.list_tools()` merges them in.

MCP mirror of the same [Unified Intelligence Query Surface](PUBLIC_API.md#unified-intelligence-query-surface--get-apiv1intel) exposed over REST (`/api/v1/intel/*`) and PAI (`/internal/v1/intel/*`) — all three, plus the `phoenix-cli intel` command group, resolve through the same entity registry (`backend/app/services/intel_query/registry.py`), so results cannot drift between transports.

**Input schemas** (verbatim from `INTEL_TOOLS` in `backend/app/mcp/intel_tools.py`):

```json
{
  "name": "intel_get",
  "description": "Get deterministic Phoenix intelligence for one entity. Returns a versioned envelope: 'deterministic' holds enumerated classes and stable identifiers (CWE IDs, CPE URIs, MPI signal IDs, MITRE technique IDs); 'advisory' holds LLM-derived, not-reproducible content, but is only ever populated via the REST/PAI '?include=advisory' query parameter -- this MCP tool does not pass that parameter through, so 'advisory' is always null here today.",
  "inputSchema": {
    "type": "object",
    "properties": {
      "entity": {"type": "string", "enum": ["cpe", "cve", "cwe", "library", "library_version", "malware", "product", "vendor"], "description": "Entity type to fetch"},
      "id": {"type": "string", "description": "CVE-2024-27198 | CWE-89 | vendor | vendor:product | pkg:npm/express | pkg:npm/express@4.17.1 | cpe:2.3:..."}
    },
    "required": ["entity", "id"]
  }
}
```

```json
{
  "name": "intel_search",
  "description": "Search one Phoenix intelligence entity. Returns a list of envelopes.",
  "inputSchema": {
    "type": "object",
    "properties": {
      "entity": {"type": "string", "enum": ["cpe", "cve", "cwe", "library", "library_version", "malware", "product", "vendor"]},
      "q": {"type": "string", "description": "Free-text or ID query"},
      "vendor": {"type": "string"},
      "product": {"type": "string"},
      "purl": {"type": "string"},
      "limit": {"type": "integer", "minimum": 1, "maximum": 200, "default": 20}
    },
    "required": ["entity"]
  }
}
```

```json
{
  "name": "intel_vocabularies",
  "description": "List the published enumerated vocabularies and their cutpoints: confidence classes, severity classes, MPI signal categories, and taxonomy versions. Call this once to learn the closed value sets before interpreting any envelope.",
  "inputSchema": {"type": "object", "properties": {}}
}
```

**Example call**:

```json
{
  "jsonrpc": "2.0",
  "id": "intel-1",
  "method": "tools/call",
  "params": {
    "name": "intel_get",
    "arguments": { "entity": "cve", "id": "CVE-2024-27198" }
  }
}
```

**Response shape**: `intel_get`/`intel_search` return the same envelope described in [PUBLIC_API.md](PUBLIC_API.md#unified-intelligence-query-surface--get-apiv1intel), plus a `summary_markdown` string so an agent gets a readable answer without parsing the envelope. `intel_get` on a miss returns `{"found": false, "entity", "id", "summary_markdown"}` rather than an error. Tier shaping runs through the same `data_shield.filter_response_for_tier` pass as the REST surface, keyed off the caller's plain tier string (`IntelToolHandler(user_tier=...)`) — there is no admin/PAI signal available to an MCP caller, so the malware `allow_clean` gate is **never** widened for any tier here, including `enterprise`; confirmed-malicious-only, matching the public route's non-admin behavior.

Cross-reference: full envelope shape, entity ID forms, confidence/severity cutpoints, and tier matrix in [PUBLIC_API.md](PUBLIC_API.md#unified-intelligence-query-surface--get-apiv1intel). Feature doc: [docs/Individual_Feature/2026-07-25-unified-intelligence-query-surface.md](../Individual_Feature/2026-07-25-unified-intelligence-query-surface.md).

### `intel_research_start` / `intel_research_status` — Tenant-Scoped Research Triggers

> Added 2026-07-26. Gated by feature flag `enable_intel_research_triggers` (default `false`). When the flag is off these two tools are **hidden from `tools/list` entirely** (same discipline as `intel_get`/`intel_search`/`intel_vocabularies` above) — `backend/app/mcp/research_tools.py`'s `is_research_mcp_enabled()` gate is checked before `MCPServer.list_tools()` merges them in, and `call_tool()` raises `ValueError("Unknown tool: ...")` rather than dispatching when the flag is off.

MCP mirror of the [Tenant-Scoped Research Triggers](PUBLIC_API.md#tenant-scoped-research-triggers--apiv1research) surface exposed over REST (`/api/v1/research/*`) and PAI (`/internal/v1/research/*`) — all three, plus the `phoenix-cli research` command group, resolve into the same job store and dispatcher (`app.services.research_jobs`), so a job triggered from any transport runs identical worker logic.

**Dispatch ordering note**: `MCPServer.call_tool()` checks the `intel_research_` prefix **before** the plain `intel_` prefix used by the tools above — every `intel_research_*` name also starts with `intel_`, so without that ordering every research tool call would silently fall into `IntelToolHandler`'s "Unknown intel tool" error instead of reaching `ResearchToolHandler`.

**Input schemas** (verbatim from `RESEARCH_TOOLS` in `backend/app/mcp/research_tools.py`):

```json
{
  "name": "intel_research_start",
  "description": "Trigger Phoenix research on a package or CVE. Returns immediately with a job id -- poll intel_research_status for the result. Requires a Pro or Enterprise subscription and is metered against a daily per-organisation quota.",
  "inputSchema": {
    "type": "object",
    "properties": {
      "kind": {"type": "string", "enum": ["PACKAGE_SCAN", "CVE_ANALYSIS", "PACKAGE_HISTORY_REFRESH"]},
      "target": {"type": "string", "description": "Versioned purl for PACKAGE_SCAN (pkg:npm/express@4.17.1), purl base for PACKAGE_HISTORY_REFRESH, CVE id for CVE_ANALYSIS"}
    },
    "required": ["kind", "target"]
  }
}
```

```json
{
  "name": "intel_research_status",
  "description": "Poll a research job. States: QUEUED, RUNNING, COMPLETED, FAILED, REJECTED, EXPIRED. The four latter states are terminal -- stop polling when you see one.",
  "inputSchema": {
    "type": "object",
    "properties": {"job_id": {"type": "string"}},
    "required": ["job_id"]
  }
}
```

**Example call**:

```json
{
  "jsonrpc": "2.0",
  "id": "research-1",
  "method": "tools/call",
  "params": {
    "name": "intel_research_start",
    "arguments": { "kind": "CVE_ANALYSIS", "target": "CVE-2024-27198" }
  }
}
```

**org_id resolution**: comes from the authenticated MCP API key (`api_key_info["org_id"]`, threaded from `authenticate_mcp_request()` through `MCPServer.__init__`'s optional `api_key_info` argument into `ResearchToolHandler`) — **never** a tool argument. A tool argument naming an org would make this a cross-tenant primitive. `intel_research_start` refuses (`accepted: false`, no exception) below Pro tier, with no resolvable `org_id`, on an unknown `kind`, or on a malformed `target` for its kind; `intel_research_status` is org-scoped the same way (`get_job(org_id, job_id)`) and returns `{"found": false, ...}` rather than an error for a job it cannot see.

**Known gap (final-review, not yet fixed): `intel_research_status` has no Pro/Enterprise tier gate.** Unlike `intel_research_start` (which refuses below Pro) and the REST/PAI equivalents of this same read (`GET /api/v1/research/{job_id}`, both of which enforce the tier check on every route in the router), `_status()` in `ResearchToolHandler` only checks `self.org_id`, never `self.user_tier`. Same-org-only scoping still holds (no cross-tenant read), but a downgraded/free-tier MCP key belonging to a Pro/Enterprise org can poll that org's own research job results — a job any teammate on the same key's org triggered. Left as a documented gap rather than a code change in this fix wave; add the same tier check `_start()` already has before treating this tool as fully access-controlled.

**Response shape**: `intel_research_start` returns `{"accepted": true, "job_id", "state", "summary_markdown"}` on success or `{"accepted": false, "summary_markdown"}` on refusal (never an exception for an expected refusal — a tier gate, quota, or malformed target is a normal outcome an agent should be able to read, not a JSON-RPC error). `intel_research_status` returns `{"found": true, "terminal": bool, "summary_markdown", ...job fields}` or `{"found": false, "summary_markdown"}`. Note the job dict's own `state` key is **not** renamed to `job_state` on this transport (unlike REST/PAI) — the MCP tool reads and returns the store's raw dict as-is; only the REST and PAI response boundaries do that rename.

Cross-reference: job kinds, states, quota, and idempotency behavior in [PUBLIC_API.md](PUBLIC_API.md#tenant-scoped-research-triggers--apiv1research). Feature doc: [docs/Individual_Feature/2026-07-25-tenant-scoped-research-triggers.md](../Individual_Feature/2026-07-25-tenant-scoped-research-triggers.md).

### Enterprise-Only Tools (Normal API)

| Tool Name | Description | Input Schema |
|-----------|-------------|--------------|
| `calculate_custom_phoenix_score` | Calculate PS-HP from custom inputs | `{cvss: number, epss?, in_kev?, has_ransomware?, exploit_status?, vendor?, product?, github_stars?, github_forks?, bugbounty_reports?}` |
| `explain_score_components` | Get detailed PS-HP component explanation | `{cve_id: string}` |

**Note**: Enterprise-only tools return error code `-32001` (Permission Denied) for non-Enterprise tier users on Normal API. PAPI has access to all tools regardless of tier.

### Example: Call Tool (Normal API)

**Request**:
```json
{
  "jsonrpc": "2.0",
  "id": "tool-1",
  "method": "tools/call",
  "params": {
    "name": "get_cve_intelligence",
    "arguments": {
      "cve_id": "CVE-2024-27198"
    }
  }
}
```

**Response (Registered Tier)**:
```json
{
  "jsonrpc": "2.0",
  "id": "tool-1",
  "result": {
    "content": [
      {
        "type": "text",
        "text": "# CVE-2024-27198 Intelligence\n\n**Severity**: CRITICAL (CVSS 9.8)\n**Phoenix Score**: 8.7/10 (Tier 1 - Confirmed High-Profile)\n\n## Summary\nCritical authentication bypass in JetBrains TeamCity...\n\n## Key Risk Factors\n- In CISA KEV catalog\n- CVSS 9.8 (Critical)\n- Active exploitation detected\n\n## Recommendation\nImmediate patching required."
      },
      {
        "type": "json",
        "json": {
          "cve": {
            "cve_id": "CVE-2024-27198",
            "description": "Authentication bypass vulnerability in JetBrains TeamCity...",
            "cvss_score": 9.8,
            "severity": "CRITICAL",
            "published_date": "2024-03-04",
            "kev": {
              "is_kev": true,
              "date_added": "2024-03-05",
              "due_date": "2024-03-26"
            },
            "epss": {
              "score": 0.85,
              "percentile": 0.95
            }
          },
          "phoenix_score": {
            "ps_hp_score": 8.7,
            "ps_hp_tier": 1,
            "ps_hp_tier_name": "Confirmed High-Profile",
            "hp_summary": "Critical vulnerability with active exploitation",
            "hp_reasons": [
              "In CISA KEV catalog",
              "CVSS 9.8 (Critical)",
              "Active exploitation detected"
            ],
            "is_enterprise_watchlist": false
          }
        }
      }
    ]
  }
}
```

### Example: Call Tool (PAPI)

**Request**:
```json
{
  "jsonrpc": "2.0",
  "id": "tool-2",
  "method": "tools/call",
  "params": {
    "name": "calculate_custom_phoenix_score",
    "arguments": {
      "cvss": 9.8,
      "epss": 0.85,
      "in_kev": true,
      "exploit_status": "weaponized",
      "vendor": "JetBrains",
      "product": "TeamCity",
      "github_stars": 250,
      "github_forks": 45
    }
  }
}
```

**Response (PAPI - Full Components)**:
```json
{
  "jsonrpc": "2.0",
  "id": "tool-2",
  "result": {
    "content": [
      {
        "type": "json",
        "json": {
          "ps_hp_score": 8.7,
          "ps_hp_tier": 1,
          "ps_hp_tier_name": "Confirmed High-Profile",
          "components": {
            "cvss": 0.98,
            "epss": 0.85,
            "kev": 1.0,
            "ransomware": 0.0,
            "exploit": 0.92,
            "enterprise": 0.88,
            "github": 0.65,
            "bugbounty": 0.0
          },
          "hp_summary": "Critical vulnerability with weaponized exploits",
          "hp_reasons": [
            "In CISA KEV catalog",
            "CVSS 9.8 (Critical)",
            "Weaponized exploit available",
            "Enterprise-critical vendor (JetBrains)",
            "High EPSS score (85th percentile)"
          ],
          "hp_rationale": "This hypothetical CVE scores 8.7/10 due to confirmed KEV status, critical CVSS, weaponized exploits, and enterprise impact. The combination of high technical severity and active exploitation makes this a top-priority vulnerability.",
          "executive_summary": "Immediate action required. Weaponized exploits available for enterprise-critical infrastructure.",
          "enterprise_category": "DevOps Tools",
          "enterprise_risk_score": 9.2
        }
      }
    ]
  }
}
```

---

## Tiered Access Control

### Normal API Tiers

| Tier | API Key Scope | Phoenix Score Fields | High-Profile Fields | Enterprise CPE Fields |
|------|---------------|----------------------|---------------------|----------------------|
| **Registered** | `mcp`, `api_basic` | Score, tier, summary, generic reasons (top 3), watchlist flag | CVE ID, severity, CVSS, technology, score, tier, summary, KEV, EPSS, watchlist, generic reasons | Vendor, product, category only |
| **Pro** | `api_power`, `api_integration` | All Registered + component levels (H/M/L), enterprise category, specific reasons (top 5), abbreviated rationale | All Registered + enterprise category, specific reasons (top 5), GitHub repo count | All Registered + KEV count, ransomware count |
| **Enterprise** | `api_unlimited` | All Pro + numeric component values (0.0-1.0), full rationale, executive summary, enterprise risk score | All Pro + full component breakdown, rationale, risk scores, detailed GitHub stats | All Pro + risk_weight values, CVE IDs, full risk scoring |

### PAPI Access

PAPI bypasses all tier restrictions and returns full unredacted data:

- **Phoenix Score**: All numeric component values (0.0-1.0), full rationale, executive summary, internal scoring weights
- **High-Profile CVEs**: Complete dataset with all fields
- **Enterprise CPE**: Full risk weights, CVE mappings, proprietary classifications
- **Scoring Calculations**: Access to all scoring endpoints with neutral defaults for missing inputs

---

## Examples

### Example 1: Initialize Connection (Normal API)

**Request**:
```json
{
  "jsonrpc": "2.0",
  "id": "init-1",
  "method": "initialize",
  "params": {}
}
```

**Response**:
```json
{
  "jsonrpc": "2.0",
  "id": "init-1",
  "result": {
    "protocolVersion": "0.1.0",
    "serverInfo": {
      "name": "phoenix-mcp",
      "version": "1.0.0"
    },
    "capabilities": {
      "resources": {},
      "tools": {},
      "prompts": {},
      "logging": {}
    }
  }
}
```

### Example 2: List Available Tools (Normal API - Enterprise Tier)

**Request**:
```json
{
  "jsonrpc": "2.0",
  "id": "list-1",
  "method": "tools/list",
  "params": {}
}
```

**Response**:
```json
{
  "jsonrpc": "2.0",
  "id": "list-1",
  "result": {
    "tools": [
      {
        "name": "search_cves",
        "description": "Search CVEs with filters including PS-HP scoring",
        "inputSchema": {
          "type": "object",
          "properties": {
            "query": {"type": "string"},
            "year": {"type": "integer"},
            "severity": {"type": "string", "enum": ["CRITICAL", "HIGH", "MEDIUM", "LOW"]},
            "kev_only": {"type": "boolean"},
            "ps_hp_min": {"type": "number"},
            "ps_hp_tier": {"type": "integer"},
            "enterprise_watchlist": {"type": "boolean"},
            "limit": {"type": "integer"},
            "offset": {"type": "integer"}
          }
        }
      },
      {
        "name": "get_cve_intelligence",
        "description": "Get comprehensive CVE intelligence with PS-HP/PS-EW scoring",
        "inputSchema": {
          "type": "object",
          "properties": {
            "cve_id": {"type": "string", "pattern": "^CVE-\\d{4}-\\d{4,}$"}
          },
          "required": ["cve_id"]
        }
      },
      {
        "name": "calculate_custom_phoenix_score",
        "description": "Calculate PS-HP score from custom inputs (hypothetical analysis)",
        "inputSchema": {
          "type": "object",
          "properties": {
            "cvss": {"type": "number", "minimum": 0, "maximum": 10},
            "epss": {"type": "number", "minimum": 0, "maximum": 1},
            "in_kev": {"type": "boolean"},
            "exploit_status": {"type": "string", "enum": ["none", "poc", "verified", "weaponized", "in_ransomware"]}
          },
          "required": ["cvss"]
        }
      }
    ]
  }
}
```

### Example 3: Search High-Profile CVEs (Normal API - Pro Tier)

**Request**:
```json
{
  "jsonrpc": "2.0",
  "id": "search-1",
  "method": "tools/call",
  "params": {
    "name": "search_cves",
    "arguments": {
      "ps_hp_tier": 1,
      "severity": "CRITICAL",
      "limit": 10
    }
  }
}
```

**Response (Pro Tier)**:
```json
{
  "jsonrpc": "2.0",
  "id": "search-1",
  "result": {
    "content": [
      {
        "type": "json",
        "json": {
          "results": [
            {
              "cve_id": "CVE-2024-27198",
              "description": "Authentication bypass in JetBrains TeamCity",
              "cvss_score": 9.8,
              "severity": "CRITICAL",
              "ps_hp_score": 8.7,
              "ps_hp_tier": 1,
              "components": "H/H/H/L/H/H/M/L",
              "enterprise_category": "DevOps Tools",
              "hp_reasons": [
                "In CISA KEV catalog",
                "CVSS 9.8 (Critical)",
                "Active exploitation detected",
                "Enterprise-critical vendor",
                "High EPSS score"
              ]
            }
          ],
          "total": 1,
          "limit": 10,
          "offset": 0
        }
      }
    ]
  }
}
```

### Example 4: Get EOL Product Detail (PAPI)

**Request**:
```json
{
  "jsonrpc": "2.0",
  "id": "eol-1",
  "method": "tools/call",
  "params": {
    "name": "get_eol_product",
    "arguments": {
      "product_slug": "ubuntu-1804"
    }
  }
}
```

**Response (PAPI - Full Data)**:
```json
{
  "jsonrpc": "2.0",
  "id": "eol-1",
  "result": {
    "content": [
      {
        "type": "json",
        "json": {
          "product_slug": "ubuntu-1804",
          "product_name": "Ubuntu 18.04 LTS",
          "vendor": "Canonical",
          "category": "Operating Systems",
          "eol_date": "2023-05-31",
          "support_status": "eol",
          "days_until_eol": -639,
          "cve_count": 1247,
          "non_fixable_cve_count": 89,
          "kev_cve_count": 12,
          "risk_score": 8.9,
          "replacement_recommendations": [
            {
              "product_slug": "ubuntu-2204",
              "product_name": "Ubuntu 22.04 LTS",
              "eol_date": "2027-04-30",
              "migration_complexity": "medium"
            }
          ]
        }
      }
    ]
  }
}
```

### Example 5: Error Response (Permission Denied)

**Request (Registered Tier trying Enterprise-only tool)**:
```json
{
  "jsonrpc": "2.0",
  "id": "err-1",
  "method": "tools/call",
  "params": {
    "name": "calculate_custom_phoenix_score",
    "arguments": {
      "cvss": 9.8
    }
  }
}
```

**Response**:
```json
{
  "jsonrpc": "2.0",
  "id": "err-1",
  "error": {
    "code": -32000,
    "message": "Tool 'calculate_custom_phoenix_score' requires Enterprise tier"
  }
}
```

---

## Error Handling

### Common Error Scenarios

| Scenario | Error Code | Message | Resolution |
|----------|-----------|---------|------------|
| Invalid API key | HTTP 401 | "API key required" | Provide valid `x-api-key` header |
| Insufficient tier | `-32000` | "Tool requires Enterprise tier" | Upgrade API key scope or use PAPI |
| Invalid CVE ID | `-32602` | "Invalid CVE ID" | Use format `CVE-YYYY-NNNNN` |
| Resource not found | `-32000` | "CVE not found" | Verify CVE exists in database |
| Rate limit exceeded | HTTP 429 | "Rate limit exceeded" | Wait for rate limit window reset |
| Invalid JSON | `-32600` | "Invalid JSON payload" | Fix JSON syntax |
| Unknown method | `-32601` | "Method not found" | Check method name spelling |
| Missing required param | `-32602` | "Missing required param: cve_id" | Provide required parameters |

### Error Response Structure

```json
{
  "jsonrpc": "2.0",
  "id": "request-id",
  "error": {
    "code": -32602,
    "message": "Missing required param: cve_id",
    "data": {
      "details": "The 'cve_id' parameter is required for this tool"
    }
  }
}
```

---

## Rate Limits

### Normal API Rate Limits

| Tier | Requests/Hour | Requests/Minute |
|------|---------------|-----------------|
| Registered | 100 | 10 |
| Pro | 500 | 50 |
| Enterprise | 5000 | 500 |

### PAPI Rate Limits

| Limit Type | Default Value | Configurable |
|------------|---------------|--------------|
| Requests/Minute | 100 | Yes (`PAI_RATE_LIMIT_PER_MINUTE`) |
| Requests/Hour | 1000 | Yes (`PAI_RATE_LIMIT_PER_HOUR`) |

**Rate Limit Headers** (Normal API):
```
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1709136000
```

---

## Integration Patterns

### Pattern 1: Claude Desktop Integration (stdio bridge)

**Setup**:
1. Download the bridge script: `curl -o mcp_http_bridge.py https://phxintel.security/downloads/mcp/mcp_http_bridge.py` (source: `scripts/mcp_http_bridge.py`; also downloadable from the [MCP Installation guide](https://phxintel.security/pubdoc/mcp/installation.html))
2. Configure environment:
```bash
export MCP_HTTP_URL="https://api.phoenix.example.com/api/v1/mcp/claude"
export MCP_API_KEY="<your_api_key>"
```
3. Run bridge: `python scripts/mcp_http_bridge.py`
4. Configure Claude Desktop to use stdio bridge

**Claude Desktop Config** (`~/Library/Application Support/Claude/claude_desktop_config.json`):
```json
{
  "mcpServers": {
    "phoenix": {
      "command": "python",
      "args": ["/path/to/mcp_http_bridge.py"],
      "env": {
        "MCP_HTTP_URL": "https://api.phoenix.example.com/api/v1/mcp/claude",
        "MCP_API_KEY": "<your_api_key>"
      }
    }
  }
}
```

### Pattern 2: Direct HTTP Integration (Custom Agent)

**Python Example**:
```python
import requests

class PhoenixMCPClient:
    def __init__(self, base_url: str, api_key: str):
        self.base_url = base_url
        self.headers = {
            "Content-Type": "application/json",
            "x-api-key": api_key
        }
        self.request_id = 0
    
    def call_method(self, method: str, params: dict = None):
        self.request_id += 1
        payload = {
            "jsonrpc": "2.0",
            "id": str(self.request_id),
            "method": method,
            "params": params or {}
        }
        response = requests.post(self.base_url, json=payload, headers=self.headers)
        response.raise_for_status()
        return response.json()
    
    def get_cve_intelligence(self, cve_id: str):
        return self.call_method("tools/call", {
            "name": "get_cve_intelligence",
            "arguments": {"cve_id": cve_id}
        })

# Usage
client = PhoenixMCPClient(
    "https://api.phoenix.example.com/api/v1/mcp",
    "<your_api_key>"
)
result = client.get_cve_intelligence("CVE-2024-27198")
print(result["result"]["content"][1]["json"]["phoenix_score"])
```

### Pattern 3: PAPI Integration (Internal Service)

**Python Example**:
```python
import requests

class PhoenixPAPIClient:
    def __init__(self, base_url: str, pai_key: str):
        self.base_url = base_url
        self.headers = {
            "Content-Type": "application/json",
            "x-pai-key": pai_key
        }
        self.request_id = 0
    
    def call_tool(self, tool_name: str, arguments: dict):
        self.request_id += 1
        payload = {
            "jsonrpc": "2.0",
            "id": str(self.request_id),
            "method": "tools/call",
            "params": {
                "name": tool_name,
                "arguments": arguments
            }
        }
        response = requests.post(self.base_url, json=payload, headers=self.headers)
        response.raise_for_status()
        return response.json()
    
    def calculate_custom_score(self, cvss: float, **kwargs):
        arguments = {"cvss": cvss, **kwargs}
        return self.call_tool("calculate_custom_phoenix_score", arguments)

# Usage
papi_client = PhoenixPAPIClient(
    "https://internal.phoenix.example.com/internal/v1/mcp",
    "pai_admin_xyz789..."
)
score = papi_client.calculate_custom_score(
    cvss=9.8,
    epss=0.85,
    in_kev=True,
    exploit_status="weaponized",
    vendor="JetBrains",
    product="TeamCity"
)
print(score["result"]["content"][0]["json"]["components"])
```

### Pattern 4: Batch Processing (Multiple CVEs)

**Python Example**:
```python
import requests
from typing import List

class PhoenixBatchClient:
    def __init__(self, base_url: str, api_key: str):
        self.base_url = base_url
        self.headers = {
            "Content-Type": "application/json",
            "x-api-key": api_key
        }
    
    def batch_get_cve_intelligence(self, cve_ids: List[str]):
        results = []
        for cve_id in cve_ids:
            payload = {
                "jsonrpc": "2.0",
                "id": cve_id,
                "method": "tools/call",
                "params": {
                    "name": "get_cve_intelligence",
                    "arguments": {"cve_id": cve_id}
                }
            }
            response = requests.post(self.base_url, json=payload, headers=self.headers)
            if response.status_code == 200:
                results.append(response.json())
        return results

# Usage
batch_client = PhoenixBatchClient(
    "https://api.phoenix.example.com/api/v1/mcp",
    "<your_api_key>"
)
cve_list = ["CVE-2024-27198", "CVE-2024-3400", "CVE-2024-21887"]
results = batch_client.batch_get_cve_intelligence(cve_list)
for result in results:
    cve_data = result["result"]["content"][1]["json"]
    print(f"{cve_data['cve']['cve_id']}: PS-HP {cve_data['phoenix_score']['ps_hp_score']}")
```

### Pattern 5: Command-Line (phoenix-cli)

For ad-hoc queries and shell scripting, use the open-source `phoenix-cli` instead of writing a
custom HTTP client. It wraps both the REST endpoints and the raw MCP JSON-RPC method:

```bash
pip install "git+https://github.com/Security-Phoenix-demo/blue-cve-intelligence-mcp-cli.git"

phoenix-cli configure --api-key <your_api_key>
phoenix-cli get CVE-2024-27198
phoenix-cli mcp tools/call --params '{"name":"get_cve_intelligence","arguments":{"cve_id":"CVE-2024-27198"}}'
```

Full reference: [github.com/Security-Phoenix-demo/blue-cve-intelligence-mcp-cli/docs/CLI.md](https://github.com/Security-Phoenix-demo/blue-cve-intelligence-mcp-cli/blob/main/docs/CLI.md).

---

## Additional Resources

- **MCP Server Documentation**: `docs/MCP_SERVER.md`
- **PAI Documentation**: `docs/key_doc_and_architecture/PAI_INTERNAL_API.md`
- **API Keys Reference**: `docs/key_doc_and_architecture/API_KEYS_REFERENCE.md`
- **Tier Access Guide**: `docs/key_doc_and_architecture/USER TYPE and LEVELS - ACCESS_TIERS_AND_API.md`
- **Bridge Scripts**: `scripts/mcp_http_bridge.py`, `scripts/mcp_http_bridge_chatgpt.py` — downloadable at `/downloads/mcp/mcp_http_bridge.py` and `/downloads/mcp/mcp_http_bridge_chatgpt.py`
- **MCP Installation Guide**: [/pubdoc/mcp/installation.html](https://phxintel.security/pubdoc/mcp/installation.html)
- **MCP CLI Guide**: [/pubdoc/mcp/cli.html](https://phxintel.security/pubdoc/mcp/cli.html)
- **CLI + MCP Bridge Public Repo**: [github.com/Security-Phoenix-demo/blue-cve-intelligence-mcp-cli](https://github.com/Security-Phoenix-demo/blue-cve-intelligence-mcp-cli) — `phoenix-cli` command-line client plus a copy of the MCP bridge scripts; see `docs/CLI.md` and `docs/REPOSITORY.md` in that repo for full documentation

---

## Support

For integration support, contact:
- **Email**: api-support@phoenix.example.com
- **Documentation**: https://docs.phoenix.example.com
- **Status Page**: https://status.phoenix.example.com

---

**Document Version**: 1.4  
**Last Updated**: 2026-07-26  
**Maintained By**: Phoenix API Team
