Skip to slide
Chapter 10 · Skills, MCP, and Deterministic Computation
69 / 142

CHAPTER 10 · Skills, MCP, and Deterministic Computation · 6 / 8

Code MVP: skills and a mini MCP

"""
chapter 10: skills, MCP, and deterministic computation.
SkillLoader: progressive disclosure (descriptions up front, body on demand).
MiniMCPClient: list tools from a server and register them (deferred schemas).
A deterministic 'compare' tool shows the anti-hallucination contract.
"""
import os, re

# ---------- Skills ----------
class SkillLoader:
    def __init__(self, skills_dir: str):
        self.dir = skills_dir
        self.index = {}       # name -> (description, path)
        self._scan()

    def _scan(self):
        if not os.path.isdir(self.dir):
            return
        for fn in os.listdir(self.dir):
            if fn.endswith(".md"):
                path = os.path.join(self.dir, fn)
                text = open(path, encoding="utf-8").read()
                name = re.search(r"name:\s*(.+)", text)
                desc = re.search(r"description:\s*(.+)", text)
                key = (name.group(1).strip() if name else fn)
                self.index[key] = (desc.group(1).strip() if desc else "", path)

    def summary(self) -> str:
        """Cheap: only names + descriptions go into the prompt at startup."""
        return "\n".join(f"- {n}: {d}" for n, (d, _) in self.index.items())

    def load_body(self, name: str) -> str:
        """Expensive: the full skill body, fetched ONLY when invoked."""
        _, path = self.index[name]
        return open(path, encoding="utf-8").read()

# ---------- A tiny MCP-style server/client ----------
class MiniMCPServer:
    """Pretend external server exposing tools (e.g. a data service)."""
    def list_tools(self):
        return [{"name": "compare_data",
                 "description": "Exactly diff two lists of numbers",
                 "parameters": {"type": "object",
                                "properties": {"a": {"type": "array"},
                                               "b": {"type": "array"}},
                                "required": ["a", "b"]}}]
    def call(self, name, **args):
        if name == "compare_data":
            # DETERMINISTIC: code computes the truth; the model never guesses it.
            a, b = args["a"], args["b"]
            diffs = [{"index": i, "a": x, "b": y, "delta": y - x}
                     for i, (x, y) in enumerate(zip(a, b)) if x != y]
            return {"differences": diffs, "count": len(diffs)}

class MiniMCPClient:
    def __init__(self, server): self.server = server
    def register_into(self, registry, Tool):
        for spec in self.server.list_tools():           # discover (deferred schema)
            registry.register(Tool(
                name=f"mcp__data__{spec['name']}",
                description=spec["description"],
                parameters=spec["parameters"],
                handler=lambda _n=spec["name"], **a: self.server.call(_n, **a)))

if __name__ == "__main__":
    os.makedirs("/tmp/skills", exist_ok=True)
    open("/tmp/skills/investigate.md", "w").write(
        "---\nname: investigate\ndescription: Trace a value across backends\n---\n"
        "## Steps\n1. Run fetch_data.py\n2. Run compare_data.py\n3. Write a report\n")
    sl = SkillLoader("/tmp/skills")
    print("startup (cheap):", sl.summary())
    print("on demand (full body):\n", sl.load_body("investigate")[:80], "...")

    # MCP: register a deterministic tool and call it.
    server = MiniMCPServer()
    print("\ndeterministic compare:",
          server.call("compare_data", a=[1, 2, 3], b=[1, 9, 3]))

Run it: at startup you pay only for the one-line skill description; the full body loads only when asked. The MCP server's compare_data computes the exact diff in code, so the model interprets {"differences": [...], "count": 1} instead of squinting at raw numbers and possibly inventing one. That is the anti-hallucination contract in working form.

← → arrow keys work too