ContrastAPI exposes the ATLAS / D3FEND / CWE catalogs as MCP resources/* so agents can browse without spending a tool slot. Resources are pure local-DB lookups — no rate limit, no upstream API, no auth.
| URI | Type | Returns |
|---|---|---|
atlas://catalog |
static | All ATLAS techniques + case studies (slim summary) |
atlas://technique/{technique_id} |
template | Full ATLAS technique record |
atlas://case-study/{case_study_id} |
template | Full ATLAS case study |
d3fend://catalog |
static | All D3FEND defenses (slim summary) |
d3fend://defense/{defense_id} |
template | Full D3FEND defense + ATT&CK mappings |
cwe://catalog |
static | All CWE weaknesses (id+name+abstract_type) |
cwe://weakness/{cwe_id} |
template | Full CWE record incl. mitigations + examples |
{technique_id} accepts ATLAS format AML.T#### or AML.T####.###. {cwe_id} accepts CWE-79 or just 79 (auto-prefixed). All MIME types are application/json.
Tools and resources cover different use-cases:
- Resources — "I know exactly which catalog row I want." Browse-style. Cheap. No filtering / pivots.
- Tools (
atlas_technique_search,d3fend_defense_search,cwe_lookup, ...) — "I want to filter / pivot / chain." Carries a rate budget but supports parameters and emitsnext_callspivot hints.
Reach for resources when an agent already has a CWE id or a D3FEND slug from a prior tool call and you want to drill the full record without re-running the search.
# List static resources (3 catalogs)
curl -X POST https://api.contrastcyber.com/mcp/ \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"resources/list","params":{}}'
# List URI templates (4 detail-resource templates)
curl -X POST https://api.contrastcyber.com/mcp/ \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":2,"method":"resources/templates/list","params":{}}'# Full ATLAS technique
curl -X POST https://api.contrastcyber.com/mcp/ \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":3,"method":"resources/read","params":{"uri":"atlas://technique/AML.T0051"}}'
# CWE-79 (bare-number form auto-prefixes)
curl -X POST https://api.contrastcyber.com/mcp/ \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":4,"method":"resources/read","params":{"uri":"cwe://weakness/79"}}'
# Full D3FEND catalog (149 defenses, slim)
curl -X POST https://api.contrastcyber.com/mcp/ \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":5,"method":"resources/read","params":{"uri":"d3fend://catalog"}}'The CWE catalog has 944 rows in production; full descriptions blow past most agent context budgets. Catalog responses therefore carry only id + name + key fields per row. Use the per-id template URI when you need the full record.
// atlas://catalog
{
"techniques": [{"technique_id": "AML.T0051", "name": "LLM Prompt Injection", "tactics": ["AML.TA0011"], "subtechnique_of": null}, ...],
"case_studies": [{"case_study_id": "AML.CS0000", "name": "Evasion of Deep Learning Detector"}, ...],
"totals": {"techniques": 167, "case_studies": 57},
"truncated": false
}
// d3fend://catalog
{
"defenses": [{"defense_id": "TokenBinding", "label": "Token Binding", "tactic": "Harden", "artifact": "Token", "parent_label": "Authentication"}, ...],
"totals": {"defenses": 149},
"truncated": false
}
// cwe://catalog
{
"weaknesses": [{"cwe_id": "CWE-79", "name": "Improper Neutralization of Input ...", "abstract_type": "Base"}, ...],
"totals": {"weaknesses": 944},
"truncated": false,
"note": "Slim view (cwe_id + name + abstract_type only). Read cwe://weakness/{id} for description, mitigations, examples."
}The truncated boolean is true when the in-memory listing length is below the table count — surfaced honestly so clients fall back to the search tools (atlas_technique_search, d3fend_defense_search) instead of trusting an incomplete catalog. Today it is always false in production (catalog sizes well within the listing cap); the flag is forward-compatible.
A well-formed but unknown id surfaces as a JSON-RPC error response (not a 200-with-empty-body) so agents can branch on it cleanly:
atlas://technique/AML.T9999(well-formed, not in catalog) → JSON-RPC erroratlas://technique/not-an-id(malformed) → JSON-RPC error (validator rejects before DB lookup)cwe://weakness/0(well-formed, not in catalog) → JSON-RPC error
Catalog data ships with the server (synced from upstream on a schedule — ATLAS ~6 months, D3FEND ~yearly, CWE ~weekly). Resources read directly from SQLite on each call; no MCP-layer cache, no TTL. Upstream sync cadence is the only cache.