Skip to content

Commit 4e285b2

Browse files
feat: agents mcp (#643)
* feat: agents mcp * more effect and stemming * add readme * add note about ratelimiting * move it all into the site app * Update package-lock.json * fix: add main entrypoint and node compat --------- Co-authored-by: Sunil Pai <[email protected]>
1 parent a315e86 commit 4e285b2

File tree

9 files changed

+441
-4
lines changed

9 files changed

+441
-4
lines changed

package-lock.json

Lines changed: 67 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

site/agents/README.md

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,68 @@ npm run deploy
4040
- **Framer Motion** - Animation library
4141
- **GSAP** - Advanced animations
4242
- **Cloudflare Workers** - Deployment platform
43+
44+
# Agents MCP Server
45+
46+
[![Add to Cursor](https://img.shields.io/badge/Add%20to-Cursor-blue)](https://cursor.com/en-US/install-mcp?name=cloudflare-agents&config=eyJ1cmwiOiJodHBzOi8vYWdlbnRzLm1jcC5jbG91ZGZsYXJlLmNvbS9tY3AifQ%3D%3D)
47+
[![Add to VS Code](https://img.shields.io/badge/Add%20to-VS%20Code-blue)](vscode:mcp/install?%7B%22name%22%3A%22cloudflare-agents%22%2C%22type%22%3A%22http%22%2C%22url%22%3A%22https%3A%2F%2Fagents.mcp.cloudflare.com%2Fmcp%22%7D)
48+
49+
This is an MCP server for anyone building with Agents SDK. It exposes just 1 tool.
50+
51+
```json
52+
{
53+
"name": "search-agent-docs",
54+
"description": "Token efficient search of the Cloudflare Agents SDK documentation",
55+
"inputSchema": {
56+
"query": {
57+
"type": "string",
58+
"description": "query string to search for eg. 'agent hibernate', 'schedule tasks'"
59+
},
60+
"k": {
61+
"type": "number",
62+
"optional": true,
63+
"default": 5,
64+
"description": "number of results to return"
65+
}
66+
}
67+
}
68+
```
69+
70+
## Usage
71+
72+
Connect to this MCP server to any MCP Client that supports remote MCP servers.
73+
74+
```txt
75+
https://agents.mcp.cloudflare.com/mcp
76+
```
77+
78+
## How it works
79+
80+
It pulls the docs from Github, chunks them with a recursive chunker, and indexes them with Orama. The index is cached in KV for 1 day. Search is BM25 with stemming enabled for better results. This allows "hibernation" to match with "hibernate" allowing for more natural language queries.
81+
82+
### Ratelimiting
83+
84+
To avoid ratelimiting by GitHub, you can set the `GITHUB_TOKEN` environment variable with `wrangler secret put GITHUB_TOKEN`
85+
86+
## Development
87+
88+
To run this server locally, you can use the following command:
89+
90+
```bash
91+
npm install
92+
npm run dev
93+
```
94+
95+
You can test this server with the MCP Inspector.
96+
97+
```bash
98+
npx @modelcontextprotocol/inspector
99+
```
100+
101+
## Deployment
102+
103+
To deploy this server to Cloudflare Workers, you can use the following command:
104+
105+
```bash
106+
npm run deploy
107+
```

site/agents/env.d.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
/* eslint-disable */
2+
// Generated by Wrangler by running `wrangler types env.d.ts --include-runtime false` (hash: 83be826bfd14e0006039e186e1b11835)
3+
declare namespace Cloudflare {
4+
interface Env {
5+
DOCS_KV: KVNamespace;
6+
}
7+
}
8+
interface Env extends Cloudflare.Env {}

site/agents/package.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,22 @@
44
"private": true,
55
"scripts": {
66
"dev": "astro dev",
7+
"start": "wrangler dev",
78
"build": "astro build",
8-
"deploy": "wrangler deploy"
9+
"types": "wrangler types env.d.ts --include-runtime false",
10+
"deploy": "npm run build && wrangler deploy"
911
},
1012
"dependencies": {
1113
"@astrojs/cloudflare": "^12.6.10",
1214
"@astrojs/react": "^4.4.2",
15+
"@cfworker/json-schema": "^4.1.1",
16+
"@chonkiejs/core": "^0.0.5",
1317
"@gsap/react": "^2.1.2",
18+
"@orama/orama": "^3.1.16",
1419
"@use-it/interval": "^1.0.0",
1520
"astro": "^5.15.4",
1621
"clsx": "^2.1.1",
22+
"effect": "^3.19.2",
1723
"framer-motion": "^12.23.24",
1824
"gsap": "^3.13.0",
1925
"react": "^19.2.0",

site/agents/src/.env_example

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
GITHUB_TOKEN=optional-to-avoid-rate-limiting

site/agents/src/server/index.ts

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2+
import { CfWorkerJsonSchemaValidator } from "@modelcontextprotocol/sdk/validation/cfworker";
3+
import { z } from "zod";
4+
import { createMcpHandler } from "agents/mcp";
5+
import { fetchAndBuildIndex, formatResults } from "./utils";
6+
import { search } from "@orama/orama";
7+
import { Effect } from "effect";
8+
9+
// TODO: instrument this server for observability
10+
const mcpServer = new McpServer(
11+
{
12+
name: "agents-mcp",
13+
version: "0.0.1"
14+
},
15+
{
16+
capabilities: {},
17+
jsonSchemaValidator: new CfWorkerJsonSchemaValidator()
18+
}
19+
);
20+
21+
const inputSchema = {
22+
query: z
23+
.string()
24+
.describe(
25+
"query string to search for eg. 'agent hibernate', 'schedule tasks'"
26+
),
27+
k: z.number().optional().default(5).describe("number of results to return")
28+
};
29+
30+
mcpServer.registerTool(
31+
"search-agent-docs",
32+
{
33+
description:
34+
"Token efficient search of the Cloudflare Agents SDK documentation",
35+
inputSchema
36+
},
37+
async ({ query, k }) => {
38+
const searchEffect = Effect.gen(function* () {
39+
console.log({ query, k });
40+
const term = query.trim();
41+
42+
const docsDb = yield* fetchAndBuildIndex;
43+
44+
const result = search(docsDb, { term, limit: k });
45+
const searchResult = yield* result instanceof Promise
46+
? Effect.promise(() => result)
47+
: Effect.succeed(result);
48+
49+
return {
50+
content: [
51+
{
52+
type: "text" as const,
53+
text: formatResults(searchResult, term, k)
54+
}
55+
]
56+
};
57+
}).pipe(
58+
Effect.catchAll((error) => {
59+
console.error(error);
60+
return Effect.succeed({
61+
content: [
62+
{
63+
type: "text" as const,
64+
text: `There was an error with the search tool. Please try again later.`
65+
}
66+
]
67+
});
68+
})
69+
);
70+
71+
return await Effect.runPromise(searchEffect);
72+
}
73+
);
74+
75+
export default {
76+
async fetch(request: Request, env: Env, ctx: ExecutionContext) {
77+
return createMcpHandler(mcpServer)(request, env, ctx);
78+
}
79+
};

0 commit comments

Comments
 (0)