· about 35 minutes · runs on ubuntu-26.04-claude · unrated
An unrated lab. It runs on your machine with no account and no network, and everything about it — the faults, the checks, the hints and the reference solution — is in the repository. An attempt on it is recorded on your profile and never moves a rating: only rated labs do. Rated and unrated labs.
Every morning ~/bin/support-digest asks Claude Code to summarise the open support tickets. The
tickets come from the team's own MCP server, /opt/tickets/tickets_mcp.py, which the repository
~/support-digest declares in its .mcp.json. The server itself works — the platform team tests
it daily — and it wants the queue's API token in TICKETS_TOKEN. The token lives in
~/.config/support-digest/env, which the job reads.
For a week the digest has said there are no tickets, or that it has no way to see them. Someone
tried to fix it last Friday and committed what they had. The job's JSON result is
~/digest.json.
This lab runs in a container, as learner with sudo. claude here is the real Claude Code
2.1.270, talking to a scripted model on this machine that asks for the ticket list on every run;
Claude Code starts (or fails to start) the MCP server and calls it for real.
What is expected, and graded — the grader runs ~/bin/support-digest itself:
Leave /opt/tickets alone: the server is not the problem.
This lab runs in a container — Docker or Podman, no VM — so there is no boot to survive: the checks run once, against the state you left.
| Check | Objective |
|---|---|
| 01_the_server_starts_for_the_job | Configure a project MCP server that starts for a headless run |
| 02_the_job_may_call_the_tool | Let a job call exactly the MCP tool it needs |
| 03_the_tool_is_authorised | Pass an MCP server its credentials without committing them |
| 04_no_token_in_the_repository | Pass an MCP server its credentials without committing them |
Where the lab's hints send you, level by level, as you ask for them (h, then l opens a journal section in the TUI).
4 questions on the same topic, in the lab's Theory tab. They never affect the lab's grade. Three of them, to answer here:
A project's .mcp.json declares a server named `tickets` with a tool `list_tickets`. What name must a job pass to --allowedTools so that it may call that tool in dontAsk mode?
mcp__tickets__list_tickets (or mcp__tickets for every tool of the server)
Claude Code names MCP tools mcp__<server>__<tool>, with the server name from the configuration. Permission rules and hook matchers use that name; a rule of just the prefix mcp__<server> covers all the server's tools. A misspelled server name in the rule allows nothing, and the call shows up in permission_denials.
https://code.claude.com/docs/en/mcp · https://code.claude.com/docs/en/permissions
.mcp.json passes `"env": {"TICKETS_TOKEN": "${TICKET_TOKEN}"}` to a stdio server, and TICKET_TOKEN is not set in Claude Code's environment. What does the server receive?
The literal text ${TICKET_TOKEN}; claude mcp list warns about a missing variable
${VAR} and ${VAR:-default} are expanded in command, args, env, url and headers. A variable that is unset and has no default stays literal, so the server starts and gets the placeholder text. `claude mcp list` reports "Missing environment variables: TICKET_TOKEN" in its diagnostics. Verified with Claude Code 2.1.270.
https://code.claude.com/docs/en/mcp
A `claude -p` run offers the model no tools from a project MCP server, and the server's command works when run by hand. Which setting would explain it?
"disabledMcpjsonServers": ["tickets"] in a settings file, for example .claude/settings.local.json
disabledMcpjsonServers keeps a named .mcp.json server from loading at all; the stream-json init event then lists no such server. -p loads .mcp.json servers without a trust prompt, so trust is not the reason; enableAllProjectMcpServers approves servers rather than disabling them; and a server that works by hand starts well within 30 seconds.
https://code.claude.com/docs/en/mcp · https://code.claude.com/docs/en/settings