Skip to content

feat: MCP server for agentic scenario generation (+ tabletop skill) - #60

Merged
mrwadams merged 6 commits into
mainfrom
feat/mcp-server
Jul 21, 2026
Merged

feat: MCP server for agentic scenario generation (+ tabletop skill)#60
mrwadams merged 6 commits into
mainfrom
feat/mcp-server

Conversation

@mrwadams

Copy link
Copy Markdown
Owner

Overview

Adds an MCP server that exposes AttackGen's scenario generation to agentic clients, plus the supporting refactor that makes the scenario logic reusable outside Streamlit, and an attackgen-tabletop Agent Skill built on top of it.

What's included

MCP server (mcp_server.py)

FastMCP server (official mcp SDK) over stdio, in two tiers:

  • Data toolslist_threat_groups, list_case_studies, get_kill_chain, get_detection_report, get_navigator_layer, list_ai_insider_options, get_ai_insider_prompt. No LLM call, no API key required; return structured MITRE data (and a ready-to-run prompt where useful). Safe to host over HTTP.
  • Generate toolsgenerate_threat_group_scenario, generate_custom_scenario, generate_ai_insider_scenario. Bring-your-own-key LLMConfig (validated against core/models.py), return finished Markdown. Keep on local stdio.

Launch: python -m mcp_server or the attackgen-mcp console script.

Headless core refactor

Scenario prompts and MITRE data loading were lifted out of the Streamlit pages so the pages and the MCP server share one implementation:

  • core/attack_data.py — headless MITRE loaders + kill-chain resolution (lazy @lru_cache singletons, cwd-independent absolute paths, deterministic sampling via seed).
  • core/prompts.py — single source of truth for every scenario prompt + the build_*_messages builders (Streamlit-free). Pages 1–3 and the MCP server all call these.
  • Pages 1–3 slimmed down to consume the shared builders (net −327 lines in the page files).

attackgen-tabletop Agent Skill (skills/)

Turns the MCP data tools into a facilitator-ready IR tabletop (MSEL) — scenario narrative, kill chain, timestamped injects, discussion questions, and a detection-coverage scorecard, as Markdown or a self-contained, print-friendly HTML report.

Packaging & tests

  • pyproject.toml[project]/[build-system] metadata, attackgen-mcp console script, pytest config.
  • New test suites: tests/test_attack_data.py, tests/test_prompts.py, tests/test_mcp_server.py, tests/test_llm.py.

Test plan

  • pytest passes from the repo root
  • python -m mcp_server starts and the data tools return over stdio
  • Streamlit pages 1–3 still generate scenarios (shared-builder parity)

🤖 Generated with Claude Code

mrwadams and others added 3 commits July 20, 2026 09:19
Expose AttackGen to MCP clients (Claude Code/Desktop, Cursor, agents) via a
FastMCP server with two tiers of tools:

- Data tools (no key, no LLM call; safe to host over HTTP): list_threat_groups,
  list_case_studies, get_kill_chain, get_detection_report, get_navigator_layer,
  list_ai_insider_options, get_ai_insider_prompt. Return structured MITRE data
  and, where useful, a ready-to-run prompt so a client's own model can generate.
- Generate tools (bring-your-own-key; local stdio): generate_threat_group_scenario,
  generate_custom_scenario, generate_ai_insider_scenario. Call core.llm.call_llm
  with an LLMConfig validated against core/models.py; api_key omitted falls back
  to the provider env var (the caller's own key).

Prerequisite refactor (pages and MCP server now share one source of truth):
- core/prompts.py: every scenario prompt + build_*_messages, lifted byte-for-byte
  from pages 1-3 (incl. the deliberate Custom-ATTACK British-English omission).
- core/attack_data.py: headless MITRE loaders (lazy lru_cache, __file__-based
  absolute paths) + kill-chain resolver reproducing page-1 logic exactly
  (non-deduped per-phase sampling; seed for determinism; JSON-native output).
- core/ai_uplift.py: pure append_ai_uplift(content, bool); apply_ai_uplift delegates.
- core/llm.py: route the run_id writes through _stash_run_id (try/except) so a
  headless generate can't crash when LANGCHAIN_API_KEY is set.
- Pages 1/2/3 refactored to thin wrappers over the shared modules.

Packaging: add mcp>=1.2.0; pyproject [project]/[build-system] + attackgen-mcp
console script. Docs: README MCP Server section, CLAUDE.md/AGENTS.md.

Tests: +31 (test_prompts, test_attack_data, test_mcp_server), 162 total green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add an open-spec Agent Skill that drives the AttackGen MCP data tools into a
facilitator-ready incident-response tabletop exercise (MSEL) — the craft layer
over the MCP capability layer. Runs on the caller's own model, no API key.

- skills/attackgen-tabletop/SKILL.md — orchestration + workflow (resolve kill
  chain, pull detection report, author the exercise). Model-invoked.
- references/exercise-format.md — the MSEL section structure + house style.
- references/html-report.md — HTML delivery mechanics (write self-contained file
  to the OS temp dir, open it, report the path).
- assets/tabletop-report.html — canonical self-contained template the model
  clones: theme-aware, print-friendly, facilitator/participant toggle, CSS inject
  timeline, detection scorecard. Fully inline (no CDN) so it works offline, in an
  air-gapped SOC, and as an emailable PDF — a deliberate departure from
  CDN-based report skills.
- skills/README.md — cross-client install + Claude Code plugin bundling (ships
  the MCP server config and skills together).

Data stays live: the skill bundles no MITRE data and formats only what the MCP
tools return, so nothing goes stale. Authored to mattpocock/writing-great-skills
conventions — positive framing throughout (no prohibition steering), single
source of truth for each rule, trigger-focused description, progressive
disclosure into references/.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Print (@media print) fixes to the attackgen-tabletop HTML template so a
facilitator's Print/PDF yields a usable handout:
- Expand all <details> via beforeprint/afterprint JS (a closed <details>
  hides content through the UA shadow-DOM slot, which author CSS can't
  override) so collapsed question groups aren't dropped from the PDF.
- Scale the wide SVG kill-chain ribbon to the page instead of clipping.
- Let wide tables (kill chain, detection scorecard) wrap and shrink to
  fit the page rather than scroll-then-clip on paper.

Also gitignore .claude/ and .codex/ local agent/tooling directories.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Comment thread core/llm.py Fixed
mrwadams and others added 3 commits July 21, 2026 09:26
- README: add v0.14 changelog rows for the MCP server and the
  attackgen-tabletop Agent Skill, plus a new Agent Skills section
  and TOC entry so the skill is discoverable from the main README.
- AGENTS.md: undo a bad global Claude→Codex replace that produced a
  fake "Codex.ai/code" URL and mislabelled the Anthropic provider as
  "Codex 4.x family" (restored to Claude).
- SECURITY.md: note MCP server exposure — stdio-only/no auth, data
  tools HTTP-safe, keep generate tools on local stdio.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Fill the high-value gaps in the MCP PR's test surface:
- generate_ai_insider_scenario: happy path (was registration-check only)
- generate tools' empty-input guards (empty kill chain / techniques -> ValueError)
- include_detection append branch on both threat-group and custom generate tools
- get_ai_insider_prompt data-tool message contract
- core.attack_data.list_technique_options (ATT&CK external_id filtering + ATLAS)
- core.attack_data.mitre_data_for_matrix ValueError for ATLAS/unknown

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add an inline comment documenting the deliberate no-op swallow so the
GitHub Advanced Security alert (#223) clears; behaviour is unchanged and
is still pinned by test_stash_run_id_swallows_missing_streamlit_context.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@mrwadams
mrwadams merged commit d7c538a into main Jul 21, 2026
7 checks passed
@mrwadams
mrwadams deleted the feat/mcp-server branch July 21, 2026 14:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants