mcp-lab

mcp-lab

A teaching server for the Model Context Protocol with a local dashboard that visualizes JSON-RPC messages in transit.

Category
访问服务器

README

mcp-lab

CI E2E License: MIT Python 3.13 Checked with ruff

Learn the Model Context Protocol by reading a working server, then watching the protocol happen in your browser.

MCP's problem as a learning subject is that it's invisible: things work, and you never see why. This repository fixes that from two directions.

  1. A teaching server built on the official Python SDK (mcp 1.x, FastMCP) — every MCP primitive exactly once, heavily commented, meant to be read. The domain is a notes store, chosen because tools, resources, and prompts each have an obvious distinct role in it.
  2. A local dashboard that connects to real MCP servers as a real client, runs guided lessons against them, and shows you the actual JSON-RPC frames in transit — not a reconstruction.

[!NOTE] The comments are the product. This is a repository to read, not a library to depend on. If you only open one file, open src/notes_server/server.py.

Quick start

Needs uv and Python 3.13. Docker is optional — you only need it for the Postgres server.

git clone https://github.com/nikhilpatil79/mcp.git
cd mcp
uv sync --group dev
uv run pytest -q          # all green, no Docker or network needed

Then generate your local credentials (this writes .env with fresh random passwords on first run):

./scripts/setup-env.sh              # macOS / Linux
.\scripts\setup-env.ps1             # Windows

And start it:

docker compose up -d --wait    # 1. Postgres
uv run mcp-lab-ui              # 2. dashboard + UI  → http://127.0.0.1:8765

Or one command: ./scripts/start-ui.sh (.\scripts\start-ui.ps1 on Windows).

It's an ordinary local web app — no Claude account, no login, no browser extension. Any browser opens it. There is no separate backend: mcp-lab-ui serves the API and the page, and launches the MCP servers as child processes.

Full walkthrough, how to verify each layer, and what to do when something breaks: docs/RUNNING.md.

The dashboard

/ — guided walkthroughs (start here)

Four short lessons. Each runs real calls against the servers on your machine and narrates what happened in plain English, one step at a time:

  1. What is a tool? — Claude discovers what a server offers, then uses one
  2. Tools vs resources vs prompts — the one distinction that matters: who decides to use it
  3. What happens when something goes wrong — why a failed tool isn't a crash
  4. Talking to a real database — a real SQL query, then a refused DELETE

Every step shows the plain-English explanation first, the result second, and the raw JSON-RPC messages last — behind a "show the actual messages" toggle. That ordering is deliberate: a protocol log only teaches you something once you already know what you're looking at.

Lesson 4 surfaces something genuinely worth knowing — servers don't agree on how to report a refusal. The notes server raises, so the protocol's isError flag gets set. postgres-mcp returns a normal result with an error message in the text. The UI labels each case distinctly rather than flattening them.

/pipeline — what CI/CD runs, and where Claude sits in it

The four CI stages, each with a run it now button that executes the local equivalent so you can watch it pass or fail — then the two Claude Code jobs, side by side, showing what each one does and what it cannot do.

The flags, triggers and permissions on that page are parsed out of .github/workflows/*.yml when you load it, so the page can't drift from the YAML. The commentary is hand-written, because parsing never produces an explanation.

/wire — the raw protocol dashboard

For once you know what you're looking at: every capability across all servers, an inspector to invoke anything, and a live JSON-RPC frame log.

The wire log is not a reconstruction. hub.py::_tap inserts a pair of memory streams between stdio_client and ClientSession and pumps messages across, logging each SessionMessage in transit — so you read the literal frame:

{ "method": "tools/call",
  "params": { "name": "search_notes", "arguments": { "query": "mcp" } },
  "jsonrpc": "2.0", "id": 7 }

[!WARNING] The dashboard is unauthenticated and can invoke every tool on every connected server, including the Docker write tools. It binds to 127.0.0.1 deliberately — don't put it on a network interface. The .claude/settings.json allowlist governs Claude Code, not this UI. See SECURITY.md.

The connected servers

Server What Access
notes The teaching server in src/ Read-write (local file)
postgres Postgres MCP Pro → local postgres:17 container Read-only, two enforced layers
github Official GitHub server Read-only, needs a PAT
docker mcp-server-docker, 19 tools Read + write ⚠️

The GitHub server is optional — leave the token unset and it reports as skipped rather than failing. Full setup, security model, and troubleshooting: docs/SERVERS.md.

docker compose up -d --wait                 # start Postgres
./scripts/setup-env.sh                      # or .\scripts\setup-env.ps1
uv run python scripts/drive_servers.py      # smoke-test all four
# then FULLY restart Claude Code, and check /mcp

drive_servers.py connects to each server as a real MCP client and exercises it, so you get the actual error instead of /mcp's connected/failed. It's also wrapped as a project skill (.claude/skills/run-mcp-servers/) — just ask Claude to run the MCP servers.

Permissions

.claude/settings.json pre-approves the read-only tools (all 9 Postgres, the 5 Docker list_*/fetch_*) and forces a prompt on the 14 Docker write tools and delete_note. The Docker server has no read-only mode, so this allowlist is the control — see docs/SERVERS.md.

Use it from Claude Code

.mcp.json is already wired up. Open this project in Claude Code, approve the servers when prompted, then:

> what MCP tools do you have available?
> save a note titled "MCP basics" saying MCP is JSON-RPC with agreed nouns, tag it mcp
> what have I written about mcp?

Check connection status any time with /mcp.

Poke at it in the Inspector

The fastest way to build intuition — a web UI that speaks the protocol, so you can list tools, call them, and read resources by hand:

uv run mcp dev src/notes_server/server.py

What's in the server

Tools (model-controlled — Claude decides to call these)

  • add_note — the minimal case; shows how docstring and type hints become the schema
  • search_notes — structured output via a pydantic model, plus readOnlyHint
  • delete_note — destructive annotations, and raising to signal failure
  • retag_notes — Context injection for progress reporting and logging

Resources (application-controlled — the app loads these into context)

  • notes://stats — a static resource
  • notes://note/{note_id} — a resource template: one declaration, many URIs

Prompts (user-controlled — surface as slash commands)

  • summarise_tag — the simple single-string form
  • weekly_review — multi-message scaffolding

Subagents

Two, in .claude/agents/:

  • mcp-explainer — answers MCP concept questions from this repo's own code and docs. Read-only tools; grounded answers with file:line citations.
  • notes-librarian — operates the notes store through the MCP server. Its allowlist includes search/add/retag but deliberately excludes delete_note — destructive operations stay with the main agent where you can confirm them.

That exclusion is the point worth noticing: MCP tool annotations (destructiveHint) are an advisory hint to the client, while a subagent's tools: allowlist is actual enforcement. docs/CONCEPTS.md § Part 2 covers the distinction.

CI/CD

.github/workflows/ holds a working pipeline, written to be read:

Workflow Runs when Does
ci.yml every push and PR lint → protocol tests (Ubuntu + Windows) → live MCP servers against real Postgres → build
e2e.yml nightly boots the whole stack, runs every dashboard lesson, checks each behaved as advertised
release.yml you push a v* tag re-verifies the tag, publishes the wheel, pushes the Postgres image to GHCR
claude.yml someone types @claude Claude Code as a job, interactive mode
claude-review.yml a PR opens Claude Code as a job, automation mode, read-only

The integration job asserts the read-only Postgres boundary with a grep — a security control nobody tests is one you're only hoping about.

docs/CICD.md explains all of it: the CI/CD split, how to test an MCP server properly, the three kinds of credential in a pipeline, and what changes about Claude Code's permission model when there's no human to approve a tool call.

What to read, in order

File What it teaches
src/notes_server/server.py Start here. All three primitives, one numbered section each, with the reasoning inline
docs/CONCEPTS.md The prose companion — architecture, message flow, primitive selection, and subagents
docs/CICD.md The pipeline — CI/CD concepts, testing MCP servers, and running Claude Code as a job
tests/test_server.py The same server seen from the client side — what the model actually receives
src/mcp_lab_ui/hub.py How to be an MCP client, and how to tap the wire
src/notes_server/store.py Plain storage, no MCP. Separate on purpose: an MCP server is a thin wrapper over capabilities you already have

Layout

src/notes_server/
  server.py     ← the annotated reference implementation
  store.py      ← plain JSON-backed storage, no MCP
  __main__.py   ← `python -m notes_server`
src/mcp_lab_ui/
  app.py        ← Starlette routes; thin adapters over Hub
  hub.py        ← one live MCP session per server, and the wire tap
  lessons.py    ← the guided lessons, and how a refusal is classified
  pipeline.py   ← parses .github/workflows/ so the page can't drift
  static/       ← learn.html, index.html, pipeline.html
tests/          ← protocol tests, store, hub, pipeline and route tests
docs/
  CONCEPTS.md   ← MCP concepts + subagents, explained
  SERVERS.md    ← the four connected servers, setup and security model
  RUNNING.md    ← starting and stopping it by hand
  CICD.md       ← the pipeline, and Claude Code running as a job
infra/postgres/init/
  01-schema.sql        ← seeded demo database
  02-readonly-role.sql ← the mcp_ro role the Postgres server logs in as
scripts/
  setup-env.{ps1,sh}   ← generate .env, sync secrets into the environment
  start-ui.{ps1,sh}    ← Postgres + dashboard in one command
  drive_servers.py     ← smoke-test every server in .mcp.json as a real client
  check_dashboard.py   ← run every lesson, assert each behaved as advertised
.github/
  dependabot.yml       ← grouped weekly updates for actions and dependencies
  workflows/           ← ci, nightly e2e, release, and two Claude Code jobs
  ISSUE_TEMPLATE/      ← bug report and unclear-explanation forms
.claude/
  settings.json                    ← permission allowlist (read vs write tools)
  agents/                          ← mcp-explainer, notes-librarian
  skills/run-mcp-servers/SKILL.md  ← how to run and debug the servers
CLAUDE.md            ← guidance for Claude Code working in this repo
docker-compose.yml   ← local Postgres
.mcp.json            ← registers all four servers with Claude Code
.env.example         ← credential template; .env itself is gitignored

Notes persist to notes.json at the project root; override with the NOTES_DB_PATH environment variable.

Contributing

See CONTRIBUTING.md. The review bar has one unusual item on it: because the comments are the product, a change that improves the code but degrades the explanation is a regression.

License

MIT.

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选