Skip to content

Add MCP client quickstart guides and sample app - #4400

Open
sahandilshan wants to merge 2 commits into
thunder-id:mainfrom
sahandilshan:docs/mcp-quickstart
Open

Add MCP client quickstart guides and sample app#4400
sahandilshan wants to merge 2 commits into
thunder-id:mainfrom
sahandilshan:docs/mcp-quickstart

Conversation

@sahandilshan

@sahandilshan sahandilshan commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Add Connect an MCP Client page: step-by-step guides for connecting MCP Inspector and Claude Code (via DCR) to a ThunderID-secured MCP server.
  • Add Build an MCP Client page: build a Python FastMCP OAuth client from scratch, with persistent token storage and pinned callback port.
  • Add Calculator MCP sample (samples/apps/mcp-calculator-sample/): runnable server and client code matching the guides, with PEP 723 inline metadata for zero-install uv run.
  • Update the existing Secure Your MCP Server page (python.mdx): add sample code link, What's Next card, fix sign-in wording and Inspector UI labels.
  • Register both new pages in the sidebar.

All doc claims were verified against a live ThunderID + Calculator MCP server stack. make build_docs passes. Vale is clean.

Test plan

  • make build_docs passes with no new broken-anchor warnings
  • Sidebar renders both new pages after the Python entry in the MCP category
  • connect-a-client.mdx: follow the Inspector path end to end (requires a registered app from the server guide)
  • connect-a-client.mdx: follow the Claude Code path end to end (requires DCR enabled)
  • build-a-client.mdx: uv run client.py completes the OAuth flow and prints tool results
  • python.mdx: sample code tip and What's Next card render correctly

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added MCP quickstarts for securing Python servers and building OAuth-authenticated clients.
    • Added guides for connecting MCP Inspector and Claude Code to protected MCP servers.
    • Added a complete calculator MCP server and client sample with scope-based authorization.
    • MCP quickstarts are now available from the developer shortcuts.
  • Documentation

    • Reorganized MCP documentation into Server and Client sections with improved navigation.

@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds MCP server and client quickstarts, restructures MCP documentation navigation, activates MCP developer shortcuts, and introduces an OAuth-authenticated calculator server/client sample with scope-protected tools.

Changes

MCP quickstarts and calculator sample

Layer / File(s) Summary
Secure MCP server and scope-protected tools
samples/apps/mcp-calculator-sample/server/*, docs/content/getting-started/connect-your-mcp/server/*
Adds JWT verification, OAuth resource-server configuration, scoped calculator tools, environment setup, and server protection verification guidance.
OAuth client implementation and sample
samples/apps/mcp-calculator-sample/client/*, samples/apps/mcp-calculator-sample/README.md, docs/content/getting-started/connect-your-mcp/client/build-a-client/*
Adds a FastMCP OAuth client, token caching, calculator sample instructions, DCR setup, and a Python client-building guide.
MCP client connection guides
docs/content/getting-started/connect-your-mcp/client/connect/*
Adds MCP Inspector and Claude Code guides for DCR, TLS configuration, OAuth authentication, and scope enforcement.
MCP documentation navigation and quickstarts
docs/sidebars.ts, docs/src/components/DeveloperShortcut.tsx
Restructures the MCP sidebar and enables MCP quickstarts with Python branding and MCP-specific copy.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant MCPServer
  participant ThunderID
  participant Browser
  Client->>MCPServer: Request protected-resource metadata
  MCPServer-->>Client: Return OAuth metadata and scopes
  Client->>ThunderID: Register client and authorize
  ThunderID->>Browser: Present sign-in
  Browser-->>ThunderID: Return authorization code
  ThunderID-->>Client: Return access token
  Client->>MCPServer: Call scoped calculator tool
  MCPServer-->>Client: Return permitted result
Loading

Possibly related PRs

Suggested reviewers: brionmario, donomalvindula

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description is informative, but it misses most required template sections like Purpose, Approach, Checklist, and Security checks. Rewrite the PR description using the repository template and add Purpose, Approach, Related Issues/PRs, Checklist, and Security checks sections.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly matches the main change: adding MCP client quickstarts and a sample app.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install timed out. The project may have too many dependencies for the sandbox.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (5)
docs/content/getting-started/connect-your-mcp/connect-a-client.mdx (1)

141-142: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use "select" instead of "choose" for UI selection.

-2. Choose the `calculator` server and authenticate.
+2. Select the `calculator` server and authenticate.

As per path instructions: flag "'choose'/'pick' instead of 'select' for UI dropdowns."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/content/getting-started/connect-your-mcp/connect-a-client.mdx` around
lines 141 - 142, Update the UI instruction in the numbered steps to use “select”
instead of “choose” when referring to the calculator server.

Source: Path instructions

samples/apps/mcp-calculator-sample/README.md (1)

13-25: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add a language to the fenced project-structure block.

markdownlint flags this fence for missing a language identifier (MD040).

📝 Proposed fix
-```
+```text
 mcp-calculator-sample/
As per static analysis: markdownlint-cli2 flags "Fenced code blocks should have a language specified" at this line.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@samples/apps/mcp-calculator-sample/README.md` around lines 13 - 25, Add the
text language identifier to the fenced project-structure block in the README,
changing the opening fence to a text-designated fence while preserving the
directory listing unchanged.

Source: Linters/SAST tools

docs/content/getting-started/connect-your-mcp/python.mdx (2)

89-99: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Concept bleed: RBAC/scope mechanics explained inline.

This paragraph explains, in three sentences, how role membership determines which scopes land in a token, an implementation concept, mid-quickstart. Per the doc-quality guideline, quickstarts should link to a concepts page rather than defining this beyond one sentence.

Consider trimming to one sentence with a pointer to a permissions/roles concept page (if one exists), keeping only the actionable instruction here.

As per path instructions: "Flag any page that introduces a concept that belongs on a separate concepts page, mid-way through a quickstart or guide. Quickstarts and guides should link to concepts pages, not define terms inline beyond one sentence."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/content/getting-started/connect-your-mcp/python.mdx` around lines 89 -
99, Trim the introductory paragraph in the role-creation section to one
actionable sentence explaining that the user must hold the calculator
permissions for their token to include the required scopes, and link to the
existing permissions/roles concepts page for further scope and RBAC details.
Keep the six role and assignment steps unchanged.

Source: Path instructions


312-336: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicate "What's Next" card grid across 3 quickstarts. All three pages repeat the same raw inline-style JSX card-grid markup verbatim; a shared MDX component (e.g. <NextStepsGrid items={[...]} />) would remove the duplication and make future style/link updates single-source.

  • docs/content/getting-started/connect-your-mcp/python.mdx#L312-L336: extract this card grid into a shared component, passing the 3 card links as data.
  • docs/content/getting-started/connect-your-mcp/build-a-client.mdx#L151-L166: replace with the same shared component, passing its 2 card links.
  • docs/content/getting-started/connect-your-mcp/connect-a-client.mdx#L160-L175: replace with the same shared component, passing its 2 card links.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/content/getting-started/connect-your-mcp/python.mdx` around lines 312 -
336, Extract the repeated inline-style “What’s Next” card grid into a shared
NextStepsGrid MDX component that accepts card data, preserving each card’s
title, description, link, and ProductName usage. Replace the grids in
docs/content/getting-started/connect-your-mcp/python.mdx lines 312-336,
build-a-client.mdx lines 151-166, and connect-a-client.mdx lines 160-175 with
the shared component, passing three cards for python.mdx and the existing two
cards for each sibling page.
docs/src/components/McpQuickstartFlow.tsx (1)

41-41: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use an Oxygen UI container.

Line 41 can use Box instead of a raw div. Should this use an Oxygen UI component instead of raw HTML?

Proposed fix
+import {Box} from '`@wso2/oxygen-ui`';
+
-    <div className="uc-agent-wayfinder-arch uc-mcp-qs-arch">
+    <Box className="uc-agent-wayfinder-arch uc-mcp-qs-arch">
       <svg>
         ...
       </svg>
-    </div>
+    </Box>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/src/components/McpQuickstartFlow.tsx` at line 41, Replace the raw div in
McpQuickstartFlow with the Oxygen UI Box component while preserving the existing
className and rendered structure.

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/src/components/McpQuickstartFlow.tsx`:
- Around line 42-154: Replace the hand-built SVG inside McpQuickstartFlow with a
Mermaid-based architecture flow diagram, preserving the existing MCP OAuth
participants, interactions, labels, and productName interpolation. Remove the
raw SVG groups, shapes, markers, and text, and use the repository’s established
Mermaid rendering approach if available.

In `@samples/apps/mcp-calculator-sample/client/client.py`:
- Around line 3-23: Replace DiskStore with FileTreeStore in
samples/apps/mcp-calculator-sample/client/client.py, remove the
py-key-value-aio[disk] extra, and configure key and collection sanitization.
Update docs/content/getting-started/connect-your-mcp/build-a-client.mdx lines
67-117 to use FileTreeStore with the same sanitization settings and remove the
[disk] extra from its dependencies and bullets.
- Line 3: Replace the OAuth cache’s DiskStore usage with FastMCP’s recommended
FileTreeStore, updating the OAuth construction and related imports in the client
sample. Remove the py-key-value-aio[disk] dependency from the dependencies
declaration and retain only the dependency needed for FileTreeStore.

---

Nitpick comments:
In `@docs/content/getting-started/connect-your-mcp/connect-a-client.mdx`:
- Around line 141-142: Update the UI instruction in the numbered steps to use
“select” instead of “choose” when referring to the calculator server.

In `@docs/content/getting-started/connect-your-mcp/python.mdx`:
- Around line 89-99: Trim the introductory paragraph in the role-creation
section to one actionable sentence explaining that the user must hold the
calculator permissions for their token to include the required scopes, and link
to the existing permissions/roles concepts page for further scope and RBAC
details. Keep the six role and assignment steps unchanged.
- Around line 312-336: Extract the repeated inline-style “What’s Next” card grid
into a shared NextStepsGrid MDX component that accepts card data, preserving
each card’s title, description, link, and ProductName usage. Replace the grids
in docs/content/getting-started/connect-your-mcp/python.mdx lines 312-336,
build-a-client.mdx lines 151-166, and connect-a-client.mdx lines 160-175 with
the shared component, passing three cards for python.mdx and the existing two
cards for each sibling page.

In `@docs/src/components/McpQuickstartFlow.tsx`:
- Line 41: Replace the raw div in McpQuickstartFlow with the Oxygen UI Box
component while preserving the existing className and rendered structure.

In `@samples/apps/mcp-calculator-sample/README.md`:
- Around line 13-25: Add the text language identifier to the fenced
project-structure block in the README, changing the opening fence to a
text-designated fence while preserving the directory listing unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 0c12d23f-e779-4beb-99cd-75171de95873

📥 Commits

Reviewing files that changed from the base of the PR and between d46470e and b608ceb.

📒 Files selected for processing (16)
  • docs/content/getting-started/connect-your-mcp/_category_.json
  • docs/content/getting-started/connect-your-mcp/build-a-client.mdx
  • docs/content/getting-started/connect-your-mcp/connect-a-client.mdx
  • docs/content/getting-started/connect-your-mcp/python.mdx
  • docs/sidebars.ts
  • docs/src/components/DeveloperShortcut.tsx
  • docs/src/components/McpQuickstartFlow.tsx
  • docs/src/components/WayfinderDiagrams.css
  • docs/src/theme/DocSidebarItem/Category/index.tsx
  • docs/src/theme/DocSidebarItem/Link/index.tsx
  • docs/src/theme/MDXComponents.tsx
  • samples/apps/mcp-calculator-sample/.gitignore
  • samples/apps/mcp-calculator-sample/README.md
  • samples/apps/mcp-calculator-sample/client/client.py
  • samples/apps/mcp-calculator-sample/server/.env.example
  • samples/apps/mcp-calculator-sample/server/server.py

Comment on lines +42 to +154
<svg
className="uc-agent-wayfinder-arch__svg"
viewBox="0 0 820 330"
xmlns="http://www.w3.org/2000/svg"
role="img"
aria-label={`MCP OAuth flow: an MCP client discovers ${productName} as the authorization server through RFC 9728 metadata, obtains a scoped JWT via Authorization Code with PKCE, then calls MCP tools with the token. The MCP server validates the JWT offline against ${productName}'s JWKS endpoint.`}
>
<defs>
<marker
id="mcp-qs-arrow"
viewBox="0 0 10 10"
refX="9"
refY="5"
markerWidth="6"
markerHeight="6"
orient="auto-start-reverse"
>
<path d="M0,0 L10,5 L0,10 z" fill="currentColor" />
</marker>
</defs>

{/* User at top */}
<g className="uc-agent-wayfinder-arch__consumers">
<text x="170" y="12" textAnchor="middle" className="uc-agent-wayfinder-arch__group-label">
User
</text>
<g transform="translate(156,20)">
<g transform="scale(0.5)">
<PersonIcon className="uc-agent-wayfinder-arch__icon" />
</g>
</g>
</g>

{/* User → MCP Client */}
<g className="uc-agent-wayfinder-arch__edges">
<line x1="170" y1="52" x2="170" y2="76" markerEnd="url(#mcp-qs-arrow)" />
</g>

{/* MCP Client */}
<g className="uc-agent-wayfinder-arch__app" transform="translate(20,76)">
<rect width="300" height="88" rx="10" />
<text x="150" y="30" textAnchor="middle" className="uc-agent-wayfinder-arch__app-title">
MCP Client
</text>
<text x="150" y="50" textAnchor="middle" className="uc-agent-wayfinder-arch__sub">
e.g., Claude Desktop, MCP Inspector
</text>
<line x1="24" y1="62" x2="276" y2="62" className="uc-agent-wayfinder-arch__divider" />
<text x="150" y="79" textAnchor="middle" className="uc-agent-wayfinder-arch__detail">
Discovers auth, signs in, calls tools
</text>
</g>

{/* ThunderID — tall box on the right */}
<g className="uc-agent-wayfinder-arch__idp" transform="translate(560,76)">
<rect width="220" height="240" rx="10" />
<text x="110" y="42" textAnchor="middle" className="uc-agent-wayfinder-arch__idp-title">
{productName}
</text>
<text x="110" y="64" textAnchor="middle" className="uc-agent-wayfinder-arch__sub">
Authorization Server
</text>
<line x1="26" y1="78" x2="194" y2="78" className="uc-agent-wayfinder-arch__divider" />
<text x="110" y="104" textAnchor="middle" className="uc-agent-wayfinder-arch__detail">
Signs users in and
</text>
<text x="110" y="122" textAnchor="middle" className="uc-agent-wayfinder-arch__detail">
issues scoped JWTs
</text>
</g>

{/* Your MCP Server — bottom left */}
<g className="uc-agent-wayfinder-arch__svc" transform="translate(20,228)">
<rect width="300" height="88" rx="10" />
<text x="150" y="30" textAnchor="middle" className="uc-agent-wayfinder-arch__app-title">
Your MCP Server
</text>
<text x="150" y="50" textAnchor="middle" className="uc-agent-wayfinder-arch__sub">
OAuth 2.0 Resource Server
</text>
<line x1="24" y1="62" x2="276" y2="62" className="uc-agent-wayfinder-arch__divider" />
<text x="150" y="79" textAnchor="middle" className="uc-agent-wayfinder-arch__detail">
Publishes RFC 9728 metadata, validates JWTs
</text>
</g>

{/* Edges */}
<g className="uc-agent-wayfinder-arch__edges">
{/* MCP Client → ThunderID: Sign in */}
<line x1="320" y1="110" x2="560" y2="110" markerEnd="url(#mcp-qs-arrow)" />
<text x="440" y="102" textAnchor="middle" className="uc-agent-wayfinder-arch__edge-label">
Sign in (Auth Code + PKCE)
</text>

{/* ThunderID → MCP Client: Token */}
<line x1="560" y1="136" x2="320" y2="136" markerEnd="url(#mcp-qs-arrow)" />
<text x="440" y="152" textAnchor="middle" className="uc-agent-wayfinder-arch__edge-label">
Scoped access token (JWT)
</text>

{/* MCP Client → Your MCP Server: Call tools */}
<line x1="170" y1="164" x2="170" y2="228" markerEnd="url(#mcp-qs-arrow)" />
<text x="184" y="200" className="uc-agent-wayfinder-arch__edge-label">
Call tools with token
</text>

{/* Your MCP Server → ThunderID: Validate */}
<line x1="320" y1="272" x2="560" y2="272" markerEnd="url(#mcp-qs-arrow)" />
<text x="440" y="264" textAnchor="middle" className="uc-agent-wayfinder-arch__edge-label">
Validate JWT via JWKS
</text>
</g>
</svg>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟠 Major | 🏗️ Heavy lift

Replace the hand-built architecture SVG with Mermaid.

This is an architecture-flow diagram assembled from raw SVG elements. Should this diagram use Mermaid instead of raw SVG?

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/src/components/McpQuickstartFlow.tsx` around lines 42 - 154, Replace the
hand-built SVG inside McpQuickstartFlow with a Mermaid-based architecture flow
diagram, preserving the existing MCP OAuth participants, interactions, labels,
and productName interpolation. Remove the raw SVG groups, shapes, markers, and
text, and use the repository’s established Mermaid rendering approach if
available.

Source: Path instructions

@@ -0,0 +1,39 @@
# /// script
# requires-python = ">=3.11"
# dependencies = ["fastmcp>=3.4,<4", "py-key-value-aio[disk]"]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

FastMCP FileTreeStore constructor signature py-key-value-aio filetree

💡 Result:

The FileTreeStore constructor is provided by the py-key-value-aio library, which powers storage backends for FastMCP [1]. The constructor signature is as follows [2]: init( *, data_directory, metadata_directory=None, default_collection=None, serialization_adapter=None, key_sanitization_strategy=None, collection_sanitization_strategy=None, auto_create=True,) Parameters: - data_directory (Path | str): The required base directory where the store will save data [2]. - metadata_directory (Path | str | None): Optional directory for metadata; defaults to None [2]. - default_collection (str | None): An optional default collection; defaults to None [2]. - serialization_adapter (SerializationAdapter | None): Optional adapter for data serialization; defaults to None [2]. - key_sanitization_strategy (SanitizationStrategy | None): Optional strategy to sanitize keys to prevent filesystem errors (highly recommended for production) [3][2]. - collection_sanitization_strategy (SanitizationStrategy | None): Optional strategy to sanitize collection names [3][2]. - auto_create (bool): Whether to automatically create the data directory; defaults to True [2]. When using FileTreeStore within FastMCP, it is common practice to provide explicit sanitization strategies (such as FileTreeV1KeySanitizationStrategy and FileTreeV1CollectionSanitizationStrategy) to ensure that keys containing special characters—often found in URLs or OAuth client IDs—do not cause FileNotFoundError crashes on the filesystem [3][4][5].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== repository file =="
wc -l samples/apps/mcp-calculator-sample/client/client.py || true
sed -n '1,80p' samples/apps/mcp-calculator-sample/client/client.py || true

echo "== nearby references to py-key-value-aio and DiskStore/FileTreeStore =="
rg -n "py-key-value-aio|DiskStore|FileTreeStore|token_storage|diskcache|CVE|pickle|storage" samples/apps/mcp-calculator-sample -S || true

echo "== package pin/version declarations mentioning py-key-value-aio or fastmcp =="
rg -n "py-key-value-aio|fastmcp" pyproject.toml poetry.lock uv.lock requirements*.txt samples -S || true

echo "== git status/stat =="
git status --short || true
git diff --stat || true
git diff HEAD samples/apps/mcp-calculator-sample/client/client.py | sed -n '1,180p' || true

Repository: thunder-id/thunderid

Length of output: 2029


🌐 Web query:

CVE-2025-69872 diskcache pickle RCE FastMCP FileTreeStore DiskStore

💡 Result:

CVE-2025-69872 is a security vulnerability in the diskcache library (up to version 5.6.3) involving unsafe deserialization of untrusted data [1][2]. Because diskcache uses Python's pickle module by default to serialize and store data, an attacker with write access to the cache directory can inject a malicious pickle payload [3][4]. When the application performs a standard read operation (e.g., cache.get()), the pickle.load() function triggers, potentially leading to arbitrary code execution (RCE) within the context of the application process [4]. Impact on FastMCP: FastMCP previously utilized diskcache via the py-key-value-aio[disk] dependency for its default OAuth client storage (DiskStore) [5][6]. Due to this vulnerability, FastMCP has taken the following actions [5][7]: 1. Default Storage Change: The default OAuth client storage backend has been migrated from DiskStore to FileTreeStore [5][7]. FileTreeStore uses JSON serialization instead of pickle, eliminating the RCE risk associated with diskcache [5]. 2. Dependency Removal: FastMCP has removed diskcache as a default dependency to resolve security scanner alerts and blockages in security-conscious deployment pipelines [5][6][8]. 3. User Impact: - Users relying on default storage will experience an automatic re-registration of OAuth clients upon their first connection after upgrading [7][9]. - If a project explicitly requires DiskStore, it can still be used by manually installing pip install 'py-key-value-aio[disk]', though this re-introduces the vulnerable diskcache package into the environment [7][10][9]. - When migrating to FileTreeStore, developers are required to configure key and collection sanitization strategies to prevent filesystem errors caused by special characters in keys (e.g., URL-based OAuth client IDs) [7][9].

Citations:


Move this OAuth cache off DiskStore.

This sample installs py-key-value-aio[disk] and passes DiskStore directly to OAuth(...), which pulls in diskcache and re-enables the pickle-deserialization RCE path identified as CVE-2025-69872. FastMCP’s current guidance is to use FileTreeStore instead, which does not require py-key-value-aio[disk].

Also applies to lines 12 and 19-23.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@samples/apps/mcp-calculator-sample/client/client.py` at line 3, Replace the
OAuth cache’s DiskStore usage with FastMCP’s recommended FileTreeStore, updating
the OAuth construction and related imports in the client sample. Remove the
py-key-value-aio[disk] dependency from the dependencies declaration and retain
only the dependency needed for FileTreeStore.

Comment on lines +3 to +23
# dependencies = ["fastmcp>=3.4,<4", "py-key-value-aio[disk]"]
# ///
"""OAuth-authenticated client for the Calculator MCP server."""

import asyncio
from pathlib import Path

from fastmcp import Client
from fastmcp.client.auth import OAuth
from key_value.aio.stores.disk import DiskStore

MCP_URL = "http://localhost:8000/mcp"
THUNDERID_CA_CERT = "../server/thunderid.cert"
TOKEN_CACHE_DIR = Path(__file__).parent / ".mcp-oauth-cache"
CALLBACK_PORT = 52360

oauth = OAuth(
mcp_url=MCP_URL,
token_storage=DiskStore(directory=TOKEN_CACHE_DIR),
callback_port=CALLBACK_PORT,
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== files =="
git ls-files | rg '(^samples/apps/mcp-calculator-sample/client/client\.py$|^docs/content/getting-started/connect-your-mcp/build-a-client\.mdx$|pyproject\.toml|requirements|lock)'

echo
echo "== sample client =="
cat -n samples/apps/mcp-calculator-sample/client/client.py

echo
echo "== docs excerpt =="
sed -n '55,135p' docs/content/getting-started/connect-your-mcp/build-a-client.mdx

echo
echo "== related references =="
rg -n "DiskStore|FileTreeStore|py-key-value-aio|CVE-2025-69872|2025-69872|ThunderID|thunderid" samples/docs content docs -S || true

Repository: thunder-id/thunderid

Length of output: 2029


🌐 Web query:

FastMCP OAuth DiskStore CVE-2025-69872 py-key-value-aio disk

💡 Result:

CVE-2025-69872 is a security vulnerability in the python-diskcache library (versions up to 5.6.3) [1][2][3]. The vulnerability stems from the library's default use of Python's pickle serialization [1][2][4]. If an attacker gains write access to the cache directory, they can manipulate the serialized data to achieve arbitrary code execution when the victim application reads from the cache [1][3]. This issue significantly impacted the FastMCP ecosystem because FastMCP previously depended on py-key-value-aio[disk], which in turn pulled in the vulnerable diskcache package [5][6][7]. Key points regarding the impact and resolution: - Vulnerability Details: CVE-2025-69872 is rated with a high CVSS 3.1 severity (base score 9.8/Critical) [1][3]. It remains an issue for users relying on the affected versions of diskcache [6][7]. - FastMCP Resolution: To address this, FastMCP has moved away from DiskStore as the default OAuth client storage mechanism [8]. In newer versions, the default storage has been changed to FileTreeStore [8]. - Migration Guidance: Users upgrading from earlier versions of FastMCP are advised to transition from DiskStore to FileTreeStore [8]. When using FileTreeStore, it is critical to configure key and collection sanitization strategies to prevent filesystem errors [8]. Users who still require DiskStore can continue to use it by explicitly adding the py-key-value-aio[disk] dependency, though this re-introduces the vulnerable diskcache dependency into their environment [8]. - Security Best Practice: FastMCP documentation consistently emphasizes that for production environments, OAuth token storage must be encrypted using mechanisms such as FernetEncryptionWrapper [9][10][11]. Plaintext storage is considered insecure [10][12].

Citations:


Replace DiskStore with the safer default OAuth storage in the sample and docs. The sample still explicitly uses DiskStore via py-key-value-aio[disk], which reintroduces diskcache’s known pickle RCE risk (CVE-2025-69872). Switch both samples/apps/mcp-calculator-sample/client/client.py and the build-a-client.mdx code/bullets to FileTreeStore with key and collection sanitization, and remove the [disk] extra.

📍 Affects 2 files
  • samples/apps/mcp-calculator-sample/client/client.py#L3-L23 (this comment)
  • docs/content/getting-started/connect-your-mcp/build-a-client.mdx#L67-L117
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@samples/apps/mcp-calculator-sample/client/client.py` around lines 3 - 23,
Replace DiskStore with FileTreeStore in
samples/apps/mcp-calculator-sample/client/client.py, remove the
py-key-value-aio[disk] extra, and configure key and collection sanitization.
Update docs/content/getting-started/connect-your-mcp/build-a-client.mdx lines
67-117 to use FileTreeStore with the same sanitization settings and remove the
[disk] extra from its dependencies and bullets.

Add two new docs pages and a runnable sample:
- connect-a-client.mdx: connect MCP Inspector and Claude Code to the Calculator server
- build-a-client.mdx: build a Python FastMCP OAuth client from scratch
- samples/apps/mcp-calculator-sample/: server + client code matching the guides
- python.mdx: add sample code link and What's Next card, fix sign-in wording

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@sahandilshan
sahandilshan force-pushed the docs/mcp-quickstart branch from b608ceb to 7b1c1da Compare July 28, 2026 10:04
# Conflicts:
#	docs/sidebars.ts
#	docs/src/components/DeveloperShortcut.tsx
@sahandilshan sahandilshan added the skip-changelog Skip generating changelog for a particular PR label Jul 28, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
docs/content/getting-started/connect-your-mcp/server/python.mdx (1)

312-343: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift

Extract the "What's Next" card grid into a shared MDX component.

All four new quickstart pages hand-roll the same raw <div>/<a> card-grid markup with inline style={{...}} props (grid layout, borders, padding, link colors), differing only in title/description/href text. This is significant copy-pasted markup that will drift as pages are added or restyled.

  • docs/content/getting-started/connect-your-mcp/server/python.mdx#L312-L343: replace this grid with a shared <NextSteps>/<NextStepCard title=... description=... href=...> component (or similar) instead of inline-styled <div>/<a>.
  • docs/content/getting-started/connect-your-mcp/client/build-a-client/python.mdx#L151-L173: use the same shared component here.
  • docs/content/getting-started/connect-your-mcp/client/connect/mcp-inspector.mdx#L83-L105: use the same shared component here.
  • docs/content/getting-started/connect-your-mcp/client/connect/claude-code.mdx#L136-L151: use the same shared component here.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/content/getting-started/connect-your-mcp/server/python.mdx` around lines
312 - 343, Extract the repeated “What’s Next” card-grid markup into a shared
NextSteps/NextStepCard MDX component, preserving each card’s existing title,
description, href, and ProductName content. Replace the inline-styled grids in
docs/content/getting-started/connect-your-mcp/server/python.mdx lines 312-343,
docs/content/getting-started/connect-your-mcp/client/build-a-client/python.mdx
lines 151-173,
docs/content/getting-started/connect-your-mcp/client/connect/mcp-inspector.mdx
lines 83-105, and
docs/content/getting-started/connect-your-mcp/client/connect/claude-code.mdx
lines 136-151 with that shared component, and ensure the shared component owns
the common layout and styling.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@docs/content/getting-started/connect-your-mcp/client/connect/mcp-inspector.mdx`:
- Around line 59-61: Update the “Running this from a clone of the repository?”
note in the MCP Inspector documentation to remove the incorrect claim that the
root package.json pins pnpm and causes EBADDEVENGINES. Replace it with the
verified actual cause and accurate workaround, or remove the note entirely if no
applicable repository-clone issue exists.
- Line 84: Update the link in the MCP Inspector page’s Claude Code anchor from
`./claude-code` to `../claude-code` so it resolves to the sibling page in the
parent connect directory.

In `@docs/content/getting-started/connect-your-mcp/server/python.mdx`:
- Around line 45-50: Trim the “How It Works” section in the Python MCP
quickstart by removing the inline OAuth 2.0, PKCE, JWT, and JWKS flow
explanation, then replace it with a brief pointer to the existing “Securing MCP”
concepts page referenced in the “What’s Next” section. Keep the
<McpOAuthFlowDiagram /> only if it remains useful without the removed
explanation.

---

Nitpick comments:
In `@docs/content/getting-started/connect-your-mcp/server/python.mdx`:
- Around line 312-343: Extract the repeated “What’s Next” card-grid markup into
a shared NextSteps/NextStepCard MDX component, preserving each card’s existing
title, description, href, and ProductName content. Replace the inline-styled
grids in docs/content/getting-started/connect-your-mcp/server/python.mdx lines
312-343,
docs/content/getting-started/connect-your-mcp/client/build-a-client/python.mdx
lines 151-173,
docs/content/getting-started/connect-your-mcp/client/connect/mcp-inspector.mdx
lines 83-105, and
docs/content/getting-started/connect-your-mcp/client/connect/claude-code.mdx
lines 136-151 with that shared component, and ensure the shared component owns
the common layout and styling.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: fcec1108-7279-4f52-9d00-f15bdfa77ae8

📥 Commits

Reviewing files that changed from the base of the PR and between b608ceb and de417d0.

📒 Files selected for processing (10)
  • docs/content/getting-started/connect-your-mcp/client/_category_.json
  • docs/content/getting-started/connect-your-mcp/client/build-a-client/_category_.json
  • docs/content/getting-started/connect-your-mcp/client/build-a-client/python.mdx
  • docs/content/getting-started/connect-your-mcp/client/connect/_category_.json
  • docs/content/getting-started/connect-your-mcp/client/connect/claude-code.mdx
  • docs/content/getting-started/connect-your-mcp/client/connect/mcp-inspector.mdx
  • docs/content/getting-started/connect-your-mcp/server/_category_.json
  • docs/content/getting-started/connect-your-mcp/server/python.mdx
  • docs/sidebars.ts
  • docs/src/components/DeveloperShortcut.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • docs/src/components/DeveloperShortcut.tsx

Comment on lines +59 to +61
:::note Running this from a clone of the repository?
If you launch this command from inside a clone of the <ProductName /> repository (for example, from `samples/apps/mcp-calculator-sample/server/`), it fails with `npm error code EBADDEVENGINES`, because npm walks up to the repository's root `package.json`, which pins `pnpm` as the package manager. Launch Inspector from a directory outside the repository instead, and point `NODE_EXTRA_CA_CERTS` at the absolute path of `thunderid.cert`.
:::

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify the repo root package.json pins pnpm as the package manager.
cat package.json | jq '.packageManager, .engines'

Repository: thunder-id/thunderid

Length of output: 168


Fix the EBADDEVENGINES troubleshooting claim

The repository root package.json does not declare packageManager or engines, so npm walking upward to it would not produce the claimed npm error code EBADDEVENGINES based on a pinned pnpm. Update this note to describe the actual cause, or remove it if this does not apply.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@docs/content/getting-started/connect-your-mcp/client/connect/mcp-inspector.mdx`
around lines 59 - 61, Update the “Running this from a clone of the repository?”
note in the MCP Inspector documentation to remove the incorrect claim that the
root package.json pins pnpm and causes EBADDEVENGINES. Replace it with the
verified actual cause and accurate workaround, or remove the note entirely if no
applicable repository-clone issue exists.

## What's Next

<div style={{display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(240px, 1fr))', gap: '1rem', marginTop: '1.5rem'}}>
<a href="./claude-code" style={{textDecoration: 'none', color: 'inherit'}}>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Broken sibling link: ./claude-code should be ../claude-code.

claude-code.mdx is a sibling page in the same connect/ directory. Using ./claude-code resolves to /client/connect/mcp-inspector/claude-code/, which doesn't exist, instead of /client/connect/claude-code/.

Based on learnings: "when linking to a sibling doc within the same directory, use ../sibling-slug (not ./sibling-slug)... Using ./sibling-slug would resolve incorrectly in this URL structure."

🔗 Proposed fix
-  <a href="./claude-code" style={{textDecoration: 'none', color: 'inherit'}}>
+  <a href="../claude-code" style={{textDecoration: 'none', color: 'inherit'}}>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<a href="./claude-code" style={{textDecoration: 'none', color: 'inherit'}}>
<a href="../claude-code" style={{textDecoration: 'none', color: 'inherit'}}>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@docs/content/getting-started/connect-your-mcp/client/connect/mcp-inspector.mdx`
at line 84, Update the link in the MCP Inspector page’s Claude Code anchor from
`./claude-code` to `../claude-code` so it resolves to the sibling page in the
parent connect directory.

Source: Learnings

Comment on lines +45 to +50
## How It Works

Your MCP server becomes an OAuth 2.0 resource server. When a client connects without a token, the server responds with a `401` and RFC 9728 metadata that points the client to <ProductName /> for authentication. The client runs an Authorization Code + PKCE flow, gets a JWT scoped to the user's role-based permissions, and presents it on reconnect. The server validates the token offline against <ProductName />'s JWKS and filters visible tools by the token's scopes.

<McpOAuthFlowDiagram />

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Trim "How It Works" and link to the concepts page instead of explaining OAuth 2.0/PKCE/JWKS inline.

This paragraph defines the OAuth 2.0 resource-server flow, PKCE, and offline JWKS validation from scratch mid-quickstart. The page already links to a dedicated "Securing MCP" concepts page in What's Next (line 329-335) — the concept belongs there, and this section should point to it rather than re-explain it.

As per path instructions: "Flag any page that introduces a concept that belongs on a separate concepts page, mid-way through a quickstart or guide. Quickstarts and guides should link to concepts pages, not define terms inline beyond one sentence."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/content/getting-started/connect-your-mcp/server/python.mdx` around lines
45 - 50, Trim the “How It Works” section in the Python MCP quickstart by
removing the inline OAuth 2.0, PKCE, JWT, and JWKS flow explanation, then
replace it with a brief pointer to the existing “Securing MCP” concepts page
referenced in the “What’s Next” section. Keep the <McpOAuthFlowDiagram /> only
if it remains useful without the removed explanation.

Source: Path instructions

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

skip-changelog Skip generating changelog for a particular PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant