Skip to content

Commit 1148aee

Browse files
kennyderekdevalogfern-support
authored
Add docs and API Reference for AI tooling (#1763)
Co-authored-by: Devin Logan <[email protected]> Co-authored-by: Fern Support <[email protected]>
1 parent 3e5b927 commit 1148aee

File tree

5 files changed

+250
-3
lines changed

5 files changed

+250
-3
lines changed

fern/apis/mcp-tools/generators.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
api:
2+
specs:
3+
- openapi: openapi.json

fern/apis/mcp-tools/openapi.json

Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
{
2+
"openapi": "3.1.0",
3+
"info": {
4+
"title": "Fern Docs MCP API",
5+
"version": "1.0.0",
6+
"description": "API endpoints for MCP agents to authenticate and search Fern documentation sites."
7+
},
8+
"servers": [
9+
{
10+
"url": "https://docs.example.com",
11+
"description": "Your documentation domain"
12+
}
13+
],
14+
"components": {
15+
"securitySchemes": {
16+
"FernApiKey": {
17+
"type": "apiKey",
18+
"in": "header",
19+
"name": "FERN_API_KEY",
20+
"description": "Fern API key, from `fern generate token`."
21+
},
22+
"FernToken": {
23+
"type": "apiKey",
24+
"in": "header",
25+
"name": "FERN_TOKEN",
26+
"description": "JWT token for this user."
27+
}
28+
}
29+
},
30+
"paths": {
31+
"/api/fern-docs/get-jwt": {
32+
"get": {
33+
"summary": "JWT from Fern API key",
34+
"description": "Get a JWT to access protected documentation endpoints, optionally scoped to specific roles.",
35+
"operationId": "getJwt",
36+
"security": [
37+
{
38+
"FernApiKey": []
39+
}
40+
],
41+
"parameters": [
42+
{
43+
"name": "ROLES",
44+
"in": "header",
45+
"required": false,
46+
"schema": {
47+
"type": "string"
48+
},
49+
"description": "Comma-separated list of roles (e.g., \"botanist,seedling\"). Sets roles for returned JWT if provided, otherwise, roles are empty."
50+
},
51+
{
52+
"name": "x-fern-host",
53+
"in": "header",
54+
"required": false,
55+
"schema": {
56+
"type": "string"
57+
},
58+
"description": "Domain (required on preview URLs)"
59+
}
60+
],
61+
"responses": {
62+
"200": {
63+
"description": "Successfully generated JWT",
64+
"content": {
65+
"application/json": {
66+
"schema": {
67+
"type": "object",
68+
"properties": {
69+
"fern_token": {
70+
"type": "string",
71+
"description": "JWT token for authenticating subsequent requests"
72+
},
73+
"roles": {
74+
"type": "array",
75+
"items": {
76+
"type": "string"
77+
},
78+
"description": "Roles included in the JWT"
79+
}
80+
},
81+
"required": ["fern_token", "roles"]
82+
}
83+
}
84+
}
85+
},
86+
"400": {
87+
"description": "Bad request (local preview, self-hosted, or SSO environment)",
88+
"content": {
89+
"application/json": {
90+
"schema": {
91+
"type": "object",
92+
"properties": {
93+
"error": {
94+
"type": "string"
95+
}
96+
}
97+
}
98+
}
99+
}
100+
},
101+
"401": {
102+
"description": "Unauthorized (missing or invalid API key)",
103+
"content": {
104+
"application/json": {
105+
"schema": {
106+
"type": "object",
107+
"properties": {
108+
"error": {
109+
"type": "string"
110+
}
111+
}
112+
}
113+
}
114+
}
115+
},
116+
"403": {
117+
"description": "Forbidden (API key does not belong to this domain's Fern organization)",
118+
"content": {
119+
"application/json": {
120+
"schema": {
121+
"type": "object",
122+
"properties": {
123+
"error": {
124+
"type": "string"
125+
}
126+
}
127+
}
128+
}
129+
}
130+
}
131+
}
132+
}
133+
},
134+
"/api/fern-docs/search/v2/key": {
135+
"get": {
136+
"summary": "Algolia search credentials",
137+
"description": "Get Algolia search credentials for querying documentation.",
138+
"operationId": "getSearchKey",
139+
"security": [
140+
{
141+
"FernApiKey": []
142+
},
143+
{
144+
"FernToken": []
145+
}
146+
],
147+
"parameters": [
148+
{
149+
"name": "ROLES",
150+
"in": "header",
151+
"required": false,
152+
"schema": {
153+
"type": "string"
154+
},
155+
"description": "Comma-separated list of roles (only with FERN_API_KEY). Sets roles for returned search key if provided, otherwise, roles are empty."
156+
},
157+
{
158+
"name": "x-fern-host",
159+
"in": "header",
160+
"required": false,
161+
"schema": {
162+
"type": "string"
163+
},
164+
"description": "Documentation domain (required on preview URLs)"
165+
}
166+
],
167+
"responses": {
168+
"200": {
169+
"description": "Successfully retrieved search credentials",
170+
"content": {
171+
"application/json": {
172+
"schema": {
173+
"type": "object",
174+
"properties": {
175+
"appId": {
176+
"type": "string",
177+
"description": "Algolia application ID"
178+
},
179+
"apiKey": {
180+
"type": "string",
181+
"description": "Short-lived Algolia search API key"
182+
},
183+
"roles": {
184+
"type": "array",
185+
"items": {
186+
"type": "string"
187+
},
188+
"description": "Roles included in the search key (only with FERN_API_KEY auth)"
189+
}
190+
},
191+
"required": ["appId", "apiKey"]
192+
}
193+
}
194+
}
195+
},
196+
"400": {
197+
"description": "Bad request (local preview or unsupported preview URL)"
198+
},
199+
"401": {
200+
"description": "Unauthorized (invalid Fern API key)"
201+
},
202+
"403": {
203+
"description": "Forbidden (API key does not belong to this domain's Fern organization)"
204+
}
205+
}
206+
}
207+
}
208+
}
209+
}

fern/products/docs/docs.yml

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,8 +131,13 @@ navigation:
131131
contents:
132132
- link: Ask Fern
133133
href: /learn/ask-fern/getting-started/what-is-ask-fern
134-
- page: MCP server for your site
135-
path: ./pages/ai/mcp-server.mdx
134+
- section: MCP server for your site
135+
contents:
136+
- page: Overview
137+
path: ./pages/ai/mcp-server.mdx
138+
- api: API Reference
139+
paginated: false
140+
api-name: mcp-tools
136141
slug: mcp-server
137142
- page: Fern Scribe (coming soon)
138143
path: ./pages/ai/scribe.mdx

fern/products/docs/pages/ai/mcp-server.mdx

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,17 @@ To connect to your MCP server:
4242
3. Authenticate if your documentation requires authentication
4343
4. Start asking questions about your product directly in the AI client
4444
</Accordion>
45-
</AccordionGroup>
45+
</AccordionGroup>
46+
47+
## Direct API access for AI agents
48+
49+
AI agents can access your documentation, including authenticated documentation, directly via HTTP. Fern serves content as clean Markdown for token efficiency.
50+
51+
For authenticated sites, agents obtain a JWT via [`/api/fern-docs/get-jwt`](/learn/docs/ai-features/mcp-server/api-reference/get-jwt) with a Fern API key to access the protected documentation content and search functionality.
52+
53+
```bash Access protected content
54+
curl https://docs.example.com/platform/overview \
55+
-H 'Accept: text/plain' \
56+
-H 'x-fern-host: docs.example.com' \
57+
-H 'FERN_TOKEN: your-jwt-here'
58+
```

fern/products/docs/pages/changelog/2025-11-05.mdx

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,20 @@
1+
## HTTP API access for AI agents
2+
3+
AI agents can now access authenticated documentation directly via HTTP API. This enables custom integrations and AI tools to retrieve protected content programmatically.
4+
5+
Agents obtain a JWT via the `/api/fern-docs/get-jwt` endpoint with a Fern API key, then use it to access protected documentation:
6+
7+
```bash
8+
curl https://docs.example.com/platform/overview \
9+
-H 'Accept: text/plain' \
10+
-H 'x-fern-host: docs.example.com' \
11+
-H 'FERN_TOKEN: your-jwt-here'
12+
```
13+
14+
Content is served as clean Markdown for token-efficient processing.
15+
16+
Learn more in the [MCP server documentation](/learn/docs/ai-features/mcp-server).
17+
118
## Folder-based navigation
219

320
Auto-generate navigation from a folder of markdown files using the new `folder` configuration. Instead of manually listing each page in `docs.yml`, point to a folder. Fern discovers all `.md` and `.mdx` files and adds them to the navigation.

0 commit comments

Comments
 (0)