De-slop: remove every em-dash + banned words across all modules + capstone (#94)
Sync course wiki / sync-wiki (push) Successful in 4s

Co-authored-by: claude <claude@jpaul.io>
Co-committed-by: claude <claude@jpaul.io>
This commit was merged in pull request #94.
This commit is contained in:
2026-06-22 23:21:22 -04:00
committed by Claude (agent)
parent 513d7e7ac8
commit c098933f25
99 changed files with 1324 additions and 1315 deletions
@@ -1,4 +1,4 @@
# Module 20 MCP Servers: Giving the AI Hands
# Module 20: MCP Servers, Giving the AI Hands
> **Until now the AI could read and write files in your repo and nothing else. MCP lets it reach
> your real tools, data, and systems (your task tracker, your database, your docs, your APIs)
@@ -23,7 +23,7 @@ Helpful but not required: **Module 16** (containers) and **Module 17** (secrets)
we talk about *where* a server runs and *what it's allowed to touch*. You can read this module
without them.
This is the opener of **Unit 4 Extend the AI into your systems.** Units 13 got the AI safely
This is the opener of **Unit 4: Extend the AI into your systems.** Units 13 got the AI safely
editing your code and shipping it. Unit 4 is about giving it reach beyond the repo.
---
@@ -115,17 +115,17 @@ server to a client," and it's the same skill everywhere.
An MCP server can offer three kinds of things. You'll mostly care about the first:
- **Tools** *actions the AI can take.* A tool is a named function with typed arguments and a
- **Tools** are *actions the AI can take.* A tool is a named function with typed arguments and a
description: `add_task(title)`, `run_query(sql)`, `create_issue(title, body)`. The AI reads the
description, decides to call it, supplies the arguments, and gets a result. This is the "hands"
half of the module title; tools are how the AI *does* things. (Tools can have side effects: they
write to your database, hit your API, change real state. That power is exactly why Module 22
exists.)
- **Resources** *data the AI can read.* Read-only context the server makes available: a file, a
- **Resources** are *data the AI can read.* Read-only context the server makes available: a file, a
database record, a docs page, the contents of a config. Where tools *do*, resources *inform*:
they're how the AI gets eyes on a system, the parallel to "durable memory it can read" from
Module 2, extended past your repo.
- **Prompts** *reusable prompt templates the server offers* for common operations against it (e.g.
- **Prompts** are *reusable prompt templates the server offers* for common operations against it (e.g.
"summarize this incident from these logs"). Useful, but the least-used of the three; don't worry
about them while you're learning.
@@ -279,7 +279,7 @@ is where the idea sticks.
> /home/you/ai-workflow-course/tasks-app/.venv/bin/python -c "import mcp; print('mcp ok')"
> ```
### Part A Connect an existing server (optional warm-up, ~10 min)
### Part A: Connect an existing server (optional warm-up, ~10 min)
This part is **optional**: it proves the plumbing works by connecting a server someone else already
wrote, but it's a warm-up. Parts B/C carry the real lesson on the Python SDK you already installed.
@@ -308,7 +308,7 @@ That's the entire client/server loop, end to end, with zero code you wrote. Now
> will run with your permissions; vetting that is **Module 22's** job, and it's not optional. For
> now, stick to first-party reference servers or the one you write next.
### Part B Build a one-tool server over the tasks-app
### Part B: Build a one-tool server over the tasks-app
1. Have Claude Code (or sub your own agent) copy this module's `lab/tasks_mcp_server.py` into your
`tasks-app` folder, next to `tasks.py` and `cli.py`, and confirm it landed there:
@@ -348,7 +348,7 @@ That's the entire client/server loop, end to end, with zero code you wrote. Now
there's nothing to print and no prompt to return to until a client connects. That waiting *is*
the correct behavior. You don't run it by hand for real; the client launches it.
### Part C Wire it into your agentic tool
### Part C: Wire it into your agentic tool
3. Have the agent write the `tasks` config entry. It already knows both absolute paths (the venv
python it just reported and the server file it just copied), so let it fill them in. Point it at
@@ -381,7 +381,7 @@ That's the entire client/server loop, end to end, with zero code you wrote. Now
`... .venv/bin/python -c "import mcp"` check from the note above against the *exact* path in
`"command"`, then check the tool's MCP logs.
### Part D Watch the AI use its new hands
### Part D: Watch the AI use its new hands
5. In the AI chat, **don't** mention files or `tasks.json`. Ask in terms of the *system*:
@@ -411,8 +411,8 @@ That's the entire client/server loop, end to end, with zero code you wrote. Now
history. No copy-paste, no script you ran by hand, no pasting `tasks.json` into a chat. That's
"hands."
7. (Optional, to feel the discovery point.) Edit the docstring on `add_task` to be vague change it
to just `"""Adds something."""` reload, and try the same request. Notice the AI gets *less*
7. (Optional, to feel the discovery point.) Edit the docstring on `add_task` to be vague; change it
to just `"""Adds something."""`, reload, and try the same request. Notice the AI gets *less*
reliable about choosing the tool. The description is part of the interface; the model reads it to
decide. Restore the good docstring.
@@ -1,22 +1,22 @@
"""A tiny MCP server that gives an AI client hands on the tasks-app.
It exposes the tasks-app over the Model Context Protocol (MCP) so an agentic tool can read and
change your real task list directly no copy-paste, no pasting tasks.json into a chat window.
change your real task list directly, with no copy-paste and no pasting tasks.json into a chat window.
The whole server is the decorated functions below. FastMCP (from the official Python SDK) turns
each `@mcp.tool()` function into a tool the AI client can discover and call. That's it a tool is
each `@mcp.tool()` function into a tool the AI client can discover and call. That's it: a tool is
a normal Python function plus a docstring the client reads to know what it does.
Setup (once):
pip install "mcp[cli]"
Drop this file into your tasks-app folder, next to tasks.py and cli.py (it reuses them, and shares
the same tasks.json so a task the AI adds through this server shows up in `python cli.py list`).
the same tasks.json, so a task the AI adds through this server shows up in `python cli.py list`).
Sanity-check that it starts (it will sit waiting for a client to talk to it; Ctrl-C to stop):
python tasks_mcp_server.py
You don't normally run it by hand, though. Your agentic tool launches it for you see the lab.
You don't normally run it by hand, though. Your agentic tool launches it for you; see the lab.
"""
import json
@@ -60,6 +60,6 @@ def add_task(title: str) -> str:
if __name__ == "__main__":
# stdio transport by default: the client launches this process and talks to it over
# stdin/stdout. That's why the server "just sits there" when you run it by hand it's
# stdin/stdout. That's why the server "just sits there" when you run it by hand: it's
# waiting for a client on the other end of the pipe.
mcp.run()