Lab 11 — Environment check and decision memo
Lesson 11 · MCP Servers · ~30 min, no code change
This lesson has no code change. The lab is three things, in order: (a) verify your Node and Docker environment so the next four lessons do not bounce off a missing tool, (b) trace the existing TypeScript skeleton that is already sitting in the repo so you know what L12 is going to extend, and (c) write a one-page decision memo answering the only question this lesson really cares about: would you port your PKB to TypeScript, or is the Python version good enough? Either answer is legitimate. The point is to have the argument with yourself in writing before you spend four lessons learning the TS path.
Prereqs
- Module 4 complete. The Python PKB server at
mcp-servers/sample-server/python/runs locally, exposes 7 tools, and itspkb/tests/suite passes. If anything from L09 or L10 is still flaky, fix it before starting Module 5 — the TS lessons assume the Python half is the working baseline you are comparing against. - Node 20+ and npm 10+ installed. Older Node versions
(18 and below) miss APIs the MCP TypeScript SDK and our Dockerfile rely on.
macOS users on Apple Silicon: the official
nodejs.orgLTS installer ornvm install --ltsboth work; pick whichever fits how you already manage tool versions. - Docker (Engine or Desktop) installed and running. L13 makes Docker the deploy unit; if the daemon is not running on your machine today, this lab catches that now rather than 90 minutes into L13.
Step 1 — Verify Node and Docker
Run all four commands. The expected outputs are below each — exact version numbers will differ, but the major version must match.
node --version # v20.x or v22.x
npm --version # 10.x
docker --version # Docker version 24+ or 25+
docker run --rm hello-world
The docker run --rm hello-world line is the critical one: it confirms
the daemon is actually running and that your user can talk to it, not just
that the CLI is installed. A common failure mode on Linux is "docker is
installed but the daemon is stopped" — that produces a confusing
Cannot connect to the Docker daemon error rather than
command not found.
What to do if one of these fails:
- Node missing or too old. Install Node 20 LTS from
nodejs.orgor, if you already usenvm, runnvm install --lts && nvm use --lts. Re-open your terminal soPATHpicks up the new binary. - Docker missing. macOS / Windows: install Docker Desktop and
launch it once so it starts the daemon. Linux: install Docker Engine via your
package manager and add your user to the
dockergroup (sudo usermod -aG docker $USER; log out and back in). docker run hello-worldtimes out or errors. The daemon is not running or your user is not in thedockergroup. On Linux:sudo systemctl start docker. On macOS/Windows: open Docker Desktop and wait for the whale icon to stop animating.
Step 2 — Locate the TS skeleton
The TypeScript sample-server tree was committed back in Plan A as a stub. Find it and read each file.
cd mcp-servers/sample-server/typescript
ls
Expected output:
package.json
tsconfig.json
src/
Inside src/ you should see server.ts. Open all three files and trace what each is doing:
package.json. Three things to notice. First,"type": "module"— this is ESM-only; CommonJS imports will fail at load time. Second,"@modelcontextprotocol/sdk": "^1.0.0"independencies— the official TS SDK is pinned. Third, thescriptsblock definesnpm run build(which runstscto producedist/) andnpm run dev(which runstsx src/server.tsto execute the source directly without a build step). The build path is for the production Docker image in L13; the dev path is what you use during L12–L15.tsconfig.json. Set to"strict": true,"target": "ES2022","module": "ES2022", with output todist/. Strict mode is on intentionally — the whole point of the TS port is type-checked tool handlers; loosening strict mode here will hide bugs Zod is later supposed to catch at runtime.src/server.ts. Currently a one-line stub that throwsError("pkb (TS) server has no tools yet — start at lesson 12")whenmain()runs. The throw is intentional: it proves the build and runtime are wired (Node can load the module, the SDK import resolves, the entry point is reachable) without pretending the server does anything useful. L12 deletes the throw and replaces it with a realechotool.
Step 3 — Install deps and confirm tsc + tsx work
From inside mcp-servers/sample-server/typescript/:
npm install
npm run build # tsc -> dist/server.js (compiles cleanly even though main() throws)
npm run dev || true # tsx will print the thrown error; that's expected
What to look for:
npm installfinishes without errors and produces anode_modules/directory plus apackage-lock.json. The lock file should be left untouched in your working tree for now — it will get a real commit in L12 when the dep set actually changes.npm run buildproducesdist/server.js.tsccompiles the stub cleanly: a function that throws is still syntactically valid TypeScript. Iftscfails here, yourtsconfig.jsonwas edited or yourtypescriptdev dependency did not install — re-runnpm installand try again.npm run devprints the thrownErrorand exits non-zero. That is the expected outcome — the stub is supposed to throw. The|| truesuffix on the command above prevents your shell from treating the non-zero exit as a script-stopping error. Seeing the message "pkb (TS) server has no tools yet — start at lesson 12" in your terminal confirms the entire runtime stack is wired: Node loads the module, the SDK import resolves,main()is reached and runs. L12 starts by replacing the line that throws.
Step 4 — Write your decision memo
This is the actual deliverable of the lab. One page, four headings, no more than ten minutes of writing. The memo is for you — don't commit it to the repo unless you specifically want to.
- My use-case. One paragraph. Who connects to this server, from where, and how often? "Only me, on my laptop, a few times an hour while drafting" is a complete answer. So is "30 internal users on the company VPN, several times a minute during business hours". The shape of this paragraph predicts the rest of the memo.
- Three reasons I would port to TypeScript. Three bullets. Draw from the slides and theory: smaller / faster container images, SDK transport-feature lead, Node-friendly edge runtimes (Workers, Vercel, Deno Deploy), JS-shop hiring pool. Pick the three that are true for your project, not the three that sound most impressive.
- Three reasons I would stay in Python. Three bullets. Same
discipline: which Python-side wins actually apply to your situation? Personal-only
use? A tool that calls
torchortransformers? A compliance shop that only signs off on Python? A prototype with a one-week lifetime? - My decision. One sentence. "I will port" or "I will stay" are both correct answers. The value of the memo is the forcing function, not the answer.
Step 5 — If you decided to stay in Python
Module 5 still has value for you, but you can skip most of the hands-on work:
- Read the slides for L12–L15. The conceptual content (HTTP+SSE transport, multi-tenant isolation, audit logging, threat-modelling) survives the language choice and is worth knowing.
- Skim the theory pages for the same reason. Pay particular attention to L13 (HTTP transport + Caddy) and L15 (production hardening) — when the time comes to expose your Python PKB to a second user, you will want to have already seen these patterns.
- Skip the L12–L15 labs. They mutate
mcp-servers/sample-server/typescript/; running them is only worth your time if you are committing to the TS path. - Re-join the course at the L15 "what you should leave with" section — that summary works equally well whichever language your real production server ends up in.
Step 6 — If you decided to port
Confirm a few things before you start L12:
- Step 1 fully passed (all four version / hello-world commands worked). If any of them was shaky, fix it now. L12 will not be a good place to debug a missing Node binary or a stopped Docker daemon.
- You can read TypeScript at the level of
asyncfunctions,interfacedeclarations, and ESMimportsyntax. The TS lessons do not re-teach the language. If you can't, take a 30-minute detour through the TypeScript handbook intro before L12. - You have ~45 minutes free for L12. The first port (echo tool + Zod + stdio transport + Inspector smoke test) is meaningfully longer than a typical Python lesson because there are more moving pieces to wire on first contact.
What you should leave with
- A working Node 20+ and Docker environment — verified by
node --version,docker --version, and a successfuldocker run hello-world. - The TS skeleton at your fingertips. You know where
package.json,tsconfig.json, andsrc/server.tslive, you have read each of them, and you know whynpm run devcurrently throws. - A one-page memo recording, for your own use-case, whether you plan to migrate PKB to TypeScript or stay on the Python implementation. Either answer is the right one if you can defend it in three bullets each way.
- An honest answer to "do I belong in the TS lessons or the skip-the-labs reading path?" — so the next four lessons either get your full attention or your skimming time, but not the half-and-half that produces neither learning nor a working server.
Troubleshooting
Common stumbles
- "
tsc: command not found" — you rantscdirectly instead of going throughnpm run build.tscships with the localtypescriptdevDependency, so it is on your project'snode_modules/.bin/, not on the globalPATH. Either runnpm run build(recommended) ornpx tscif you really want a one-off invocation. - "Docker daemon not running." macOS / Windows: open Docker
Desktop and wait for the whale icon to stop animating before re-running the
command. Linux:
sudo systemctl start docker(and considersudo systemctl enable dockerif you want it to start at boot). - "Node 18 is fine, right?" No. The MCP SDK uses APIs that
stabilised in Node 20, and the Dockerfile in L13 targets
node:20-alpine. Upgrade to Node 20 LTS or newer before continuing — running L12–L15 on Node 18 will produce confusing import errors that look like SDK bugs but are runtime mismatches. - "
npm installis slow or hangs." Usually a corporate proxy intercepting the npm registry. Force the public registry withnpm config set registry https://registry.npmjs.org/and try again. If that still hangs, you are on a network that requires a proxy — seenpm config set proxy <url>in the npm docs. - "The
npm run deverror mentions ESM / CJS." Someone editedpackage.jsonand removed"type": "module", or editedtsconfig.jsonand switched the module setting away from ES2022. Restore both and re-run. The TS SDK is ESM-only; CommonJS will not work at any point in Module 5.