dns_add_record
Add a DNS record to a zone, automatically creating the zone if it does not exist for primary type. Supports A, AAAA, CNAME, MX, NS, PTR, SOA, SRV, TXT, and CAA records.
Instructions
Add a DNS record to a zone. Creates the zone automatically if it doesn't exist for Primary type.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| zone | Yes | Zone domain name | |
| domain | Yes | Full domain name for the record | |
| type | Yes | Record type | |
| value | Yes | Record value (IP for A/AAAA, hostname for CNAME/MX/NS, text for TXT) | |
| ttl | No | TTL in seconds (default: 3600) | |
| overwrite | No | Overwrite existing records of the same type (default: false) | |
| priority | No | Priority for MX records |
Implementation Reference
- src/tools/records.ts:178-220 (handler)Handler function for dns_add_record. Validates zone, domain, record type, and value; builds API parameters based on record type (A/AAAA/CNAME/MX/NS/PTR/TXT/SRV/CAA); calls Technitium API /api/zones/records/add; returns the API response as JSON.
readonly: false, handler: async (args) => { const zone = validateDomain(args.zone as string); const domain = validateDomain(args.domain as string); const recType = validateRecordType(args.type as string); const value = args.value as string; const params: Record<string, string> = { zone, domain, type: recType, overwrite: args.overwrite ? "true" : "false", }; if (args.ttl) params.ttl = String(args.ttl); if (recType === "A" || recType === "AAAA") { params.ipAddress = validateIp(value); } else if (recType === "CNAME") { params.cname = validateDomain(value); } else if (recType === "NS") { params.nameServer = validateDomain(value); } else if (recType === "PTR") { params.ptrName = validateDomain(value); } else if (recType === "MX") { params.exchange = validateDomain(value); if (args.priority) params.preference = String(args.priority); } else if (recType === "TXT") { params.text = value; } else if (recType === "SRV") { params.target = value; if (args.priority) params.priority = String(args.priority); } else if (recType === "CAA") { params.value = value; } const data = await client.callOrThrow( "/api/zones/records/add", params ); return JSON.stringify(data, null, 2); }, }, - src/tools/records.ts:125-176 (schema)Input schema for dns_add_record defining required fields (zone, domain, type, value) and optional fields (ttl, overwrite, priority) with enumerated record types (A, AAAA, CNAME, MX, NS, PTR, SOA, SRV, TXT, CAA).
definition: { name: "dns_add_record", description: "Add a DNS record to a zone. Creates the zone automatically if it doesn't exist for Primary type.", inputSchema: { type: "object", properties: { zone: { type: "string", description: "Zone domain name", }, domain: { type: "string", description: "Full domain name for the record", }, type: { type: "string", enum: [ "A", "AAAA", "CNAME", "MX", "NS", "PTR", "SOA", "SRV", "TXT", "CAA", ], description: "Record type", }, value: { type: "string", description: "Record value (IP for A/AAAA, hostname for CNAME/MX/NS, text for TXT)", }, ttl: { type: "number", description: "TTL in seconds (default: 3600)", }, overwrite: { type: "boolean", description: "Overwrite existing records of the same type (default: false)", }, priority: { type: "number", description: "Priority for MX records", }, }, required: ["zone", "domain", "type", "value"], }, - src/tools/index.ts:14-45 (registration)Registration of all tools via getAllTools(), which includes recordTools(client) from records.ts where dns_add_record is defined as part of the returned array.
export function getAllTools(client: TechnitiumClient): ToolEntry[] { return [ ...dashboardTools(client), ...dnsClientTools(client), ...zoneTools(client), ...recordTools(client), ...blockingTools(client), ...cacheTools(client), ...settingsTools(client), ...logTools(client), ...appTools(client), ...dnssecTools(client), ]; } - src/validate.ts:5-60 (helper)Helper functions validateDomain, validateRecordType, and validateIp used by the dns_add_record handler to validate input parameters.
export function validateDomain(domain: string): string { if (!domain || typeof domain !== "string") { throw new Error("Domain name is required"); } const trimmed = domain.trim().toLowerCase(); if (trimmed.length > 253) { throw new Error("Domain name exceeds maximum length of 253 characters"); } if (!DOMAIN_RE.test(trimmed)) { throw new Error("Invalid domain name format"); } return trimmed; } export function validateIp(ip: string): string { if (!ip || typeof ip !== "string") { throw new Error("IP address is required"); } const trimmed = ip.trim(); if (!IPV4_RE.test(trimmed) && !IPV6_RE.test(trimmed)) { throw new Error("Invalid IP address format"); } return trimmed; } export function validateIpOrHostname(value: string): string { if (!value || typeof value !== "string") { throw new Error("Server address is required"); } const trimmed = value.trim(); if (IPV4_RE.test(trimmed) || IPV6_RE.test(trimmed)) { return trimmed; } if (trimmed.startsWith("https://")) { return trimmed; } if (DOMAIN_RE.test(trimmed) && trimmed.length <= 253) { return trimmed; } throw new Error("Invalid server address: must be IP, hostname, or https:// URL"); } const VALID_RECORD_TYPES = new Set([ "A", "AAAA", "CNAME", "MX", "NS", "PTR", "SOA", "SRV", "TXT", "CAA", "ANY", ]); export function validateRecordType(type: string): string { if (!type || typeof type !== "string") { throw new Error("Record type is required"); } const upper = type.trim().toUpperCase(); if (!VALID_RECORD_TYPES.has(upper)) { throw new Error(`Invalid record type: ${upper}`); } return upper; } - src/rate-limit.ts:32-40 (registration)Rate limit registration for dns_add_record - it is configured with a mutate limit of 10 requests per 60-second window.
for (const tool of [ "dns_create_zone", "dns_add_record", "dns_update_record", "dns_block_domain", "dns_allow_domain", "dns_remove_allowed", "dns_remove_blocked", "dns_delete_cached", "dns_enable_zone", "dns_disable_zone", "dns_set_zone_options", "dns_set_settings", "dns_install_app", ]) { this.toolLimits.set(tool, mutateLimits); }