Skip to content

Commit eeefc82

Browse files
committed
add MCP metrics
1 parent 54303d9 commit eeefc82

File tree

7 files changed

+98
-43
lines changed

7 files changed

+98
-43
lines changed

apps/radar/README.md

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ Internet traffic insights, trends and other utilities.
1111
Currently available tools:
1212

1313
| **Category** | **Tool** | **Description** |
14-
|------------------------|---------------------------|---------------------------------------------------------------------------------------------------------------------------|
14+
| ---------------------- | ------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
1515
| **HTTP Requests** | `get_http_requests_data` | Fetches HTTP request data (timeseries, summaries, and grouped timeseries across dimensions like `deviceType`, `botClass`) |
1616
| **Autonomous Systems** | `list_autonomous_systems` | Lists ASes; filter by location and sort by population size |
1717
| | `get_as_details` | Retrieves detailed info for a specific ASN |
@@ -64,17 +64,17 @@ This will require you to create another OAuth App on Cloudflare:
6464

6565
1. Create a `.dev.vars` file in your project root with:
6666

67-
```
68-
CLOUDFLARE_CLIENT_ID=your_development_cloudflare_client_id
69-
CLOUDFLARE_CLIENT_SECRET=your_development_cloudflare_client_secret
70-
URL_SCANNER_API_TOKEN=your_development_url_scanner_api_token
71-
```
67+
```
68+
CLOUDFLARE_CLIENT_ID=your_development_cloudflare_client_id
69+
CLOUDFLARE_CLIENT_SECRET=your_development_cloudflare_client_secret
70+
URL_SCANNER_API_TOKEN=your_development_url_scanner_api_token
71+
```
7272

7373
2. Start the local development server:
7474

75-
```bash
76-
npx wrangler dev
77-
```
75+
```bash
76+
npx wrangler dev
77+
```
7878

7979
3. To test locally, open Inspector, and connect to `http://localhost:8788/sse`.
80-
Once you follow the prompts, you'll be able to "List Tools".
80+
Once you follow the prompts, you'll be able to "List Tools".

apps/radar/package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"scripts": {
66
"check:lint": "run-eslint-workers",
77
"check:types": "run-tsc",
8-
"deploy": "wrangler deploy",
8+
"deploy": "run-wrangler-deploy",
99
"dev": "wrangler dev",
1010
"start": "wrangler dev",
1111
"cf-typegen": "wrangler types",
@@ -16,6 +16,7 @@
1616
"@hono/zod-validator": "0.4.3",
1717
"@modelcontextprotocol/sdk": "1.9.0",
1818
"@repo/mcp-common": "workspace:*",
19+
"@repo/mcp-observability": "workspace:*",
1920
"agents": "0.0.62",
2021
"cloudflare": "4.2.0",
2122
"hono": "4.7.6",
@@ -24,6 +25,7 @@
2425
"devDependencies": {
2526
"@cloudflare/vitest-pool-workers": "0.8.14",
2627
"@cloudflare/workers-types": "4.20250410.0",
28+
"@types/node": "^22.14.1",
2729
"prettier": "3.5.3",
2830
"typescript": "5.5.4",
2931
"vitest": "3.0.9",

apps/radar/src/index.ts

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,57 @@
11
import OAuthProvider from '@cloudflare/workers-oauth-provider'
2-
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
32
import { McpAgent } from 'agents/mcp'
43
import { env } from 'cloudflare:workers'
54

65
import {
76
createAuthHandlers,
87
handleTokenExchangeCallback,
98
} from '@repo/mcp-common/src/cloudflare-oauth-handler'
9+
import { CloudflareMCPServer } from '@repo/mcp-common/src/server'
10+
import { MetricsTracker } from '@repo/mcp-observability'
1011

1112
import { registerRadarTools } from './tools/radar'
1213
import { registerUrlScannerTools } from './tools/url-scanner'
1314

15+
import type { UserSchema } from '@repo/mcp-common/src/cloudflare-oauth-handler'
16+
17+
const metrics = new MetricsTracker(env.MCP_METRICS, {
18+
name: env.MCP_SERVER_NAME,
19+
version: env.MCP_SERVER_VERSION,
20+
})
21+
1422
// Context from the auth process, encrypted & stored in the auth token
1523
// and provided to the DurableMCP as this.props
1624
export type Props = {
1725
accessToken: string
26+
user: UserSchema['result']
1827
}
1928

2029
export type State = never
2130

2231
export class RadarMCP extends McpAgent<Env, State, Props> {
23-
server = new McpServer({
24-
name: 'Cloudflare Radar Remote MCP Server',
25-
version: '1.0.0',
26-
})
27-
28-
constructor(
29-
public ctx: DurableObjectState,
30-
public env: Env
31-
) {
32+
_server: CloudflareMCPServer | undefined
33+
set server(server: CloudflareMCPServer) {
34+
this._server = server
35+
}
36+
37+
get server(): CloudflareMCPServer {
38+
if (!this._server) {
39+
throw new Error('Tried to access server before it was initialized')
40+
}
41+
42+
return this._server
43+
}
44+
45+
constructor(ctx: DurableObjectState, env: Env) {
3246
super(ctx, env)
3347
}
3448

3549
async init() {
50+
this.server = new CloudflareMCPServer(this.props.user.id, this.env.MCP_METRICS, {
51+
name: this.env.MCP_SERVER_NAME,
52+
version: this.env.MCP_SERVER_VERSION,
53+
})
54+
3655
registerRadarTools(this)
3756
registerUrlScannerTools(this)
3857
}
@@ -49,7 +68,7 @@ export default new OAuthProvider({
4968
// @ts-ignore
5069
apiHandler: RadarMCP.mount('/sse'),
5170
// @ts-ignore
52-
defaultHandler: createAuthHandlers({ scopes: RadarScopes }),
71+
defaultHandler: createAuthHandlers({ scopes: RadarScopes, metrics }),
5372
authorizeEndpoint: '/oauth/authorize',
5473
tokenEndpoint: '/token',
5574
tokenExchangeCallback: (options) =>

apps/radar/src/tools/radar.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -184,8 +184,8 @@ export function registerRadarTools(agent: RadarMCP) {
184184
agent.server.tool(
185185
'get_http_requests_data',
186186
'Retrieve HTTP request trends. Provide either a `dateRange`, or both `dateStart` and `dateEnd`, to define the time window. ' +
187-
'Use arrays to compare multiple filters — the array index determines which series each filter value belongs to.' +
188-
'For each filter series, you must provide a corresponding `dateRange`, or a `dateStart`/`dateEnd` pair.',
187+
'Use arrays to compare multiple filters — the array index determines which series each filter value belongs to.' +
188+
'For each filter series, you must provide a corresponding `dateRange`, or a `dateStart`/`dateEnd` pair.',
189189
{
190190
dateRange: DateRangeArrayParam.optional(),
191191
dateStart: DateStartArrayParam.optional(),
@@ -205,9 +205,10 @@ export function registerRadarTools(agent: RadarMCP) {
205205
}
206206

207207
const client = getCloudflareClient(agent.props.accessToken)
208-
const endpoint = (...args: any) => format === 'timeseries'
209-
? client.radar.http[format](...args)
210-
: client.radar.http[format][dimension!](...args)
208+
const endpoint = (...args: any) =>
209+
format === 'timeseries'
210+
? client.radar.http[format](...args)
211+
: client.radar.http[format][dimension!](...args)
211212

212213
const r = await endpoint({
213214
asn: asn ?? undefined,

apps/radar/worker-configuration.d.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
1-
// Generated by Wrangler by running `wrangler types` (hash: 4c15ae95f0b70565da83b0950cd1543a)
1+
// Generated by Wrangler by running `wrangler types` (hash: 89a56f47391b45855db2f400ee014e0c)
22
// Runtime types generated with [email protected] 2025-03-10 nodejs_compat
33
declare namespace Cloudflare {
44
interface Env {
55
OAUTH_KV: KVNamespace;
66
ENVIRONMENT: "development" | "staging" | "production";
77
ACCOUNT_ID: "6702657b6aa048cf3081ff3ff3c9c52f";
8+
MCP_SERVER_NAME: "Cloudflare Radar Remote MCP Server - Dev" | "Cloudflare Radar Remote MCP Server - Staging" | "Cloudflare Radar Remote MCP Server";
9+
MCP_SERVER_VERSION: "1.0.0";
810
CLOUDFLARE_CLIENT_ID: string;
911
CLOUDFLARE_CLIENT_SECRET: string;
1012
URL_SCANNER_API_TOKEN: string;
1113
MCP_OBJECT: DurableObjectNamespace<import("./src/index").RadarMCP>;
14+
MCP_METRICS: AnalyticsEngineDataset;
1215
}
1316
}
1417
interface Env extends Cloudflare.Env {}

apps/radar/wrangler.jsonc

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,16 @@
3333
],
3434
"vars": {
3535
"ENVIRONMENT": "development",
36-
"ACCOUNT_ID": "6702657b6aa048cf3081ff3ff3c9c52f"
36+
"ACCOUNT_ID": "6702657b6aa048cf3081ff3ff3c9c52f",
37+
"MCP_SERVER_NAME": "Cloudflare Radar Remote MCP Server - Dev",
38+
"MCP_SERVER_VERSION": "1.0.0"
3739
},
40+
"analytics_engine_datasets": [
41+
{
42+
"binding": "MCP_METRICS",
43+
"dataset": "mcp-metrics-dev"
44+
}
45+
],
3846
"dev": {
3947
"port": 8976
4048
},
@@ -61,8 +69,16 @@
6169
],
6270
"vars": {
6371
"ENVIRONMENT": "staging",
64-
"ACCOUNT_ID": "6702657b6aa048cf3081ff3ff3c9c52f"
65-
}
72+
"ACCOUNT_ID": "6702657b6aa048cf3081ff3ff3c9c52f",
73+
"MCP_SERVER_NAME": "Cloudflare Radar Remote MCP Server - Staging",
74+
"MCP_SERVER_VERSION": "1.0.0"
75+
},
76+
"analytics_engine_datasets": [
77+
{
78+
"binding": "MCP_METRICS",
79+
"dataset": "mcp-metrics-staging"
80+
}
81+
]
6682
},
6783
"production": {
6884
"name": "mcp-cloudflare-radar-production",
@@ -84,8 +100,16 @@
84100
],
85101
"vars": {
86102
"ENVIRONMENT": "production",
87-
"ACCOUNT_ID": "6702657b6aa048cf3081ff3ff3c9c52f"
88-
}
103+
"ACCOUNT_ID": "6702657b6aa048cf3081ff3ff3c9c52f",
104+
"MCP_SERVER_NAME": "Cloudflare Radar Remote MCP Server",
105+
"MCP_SERVER_VERSION": "1.0.0"
106+
},
107+
"analytics_engine_datasets": [
108+
{
109+
"binding": "MCP_METRICS",
110+
"dataset": "mcp-metrics-production"
111+
}
112+
]
89113
}
90114
}
91115
}

pnpm-lock.yaml

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

0 commit comments

Comments
 (0)