Skills, tools, and MCPs

Agents need ways to act and ways to reuse guidance. Tools, MCPs, and skills solve related but different parts of that problem.

Mechanism What it supplies Use it for
Tool A typed action the harness can execute Reading a file, querying a database, or controlling a browser
MCP A standard connection to tools and context Plugging an external system into an agent harness
SKILL Text and resources for a matching task Describes a workflow, checklist, or domain-specific tool

Before writing a skill, check whether it already exists: browse Anthropic’s skills library or search the registry with npx skills find plus a keyword. Reading a well-written skill is also the fastest way to pick up the format.

Activity

We’ll learn this by connecting Claude to the HADR simulation over MCP, playing it by hand, and then packaging the winning procedure as a skill.

Launch the engine

Launch the engine and open the display to see the map, trucks, and incoming reports for yourself:

cd engine && uv run hadr-engine serve --port 8000

Then open http://127.0.0.1:8000/ in a browser. You should be greeted by a blank screen saying “connect to continue”. The game guide covers the rules and the API guide the control surface.

Remember, the agent has no way to know the actual fires and damage directly, only through what is reported to it.

Connect Claude

Claude Code reads MCP configuration from the folder it starts in, so you must open a new Claude instance in mcp-play/ - the session you already have open cannot see the game:

cd mcp-play && claude

Before playing, read the configuration you just inherited - it is three small files:

  • .mcp.json declares the hadr MCP server: an HTTP endpoint at http://localhost:8000/mcp. That one file is the entire connection.
  • .claude/settings.json pins a small model and allowlists the game tools (mcp__hadr__*) so play does not stop for approval on every call.
  • CLAUDE.md is the runbook the new instance follows on startup.

Run /mcp to confirm the hadr server is connected and to list its tools.

Play

Work through the game interactively before attempting to automate it:

  1. Use a tool: try at least one game action - observe contacts, inspect trucks, query the map, dispatch a vehicle. Inspect its inputs, result, side effects, and failure modes.
  2. Solve the game interactively: direct Claude through a complete stage-1 episode, having it file incidents in a scratch file as it plays; that file is a preview of the incident store your team is building. Predict the next public state before ending each tick, compare the result with the simulator’s response, and refine your instructions until Claude can solve the game with you in the loop.

As you play, consider:

  • Which state is public, which is an agent belief, and which is hidden truth?
  • Why must dispatch reference a filed incident, and what actually enforces that? The simulator logs the incident_id and echoes it back, but never checks that it names a real filed incident.
  • Who is allowed to call next_tick()?
  • Where is the boundary between the inner tool loop and the person directing Claude?

Write the skill

Don’t write the skill yourself: Claude is very good at generalizing from examples, and the session that just played holds several worked examples in context. Have it distill them. After a few episodes, in the same session:

Write what worked as a skill at .claude/skills/hadr-play/SKILL.md: the per-tick checklist, what to verify before each dispatch, and the stopping condition. Include the mistakes you made this session and how to avoid them.

A skill is one markdown file in a named folder, with YAML frontmatter:

---
name: hadr-play
description: Play a HADR fire-dispatch episode over the hadr MCP server. Use when asked to play, resume, or demo the game.
---

[The operating procedure.]

Review what Claude wrote before accepting it. The frontmatter description is the trigger: Claude reads only the descriptions to decide which skill matches the task, so it must say when to use it, not just what it is. The body loads only after triggering, so the full procedure goes there - and vague advice (“dispatch carefully”) is filler; every line should change what the next session does in a concrete and observable manner.

Do not create a skill for a rule or policy that should always be loaded, that belongs in CLAUDE.md. A skill loads only when its description matches.

Test the skill

A skill you have not watched fire is a guess:

  1. Start a fresh Claude session in mcp-play/ (skills are discovered at startup).
  2. Ask for the task without naming the skill - “play a stage-1 episode” - and confirm the skill loads. /hadr-play invokes it directly, but the real test is the indirect trigger.
  3. Watch it play a full episode. Where it stalls or misreads state, fix the skill, not the chat.
  4. Raise the difficulty: the skill was distilled from stage-1 play, so run it against harder scenarios (list_scenarios shows all five stages). Where it breaks - noise, contradictions, too many calls - is exactly what the skill under-specified; fold what you learn back in.

If time permits: run the same skill from OpenCode (cd mcp-play && opencode), which also supports skills. Same file, different harness and model - see what survives the swap.

Expected results on the default seed (lower is better; the baseline is the shipped greedy dispatcher). Use them as the yardstick when you raise the difficulty. Dispatch is not fully deterministic at temperature 0 on this endpoint, so some run-to-run variation is normal.

Scenario Greedy baseline (casualties / buildings) Reference agent (casualties / buildings)
stage1-basic 40 / 1 5 / 1
stage2-language 40 / 1 26 / 1
stage3-partial 26 / 1 0 / 0
stage4-replan 40 / 1 5 / 1
stage5-triage 40 / 1 0 / 0

When you’re done

  1. Trade pull requests. Open a pull request with your skill in it and swap with a teammate: review theirs, have them review yours, and compare the two side by side. A skill that only works for its author is a prompt, not a skill, and the differences between two skills built for the same task are the interesting part.
  2. Screenshot your context. Run /context, screenshot the output, and upload it to the Padlet. We’ll explain and discuss those after lunch.