diff --git a/fern/docs.yml b/fern/docs.yml
index d6dbf4896..d06132efe 100644
--- a/fern/docs.yml
+++ b/fern/docs.yml
@@ -51,6 +51,14 @@ products:
slug: cli-generator
subtitle: Generate a CLI from your API definition
+ # TODO(design): placeholder icon/image reused from CLI Generator — swap in real MCP Generator artwork before this ships publicly.
+ - display-name: MCP Generator
+ path: ./products/mcp-generator/mcp-generator.yml
+ icon: fa-regular fa-robot
+ image: ./images/product-switcher/product-switcher-cli-generator-light.png
+ slug: mcp-generator
+ subtitle: Generate an MCP server from your API definition
+
- display-name: Docs
path: ./products/docs/docs.yml
icon: fa-regular fa-browser
diff --git a/fern/products/mcp-generator/authentication.mdx b/fern/products/mcp-generator/authentication.mdx
new file mode 100644
index 000000000..9bf436eca
--- /dev/null
+++ b/fern/products/mcp-generator/authentication.mdx
@@ -0,0 +1,39 @@
+---
+title: Authentication
+description: How your API's security schemes become the environment variables an MCP server reads at startup.
+availability: beta
+---
+
+The generated MCP server doesn't need a separate auth configuration. It reads one environment variable per security scheme declared under your spec's `components.securitySchemes` and forwards it as the corresponding header on every request that needs it.
+
+## How the variable name is derived
+
+The variable's base name is the security scheme's key, upper-snake-cased. A scheme named `widgetKey` becomes `WIDGET_KEY`; a scheme named `apiToken` becomes `API_TOKEN`.
+
+- **HTTP Basic** schemes get two variables: `{BASE}_USERNAME` and `{BASE}_PASSWORD`.
+- Every other scheme type — API key, bearer token, another HTTP scheme — gets one: `{BASE}` itself.
+
+A scheme named `basicAuth` with type `http`/`basic`, for example, produces `BASIC_AUTH_USERNAME` and `BASIC_AUTH_PASSWORD`.
+
+Generation fails if a scheme's derived base isn't a legal environment variable name, or if it collides with another scheme's base or with one of the two reserved names, `BASE_URL` or `MCP_TOOLSET` — so a naming conflict surfaces at generation time instead of as a runtime mystery.
+
+## Always-present variables
+
+Every generated server also reads:
+
+- **`BASE_URL`** — the API's base URL.
+- **`MCP_TOOLSET`** — selects which [toolset or preset](/learn/mcp-generator/get-started/configuration#presets) the server exposes at startup. Its description lists every valid value: `default`, plus whatever you've configured.
+
+Because these two names are reserved, no security scheme in your spec can be named `baseUrl` or `mcpToolset` — rename the scheme if it collides.
+
+## Where the description comes from
+
+Each environment variable's description comes from the security scheme's own OpenAPI `description`, when you've written one. Otherwise the generator fills in a fallback naming the credential type, such as "Credential for the widgetKey security scheme (API key)."
+
+## Missing credentials
+
+Every environment variable is optional at startup, so the server always starts even with none set. A tool call that needs a credential you haven't set fails when it's made, not before. [`fern mcp dev`](/learn/mcp-generator/get-started/local-development) checks for this up front: it detects which credentials the toolset you're running actually needs and prints the exact `export` command for anything missing, instead of leaving you to debug a 401.
+
+## Current limits
+
+OAuth client-credentials schemes aren't supported as a server's only auth source — the generated server has no token-acquisition flow to run, so generation fails outright if every security scheme your spec declares is OAuth client-credentials. Add an API key or bearer scheme for the endpoints an MCP client should reach, or [scope the toolset](/learn/mcp-generator/get-started/tool-selection) away from the ones that require it.
diff --git a/fern/products/mcp-generator/configuration.mdx b/fern/products/mcp-generator/configuration.mdx
new file mode 100644
index 000000000..554a0a4b7
--- /dev/null
+++ b/fern/products/mcp-generator/configuration.mdx
@@ -0,0 +1,149 @@
+---
+title: Configuration reference
+description: Configure MCP server generation in generators.yml — server identity, tool selection, and per-tool overrides.
+availability: beta
+---
+
+Configure the MCP generator in `generators.yml`. Options nested under `config` are specific to the MCP generator. The rest (`output`, `github`, `audiences`, `smart-casing`, `metadata`, `api`) behave the same way as for [SDK generators](/learn/sdks/reference/generators-yml).
+
+```yaml title="generators.yml" {6-21}
+groups:
+ mcp:
+ generators:
+ - name: fernapi/fern-mcp-server
+ version: 0.1.0
+ config:
+ server-name: acme-public-api
+ instructions: >-
+ Refunds must stay under $100.
+ tools:
+ intent: >-
+ Support agents look up customers/payments, refunds under $100, no admin.
+ mode: static
+ budget: { max-tools: 40, max-tokens: 60000 }
+ include:
+ - { tag: payments, method: GET }
+ - { tag: customers, method: GET }
+ - { path-prefix: /v1/refunds }
+ exclude:
+ - { tag: internal }
+ overrides:
+ POST /v1/payments:
+ name: create_payment
+ description: "Create a payment. Amounts are in minor units."
+ response-fields: [id, status, amount]
+ output:
+ location: npm
+ package-name: "@acme/mcp"
+ github:
+ repository: acme/acme-mcp
+ mode: pull-request
+```
+
+## `config` options
+
+
+Name shown in an MCP client's server list, and the basis for the generated package name. Defaults to the API definition's display name (kebab-cased) with `-mcp` appended.
+
+
+
+Server-level instructions passed to MCP clients on connect — the same role a system prompt plays for a model, scoped to this server. Anything the [AI-curated preset](/learn/mcp-generator/get-started/tool-selection#ai-curated-rulesets) can't express as a tool selector, like a spending limit or an escalation rule, is written here.
+
+```yaml
+config:
+ instructions: "Refunds must stay under $100; escalate anything larger."
+```
+
+
+## `tools` options
+
+These options live under `config.tools` in `generators.yml`.
+
+
+Free-text description of what the MCP should let an agent do, stored verbatim. Set by the [AI-curated preset](/learn/mcp-generator/get-started/tool-selection#ai-curated-rulesets); a later `fern mcp tools --refine --ai` re-runs against this stored intent to propose rule updates once the spec changes, instead of asking you to restate what the server is for.
+
+
+
+`static` generates one tool per matched endpoint. `dynamic` collapses the toolset into three meta-tools — list, describe, invoke — covered under [dynamic mode](/learn/mcp-generator/get-started/tool-selection#presets). Set by hand or via the Refine loop; it isn't offered as a top-level preset.
+
+
+
+Overrides the default [budget verdict](/learn/mcp-generator/get-started/tool-selection#the-budget-verdict) thresholds for this group.
+
+
+
+Tool count above which `fern mcp init` and `fern mcp tools` score the toolset amber. More than 3 times this value scores red.
+
+
+Estimated token cost above which the toolset scores amber. More than 3 times this value scores red.
+
+
+
+
+Endpoints to expose as tools. Entries are OR'd together; fields within a single entry are AND'd. Omit `include` to start from every endpoint the spec exposes.
+
+```yaml
+config:
+ tools:
+ include:
+ - { tag: payments, method: GET } # read-only payments
+ - { path-prefix: /v1/refunds } # coarse cut — the primary unit for untagged specs
+ - { operation-id: "payments_*" } # glob
+ - { endpoint: POST /v1/refunds } # a literal endpoint — the escape hatch
+```
+
+Each entry supports `tag`, `method`, `path-prefix`, `operation-id` (glob), and `endpoint` (a literal `METHOD /path`). Prefer the others over `endpoint` so a selection keeps matching as the spec evolves instead of freezing a list of paths.
+
+
+
+Endpoints to drop from the resolved toolset, using the same selector shape as `include`. `exclude` always wins over `include`.
+
+```yaml
+config:
+ tools:
+ exclude:
+ - { tag: internal }
+ - { method: DELETE }
+```
+
+
+
+Per-tool polish, keyed by `METHOD /path`.
+
+
+
+Overrides the generated tool name.
+
+
+Overrides the generated tool description.
+
+
+Overrides the generated `readOnlyHint` MCP annotation.
+
+
+Overrides the generated `destructiveHint` MCP annotation.
+
+
+Restricts the tool's response to the named fields, dropping the rest before it reaches the agent. The [Refine loop](/learn/mcp-generator/get-started/tool-selection#refining-an-over-budget-toolset) writes this automatically when you project down an oversized response.
+
+
+Marks the tool deprecated in its description instead of removing it — the migration path for a [published server](/learn/mcp-generator/get-started/maintaining#breaking-change-handling) when removing the tool outright would break existing agent integrations.
+
+
+
+
+Named subsets of the group's resolved toolset, using the same selector schema as `include`/`exclude`. A client can connect to one preset instead of the whole server, and each preset gets its own verdict in `fern mcp tools`.
+
+```yaml
+config:
+ tools:
+ presets:
+ read-only:
+ include: [{ method: GET }]
+ support:
+ intent: "support agents: lookups + refunds, no admin"
+ include: [{ tag: customers }, { tag: payments, method: GET }]
+```
+
+A preset defined here is the same object the dashboard's preset picker edits — changing one updates the other.
+
diff --git a/fern/products/mcp-generator/local-development.mdx b/fern/products/mcp-generator/local-development.mdx
new file mode 100644
index 000000000..3e749b663
--- /dev/null
+++ b/fern/products/mcp-generator/local-development.mdx
@@ -0,0 +1,69 @@
+---
+title: Local development
+description: Build, inspect, and connect a generated MCP server to Claude, Cursor, or Codex.
+availability: beta
+---
+
+## Run the inspector
+
+```bash
+fern mcp dev --group mcp
+```
+
+`fern mcp dev` builds the group's server and attaches the [MCP inspector](https://modelcontextprotocol.io/legacy/tools/inspector), so you can call tools directly and check their input schemas and responses before wiring up a real client. If the toolset you're running needs a credential you haven't [set](/learn/mcp-generator/get-started/authentication), it prints the exact `export` command instead of starting a server where every call fails.
+
+## Build and run manually
+
+Every generated project also builds and runs as a standalone Node package, without the inspector:
+
+```bash
+cd path/to/generated/mcp
+npm run setup # installs dependencies and builds
+npm start # runs the server over stdio
+```
+
+Node 20 or later is required.
+
+## Connect a client
+
+```bash
+fern mcp install --local --group mcp
+```
+
+This wires the generated server into your local Claude, Cursor, or Codex configuration, pointing at the built `dist/index.js` and filling in the environment variables it needs.
+
+To wire it up by hand instead, every generated project's README includes the client config as JSON:
+
+```json
+{
+ "mcpServers": {
+ "acme-public-api": {
+ "command": "node",
+ "args": ["/absolute/path/to/dist/index.js"],
+ "env": {
+ "WIDGET_KEY": "",
+ "BASE_URL": ""
+ }
+ }
+ }
+}
+```
+
+and, for Claude Code specifically, a ready-to-run install command:
+
+```bash
+claude mcp add acme-public-api --env WIDGET_KEY= --env BASE_URL= -- node "/absolute/path/to/dist/index.js"
+```
+
+The client starts the server itself over stdio the first time it needs it — there's no separate process to keep running or port to open.
+
+## Next steps
+
+
+
+ Regenerate on spec changes and catch breaking tool changes before you publish.
+
+
+ Generate separate MCP servers for different audiences from one spec.
+
+
diff --git a/fern/products/mcp-generator/maintaining.mdx b/fern/products/mcp-generator/maintaining.mdx
new file mode 100644
index 000000000..80cccec45
--- /dev/null
+++ b/fern/products/mcp-generator/maintaining.mdx
@@ -0,0 +1,61 @@
+---
+title: Maintaining MCP servers
+description: Regenerate on spec changes, catch breaking tool changes before you publish, and keep a published server's toolset stable.
+availability: beta
+---
+
+Maintaining a generated MCP server follows the same loop as an SDK — edit config, regenerate — with a few commands on top for a surface an SDK doesn't have: a live toolset that downstream agents depend on staying stable.
+
+| Command | What it does |
+|---|---|
+| `fern mcp list` | Table of every configured MCP group: server name, presets, tool count, token estimate, output target, and toolset overlaps with other groups. |
+| `fern mcp tools [--group g] [--preset p]` | Resolved toolset for a group, with per-tool token cost, the [budget verdict](/learn/mcp-generator/get-started/tool-selection#the-budget-verdict), and a quality lint (missing or derived-from-junk descriptions, tool name collisions, ambiguous near-duplicate tools, oversized responses). `--refine` opens the mutation loop; `--diff` compares the resolved toolset against `tools.lock`. |
+| `fern generate --group g` | Regenerates the server from the current config and spec, same as any other generator. |
+| `fern generator upgrade` | Upgrades the pinned generator version, same as for SDKs. |
+| `fern check` | Validates config, including the [MCP-specific rules](#fern-check-rules). |
+
+## `tools.lock`
+
+`fern generate` writes a `tools.lock` file next to `generators.yml` — the resolved tool names, input schema hashes, and token costs for that group, at that generation. It's the baseline `fern mcp tools --diff` compares against, and the artifact that makes a breaking-change classification reviewable in a pull request alongside the config change that caused it.
+
+## Breaking-change handling
+
+A renamed or removed tool breaks any agent already integrated against it — a worse failure than a breaking SDK change, because nobody recompiles an agent's tool list. `fern mcp tools --diff` classifies every delta against `tools.lock`:
+
+- **Additive** — a new tool, or a longer/clarified description.
+- **Breaking** — a tool removed or renamed, a required parameter added, response fields dropped, or the server's identity changed (`server-name` or package name, on a group that's already published).
+
+A breaking delta produces a `fern check` warning and a major-version-bump recommendation on publish; an additive one recommends a minor bump. This release detects and warns — it doesn't prevent a breaking change from generating or publishing.
+
+To retire a tool without breaking existing integrations immediately, mark it deprecated instead of removing it:
+
+```yaml
+config:
+ tools:
+ overrides:
+ POST /v1/charges:
+ deprecated: true
+```
+
+This keeps the tool available but marks it deprecated in its description, giving downstream agents a migration window instead of an outage.
+
+## `fern check` rules
+
+Beyond the general SDK checks, `fern check` also flags, for MCP groups:
+
+- A [budget](/learn/mcp-generator/get-started/tool-selection#the-budget-verdict) warning.
+- An `include`/`exclude` selector that matches nothing.
+- A destructive endpoint with no `destructive` annotation override.
+- A new spec endpoint matching no configured group.
+- An **orphaned override** — an `overrides` entry keyed to an endpoint no longer in the spec, so a hand-written description doesn't just silently stop applying.
+- A `server-name` or package rename on an already-published group, which `tools --diff` can't see on its own since it compares tools, not identity.
+- A `response-fields` projection set under a generator version that doesn't support it.
+
+All of these print as warnings, not blockers, in CI and `--json` output.
+
+## Updating a server
+
+- **Spec changed** — regenerate; `fern mcp tools --diff` reports what moved.
+- **Renaming or pruning tools** — edit `overrides` or `exclude`, then regenerate.
+- **New generator version** — `fern generator upgrade`.
+- **Publishing** — the same `github` and npm output blocks, and the same autorelease infrastructure, as SDK generators.
diff --git a/fern/products/mcp-generator/mcp-generator.yml b/fern/products/mcp-generator/mcp-generator.yml
new file mode 100644
index 000000000..5e9fafcf2
--- /dev/null
+++ b/fern/products/mcp-generator/mcp-generator.yml
@@ -0,0 +1,27 @@
+navigation:
+ - section: Get started
+ contents:
+ - page: Overview
+ path: ./overview.mdx
+ slug: overview
+ - page: Quickstart
+ path: ./quickstart.mdx
+ slug: quickstart
+ - page: Tool selection
+ path: ./tool-selection.mdx
+ slug: tool-selection
+ - page: Multiple servers
+ path: ./multiple-servers.mdx
+ slug: multiple-servers
+ - page: Local development
+ path: ./local-development.mdx
+ slug: local-development
+ - page: Maintaining MCP servers
+ path: ./maintaining.mdx
+ slug: maintaining
+ - page: Authentication
+ path: ./authentication.mdx
+ slug: authentication
+ - page: Configuration reference
+ path: ./configuration.mdx
+ slug: configuration
diff --git a/fern/products/mcp-generator/multiple-servers.mdx b/fern/products/mcp-generator/multiple-servers.mdx
new file mode 100644
index 000000000..166746211
--- /dev/null
+++ b/fern/products/mcp-generator/multiple-servers.mdx
@@ -0,0 +1,53 @@
+---
+title: Multiple servers
+description: Generate separate MCP servers for different audiences from one API definition.
+availability: beta
+---
+
+One spec can back more than one MCP server. Add another group with its own `tools` filter, and `fern generate` builds each independently:
+
+```yaml title="generators.yml"
+groups:
+ mcp-payments:
+ generators:
+ - name: fernapi/fern-mcp-server
+ config:
+ server-name: acme-payments
+ tools:
+ include: [{ tag: payments }]
+ mcp-admin:
+ generators:
+ - name: fernapi/fern-mcp-server
+ config:
+ server-name: acme-admin
+ tools:
+ include: [{ tag: admin }]
+```
+
+`fern mcp init` always adds a new group; it never mutates an existing one. `fern mcp tools --refine --group ` is the mutation path for a group already written.
+
+Two endpoints can appear in more than one group's toolset — `fern mcp list` reports the overlap as information, not a warning. When a spec grows a new endpoint, it lands in whichever group's rules match; `fern check` warns if a new endpoint matches none of them, so nothing silently falls through the cracks.
+
+## Groups vs. presets
+
+Groups and [presets](/learn/mcp-generator/get-started/configuration#presets) both narrow a toolset, but for different reasons:
+
+- A **group** is a separately generated and published server — its own npm package, its own GitHub repo, its own version.
+- A **preset** is a named subset of one group's toolset that a client can connect to directly — one deploy, several audiences.
+
+Reach for multiple groups when the audiences need different deployments (an internal admin server your public one shouldn't ship). Reach for presets when one deployment is enough and you just want to hand different clients a narrower slice of it. Small APIs typically need neither; large ones mostly need presets before they need multiple groups.
+
+## Splitting by audience with AI-curated
+
+If your intent describes more than one distinct audience, the [AI-curated preset](/learn/mcp-generator/get-started/tool-selection#ai-curated-rulesets) proposes a group per audience instead of one ruleset:
+
+```txt
+✦ This API serves 3 distinct audiences. Proposed split:
+│ acme-support (24 tools · 15k) customers, payments read + refunds
+│ acme-admin (18 tools · 12k) admin tag, destructive ops — internal only
+│ acme-reporting (11 tools · 9k) read-only analytics
+│
+◆ Accept all / Accept some / Merge into one / Adjust…
+```
+
+Accepting writes each proposed group in one pass, with its own `tools.intent`.
diff --git a/fern/products/mcp-generator/overview.mdx b/fern/products/mcp-generator/overview.mdx
new file mode 100644
index 000000000..f8807ed1f
--- /dev/null
+++ b/fern/products/mcp-generator/overview.mdx
@@ -0,0 +1,38 @@
+---
+title: MCP generator
+description: "Generate an MCP server from your API definition that exposes your endpoints as tools for AI agents."
+availability: beta
+---
+
+
+The MCP generator is in early access. [Reach out](https://buildwithfern.com/book-demo?type=mcp) to get started.
+
+
+Fern's MCP generator turns your API definition into a [Model Context Protocol](https://modelcontextprotocol.io) server: a project where every endpoint becomes a typed tool that Claude, Cursor, and other MCP clients can call directly. It shares the same spec, `generators.yml`, and generation pipeline as your SDKs and CLI — an MCP server is just another generator output, configured as a [group](/learn/mcp-generator/get-started/quickstart) like any other.
+
+## How it works
+
+The generator walks your OpenAPI operations and emits one tool per endpoint, with a name, description, and JSON Schema input derived from the operation's parameters and request body. Security schemes become environment variables the server [reads at startup](/learn/mcp-generator/get-started/authentication), and each tool carries MCP annotations (`readOnlyHint`, `destructiveHint`, and similar) derived from its HTTP method, so an agent can reason about which calls are safe without inspecting the implementation. The output runs over stdio: an MCP client launches it as a subprocess and talks to it on stdin/stdout, so there's nothing to host or expose a port for.
+
+Not every operation becomes a tool. Endpoints with a non-JSON request body, or a required query parameter with a serialization style tools can't express, are skipped and recorded — with the reason — in the generated project's `metadata.json`, so you can see what got left out without reading the diff.
+
+## Curating the toolset
+
+Unlike an SDK, where exposing every endpoint is normal, an MCP server that hands an agent 300 tools is worse than one with 30 — agents spend context distinguishing similar-sounding tools, take more turns to find the right one, and are more likely to invoke something destructive by accident. [Tool selection](/learn/mcp-generator/get-started/tool-selection) is a first-class part of setting up an MCP server: `fern mcp init` diagnoses your spec's cost up front and helps you narrow it by tag, method, path, or description before you generate anything.
+
+## Next steps
+
+
+
+ Generate an MCP server from an OpenAPI spec and connect it to an agent.
+
+
+ Curate which endpoints become tools and stay within a token budget.
+
+
+ Every field available under a group's MCP generator entry.
+
+
+ How security schemes become environment variables.
+
+
diff --git a/fern/products/mcp-generator/quickstart.mdx b/fern/products/mcp-generator/quickstart.mdx
new file mode 100644
index 000000000..353c55bed
--- /dev/null
+++ b/fern/products/mcp-generator/quickstart.mdx
@@ -0,0 +1,119 @@
+---
+title: Quickstart
+description: Generate an MCP server from an OpenAPI spec and connect it to an agent in a few minutes.
+availability: beta
+---
+
+
+The MCP generator is in early access. [Reach out](https://buildwithfern.com/book-demo?type=mcp) to get started.
+
+
+This guide generates an MCP server from an OpenAPI spec, curates its toolset, and runs it locally against an inspector.
+
+
+Generate an MCP server from an OpenAPI specification with Fern. Follow the [MCP generator quickstart](https://buildwithfern.com/learn/mcp-generator/get-started/quickstart.md) step by step.
+
+
+## Prerequisites
+
+- The Fern CLI (`npm install -g fern-api`)
+- An OpenAPI 3.x spec with at least one endpoint
+- Node.js 20 or later to build and run the generated server locally
+
+
+
+
+
+
+
+Any `securitySchemes` declared under your spec's `components` become the environment variables the generated server [reads at startup](/learn/mcp-generator/get-started/authentication) — the wizard doesn't ask about them.
+
+```bash
+fern mcp init
+```
+
+The wizard resolves every preset against your spec up front, so each option shows its tool count and estimated token cost before you pick one:
+
+```txt
+┌ Create an MCP server
+│
+◆ Server name
+│ swagger-petstore-openapi-3-0-mcp
+│
+◆ Which tools should this server expose?
+│ ● Read-only — lookups and searches, nothing that writes
+│ 8 tools · 2k tokens — ✓ within budget
+│ ○ Main resources — pet, user, store (detected from your spec)
+│ 19 tools · 4k tokens — ✓ within budget
+│ ○ AI-curated — Fern Agent picks tools from your description (requires fern login)
+│ ○ Everything — all 19 endpoints
+│ 19 tools · 4k tokens — ✓ within budget
+│
+└ Wrote group "mcp" to fern/generators.yml
+```
+
+A preset that comes back over budget routes into a [Refine loop](/learn/mcp-generator/get-started/tool-selection#refining-an-over-budget-toolset) to narrow it before anything is written. Non-interactively, `fern mcp init -y` accepts the read-only preset and writes the group without prompting; `--name`, `--preset`, `--group`, and `--dry-run` control it from a script or CI.
+
+
+
+
+```yaml title="fern/generators.yml"
+groups:
+ mcp:
+ generators:
+ - name: fernapi/fern-mcp-server
+ version: 0.1.0
+ output:
+ location: local-file-system
+ path: ../generated/mcp
+ config:
+ server-name: swagger-petstore-openapi-3-0-mcp
+ tools:
+ include:
+ - tag: pet
+ - tag: user
+ - tag: store
+```
+
+`tools.include` and `tools.exclude` accept tags, methods, path prefixes, operation ID globs, and literal endpoints — the [configuration reference](/learn/mcp-generator/get-started/configuration) covers every field a group can set, and [tool selection](/learn/mcp-generator/get-started/tool-selection) covers how each preset maps to these selectors.
+
+
+
+
+```bash
+fern generate --group mcp
+```
+
+Fern reads the OpenAPI spec, runs the MCP generator, and writes a TypeScript project to the output path: one file per tool, a manifest that ties tool names to their handlers, a README with client setup instructions, and a `metadata.json` summary of what was generated — and what was skipped, and why.
+
+
+
+
+```bash
+fern mcp dev --group mcp
+```
+
+This builds the server and attaches an MCP inspector so you can call tools directly before wiring up a real client. If a required credential is missing, `fern mcp dev` prints the exact `export` command instead of starting a server where every call fails.
+
+
+
+
+## Next steps
+
+
+
+ Curate the toolset by tag, method, path, or description.
+
+
+ Run the inspector and connect the server to Claude, Cursor, or Codex.
+
+
+ Generate separate MCP servers for different audiences from one spec.
+
+
+ Every field available under a group's MCP generator entry.
+
+
diff --git a/fern/products/mcp-generator/tool-selection.mdx b/fern/products/mcp-generator/tool-selection.mdx
new file mode 100644
index 000000000..1826bf9c2
--- /dev/null
+++ b/fern/products/mcp-generator/tool-selection.mdx
@@ -0,0 +1,98 @@
+---
+title: Tool selection
+description: Curate which endpoints become tools, and keep the toolset within a token budget agents can handle.
+availability: beta
+---
+
+An MCP server that exposes 300 tools is worse than one that exposes 30: agents spend context distinguishing similar-sounding tools, take more turns to find the right one, and are more likely to call something destructive by accident. Curating the toolset — not just generating one — is the part of setting up an MCP server that an SDK never needed.
+
+## The budget verdict
+
+`fern mcp init` and `fern mcp tools` score every toolset against two independent thresholds — tool count and estimated token cost — and report the worse of the two:
+
+| Clause | Green | Amber | Red |
+|---|---|---|---|
+| Tool count | ≤ 40 | 41 – 120 | > 120 |
+| Token cost (estimated) | ≤ 60k | 60k – 180k | > 180k |
+
+Token figures are always labeled as estimates; when a cost can't be computed for a given tool, the verdict falls back to scoring tool count alone. The thresholds are configurable per group:
+
+```yaml title="generators.yml"
+config:
+ tools:
+ budget:
+ max-tools: 40
+ max-tokens: 60000
+```
+
+An amber or red verdict doesn't block generation. Interactively, it routes into the [Refine loop](#refining-an-over-budget-toolset); in a script or CI (`--json`, non-interactive `fern mcp init -y`), it prints as a warning instead.
+
+## Presets
+
+`fern mcp init` resolves every preset against your spec up front, so each option's cost is visible before you pick one:
+
+- **Read-only** — every `GET` endpoint, plus read-like `POST` endpoints the wizard detects from naming conventions (`search*`, `list_*`, and similar — common for search or query operations hidden behind `POST`). When detection is ambiguous, the endpoint is excluded and the wizard tells you to review it with `fern mcp tools` rather than guessing.
+- **Main resources** — one `include` entry per primary tag, with administrative and internal tags excluded. Grayed out on specs with no usable tags, where [untagged spec handling](#specs-without-tags) applies instead.
+- **AI-curated** — describe what the MCP should let an agent do, and [Fern Agent](/learn/docs/fern-agent) proposes a ruleset. Requires `fern login`; falls back to the heuristic presets if you're logged out.
+- **Everything** — every endpoint becomes a tool, unfiltered.
+
+Picking a preset writes the same declarative rules you'd write by hand — tags, methods, path prefixes, operation ID globs, or literal endpoints, detailed under [`include`](/learn/mcp-generator/get-started/configuration#include) in the configuration reference — so the toolset survives spec changes instead of freezing a list of endpoint names.
+
+A **dynamic mode** is also available (`tools.mode: dynamic`), which collapses the toolset into three meta-tools — list, describe, and invoke — instead of one tool per endpoint. It isn't offered as a preset: agents do measurably worse against meta-tools than direct, named tools, since tool names and descriptions carry most of the signal an agent uses to pick correctly. Reach for it only as a last resort for a spec too large to narrow any other way, or set it by hand.
+
+## Refining an over-budget toolset
+
+`fern mcp tools --refine` opens the same loop `fern mcp init` routes into automatically on an amber or red verdict. It lists the highest-cost tools with a reason, then offers to narrow the toolset, project down oversized responses, or accept the toolset as-is — re-scoring the verdict after every change:
+
+```txt
+Verdict: 112 tools · 94k tokens — ⚠ ~3x over budget (both clauses)
+
+Highest-cost tools:
+ get_report_bundle 11k tokens oversized response schema
+ search_transactions 7k tokens 34 parameters
+
+◆ Refine?
+│ ● Narrow rules… # tags, methods, path prefixes
+│ ○ Filter oversized responses (project fields)…
+│ ○ Switch to dynamic mode (3 list/describe/invoke meta-tools)
+│ ○ Accept as-is
+```
+
+Narrowing writes compound selectors where they express the intent — `{ tag: reports, method: GET }` for "read-only reports" — rather than an enumerated endpoint list. Response-field projection keeps a tool but restricts its response to the fields you name, via `overrides..response-fields` in the [configuration reference](/learn/mcp-generator/get-started/configuration#overrides). "Switch to dynamic mode" writes `tools.mode: dynamic` as a stated trade-off, not a silent one.
+
+`--refine` mutates an existing group's config in place. `fern mcp init` always adds a new group and never mutates one — the two commands are deliberately disjoint.
+
+## AI-curated rulesets
+
+The AI-curated preset takes one free-text description and proposes a ruleset conversationally:
+
+```txt
+◆ Describe what this MCP should let an agent do (and anything it must never touch)
+│ > Let support agents look up customers and payments, issue refunds under
+│ $100, never touch admin or delete anything
+
+✦ Proposed ruleset (exclusions first — that's the part worth reviewing):
+│ exclude:
+│ - { tag: admin } # "never touch admin"
+│ - { method: DELETE } # "never delete anything"
+│ include:
+│ - { tag: customers, method: GET }
+│ - { tag: payments, method: GET }
+│ - { endpoint: POST /v1/refunds }
+│ instructions: "Refunds must stay under $100; escalate anything larger."
+│
+│ Verdict: 21 tools · 14k tokens — ✓ within budget
+│
+◆ Accept / Adjust (describe the change) / Start over / Switch to manual
+```
+
+The proposal leads with what it excluded, since a 20-tool include list is hard to eyeball but an exclusion list is easy to verify against what you asked for. Anything the model can't express as a selector — a spending limit, an escalation rule — is written into the server's `instructions` field or a per-tool `overrides` description instead of silently dropped. The output is always the same declarative rules any other preset writes: reviewable, diffable, and safe to hand-edit afterward. Run it non-interactively with `fern mcp init --preset ai --intent "support agents, refunds under $100, no admin"`.
+
+## Specs without tags
+
+Many real specs have no tags, junk operation IDs, and no descriptions — often the specs that need curation the most. When a spec has no usable tags:
+
+- The diagnosis says so up front: `312 endpoints · no tags — grouping by path prefix`.
+- Refine's narrowing offers path prefixes (`/v1/payments/*`) instead of tags.
+- The AI-curated preset is promoted as the primary option, since inferring groupings and writing tool names and descriptions is where it earns its keep on a spec like this.
+- `fern mcp tools` flags tool names derived from junk operation IDs (`post_v1_pmt_x2`) so you know where to add an `overrides` entry.