chore: import upstream snapshot with attribution
Publish CLI Package / publish-npm (push) Waiting to run
Publish Python SDK / publish-pypi (push) Waiting to run
Publish TypeScript SDK / publish-npm (push) Waiting to run
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 13:20:55 +08:00
commit d25d482dc2
13754 changed files with 4996608 additions and 0 deletions
@@ -0,0 +1,211 @@
import type {
CloudflareCreateDnsRecordParams,
CloudflareCreateDnsRecordResponse,
} from '@/tools/cloudflare/types'
import type { ToolConfig } from '@/tools/types'
export const createDnsRecordTool: ToolConfig<
CloudflareCreateDnsRecordParams,
CloudflareCreateDnsRecordResponse
> = {
id: 'cloudflare_create_dns_record',
name: 'Cloudflare Create DNS Record',
description: 'Creates a new DNS record for a zone.',
version: '1.0.0',
params: {
zoneId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The zone ID to create the DNS record in',
},
type: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'DNS record type (e.g., "A", "AAAA", "CNAME", "MX", "TXT", "NS", "SRV")',
},
name: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'DNS record name (e.g., "example.com" or "subdomain.example.com")',
},
content: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'DNS record content (e.g., IP address for A records, target for CNAME)',
},
ttl: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Time to live in seconds (1 = automatic, default: 1)',
},
proxied: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description: 'Whether to enable Cloudflare proxy (default: false)',
},
priority: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Priority for MX and SRV records',
},
comment: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comment for the DNS record',
},
tags: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated tags for the DNS record',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Cloudflare API Token',
},
},
request: {
url: (params) => `https://api.cloudflare.com/client/v4/zones/${params.zoneId}/dns_records`,
method: 'POST',
headers: (params) => ({
Authorization: `Bearer ${params.apiKey}`,
'Content-Type': 'application/json',
}),
body: (params) => {
const body: Record<string, any> = {
type: params.type,
name: params.name,
content: params.content,
}
if (params.ttl !== undefined) body.ttl = Number(params.ttl)
if (params.proxied !== undefined) body.proxied = params.proxied
if (params.priority !== undefined) body.priority = Number(params.priority)
if (params.comment) body.comment = params.comment
if (params.tags) {
const tagList = String(params.tags)
.split(',')
.map((t) => t.trim())
.filter(Boolean)
if (tagList.length > 0) body.tags = tagList
}
return body
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!data.success) {
return {
success: false,
output: {
id: '',
zone_id: '',
zone_name: '',
type: '',
name: '',
content: '',
proxiable: false,
proxied: false,
ttl: 0,
locked: false,
priority: undefined,
comment: null,
tags: [],
comment_modified_on: null,
tags_modified_on: null,
meta: null,
created_on: '',
modified_on: '',
},
error: data.errors?.[0]?.message ?? 'Failed to create DNS record',
}
}
const record = data.result
return {
success: true,
output: {
id: record?.id ?? '',
zone_id: record?.zone_id ?? '',
zone_name: record?.zone_name ?? '',
type: record?.type ?? '',
name: record?.name ?? '',
content: record?.content ?? '',
proxiable: record?.proxiable ?? false,
proxied: record?.proxied ?? false,
ttl: record?.ttl ?? 0,
locked: record?.locked ?? false,
priority: record?.priority ?? null,
comment: record?.comment ?? null,
tags: record?.tags ?? [],
comment_modified_on: record?.comment_modified_on ?? null,
tags_modified_on: record?.tags_modified_on ?? null,
meta: record?.meta ?? null,
created_on: record?.created_on ?? '',
modified_on: record?.modified_on ?? '',
},
}
},
outputs: {
id: { type: 'string', description: 'Unique identifier for the created DNS record' },
zone_id: { type: 'string', description: 'The ID of the zone the record belongs to' },
zone_name: { type: 'string', description: 'The name of the zone' },
type: { type: 'string', description: 'DNS record type (A, AAAA, CNAME, MX, TXT, etc.)' },
name: { type: 'string', description: 'DNS record hostname' },
content: {
type: 'string',
description: 'DNS record value (e.g., IP address, target hostname)',
},
proxiable: {
type: 'boolean',
description: 'Whether the record can be proxied through Cloudflare',
},
proxied: { type: 'boolean', description: 'Whether Cloudflare proxy is enabled' },
ttl: { type: 'number', description: 'Time to live in seconds (1 = automatic)' },
locked: { type: 'boolean', description: 'Whether the record is locked' },
priority: { type: 'number', description: 'Priority for MX and SRV records', optional: true },
comment: { type: 'string', description: 'Comment associated with the record', optional: true },
tags: {
type: 'array',
description: 'Tags associated with the record',
items: { type: 'string', description: 'Tag value' },
},
comment_modified_on: {
type: 'string',
description: 'ISO 8601 timestamp when the comment was last modified',
optional: true,
},
tags_modified_on: {
type: 'string',
description: 'ISO 8601 timestamp when tags were last modified',
optional: true,
},
meta: {
type: 'object',
description: 'Record metadata',
optional: true,
properties: {
source: { type: 'string', description: 'Source of the DNS record' },
},
},
created_on: { type: 'string', description: 'ISO 8601 timestamp when the record was created' },
modified_on: {
type: 'string',
description: 'ISO 8601 timestamp when the record was last modified',
},
},
}
+246
View File
@@ -0,0 +1,246 @@
import type {
CloudflareCreateZoneParams,
CloudflareCreateZoneResponse,
} from '@/tools/cloudflare/types'
import type { ToolConfig } from '@/tools/types'
export const createZoneTool: ToolConfig<CloudflareCreateZoneParams, CloudflareCreateZoneResponse> =
{
id: 'cloudflare_create_zone',
name: 'Cloudflare Create Zone',
description: 'Adds a new zone (domain) to the Cloudflare account.',
version: '1.0.0',
params: {
name: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The domain name to add (e.g., "example.com")',
},
accountId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The Cloudflare account ID',
},
type: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Zone type: "full" (Cloudflare manages DNS), "partial" (CNAME setup), or "secondary" (secondary DNS)',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Cloudflare API Token',
},
},
request: {
url: 'https://api.cloudflare.com/client/v4/zones',
method: 'POST',
headers: (params) => ({
Authorization: `Bearer ${params.apiKey}`,
'Content-Type': 'application/json',
}),
body: (params) => {
const body: Record<string, any> = {
name: params.name,
account: { id: params.accountId },
}
if (params.type) body.type = params.type
return body
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!data.success) {
return {
success: false,
output: {
id: '',
name: '',
status: '',
paused: false,
type: '',
name_servers: [],
original_name_servers: [],
created_on: '',
modified_on: '',
activated_on: '',
development_mode: 0,
plan: {
id: '',
name: '',
price: 0,
is_subscribed: false,
frequency: '',
currency: '',
legacy_id: '',
},
account: { id: '', name: '' },
owner: { id: '', name: '', type: '' },
meta: {
cdn_only: false,
custom_certificate_quota: 0,
dns_only: false,
foundation_dns: false,
page_rule_quota: 0,
phishing_detected: false,
step: 0,
},
vanity_name_servers: [],
permissions: [],
},
error: data.errors?.[0]?.message ?? 'Failed to create zone',
}
}
const zone = data.result
return {
success: true,
output: {
id: zone?.id ?? '',
name: zone?.name ?? '',
status: zone?.status ?? '',
paused: zone?.paused ?? false,
type: zone?.type ?? '',
name_servers: zone?.name_servers ?? [],
original_name_servers: zone?.original_name_servers ?? [],
created_on: zone?.created_on ?? '',
modified_on: zone?.modified_on ?? '',
activated_on: zone?.activated_on ?? '',
development_mode: zone?.development_mode ?? 0,
plan: {
id: zone?.plan?.id ?? '',
name: zone?.plan?.name ?? '',
price: zone?.plan?.price ?? 0,
is_subscribed: zone?.plan?.is_subscribed ?? false,
frequency: zone?.plan?.frequency ?? '',
currency: zone?.plan?.currency ?? '',
legacy_id: zone?.plan?.legacy_id ?? '',
},
account: {
id: zone?.account?.id ?? '',
name: zone?.account?.name ?? '',
},
owner: {
id: zone?.owner?.id ?? '',
name: zone?.owner?.name ?? '',
type: zone?.owner?.type ?? '',
},
meta: {
cdn_only: zone?.meta?.cdn_only ?? false,
custom_certificate_quota: zone?.meta?.custom_certificate_quota ?? 0,
dns_only: zone?.meta?.dns_only ?? false,
foundation_dns: zone?.meta?.foundation_dns ?? false,
page_rule_quota: zone?.meta?.page_rule_quota ?? 0,
phishing_detected: zone?.meta?.phishing_detected ?? false,
step: zone?.meta?.step ?? 0,
},
vanity_name_servers: zone?.vanity_name_servers ?? [],
permissions: zone?.permissions ?? [],
},
}
},
outputs: {
id: { type: 'string', description: 'Created zone ID' },
name: { type: 'string', description: 'Domain name' },
status: {
type: 'string',
description: 'Zone status (initializing, pending, active, moved)',
},
paused: { type: 'boolean', description: 'Whether the zone is paused' },
type: { type: 'string', description: 'Zone type (full, partial, or secondary)' },
name_servers: {
type: 'array',
description: 'Assigned Cloudflare name servers',
items: { type: 'string', description: 'Name server hostname' },
},
original_name_servers: {
type: 'array',
description: 'Original name servers before moving to Cloudflare',
items: { type: 'string', description: 'Name server hostname' },
optional: true,
},
created_on: { type: 'string', description: 'ISO 8601 date when the zone was created' },
modified_on: {
type: 'string',
description: 'ISO 8601 date when the zone was last modified',
},
activated_on: {
type: 'string',
description: 'ISO 8601 date when the zone was activated',
optional: true,
},
development_mode: {
type: 'number',
description: 'Seconds remaining in development mode (0 = off)',
},
plan: {
type: 'object',
description: 'Zone plan information',
properties: {
id: { type: 'string', description: 'Plan identifier' },
name: { type: 'string', description: 'Plan name' },
price: { type: 'number', description: 'Plan price' },
is_subscribed: {
type: 'boolean',
description: 'Whether the zone is subscribed to the plan',
},
frequency: { type: 'string', description: 'Plan billing frequency' },
currency: { type: 'string', description: 'Plan currency' },
legacy_id: { type: 'string', description: 'Legacy plan identifier' },
},
},
account: {
type: 'object',
description: 'Account the zone belongs to',
properties: {
id: { type: 'string', description: 'Account identifier' },
name: { type: 'string', description: 'Account name' },
},
},
owner: {
type: 'object',
description: 'Zone owner information',
properties: {
id: { type: 'string', description: 'Owner identifier' },
name: { type: 'string', description: 'Owner name' },
type: { type: 'string', description: 'Owner type' },
},
},
meta: {
type: 'object',
description: 'Zone metadata',
properties: {
cdn_only: { type: 'boolean', description: 'Whether the zone is CDN only' },
custom_certificate_quota: { type: 'number', description: 'Custom certificate quota' },
dns_only: { type: 'boolean', description: 'Whether the zone is DNS only' },
foundation_dns: { type: 'boolean', description: 'Whether foundation DNS is enabled' },
page_rule_quota: { type: 'number', description: 'Page rule quota' },
phishing_detected: { type: 'boolean', description: 'Whether phishing was detected' },
step: { type: 'number', description: 'Current setup step' },
},
optional: true,
},
vanity_name_servers: {
type: 'array',
description: 'Custom vanity name servers',
items: { type: 'string', description: 'Vanity name server hostname' },
optional: true,
},
permissions: {
type: 'array',
description: 'User permissions for the zone',
items: { type: 'string', description: 'Permission string' },
optional: true,
},
},
}
@@ -0,0 +1,69 @@
import type {
CloudflareDeleteDnsRecordParams,
CloudflareDeleteDnsRecordResponse,
} from '@/tools/cloudflare/types'
import type { ToolConfig } from '@/tools/types'
export const deleteDnsRecordTool: ToolConfig<
CloudflareDeleteDnsRecordParams,
CloudflareDeleteDnsRecordResponse
> = {
id: 'cloudflare_delete_dns_record',
name: 'Cloudflare Delete DNS Record',
description: 'Deletes a DNS record from a zone.',
version: '1.0.0',
params: {
zoneId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The zone ID containing the DNS record',
},
recordId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The DNS record ID to delete',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Cloudflare API Token',
},
},
request: {
url: (params) =>
`https://api.cloudflare.com/client/v4/zones/${params.zoneId}/dns_records/${params.recordId}`,
method: 'DELETE',
headers: (params) => ({
Authorization: `Bearer ${params.apiKey}`,
'Content-Type': 'application/json',
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!data.success) {
return {
success: false,
output: { id: '' },
error: data.errors?.[0]?.message ?? 'Failed to delete DNS record',
}
}
return {
success: true,
output: {
id: data.result?.id ?? '',
},
}
},
outputs: {
id: { type: 'string', description: 'Deleted record ID' },
},
}
+60
View File
@@ -0,0 +1,60 @@
import type {
CloudflareDeleteZoneParams,
CloudflareDeleteZoneResponse,
} from '@/tools/cloudflare/types'
import type { ToolConfig } from '@/tools/types'
export const deleteZoneTool: ToolConfig<CloudflareDeleteZoneParams, CloudflareDeleteZoneResponse> =
{
id: 'cloudflare_delete_zone',
name: 'Cloudflare Delete Zone',
description: 'Deletes a zone (domain) from the Cloudflare account.',
version: '1.0.0',
params: {
zoneId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The zone ID to delete',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Cloudflare API Token',
},
},
request: {
url: (params) => `https://api.cloudflare.com/client/v4/zones/${params.zoneId}`,
method: 'DELETE',
headers: (params) => ({
Authorization: `Bearer ${params.apiKey}`,
'Content-Type': 'application/json',
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!data.success) {
return {
success: false,
output: { id: '' },
error: data.errors?.[0]?.message ?? 'Failed to delete zone',
}
}
return {
success: true,
output: {
id: data.result?.id ?? '',
},
}
},
outputs: {
id: { type: 'string', description: 'Deleted zone ID' },
},
}
+346
View File
@@ -0,0 +1,346 @@
import type {
CloudflareDnsAnalyticsParams,
CloudflareDnsAnalyticsResponse,
} from '@/tools/cloudflare/types'
import type { ToolConfig } from '@/tools/types'
export const dnsAnalyticsTool: ToolConfig<
CloudflareDnsAnalyticsParams,
CloudflareDnsAnalyticsResponse
> = {
id: 'cloudflare_dns_analytics',
name: 'Cloudflare DNS Analytics',
description: 'Gets DNS analytics report for a zone including query counts and trends.',
version: '1.0.0',
params: {
zoneId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The zone ID to get DNS analytics for',
},
since: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Start date for analytics (ISO 8601, e.g., "2024-01-01T00:00:00Z") or relative (e.g., "-6h")',
},
until: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'End date for analytics (ISO 8601, e.g., "2024-01-31T23:59:59Z") or relative (e.g., "now")',
},
metrics: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description:
'Comma-separated metrics to retrieve (e.g., "queryCount,uncachedCount,staleCount,responseTimeAvg,responseTimeMedian,responseTime90th,responseTime99th")',
},
dimensions: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Comma-separated dimensions to group by (e.g., "queryName,queryType,responseCode,responseCached,coloName,origin,dayOfWeek,tcp,ipVersion,querySizeBucket,responseSizeBucket")',
},
filters: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Filters to apply to the data (e.g., "queryType==A")',
},
sort: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Sort order for the result set. Fields must be included in metrics or dimensions (e.g., "+queryCount" or "-responseTimeAvg")',
},
limit: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Maximum number of results to return',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Cloudflare API Token',
},
},
request: {
url: (params) => {
const url = new URL(
`https://api.cloudflare.com/client/v4/zones/${params.zoneId}/dns_analytics/report`
)
if (params.since) url.searchParams.append('since', params.since)
if (params.until) url.searchParams.append('until', params.until)
if (params.metrics) url.searchParams.append('metrics', params.metrics)
if (params.dimensions) url.searchParams.append('dimensions', params.dimensions)
if (params.filters) url.searchParams.append('filters', params.filters)
if (params.sort) url.searchParams.append('sort', params.sort)
if (params.limit) url.searchParams.append('limit', String(params.limit))
return url.toString()
},
method: 'GET',
headers: (params) => ({
Authorization: `Bearer ${params.apiKey}`,
'Content-Type': 'application/json',
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!data.success) {
return {
success: false,
output: {
totals: {
queryCount: 0,
uncachedCount: 0,
staleCount: 0,
responseTimeAvg: 0,
responseTimeMedian: 0,
responseTime90th: 0,
responseTime99th: 0,
},
min: {
queryCount: 0,
uncachedCount: 0,
staleCount: 0,
responseTimeAvg: 0,
responseTimeMedian: 0,
responseTime90th: 0,
responseTime99th: 0,
},
max: {
queryCount: 0,
uncachedCount: 0,
staleCount: 0,
responseTimeAvg: 0,
responseTimeMedian: 0,
responseTime90th: 0,
responseTime99th: 0,
},
data: [],
data_lag: 0,
rows: 0,
query: {
since: '',
until: '',
metrics: [],
dimensions: [],
filters: '',
sort: [],
limit: 0,
},
},
error: data.errors?.[0]?.message ?? 'Failed to get DNS analytics',
}
}
const result = data.result
return {
success: true,
output: {
totals: {
queryCount: result?.totals?.queryCount ?? 0,
uncachedCount: result?.totals?.uncachedCount ?? 0,
staleCount: result?.totals?.staleCount ?? 0,
responseTimeAvg: result?.totals?.responseTimeAvg ?? 0,
responseTimeMedian: result?.totals?.responseTimeMedian ?? 0,
responseTime90th: result?.totals?.responseTime90th ?? 0,
responseTime99th: result?.totals?.responseTime99th ?? 0,
},
min: {
queryCount: result?.min?.queryCount ?? 0,
uncachedCount: result?.min?.uncachedCount ?? 0,
staleCount: result?.min?.staleCount ?? 0,
responseTimeAvg: result?.min?.responseTimeAvg ?? 0,
responseTimeMedian: result?.min?.responseTimeMedian ?? 0,
responseTime90th: result?.min?.responseTime90th ?? 0,
responseTime99th: result?.min?.responseTime99th ?? 0,
},
max: {
queryCount: result?.max?.queryCount ?? 0,
uncachedCount: result?.max?.uncachedCount ?? 0,
staleCount: result?.max?.staleCount ?? 0,
responseTimeAvg: result?.max?.responseTimeAvg ?? 0,
responseTimeMedian: result?.max?.responseTimeMedian ?? 0,
responseTime90th: result?.max?.responseTime90th ?? 0,
responseTime99th: result?.max?.responseTime99th ?? 0,
},
data:
result?.data?.map((entry: any) => ({
dimensions: entry.dimensions ?? [],
metrics: entry.metrics ?? [],
})) ?? [],
data_lag: result?.data_lag ?? 0,
rows: result?.rows ?? 0,
query: {
since: result?.query?.since ?? '',
until: result?.query?.until ?? '',
metrics: result?.query?.metrics ?? [],
dimensions: result?.query?.dimensions ?? [],
filters: result?.query?.filters ?? '',
sort: result?.query?.sort ?? [],
limit: result?.query?.limit ?? 0,
},
},
}
},
outputs: {
totals: {
type: 'object',
description: 'Aggregate DNS analytics totals for the entire queried period',
properties: {
queryCount: { type: 'number', description: 'Total number of DNS queries' },
uncachedCount: { type: 'number', description: 'Number of uncached DNS queries' },
staleCount: { type: 'number', description: 'Number of stale DNS queries' },
responseTimeAvg: {
type: 'number',
description: 'Average response time in milliseconds',
optional: true,
},
responseTimeMedian: {
type: 'number',
description: 'Median response time in milliseconds',
optional: true,
},
responseTime90th: {
type: 'number',
description: '90th percentile response time in milliseconds',
optional: true,
},
responseTime99th: {
type: 'number',
description: '99th percentile response time in milliseconds',
optional: true,
},
},
},
min: {
type: 'object',
description: 'Minimum values across the analytics period',
optional: true,
properties: {
queryCount: { type: 'number', description: 'Minimum number of DNS queries' },
uncachedCount: { type: 'number', description: 'Minimum number of uncached DNS queries' },
staleCount: { type: 'number', description: 'Minimum number of stale DNS queries' },
responseTimeAvg: {
type: 'number',
description: 'Minimum average response time in milliseconds',
optional: true,
},
responseTimeMedian: {
type: 'number',
description: 'Minimum median response time in milliseconds',
optional: true,
},
responseTime90th: {
type: 'number',
description: 'Minimum 90th percentile response time in milliseconds',
optional: true,
},
responseTime99th: {
type: 'number',
description: 'Minimum 99th percentile response time in milliseconds',
optional: true,
},
},
},
max: {
type: 'object',
description: 'Maximum values across the analytics period',
optional: true,
properties: {
queryCount: { type: 'number', description: 'Maximum number of DNS queries' },
uncachedCount: { type: 'number', description: 'Maximum number of uncached DNS queries' },
staleCount: { type: 'number', description: 'Maximum number of stale DNS queries' },
responseTimeAvg: {
type: 'number',
description: 'Maximum average response time in milliseconds',
optional: true,
},
responseTimeMedian: {
type: 'number',
description: 'Maximum median response time in milliseconds',
optional: true,
},
responseTime90th: {
type: 'number',
description: 'Maximum 90th percentile response time in milliseconds',
optional: true,
},
responseTime99th: {
type: 'number',
description: 'Maximum 99th percentile response time in milliseconds',
optional: true,
},
},
},
data: {
type: 'array',
description: 'Raw analytics data rows returned by the Cloudflare DNS analytics report',
items: {
type: 'object',
properties: {
dimensions: {
type: 'array',
description:
'Dimension values for this data row, parallel to the requested dimensions list',
items: { type: 'string', description: 'Dimension value' },
},
metrics: {
type: 'array',
description: 'Metric values for this data row, parallel to the requested metrics list',
items: { type: 'number', description: 'Metric value' },
},
},
},
},
data_lag: {
type: 'number',
description: 'Processing lag in seconds before analytics data becomes available',
},
rows: {
type: 'number',
description: 'Total number of rows in the result set',
},
query: {
type: 'object',
description: 'Echo of the query parameters sent to the API',
optional: true,
properties: {
since: { type: 'string', description: 'Start date of the analytics query' },
until: { type: 'string', description: 'End date of the analytics query' },
metrics: {
type: 'array',
description: 'Metrics requested in the query',
items: { type: 'string', description: 'Metric name' },
},
dimensions: {
type: 'array',
description: 'Dimensions requested in the query',
items: { type: 'string', description: 'Dimension name' },
},
filters: { type: 'string', description: 'Filters applied to the query' },
sort: {
type: 'array',
description: 'Sort order applied to the query',
items: { type: 'string', description: 'Sort field with direction prefix' },
},
limit: { type: 'number', description: 'Maximum number of results requested' },
},
},
},
}
+218
View File
@@ -0,0 +1,218 @@
import type { CloudflareGetZoneParams, CloudflareGetZoneResponse } from '@/tools/cloudflare/types'
import type { ToolConfig } from '@/tools/types'
export const getZoneTool: ToolConfig<CloudflareGetZoneParams, CloudflareGetZoneResponse> = {
id: 'cloudflare_get_zone',
name: 'Cloudflare Get Zone',
description: 'Gets details for a specific zone (domain) by its ID.',
version: '1.0.0',
params: {
zoneId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The zone ID to retrieve details for',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Cloudflare API Token',
},
},
request: {
url: (params) => `https://api.cloudflare.com/client/v4/zones/${params.zoneId}`,
method: 'GET',
headers: (params) => ({
Authorization: `Bearer ${params.apiKey}`,
'Content-Type': 'application/json',
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!data.success) {
return {
success: false,
output: {
id: '',
name: '',
status: '',
paused: false,
type: '',
name_servers: [],
original_name_servers: [],
created_on: '',
modified_on: '',
activated_on: '',
development_mode: 0,
plan: {
id: '',
name: '',
price: 0,
is_subscribed: false,
frequency: '',
currency: '',
legacy_id: '',
},
account: { id: '', name: '' },
owner: { id: '', name: '', type: '' },
meta: {
cdn_only: false,
custom_certificate_quota: 0,
dns_only: false,
foundation_dns: false,
page_rule_quota: 0,
phishing_detected: false,
step: 0,
},
vanity_name_servers: [],
permissions: [],
},
error: data.errors?.[0]?.message ?? 'Failed to get zone',
}
}
const zone = data.result
return {
success: true,
output: {
id: zone?.id ?? '',
name: zone?.name ?? '',
status: zone?.status ?? '',
paused: zone?.paused ?? false,
type: zone?.type ?? '',
name_servers: zone?.name_servers ?? [],
original_name_servers: zone?.original_name_servers ?? [],
created_on: zone?.created_on ?? '',
modified_on: zone?.modified_on ?? '',
activated_on: zone?.activated_on ?? '',
development_mode: zone?.development_mode ?? 0,
plan: {
id: zone?.plan?.id ?? '',
name: zone?.plan?.name ?? '',
price: zone?.plan?.price ?? 0,
is_subscribed: zone?.plan?.is_subscribed ?? false,
frequency: zone?.plan?.frequency ?? '',
currency: zone?.plan?.currency ?? '',
legacy_id: zone?.plan?.legacy_id ?? '',
},
account: {
id: zone?.account?.id ?? '',
name: zone?.account?.name ?? '',
},
owner: {
id: zone?.owner?.id ?? '',
name: zone?.owner?.name ?? '',
type: zone?.owner?.type ?? '',
},
meta: {
cdn_only: zone?.meta?.cdn_only ?? false,
custom_certificate_quota: zone?.meta?.custom_certificate_quota ?? 0,
dns_only: zone?.meta?.dns_only ?? false,
foundation_dns: zone?.meta?.foundation_dns ?? false,
page_rule_quota: zone?.meta?.page_rule_quota ?? 0,
phishing_detected: zone?.meta?.phishing_detected ?? false,
step: zone?.meta?.step ?? 0,
},
vanity_name_servers: zone?.vanity_name_servers ?? [],
permissions: zone?.permissions ?? [],
},
}
},
outputs: {
id: { type: 'string', description: 'Zone ID' },
name: { type: 'string', description: 'Domain name' },
status: {
type: 'string',
description: 'Zone status (initializing, pending, active, moved)',
},
paused: { type: 'boolean', description: 'Whether the zone is paused' },
type: { type: 'string', description: 'Zone type (full, partial, or secondary)' },
name_servers: {
type: 'array',
description: 'Assigned Cloudflare name servers',
items: { type: 'string', description: 'Name server hostname' },
},
original_name_servers: {
type: 'array',
description: 'Original name servers before moving to Cloudflare',
items: { type: 'string', description: 'Name server hostname' },
optional: true,
},
created_on: { type: 'string', description: 'ISO 8601 date when the zone was created' },
modified_on: { type: 'string', description: 'ISO 8601 date when the zone was last modified' },
activated_on: {
type: 'string',
description: 'ISO 8601 date when the zone was activated',
optional: true,
},
development_mode: {
type: 'number',
description: 'Seconds remaining in development mode (0 = off)',
},
plan: {
type: 'object',
description: 'Zone plan information',
properties: {
id: { type: 'string', description: 'Plan identifier' },
name: { type: 'string', description: 'Plan name' },
price: { type: 'number', description: 'Plan price' },
is_subscribed: {
type: 'boolean',
description: 'Whether the zone is subscribed to the plan',
},
frequency: { type: 'string', description: 'Plan billing frequency' },
currency: { type: 'string', description: 'Plan currency' },
legacy_id: { type: 'string', description: 'Legacy plan identifier' },
},
},
account: {
type: 'object',
description: 'Account the zone belongs to',
properties: {
id: { type: 'string', description: 'Account identifier' },
name: { type: 'string', description: 'Account name' },
},
},
owner: {
type: 'object',
description: 'Zone owner information',
properties: {
id: { type: 'string', description: 'Owner identifier' },
name: { type: 'string', description: 'Owner name' },
type: { type: 'string', description: 'Owner type' },
},
},
meta: {
type: 'object',
description: 'Zone metadata',
properties: {
cdn_only: { type: 'boolean', description: 'Whether the zone is CDN only' },
custom_certificate_quota: { type: 'number', description: 'Custom certificate quota' },
dns_only: { type: 'boolean', description: 'Whether the zone is DNS only' },
foundation_dns: { type: 'boolean', description: 'Whether foundation DNS is enabled' },
page_rule_quota: { type: 'number', description: 'Page rule quota' },
phishing_detected: { type: 'boolean', description: 'Whether phishing was detected' },
step: { type: 'number', description: 'Current setup step' },
},
optional: true,
},
vanity_name_servers: {
type: 'array',
description: 'Custom vanity name servers',
items: { type: 'string', description: 'Vanity name server hostname' },
optional: true,
},
permissions: {
type: 'array',
description: 'User permissions for the zone',
items: { type: 'string', description: 'Permission string' },
optional: true,
},
},
}
@@ -0,0 +1,107 @@
import type {
CloudflareGetZoneSettingsParams,
CloudflareGetZoneSettingsResponse,
} from '@/tools/cloudflare/types'
import type { ToolConfig } from '@/tools/types'
export const getZoneSettingsTool: ToolConfig<
CloudflareGetZoneSettingsParams,
CloudflareGetZoneSettingsResponse
> = {
id: 'cloudflare_get_zone_settings',
name: 'Cloudflare Get Zone Settings',
description:
'Gets all settings for a zone including SSL mode, caching level, and security settings.',
version: '1.0.0',
params: {
zoneId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The zone ID to get settings for',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Cloudflare API Token',
},
},
request: {
url: (params) => `https://api.cloudflare.com/client/v4/zones/${params.zoneId}/settings`,
method: 'GET',
headers: (params) => ({
Authorization: `Bearer ${params.apiKey}`,
'Content-Type': 'application/json',
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!data.success) {
return {
success: false,
output: { settings: [] },
error: data.errors?.[0]?.message ?? 'Failed to get zone settings',
}
}
return {
success: true,
output: {
settings:
data.result?.map((setting: Record<string, unknown>) => ({
id: (setting.id as string) ?? '',
value:
typeof setting.value === 'object' && setting.value !== null
? JSON.stringify(setting.value)
: String(setting.value ?? ''),
editable: (setting.editable as boolean) ?? false,
modified_on: (setting.modified_on as string) ?? '',
...(setting.time_remaining != null
? { time_remaining: setting.time_remaining as number }
: {}),
})) ?? [],
},
}
},
outputs: {
settings: {
type: 'array',
description: 'List of zone settings',
items: {
type: 'object',
properties: {
id: {
type: 'string',
description:
'Setting identifier (e.g., ssl, cache_level, security_level, always_use_https)',
},
value: {
type: 'string',
description:
'Setting value as a string. Simple values returned as-is (e.g., "full", "on"). Complex values are JSON-stringified (e.g., \'{"css":"on","html":"on","js":"on"}\').',
},
editable: {
type: 'boolean',
description: 'Whether the setting can be modified for the current zone plan',
},
modified_on: {
type: 'string',
description: 'ISO 8601 timestamp when the setting was last modified',
},
time_remaining: {
type: 'number',
description:
'Seconds remaining until the setting can be modified again (only present for rate-limited settings)',
optional: true,
},
},
},
},
},
}
+27
View File
@@ -0,0 +1,27 @@
import { createDnsRecordTool } from '@/tools/cloudflare/create_dns_record'
import { createZoneTool } from '@/tools/cloudflare/create_zone'
import { deleteDnsRecordTool } from '@/tools/cloudflare/delete_dns_record'
import { deleteZoneTool } from '@/tools/cloudflare/delete_zone'
import { dnsAnalyticsTool } from '@/tools/cloudflare/dns_analytics'
import { getZoneTool } from '@/tools/cloudflare/get_zone'
import { getZoneSettingsTool } from '@/tools/cloudflare/get_zone_settings'
import { listCertificatesTool } from '@/tools/cloudflare/list_certificates'
import { listDnsRecordsTool } from '@/tools/cloudflare/list_dns_records'
import { listZonesTool } from '@/tools/cloudflare/list_zones'
import { purgeCacheTool } from '@/tools/cloudflare/purge_cache'
import { updateDnsRecordTool } from '@/tools/cloudflare/update_dns_record'
import { updateZoneSettingTool } from '@/tools/cloudflare/update_zone_setting'
export const cloudflareCreateDnsRecordTool = createDnsRecordTool
export const cloudflareCreateZoneTool = createZoneTool
export const cloudflareDeleteDnsRecordTool = deleteDnsRecordTool
export const cloudflareDeleteZoneTool = deleteZoneTool
export const cloudflareDnsAnalyticsTool = dnsAnalyticsTool
export const cloudflareGetZoneTool = getZoneTool
export const cloudflareGetZoneSettingsTool = getZoneSettingsTool
export const cloudflareListCertificatesTool = listCertificatesTool
export const cloudflareListDnsRecordsTool = listDnsRecordsTool
export const cloudflareListZonesTool = listZonesTool
export const cloudflarePurgeCacheTool = purgeCacheTool
export const cloudflareUpdateDnsRecordTool = updateDnsRecordTool
export const cloudflareUpdateZoneSettingTool = updateZoneSettingTool
@@ -0,0 +1,302 @@
import type {
CloudflareListCertificatesParams,
CloudflareListCertificatesResponse,
} from '@/tools/cloudflare/types'
import type { ToolConfig } from '@/tools/types'
export const listCertificatesTool: ToolConfig<
CloudflareListCertificatesParams,
CloudflareListCertificatesResponse
> = {
id: 'cloudflare_list_certificates',
name: 'Cloudflare List Certificates',
description: 'Lists SSL/TLS certificate packs for a zone.',
version: '1.0.0',
params: {
zoneId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The zone ID to list certificates for',
},
status: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Filter certificate packs by status (e.g., "all", "active", "pending")',
},
page: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Page number of paginated results (default: 1)',
},
per_page: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of certificate packs per page (default: 20, min: 5, max: 50)',
},
deploy: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Filter by deployment environment: "staging" or "production"',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Cloudflare API Token',
},
},
request: {
url: (params) => {
const url = new URL(
`https://api.cloudflare.com/client/v4/zones/${params.zoneId}/ssl/certificate_packs`
)
if (params.status) url.searchParams.append('status', params.status)
if (params.page) url.searchParams.append('page', String(params.page))
if (params.per_page) url.searchParams.append('per_page', String(params.per_page))
if (params.deploy) url.searchParams.append('deploy', params.deploy)
return url.toString()
},
method: 'GET',
headers: (params) => ({
Authorization: `Bearer ${params.apiKey}`,
'Content-Type': 'application/json',
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!data.success) {
return {
success: false,
output: { certificates: [], total_count: 0 },
error: data.errors?.[0]?.message ?? 'Failed to list certificates',
}
}
return {
success: true,
output: {
certificates:
data.result?.map((cert: any) => ({
id: cert.id ?? '',
type: cert.type ?? '',
hosts: cert.hosts ?? [],
primary_certificate: cert.primary_certificate ?? '',
status: cert.status ?? '',
certificates:
cert.certificates?.map((c: any) => ({
id: c.id ?? '',
hosts: c.hosts ?? [],
issuer: c.issuer ?? '',
signature: c.signature ?? '',
status: c.status ?? '',
bundle_method: c.bundle_method ?? '',
zone_id: c.zone_id ?? '',
uploaded_on: c.uploaded_on ?? '',
modified_on: c.modified_on ?? '',
expires_on: c.expires_on ?? '',
priority: c.priority ?? 0,
geo_restrictions: c.geo_restrictions ?? undefined,
})) ?? [],
cloudflare_branding: cert.cloudflare_branding ?? false,
validation_method: cert.validation_method ?? '',
validity_days: cert.validity_days ?? 0,
certificate_authority: cert.certificate_authority ?? '',
validation_errors:
cert.validation_errors?.map((e: any) => ({
message: e.message ?? '',
})) ?? [],
validation_records:
cert.validation_records?.map((r: any) => ({
cname: r.cname ?? '',
cname_target: r.cname_target ?? '',
emails: r.emails ?? [],
http_body: r.http_body ?? '',
http_url: r.http_url ?? '',
status: r.status ?? '',
txt_name: r.txt_name ?? '',
txt_value: r.txt_value ?? '',
})) ?? [],
dcv_delegation_records:
cert.dcv_delegation_records?.map((r: any) => ({
cname: r.cname ?? '',
cname_target: r.cname_target ?? '',
emails: r.emails ?? [],
http_body: r.http_body ?? '',
http_url: r.http_url ?? '',
status: r.status ?? '',
txt_name: r.txt_name ?? '',
txt_value: r.txt_value ?? '',
})) ?? [],
})) ?? [],
total_count: data.result_info?.total_count ?? data.result?.length ?? 0,
},
}
},
outputs: {
certificates: {
type: 'array',
description: 'List of SSL/TLS certificate packs',
items: {
type: 'object',
properties: {
id: { type: 'string', description: 'Certificate pack ID' },
type: { type: 'string', description: 'Certificate type (e.g., "universal", "advanced")' },
hosts: {
type: 'array',
description: 'Hostnames covered by this certificate pack',
items: {
type: 'string',
description: 'Hostname',
},
},
primary_certificate: {
type: 'string',
description: 'ID of the primary certificate in the pack',
optional: true,
},
status: {
type: 'string',
description: 'Certificate pack status (e.g., "active", "pending")',
},
certificates: {
type: 'array',
description: 'Individual certificates within the pack',
items: {
type: 'object',
properties: {
id: { type: 'string', description: 'Certificate ID' },
hosts: {
type: 'array',
description: 'Hostnames covered by this certificate',
items: { type: 'string', description: 'Hostname' },
},
issuer: { type: 'string', description: 'Certificate issuer' },
signature: {
type: 'string',
description: 'Signature algorithm (e.g., "ECDSAWithSHA256")',
},
status: { type: 'string', description: 'Certificate status' },
bundle_method: {
type: 'string',
description: 'Bundle method (e.g., "ubiquitous")',
},
zone_id: { type: 'string', description: 'Zone ID the certificate belongs to' },
uploaded_on: { type: 'string', description: 'Upload date (ISO 8601)' },
modified_on: { type: 'string', description: 'Last modified date (ISO 8601)' },
expires_on: { type: 'string', description: 'Expiration date (ISO 8601)' },
priority: {
type: 'number',
description: 'Certificate priority order',
optional: true,
},
geo_restrictions: {
type: 'object',
description: 'Geographic restrictions for the certificate',
optional: true,
properties: {
label: {
type: 'string',
description: 'Geographic restriction label',
},
},
},
},
},
},
cloudflare_branding: {
type: 'boolean',
description: 'Whether Cloudflare branding is enabled on the certificate',
optional: true,
},
validation_method: {
type: 'string',
description: 'Validation method (e.g., "txt", "http", "cname")',
optional: true,
},
validity_days: {
type: 'number',
description: 'Validity period in days',
optional: true,
},
certificate_authority: {
type: 'string',
description: 'Certificate authority (e.g., "lets_encrypt", "google")',
optional: true,
},
validation_errors: {
type: 'array',
description: 'Validation issues for the certificate pack',
optional: true,
items: {
type: 'object',
properties: {
message: {
type: 'string',
description: 'Validation error message',
},
},
},
},
validation_records: {
type: 'array',
description: 'Validation records for the certificate pack',
optional: true,
items: {
type: 'object',
properties: {
cname: { type: 'string', description: 'CNAME record name' },
cname_target: { type: 'string', description: 'CNAME record target' },
emails: {
type: 'array',
description: 'Email addresses for validation',
items: { type: 'string', description: 'Email address' },
},
http_body: { type: 'string', description: 'HTTP validation body content' },
http_url: { type: 'string', description: 'HTTP validation URL' },
status: { type: 'string', description: 'Validation record status' },
txt_name: { type: 'string', description: 'TXT record name' },
txt_value: { type: 'string', description: 'TXT record value' },
},
},
},
dcv_delegation_records: {
type: 'array',
description: 'Domain control validation delegation records',
optional: true,
items: {
type: 'object',
properties: {
cname: { type: 'string', description: 'CNAME record name' },
cname_target: { type: 'string', description: 'CNAME record target' },
emails: {
type: 'array',
description: 'Email addresses for validation',
items: { type: 'string', description: 'Email address' },
},
http_body: { type: 'string', description: 'HTTP validation body content' },
http_url: { type: 'string', description: 'HTTP validation URL' },
status: { type: 'string', description: 'Delegation record status' },
txt_name: { type: 'string', description: 'TXT record name' },
txt_value: { type: 'string', description: 'TXT record value' },
},
},
},
},
},
},
total_count: {
type: 'number',
description: 'Total number of certificate packs',
},
},
}
@@ -0,0 +1,237 @@
import type {
CloudflareListDnsRecordsParams,
CloudflareListDnsRecordsResponse,
} from '@/tools/cloudflare/types'
import type { ToolConfig } from '@/tools/types'
export const listDnsRecordsTool: ToolConfig<
CloudflareListDnsRecordsParams,
CloudflareListDnsRecordsResponse
> = {
id: 'cloudflare_list_dns_records',
name: 'Cloudflare List DNS Records',
description: 'Lists DNS records for a specific zone.',
version: '1.0.0',
params: {
zoneId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The zone ID to list DNS records for',
},
type: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Filter by record type (e.g., "A", "AAAA", "CNAME", "MX", "TXT")',
},
name: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Filter by record name (exact match)',
},
content: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Filter by record content (exact match)',
},
page: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Page number for pagination (default: 1)',
},
per_page: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of records per page (default: 100, max: 5000000)',
},
direction: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Sort direction (asc or desc)',
},
match: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Match logic for filters: any or all (default: all)',
},
order: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Sort field (type, name, content, ttl, proxied)',
},
proxied: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description: 'Filter by proxy status',
},
search: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Free-text search across record name, content, and value',
},
tag: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Filter by an exact tag name',
},
tag_match: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Tag filter match logic: any or all. Only affects results when combined with multiple tag filter conditions; has no effect with the single exact-match Tag Filter above.',
},
commentFilter: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Filter records by comment content (substring match)',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Cloudflare API Token',
},
},
request: {
url: (params) => {
const url = new URL(`https://api.cloudflare.com/client/v4/zones/${params.zoneId}/dns_records`)
if (params.type) url.searchParams.append('type', params.type)
if (params.name) url.searchParams.append('name.exact', params.name)
if (params.content) url.searchParams.append('content.exact', params.content)
if (params.page) url.searchParams.append('page', String(params.page))
if (params.per_page) url.searchParams.append('per_page', String(params.per_page))
if (params.direction) url.searchParams.append('direction', params.direction)
if (params.match) url.searchParams.append('match', params.match)
if (params.order) url.searchParams.append('order', params.order)
if (params.proxied !== undefined) url.searchParams.append('proxied', String(params.proxied))
if (params.search) url.searchParams.append('search', params.search)
if (params.tag) url.searchParams.append('tag.exact', params.tag)
if (params.tag_match) url.searchParams.append('tag_match', params.tag_match)
if (params.commentFilter) url.searchParams.append('comment.contains', params.commentFilter)
return url.toString()
},
method: 'GET',
headers: (params) => ({
Authorization: `Bearer ${params.apiKey}`,
'Content-Type': 'application/json',
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!data.success) {
return {
success: false,
output: { records: [], total_count: 0 },
error: data.errors?.[0]?.message ?? 'Failed to list DNS records',
}
}
return {
success: true,
output: {
records:
data.result?.map((record: any) => ({
id: record.id ?? '',
zone_id: record.zone_id ?? '',
zone_name: record.zone_name ?? '',
type: record.type ?? '',
name: record.name ?? '',
content: record.content ?? '',
proxiable: record.proxiable ?? false,
proxied: record.proxied ?? false,
ttl: record.ttl ?? 0,
locked: record.locked ?? false,
priority: record.priority ?? null,
comment: record.comment ?? null,
tags: record.tags ?? [],
comment_modified_on: record.comment_modified_on ?? null,
tags_modified_on: record.tags_modified_on ?? null,
meta: record.meta ?? null,
created_on: record.created_on ?? '',
modified_on: record.modified_on ?? '',
})) ?? [],
total_count: data.result_info?.total_count ?? data.result?.length ?? 0,
},
}
},
outputs: {
records: {
type: 'array',
description: 'List of DNS records',
items: {
type: 'object',
properties: {
id: { type: 'string', description: 'Unique identifier for the DNS record' },
zone_id: { type: 'string', description: 'The ID of the zone the record belongs to' },
zone_name: { type: 'string', description: 'The name of the zone' },
type: { type: 'string', description: 'Record type (A, AAAA, CNAME, MX, TXT, etc.)' },
name: { type: 'string', description: 'Record name (e.g., example.com)' },
content: { type: 'string', description: 'Record content (e.g., IP address)' },
proxiable: { type: 'boolean', description: 'Whether the record can be proxied' },
proxied: { type: 'boolean', description: 'Whether Cloudflare proxy is enabled' },
ttl: { type: 'number', description: 'TTL in seconds (1 = automatic)' },
locked: { type: 'boolean', description: 'Whether the record is locked' },
priority: { type: 'number', description: 'MX/SRV record priority', optional: true },
comment: {
type: 'string',
description: 'Comment associated with the record',
optional: true,
},
tags: {
type: 'array',
description: 'Tags associated with the record',
items: { type: 'string', description: 'Tag value' },
},
comment_modified_on: {
type: 'string',
description: 'ISO 8601 timestamp when the comment was last modified',
optional: true,
},
tags_modified_on: {
type: 'string',
description: 'ISO 8601 timestamp when tags were last modified',
optional: true,
},
meta: {
type: 'object',
description: 'Record metadata',
optional: true,
properties: {
source: { type: 'string', description: 'Source of the DNS record' },
},
},
created_on: {
type: 'string',
description: 'ISO 8601 timestamp when the record was created',
},
modified_on: {
type: 'string',
description: 'ISO 8601 timestamp when the record was last modified',
},
},
},
},
total_count: {
type: 'number',
description: 'Total number of DNS records matching the query',
},
},
}
+259
View File
@@ -0,0 +1,259 @@
import type {
CloudflareListZonesParams,
CloudflareListZonesResponse,
} from '@/tools/cloudflare/types'
import type { ToolConfig } from '@/tools/types'
export const listZonesTool: ToolConfig<CloudflareListZonesParams, CloudflareListZonesResponse> = {
id: 'cloudflare_list_zones',
name: 'Cloudflare List Zones',
description: 'Lists all zones (domains) in the Cloudflare account.',
version: '1.0.0',
params: {
name: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Filter zones by domain name (e.g., "example.com")',
},
status: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Filter by zone status: "initializing", "pending", "active", or "moved"',
},
page: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Page number for pagination (default: 1)',
},
per_page: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of zones per page (default: 20, max: 50)',
},
accountId: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Filter zones by account ID',
},
order: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Sort field (name, status, account.id, account.name, plan.id)',
},
direction: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Sort direction (asc, desc)',
},
match: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Match logic for filters (any, all). Default: all',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Cloudflare API Token',
},
},
request: {
url: (params) => {
const url = new URL('https://api.cloudflare.com/client/v4/zones')
if (params.name) url.searchParams.append('name', params.name)
if (params.status) url.searchParams.append('status', params.status)
if (params.page) url.searchParams.append('page', String(params.page))
if (params.per_page) url.searchParams.append('per_page', String(params.per_page))
if (params.accountId) url.searchParams.append('account.id', params.accountId)
if (params.order) url.searchParams.append('order', params.order)
if (params.direction) url.searchParams.append('direction', params.direction)
if (params.match) url.searchParams.append('match', params.match)
return url.toString()
},
method: 'GET',
headers: (params) => ({
Authorization: `Bearer ${params.apiKey}`,
'Content-Type': 'application/json',
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!data.success) {
return {
success: false,
output: { zones: [], total_count: 0 },
error: data.errors?.[0]?.message ?? 'Failed to list zones',
}
}
return {
success: true,
output: {
zones:
data.result?.map((zone: any) => ({
id: zone.id ?? '',
name: zone.name ?? '',
status: zone.status ?? '',
paused: zone.paused ?? false,
type: zone.type ?? '',
name_servers: zone.name_servers ?? [],
original_name_servers: zone.original_name_servers ?? [],
created_on: zone.created_on ?? '',
modified_on: zone.modified_on ?? '',
activated_on: zone.activated_on ?? '',
development_mode: zone.development_mode ?? 0,
plan: {
id: zone.plan?.id ?? '',
name: zone.plan?.name ?? '',
price: zone.plan?.price ?? 0,
is_subscribed: zone.plan?.is_subscribed ?? false,
frequency: zone.plan?.frequency ?? '',
currency: zone.plan?.currency ?? '',
legacy_id: zone.plan?.legacy_id ?? '',
},
account: {
id: zone.account?.id ?? '',
name: zone.account?.name ?? '',
},
owner: {
id: zone.owner?.id ?? '',
name: zone.owner?.name ?? '',
type: zone.owner?.type ?? '',
},
meta: {
cdn_only: zone.meta?.cdn_only ?? false,
custom_certificate_quota: zone.meta?.custom_certificate_quota ?? 0,
dns_only: zone.meta?.dns_only ?? false,
foundation_dns: zone.meta?.foundation_dns ?? false,
page_rule_quota: zone.meta?.page_rule_quota ?? 0,
phishing_detected: zone.meta?.phishing_detected ?? false,
step: zone.meta?.step ?? 0,
},
vanity_name_servers: zone.vanity_name_servers ?? [],
permissions: zone.permissions ?? [],
})) ?? [],
total_count: data.result_info?.total_count ?? data.result?.length ?? 0,
},
}
},
outputs: {
zones: {
type: 'array',
description: 'List of zones/domains',
items: {
type: 'object',
properties: {
id: { type: 'string', description: 'Zone ID' },
name: { type: 'string', description: 'Domain name' },
status: {
type: 'string',
description: 'Zone status (initializing, pending, active, moved)',
},
paused: { type: 'boolean', description: 'Whether the zone is paused' },
type: { type: 'string', description: 'Zone type (full, partial, or secondary)' },
name_servers: {
type: 'array',
description: 'Assigned Cloudflare name servers',
items: { type: 'string', description: 'Name server hostname' },
},
original_name_servers: {
type: 'array',
description: 'Original name servers before moving to Cloudflare',
items: { type: 'string', description: 'Name server hostname' },
optional: true,
},
created_on: { type: 'string', description: 'ISO 8601 date when the zone was created' },
modified_on: {
type: 'string',
description: 'ISO 8601 date when the zone was last modified',
},
activated_on: {
type: 'string',
description: 'ISO 8601 date when the zone was activated',
optional: true,
},
development_mode: {
type: 'number',
description: 'Seconds remaining in development mode (0 = off)',
},
plan: {
type: 'object',
description: 'Zone plan information',
properties: {
id: { type: 'string', description: 'Plan identifier' },
name: { type: 'string', description: 'Plan name' },
price: { type: 'number', description: 'Plan price' },
is_subscribed: {
type: 'boolean',
description: 'Whether the zone is subscribed to the plan',
},
frequency: { type: 'string', description: 'Plan billing frequency' },
currency: { type: 'string', description: 'Plan currency' },
legacy_id: { type: 'string', description: 'Legacy plan identifier' },
},
},
account: {
type: 'object',
description: 'Account the zone belongs to',
properties: {
id: { type: 'string', description: 'Account identifier' },
name: { type: 'string', description: 'Account name' },
},
},
owner: {
type: 'object',
description: 'Zone owner information',
properties: {
id: { type: 'string', description: 'Owner identifier' },
name: { type: 'string', description: 'Owner name' },
type: { type: 'string', description: 'Owner type' },
},
},
meta: {
type: 'object',
description: 'Zone metadata',
properties: {
cdn_only: { type: 'boolean', description: 'Whether the zone is CDN only' },
custom_certificate_quota: { type: 'number', description: 'Custom certificate quota' },
dns_only: { type: 'boolean', description: 'Whether the zone is DNS only' },
foundation_dns: { type: 'boolean', description: 'Whether foundation DNS is enabled' },
page_rule_quota: { type: 'number', description: 'Page rule quota' },
phishing_detected: { type: 'boolean', description: 'Whether phishing was detected' },
step: { type: 'number', description: 'Current setup step' },
},
optional: true,
},
vanity_name_servers: {
type: 'array',
description: 'Custom vanity name servers',
items: { type: 'string', description: 'Vanity name server hostname' },
optional: true,
},
permissions: {
type: 'array',
description: 'User permissions for the zone',
items: { type: 'string', description: 'Permission string' },
optional: true,
},
},
},
},
total_count: {
type: 'number',
description: 'Total number of zones matching the query',
},
},
}
+135
View File
@@ -0,0 +1,135 @@
import type {
CloudflarePurgeCacheParams,
CloudflarePurgeCacheResponse,
} from '@/tools/cloudflare/types'
import type { ToolConfig } from '@/tools/types'
export const purgeCacheTool: ToolConfig<CloudflarePurgeCacheParams, CloudflarePurgeCacheResponse> =
{
id: 'cloudflare_purge_cache',
name: 'Cloudflare Purge Cache',
description:
'Purges cached content for a zone. Can purge everything or specific files/tags/hosts/prefixes.',
version: '1.0.0',
params: {
zoneId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The zone ID to purge cache for',
},
purge_everything: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description:
'Set to true to purge all cached content. Mutually exclusive with files, tags, hosts, and prefixes',
},
files: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated list of URLs to purge from cache',
},
tags: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated list of cache tags to purge (Enterprise only)',
},
hosts: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated list of hostnames to purge (Enterprise only)',
},
prefixes: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated list of URL prefixes to purge (Enterprise only)',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Cloudflare API Token',
},
},
request: {
url: (params) => `https://api.cloudflare.com/client/v4/zones/${params.zoneId}/purge_cache`,
method: 'POST',
headers: (params) => ({
Authorization: `Bearer ${params.apiKey}`,
'Content-Type': 'application/json',
}),
body: (params) => {
if (params.purge_everything) {
return { purge_everything: true }
}
const body: Record<string, string[]> = {}
if (params.files) {
const fileList = String(params.files)
.split(',')
.map((f) => f.trim())
.filter(Boolean)
if (fileList.length > 0) body.files = fileList
}
if (params.tags) {
const tagList = String(params.tags)
.split(',')
.map((t) => t.trim())
.filter(Boolean)
if (tagList.length > 0) body.tags = tagList
}
if (params.hosts) {
const hostList = String(params.hosts)
.split(',')
.map((h) => h.trim())
.filter(Boolean)
if (hostList.length > 0) body.hosts = hostList
}
if (params.prefixes) {
const prefixList = String(params.prefixes)
.split(',')
.map((p) => p.trim())
.filter(Boolean)
if (prefixList.length > 0) body.prefixes = prefixList
}
if (Object.keys(body).length === 0) {
throw new Error(
'No purge targets specified. Provide at least one of: files, tags, hosts, or prefixes, or set purge_everything to true.'
)
}
return body
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!data.success) {
return {
success: false,
output: { id: '' },
error: data.errors?.[0]?.message ?? 'Failed to purge cache',
}
}
return {
success: true,
output: {
id: data.result?.id ?? '',
},
}
},
outputs: {
id: { type: 'string', description: 'Purge request identifier returned by Cloudflare' },
},
}
+454
View File
@@ -0,0 +1,454 @@
import type { ToolResponse } from '@/tools/types'
interface CloudflareBaseParams {
apiKey: string
}
export interface CloudflareListZonesParams extends CloudflareBaseParams {
name?: string
status?: string
page?: number
per_page?: number
accountId?: string
order?: string
direction?: string
match?: string
}
interface CloudflareZonePlan {
id: string
name: string
price: number
is_subscribed: boolean
frequency: string
currency: string
legacy_id: string
}
interface CloudflareZoneMeta {
cdn_only: boolean
custom_certificate_quota: number
dns_only: boolean
foundation_dns: boolean
page_rule_quota: number
phishing_detected: boolean
step: number
}
interface CloudflareZone {
id: string
name: string
status: string
paused: boolean
type: string
name_servers: string[]
original_name_servers?: string[]
created_on: string
modified_on: string
activated_on?: string
development_mode?: number
plan?: CloudflareZonePlan
account?: {
id: string
name: string
}
owner?: {
id: string
name: string
type: string
}
meta?: CloudflareZoneMeta
vanity_name_servers?: string[]
permissions?: string[]
}
export interface CloudflareListZonesResponse extends ToolResponse {
output: {
zones: CloudflareZone[]
total_count: number
}
}
export interface CloudflareGetZoneParams extends CloudflareBaseParams {
zoneId: string
}
export interface CloudflareGetZoneResponse extends ToolResponse {
output: {
id: string
name: string
status: string
paused: boolean
type: string
name_servers: string[]
original_name_servers: string[]
created_on: string
modified_on: string
activated_on: string
development_mode: number
plan: CloudflareZonePlan
account: {
id: string
name: string
}
owner: {
id: string
name: string
type: string
}
meta: CloudflareZoneMeta
vanity_name_servers: string[]
permissions: string[]
}
}
export interface CloudflareCreateZoneParams extends CloudflareBaseParams {
name: string
accountId: string
type?: string
}
export interface CloudflareCreateZoneResponse extends ToolResponse {
output: {
id: string
name: string
status: string
paused: boolean
type: string
name_servers: string[]
original_name_servers: string[]
created_on: string
modified_on: string
activated_on: string
development_mode: number
plan: CloudflareZonePlan
account: {
id: string
name: string
}
owner: {
id: string
name: string
type: string
}
meta: CloudflareZoneMeta
vanity_name_servers: string[]
permissions: string[]
}
}
export interface CloudflareDeleteZoneParams extends CloudflareBaseParams {
zoneId: string
}
export interface CloudflareDeleteZoneResponse extends ToolResponse {
output: {
id: string
}
}
export interface CloudflareListDnsRecordsParams extends CloudflareBaseParams {
zoneId: string
type?: string
name?: string
content?: string
page?: number
per_page?: number
direction?: string
match?: string
order?: string
proxied?: boolean
search?: string
tag?: string
tag_match?: string
commentFilter?: string
}
interface CloudflareDnsRecordMeta {
source: string
}
interface CloudflareDnsRecord {
id: string
zone_id: string
zone_name: string
type: string
name: string
content: string
proxiable: boolean
proxied: boolean
ttl: number
locked: boolean
priority?: number
comment?: string | null
tags: string[]
comment_modified_on?: string | null
tags_modified_on?: string | null
meta?: CloudflareDnsRecordMeta | null
created_on: string
modified_on: string
}
export interface CloudflareListDnsRecordsResponse extends ToolResponse {
output: {
records: CloudflareDnsRecord[]
total_count: number
}
}
export interface CloudflareCreateDnsRecordParams extends CloudflareBaseParams {
zoneId: string
type: string
name: string
content: string
ttl?: number
proxied?: boolean
priority?: number
comment?: string
tags?: string
}
export interface CloudflareCreateDnsRecordResponse extends ToolResponse {
output: {
id: string
zone_id: string
zone_name: string
type: string
name: string
content: string
proxiable: boolean
proxied: boolean
ttl: number
locked: boolean
priority?: number
comment?: string | null
tags: string[]
comment_modified_on?: string | null
tags_modified_on?: string | null
meta?: CloudflareDnsRecordMeta | null
created_on: string
modified_on: string
}
}
export interface CloudflareUpdateDnsRecordParams extends CloudflareBaseParams {
zoneId: string
recordId: string
type?: string
name?: string
content?: string
ttl?: number
proxied?: boolean
priority?: number
comment?: string
tags?: string
}
export interface CloudflareUpdateDnsRecordResponse extends ToolResponse {
output: {
id: string
zone_id: string
zone_name: string
type: string
name: string
content: string
proxiable: boolean
proxied: boolean
ttl: number
locked: boolean
priority?: number
comment?: string | null
tags: string[]
comment_modified_on?: string | null
tags_modified_on?: string | null
meta?: CloudflareDnsRecordMeta | null
created_on: string
modified_on: string
}
}
export interface CloudflareDeleteDnsRecordParams extends CloudflareBaseParams {
zoneId: string
recordId: string
}
export interface CloudflareDeleteDnsRecordResponse extends ToolResponse {
output: {
id: string
}
}
export interface CloudflareListCertificatesParams extends CloudflareBaseParams {
zoneId: string
status?: string
page?: number
per_page?: number
deploy?: string
}
interface CloudflareCertificateGeoRestrictions {
label: string
}
interface CloudflareCertificate {
id: string
hosts: string[]
issuer: string
signature: string
status: string
bundle_method: string
zone_id: string
uploaded_on: string
modified_on: string
expires_on: string
priority?: number
geo_restrictions?: CloudflareCertificateGeoRestrictions
}
interface CloudflareCertificateValidationError {
message: string
}
interface CloudflareDcvDelegationRecord {
cname: string
cname_target: string
emails: string[]
http_body: string
http_url: string
status: string
txt_name: string
txt_value: string
}
interface CloudflareCertificatePack {
id: string
type: string
hosts: string[]
primary_certificate: string
status: string
certificates: CloudflareCertificate[]
cloudflare_branding?: boolean
validation_method?: string
validity_days?: number
certificate_authority?: string
validation_errors?: CloudflareCertificateValidationError[]
validation_records?: CloudflareDcvDelegationRecord[]
dcv_delegation_records?: CloudflareDcvDelegationRecord[]
}
export interface CloudflareListCertificatesResponse extends ToolResponse {
output: {
certificates: CloudflareCertificatePack[]
total_count: number
}
}
export interface CloudflarePurgeCacheParams extends CloudflareBaseParams {
zoneId: string
purge_everything?: boolean
files?: string
tags?: string
hosts?: string
prefixes?: string
}
export interface CloudflarePurgeCacheResponse extends ToolResponse {
output: {
id: string
}
}
export interface CloudflareDnsAnalyticsParams extends CloudflareBaseParams {
zoneId: string
since?: string
until?: string
metrics: string
dimensions?: string
filters?: string
sort?: string
limit?: number
}
interface CloudflareDnsAnalyticsTotals {
queryCount: number
uncachedCount: number
staleCount: number
responseTimeAvg?: number
responseTimeMedian?: number
responseTime90th?: number
responseTime99th?: number
}
interface CloudflareDnsAnalyticsQuery {
since: string
until: string
metrics: string[]
dimensions: string[]
filters: string
sort: string[]
limit: number
}
export interface CloudflareDnsAnalyticsResponse extends ToolResponse {
output: {
totals: CloudflareDnsAnalyticsTotals
min: CloudflareDnsAnalyticsTotals
max: CloudflareDnsAnalyticsTotals
data: Array<{
dimensions: string[]
metrics: number[]
}>
data_lag: number
rows: number
query: CloudflareDnsAnalyticsQuery
}
}
export interface CloudflareGetZoneSettingsParams extends CloudflareBaseParams {
zoneId: string
}
interface CloudflareZoneSetting {
id: string
value: string
editable: boolean
modified_on: string
time_remaining?: number
}
export interface CloudflareGetZoneSettingsResponse extends ToolResponse {
output: {
settings: CloudflareZoneSetting[]
}
}
export interface CloudflareUpdateZoneSettingParams extends CloudflareBaseParams {
zoneId: string
settingId: string
value: string
}
export interface CloudflareUpdateZoneSettingResponse extends ToolResponse {
output: {
id: string
value: string
editable: boolean
modified_on: string
time_remaining?: number
}
}
export type CloudflareResponse =
| CloudflareListZonesResponse
| CloudflareGetZoneResponse
| CloudflareCreateZoneResponse
| CloudflareDeleteZoneResponse
| CloudflareListDnsRecordsResponse
| CloudflareCreateDnsRecordResponse
| CloudflareUpdateDnsRecordResponse
| CloudflareDeleteDnsRecordResponse
| CloudflareListCertificatesResponse
| CloudflarePurgeCacheResponse
| CloudflareDnsAnalyticsResponse
| CloudflareGetZoneSettingsResponse
| CloudflareUpdateZoneSettingResponse
@@ -0,0 +1,217 @@
import type {
CloudflareUpdateDnsRecordParams,
CloudflareUpdateDnsRecordResponse,
} from '@/tools/cloudflare/types'
import type { ToolConfig } from '@/tools/types'
export const updateDnsRecordTool: ToolConfig<
CloudflareUpdateDnsRecordParams,
CloudflareUpdateDnsRecordResponse
> = {
id: 'cloudflare_update_dns_record',
name: 'Cloudflare Update DNS Record',
description: 'Updates an existing DNS record for a zone.',
version: '1.0.0',
params: {
zoneId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The zone ID containing the DNS record',
},
recordId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The DNS record ID to update',
},
type: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'DNS record type (e.g., "A", "AAAA", "CNAME", "MX", "TXT")',
},
name: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'DNS record name',
},
content: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'DNS record content (e.g., IP address)',
},
ttl: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Time to live in seconds (1 = automatic)',
},
proxied: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description: 'Whether to enable Cloudflare proxy',
},
priority: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Priority for MX and SRV records',
},
comment: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comment for the DNS record',
},
tags: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated tags for the DNS record',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Cloudflare API Token',
},
},
request: {
url: (params) =>
`https://api.cloudflare.com/client/v4/zones/${params.zoneId}/dns_records/${params.recordId}`,
method: 'PATCH',
headers: (params) => ({
Authorization: `Bearer ${params.apiKey}`,
'Content-Type': 'application/json',
}),
body: (params) => {
const body: Record<string, any> = {}
if (params.type !== undefined) body.type = params.type
if (params.name !== undefined) body.name = params.name
if (params.content !== undefined) body.content = params.content
if (params.ttl !== undefined) body.ttl = Number(params.ttl)
if (params.proxied !== undefined) body.proxied = params.proxied
if (params.priority !== undefined) body.priority = Number(params.priority)
if (params.comment !== undefined) body.comment = params.comment
if (params.tags) {
const tagList = String(params.tags)
.split(',')
.map((t) => t.trim())
.filter(Boolean)
if (tagList.length > 0) body.tags = tagList
}
return body
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!data.success) {
return {
success: false,
output: {
id: '',
zone_id: '',
zone_name: '',
type: '',
name: '',
content: '',
proxiable: false,
proxied: false,
ttl: 0,
locked: false,
priority: undefined,
comment: null,
tags: [],
comment_modified_on: null,
tags_modified_on: null,
meta: null,
created_on: '',
modified_on: '',
},
error: data.errors?.[0]?.message ?? 'Failed to update DNS record',
}
}
const record = data.result
return {
success: true,
output: {
id: record?.id ?? '',
zone_id: record?.zone_id ?? '',
zone_name: record?.zone_name ?? '',
type: record?.type ?? '',
name: record?.name ?? '',
content: record?.content ?? '',
proxiable: record?.proxiable ?? false,
proxied: record?.proxied ?? false,
ttl: record?.ttl ?? 0,
locked: record?.locked ?? false,
priority: record?.priority ?? null,
comment: record?.comment ?? null,
tags: record?.tags ?? [],
comment_modified_on: record?.comment_modified_on ?? null,
tags_modified_on: record?.tags_modified_on ?? null,
meta: record?.meta ?? null,
created_on: record?.created_on ?? '',
modified_on: record?.modified_on ?? '',
},
}
},
outputs: {
id: { type: 'string', description: 'Unique identifier for the updated DNS record' },
zone_id: { type: 'string', description: 'The ID of the zone the record belongs to' },
zone_name: { type: 'string', description: 'The name of the zone' },
type: { type: 'string', description: 'DNS record type (A, AAAA, CNAME, MX, TXT, etc.)' },
name: { type: 'string', description: 'DNS record hostname' },
content: {
type: 'string',
description: 'DNS record value (e.g., IP address, target hostname)',
},
proxiable: {
type: 'boolean',
description: 'Whether the record can be proxied through Cloudflare',
},
proxied: { type: 'boolean', description: 'Whether Cloudflare proxy is enabled' },
ttl: { type: 'number', description: 'Time to live in seconds (1 = automatic)' },
locked: { type: 'boolean', description: 'Whether the record is locked' },
priority: { type: 'number', description: 'Priority for MX and SRV records', optional: true },
comment: { type: 'string', description: 'Comment associated with the record', optional: true },
tags: {
type: 'array',
description: 'Tags associated with the record',
items: { type: 'string', description: 'Tag value' },
},
comment_modified_on: {
type: 'string',
description: 'ISO 8601 timestamp when the comment was last modified',
optional: true,
},
tags_modified_on: {
type: 'string',
description: 'ISO 8601 timestamp when tags were last modified',
optional: true,
},
meta: {
type: 'object',
description: 'Record metadata',
optional: true,
properties: {
source: { type: 'string', description: 'Source of the DNS record' },
},
},
created_on: { type: 'string', description: 'ISO 8601 timestamp when the record was created' },
modified_on: {
type: 'string',
description: 'ISO 8601 timestamp when the record was last modified',
},
},
}
@@ -0,0 +1,144 @@
import type {
CloudflareUpdateZoneSettingParams,
CloudflareUpdateZoneSettingResponse,
} from '@/tools/cloudflare/types'
import type { ToolConfig } from '@/tools/types'
export const updateZoneSettingTool: ToolConfig<
CloudflareUpdateZoneSettingParams,
CloudflareUpdateZoneSettingResponse
> = {
id: 'cloudflare_update_zone_setting',
name: 'Cloudflare Update Zone Setting',
description:
'Updates a specific zone setting such as SSL mode, security level, cache level, or other configuration.',
version: '1.0.0',
params: {
zoneId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The zone ID to update settings for',
},
settingId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description:
'Setting to update (e.g., "ssl", "security_level", "cache_level", "always_use_https", "browser_cache_ttl", "http3", "min_tls_version", "ciphers")',
},
value: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description:
'New value for the setting as a string or JSON string for complex values (e.g., "full" for SSL, "medium" for security_level, "aggressive" for cache_level, \'["ECDHE-RSA-AES128-GCM-SHA256"]\' for ciphers)',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Cloudflare API Token',
},
},
request: {
url: (params) =>
`https://api.cloudflare.com/client/v4/zones/${params.zoneId}/settings/${params.settingId}`,
method: 'PATCH',
headers: (params) => ({
Authorization: `Bearer ${params.apiKey}`,
'Content-Type': 'application/json',
}),
body: (params) => {
// A block reference can pass an already-structured array/object straight
// through despite the declared string param type — send it as-is rather
// than stringifying it (String([...]) comma-joins, String({...}) yields
// "[object Object]", neither of which is the JSON shape Cloudflare expects).
if (params.value !== null && typeof params.value === 'object') {
return { value: params.value }
}
// Wand-generated values can also arrive as a non-string primitive
// (e.g. a number, or null/undefined) at runtime despite the declared
// param type — coerce null/undefined to '' rather than the literal
// "null"/"undefined" strings String() would otherwise produce.
const trimmed = (params.value == null ? '' : String(params.value)).trim()
// browser_cache_ttl is the one setting whose value must be a number.
// Number('') is 0, not NaN, so an empty value must be rejected explicitly.
if (params.settingId === 'browser_cache_ttl') {
const numeric = trimmed === '' ? Number.NaN : Number(trimmed)
return { value: Number.isNaN(numeric) ? trimmed : numeric }
}
// Only parse JSON object/array literals (e.g. ciphers). Scalar settings like
// min_tls_version ("1.2") or tls_1_3 ("on") must stay strings — a blind JSON.parse would
// silently coerce them to numbers/booleans and the Cloudflare API would reject the type.
if (trimmed.startsWith('{') || trimmed.startsWith('[')) {
try {
return { value: JSON.parse(trimmed) }
} catch {
return { value: trimmed }
}
}
return { value: trimmed }
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!data.success) {
return {
success: false,
output: { id: '', value: '', editable: false, modified_on: '' },
error: data.errors?.[0]?.message ?? 'Failed to update zone setting',
}
}
const setting = data.result
return {
success: true,
output: {
id: setting?.id ?? '',
value:
typeof setting?.value === 'object' && setting?.value !== null
? JSON.stringify(setting.value)
: String(setting?.value ?? ''),
editable: setting?.editable ?? false,
modified_on: setting?.modified_on ?? '',
...(setting?.time_remaining != null
? { time_remaining: setting.time_remaining as number }
: {}),
},
}
},
outputs: {
id: {
type: 'string',
description: 'Setting identifier (e.g., ssl, cache_level, security_level)',
},
value: {
type: 'string',
description:
'Updated setting value as a string. Simple values returned as-is (e.g., "full", "on"). Complex values are JSON-stringified.',
},
editable: {
type: 'boolean',
description: 'Whether the setting can be modified for the current zone plan',
},
modified_on: {
type: 'string',
description: 'ISO 8601 timestamp when the setting was last modified',
},
time_remaining: {
type: 'number',
description:
'Seconds remaining until the setting can be modified again (only present for rate-limited settings)',
optional: true,
},
},
}