Skip to content

Commit c56484c

Browse files
authored
added zone_list / zone_details tools (#91)
1 parent b3df874 commit c56484c

File tree

2 files changed

+190
-0
lines changed

2 files changed

+190
-0
lines changed

packages/mcp-common/src/api/zone.ts

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import type { Cloudflare } from 'cloudflare'
2+
3+
export interface ZoneListParams {
4+
client: Cloudflare
5+
accountId: string
6+
page?: number
7+
perPage?: number
8+
direction?: 'asc' | 'desc'
9+
match?: 'any' | 'all'
10+
name?: string
11+
status?: string
12+
order?: string
13+
}
14+
15+
/**
16+
* Lists zones under a Cloudflare account
17+
* @see https://developers.cloudflare.com/api/resources/zones/methods/list/
18+
*/
19+
export async function handleZonesList({
20+
client,
21+
accountId,
22+
page = 1,
23+
perPage = 50,
24+
direction = 'desc',
25+
match = 'all',
26+
name,
27+
status,
28+
order = 'name',
29+
}: ZoneListParams) {
30+
// Build query parameters
31+
const query: Record<string, string | number> = {
32+
page,
33+
per_page: perPage,
34+
direction,
35+
match,
36+
account_id: accountId,
37+
}
38+
39+
// Only add these parameters if they're defined and not empty strings
40+
if (name) {
41+
query.name = name
42+
}
43+
44+
if (status) {
45+
query.status = status
46+
}
47+
48+
if (order) {
49+
query.order = order
50+
}
51+
52+
try {
53+
// Use the zones.list method from the Cloudflare client
54+
const response = await client.zones.list({ query })
55+
return response.result
56+
} catch (error) {
57+
throw new Error(
58+
`Failed to list zones: ${error instanceof Error ? error.message : String(error)}`
59+
)
60+
}
61+
}

packages/mcp-common/src/tools/zone.ts

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
import { z } from 'zod'
2+
3+
import { handleZonesList } from '../api/zone'
4+
import { getCloudflareClient } from '../cloudflare-api'
5+
import { type CloudflareMcpAgent } from '../types/cloudflare-mcp-agent'
6+
7+
export function registerZoneTools(agent: CloudflareMcpAgent) {
8+
// Tool to list all zones under an account
9+
agent.server.tool(
10+
'zones_list',
11+
'List all zones under a Cloudflare account',
12+
{
13+
name: z.string().optional().describe('Filter zones by name'),
14+
status: z
15+
.string()
16+
.optional()
17+
.describe(
18+
'Filter zones by status (active, pending, initializing, moved, deleted, deactivated, read only)'
19+
),
20+
page: z.number().min(1).default(1).describe('Page number for pagination'),
21+
perPage: z.number().min(5).max(1000).default(50).describe('Number of zones per page'),
22+
order: z
23+
.string()
24+
.default('name')
25+
.describe('Field to order results by (name, status, account_name)'),
26+
direction: z
27+
.enum(['asc', 'desc'])
28+
.default('desc')
29+
.describe('Direction to order results (asc, desc)'),
30+
},
31+
async (params) => {
32+
const accountId = await agent.getActiveAccountId()
33+
if (!accountId) {
34+
return {
35+
content: [
36+
{
37+
type: 'text',
38+
text: 'No currently active accountId. Try listing your accounts (accounts_list) and then setting an active account (set_active_account)',
39+
},
40+
],
41+
}
42+
}
43+
44+
try {
45+
const { page = 1, perPage = 50 } = params
46+
47+
const zones = await handleZonesList({
48+
client: getCloudflareClient(agent.props.accessToken),
49+
accountId,
50+
...params,
51+
})
52+
53+
return {
54+
content: [
55+
{
56+
type: 'text',
57+
text: JSON.stringify({
58+
zones,
59+
count: zones.length,
60+
page,
61+
perPage,
62+
accountId,
63+
}),
64+
},
65+
],
66+
}
67+
} catch (error) {
68+
return {
69+
content: [
70+
{
71+
type: 'text',
72+
text: `Error listing zones: ${error instanceof Error ? error.message : String(error)}`,
73+
},
74+
],
75+
}
76+
}
77+
}
78+
)
79+
80+
// Tool to get zone details by ID
81+
agent.server.tool(
82+
'zone_details',
83+
'Get details for a specific Cloudflare zone',
84+
{
85+
zoneId: z.string().describe('The ID of the zone to get details for'),
86+
},
87+
async (params) => {
88+
const accountId = await agent.getActiveAccountId()
89+
if (!accountId) {
90+
return {
91+
content: [
92+
{
93+
type: 'text',
94+
text: 'No currently active accountId. Try listing your accounts (accounts_list) and then setting an active account (set_active_account)',
95+
},
96+
],
97+
}
98+
}
99+
100+
try {
101+
const { zoneId } = params
102+
const client = getCloudflareClient(agent.props.accessToken)
103+
104+
// Use the zones.get method to fetch a specific zone
105+
const response = await client.zones.get({ zone_id: zoneId })
106+
107+
return {
108+
content: [
109+
{
110+
type: 'text',
111+
text: JSON.stringify({
112+
zone: response,
113+
}),
114+
},
115+
],
116+
}
117+
} catch (error) {
118+
return {
119+
content: [
120+
{
121+
type: 'text',
122+
text: `Error fetching zone details: ${error instanceof Error ? error.message : String(error)}`,
123+
},
124+
],
125+
}
126+
}
127+
}
128+
)
129+
}

0 commit comments

Comments
 (0)