Skip to content

Module 07 — LLM-Native Python & MCP

Type 9 · Tool-Build — expose sift to an LLM as an MCP server, and validate the LLM's own output with the same discipline you validate an API response. Go to the hands-on lab →  ·  Cheat sheet →

Last reviewed: 2026-07

Python for Securitythe same "parse, don't trust" you apply to a feed applies to the model — its arguments in, and its answers out.

In 60 seconds

Two moves make sift LLM-native, and both are the input edge discipline from Module 02 applied to the AI. First, expose sift's enrich/triage functions as an MCP server so an LLM or agent can call them — where every argument the model passes is untrusted input, validated exactly like Module 02 validates a feed. Second, when sift itself calls an LLM (to summarize or classify an alert), the model's output is also untrusted — use instructor to force it into a pydantic model, validated like an API response instead of parsed out of free text. Module 02 was the input edge; this is the AI edge; Module 09 is the measurement layer. Same discipline, three places.

Why this matters

"LLM-native" is where a lot of security tooling is heading, and where a lot of it is quietly unsafe. Two trust boundaries get missed. When you expose a tool to a model via MCP, people forget that the model is an untrusted caller — it can be prompt-injected into calling your enrich tool with a hostile argument, so the tool must validate its inputs as if they came from the internet (because, transitively, they did). And when your code consumes an LLM's output, people json.loads() the model's free text and hope — which breaks the moment the model wraps it in prose or hallucinates a field.

Both failures are the same root mistake this whole track fights: trusting input you didn't validate. The fix is the fix you already know — parse into a typed model at the boundary — applied to the AI on both sides. Get this right and sift becomes a tool an agent can safely use and a tool that safely uses an agent.

The core idea

An MCP server is an API whose caller is an LLM — so validate every argument. Exposing sift.enrich as an MCP tool (with FastMCP, @mcp.tool()) is a few lines: the type hints and docstring become the schema the model sees. But the model can be manipulated into calling it with "1.1.1.1; drop table" or a path-traversal string, so the tool validates its arguments with Module 02's pydantic models before doing anything. Prefer read-only tools; if a tool changes state, gate it behind explicit human confirmation rather than letting the model trigger it.

instructor makes the LLM's output a typed object, not a hope. When sift asks a model to classify an alert, you don't want a paragraph you regex — you want a validated Verdict(severity=..., is_tp=...). instructor patches the client so the model's response is coerced into (and re-asked until it satisfies) a pydantic model. That's the exact twin of Module 02: there you validated an untrusted API response into an Alert; here you validate an untrusted model response into a Verdict. The LLM is just another unreliable upstream you refuse to trust raw.

Pin the moving parts. MCP and instructor are newer and still evolving. Pin their versions (Module 01's lockfile), teach yourself the durable pattern (typed tool arguments; typed model output), and treat the specific API as replaceable — the discipline outlives the library.

Where this ends and Track 12 begins

This module is about building the tool well in Python — the typed MCP server, the validated LLM output. Operating and securing AI systems at large — RAG quality, a SOC copilot at volume, the broad red-team — is Track 12 (AI-Augmented Ops). The shared verbs (MCP, prompt injection) appear in both: here you learn the craft; there you learn the operation. Module 08 next bridges them by attacking the very server you build here.

Learn (~2–3 hrs)

MCP

Typed LLM output

Key concepts

  • An MCP server's caller (the LLM) is untrusted — validate every tool argument with pydantic.
  • Type hints + docstring = the tool schema the model sees; write them for the model.
  • Read-only by default; gate state-changing tools behind human confirmation.
  • instructor validates LLM output into a pydantic model — the AI-edge twin of Module 02.
  • Pin MCP/instructor (they move fast); own the durable pattern, not the specific API.

AI acceleration

This is the module where the track's tool becomes usable by AI — so the review stakes rise. Have the copilot scaffold the MCP server and the instructor-typed classifier, then check the two boundaries: does the tool validate its arguments (or trust whatever the model passes)? Does the classifier return a validated model (or json.loads() free text and pray)? Both are the same bug you've been catching all track, now at the AI edge.

Check yourself

  • Why is an argument an LLM passes to your MCP tool "untrusted input," and what stops it being dangerous?
  • How is validating an instructor response into a Verdict the same discipline as validating a feed into an Alert?
  • Which of sift's tools should be read-only, and which (if any) deserve a human-confirmation gate?

Comments

Sign in with GitHub to comment. Choose the type: Feedback (errors or suggestions on this page) · Hints (help for fellow learners — no spoilers) · General (anything else).