Skip to content

Commit 2333b63

Browse files
committed
Add docs autorag
1 parent 4717f26 commit 2333b63

File tree

12 files changed

+6058
-2
lines changed

12 files changed

+6058
-2
lines changed

apps/docs-autorag/.dev.vars.example

Whitespace-only changes.

apps/docs-autorag/.eslintrc.cjs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
/** @type {import("eslint").Linter.Config} */
2+
module.exports = {
3+
root: true,
4+
extends: ['@repo/eslint-config/default.cjs'],
5+
}

apps/docs-autorag/README.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Model Context Protocol (MCP) Server + Cloudflare Documentation (via Autorag)
2+
3+
This is a [Model Context Protocol (MCP)](https://modelcontextprotocol.io/introduction) server that supports remote MCP connections. It connects to an autorag instance (in this case, Cloudflare docs)
4+
5+
To run this server, you'll need access to an autorag instance which has indexed the contents of cloudflare-docs: https://github.com/cloudflare/cloudflare-docs/
6+
7+
The Cloudflare account this worker is deployed on already has this Autorag instance setup and indexed.
8+
9+
## Running locally
10+
11+
```
12+
pnpm run start
13+
```
14+
15+
Then connect to the server via remote MCP at `http://localhost:8976/sse`
16+
17+
## Deploying
18+
19+
```
20+
pnpm run deploy --env [ENVIRONMENT]
21+
```

apps/docs-autorag/package.json

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
{
2+
"name": "docs-autorag",
3+
"version": "0.0.1",
4+
"private": true,
5+
"scripts": {
6+
"check:lint": "run-eslint-workers",
7+
"check:types": "run-tsc",
8+
"deploy": "wrangler deploy",
9+
"dev": "wrangler dev",
10+
"start": "wrangler dev",
11+
"cf-typegen": "wrangler types",
12+
"test": "vitest run"
13+
},
14+
"dependencies": {
15+
"@cloudflare/workers-oauth-provider": "0.0.2",
16+
"@hono/zod-validator": "0.4.3",
17+
"@modelcontextprotocol/sdk": "1.9.0",
18+
"@repo/mcp-common": "workspace:*",
19+
"agents": "0.0.62",
20+
"cloudflare": "4.2.0",
21+
"hono": "4.7.6",
22+
"mime": "^4.0.6",
23+
"zod": "3.24.2"
24+
},
25+
"devDependencies": {
26+
"@cloudflare/vitest-pool-workers": "0.8.14",
27+
"@cloudflare/workers-types": "4.20250410.0",
28+
"prettier": "3.5.3",
29+
"typescript": "5.5.4",
30+
"vitest": "3.0.9",
31+
"wrangler": "4.10.0"
32+
}
33+
}

apps/docs-autorag/src/index.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
2+
import { McpAgent } from 'agents/mcp'
3+
import { registerDocsTools } from './tools/docs'
4+
5+
// The docs MCP server isn't stateful, so we don't have state/props
6+
export type Props = never
7+
8+
export type State = never
9+
10+
export class CloudflareDocumentationMCP extends McpAgent<Env, State, Props> {
11+
server = new McpServer({
12+
name: 'Remote MCP Server with Cloudflare Documentation',
13+
version: '1.0.0',
14+
})
15+
16+
constructor(public ctx: DurableObjectState, public env: Env) {
17+
super(ctx, env)
18+
}
19+
20+
async init() {
21+
registerDocsTools(this)
22+
}
23+
}
24+
25+
export default CloudflareDocumentationMCP.mount('/sse')

apps/docs-autorag/src/tools/docs.ts

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import { z } from 'zod'
2+
import type { CloudflareDocumentationMCP } from '../index'
3+
import { type EmbeddedResource } from "@modelcontextprotocol/sdk/types.js"
4+
import mime from "mime"
5+
/**
6+
* Registers the docs search tool with the MCP server
7+
* @param agent The MCP server instance
8+
*/
9+
export function registerDocsTools(agent: CloudflareDocumentationMCP) {
10+
// Register the worker logs analysis tool by worker name
11+
agent.server.tool(
12+
'search_cloudflare_documentation',
13+
`Search the Cloudflare documentation.
14+
15+
You should use this tool when:
16+
- A user asks questions about Cloudflare products (Workers, Developer Platform, Zero Trust, CDN, etc)
17+
- A user requests information about a Cloudflare feature
18+
- You are unsure of how to use some Cloudflare functionality
19+
- You are writing Cloudflare Workers code and need to look up Workers-specific documentation
20+
21+
This tool returns a number of results from a vector database. These are embedded as resources in the response and are plaintext doucments in a variety of formats.
22+
`,
23+
{
24+
// partially pulled from autorag query optimization example
25+
query: z.string().describe(`Search query. The query should:
26+
1. Identify the core concepts and intent
27+
2. Add relevant synonyms and related terms
28+
3. Remove irrelevant filler words
29+
4. Structure the query to emphasize key terms
30+
5. Include technical or domain-specific terminology if applicable`),
31+
scoreThreshold: z.number().min(0).max(1).optional().describe("A score threshold (0-1) for which matches should be included."),
32+
maxNumResults: z.number().default(10).optional().describe("The maximum number of results to return.")
33+
},
34+
async (params) => {
35+
// we don't need "rewrite query" OR aiSearch because an LLM writes the query and formats the output for us.
36+
const result = await agent.env.AI.autorag(agent.env.AUTORAG_NAME).search({
37+
query: params.query,
38+
ranking_options: params.scoreThreshold ? {
39+
score_threshold: params.scoreThreshold
40+
} : undefined,
41+
max_num_results: params.maxNumResults
42+
})
43+
44+
const resources: EmbeddedResource[] = result.data.map((result) => {
45+
const content = result.content.reduce((acc, contentPart) => {
46+
return acc + contentPart.text
47+
}, "")
48+
return {
49+
type: "resource",
50+
resource: {
51+
uri: `docs://${result.filename}`,
52+
mimeType: mime.getType(result.filename) ?? "text/plain",
53+
text: content
54+
}
55+
}
56+
})
57+
58+
return {
59+
content: resources
60+
}
61+
}
62+
)
63+
}

apps/docs-autorag/tsconfig.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"extends": "@repo/typescript-config/workers.json",
3+
"include": ["*/**.ts", "./vitest.config.ts"],
4+
}

apps/docs-autorag/types.d.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import type { TestEnv } from './vitest.config'
2+
3+
declare module 'cloudflare:test' {
4+
interface ProvidedEnv extends TestEnv {}
5+
}

apps/docs-autorag/vitest.config.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { defineWorkersConfig } from '@cloudflare/vitest-pool-workers/config'
2+
3+
export interface TestEnv extends Env {
4+
CLOUDFLARE_MOCK_ACCOUNT_ID: string
5+
CLOUDFLARE_MOCK_API_TOKEN: string
6+
}
7+
8+
export default defineWorkersConfig({
9+
test: {
10+
poolOptions: {
11+
workers: {
12+
wrangler: { configPath: `${__dirname}/wrangler.jsonc` },
13+
miniflare: {
14+
bindings: {
15+
CLOUDFLARE_MOCK_ACCOUNT_ID: 'mock-account-id',
16+
CLOUDFLARE_MOCK_API_TOKEN: 'mock-api-token',
17+
} satisfies Partial<TestEnv>,
18+
},
19+
},
20+
},
21+
},
22+
})

0 commit comments

Comments
 (0)