From c8e2aeddce8f73a51a7b197c237bfbafaa0dadfb Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Tue, 4 Nov 2025 17:34:37 +0000 Subject: [PATCH 1/4] docs: add JWT authentication flow for protected endpoints Co-Authored-By: kenny@buildwithfern.com --- .../pages/getting-started/api-get-started.mdx | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/fern/products/ask-fern/pages/getting-started/api-get-started.mdx b/fern/products/ask-fern/pages/getting-started/api-get-started.mdx index ea3d4616a..52f97b630 100644 --- a/fern/products/ask-fern/pages/getting-started/api-get-started.mdx +++ b/fern/products/ask-fern/pages/getting-started/api-get-started.mdx @@ -14,3 +14,31 @@ The Fern AI API allows you to manage your Ask Fern configuration using Fern's pu ## Authentication Fern API requests require a bearer token for authentication. Use the CLI command [`fern token`](/learn/cli-api/cli-reference/commands#fern-token) to generate a bearer token. Tokens do not expire. + +### JWT authentication flow + +For accessing protected documentation endpoints, you can exchange a Fern API key for a JWT token: + +1. Generate and export your Fern API key: + +```bash +fern generate token +export FERN_API_KEY= +``` + +2. Request a JWT from the authentication endpoint: + +```bash +export JWT=$(curl -X GET https://docs.example.com/api/fern-docs/get-jwt \ + -H "FERN_API_KEY:${FERN_API_KEY}" \ + -H 'x-fern-host: docs.example.com') +``` + +3. Use the JWT to access protected endpoints: + +```bash +curl -X GET https://docs.example.com/api/endpoint \ + -H 'Accept: text/plain' \ + -H 'x-fern-host: docs.example.com' \ + -H "FERN_TOKEN: ${JWT}" +``` From cf33cb211ab0a5de50a438adcd4d113d1e9f63aa Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Tue, 4 Nov 2025 19:04:32 +0000 Subject: [PATCH 2/4] docs: add MCP server API reference with OpenAPI spec - Create new MCP server documentation page under Ask Fern features - Add comprehensive API reference for get-jwt and search/v2/key endpoints - Include OpenAPI 3.1 specification with downloadable YAML file - Update navigation to include MCP server page - Replace JWT auth flow in api-get-started.mdx with link to MCP docs Co-Authored-By: kenny@buildwithfern.com --- fern/apis/fern-docs-mcp/openapi.yaml | 149 ++++++++ fern/products/ask-fern/ask-fern.yml | 2 + .../ask-fern/pages/features/mcp-server.mdx | 327 ++++++++++++++++++ .../pages/getting-started/api-get-started.mdx | 28 +- 4 files changed, 479 insertions(+), 27 deletions(-) create mode 100644 fern/apis/fern-docs-mcp/openapi.yaml create mode 100644 fern/products/ask-fern/pages/features/mcp-server.mdx diff --git a/fern/apis/fern-docs-mcp/openapi.yaml b/fern/apis/fern-docs-mcp/openapi.yaml new file mode 100644 index 000000000..b8d35ac46 --- /dev/null +++ b/fern/apis/fern-docs-mcp/openapi.yaml @@ -0,0 +1,149 @@ +openapi: 3.1.0 +info: + title: Fern Docs MCP API + version: 1.0.0 + description: API endpoints for MCP agents to authenticate and search Fern documentation sites. + +servers: + - url: https://docs.example.com + description: Your documentation domain + +paths: + /api/fern-docs/get-jwt: + get: + summary: Exchange an API key for a JWT + description: Exchange a Fern API key for a JWT token that can be used to access protected documentation endpoints. + operationId: getJwt + parameters: + - name: FERN_API_KEY + in: header + required: true + schema: + type: string + description: Your Fern API key + - name: ROLES + in: header + required: false + schema: + type: string + description: Comma-separated list of roles (e.g., "botanist,seedling") + - name: x-fern-host + in: header + required: false + schema: + type: string + description: Documentation domain (required on preview URLs) + responses: + '200': + description: Successfully generated JWT + content: + application/json: + schema: + type: object + properties: + fern_token: + type: string + description: JWT token for authenticating subsequent requests + roles: + type: array + items: + type: string + description: Roles included in the JWT + '400': + description: Bad request (local preview, self-hosted, or SSO environment) + content: + application/json: + schema: + type: object + properties: + error: + type: string + '401': + description: Unauthorized (missing or invalid API key) + content: + application/json: + schema: + type: object + properties: + error: + type: string + '403': + description: Forbidden (API key does not belong to organization) + content: + application/json: + schema: + type: object + properties: + error: + type: string + '500': + description: Internal server error + content: + application/json: + schema: + type: object + properties: + error: + type: string + + /api/fern-docs/search/v2/key: + get: + summary: Get search credentials + description: Retrieve Algolia search credentials for querying documentation. Supports API key or JWT authentication. + operationId: getSearchKey + parameters: + - name: FERN_API_KEY + in: header + required: false + schema: + type: string + description: Your Fern API key (Option 1) + - name: FERN_TOKEN + in: header + required: false + schema: + type: string + description: JWT token from /api/fern-docs/get-jwt (Option 2) + - name: ROLES + in: header + required: false + schema: + type: string + description: Comma-separated list of roles (only with FERN_API_KEY) + - name: X-User-Token + in: header + required: false + schema: + type: string + description: Optional user identifier for analytics + - name: x-fern-host + in: header + required: false + schema: + type: string + description: Documentation domain (required on preview URLs) + responses: + '200': + description: Successfully retrieved search credentials + content: + application/json: + schema: + type: object + properties: + appId: + type: string + description: Algolia application ID + apiKey: + type: string + description: Short-lived Algolia search API key + roles: + type: array + items: + type: string + description: Roles included in the search key (only with FERN_API_KEY auth) + '400': + description: Bad request (local preview or unsupported preview URL) + '401': + description: Unauthorized (invalid API key) + '403': + description: Forbidden (API key does not belong to organization) diff --git a/fern/products/ask-fern/ask-fern.yml b/fern/products/ask-fern/ask-fern.yml index bcfc656a7..6ceafee30 100644 --- a/fern/products/ask-fern/ask-fern.yml +++ b/fern/products/ask-fern/ask-fern.yml @@ -28,6 +28,8 @@ navigation: path: ./pages/features/insights.mdx - page: Evaluation path: ./pages/features/evals.mdx + - page: MCP server for your site + path: ./pages/features/mcp-server.mdx - page: Role-based access control path: ./pages/features/rbac.mdx - page: Slack app diff --git a/fern/products/ask-fern/pages/features/mcp-server.mdx b/fern/products/ask-fern/pages/features/mcp-server.mdx new file mode 100644 index 000000000..75a64fe46 --- /dev/null +++ b/fern/products/ask-fern/pages/features/mcp-server.mdx @@ -0,0 +1,327 @@ +--- +title: MCP server for your site +subtitle: Use these endpoints to let your MCP agents fetch a JWT and a short-lived search key to query your docs. +--- + + + +The Model Context Protocol (MCP) server endpoints allow AI agents and automated tools to authenticate and search your documentation programmatically. These endpoints are designed for machine-to-machine communication, enabling agents to access gated content and perform searches on behalf of users. + +## Use cases + +- **AI agent integration**: Allow MCP-compatible agents to authenticate and search your documentation +- **Automated testing**: Programmatically verify documentation content and search functionality +- **Custom integrations**: Build tools that need to access protected documentation content + +## API reference + +### Exchange an API key for a JWT + +Exchange a Fern API key for a JWT token that can be used to access protected documentation endpoints. + +```http +GET /api/fern-docs/get-jwt +``` + +#### Request headers + +| Header | Type | Required | Description | +|--------|------|----------|-------------| +| `FERN_API_KEY` | string | Yes | Your Fern API key. Generate one using the [Fern CLI](/learn/cli-api/cli-reference/commands#fern-token). | +| `ROLES` | string | No | Comma-separated list of roles to include in the JWT (e.g., `botanist,seedling`). | +| `x-fern-host` | string | Conditional | Required on preview URLs; optional on custom domains. The documentation domain (e.g., `docs.example.com`). | + +#### Response + +**Success (200)** + +```json +{ + "fern_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", + "roles": ["botanist", "seedling"] +} +``` + +| Field | Type | Description | +|-------|------|-------------| +| `fern_token` | string | JWT token for authenticating subsequent requests | +| `roles` | string[] | Roles included in the JWT | + +**Error responses** + +| Status | Description | +|--------|-------------| +| 400 | JWT generation is not accessible in local preview mode | +| 400 | JWT generation is not supported in self-hosted environments | +| 400 | SSO/WorkOS authentication is not supported by this endpoint | +| 401 | Missing `FERN_API_KEY` header | +| 401 | Invalid API key | +| 403 | API key does not belong to the organization that owns this domain | +| 500 | Authentication configuration error or JWT generation failed | + +#### Example + +```bash +# Generate and export your Fern API key +fern token +export FERN_API_KEY= + +# Request a JWT +export JWT=$(curl -X GET https://docs.example.com/api/fern-docs/get-jwt \ + -H "FERN_API_KEY:${FERN_API_KEY}" \ + -H "ROLES: botanist,seedling" \ + -H "x-fern-host: docs.example.com") + +# Extract the token from the response +export FERN_TOKEN=$(echo $JWT | jq -r '.fern_token') +``` + +#### Environment restrictions + +- **Local preview**: Not available (returns 400) +- **Self-hosted**: Not available (returns 400) +- **Production**: Fully supported + +--- + +### Get search credentials + +Retrieve Algolia search credentials for querying documentation. Supports two authentication methods: API key-based or JWT-based. + +```http +GET /api/fern-docs/search/v2/key +``` + +#### Request headers + +**Option 1: API key authentication** + +| Header | Type | Required | Description | +|--------|------|----------|-------------| +| `FERN_API_KEY` | string | Yes | Your Fern API key. Generate one using the [Fern CLI](/learn/cli-api/cli-reference/commands#fern-token). | +| `ROLES` | string | No | Comma-separated list of roles for filtering search results (e.g., `botanist,seedling`). | +| `x-fern-host` | string | Conditional | Required on preview URLs; optional on custom domains. The documentation domain (e.g., `docs.example.com`). | + +**Option 2: JWT authentication** + +| Header | Type | Required | Description | +|--------|------|----------|-------------| +| `FERN_TOKEN` | string | Yes | JWT token obtained from `/api/fern-docs/get-jwt` | +| `X-User-Token` | string | No | Optional user identifier for analytics (e.g., `aloe-bot-42`) | +| `x-fern-host` | string | Conditional | Required on preview URLs; optional on custom domains. The documentation domain (e.g., `docs.example.com`). | + +Alternatively, the `FERN_TOKEN` can be provided as a cookie instead of a header. + +#### Response + +**Success (200)** + +```json +{ + "appId": "ABC123XYZ", + "apiKey": "a1b2c3d4e5f6g7h8i9j0", + "roles": ["botanist", "seedling"] +} +``` + +| Field | Type | Description | +|-------|------|-------------| +| `appId` | string | Algolia application ID | +| `apiKey` | string | Short-lived Algolia search API key | +| `roles` | string[] | Roles included in the search key (only present when using API key authentication) | + +**Error responses** + +| Status | Description | +|--------|-------------| +| 400 | Search key is not accessible in local preview mode | +| 400 | Search is not supported for preview URLs (unless explicitly enabled) | +| 401 | Invalid API key | +| 403 | API key does not belong to the organization that owns this domain | + +#### Example with API key + +```bash +# Using FERN_API_KEY +curl -X GET https://docs.example.com/api/fern-docs/search/v2/key \ + -H "FERN_API_KEY: ${FERN_API_KEY}" \ + -H "ROLES: botanist" \ + -H "x-fern-host: docs.example.com" +``` + +#### Example with JWT + +```bash +# Using FERN_TOKEN from previous step +curl -X GET https://docs.example.com/api/fern-docs/search/v2/key \ + -H "FERN_TOKEN: ${FERN_TOKEN}" \ + -H "X-User-Token: aloe-bot-42" \ + -H "x-fern-host: docs.example.com" +``` + +#### Environment restrictions + +- **Local preview**: Not available (returns 400) +- **Self-hosted**: Returns mock credentials (`appId: "selfhosted-appid"`, `apiKey: "selfhosted-apikey"`) +- **Preview URLs**: Not available unless explicitly enabled (returns 400) +- **Production**: Fully supported + +--- + +## OpenAPI specification + +Download the complete OpenAPI specification for these endpoints: + +```yaml +openapi: 3.1.0 +info: + title: Fern Docs MCP API + version: 1.0.0 + description: API endpoints for MCP agents to authenticate and search Fern documentation sites. + +servers: + - url: https://docs.example.com + description: Your documentation domain + +paths: + /api/fern-docs/get-jwt: + get: + summary: Exchange an API key for a JWT + description: Exchange a Fern API key for a JWT token that can be used to access protected documentation endpoints. + operationId: getJwt + parameters: + - name: FERN_API_KEY + in: header + required: true + schema: + type: string + description: Your Fern API key + - name: ROLES + in: header + required: false + schema: + type: string + description: Comma-separated list of roles (e.g., "botanist,seedling") + - name: x-fern-host + in: header + required: false + schema: + type: string + description: Documentation domain (required on preview URLs) + responses: + '200': + description: Successfully generated JWT + content: + application/json: + schema: + type: object + properties: + fern_token: + type: string + description: JWT token for authenticating subsequent requests + roles: + type: array + items: + type: string + description: Roles included in the JWT + '400': + description: Bad request (local preview, self-hosted, or SSO environment) + content: + application/json: + schema: + type: object + properties: + error: + type: string + '401': + description: Unauthorized (missing or invalid API key) + content: + application/json: + schema: + type: object + properties: + error: + type: string + '403': + description: Forbidden (API key does not belong to organization) + content: + application/json: + schema: + type: object + properties: + error: + type: string + '500': + description: Internal server error + content: + application/json: + schema: + type: object + properties: + error: + type: string + + /api/fern-docs/search/v2/key: + get: + summary: Get search credentials + description: Retrieve Algolia search credentials for querying documentation. Supports API key or JWT authentication. + operationId: getSearchKey + parameters: + - name: FERN_API_KEY + in: header + required: false + schema: + type: string + description: Your Fern API key (Option 1) + - name: FERN_TOKEN + in: header + required: false + schema: + type: string + description: JWT token from /api/fern-docs/get-jwt (Option 2) + - name: ROLES + in: header + required: false + schema: + type: string + description: Comma-separated list of roles (only with FERN_API_KEY) + - name: X-User-Token + in: header + required: false + schema: + type: string + description: Optional user identifier for analytics + - name: x-fern-host + in: header + required: false + schema: + type: string + description: Documentation domain (required on preview URLs) + responses: + '200': + description: Successfully retrieved search credentials + content: + application/json: + schema: + type: object + properties: + appId: + type: string + description: Algolia application ID + apiKey: + type: string + description: Short-lived Algolia search API key + roles: + type: array + items: + type: string + description: Roles included in the search key (only with FERN_API_KEY auth) + '400': + description: Bad request (local preview or unsupported preview URL) + '401': + description: Unauthorized (invalid API key) + '403': + description: Forbidden (API key does not belong to organization) +``` + +You can also download this specification as a file: [openapi.yaml](/apis/fern-docs-mcp/openapi.yaml) diff --git a/fern/products/ask-fern/pages/getting-started/api-get-started.mdx b/fern/products/ask-fern/pages/getting-started/api-get-started.mdx index 52f97b630..6ec074103 100644 --- a/fern/products/ask-fern/pages/getting-started/api-get-started.mdx +++ b/fern/products/ask-fern/pages/getting-started/api-get-started.mdx @@ -15,30 +15,4 @@ The Fern AI API allows you to manage your Ask Fern configuration using Fern's pu Fern API requests require a bearer token for authentication. Use the CLI command [`fern token`](/learn/cli-api/cli-reference/commands#fern-token) to generate a bearer token. Tokens do not expire. -### JWT authentication flow - -For accessing protected documentation endpoints, you can exchange a Fern API key for a JWT token: - -1. Generate and export your Fern API key: - -```bash -fern generate token -export FERN_API_KEY= -``` - -2. Request a JWT from the authentication endpoint: - -```bash -export JWT=$(curl -X GET https://docs.example.com/api/fern-docs/get-jwt \ - -H "FERN_API_KEY:${FERN_API_KEY}" \ - -H 'x-fern-host: docs.example.com') -``` - -3. Use the JWT to access protected endpoints: - -```bash -curl -X GET https://docs.example.com/api/endpoint \ - -H 'Accept: text/plain' \ - -H 'x-fern-host: docs.example.com' \ - -H "FERN_TOKEN: ${JWT}" -``` +For MCP agents and automated tools that need to authenticate and search your documentation, see the [MCP server documentation](/learn/ask-fern/mcp-server). From b3c5a8514b11e87473a9de505a87f63465ba94d3 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Tue, 4 Nov 2025 19:10:19 +0000 Subject: [PATCH 3/4] fix: resolve CI failures and Vale linting errors - Remove empty fern/apis/fern-docs-mcp directory causing CI failure - Change 'API reference' to 'API Reference' per FernStyles.Reject rule - Use contractions (isn't, doesn't) per Microsoft.Contractions - Define SSO (Single sign-on) on first use per FernStyles.Acronyms - Fix broken link in api-get-started.mdx to use correct path - Remove download link to openapi.yaml (file not hosted) Co-Authored-By: kenny@buildwithfern.com --- fern/apis/fern-docs-mcp/openapi.yaml | 149 ------------------ .../ask-fern/pages/features/mcp-server.mdx | 20 ++- .../pages/getting-started/api-get-started.mdx | 2 +- 3 files changed, 10 insertions(+), 161 deletions(-) delete mode 100644 fern/apis/fern-docs-mcp/openapi.yaml diff --git a/fern/apis/fern-docs-mcp/openapi.yaml b/fern/apis/fern-docs-mcp/openapi.yaml deleted file mode 100644 index b8d35ac46..000000000 --- a/fern/apis/fern-docs-mcp/openapi.yaml +++ /dev/null @@ -1,149 +0,0 @@ -openapi: 3.1.0 -info: - title: Fern Docs MCP API - version: 1.0.0 - description: API endpoints for MCP agents to authenticate and search Fern documentation sites. - -servers: - - url: https://docs.example.com - description: Your documentation domain - -paths: - /api/fern-docs/get-jwt: - get: - summary: Exchange an API key for a JWT - description: Exchange a Fern API key for a JWT token that can be used to access protected documentation endpoints. - operationId: getJwt - parameters: - - name: FERN_API_KEY - in: header - required: true - schema: - type: string - description: Your Fern API key - - name: ROLES - in: header - required: false - schema: - type: string - description: Comma-separated list of roles (e.g., "botanist,seedling") - - name: x-fern-host - in: header - required: false - schema: - type: string - description: Documentation domain (required on preview URLs) - responses: - '200': - description: Successfully generated JWT - content: - application/json: - schema: - type: object - properties: - fern_token: - type: string - description: JWT token for authenticating subsequent requests - roles: - type: array - items: - type: string - description: Roles included in the JWT - '400': - description: Bad request (local preview, self-hosted, or SSO environment) - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized (missing or invalid API key) - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Forbidden (API key does not belong to organization) - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: Internal server error - content: - application/json: - schema: - type: object - properties: - error: - type: string - - /api/fern-docs/search/v2/key: - get: - summary: Get search credentials - description: Retrieve Algolia search credentials for querying documentation. Supports API key or JWT authentication. - operationId: getSearchKey - parameters: - - name: FERN_API_KEY - in: header - required: false - schema: - type: string - description: Your Fern API key (Option 1) - - name: FERN_TOKEN - in: header - required: false - schema: - type: string - description: JWT token from /api/fern-docs/get-jwt (Option 2) - - name: ROLES - in: header - required: false - schema: - type: string - description: Comma-separated list of roles (only with FERN_API_KEY) - - name: X-User-Token - in: header - required: false - schema: - type: string - description: Optional user identifier for analytics - - name: x-fern-host - in: header - required: false - schema: - type: string - description: Documentation domain (required on preview URLs) - responses: - '200': - description: Successfully retrieved search credentials - content: - application/json: - schema: - type: object - properties: - appId: - type: string - description: Algolia application ID - apiKey: - type: string - description: Short-lived Algolia search API key - roles: - type: array - items: - type: string - description: Roles included in the search key (only with FERN_API_KEY auth) - '400': - description: Bad request (local preview or unsupported preview URL) - '401': - description: Unauthorized (invalid API key) - '403': - description: Forbidden (API key does not belong to organization) diff --git a/fern/products/ask-fern/pages/features/mcp-server.mdx b/fern/products/ask-fern/pages/features/mcp-server.mdx index 75a64fe46..77203c03e 100644 --- a/fern/products/ask-fern/pages/features/mcp-server.mdx +++ b/fern/products/ask-fern/pages/features/mcp-server.mdx @@ -13,7 +13,7 @@ The Model Context Protocol (MCP) server endpoints allow AI agents and automated - **Automated testing**: Programmatically verify documentation content and search functionality - **Custom integrations**: Build tools that need to access protected documentation content -## API reference +## API Reference ### Exchange an API key for a JWT @@ -51,12 +51,12 @@ GET /api/fern-docs/get-jwt | Status | Description | |--------|-------------| -| 400 | JWT generation is not accessible in local preview mode | -| 400 | JWT generation is not supported in self-hosted environments | -| 400 | SSO/WorkOS authentication is not supported by this endpoint | +| 400 | JWT generation isn't accessible in local preview mode | +| 400 | JWT generation isn't supported in self-hosted environments | +| 400 | Single sign-on (SSO)/WorkOS authentication isn't supported by this endpoint | | 401 | Missing `FERN_API_KEY` header | | 401 | Invalid API key | -| 403 | API key does not belong to the organization that owns this domain | +| 403 | API key doesn't belong to the organization that owns this domain | | 500 | Authentication configuration error or JWT generation failed | #### Example @@ -134,10 +134,10 @@ Alternatively, the `FERN_TOKEN` can be provided as a cookie instead of a header. | Status | Description | |--------|-------------| -| 400 | Search key is not accessible in local preview mode | -| 400 | Search is not supported for preview URLs (unless explicitly enabled) | +| 400 | Search key isn't accessible in local preview mode | +| 400 | Search isn't supported for preview URLs (unless explicitly enabled) | | 401 | Invalid API key | -| 403 | API key does not belong to the organization that owns this domain | +| 403 | API key doesn't belong to the organization that owns this domain | #### Example with API key @@ -170,7 +170,7 @@ curl -X GET https://docs.example.com/api/fern-docs/search/v2/key \ ## OpenAPI specification -Download the complete OpenAPI specification for these endpoints: +The complete OpenAPI specification for these endpoints: ```yaml openapi: 3.1.0 @@ -323,5 +323,3 @@ paths: '403': description: Forbidden (API key does not belong to organization) ``` - -You can also download this specification as a file: [openapi.yaml](/apis/fern-docs-mcp/openapi.yaml) diff --git a/fern/products/ask-fern/pages/getting-started/api-get-started.mdx b/fern/products/ask-fern/pages/getting-started/api-get-started.mdx index 6ec074103..a965fab1c 100644 --- a/fern/products/ask-fern/pages/getting-started/api-get-started.mdx +++ b/fern/products/ask-fern/pages/getting-started/api-get-started.mdx @@ -15,4 +15,4 @@ The Fern AI API allows you to manage your Ask Fern configuration using Fern's pu Fern API requests require a bearer token for authentication. Use the CLI command [`fern token`](/learn/cli-api/cli-reference/commands#fern-token) to generate a bearer token. Tokens do not expire. -For MCP agents and automated tools that need to authenticate and search your documentation, see the [MCP server documentation](/learn/ask-fern/mcp-server). +For MCP agents and automated tools that need to authenticate and search your documentation, see the [MCP server documentation](/learn/ask-fern/features/mcp-server). From 68aa6c5bc4de3ac0a53ce74e28ee969b9ba4ecfe Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Tue, 4 Nov 2025 20:21:45 +0000 Subject: [PATCH 4/4] feat: add Fern API definition for MCP endpoints - Create fern/apis/fern-docs-mcp/openapi.json with OpenAPI 3.1.0 spec - Add generators.yml to properly configure the API definition - Update MCP server documentation to reference the API spec location - Includes both get-jwt and search/v2/key endpoints with full specifications Co-Authored-By: kenny@buildwithfern.com --- fern/apis/fern-docs-mcp/generators.yml | 3 + fern/apis/fern-docs-mcp/openapi.json | 231 ++++++++++++++++++ .../ask-fern/pages/features/mcp-server.mdx | 2 +- 3 files changed, 235 insertions(+), 1 deletion(-) create mode 100644 fern/apis/fern-docs-mcp/generators.yml create mode 100644 fern/apis/fern-docs-mcp/openapi.json diff --git a/fern/apis/fern-docs-mcp/generators.yml b/fern/apis/fern-docs-mcp/generators.yml new file mode 100644 index 000000000..7868b241d --- /dev/null +++ b/fern/apis/fern-docs-mcp/generators.yml @@ -0,0 +1,3 @@ +api: + specs: + - openapi: openapi.json diff --git a/fern/apis/fern-docs-mcp/openapi.json b/fern/apis/fern-docs-mcp/openapi.json new file mode 100644 index 000000000..c440f3a82 --- /dev/null +++ b/fern/apis/fern-docs-mcp/openapi.json @@ -0,0 +1,231 @@ +{ + "openapi": "3.1.0", + "info": { + "title": "Fern Docs MCP API", + "version": "1.0.0", + "description": "API endpoints for MCP agents to authenticate and search Fern documentation sites." + }, + "servers": [ + { + "url": "https://docs.example.com", + "description": "Your documentation domain" + } + ], + "paths": { + "/api/fern-docs/get-jwt": { + "get": { + "summary": "Exchange an API key for a JWT", + "description": "Exchange a Fern API key for a JWT token that can be used to access protected documentation endpoints.", + "operationId": "getJwt", + "parameters": [ + { + "name": "FERN_API_KEY", + "in": "header", + "required": true, + "schema": { + "type": "string" + }, + "description": "Your Fern API key" + }, + { + "name": "ROLES", + "in": "header", + "required": false, + "schema": { + "type": "string" + }, + "description": "Comma-separated list of roles (e.g., \"botanist,seedling\")" + }, + { + "name": "x-fern-host", + "in": "header", + "required": false, + "schema": { + "type": "string" + }, + "description": "Documentation domain (required on preview URLs)" + } + ], + "responses": { + "200": { + "description": "Successfully generated JWT", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "fern_token": { + "type": "string", + "description": "JWT token for authenticating subsequent requests" + }, + "roles": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Roles included in the JWT" + } + }, + "required": ["fern_token", "roles"] + } + } + } + }, + "400": { + "description": "Bad request (local preview, self-hosted, or SSO environment)", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "error": { + "type": "string" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized (missing or invalid API key)", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "error": { + "type": "string" + } + } + } + } + } + }, + "403": { + "description": "Forbidden (API key does not belong to organization)", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "error": { + "type": "string" + } + } + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "error": { + "type": "string" + } + } + } + } + } + } + } + } + }, + "/api/fern-docs/search/v2/key": { + "get": { + "summary": "Get search credentials", + "description": "Retrieve Algolia search credentials for querying documentation. Supports API key or JWT authentication.", + "operationId": "getSearchKey", + "parameters": [ + { + "name": "FERN_API_KEY", + "in": "header", + "required": false, + "schema": { + "type": "string" + }, + "description": "Your Fern API key (Option 1)" + }, + { + "name": "FERN_TOKEN", + "in": "header", + "required": false, + "schema": { + "type": "string" + }, + "description": "JWT token from /api/fern-docs/get-jwt (Option 2)" + }, + { + "name": "ROLES", + "in": "header", + "required": false, + "schema": { + "type": "string" + }, + "description": "Comma-separated list of roles (only with FERN_API_KEY)" + }, + { + "name": "X-User-Token", + "in": "header", + "required": false, + "schema": { + "type": "string" + }, + "description": "Optional user identifier for analytics" + }, + { + "name": "x-fern-host", + "in": "header", + "required": false, + "schema": { + "type": "string" + }, + "description": "Documentation domain (required on preview URLs)" + } + ], + "responses": { + "200": { + "description": "Successfully retrieved search credentials", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "appId": { + "type": "string", + "description": "Algolia application ID" + }, + "apiKey": { + "type": "string", + "description": "Short-lived Algolia search API key" + }, + "roles": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Roles included in the search key (only with FERN_API_KEY auth)" + } + }, + "required": ["appId", "apiKey"] + } + } + } + }, + "400": { + "description": "Bad request (local preview or unsupported preview URL)" + }, + "401": { + "description": "Unauthorized (invalid API key)" + }, + "403": { + "description": "Forbidden (API key does not belong to organization)" + } + } + } + } + } +} diff --git a/fern/products/ask-fern/pages/features/mcp-server.mdx b/fern/products/ask-fern/pages/features/mcp-server.mdx index 77203c03e..c9b8cdb38 100644 --- a/fern/products/ask-fern/pages/features/mcp-server.mdx +++ b/fern/products/ask-fern/pages/features/mcp-server.mdx @@ -170,7 +170,7 @@ curl -X GET https://docs.example.com/api/fern-docs/search/v2/key \ ## OpenAPI specification -The complete OpenAPI specification for these endpoints: +The complete OpenAPI specification for these endpoints is available in the repository at `fern/apis/fern-docs-mcp/openapi.json`. ```yaml openapi: 3.1.0