From 8bc31360e85b1192e78615f09fc525d57ff5c5f7 Mon Sep 17 00:00:00 2001
From: Jeremiah Lowin <153965+jlowin@users.noreply.github.com>
Date: Mon, 2 Mar 2026 21:09:48 -0500
Subject: [PATCH] Restructure docs navigation: CLI section, Composition, More
(#3361)
* WIP: Move mounting docs to servers/composition, remove deprecated import_server content
* WIP: Add CLI section under More, move testing to Features, restructure nav
* WIP: Rename querying to client, remove factory functions from CLI overview
* WIP: Promote CLI to top-level section, move Upgrading to More
* WIP: Rename CLI installing page to install-mcp
* WIP
* Add Google Gemini sampling handler docs, fix version badges
---
docs/cli/auth.mdx | 85 +++++++++++
docs/cli/client.mdx | 140 +++++++++++++++++
docs/cli/generate-cli.mdx | 106 +++++++++++++
docs/cli/inspecting.mdx | 72 +++++++++
docs/cli/install-mcp.mdx | 141 ++++++++++++++++++
docs/cli/overview.mdx | 103 +++++++++++++
docs/cli/running.mdx | 141 ++++++++++++++++++
docs/clients/sampling.mdx | 20 ++-
docs/deployment/running-server.mdx | 2 +-
docs/development/v3-notes/v3-features.mdx | 6 +-
docs/docs.json | 122 +++++++++------
docs/getting-started/installation.mdx | 22 +--
.../upgrading/from-fastmcp-2.mdx | 1 -
.../upgrading/from-low-level-sdk.mdx | 5 +-
.../upgrading/from-mcp-sdk.mdx | 1 -
docs/integrations/propelauth.mdx | 2 +-
.../mounting.mdx => composition.mdx} | 100 ++-----------
docs/servers/middleware.mdx | 2 +-
docs/servers/providers/overview.mdx | 4 +-
docs/servers/providers/proxy.mdx | 4 +-
docs/servers/testing.mdx | 104 +++++++++++++
21 files changed, 1020 insertions(+), 163 deletions(-)
create mode 100644 docs/cli/auth.mdx
create mode 100644 docs/cli/client.mdx
create mode 100644 docs/cli/generate-cli.mdx
create mode 100644 docs/cli/inspecting.mdx
create mode 100644 docs/cli/install-mcp.mdx
create mode 100644 docs/cli/overview.mdx
create mode 100644 docs/cli/running.mdx
rename docs/servers/{providers/mounting.mdx => composition.mdx} (60%)
create mode 100644 docs/servers/testing.mdx
diff --git a/docs/cli/auth.mdx b/docs/cli/auth.mdx
new file mode 100644
index 000000000..71b89e08a
--- /dev/null
+++ b/docs/cli/auth.mdx
@@ -0,0 +1,85 @@
+---
+title: Auth Utilities
+sidebarTitle: Auth
+description: Create and validate CIMD documents for OAuth
+icon: key
+---
+
+import { VersionBadge } from '/snippets/version-badge.mdx'
+
+
+
+The `fastmcp auth` commands help with CIMD (Client ID Metadata Document) management — part of MCP's OAuth authentication flow. A CIMD is a JSON document you host at an HTTPS URL to identify your client application to MCP servers.
+
+## Creating a CIMD
+
+`fastmcp auth cimd create` generates a CIMD document:
+
+```bash
+fastmcp auth cimd create \
+ --name "My App" \
+ --redirect-uri "http://localhost:*/callback"
+```
+
+```json
+{
+ "client_id": "https://your-domain.com/oauth/client.json",
+ "client_name": "My App",
+ "redirect_uris": ["http://localhost:*/callback"],
+ "token_endpoint_auth_method": "none"
+}
+```
+
+The generated document includes a placeholder `client_id` — update it to match the URL where you'll host the document before deploying.
+
+### Options
+
+| Option | Flag | Description |
+| ------ | ---- | ----------- |
+| Name | `--name` | **Required.** Human-readable client name |
+| Redirect URI | `--redirect-uri` | **Required.** Allowed redirect URIs (repeatable) |
+| Client URI | `--client-uri` | Client's home page URL |
+| Logo URI | `--logo-uri` | Client's logo URL |
+| Scope | `--scope` | Space-separated list of scopes |
+| Output | `--output`, `-o` | Save to file (default: stdout) |
+| Pretty | `--pretty` | Pretty-print JSON (default: true) |
+
+### Example
+
+```bash
+fastmcp auth cimd create \
+ --name "My Production App" \
+ --redirect-uri "http://localhost:*/callback" \
+ --redirect-uri "https://myapp.example.com/callback" \
+ --client-uri "https://myapp.example.com" \
+ --scope "read write" \
+ --output client.json
+```
+
+## Validating a CIMD
+
+`fastmcp auth cimd validate` fetches a hosted CIMD and verifies it conforms to the spec:
+
+```bash
+fastmcp auth cimd validate https://myapp.example.com/oauth/client.json
+```
+
+The validator checks that the URL is valid (HTTPS, non-root path), the document is valid JSON, the `client_id` matches the URL, and no shared-secret auth methods are used.
+
+On success:
+
+```
+→ Fetching https://myapp.example.com/oauth/client.json...
+✓ Valid CIMD document
+
+Document details:
+ client_id: https://myapp.example.com/oauth/client.json
+ client_name: My App
+ token_endpoint_auth_method: none
+ redirect_uris:
+ • http://localhost:*/callback
+```
+
+| Option | Flag | Description |
+| ------ | ---- | ----------- |
+| Timeout | `--timeout`, `-t` | HTTP request timeout in seconds (default: 10) |
diff --git a/docs/cli/client.mdx b/docs/cli/client.mdx
new file mode 100644
index 000000000..bd72b163d
--- /dev/null
+++ b/docs/cli/client.mdx
@@ -0,0 +1,140 @@
+---
+title: Client Commands
+sidebarTitle: Client
+description: List tools, call them, and discover configured servers
+icon: satellite-dish
+---
+
+import { VersionBadge } from '/snippets/version-badge.mdx'
+
+
+
+The CLI can act as an MCP client — connecting to any server (local or remote) to list what it exposes and call its tools directly. This is useful for development, debugging, scripting, and giving shell-capable LLM agents access to MCP servers.
+
+## Listing Tools
+
+`fastmcp list` connects to a server and prints its tools as function signatures, showing parameter names, types, and descriptions at a glance:
+
+```bash
+fastmcp list http://localhost:8000/mcp
+fastmcp list server.py
+fastmcp list weather # name-based resolution
+```
+
+When you need the full JSON Schema for a tool's inputs or outputs — for understanding nested objects, enum constraints, or complex types — opt in with `--input-schema` or `--output-schema`:
+
+```bash
+fastmcp list server.py --input-schema
+```
+
+### Resources and Prompts
+
+By default, only tools are shown. Add `--resources` or `--prompts` to include those:
+
+```bash
+fastmcp list server.py --resources --prompts
+```
+
+### Machine-Readable Output
+
+The `--json` flag switches to structured JSON with full schemas included. This is the format to use when feeding tool definitions to an LLM or building automation:
+
+```bash
+fastmcp list server.py --json
+```
+
+### Options
+
+| Option | Flag | Description |
+| ------ | ---- | ----------- |
+| Command | `--command` | Connect via stdio (e.g., `'npx -y @mcp/server'`) |
+| Transport | `--transport`, `-t` | Force `http` or `sse` for URL targets |
+| Resources | `--resources` | Include resources in output |
+| Prompts | `--prompts` | Include prompts in output |
+| Input Schema | `--input-schema` | Show full input schemas |
+| Output Schema | `--output-schema` | Show full output schemas |
+| JSON | `--json` | Structured JSON output |
+| Timeout | `--timeout` | Connection timeout in seconds |
+| Auth | `--auth` | `oauth` (default for HTTP), a bearer token, or `none` |
+
+## Calling Tools
+
+`fastmcp call` invokes a single tool on a server. Pass arguments as `key=value` pairs — the CLI fetches the tool's schema and coerces your string values to the right types automatically:
+
+```bash
+fastmcp call server.py greet name=World
+fastmcp call http://localhost:8000/mcp search query=hello limit=5
+```
+
+Type coercion is schema-driven: `"5"` becomes the integer `5` when the schema expects an integer. Booleans accept `true`/`false`, `yes`/`no`, and `1`/`0`. Arrays and objects are parsed as JSON.
+
+### Complex Arguments
+
+For tools with nested or structured parameters, `key=value` syntax gets awkward. Pass a single JSON object instead:
+
+```bash
+fastmcp call server.py create_item '{"name": "Widget", "tags": ["sale"], "metadata": {"color": "blue"}}'
+```
+
+Or use `--input-json` to provide a base dictionary, then override individual keys with `key=value` pairs:
+
+```bash
+fastmcp call server.py search --input-json '{"query": "hello", "limit": 5}' limit=10
+```
+
+### Error Handling
+
+If you misspell a tool name, the CLI suggests corrections via fuzzy matching. Missing required arguments produce a clear message with the tool's signature as a reminder. Tool execution errors are printed with a non-zero exit code, making the CLI straightforward to use in scripts.
+
+### Structured Output
+
+`--json` emits the raw result including content blocks, error status, and structured content:
+
+```bash
+fastmcp call server.py get_weather city=London --json
+```
+
+### Interactive Elicitation
+
+Some tools request additional input during execution through MCP's elicitation mechanism. When this happens, the CLI prompts you in the terminal — showing each field's name, type, and whether it's required. You can type `decline` to skip a question or `cancel` to abort the call entirely.
+
+### Options
+
+| Option | Flag | Description |
+| ------ | ---- | ----------- |
+| Command | `--command` | Connect via stdio |
+| Transport | `--transport`, `-t` | Force `http` or `sse` |
+| Input JSON | `--input-json` | Base arguments as JSON (merged with `key=value`) |
+| JSON | `--json` | Raw JSON output |
+| Timeout | `--timeout` | Connection timeout in seconds |
+| Auth | `--auth` | `oauth`, a bearer token, or `none` |
+
+## Discovering Configured Servers
+
+`fastmcp discover` scans your machine for MCP servers configured in editors and tools. It checks:
+
+- **Claude Desktop** — `claude_desktop_config.json`
+- **Claude Code** — `~/.claude.json`
+- **Cursor** — `.cursor/mcp.json` (walks up from current directory)
+- **Gemini CLI** — `~/.gemini/settings.json`
+- **Goose** — `~/.config/goose/config.yaml`
+- **Project** — `./mcp.json` in the current directory
+
+```bash
+fastmcp discover
+```
+
+The output groups servers by source, showing each server's name and transport. Filter by source or get machine-readable output:
+
+```bash
+fastmcp discover --source claude-code
+fastmcp discover --source cursor --source gemini --json
+```
+
+Any server that appears here can be used by name with `list`, `call`, and other commands — so you can go from "I have a server in Claude Code" to querying it without copying URLs or paths.
+
+## LLM Agent Integration
+
+For LLM agents that can execute shell commands but don't have native MCP support, the CLI provides a clean bridge. The agent calls `fastmcp list --json` to discover available tools with full schemas, then `fastmcp call --json` to invoke them with structured results.
+
+Because the CLI handles connection management, transport selection, and type coercion internally, the agent doesn't need to understand MCP protocol details — it just reads JSON and constructs shell commands.
diff --git a/docs/cli/generate-cli.mdx b/docs/cli/generate-cli.mdx
new file mode 100644
index 000000000..2754d199a
--- /dev/null
+++ b/docs/cli/generate-cli.mdx
@@ -0,0 +1,106 @@
+---
+title: Generate CLI
+sidebarTitle: Generate CLI
+description: Scaffold a standalone typed CLI from any MCP server
+icon: wand-magic-sparkles
+---
+
+import { VersionBadge } from '/snippets/version-badge.mdx'
+
+
+
+`fastmcp list` and `fastmcp call` are general-purpose — you always specify the server, the tool name, and the arguments from scratch. `fastmcp generate-cli` goes further: it connects to a server, reads its tool schemas, and writes a standalone Python script where every tool is a proper subcommand with typed flags, help text, and tab completion. The result is a CLI that feels hand-written for that specific server.
+
+MCP tool schemas already contain everything a CLI framework needs — parameter names, types, descriptions, required/optional status, and defaults. `generate-cli` maps that into [cyclopts](https://cyclopts.readthedocs.io/) commands, so JSON Schema types become Python type annotations, descriptions become `--help` text, and required parameters become mandatory flags.
+
+## Generating a Script
+
+Point the command at any [server target](/cli/overview#server-targets) and it writes a CLI script:
+
+```bash
+fastmcp generate-cli weather
+fastmcp generate-cli http://localhost:8000/mcp
+fastmcp generate-cli server.py my_weather_cli.py
+```
+
+The second positional argument sets the output path (defaults to `cli.py`). If the file already exists, pass `-f` to overwrite:
+
+```bash
+fastmcp generate-cli weather -f
+```
+
+## What You Get
+
+The generated script is a regular Python file — executable, editable, and yours:
+
+```
+$ python cli.py call-tool --help
+Usage: weather-cli call-tool COMMAND
+
+Call a tool on the server
+
+Commands:
+ get_forecast Get the weather forecast for a city.
+ search_city Search for a city by name.
+```
+
+Each tool has typed parameters with help text pulled directly from the server's schema:
+
+```
+$ python cli.py call-tool get_forecast --help
+Usage: weather-cli call-tool get_forecast [OPTIONS]
+
+Get the weather forecast for a city.
+
+Options:
+ --city [str] City name (required)
+ --days [int] Number of forecast days (default: 3)
+```
+
+Beyond tool commands, the script includes generic MCP operations — `list-tools`, `list-resources`, `read-resource`, `list-prompts`, and `get-prompt` — that always reflect the server's current state, even if tools have changed since generation.
+
+## Parameter Handling
+
+Parameters are mapped based on their JSON Schema type:
+
+**Simple types** (`string`, `integer`, `number`, `boolean`) become typed flags:
+
+```bash
+python cli.py call-tool get_forecast --city London --days 3
+```
+
+**Arrays of simple types** become repeatable flags:
+
+```bash
+python cli.py call-tool tag_items --tags python --tags fastapi --tags mcp
+```
+
+**Complex types** (objects, nested arrays, unions) accept JSON strings. The `--help` output shows the full schema so you know what structure to pass:
+
+```bash
+python cli.py call-tool create_user \
+ --name John \
+ --metadata '{"role": "admin", "dept": "engineering"}'
+```
+
+## Agent Skill
+
+Alongside the CLI script, `generate-cli` writes a `SKILL.md` file — a [Claude Code agent skill](https://docs.anthropic.com/en/docs/agents-and-tools/claude-code/skills) that documents every tool's exact invocation syntax, parameter flags, types, and descriptions. An agent can pick up the CLI immediately without running `--help` or experimenting with flag names.
+
+To skip skill generation:
+
+```bash
+fastmcp generate-cli weather --no-skill
+```
+
+## How It Works
+
+The generated script is a *client*, not a server — it connects to the server on every invocation rather than bundling it. A `CLIENT_SPEC` variable at the top holds the resolved transport (a URL string or `StdioTransport` with baked-in command and arguments).
+
+The most common edit is changing `CLIENT_SPEC` — for example, pointing a script generated from a dev server at production. Beyond that, the helper functions (`_call_tool`, `_print_tool_result`) are thin wrappers around `fastmcp.Client` that are easy to adapt.
+
+The script requires `fastmcp` as a dependency. If it lives outside a project that already has FastMCP installed:
+
+```bash
+uv run --with fastmcp python cli.py call-tool get_forecast --city London
+```
diff --git a/docs/cli/inspecting.mdx b/docs/cli/inspecting.mdx
new file mode 100644
index 000000000..657921357
--- /dev/null
+++ b/docs/cli/inspecting.mdx
@@ -0,0 +1,72 @@
+---
+title: Inspecting Servers
+sidebarTitle: Inspecting
+description: View a server's components and metadata
+icon: magnifying-glass
+---
+
+import { VersionBadge } from '/snippets/version-badge.mdx'
+
+
+
+`fastmcp inspect` loads a server and reports what it contains — its tools, resources, prompts, version, and metadata. The default output is a human-readable summary:
+
+```bash
+fastmcp inspect server.py
+```
+
+```
+Server: MyServer
+Instructions: A helpful MCP server
+Version: 1.0.0
+
+Components:
+ Tools: 5
+ Prompts: 2
+ Resources: 3
+ Templates: 1
+
+Environment:
+ FastMCP: 2.0.0
+ MCP: 1.0.0
+
+Use --format [fastmcp|mcp] for complete JSON output
+```
+
+## JSON Output
+
+For programmatic use, two JSON formats are available:
+
+**FastMCP format** (`--format fastmcp`) includes everything FastMCP knows about the server — tool tags, enabled status, output schemas, annotations, and custom metadata. Field names use `snake_case`. This is the format for debugging and introspecting FastMCP servers.
+
+**MCP protocol format** (`--format mcp`) shows exactly what MCP clients see through the protocol — only standard MCP fields, `camelCase` names, no FastMCP-specific extensions. This is the format for verifying client compatibility and debugging what clients actually receive.
+
+```bash
+# Full FastMCP metadata to stdout
+fastmcp inspect server.py --format fastmcp
+
+# MCP protocol view saved to file
+fastmcp inspect server.py --format mcp -o manifest.json
+```
+
+## Options
+
+| Option | Flag | Description |
+| ------ | ---- | ----------- |
+| Format | `--format`, `-f` | `fastmcp` or `mcp` (required when using `-o`) |
+| Output File | `--output`, `-o` | Save to file instead of stdout |
+
+## Entrypoints
+
+The `inspect` command supports the same local entrypoints as [`fastmcp run`](/cli/running): inferred instances, explicit entrypoints, factory functions, and `fastmcp.json` configs.
+
+```bash
+fastmcp inspect server.py # inferred instance
+fastmcp inspect server.py:my_server # explicit entrypoint
+fastmcp inspect server.py:create_server # factory function
+fastmcp inspect fastmcp.json # config file
+```
+
+
+`inspect` only works with local files and `fastmcp.json` — it doesn't connect to remote URLs or standard MCP config files.
+
diff --git a/docs/cli/install-mcp.mdx b/docs/cli/install-mcp.mdx
new file mode 100644
index 000000000..bf1b60b36
--- /dev/null
+++ b/docs/cli/install-mcp.mdx
@@ -0,0 +1,141 @@
+---
+title: Install MCP Servers
+sidebarTitle: Install MCPs
+description: Install MCP servers into Claude, Cursor, Gemini, and other clients
+icon: download
+---
+
+import { VersionBadge } from '/snippets/version-badge.mdx'
+
+
+
+`fastmcp install` registers a server with an MCP client application so the client can launch it automatically. Each MCP client runs servers in its own isolated environment, which means dependencies need to be explicitly declared — you can't rely on whatever happens to be installed locally.
+
+```bash
+fastmcp install claude-desktop server.py
+fastmcp install claude-code server.py --with pandas --with matplotlib
+fastmcp install cursor server.py -e .
+```
+
+
+`uv` must be installed and available in your system PATH. Both Claude Desktop and Cursor run servers in isolated environments managed by `uv`. On macOS, install it globally with Homebrew for Claude Desktop compatibility: `brew install uv`.
+
+
+## Supported Clients
+
+| Client | Install method |
+| ------ | -------------- |
+| `claude-code` | Claude Code's built-in MCP management |
+| `claude-desktop` | Direct config file modification |
+| `cursor` | Deeplink that opens Cursor for confirmation |
+| `gemini-cli` | Gemini CLI's built-in MCP management |
+| `goose` | Deeplink that opens Goose for confirmation (uses `uvx`) |
+| `mcp-json` | Generates standard MCP JSON config for manual use |
+| `stdio` | Outputs the shell command to run via stdio |
+
+## Declaring Dependencies
+
+Because MCP clients run servers in isolation, you need to tell the install command what your server needs. There are two approaches:
+
+**Command-line flags** let you specify dependencies directly:
+
+```bash
+fastmcp install claude-desktop server.py --with pandas --with "sqlalchemy>=2.0"
+fastmcp install cursor server.py -e . --with-requirements requirements.txt
+```
+
+**`fastmcp.json`** configuration files declare dependencies alongside the server definition. When you install from a config file, dependencies are picked up automatically:
+
+```bash
+fastmcp install claude-desktop fastmcp.json
+fastmcp install claude-desktop # auto-detects fastmcp.json in current directory
+```
+
+See [Server Configuration](/deployment/server-configuration) for the full config format.
+
+## Options
+
+| Option | Flag | Description |
+| ------ | ---- | ----------- |
+| Server Name | `--server-name`, `-n` | Custom name for the server |
+| Editable Package | `--with-editable`, `-e` | Install a directory in editable mode |
+| Extra Packages | `--with` | Additional packages (repeatable) |
+| Environment Variables | `--env` | `KEY=VALUE` pairs (repeatable) |
+| Environment File | `--env-file`, `-f` | Load env vars from a `.env` file |
+| Python | `--python` | Python version (e.g., `3.11`) |
+| Project | `--project` | Run within a uv project directory |
+| Requirements | `--with-requirements` | Install from a requirements file |
+
+## Examples
+
+```bash
+# Basic install with auto-detected server instance
+fastmcp install claude-desktop server.py
+
+# Install from fastmcp.json with auto-detection
+fastmcp install claude-desktop
+
+# Explicit entrypoint with dependencies
+fastmcp install claude-desktop server.py:my_server \
+ --server-name "My Analysis Server" \
+ --with pandas
+
+# With environment variables
+fastmcp install claude-code server.py \
+ --env API_KEY=secret \
+ --env DEBUG=true
+
+# With env file
+fastmcp install cursor server.py --env-file .env
+
+# Specific Python version and requirements file
+fastmcp install claude-desktop server.py \
+ --python 3.11 \
+ --with-requirements requirements.txt
+```
+
+## Generating MCP JSON
+
+The `mcp-json` target generates standard MCP configuration JSON instead of installing into a specific client. This is useful for clients that FastMCP doesn't directly support, for CI/CD environments, or for sharing server configs:
+
+```bash
+fastmcp install mcp-json server.py
+```
+
+The output follows the standard format used by Claude Desktop, Cursor, and other MCP clients:
+
+```json
+{
+ "server-name": {
+ "command": "uv",
+ "args": ["run", "--with", "fastmcp", "fastmcp", "run", "/path/to/server.py"],
+ "env": {
+ "API_KEY": "value"
+ }
+ }
+}
+```
+
+Use `--copy` to send it to your clipboard instead of stdout.
+
+## Generating Stdio Commands
+
+The `stdio` target outputs the shell command an MCP host would use to start your server over stdio:
+
+```bash
+fastmcp install stdio server.py
+# Output: uv run --with fastmcp fastmcp run /absolute/path/to/server.py
+```
+
+When installing from a `fastmcp.json`, dependencies from the config are included automatically:
+
+```bash
+fastmcp install stdio fastmcp.json
+# Output: uv run --with fastmcp --with pillow --with 'qrcode[pil]>=8.0' fastmcp run /path/to/server.py
+```
+
+Use `--copy` to copy to clipboard.
+
+
+`fastmcp install` is designed for local server files with stdio transport. For remote servers running over HTTP, use your client's native configuration — FastMCP's value here is simplifying the complex local setup with `uv`, dependencies, and environment variables.
+
diff --git a/docs/cli/overview.mdx b/docs/cli/overview.mdx
new file mode 100644
index 000000000..2cd4e145d
--- /dev/null
+++ b/docs/cli/overview.mdx
@@ -0,0 +1,103 @@
+---
+title: CLI
+sidebarTitle: Overview
+description: The fastmcp command-line interface
+icon: terminal
+---
+
+import { VersionBadge } from '/snippets/version-badge.mdx'
+
+The `fastmcp` CLI is installed automatically with FastMCP. It's the primary way to run, test, install, and interact with MCP servers from your terminal.
+
+```bash
+fastmcp --help
+```
+
+## Commands at a Glance
+
+| Command | What it does |
+| ------- | ------------ |
+| [`run`](/cli/running) | Run a server (local file, factory function, remote URL, or config file) |
+| [`dev inspector`](/cli/running#development-with-the-inspector) | Launch a server inside the MCP Inspector for interactive testing |
+| [`install`](/cli/install-mcp) | Install a server into Claude Code, Claude Desktop, Cursor, Gemini CLI, or Goose |
+| [`inspect`](/cli/inspecting) | Print a server's tools, resources, and prompts as a summary or JSON report |
+| [`list`](/cli/client) | List a server's tools (and optionally resources and prompts) |
+| [`call`](/cli/client#calling-tools) | Call a single tool with arguments |
+| [`discover`](/cli/client#discovering-configured-servers) | Find MCP servers configured in your editors and tools |
+| [`generate-cli`](/cli/generate-cli) | Scaffold a standalone typed CLI from a server's tool schemas |
+| [`project prepare`](/cli/running#pre-building-environments) | Pre-install dependencies into a reusable uv project |
+| [`auth cimd`](/cli/auth) | Create and validate CIMD documents for OAuth |
+| `version` | Print version info (`--copy` to copy to clipboard) |
+
+## Server Targets
+
+Most commands need to know *which server* to talk to. You pass a "server spec" as the first argument, and FastMCP resolves the right transport automatically.
+
+**URLs** connect to a running HTTP server:
+
+```bash
+fastmcp list http://localhost:8000/mcp
+fastmcp call http://localhost:8000/mcp get_forecast city=London
+```
+
+**Python files** are loaded directly — no `mcp.run()` boilerplate needed. FastMCP finds a server instance named `mcp`, `server`, or `app` in the file, or you can specify one explicitly:
+
+```bash
+fastmcp list server.py
+fastmcp run server.py:my_custom_server
+```
+
+**Config files** work too — both FastMCP's own `fastmcp.json` format and standard MCP config files with an `mcpServers` key:
+
+```bash
+fastmcp run fastmcp.json
+fastmcp list mcp-config.json
+```
+
+**Stdio commands** connect to any MCP server that speaks over standard I/O. Use `--command` instead of a positional argument:
+
+```bash
+fastmcp list --command 'npx -y @modelcontextprotocol/server-github'
+```
+
+### Name-Based Resolution
+
+If your servers are already configured in an editor or tool, you can refer to them by name. FastMCP scans configs from Claude Desktop, Claude Code, Cursor, Gemini CLI, and Goose:
+
+```bash
+fastmcp list weather
+fastmcp call weather get_forecast city=London
+```
+
+When the same name appears in multiple configs, use the `source:name` form to be specific:
+
+```bash
+fastmcp list claude-code:my-server
+fastmcp call cursor:weather get_forecast city=London
+```
+
+Run [`fastmcp discover`](/cli/client#discovering-configured-servers) to see what's available on your machine.
+
+## Authentication
+
+When targeting an HTTP URL, the CLI enables OAuth authentication by default. If the server requires it, you'll be guided through the flow (typically opening a browser). If it doesn't, the setup is a silent no-op.
+
+To skip authentication entirely — useful for local development servers — pass `--auth none`:
+
+```bash
+fastmcp call http://localhost:8000/mcp my_tool --auth none
+```
+
+You can also pass a bearer token directly:
+
+```bash
+fastmcp list http://localhost:8000/mcp --auth "Bearer sk-..."
+```
+
+## Transport Override
+
+FastMCP defaults to Streamable HTTP for URL targets. If the server only supports Server-Sent Events (SSE), force the older transport:
+
+```bash
+fastmcp list http://localhost:8000 --transport sse
+```
diff --git a/docs/cli/running.mdx b/docs/cli/running.mdx
new file mode 100644
index 000000000..dd976d561
--- /dev/null
+++ b/docs/cli/running.mdx
@@ -0,0 +1,141 @@
+---
+title: Running Servers
+sidebarTitle: Running
+description: Start, develop, and configure servers from the command line
+icon: play
+---
+
+import { VersionBadge } from '/snippets/version-badge.mdx'
+
+## Starting a Server
+
+`fastmcp run` starts a server. Point it at a Python file, a factory function, a remote URL, or a config file:
+
+```bash
+fastmcp run server.py
+fastmcp run server.py:create_server
+fastmcp run https://example.com/mcp
+fastmcp run fastmcp.json
+```
+
+By default, the server runs over **stdio** — the transport that MCP clients like Claude Desktop expect. To serve over HTTP instead, specify the transport:
+
+```bash
+fastmcp run server.py --transport http
+fastmcp run server.py --transport http --host 0.0.0.0 --port 9000
+```
+
+### Entrypoints
+
+FastMCP supports several ways to locate and start your server:
+
+**Inferred instance** — FastMCP imports the file and looks for a variable named `mcp`, `server`, or `app`:
+
+```bash
+fastmcp run server.py
+```
+
+**Explicit instance** — point at a specific variable:
+
+```bash
+fastmcp run server.py:my_server
+```
+
+**Factory function** — FastMCP calls the function and uses the returned server. Useful when your server needs async setup or configuration that runs before startup:
+
+```bash
+fastmcp run server.py:create_server
+```
+
+**Remote URL** — starts a local proxy that bridges to a remote server. Handy for local development against a deployed server, or for bridging a remote HTTP server to stdio:
+
+```bash
+fastmcp run https://example.com/mcp
+```
+
+**FastMCP config** — uses a `fastmcp.json` file that declaratively specifies the server, its dependencies, and deployment settings. When you run `fastmcp run` with no arguments, it auto-detects `fastmcp.json` in the current directory:
+
+```bash
+fastmcp run
+fastmcp run my-config.fastmcp.json
+```
+
+See [Server Configuration](/deployment/server-configuration) for the full `fastmcp.json` format.
+
+**MCP config** — runs servers defined in a standard MCP configuration file (any `.json` with an `mcpServers` key):
+
+```bash
+fastmcp run mcp.json
+```
+
+
+`fastmcp run` completely ignores the `if __name__ == "__main__"` block. Any setup code in that block won't execute. If you need initialization logic to run, use a [factory function](/cli/overview#factory-functions).
+
+
+### Options
+
+| Option | Flag | Description |
+| ------ | ---- | ----------- |
+| Transport | `--transport`, `-t` | `stdio` (default), `http`, or `sse` |
+| Host | `--host` | Bind address for HTTP (default: `127.0.0.1`) |
+| Port | `--port`, `-p` | Bind port for HTTP (default: `8000`) |
+| Path | `--path` | URL path for HTTP (default: `/mcp/`) |
+| Log Level | `--log-level`, `-l` | `DEBUG`, `INFO`, `WARNING`, `ERROR`, `CRITICAL` |
+| No Banner | `--no-banner` | Suppress the startup banner |
+| Auto-Reload | `--reload` / `--no-reload` | Watch for file changes and restart automatically |
+| Reload Dirs | `--reload-dir` | Directories to watch (repeatable) |
+| Skip Env | `--skip-env` | Don't set up a uv environment (use when already in one) |
+| Python | `--python` | Python version to use (e.g., `3.11`) |
+| Extra Packages | `--with` | Additional packages to install (repeatable) |
+| Project | `--project` | Run within a specific uv project directory |
+| Requirements | `--with-requirements` | Install from a requirements file |
+
+### Dependency Management
+
+By default, `fastmcp run` uses your current Python environment directly. When you pass `--python`, `--with`, `--project`, or `--with-requirements`, it switches to running via `uv run` in a subprocess, which handles dependency isolation automatically.
+
+The `--skip-env` flag is useful when you're already inside an activated venv, a Docker container with pre-installed dependencies, or a uv-managed project — it prevents uv from trying to set up another environment layer.
+
+## Development with the Inspector
+
+`fastmcp dev inspector` launches your server inside the [MCP Inspector](https://github.com/modelcontextprotocol/inspector), a browser-based tool for interactively testing MCP servers. Auto-reload is on by default, so your server restarts when you save changes.
+
+```bash
+fastmcp dev inspector server.py
+fastmcp dev inspector server.py -e . --with pandas
+```
+
+
+The Inspector always runs your server via `uv run` in a subprocess — it never uses your local environment directly. Specify dependencies with `--with`, `--with-editable`, `--with-requirements`, or through a `fastmcp.json` file.
+
+
+
+The Inspector connects over **stdio only**. When it launches, you may need to select "STDIO" from the transport dropdown and click connect. To test a server over HTTP, start it separately with `fastmcp run server.py --transport http` and point the Inspector at the URL.
+
+
+| Option | Flag | Description |
+| ------ | ---- | ----------- |
+| Editable Package | `--with-editable`, `-e` | Install a directory in editable mode |
+| Extra Packages | `--with` | Additional packages (repeatable) |
+| Inspector Version | `--inspector-version` | MCP Inspector version to use |
+| UI Port | `--ui-port` | Port for the Inspector UI |
+| Server Port | `--server-port` | Port for the Inspector proxy |
+| Auto-Reload | `--reload` / `--no-reload` | File watching (default: on) |
+| Reload Dirs | `--reload-dir` | Directories to watch (repeatable) |
+| Python | `--python` | Python version |
+| Project | `--project` | Run within a uv project directory |
+| Requirements | `--with-requirements` | Install from a requirements file |
+
+## Pre-Building Environments
+
+`fastmcp project prepare` creates a persistent uv project from a `fastmcp.json` file, pre-installing all dependencies. This separates environment setup from server execution — install once, run many times.
+
+```bash
+# Step 1: Build the environment (slow, does dependency resolution)
+fastmcp project prepare fastmcp.json --output-dir ./env
+
+# Step 2: Run using the prepared environment (fast, no install step)
+fastmcp run fastmcp.json --project ./env
+```
+
+The prepared directory contains a `pyproject.toml`, a `.venv` with all packages installed, and a `uv.lock` for reproducibility. This is particularly useful in deployment scenarios where you want deterministic, pre-built environments.
diff --git a/docs/clients/sampling.mdx b/docs/clients/sampling.mdx
index b1114da0d..a2e0e9942 100644
--- a/docs/clients/sampling.mdx
+++ b/docs/clients/sampling.mdx
@@ -97,7 +97,7 @@ client = Client(
## Built-in Handlers
-FastMCP provides built-in handlers for OpenAI and Anthropic APIs that support the full sampling API including tool use.
+FastMCP provides built-in handlers for OpenAI, Anthropic, and Google Gemini APIs that support the full sampling API including tool use.
### OpenAI Handler
@@ -149,6 +149,24 @@ client = Client(
Install the Anthropic handler with `pip install fastmcp[anthropic]`.
+### Google Gemini Handler
+
+
+
+```python
+from fastmcp import Client
+from fastmcp.client.sampling.handlers.google_genai import GoogleGenAISamplingHandler
+
+client = Client(
+ "my_mcp_server.py",
+ sampling_handler=GoogleGenAISamplingHandler(default_model="gemini-2.0-flash"),
+)
+```
+
+
+Install the Google Gemini handler with `pip install fastmcp[gemini]`.
+
+
## Sampling Capabilities
When you provide a `sampling_handler`, FastMCP automatically advertises full sampling capabilities to the server, including tool support. To disable tool support for simpler handlers:
diff --git a/docs/deployment/running-server.mdx b/docs/deployment/running-server.mdx
index bf4b83161..c10855345 100644
--- a/docs/deployment/running-server.mdx
+++ b/docs/deployment/running-server.mdx
@@ -157,7 +157,7 @@ fastmcp run database_server.py -- --database-path /tmp/db.sqlite --debug
This is useful for servers that need configuration files, database paths, API keys, or other runtime options.
-For more CLI features including development mode with the MCP Inspector, see the [CLI documentation](/patterns/cli).
+For more CLI features including development mode with the MCP Inspector, see the [CLI documentation](/cli/running).
### Auto-Reload for Development
diff --git a/docs/development/v3-notes/v3-features.mdx b/docs/development/v3-notes/v3-features.mdx
index 4a8f11a1a..da9fc87db 100644
--- a/docs/development/v3-notes/v3-features.mdx
+++ b/docs/development/v3-notes/v3-features.mdx
@@ -185,7 +185,7 @@ Key features:
- Fuzzy tool name matching suggests alternatives on typos
- Interactive terminal elicitation for tools that request user input mid-execution
-Documentation: [Client CLI](/clients/cli)
+Documentation: [CLI Querying](/cli/client)
### CLI: `fastmcp discover` and name-based resolution
@@ -207,7 +207,7 @@ fastmcp call cursor:weather get_forecast city=London
fastmcp discover --source claude-code --source cursor
```
-Documentation: [Client CLI](/clients/cli)
+Documentation: [CLI Querying](/cli/client)
### CLI: Expanded Reload File Watching
@@ -315,7 +315,7 @@ python my_weather_cli.py read-resource docs://readme
The generated script embeds the resolved transport (URL or stdio command), so it's self-contained — users don't need to know about MCP or FastMCP to use it. Supports `-f` to overwrite existing files, and name-based resolution via `fastmcp discover`.
-Documentation: [Generate CLI](/clients/generate-cli)
+Documentation: [Generate CLI](/cli/generate-cli)
### CLI: Goose Integration
diff --git a/docs/docs.json b/docs/docs.json
index 1a72acf86..758524c66 100644
--- a/docs/docs.json
+++ b/docs/docs.json
@@ -88,18 +88,7 @@
"pages": [
"getting-started/welcome",
"getting-started/installation",
- "getting-started/quickstart",
- {
- "collapsed": true,
- "group": "Upgrade",
- "icon": "up",
- "pages": [
- "getting-started/upgrading/from-fastmcp-2",
- "getting-started/upgrading/from-mcp-sdk",
- "getting-started/upgrading/from-low-level-sdk"
- ],
- "tag": "NEW"
- }
+ "getting-started/quickstart"
]
},
{
@@ -123,6 +112,7 @@
"icon": "stars",
"pages": [
"servers/tasks",
+ "servers/composition",
"servers/dependency-injection",
"servers/elicitation",
"servers/icons",
@@ -134,9 +124,10 @@
"servers/sampling",
"servers/storage-backends",
"servers/telemetry",
+ "servers/testing",
"servers/versioning"
],
- "tag": "NEW"
+ "tag": "UPDATED"
},
{
"collapsed": true,
@@ -148,8 +139,7 @@
"servers/providers/filesystem",
"servers/providers/proxy",
"servers/providers/skills",
- "servers/providers/custom",
- "servers/providers/mounting"
+ "servers/providers/custom"
],
"tag": "NEW"
},
@@ -173,6 +163,7 @@
"collapsed": true,
"group": "Authentication",
"icon": "key",
+ "tag": "UPDATED",
"pages": [
"servers/auth/authentication",
"servers/auth/token-verification",
@@ -192,9 +183,7 @@
"deployment/running-server",
"deployment/http",
"deployment/prefect-horizon",
- "deployment/server-configuration",
- "patterns/cli",
- "patterns/testing"
+ "deployment/server-configuration"
]
}
]
@@ -213,16 +202,6 @@
"pages": [
"clients/client",
"clients/transports",
- {
- "collapsed": true,
- "group": "CLI",
- "icon": "terminal",
- "pages": [
- "clients/cli",
- "clients/generate-cli"
- ],
- "tag": "NEW"
- },
{
"collapsed": true,
"group": "Core Operations",
@@ -237,6 +216,7 @@
"collapsed": true,
"group": "Handlers",
"icon": "hand",
+ "tag": "UPDATED",
"pages": [
"clients/notifications",
"clients/sampling",
@@ -256,7 +236,7 @@
"clients/auth/cimd",
"clients/auth/bearer"
],
- "tag": "NEW"
+ "tag": "UPDATED"
}
]
},
@@ -274,15 +254,15 @@
"integrations/azure",
"integrations/descope",
"integrations/discord",
+ "integrations/eunomia-authorization",
"integrations/github",
"integrations/google",
"integrations/oci",
+ "integrations/permit",
"integrations/propelauth",
"integrations/scalekit",
"integrations/supabase",
- "integrations/workos",
- "integrations/eunomia-authorization",
- "integrations/permit"
+ "integrations/workos"
]
},
{
@@ -304,8 +284,7 @@
"integrations/claude-desktop",
"integrations/cursor",
"integrations/gemini-cli",
- "integrations/goose",
- "integrations/mcp-json-configuration"
+ "integrations/goose"
]
},
{
@@ -317,18 +296,55 @@
"integrations/gemini",
"integrations/openai"
]
- }
+ },
+ "integrations/mcp-json-configuration"
]
},
{
- "group": "Development",
+ "group": "CLI",
"pages": [
- "development/contributing",
- "development/tests",
- "development/releases",
- "updates",
- "changelog",
- "patterns/contrib"
+ "cli/overview",
+ "cli/running",
+ "cli/install-mcp",
+ "cli/inspecting",
+ "cli/client",
+ "cli/generate-cli",
+ "cli/auth"
+ ]
+ },
+ {
+ "group": "More",
+ "pages": [
+ {
+ "collapsed": true,
+ "group": "Upgrading",
+ "icon": "up",
+ "pages": [
+ "getting-started/upgrading/from-fastmcp-2",
+ "getting-started/upgrading/from-mcp-sdk",
+ "getting-started/upgrading/from-low-level-sdk"
+ ]
+ },
+ {
+ "collapsed": true,
+ "group": "Development",
+ "icon": "code",
+ "pages": [
+ "development/contributing",
+ "development/tests",
+ "development/releases",
+ "patterns/contrib"
+ ]
+ },
+ {
+ "collapsed": true,
+ "group": "What's New",
+ "icon": "sparkles",
+ "pages": [
+ "updates",
+ "changelog"
+ ]
+ }
]
}
],
@@ -948,6 +964,22 @@
]
},
"redirects": [
+ {
+ "destination": "/cli/overview",
+ "source": "/patterns/cli"
+ },
+ {
+ "destination": "/servers/testing",
+ "source": "/patterns/testing"
+ },
+ {
+ "destination": "/cli/client",
+ "source": "/clients/cli"
+ },
+ {
+ "destination": "/cli/generate-cli",
+ "source": "/clients/generate-cli"
+ },
{
"destination": "/deployment/prefect-horizon",
"source": "/deployment/fastmcp-cloud"
@@ -969,7 +1001,7 @@
"source": "/patterns/proxy"
},
{
- "destination": "/servers/providers/mounting",
+ "destination": "/servers/composition",
"source": "/patterns/composition"
},
{
@@ -977,8 +1009,8 @@
"source": "/servers/proxy"
},
{
- "destination": "/servers/providers/mounting",
- "source": "/servers/composition"
+ "destination": "/servers/composition",
+ "source": "/servers/providers/mounting"
},
{
"destination": "/servers/transforms/transforms",
diff --git a/docs/getting-started/installation.mdx b/docs/getting-started/installation.mdx
index 657b995fc..20443337b 100644
--- a/docs/getting-started/installation.mdx
+++ b/docs/getting-started/installation.mdx
@@ -62,15 +62,17 @@ Alternatively, wait for the stable v5 release. See [this issue](https://github.c
## Upgrading
-### From FastMCP 2.x
+### From FastMCP 2.0
See the [Upgrade Guide](/getting-started/upgrading/from-fastmcp-2) for a complete list of breaking changes and migration steps.
-### From FastMCP 1.0 (in the Low-Level SDK)
+### From the MCP SDK
-If you're using FastMCP 1.0 via the `mcp` package (`from mcp.server.fastmcp import FastMCP`), upgrading is straightforward — for most servers, it's a single import change. See the [full upgrade guide](/getting-started/upgrading/from-mcp-sdk) for details.
+#### From FastMCP 1.0
-### From the Low-Level Server API
+If you're using FastMCP 1.0 via the `mcp` package (meaning you import FastMCP as `from mcp.server.fastmcp import FastMCP`), upgrading is straightforward — for most servers, it's a single import change. See the [full upgrade guide](/getting-started/upgrading/from-mcp-sdk) for details.
+
+#### From the Low-Level Server API
If you built your server directly on the `mcp` package's `Server` class — with `list_tools()`/`call_tool()` handlers and hand-written JSON Schema — see the [migration guide](/getting-started/upgrading/from-low-level-sdk) for a full walkthrough.
@@ -86,18 +88,6 @@ fastmcp>=3.0.0 # Bad - may install breaking changes
See the full [versioning and release policy](/development/releases#versioning-policy) for details on our public API, deprecation practices, and breaking change philosophy.
-### Looking Ahead: FastMCP 4.0
-
-The MCP Python SDK v2 is expected in early 2026 and will include breaking changes. When released, FastMCP will incorporate these upstream changes in a new major version (FastMCP 4.0).
-
-To avoid unexpected breaking changes, we recommend pinning your dependency with an upper bound:
-
-```
-fastmcp>=3.0,<4
-```
-
-We'll provide migration guidance when FastMCP 4.0 is released.
-
## Contributing to FastMCP
Interested in contributing to FastMCP? See the [Contributing Guide](/development/contributing) for details on:
diff --git a/docs/getting-started/upgrading/from-fastmcp-2.mdx b/docs/getting-started/upgrading/from-fastmcp-2.mdx
index fb8c57bf5..47baa5655 100644
--- a/docs/getting-started/upgrading/from-fastmcp-2.mdx
+++ b/docs/getting-started/upgrading/from-fastmcp-2.mdx
@@ -3,7 +3,6 @@ title: Upgrading from FastMCP 2
sidebarTitle: "From FastMCP 2"
description: Migration instructions for upgrading between FastMCP versions
icon: up
-tag: NEW
---
This guide covers breaking changes and migration steps when upgrading FastMCP.
diff --git a/docs/getting-started/upgrading/from-low-level-sdk.mdx b/docs/getting-started/upgrading/from-low-level-sdk.mdx
index e2be2630e..ce4ddea75 100644
--- a/docs/getting-started/upgrading/from-low-level-sdk.mdx
+++ b/docs/getting-started/upgrading/from-low-level-sdk.mdx
@@ -3,7 +3,6 @@ title: Upgrading from the MCP Low-Level SDK
sidebarTitle: "From MCP Low-Level SDK"
description: Upgrade your MCP server from the low-level Python SDK's Server class to FastMCP
icon: up
-tag: NEW
---
If you've been building MCP servers directly on the `mcp` package's `Server` class — writing `list_tools()` and `call_tool()` handlers, hand-crafting JSON Schema dicts, and wiring up transport boilerplate — this guide is for you. FastMCP replaces all of that machinery with a declarative, Pythonic API where your functions *are* the protocol surface.
@@ -583,11 +582,11 @@ if __name__ == "__main__":
Once you've upgraded, you have access to everything FastMCP provides beyond the basics:
-- **[Server composition](/servers/providers/mounting)** — Mount sub-servers to build modular applications
+- **[Server composition](/servers/composition)** — Mount sub-servers to build modular applications
- **[Middleware](/servers/middleware)** — Add logging, rate limiting, error handling, and caching
- **[Proxy servers](/servers/providers/proxy)** — Create a proxy to any existing MCP server
- **[OpenAPI integration](/integrations/openapi)** — Generate an MCP server from an OpenAPI spec
- **[Authentication](/servers/auth/authentication)** — Built-in OAuth and token verification
-- **[Testing](/patterns/testing)** — Test your server directly in Python without running a subprocess
+- **[Testing](/servers/testing)** — Test your server directly in Python without running a subprocess
Explore the full documentation at [gofastmcp.com](https://gofastmcp.com).
diff --git a/docs/getting-started/upgrading/from-mcp-sdk.mdx b/docs/getting-started/upgrading/from-mcp-sdk.mdx
index 4d1c2ddfc..494d06bdc 100644
--- a/docs/getting-started/upgrading/from-mcp-sdk.mdx
+++ b/docs/getting-started/upgrading/from-mcp-sdk.mdx
@@ -3,7 +3,6 @@ title: Upgrading from the MCP SDK
sidebarTitle: "From MCP SDK"
description: Upgrade from FastMCP in the MCP Python SDK to the standalone FastMCP framework
icon: up
-tag: NEW
---
If your server starts with `from mcp.server.fastmcp import FastMCP`, you're using FastMCP 1.0 — the version bundled with v1 of the `mcp` package. Upgrading to the standalone FastMCP framework is easy. **For most servers, it's a single import change.**
diff --git a/docs/integrations/propelauth.mdx b/docs/integrations/propelauth.mdx
index 9b2838c3d..7f21d2010 100644
--- a/docs/integrations/propelauth.mdx
+++ b/docs/integrations/propelauth.mdx
@@ -7,7 +7,7 @@ icon: shield-check
import { VersionBadge } from "/snippets/version-badge.mdx";
-
+
This guide shows you how to secure your FastMCP server using [**PropelAuth**](https://www.propelauth.com), a complete authentication and user management solution. This integration uses the [**Remote OAuth**](/servers/auth/remote-oauth) pattern, where PropelAuth handles user login, consent management, and your FastMCP server validates the tokens.
diff --git a/docs/servers/providers/mounting.mdx b/docs/servers/composition.mdx
similarity index 60%
rename from docs/servers/providers/mounting.mdx
rename to docs/servers/composition.mdx
index 93d1acd06..42523a5cd 100644
--- a/docs/servers/providers/mounting.mdx
+++ b/docs/servers/composition.mdx
@@ -1,7 +1,7 @@
---
-title: Mounting Servers
-sidebarTitle: Mounting
-description: Compose servers by mounting one inside another
+title: Composing Servers
+sidebarTitle: Composition
+description: Combine multiple servers into one
icon: puzzle-piece
---
@@ -9,42 +9,29 @@ import { VersionBadge } from '/snippets/version-badge.mdx'
-Mounting lets you combine multiple FastMCP servers into one. When you mount a server, all its components become available through the parent. Under the hood, FastMCP uses `FastMCPProvider` (v3.0.0+) to source components from the mounted server.
+As your application grows, you'll want to split it into focused servers — one for weather, one for calendar, one for admin — and combine them into a single server that clients connect to. That's what `mount()` does.
-## Why Mount Servers
-
-Large applications benefit from modular organization. Rather than defining all components in one massive file, create focused servers for specific domains and combine them:
-
-- **Modularity**: Break down applications into smaller, focused servers
-- **Reusability**: Create utility servers and mount them wherever needed
-- **Teamwork**: Different teams can work on separate servers
-- **Organization**: Keep related functionality grouped together
-
-## Basic Mounting
-
-Use `mount()` to add another server's components to your server:
+When you mount a server, all its tools, resources, and prompts become available through the parent. The connection is live: add a tool to the child after mounting, and it's immediately visible through the parent.
```python
from fastmcp import FastMCP
-# Create focused subservers
-weather_server = FastMCP("Weather")
+weather = FastMCP("Weather")
-@weather_server.tool
+@weather.tool
def get_forecast(city: str) -> str:
"""Get weather forecast for a city."""
return f"Sunny in {city}"
-@weather_server.resource("data://cities")
+@weather.resource("data://cities")
def list_cities() -> list[str]:
"""List supported cities."""
return ["London", "Paris", "Tokyo"]
-# Create main server and mount the subserver
main = FastMCP("MainApp")
-main.mount(weather_server)
+main.mount(weather)
-# Now main has access to get_forecast and data://cities
+# main now serves get_forecast and data://cities
```
## Mounting External Servers
@@ -156,20 +143,9 @@ main.mount(calendar, namespace="calendar")
Namespacing uses [transforms](/servers/transforms/transforms) under the hood.
-## Mounting vs Importing
+## Dynamic Composition
-FastMCP offers two ways to combine servers:
-
-| Feature | `mount()` | `import_server()` |
-|---------|-----------|-------------------|
-| **Link Type** | Live (dynamic) | One-time copy (static) |
-| **Updates** | Changes reflected immediately | Changes not reflected |
-| **Performance** | Runtime delegation | Faster - no delegation |
-| **Use Case** | Modular runtime composition | Bundling finalized components |
-
-### Live Mounting
-
-With `mount()`, changes to the subserver are immediately reflected:
+Because `mount()` creates a live link, you can add components to a child server after mounting and they'll be immediately available through the parent:
```python
main = FastMCP("Main")
@@ -179,53 +155,8 @@ main.mount(dynamic_server, namespace="dynamic")
@dynamic_server.tool
def added_later() -> str:
return "Added after mounting!"
-
-# This works because mount() creates a live link
```
-### Static Importing
-
-With `import_server()`, components are copied once at import time:
-
-```python
-main = FastMCP("Main")
-
-async def setup():
- await main.import_server(static_server, namespace="static")
-
-# Changes to static_server after this point are NOT reflected in main
-```
-
-## Direct vs Proxy Mounting
-
-
-
-FastMCP supports two mounting modes:
-
-### Direct Mounting (Default)
-
-The parent server directly accesses the mounted server's objects in memory:
-
-```python
-main.mount(subserver, namespace="api")
-```
-
-- No client lifecycle events on mounted server
-- Mounted server's lifespan is not executed
-- Communication via direct method calls
-
-### Proxy Mounting
-
-
-The `as_proxy` parameter is deprecated. Mounted servers now always have their lifespan and middleware invoked. To create a proxy server explicitly, use `create_proxy()` from `fastmcp.server`.
-
-
-Previously, the parent server could treat the mounted server as a separate entity with its own lifecycle. This behavior is now the default for all mounted servers:
-
-- Full client lifecycle events on mounted server
-- Mounted server's lifespan is executed
-- Communication via in-memory Client transport
-
## Tag Filtering
@@ -253,16 +184,13 @@ prod_app.enable(tags={"production"}, only=True)
## Performance Considerations
-When using live mounting, operations like `list_tools()` on the parent server are affected by the performance of all mounted servers. This is particularly noticeable with:
+Operations like `list_tools()` on the parent are affected by the performance of all mounted servers. This is particularly noticeable with:
- HTTP-based mounted servers (300-400ms vs 1-2ms for local tools)
- Mounted servers with slow initialization
- Deep mounting hierarchies
-If low latency is critical, consider:
-- Using `import_server()` for static composition
-- Implementing caching strategies
-- Limiting mounting depth
+If low latency is critical, consider implementing caching strategies or limiting mounting depth.
## Custom Routes
diff --git a/docs/servers/middleware.mdx b/docs/servers/middleware.mdx
index 1c66fea33..40449ae10 100644
--- a/docs/servers/middleware.mdx
+++ b/docs/servers/middleware.mdx
@@ -64,7 +64,7 @@ This ordering matters. Place error handling early so it catches exceptions from
### Server Composition
-When using [mounted servers](/servers/providers/mounting), middleware behavior follows a clear hierarchy:
+When using [mounted servers](/servers/composition), middleware behavior follows a clear hierarchy:
- **Parent middleware** runs for all requests, including those routed to mounted servers
- **Mounted server middleware** only runs for requests handled by that specific server
diff --git a/docs/servers/providers/overview.mdx b/docs/servers/providers/overview.mdx
index 178a393ef..d3e3e4e5f 100644
--- a/docs/servers/providers/overview.mdx
+++ b/docs/servers/providers/overview.mdx
@@ -66,7 +66,7 @@ When a client requests a tool, FastMCP queries providers in registration order.
**You can ignore providers entirely** if you're building a simple server with decorators. Just use `@mcp.tool`, `@mcp.resource`, and `@mcp.prompt` - FastMCP handles the rest.
**Learn about providers when** you want to:
-- [Mount another server](/servers/providers/mounting) into yours
+- [Mount another server](/servers/composition) into yours
- [Proxy a remote server](/servers/providers/proxy) through yours
- [Control visibility state](/servers/visibility) of components
- [Build dynamic sources](/servers/providers/custom) like database-backed tools
@@ -74,7 +74,7 @@ When a client requests a tool, FastMCP queries providers in registration order.
## Next Steps
- [Local](/servers/providers/local) - How decorators work
-- [Mounting](/servers/providers/mounting) - Compose servers together
+- [Mounting](/servers/composition) - Compose servers together
- [Proxying](/servers/providers/proxy) - Connect to remote servers
- [Transforms](/servers/transforms/transforms) - Namespace, rename, and modify components
- [Visibility](/servers/visibility) - Control which components clients can access
diff --git a/docs/servers/providers/proxy.mdx b/docs/servers/providers/proxy.mdx
index 805cb34be..a2def6892 100644
--- a/docs/servers/providers/proxy.mdx
+++ b/docs/servers/providers/proxy.mdx
@@ -54,7 +54,7 @@ This gives you:
- Session isolation to prevent context mixing
-To mount a proxy inside another FastMCP server, see [Mounting External Servers](/servers/providers/mounting#mounting-external-servers).
+To mount a proxy inside another FastMCP server, see [Mounting External Servers](/servers/composition#mounting-external-servers).
## Transport Bridging
@@ -258,7 +258,7 @@ Proxying introduces network latency:
When mounting proxy servers, this latency affects all operations on the parent server.
-For low-latency requirements, consider using [`import_server()`](/servers/providers/mounting#static-importing) to copy tools at startup.
+For low-latency requirements, consider caching strategies or limiting mounting depth.
## Advanced Usage
diff --git a/docs/servers/testing.mdx b/docs/servers/testing.mdx
new file mode 100644
index 000000000..7bd8600c5
--- /dev/null
+++ b/docs/servers/testing.mdx
@@ -0,0 +1,104 @@
+---
+title: Testing your FastMCP Server
+sidebarTitle: Testing
+description: How to test your FastMCP server.
+icon: vial
+---
+
+The best way to ensure a reliable and maintainable FastMCP Server is to test it! The FastMCP Client combined with Pytest provides a simple and powerful way to test your FastMCP servers.
+
+## Prerequisites
+
+Testing FastMCP servers requires `pytest-asyncio` to handle async test functions and fixtures. Install it as a development dependency:
+
+```bash
+pip install pytest-asyncio
+```
+
+We recommend configuring pytest to automatically handle async tests by setting the asyncio mode to `auto` in your `pyproject.toml`:
+
+```toml
+[tool.pytest.ini_options]
+asyncio_mode = "auto"
+```
+
+This eliminates the need to decorate every async test with `@pytest.mark.asyncio`.
+
+## Testing with Pytest Fixtures
+
+Using Pytest Fixtures, you can wrap your FastMCP Server in a Client instance that makes interacting with your server fast and easy. This is especially useful when building your own MCP Servers and enables a tight development loop by allowing you to avoid using a separate tool like MCP Inspector during development:
+
+```python
+import pytest
+from fastmcp.client import Client
+from fastmcp.client.transports import FastMCPTransport
+
+from my_project.main import mcp
+
+@pytest.fixture
+async def main_mcp_client():
+ async with Client(transport=mcp) as mcp_client:
+ yield mcp_client
+
+async def test_list_tools(main_mcp_client: Client[FastMCPTransport]):
+ list_tools = await main_mcp_client.list_tools()
+
+ assert len(list_tools) == 5
+```
+
+We recommend the [inline-snapshot library](https://github.com/15r10nk/inline-snapshot) for asserting complex data structures coming from your MCP Server. This library allows you to write tests that are easy to read and understand, and are also easy to update when the data structure changes.
+
+```python
+from inline_snapshot import snapshot
+
+async def test_list_tools(main_mcp_client: Client[FastMCPTransport]):
+ list_tools = await main_mcp_client.list_tools()
+
+ assert list_tools == snapshot()
+```
+
+Simply run `pytest --inline-snapshot=fix,create` to fill in the `snapshot()` with actual data.
+
+
+For values that change you can leverage the [dirty-equals](https://github.com/samuelcolvin/dirty-equals) library to perform flexible equality assertions on dynamic or non-deterministic values.
+
+
+Using the pytest `parametrize` decorator, you can easily test your tools with a wide variety of inputs.
+
+```python
+import pytest
+from my_project.main import mcp
+
+from fastmcp.client import Client
+from fastmcp.client.transports import FastMCPTransport
+@pytest.fixture
+async def main_mcp_client():
+ async with Client(mcp) as client:
+ yield client
+
+
+@pytest.mark.parametrize(
+ "first_number, second_number, expected",
+ [
+ (1, 2, 3),
+ (2, 3, 5),
+ (3, 4, 7),
+ ],
+)
+async def test_add(
+ first_number: int,
+ second_number: int,
+ expected: int,
+ main_mcp_client: Client[FastMCPTransport],
+):
+ result = await main_mcp_client.call_tool(
+ name="add", arguments={"x": first_number, "y": second_number}
+ )
+ assert result.data is not None
+ assert isinstance(result.data, int)
+ assert result.data == expected
+```
+
+
+The [FastMCP Repository contains thousands of tests](https://github.com/PrefectHQ/fastmcp/tree/main/tests) for the FastMCP Client and Server. Everything from connecting to remote MCP servers, to testing tools, resources, and prompts is covered, take a look for inspiration!
+
\ No newline at end of file