Skip to main content
Glama

mcp-skill-demo

An MCP server and a Skill working together in Claude Code: Claude reads a real GitHub pull request, reviews it against a fixed checklist, and can post its findings back as review comments — no diff pasted in by hand, no manual copy-paste in either direction.

main is always clean and safe. make-demo-pr.sh opens a fresh branch and PR that introduces a real bug, so there's always a live, unmerged PR to review instead of a permanent fixture baked into the default branch.


What's actually going on here

Two pieces, doing two different jobs:

  • An MCP server — a small program you write and run, that gives Claude a live connection to something outside the chat (here: GitHub). Without it, Claude only knows what you paste in.

  • A Skill (SKILL.md) — the checklist. It tells Claude what to look for and when to use the connection, so "review this PR" means the same thing every time, not whatever you happen to type that day.

flowchart LR
    GH[("GitHub<br/>a PR · CI checks")]
    MCP["pr-github MCP server<br/><i>your code, 3 tools</i>"]
    C["Claude Code<br/><i>the session</i>"]
    SK["pr-review Skill<br/><i>the checklist</i>"]

    GH -- "diff · CI status" --> MCP
    MCP -- "get_pr_diff / get_pr_checks" --> C
    C -- "post_review_comment" --> MCP
    MCP -- "review comments" --> GH
    SK -. "loaded on /pr-review" .-> C

The MCP server never decides what's wrong with the code — it just fetches and posts. The Skill never touches GitHub directly — it just reasons. Neither one does the whole job alone.

Related MCP server: PR Reviewer MCP Server

Where the two files actually live

.mcp.json                        <- Claude Code reads this on startup;
                                     declares & launches the MCP server
mcp-server/server.py             <- the server: 3 tools, stdio transport
mcp-server/github_tools.py       <- the GitHub REST calls those tools use
.claude/skills/pr-review/SKILL.md <- auto-discovered; registers /pr-review

.mcp.json says what's available (spawns server.py, gets back get_pr_diff / get_pr_checks / post_review_comment). SKILL.md says what to do with it (the checklist, run when you type /pr-review). They never talk to each other directly — they meet inside Claude's own reasoning.

The bug it finds

./make-demo-pr.sh opens a PR that adds a search_users() endpoint to app.py, building SQL with string concatenation:

sql = "SELECT id, username, is_admin FROM users WHERE username LIKE '%" + query + "%'"

— classic injection — and the PR description quietly defers the missing admin-role check to "a follow-up ticket." Both are exactly the kind of thing that's easy to wave through in a fast review and easy for a checklist to catch every time.

Install Claude Code

Skip this if claude --version already works. Otherwise:

macOS / Linux / WSL — native installer, no Node.js required:

curl -fsSL https://claude.ai/install.sh | bash

macOS alternative, if you prefer Homebrew:

brew install claude-code

Windows — native installer, in PowerShell (no WSL, Node, or npm needed):

irm https://claude.ai/install.ps1 | iex

Either way, confirm it worked:

claude --version

You'll also need Python 3 and git on your PATH — this demo's MCP server is a Python script, and you'll be cloning the repo below.

Set up

git clone https://github.com/Roli24/mcp-skill-demo && cd mcp-skill-demo

cd mcp-server && python3 -m venv venv && source venv/bin/activate
pip install -r requirements.txt && cd ..

Generate a fine-grained GitHub PAT (Settings → Developer settings → Personal access tokens → Fine-grained), scoped to just this repo, with Contents: Read and Pull requests: Read and write. .mcp.json expands it from your shell at launch — the literal token is never written to disk:

export GH_PAT="your-fine-grained-github-pat"

Open a fresh demo PR (requires gh auth login once, if you haven't):

./make-demo-pr.sh   # prints the PR number, e.g. #4

Run it

claude   # approve the pr-github MCP server when prompted

Inside the session:

what's the status of PR #<N> in Roli24/mcp-skill-demo — show me the diff and any CI checks
/pr-review PR #<N>
/pr-review PR #<N> --comment   # posts findings back to the PR

claude mcp list confirms pr-github is connected with exactly 3 tools. The first command shows Claude pulling live context via get_pr_diff / get_pr_checks; /pr-review runs the skill's checklist against that diff and reports the SQL injection and missing auth check; --comment calls post_review_comment to post the findings back to the PR itself.

Cleanup

claude mcp remove pr-github          # revoke the local MCP registration
gh pr close <N> --delete-branch      # close the demo PR, delete its branch
git checkout main

Then revoke the fine-grained PAT you generated above (GitHub → Settings → Developer settings).

Why bother wiring this up

  • Live grounding, not copy-paste — Claude reads the real diff and CI status. Nothing pasted by hand, nothing goes stale mid-review.

  • A repeatable checklist — the Skill runs the same correctness/ security pass every time, not a fresh ad hoc prompt.

  • You control the blast radius — three tools, not GitHub's whole API. A bug in the Skill can't reach further than that.

  • The loop closes — the same server that pulled the PR in posts findings back as inline comments. Starts and ends on GitHub.

  • Your token never leaves your machine — no hosted MCP endpoint, no third party ever sees it.

Where it actually falls short

  • A credential still has to live somewhere — your shell env, in this case. It needs scoping and rotation like any secret.

  • Cost and latency scale per call — fine for reviewing one PR, not a drop-in replacement for a CI bot reviewing hundreds.

  • First pass, not sign-off — it can miss a real bug or flag a fine line as risky. A human still holds the merge button.

  • Only works where Claude Code runs — it's a local subprocess, so it needs a machine with Python and this repo checked out.

  • More moving parts than a plain prompt — worth it for a repeatable workflow, overkill for a one-off question.

Repo layout

app.py, test_app.py             the demo API -- safe on main, always
make-demo-pr.sh                 opens a fresh PR that adds the bug
.claude/skills/pr-review/       the Skill
mcp-server/github_tools.py      GitHub REST logic
mcp-server/server.py            the MCP server (stdio transport)
.mcp.json                       declarative registration, committed

Related MCP Connectors

Related MCP Servers