Skip to content

Commit 6601d5a

Browse files
committed
Merge branch 'main' of https://github.com/cloudflare/mcp-server-cloudflare into fm/casb-api-improved-pagination-tools
2 parents fa4a1b5 + 599bfcf commit 6601d5a

File tree

129 files changed

+27581
-1033
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

129 files changed

+27581
-1033
lines changed

.github/workflows/evals.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,12 @@ jobs:
2222
- name: Create .dev.vars file
2323
run: |
2424
echo "OPENAI_API_KEY=${{ secrets.OPENAI_API_KEY }}" > ./apps/sandbox-container/.dev.vars
25+
echo "OPENAI_API_KEY=${{ secrets.OPENAI_API_KEY }}" > ./apps/workers-bindings/.dev.vars
26+
echo "DEV_CLOUDFLARE_API_TOKEN=${{ secrets.DEV_CLOUDFLARE_API_TOKEN }}" >> ./apps/workers-bindings/.dev.vars
2527
- name: Verify .dev.vars file
2628
run: |
2729
du -h ./apps/sandbox-container/.dev.vars
30+
du -h ./apps/workers-bindings/.dev.vars
2831
- name: Install dependencies
2932
run: pnpm install
3033
- name: Run evals

README.md

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,21 @@ These MCP servers allow your [MCP Client](https://modelcontextprotocol.io/client
66

77
The following servers are included in this repository:
88

9-
| Server Name | Description | Server URL |
10-
| ----------------------------------------------- | ---------------------------------------------------------------------------- | ---------------------------------------------- |
11-
| [**Documentation server**](/apps/docs-autorag) | Get up to date reference information on Cloudflare | `https://docs.mcp.cloudflare.com/sse` |
12-
| [**Workers Bindings server**](/apps/bindings) | Build Workers applications with storage, AI, and compute primitives | `https://bindings.mcp.cloudflare.com/sse` |
13-
| [**Observability server**](/apps/observability) | Debug and get insight into your application’s logs and analytics | `https://observability.mcp.cloudflare.com/sse` |
14-
| [**Radar server**](/apps/radar) | Get global Internet traffic insights, trends, URL scans, and other utilities | `https://radar.mcp.cloudflare.com/sse` |
9+
| Server Name | Description | Server URL |
10+
| -------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- | ---------------------------------------------- |
11+
| [**Documentation server**](/apps/docs-vectorize) | Get up to date reference information on Cloudflare | `https://docs.mcp.cloudflare.com/sse` |
12+
| [**Workers Bindings server**](/apps/workers-bindings) | Build Workers applications with storage, AI, and compute primitives | `https://bindings.mcp.cloudflare.com/sse` |
13+
| [**Observability server**](/apps/workers-observability) | Debug and get insight into your application’s logs and analytics | `https://observability.mcp.cloudflare.com/sse` |
14+
| [**Radar server**](/apps/radar) | Get global Internet traffic insights, trends, URL scans, and other utilities | `https://radar.mcp.cloudflare.com/sse` |
15+
| [**Container server**](/apps/sandbox-container) | Spin up a sandbox development environment | `https://containers.mcp.cloudflare.com/sse` |
16+
| [**Browser rendering server**](/apps/browser-rendering) | Fetch web pages, convert them to markdown and take screenshots | `https://browser.mcp.cloudflare.com/sse` |
17+
| [**Logpush server**](/apps/logpush) | Get quick summaries for Logpush job health | `https://logs.mcp.cloudflare.com/sse` |
18+
| [**AI Gateway server**](/apps/ai-gateway) | Search your logs, get details about the prompts and responses | `https://ai-gateway.mcp.cloudflare.com/sse` |
19+
| [**AutoRAG server**](/apps/autorag) | List and search documents on your AutoRAGs | `https://autorag.mcp.cloudflare.com/sse` |
20+
| [**Audit Logs server**](/apps/auditlogs) | Query audit logs and generate reports for review | `https://auditlogs.mcp.cloudflare.com/sse` |
21+
| [**DNS Analytics server**](/apps/dns-analytics) | Optimize DNS performance and debug issues based on current set up | `https://dns-analytics.mcp.cloudflare.com/sse` |
22+
| [**Digital Experience Monitoring server**](/apps/dex-analysis) | Get quick insight on critical applications for your organization | `https://dex.mcp.cloudflare.com/sse` |
23+
| [**Cloudflare One CASB server**](/apps/cloudflare-one-casb) | Quickly identify any security misconfigurations for SaaS applications to safeguard users & data | `https://casb.mcp.cloudflare.com/sse` |
1524

1625
## Access the remote MCP server from any MCP client
1726

apps/ai-gateway/.dev.vars.example

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
CLOUDFLARE_CLIENT_ID=
2+
CLOUDFLARE_CLIENT_SECRET=
3+
DEV_DISABLE_OAUTH=
4+
DEV_CLOUDFLARE_API_TOKEN=
5+
DEV_CLOUDFLARE_EMAIL=

apps/ai-gateway/.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/ai-gateway/CONTRIBUTING.md

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# Setup
2+
3+
If you'd like to iterate and test your MCP server, you can do so in local development.
4+
5+
## Local Development
6+
7+
1. Create a `.dev.vars` file in your project root:
8+
9+
If you're a Cloudflare employee:
10+
11+
```
12+
CLOUDFLARE_CLIENT_ID=your_development_cloudflare_client_id
13+
CLOUDFLARE_CLIENT_SECRET=your_development_cloudflare_client_secret
14+
```
15+
16+
If you're an external contributor, you can provide a development API token:
17+
18+
```
19+
DEV_DISABLE_OAUTH=true
20+
# This is your global api token
21+
DEV_CLOUDFLARE_API_TOKEN=your_development_api_token
22+
```
23+
24+
2. Start the local development server:
25+
26+
```bash
27+
npx wrangler dev
28+
```
29+
30+
3. To test locally, open Inspector, and connect to `http://localhost:8976/sse`.
31+
Once you follow the prompts, you'll be able to "List Tools". You can also connect with any MCP client.
32+
33+
## Deploying the Worker ( Cloudflare employees only )
34+
35+
Set secrets via Wrangler:
36+
37+
```bash
38+
npx wrangler secret put CLOUDFLARE_CLIENT_ID -e <ENVIRONMENT>
39+
npx wrangler secret put CLOUDFLARE_CLIENT_SECRET -e <ENVIRONMENT>
40+
```
41+
42+
## Set up a KV namespace
43+
44+
Create the KV namespace:
45+
46+
```bash
47+
npx wrangler kv namespace create "OAUTH_KV"
48+
```
49+
50+
Then, update the Wrangler file with the generated KV namespace ID.
51+
52+
## Deploy & Test
53+
54+
Deploy the MCP server to make it available on your workers.dev domain:
55+
56+
```bash
57+
npx wrangler deploy -e <ENVIRONMENT>
58+
```
59+
60+
Test the remote server using [Inspector](https://modelcontextprotocol.io/docs/tools/inspector):
61+
62+
```bash
63+
npx @modelcontextprotocol/inspector@latest
64+
```

apps/ai-gateway/README.md

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# Cloudflare AI Gateway MCP Server 📡
2+
3+
This is a [Model Context Protocol (MCP)](https://modelcontextprotocol.io/introduction) server that supports remote MCP
4+
connections, with Cloudflare OAuth built-in.
5+
6+
It integrates tools powered by the [Cloudflare AI Gateway API](https://developers.cloudflare.com/ai-gateway/) to provide global
7+
Internet traffic insights, trends and other utilities.
8+
9+
## 🔨 Available Tools
10+
11+
Currently available tools:
12+
13+
| **Tool** | **Description** |
14+
| ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
15+
| `list_gateways` | Lists all AI Gateways associated with the account, supporting pagination for easy navigation. |
16+
| `list_logs` | Retrieves logs for a specified gateway, offering filters such as date ranges, feedback scores, success status, model, and provider. |
17+
| `get_log_details` | Fetches detailed information about a specific log identified by its log ID within a gateway. |
18+
| `get_log_request_body` | Retrieves the request body associated with a specific log in a gateway. |
19+
| `get_log_response_body` | Retrieves the response body associated with a specific log in a gateway. |
20+
21+
**Note:** To use these tools, ensure you have an active account set. If not, use `accounts_list` to list your accounts and `set_active_account` to set one as active.
22+
23+
This MCP server is still a work in progress, and we plan to add more tools in the future.
24+
25+
### Prompt Examples
26+
27+
- `List all my AI Gateways.`
28+
- `Show logs for gateway 'gateway-001' between January 1, 2023, and January 31, 2023.`
29+
- `Fetch the latest errors from gateway-001 and debug what might have happened wrongly`
30+
31+
## Access the remote MCP server from from any MCP Client
32+
33+
If your MCP client has first class support for remote MCP servers, the client will provide a way to accept the server URL (`https://ai-gateway.mcp.cloudflare.com`) directly within its interface (for example in[Cloudflare AI Playground](https://playground.ai.cloudflare.com/)).
34+
35+
If your client does not yet support remote MCP servers, you will need to set up its resepective configuration file using mcp-remote (https://www.npmjs.com/package/mcp-remote) to specify which servers your client can access.
36+
37+
Replace the content with the following configuration:
38+
39+
```json
40+
{
41+
"mcpServers": {
42+
"cloudflare": {
43+
"command": "npx",
44+
"args": ["mcp-remote", "https://ai-gateway.mcp.cloudflare.com/sse"]
45+
}
46+
}
47+
}
48+
```
49+
50+
Once you've set up your configuration file, restart MCP client and a browser window will open showing your OAuth login page. Proceed through the authentication flow to grant the client access to your MCP server. After you grant access, the tools will become available for you to use.
51+
52+
Interested in contributing, and running this server locally? See [CONTRIBUTING.md](CONTRIBUTING.md) to get started.

apps/ai-gateway/package.json

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

apps/ai-gateway/src/context.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import type { UserDetails } from '@repo/mcp-common/src/durable-objects/user_details'
2+
import type { AIGatewayMCP } from './index'
3+
4+
export interface Env {
5+
OAUTH_KV: KVNamespace
6+
ENVIRONMENT: 'development' | 'staging' | 'production'
7+
MCP_SERVER_NAME: string
8+
MCP_SERVER_VERSION: string
9+
CLOUDFLARE_CLIENT_ID: string
10+
CLOUDFLARE_CLIENT_SECRET: string
11+
MCP_OBJECT: DurableObjectNamespace<AIGatewayMCP>
12+
USER_DETAILS: DurableObjectNamespace<UserDetails>
13+
MCP_METRICS: AnalyticsEngineDataset
14+
DEV_DISABLE_OAUTH: string
15+
DEV_CLOUDFLARE_API_TOKEN: string
16+
DEV_CLOUDFLARE_EMAIL: string
17+
}

apps/ai-gateway/src/index.ts

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
import OAuthProvider from '@cloudflare/workers-oauth-provider'
2+
import { McpAgent } from 'agents/mcp'
3+
4+
import {
5+
createAuthHandlers,
6+
handleTokenExchangeCallback,
7+
} from '@repo/mcp-common/src/cloudflare-oauth-handler'
8+
import { handleDevMode } from '@repo/mcp-common/src/dev-mode'
9+
import { getUserDetails, UserDetails } from '@repo/mcp-common/src/durable-objects/user_details'
10+
import { getEnv } from '@repo/mcp-common/src/env'
11+
import { RequiredScopes } from '@repo/mcp-common/src/scopes'
12+
import { CloudflareMCPServer } from '@repo/mcp-common/src/server'
13+
import { registerAccountTools } from '@repo/mcp-common/src/tools/account'
14+
15+
import { MetricsTracker } from '../../../packages/mcp-observability/src'
16+
import { registerAIGatewayTools } from './tools/ai-gateway'
17+
18+
import type { AuthProps } from '@repo/mcp-common/src/cloudflare-oauth-handler'
19+
import type { Env } from './context'
20+
21+
const env = getEnv<Env>()
22+
23+
export { UserDetails }
24+
25+
const metrics = new MetricsTracker(env.MCP_METRICS, {
26+
name: env.MCP_SERVER_NAME,
27+
version: env.MCP_SERVER_VERSION,
28+
})
29+
30+
// Context from the auth process, encrypted & stored in the auth token
31+
// and provided to the DurableMCP as this.props
32+
type Props = AuthProps
33+
type State = { activeAccountId: string | null }
34+
35+
export class AIGatewayMCP extends McpAgent<Env, State, Props> {
36+
_server: CloudflareMCPServer | undefined
37+
set server(server: CloudflareMCPServer) {
38+
this._server = server
39+
}
40+
get server(): CloudflareMCPServer {
41+
if (!this._server) {
42+
throw new Error('Tried to access server before it was initialized')
43+
}
44+
45+
return this._server
46+
}
47+
48+
constructor(ctx: DurableObjectState, env: Env) {
49+
super(ctx, env)
50+
}
51+
52+
async init() {
53+
this.server = new CloudflareMCPServer({
54+
userId: this.props.user.id,
55+
wae: this.env.MCP_METRICS,
56+
serverInfo: {
57+
name: this.env.MCP_SERVER_NAME,
58+
version: this.env.MCP_SERVER_VERSION,
59+
},
60+
})
61+
62+
registerAccountTools(this)
63+
64+
// Register Cloudflare Log Push tools
65+
registerAIGatewayTools(this)
66+
}
67+
68+
async getActiveAccountId() {
69+
try {
70+
// Get UserDetails Durable Object based off the userId and retrieve the activeAccountId from it
71+
// we do this so we can persist activeAccountId across sessions
72+
const userDetails = getUserDetails(env, this.props.user.id)
73+
return await userDetails.getActiveAccountId()
74+
} catch (e) {
75+
this.server.recordError(e)
76+
return null
77+
}
78+
}
79+
80+
async setActiveAccountId(accountId: string) {
81+
try {
82+
const userDetails = getUserDetails(env, this.props.user.id)
83+
await userDetails.setActiveAccountId(accountId)
84+
} catch (e) {
85+
this.server.recordError(e)
86+
}
87+
}
88+
}
89+
90+
const AIGatewayScopes = {
91+
...RequiredScopes,
92+
'account:read': 'See your account info such as account details, analytics, and memberships.',
93+
'aig:read': 'Grants read level access to AI Gateway.',
94+
} as const
95+
96+
export default {
97+
fetch: async (req: Request, env: Env, ctx: ExecutionContext) => {
98+
if (env.ENVIRONMENT === 'development' && env.DEV_DISABLE_OAUTH === 'true') {
99+
return await handleDevMode(AIGatewayMCP, req, env, ctx)
100+
}
101+
102+
return new OAuthProvider({
103+
apiHandlers: {
104+
'/mcp': AIGatewayMCP.serve('/mcp'),
105+
'/sse': AIGatewayMCP.serveSSE('/sse'),
106+
},
107+
// @ts-ignore
108+
defaultHandler: createAuthHandlers({ scopes: AIGatewayScopes, metrics }),
109+
authorizeEndpoint: '/oauth/authorize',
110+
tokenEndpoint: '/token',
111+
tokenExchangeCallback: (options) =>
112+
handleTokenExchangeCallback(
113+
options,
114+
env.CLOUDFLARE_CLIENT_ID,
115+
env.CLOUDFLARE_CLIENT_SECRET
116+
),
117+
// Cloudflare access token TTL
118+
accessTokenTTL: 3600,
119+
clientRegistrationEndpoint: '/register',
120+
}).fetch(req, env, ctx)
121+
},
122+
}

0 commit comments

Comments
 (0)