Skip to content

Commit 4dfa376

Browse files
committed
add get_http_requests_data tool
1 parent ac8b912 commit 4dfa376

File tree

2 files changed

+157
-8
lines changed

2 files changed

+157
-8
lines changed

apps/radar/src/tools/radar.ts

Lines changed: 68 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,19 @@ import { getCloudflareClient } from '@repo/mcp-common/src/cloudflare-api'
22
import { PaginationLimitParam, PaginationOffsetParam } from '@repo/mcp-common/src/types/shared'
33

44
import {
5+
AsnArrayParam,
56
AsnParam,
67
AsOrderByParam,
8+
ContinentArrayParam,
9+
DataFormatParam,
10+
DateEndArrayParam,
711
DateEndParam,
12+
DateStartArrayParam,
813
DateStartParam,
14+
HttpDimensionParam,
915
IpParam,
10-
SingleLocationParam,
16+
LocationArrayParam,
17+
LocationParam,
1118
} from '../types/radar'
1219

1320
import type { RadarMCP } from '../index'
@@ -19,7 +26,7 @@ export function registerRadarTools(agent: RadarMCP) {
1926
{
2027
limit: PaginationLimitParam,
2128
offset: PaginationOffsetParam,
22-
location: SingleLocationParam,
29+
location: LocationParam,
2330
orderBy: AsOrderByParam,
2431
},
2532
async ({ limit, offset, location, orderBy }) => {
@@ -130,7 +137,7 @@ export function registerRadarTools(agent: RadarMCP) {
130137
limit: PaginationLimitParam,
131138
offset: PaginationOffsetParam,
132139
asn: AsnParam.optional(),
133-
location: SingleLocationParam,
140+
location: LocationParam,
134141
// TODO maybe we don't need this param since we have the other two dateRange: DateRangeParam.optional(),
135142
dateStart: DateStartParam,
136143
dateEnd: DateEndParam,
@@ -170,4 +177,62 @@ export function registerRadarTools(agent: RadarMCP) {
170177
}
171178
}
172179
)
180+
181+
agent.server.tool(
182+
'get_http_requests_data',
183+
'Get HTTP requests data',
184+
{
185+
dateStart: DateStartArrayParam,
186+
dateEnd: DateEndArrayParam,
187+
// TODO maybe we don't need this param since we have the other two dateRange: DateRangeParam.optional(),
188+
asn: AsnArrayParam,
189+
continent: ContinentArrayParam,
190+
location: LocationArrayParam,
191+
format: DataFormatParam,
192+
dimension: HttpDimensionParam,
193+
},
194+
async ({ dateStart, dateEnd, asn, location, continent, format, dimension }) => {
195+
try {
196+
const client = getCloudflareClient(agent.props.accessToken)
197+
198+
if (!dimension && format !== 'timeseries') {
199+
throw new Error(
200+
`Missing 'dimension' parameter. The '${format}' format requires a dimension to group the data.`
201+
)
202+
}
203+
const endpoint =
204+
format === 'timeseries'
205+
? client.radar.http[format]
206+
: client.radar.http[format][dimension!]
207+
208+
const r = await endpoint({
209+
asn: asn ?? undefined,
210+
continent: continent ?? undefined,
211+
location: location ?? undefined,
212+
dateStart: dateStart,
213+
dateEnd: dateEnd,
214+
})
215+
216+
return {
217+
content: [
218+
{
219+
type: 'text',
220+
text: JSON.stringify({
221+
result: r,
222+
}),
223+
},
224+
],
225+
}
226+
} catch (error) {
227+
return {
228+
content: [
229+
{
230+
type: 'text',
231+
text: `Error getting HTTP data: ${error instanceof Error && error.message}`,
232+
},
233+
],
234+
}
235+
}
236+
}
237+
)
173238
}

apps/radar/src/types/radar.ts

Lines changed: 89 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import { z } from 'zod'
55

66
import type { ASNListParams } from 'cloudflare/resources/radar/entities/asns.mjs'
7+
import type { HTTPTimeseriesParams } from 'cloudflare/resources/radar/http.mjs'
78
import type { TrafficAnomalyGetParams } from 'cloudflare/resources/radar/traffic-anomalies.mjs'
89

910
export const AsnParam = z
@@ -21,29 +22,112 @@ export const DateRangeParam: z.ZodType<TrafficAnomalyGetParams['dateRange']> = z
2122
'Invalid Date Range'
2223
)
2324
.describe(
24-
"Date range string in the format of 'Xd' or 'Xw', where X is a number of days (1–364) or weeks (1–52), optionally suffixed with 'control'."
25+
"Date range string in the format of 'Xd' or 'Xw', where X is a number of days (1–364) or weeks (1–52), optionally suffixed with 'control'." +
26+
'Either use this parameter or set specific start and end dates (`dateStart` and `dateEnd` parameters).'
2527
)
2628

27-
export const DateStartParam: z.ZodType<TrafficAnomalyGetParams['dateStart']> = z
29+
export const DateRangeArrayParam: z.ZodType<HTTPTimeseriesParams['dateRange']> = z.array(
30+
z
31+
.string()
32+
.toLowerCase()
33+
.regex(
34+
/^((([1-9]|[1-9][0-9]|[1-2][0-9][0-9]|3[0-5][0-9]|36[0-4])[d](control)?)|(([1-9]|[1-4][0-9]|5[0-2])[w](control)?))$/,
35+
'Invalid Date Range'
36+
)
37+
.describe(
38+
'Filters results by date range. ' +
39+
'Either use this parameter or set specific start and end dates (`dateStart` and `dateEnd` parameters).'
40+
)
41+
)
42+
43+
export const DateStartParam = z
2844
.string()
2945
.datetime()
3046
.describe('Start date in ISO 8601 format (e.g., 2023-04-01T00:00:00Z).')
3147

32-
export const DateEndParam: z.ZodType<TrafficAnomalyGetParams['dateEnd']> = z
48+
export const DateStartArrayParam: z.ZodType<HTTPTimeseriesParams['dateStart']> = z
49+
.array(DateStartParam)
50+
.describe(
51+
'Start of the date range. ' +
52+
'Either use this parameter together with `dateEnd` or use `dateRange`.'
53+
)
54+
55+
export const DateEndParam = z
3356
.string()
3457
.datetime()
3558
.describe('End date in ISO 8601 format (e.g., 2023-04-30T23:59:59Z).')
3659

37-
export const SingleLocationParam: z.ZodType<ASNListParams['location']> = z
60+
export const DateEndArrayParam: z.ZodType<HTTPTimeseriesParams['dateEnd']> = z
61+
.array(DateEndParam)
62+
.describe(
63+
'End of the date range. ' +
64+
'Either use this parameter together with `dateStart` or use `dateRange`.'
65+
)
66+
67+
export const LocationParam: z.ZodType<ASNListParams['location']> = z
3868
.string()
3969
.regex(/^[a-zA-Z]{2}$/, {
4070
message:
4171
'Invalid location code. Must be a valid alpha-2 location code (two letters, case insensitive).',
4272
})
4373
.optional()
44-
.describe('Optional alpha-2 country code (e.g., "US", "DE").')
74+
.describe('Filters results by location. Specify a valid alpha-2 location code.')
75+
76+
export const LocationArrayParam: z.ZodType<HTTPTimeseriesParams['location']> = z
77+
.array(
78+
z.string().regex(/^(-?[a-zA-Z]{2})$/, {
79+
message: 'Each value must be a valid alpha-2 location code, optionally prefixed with `-`.',
80+
})
81+
)
82+
.optional()
83+
.describe(
84+
'Filters results by location. Provide an array of alpha-2 country codes (e.g., "US", "PT"). ' +
85+
'Prefix a code with `-` to exclude it (e.g., ["-US", "PT"] excludes the US and includes Portugal).'
86+
)
87+
88+
export const ContinentArrayParam: z.ZodType<HTTPTimeseriesParams['continent']> = z
89+
.array(
90+
z.string().regex(/^(-?[a-zA-Z]{2})$/, {
91+
message: 'Each value must be a valid alpha-2 continent code, optionally prefixed with `-`.',
92+
})
93+
)
94+
.optional()
95+
.describe(
96+
'Filters results by continent. Provide an array of alpha-2 continent codes (e.g., "EU", "NA"). ' +
97+
'Prefix a code with `-` to exclude it (e.g., ["-EU", "NA"] excludes Europe and includes North America).'
98+
)
99+
100+
export const AsnArrayParam: z.ZodType<HTTPTimeseriesParams['asn']> = z
101+
.array(z.string().refine((val) => val !== '0', { message: 'ASN cannot be 0' }))
102+
.optional()
103+
.describe(
104+
'Filters results by Autonomous System Number (ASN). Provide an array of ASN strings. ' +
105+
'Prefix with `-` to exclude (e.g., ["-174", "3356"] excludes AS174 and includes AS3356). '
106+
)
45107

46108
export const AsOrderByParam: z.ZodType<ASNListParams['orderBy']> = z
47109
.enum(['ASN', 'POPULATION'])
48110
.optional()
49111
.describe('Optional order by parameter: "ASN" or "POPULATION".')
112+
113+
export const DataFormatParam = z
114+
.enum(['timeseries', 'summary', 'timeseriesGroups'])
115+
.describe(
116+
"Specifies the data format: 'summary' for aggregated results by dimension, 'timeseries' for a time-based view of HTTP requests, or 'timeseriesGroups' to group timeseries data by dimensions."
117+
)
118+
119+
export const HttpDimensionParam = z
120+
.enum([
121+
'deviceType',
122+
'httpProtocol',
123+
'httpVersion',
124+
'botClass',
125+
'ipVersion',
126+
'tlsVersion',
127+
'os',
128+
'postQuantum',
129+
])
130+
.optional()
131+
.describe(
132+
"Dimension used to group HTTP data. Allowed only when the format is 'summary' or 'timeseries_groups'. For example, use 'device_type' to group by device type."
133+
)

0 commit comments

Comments
 (0)