Lab 3 — Multi-Tool Agent Challenge

The payoff lab for Day 1

You connected tools (Lab 1). You built tools (Lab 2).
Now you make them run as one autonomous pipeline
then you break it on purpose to learn exactly why it works.

Surface: Antigravity agent + MCP Inspector, side by side
Artifacts: lab3-system-prompt.md + lab3-retro.md + a working pipeline
Two rules: (1) write the system prompt before you run anything. (2) The break exercise is not optional — it's the most educational part.

The 5-step pipeline — predict it before you run it

Every tool call the model will make, in order:

# Tool called What it does here Loop component MCP server
1 search Finds current info on the topic Action → feeds Perception DuckDuckGo / mock (Lab 1)
2 model reasoning Synthesises results, decides what to save & how to tag Reasoning — no tool call (invisible in logs) n/a — model internal
3 create_entry Saves synthesised findings as a StackLog entry Action → writes external memory StackLog (Lab 2 — your code)
4 search_entries Verifies the entry saved — reads it back Action → reads external memory StackLog (Lab 2 — your code)
5 write_file Saves a full markdown report for human review Action → final write Filesystem (Lab 1)

You should be able to predict this pipeline before running it. If you can, you understand the agent loop.

Quick recap — the five guards (from Session 6)

Your system prompt must defend against the five failure modes. One guard each:

  1. Tool hallucination — model invents a result instead of calling the tool.
    "Do not infer from training data. You MUST call search before create_entry."
  2. Runaway loop — model calls a tool over and over.
    "Call search at most twice. Accept the results and proceed."
  3. Context bloat — raw tool output fills the window.
    "After each tool call, summarise the result in one sentence. Drop the raw data."
  4. Scope drift — model wanders beyond the task.
    "Do not expand scope beyond the stated topic."
  5. Premature stop — model quits before finishing.
    "Task is complete ONLY when an entry ID is returned AND the report file is saved. Do not stop before both."

Phase 1 · Design the system prompt (12 min)

Step 1 — Create lab3-system-prompt.md

In the workshop repo:

🪟  cd $env:USERPROFILE\stacklog-workshop ; New-Item lab3-system-prompt.md
🍎🐧 cd ~/stacklog-workshop && touch lab3-system-prompt.md

Write your prompt before opening the agent. It needs four sections: [ROLE] · [TOOLS] · [CONSTRAINTS] · [OUTPUT FORMAT].

Step 1 — reference system prompt (cont.)

Reference system prompt — adapt it or write your own:

[ROLE]
You are a StackLog research assistant. Given a topic, you will research it
on the web, save a journal entry to the StackLog store, verify it was saved,
and write a full markdown report to disk. Work autonomously — do not ask for
confirmation between steps.

[TOOLS]
- search: find current information about the topic.
  Use this first. Call it at most twice.
- create_entry: save synthesised findings to the StackLog journal.
  Call once after researching. Title max 80 chars. Tags lowercase.
- search_entries: verify the entry was saved.
  Call once after create_entry to confirm it is retrievable.
- write_file: save the full markdown report to disk.
  Call last. Save to my Desktop as: stacklog-report-[topic].md

Step 1 — reference prompt: constraints & output (cont.)

[CONSTRAINTS]
- Complete the full pipeline in at most 6 tool calls.
- Do not infer search results from training data. Call search.
- After each tool call, summarise the result in one sentence. Drop the raw data.
- Do not expand scope beyond the stated topic.
- The report filename must use only lowercase letters, numbers, and hyphens.
- Task is complete when: an entry ID is returned AND the report file is saved.
  Do not stop before both conditions are met.

[OUTPUT FORMAT]
Respond with exactly:
"Task complete.
 StackLog entry ID: [id]
 Report saved to: [filepath]
 Key finding: [one sentence]"

💡 If your search server is mock-search, the tool is still called search — no prompt change needed.

Step 2 — Peer review (3 min)

Swap prompts with a neighbour. Check only two things:

  • Are all five guards present?
  • Is the completion criterion explicit — can the model know it's done?

Checkpoint 1: both present, or fixed before running anything.

Phase 2 · Run the pipeline (23 min)

Step 3 — Set up side-by-side, reconnect servers

Layout: Antigravity agent on one side, MCP Inspector + your system prompt on the other.

Confirm all three servers are connected in Antigravity's MCP panel:

  • filesystem (Lab 1) — and its allowed path includes your Desktop (needed for write_file)
  • ddg-search or mock-search (Lab 1)
  • stacklog (Lab 2)

⚠️ Keep the StackLog server stable for the whole run — do not restart it mid-pipeline (Step 4 of troubleshooting explains why).

Checkpoint 2: all three servers show their tools.

Step 4 — Choose a topic and run

Pick a topic (suggestions if stuck):

  • "Benefits and risks of AI code generation in production software"
  • "How TypeScript improves team collaboration on large codebases"
  • "The current state of WebAssembly in frontend development"

In a new agent conversation, paste your system prompt first, then send:

Research [YOUR TOPIC] and run the full StackLog pipeline.

Watch both panels while it runs. 🔎 The moment create_entry fires, look at MCP Inspector:

"That tool call — the one creating the entry — is invoking the code you wrote in Lab 2. The model is calling YOUR function."

Step 5 — Verify all five steps

  • [ ] New entry in stacklog-entries.json with correct title, tags, content
  • [ ] Report file on the Desktop — a real markdown doc with sections
  • [ ] Entry ID in the agent's reply matches the ID in the JSON store
  • [ ] MCP Inspector shows ≤ 6 total tool calls
🪟  type $env:USERPROFILE\stacklog-entries.json
🍎🐧 cat ~/stacklog-entries.json

✅ All four pass → commit a clean baseline before breaking anything:
git add . ; git commit -m "lab3: pipeline working — [topic]"

⚠️ If search is rate-limited: switch the search server to mock-search (Lab 1, Step 6). The pipeline is identical; steps 3–5 (your code) are unaffected. The lab does not depend on the live network.

Phase 3 · Intentionally break it (25 min)

"A pipeline that works once is not a system — it's a coincidence. Understanding exactly how it fails is what turns you from an AI user into an AI architect."

Step 6 — Run at least TWO break scenarios

For each break: apply it → Refresh Antigravity (if config changed) → run the same prompt → record what happened → add ONE guard → restore → confirm baseline works again.

⚠️ Restore before the next break. Never stack breaks — you need a clean baseline each time.

Step 6 — the four break scenarios (cont.)

The four break scenarios (pick ≥ 2):

Break What you change Failure mode it triggers The guard that fixes it
A · Remove search Disable the search server in mcp_config.json Tool hallucination — model invents "search results" from training data "You MUST call search before create_entry. Do not substitute training knowledge."
B · Degrade the schema Edit your StackLog server: blank out the create_entry description / drop required Bad tool use — model calls it with missing or wrong arguments (watch MCP Inspector) Restore a precise description + required: ['title','content']
C · Remove the loop guard Delete "call search at most twice" from the prompt Runaway loop — model searches 4+ times "Call search at most twice. Accept the results and proceed."
D · Weaken completion criteria Change completion to mention only create_entry Premature stop — model never calls write_file "Complete ONLY when an entry ID is returned AND the report file is saved."

Break B edits your server code — the others edit config or the prompt. After B, rebuild/rerun the server.

Step 7 — Record in lab3-retro.md

🪟  New-Item $env:USERPROFILE\stacklog-workshop\lab3-retro.md
🍎🐧 touch ~/stacklog-workshop/lab3-retro.md

For each break, record (template in the starter — lab3-retro-template.md):

  • Break applied: what you changed
  • Failure mode: which of the five
  • Exact symptom: what the model did wrong
  • Root cause: why it happened
  • Guard added: the exact system-prompt line that prevents it

This retro is the Lab 3 artifact — it feeds the Day 1 close and the "next Monday" card.
Checkpoint 3: at least two breaks fully documented, each with a guard (not just "restored it").

The Other Failure Class — When the Tool Is the Threat

The five guards defend against the model's mistakes. But the tools themselves can be hostile — you wired in a third-party search server on trust. (Google, Agent Tools)

Threat What happens
Tool shadowing a malicious tool's description out-competes a legit one, so the agent calls it
Poisoned definition hidden instructions in a tool's description or output hijack the agent (prompt injection via tools)
Confused deputy the agent holds privileges the user doesn't — and is tricked into misusing them
Capability injection a server silently adds a new, higher-risk tool after you approved it

Your search server is third-party code with a voice inside the model's context. Trust is a decision, not a default.

Guarding the Tool Boundary

Four defenses — the tool-side mirror of your five guards:

  • Allowlist — the agent may only reach servers/tools you explicitly approved. No surprise connections.
  • Least privilege — give each tool the narrowest access that works (read-only if it only reads). A leash short enough to keep it out of traffic.
  • Human-in-the-loop — gate irreversible or high-risk actions (delete, spend, send) on explicit confirmation, whoever invokes them.
  • Sanitize the boundary — validate inputs; treat tool output as untrusted text that could carry an injected instruction.

This is Principle 3 — Constrain the Power made concrete. Utility and safety trade off; you decide where.

Phase 4 · Team demos (14 min)

Step 8 — 3-minute demos

Volunteers present (visible timer):

  1. Show the system prompt — explain one design decision (a pattern or a guard)
  2. Run the pipeline live — class watches the tool calls
  3. Open stacklog-entries.json and the report file — show both artifacts

Rotate one class question per demo:

  • "What failure mode could this still fall into? What guard would you add?"
  • "How many tool calls did that take? Could it be fewer?"
  • "What breaks if the topic were much longer or more complex?"

Phase 5 · Final commit (1 min)

Step 9 — Push all Lab 3 artifacts

🪟  cd $env:USERPROFILE\stacklog-workshop
🍎🐧 cd ~/stacklog-workshop
git add lab3-system-prompt.md lab3-retro.md
git commit -m "lab3: pipeline complete, break exercise documented"
git push origin main

Lab 3 complete when the system prompt, retro notes, and a working pipeline are all on GitHub.

Troubleshooting (top 6)

  1. Model calls no tools → StackLog server not running (npx tsx src/index.ts); or config not reloaded (Refresh / restart Antigravity); or [TOOLS] section too vague — add explicit names and call order.
  2. Hallucinated results (skipped search) → add: "You MUST call search before create_entry; do not use training knowledge as a substitute."
  3. create_entry works but search_entries is empty → the server was restarted mid-pipeline and STORE_PATH changed. Keep one server process for the whole run.
  4. write_file permission denied → the filesystem server's allowed path must include your Desktop; and keep the filename lowercase-hyphen only.
  5. Pipeline loops (search 4+ times) → add the at-most-twice guard.
  6. Stops after create_entry → completion criteria must require both the entry ID and the saved report.

Lab 3 outcome — what you now know

  • How to build an MCP server and connect it to a model (Labs 1–2)
  • How to design a system prompt that produces reliable agentic behaviour
  • Which failure modes to design against — and the guard for each
  • That the same model with a better prompt produces dramatically different results

That is the difference between using AI and architecting an AI system.

Bridge to Day 1 close: you have five artifacts (warm-up files, the MCP server, the pipeline, the system prompt, the retro). Tonight's prep and the Day-2 preview come next.

FACILITATOR (presenter note, not shown): If a demo fails live, don't skip it — diagnose the failure mode together. That's the lesson.