Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 67 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

65 changes: 65 additions & 0 deletions site/agents/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,68 @@ npm run deploy
- **Framer Motion** - Animation library
- **GSAP** - Advanced animations
- **Cloudflare Workers** - Deployment platform

# Agents MCP Server

[![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)
[![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)

This is an MCP server for anyone building with Agents SDK. It exposes just 1 tool.

```json
{
"name": "search-agent-docs",
"description": "Token efficient search of the Cloudflare Agents SDK documentation",
"inputSchema": {
"query": {
"type": "string",
"description": "query string to search for eg. 'agent hibernate', 'schedule tasks'"
},
"k": {
"type": "number",
"optional": true,
"default": 5,
"description": "number of results to return"
}
}
}
```

## Usage

Connect to this MCP server to any MCP Client that supports remote MCP servers.

```txt
https://agents.mcp.cloudflare.com/mcp
```

## How it works

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.

### Ratelimiting

To avoid ratelimiting by GitHub, you can set the `GITHUB_TOKEN` environment variable with `wrangler secret put GITHUB_TOKEN`

## Development

To run this server locally, you can use the following command:

```bash
npm install
npm run dev
```

You can test this server with the MCP Inspector.

```bash
npx @modelcontextprotocol/inspector
```

## Deployment

To deploy this server to Cloudflare Workers, you can use the following command:

```bash
npm run deploy
```
8 changes: 8 additions & 0 deletions site/agents/env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/* eslint-disable */
// Generated by Wrangler by running `wrangler types env.d.ts --include-runtime false` (hash: 83be826bfd14e0006039e186e1b11835)
declare namespace Cloudflare {
interface Env {
DOCS_KV: KVNamespace;
}
}
interface Env extends Cloudflare.Env {}
8 changes: 7 additions & 1 deletion site/agents/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,22 @@
"private": true,
"scripts": {
"dev": "astro dev",
"start": "wrangler dev",
"build": "astro build",
"deploy": "wrangler deploy"
"types": "wrangler types env.d.ts --include-runtime false",
"deploy": "npm run build && wrangler deploy"
},
"dependencies": {
"@astrojs/cloudflare": "^12.6.10",
"@astrojs/react": "^4.4.2",
"@cfworker/json-schema": "^4.1.1",
"@chonkiejs/core": "^0.0.5",
"@gsap/react": "^2.1.2",
"@orama/orama": "^3.1.16",
"@use-it/interval": "^1.0.0",
"astro": "^5.15.4",
"clsx": "^2.1.1",
"effect": "^3.19.2",
"framer-motion": "^12.23.24",
"gsap": "^3.13.0",
"react": "^19.2.0",
Expand Down
1 change: 1 addition & 0 deletions site/agents/src/.env_example
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
GITHUB_TOKEN=optional-to-avoid-rate-limiting
79 changes: 79 additions & 0 deletions site/agents/src/server/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { CfWorkerJsonSchemaValidator } from "@modelcontextprotocol/sdk/validation/cfworker";
import { z } from "zod";
import { createMcpHandler } from "agents/mcp";
import { fetchAndBuildIndex, formatResults } from "./utils";
import { search } from "@orama/orama";
import { Effect } from "effect";

// TODO: instrument this server for observability
const mcpServer = new McpServer(
{
name: "agents-mcp",
version: "0.0.1"
},
{
capabilities: {},
jsonSchemaValidator: new CfWorkerJsonSchemaValidator()
}
);

const inputSchema = {
query: z
.string()
.describe(
"query string to search for eg. 'agent hibernate', 'schedule tasks'"
),
k: z.number().optional().default(5).describe("number of results to return")
};

mcpServer.registerTool(
"search-agent-docs",
{
description:
"Token efficient search of the Cloudflare Agents SDK documentation",
inputSchema
},
async ({ query, k }) => {
const searchEffect = Effect.gen(function* () {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sneaking in effect huh

console.log({ query, k });
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

stray log?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'd kinda like to have some logging on the queries are being asked. We need to instrument the server properly but I added this till then.

const term = query.trim();

const docsDb = yield* fetchAndBuildIndex;

const result = search(docsDb, { term, limit: k });
const searchResult = yield* result instanceof Promise
? Effect.promise(() => result)
: Effect.succeed(result);

return {
content: [
{
type: "text" as const,
text: formatResults(searchResult, term, k)
}
]
};
}).pipe(
Effect.catchAll((error) => {
console.error(error);
return Effect.succeed({
content: [
{
type: "text" as const,
text: `There was an error with the search tool. Please try again later.`
}
]
});
})
);

return await Effect.runPromise(searchEffect);
}
);

export default {
async fetch(request: Request, env: Env, ctx: ExecutionContext) {
return createMcpHandler(mcpServer)(request, env, ctx);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can make a scheduled worker here and run this everyday

};
Loading
Loading