Mcp Sdk Audit logo

Mcp Sdk Audit

CommunityPopular
awdr74100
mcp-sdk-audit

Upgrade @modelcontextprotocol/server (the MCP TypeScript SDK v2) and prove the wire contract survived. The SDK is a runtime dependency whose breakage lands on the wire, not in the type checker — so this sorts each release by which SDK source files it touched (Figwright uses only the server + stdio slice of a client/server/multi-runtime package family), then diffs what a real MCP client observes — negotiated protocol version, every tool JSON Schema, annotations, prompts — before and after the bump. Use whenever the user wants @modelcontextprotocol/server or the other @modelcontextprotocol/* packages updated or audited, asks what a new SDK version changes for the server or its clients, or lands on a Renovate bump PR for that package.

Overview

Publisherawdr74100
Repositoryfigwright
Skill namemcp-sdk-audit
Stars
1.2K
Forks
67
Bundled files
1
LicenseMIT
Links
  • Markdown instructions

    A SKILL.md file the model loads on demand, so it only costs tokens when a request actually matches.

  • Works with any LLM

    AI skills are plain Markdown, not provider-specific code, so this works with GPT, Claude, Gemini, Grok, or a local model.

  • 1 bundled files

    Scripts, templates, and references the model can read while it works. Files are read-only and never executed.

  • Open source

    Published by awdr74100 on GitHub. Read the source before you install it.

Installation

Install the Mcp Sdk Audit AI skill in TypingMind to use it with any LLM, or drop it into another agent that reads SKILL.md.

1

Install in TypingMind

TypingMind installs a skill straight from its GitHub folder — it reads SKILL.md, bundles the resource files, and stores the result locally.

  1. Open the app and go to Plugins → Skills.
  2. Choose "Install from GitHub".
  3. Paste the skill folder URL below and confirm.
    https://github.com/awdr74100/figwright/tree/main/.claude/skills/mcp-sdk-audit
  4. Enable the skill in any chat where you want it available.
Plugins → Skills → Add skill → From GitHub URL, then paste the folder URL and press Continue.
2

Install in another agent

Any agent that reads the Agent Skills format can use this skill — copy the folder into that agent's skills directory.

Claude Code — .claude/skills
git clone --depth 1 https://github.com/awdr74100/figwright.git /tmp/figwright
mkdir -p .claude/skills
cp -r /tmp/figwright/.claude/skills/mcp-sdk-audit .claude/skills/mcp-sdk-audit
Restart Claude Code after copying so it picks up the new skill.

Use it in TypingMind

Enable Mcp Sdk Audit in any TypingMind chat and the model takes it from there. Its name and description sit in the system prompt, and the moment a request matches, the model loads the full instructions itself — you never invoke it by hand, and it costs no tokens until it is actually used.

The model loads Mcp Sdk Audit on its own as soon as a request matches it.

Works with any AI model

AI skills are plain Markdown instructions rather than provider-specific code, so Mcp Sdk Audit is not tied to the model it was written for. Install it once in TypingMind and use it with GPT-5, Claude, Gemini, Grok, DeepSeek, Mistral, Llama, or a local model you run yourself — all on your own API keys.

  • Loaded only when it is needed

    The system prompt carries just the name and description. The instructions are fetched on the first matching request, so an idle skill costs nothing.

  • Switch models mid-chat

    Because the skill is instructions rather than code, changing model does not break it — the next model reads the same SKILL.md.

Skill instructions

This is the SKILL.md content the model loads. Read it before installing — a skill is instructions your model will follow.

Absorbing a @modelcontextprotocol/server release into Figwright, end to end: audit → upgrade → prove the wire contract is unchanged.

Do not reason about this the way figma-typings-audit reasons about plugin typings. That package is types-only, so tsc is a real gate. This one is a runtime dependency: it serializes every tool result, generates the JSON Schema for every tool, and negotiates the protocol version. A release can leave every type identical and still change what clients see. pnpm typecheck will stay green through it.

Unlike every other dependency here, this one has a dedicated gate — use it. packages/mcp/test/e2e/mcp-wire.test.ts spawns the built dist over real stdio, speaks raw JSON-RPC at it, and asserts the advertised contract against what the specs declare. It runs in pnpm test. That gate answers did anything break; it does not answer what moved, which is what an audit is for — Stage 5 covers the difference.

Know the one thing that gate cannot see. Its schema check compares the SDK's output against test/tool-schema.ts's derivation, and both call the same z.toJSONSchema. That is independent of the SDK — it catches an SDK that stops asking Zod the same question — but not of Zod: when Zod changes what it answers, both sides move together and the equality still holds. An SDK bump that also moves the resolved zod version (its range is ^4.2.0, so it shares the repo's copy) can therefore reshape every client's schema with this gate green. packages/mcp/test/json-schema-generation.test.ts covers that half by pinning each construct's rendering by hand — if a bump moves the Zod version, read its diff too, and let probe.mjs name which tools changed.

Target version: whatever the user named, otherwise the latest @modelcontextprotocol/server on npm.

Stage 0 — Resolve versions

bash
grep '@modelcontextprotocol' packages/mcp/package.json          # declared range
grep -m1 '@modelcontextprotocol/server@' pnpm-lock.yaml         # what is installed
npm view @modelcontextprotocol/server version dist-tags --json  # latest
gh api repos/modelcontextprotocol/typescript-sdk/releases --jq '.[0:15][] | "\(.tag_name)\t\(.published_at)"'

Figwright is on v2 — the package family (@modelcontextprotocol/server + its transitive /core, with /client, /node, /express, /hono, /fastify, /server-legacy, /codemod alongside). It depends on exactly one of them.

Two things the releases list will show that are not upgrades for us:

  • Bare 1.30.0-style tags are the v1 legacy line (@modelcontextprotocol/sdk, source on the long-lived v1.x branch). Figwright left it; a v1 tag is not our concern.
  • @modelcontextprotocol/{client,express,fastify,hono,node,server-legacy,codemod}@X tags ship on the same version number as server but are packages we do not install.

If installed and target are equal, say so and stop.

Stage 1 — Read the release notes as an index, not as an answer

The GitHub Releases body is an auto-generated list of PR titles, written for SDK contributors: it says what was changed, never who is affected. "stdio buffer limit" reads like it belongs to whoever runs stdio; the useful question is which package and which directory it landed in.

So use the notes only to get the PR numbers, then ask each PR what it touched:

bash
gh api repos/modelcontextprotocol/typescript-sdk/releases --jq '.[] | select(.tag_name=="@modelcontextprotocol/server@<target>") | .body'
# then, per PR number in that body:
gh pr view <n> --repo modelcontextprotocol/typescript-sdk --json title,files \
  --jq '"\(.title)\n  " + (.files | map(.path) | join("\n  "))'

⚠️ Read the whole file list, never just the first entry. v2 splits one concern across packages by design — a wire change routinely lands in packages/core-internal/src/wire/, packages/server/src/server/, and packages/client/src/ at once. Judging a PR by its first file is how the hunk that mattered gets missed.

Stage 2 — Sort by file path

Figwright imports exactly two entry points (packages/mcp/src/index.ts, src/prompts/*, test/tool-schema.ts, test/e2e/mcp-wire.test.ts): @modelcontextprotocol/server and @modelcontextprotocol/server/stdio. That narrow slice is what makes this audit cheap — most of any given release is about parts of the family this server never loads.

SDK pathBearing on Figwright
packages/server/src/server/mcp.ts, server.tsLoad-bearing. registerTool / registerPrompt / result serialization
packages/server/src/server/serveStdio.ts, stdio.tsLoad-bearing. The entry point and the only transport this server runs
packages/server/src/fromJsonSchema.ts, validators/Load-bearing and invisible. Turns each spec's Zod object into the JSON Schema every client reads
packages/core-internal/src/wire/, types/Load-bearing. Protocol version constants, per-era codecs, CallToolResult, ToolAnnotations
packages/core/src/Schema constants + types. We import types only through server's re-export; watch renames
packages/client/**Not ours — but it is what Claude Code / Cursor run against us, so a client-side limit still bites
packages/server/src/server/streamableHttp.ts, perRequestTransport.ts, createMcpHandler.tsUnused today (stdio only). Relevant only to a future HTTP transport — note, don't act
packages/{express,fastify,hono,node,server-legacy}/**, **/auth/**, examples/**Ignore

The packages/client/** row is the subtle one: a limit added to the client's read path applies to Figwright's responses, since the client is what reads them. get_screenshot returns inline base64 and get_design_context returns large JSON, so client-side ceilings are a real exposure even though Figwright ships no client.

Stage 3 — Cross-check against the published dist

The PR list is a claim about the release; the tarball is the release. Confirm they agree — and catch anything that reached the build without a listed PR:

bash
cd "$SCRATCH" && mkdir -p mcp-sdk-audit && cd mcp-sdk-audit
npm pack @modelcontextprotocol/server@<installed> @modelcontextprotocol/server@<target> \
         @modelcontextprotocol/core@<installed> @modelcontextprotocol/core@<target> \
         --pack-destination .
for p in server core; do for v in <installed> <target>; do
  mkdir -p "$p-$v" && tar -xzf "modelcontextprotocol-$p-$v.tgz" -C "$p-$v" --strip-components=1
done; done

# Partition each tree by CONTENT, not by filename. This one step produces both the
# coverage proof and the list of files that actually have to be read. Do it for core
# too — its chunks are content-hashed the same way.
for p in server core; do for v in <installed> <target>; do
  (cd "$p-$v/dist" && find . -type f ! -name '*.map' -exec shasum -a 256 {} \; \
     | sort -k2 > "../../hash-$p-$v.txt")
done; done
for p in server core; do
  echo "== $p =="
  comm -12 <(sort "hash-$p-<installed>.txt") <(sort "hash-$p-<target>.txt") | wc -l  # identical — the proof
  comm -3  <(sort "hash-$p-<installed>.txt") <(sort "hash-$p-<target>.txt") \
    | awk '{print $NF}' | sort -u                                                   # changed — the read list
done

🔴 Do not stop at diff -ru, and do not trust its file list — the gap it leaves is silent. v2 emits .mjs/.cjs siblings in a flat dist/ with content-hashed chunk names, so a chunk whose hash moved (mcp-DXXb3Vv3.mjs → mcp-Dw2OlZ1f.mjs) appears only as two Only in ... lines and its contents are never compared — while ReadBuffer, Protocol and registerTool all live in those chunks, not in stdio.mjs. The hash partition is what makes the read list complete: pair each changed chunk with its counterpart and diff it by name, explicitly.

bash
diff -u server-<installed>/dist/<old-chunk>.mjs server-<target>/dist/<new-chunk>.mjs

The identical set is a real result, not bookkeeping: a release where ajvProvider-*, dialects-*, validators/ and types-*.d.mts all hash identically has not touched JSON Schema generation by a single byte. That is a static statement, so it is stronger than anything the probe can say.

⚠️ Two rename artifacts that read as false alarms:

  • A long run of - lines in index.mjs can be a whole region relocated into another chunk — the 2.1.0 release moved bearerAuth and oauthMetadata into the mcp chunk, which looks exactly like deleting them until you find the matching + on the other side. Check before calling it a removal.
  • .cjs and .d.cts entries are siblings of the .mjs / .d.mts you already read; read one of each pair, not both.

Within what is left, dist/**/*.d.mts hunks are the type-level surface (what tsc would catch); .mjs hunks with no .d.mts counterpart are the dangerous kind — behavior changed, signature didn't. Comparing the two versions' export { … } lists (names only, aliases stripped) settles whether the public surface lost anything, which the prose of a release note routinely omits.

Also diff package.json between the two versions: engines.node, dependencies (the pinned @modelcontextprotocol/core version and zod's supported range) all move without appearing in the source diff. v2 declares zod as a real dependency, not a peer — a range bump there can nest a second zod copy beside the repo's own.

Stage 4 — Classify

  1. Type-level — a changed export in dist/**/*.d.mts that Figwright names. tsc covers these; confirm in Stage 6 rather than reasoning about them.
  2. ★ Wire behavior — the recurring shapes:
    • the negotiated protocol version (LATEST_PROTOCOL_VERSION, SUPPORTED_PROTOCOL_VERSIONS, FIRST_MODERN_PROTOCOL_VERSION) — moving it changes what every connecting client sees, and dropping an old entry can cut off an older client outright;
    • the JSON Schema generated per tool — one for every tool Figwright registers, they are the LLM's entire spec, and a $ref/allOf/additionalProperties shift has broken third-party clients before (see project_moonshot_ref_immunity);
    • era selection in serveStdio — which revision a given opening exchange lands on;
    • stdio framing and buffering — message size ceilings, chunk handling, error-on-overflow;
    • error and result serialization — what a tool-call rejection looks like to the model.
  3. Dependency / supply chain — engines.node vs the repo's ^20.19.0 || >=22.12.0, the zod range against zod@^4, transitive advisories. Note what pnpm install flags.

Bucket 2 is the whole reason this skill exists. Never claim a bucket-2 item is safe from the diff alone — Stage 5 settles it.

Stage 5 — Run the gate, then diff the delta

Two different questions, two tools. Run both.

The gate — did anything break?

bash
pnpm build && pnpm vitest run packages/mcp/test/e2e/mcp-wire.test.ts

It asserts the advertised tool set, each tool's JSON Schema against a derivation that is independent of the SDK (but not of Zod — see above), the dialect, annotations, prompts, a live tools/call, the bad-argument path, and that a 2024-11-05 client is still served. Red here means the release moved something that matters. If the bump also moved zod, run pnpm vitest run packages/mcp/test/json-schema-generation.test.ts as a second gate.

The probe — what moved? A gate is a boolean; an audit has to name the change. probe.mjs boots the same built server, snapshots everything a client can observe, and diffs two snapshots.

bash
REPO=$(git rev-parse --show-toplevel)
pnpm build                                                   # the probe reads dist, not src
node "$REPO/.claude/skills/mcp-sdk-audit/probe.mjs" "$REPO" "$SCRATCH/mcp-sdk-audit/base.json"
# ...upgrade (Stage 6), pnpm build again, then:
node "$REPO/.claude/skills/mcp-sdk-audit/probe.mjs" "$REPO" "$SCRATCH/mcp-sdk-audit/after.json"
node "$REPO/.claude/skills/mcp-sdk-audit/probe.mjs" --diff "$SCRATCH/mcp-sdk-audit/base.json" "$SCRATCH/mcp-sdk-audit/after.json"

Notes that matter:

  • pnpm build first, every time. The MCP server runs the built dist; probing a stale bundle reports the previous SDK. (A stale dist left behind by an abandoned upgrade is also unrunnable — it imports a package the current node_modules no longer has.)
  • Both the gate and the probe run the server on a random high port via FIGWRIGHT_PORT, so neither contends for 3055 or steals a connected plugin. Neither needs a plugin — ping answers without one.
  • A baseline captured after upgrading is worthless. If the bump already happened (a Renovate branch), take the baseline from main in a git worktree, pnpm install, build, probe, then come back. probe.mjs reads the installed version out of the lockfile, so a v1 baseline needs that one regex pointed at @modelcontextprotocol/sdk@.

Stage 6 — Upgrade and run the gates

bash
pnpm -C packages/mcp add @modelcontextprotocol/server@^<target>
pnpm typecheck && pnpm lint && pnpm format:check && pnpm knip && pnpm build && pnpm test

This and the lockfile are the only writes to the repo; everything before was read-only. All six gates green and an empty probe diff is the pass condition — neither alone is one, though the six now include the wire gate, which is what made them worth trusting.

Stage 7 — Report in 繁體中文台灣用語

Ordered by consequence:

  1. 線上契約有沒有動 — the probe diff: protocol version, tool count, per-tool schema hashes, annotations, prompts. Name the tools that changed, or state plainly that none did.
  2. 會壞掉的 — bucket 1, with the gate verdict.
  3. 要知道但不用動的 — bucket 2/3 items that exist in the release but cannot reach this server (a client-side limit, an HTTP transport fix). Say why it cannot reach us; that reasoning is the deliverable, and it is what makes the next audit cheap.
  4. 新能力 — anything the SDK now exposes that Figwright could use, one line each.

Report only what the diff and the probe showed. Don't pad with plausible-sounding changes, and never claim a verification you didn't run.

Then AskUserQuestion over the items from 3 and 4 that would need work.

Stage 8 — Hand off the live verification

The gate and the probe prove the server speaks correctly to a test harness. They do not prove real clients are happy:

  • The MCP server runs the built dist → pnpm build, then the user reconnects the MCP connection (.mcp.json launches packages/mcp/dist/index.mjs).
  • Ask the user to run one read tool (ping, then something with a real payload like get_design_context) through the reconnected server with the plugin open.
  • If the release touched protocol-version constants or schema generation, that check should ideally happen in more than one client — Claude Code, Cursor, Codex ship different SDK versions (many still on v1), and the failure mode is exactly a version mismatch between the two ends.

Say what was actually run. If the live step didn't happen, say that.

Bundled files

The model reads these on demand while the skill is loaded. They are exposed as readable files and are never executed.

Frequently asked questions

What does the Mcp Sdk Audit AI skill do?

Upgrade @modelcontextprotocol/server (the MCP TypeScript SDK v2) and prove the wire contract survived. The SDK is a runtime dependency whose breakage lands on the wire, not in the type checker — so this sorts each release by which SDK source files it touched (Figwright uses only the server + stdio slice of a client/server/multi-runtime package family), then diffs what a real MCP client observes — negotiated protocol version, every tool JSON Schema, annotations, prompts — before and after the bump. Use whenever the user wants @modelcontextprotocol/server or the other @modelcontextprotocol/*...

Why use Mcp Sdk Audit on TypingMind?

Because you install it once and use it with any model. Mcp Sdk Audit is plain Markdown rather than provider-specific code, so the same skill runs on GPT-5, Claude, Gemini, Grok, or a local model — and you can switch model mid-chat without it breaking. TypingMind runs on your own API keys, so you pay providers directly instead of a per-seat subscription, and your skills and chats stay in your own storage.

How do I install Mcp Sdk Audit in TypingMind?

Open Plugins → Skills → Install from GitHub in TypingMind and paste https://github.com/awdr74100/figwright/tree/main/.claude/skills/mcp-sdk-audit. TypingMind reads its SKILL.md and bundles its files and installs it as a skill you can enable per chat.

Which AI models can use Mcp Sdk Audit?

Any model you connect in TypingMind. AI skills are plain Markdown instructions rather than provider-specific code, so GPT, Claude, Gemini, Grok, and local models can all load this skill when a request matches it.

How many AI models can I use with Mcp Sdk Audit?

As many as you like. As long as a model supports skills, you can use Mcp Sdk Audit with it — GPT, Claude, Gemini, Grok, DeepSeek, Mistral, Llama and more — all on TypingMind with your own API keys.

Is the Mcp Sdk Audit AI skill free?

Yes. It is published on GitHub by awdr74100 under the MIT license. You only pay your own AI provider for the tokens you use.

What are AI skills?

An AI skill is a reusable instruction bundle that teaches an AI model how to do one specific task. It follows the open Agent Skills format: a SKILL.md file with a name and description, plus any scripts, templates or reference files the model may need. The model reads the instructions only when your request matches the skill, so an installed skill costs nothing until it is used.

How are AI skills different from plugins or MCP servers?

A plugin or MCP server gives a model new tools to call — code that runs somewhere and returns a result. An AI skill gives the model knowledge and process instead: how to approach a task, which steps to follow, what good output looks like. Skills are plain Markdown, so they need no server, no API key and no runtime, and they work with any model.

View all

Set up your own AI workspace now

Get notified about new features and future giveaways by subscribing to our newsletter 👇