/**
* Gandi LiveDNS management tools
*/
import { json, error, type ToolDefinition } from "../lib/mcp-core.js";
import { GandiClient } from "../lib/client.js";
import type { GandiDNSRecord, GandiDNSRecordCreate, GandiDNSRecordUpdate, DNSRecordType } from "../types/index.js";
const DNS_RECORD_TYPES: DNSRecordType[] = ['A', 'AAAA', 'CNAME', 'MX', 'NS', 'PTR', 'SRV', 'TXT', 'CAA'];
export function createDNSTools(gandiClient: GandiClient): ToolDefinition[] {
/**
* List DNS records for a domain
*/
const listDNSRecordsTool: ToolDefinition = {
name: "gandi_dns_records_list",
description: "List all DNS records for a domain",
inputSchema: {
type: "object",
properties: {
domain: {
type: "string",
description: "Domain name (e.g., example.com)",
},
type: {
type: "string",
description: "Filter by record type (optional)",
enum: DNS_RECORD_TYPES,
},
},
required: ["domain"],
},
handler: async (args) => {
const domain = args.domain as string;
const type = args.type as DNSRecordType | undefined;
try {
const params = type ? { type } : {};
const records = await gandiClient.get<GandiDNSRecord[]>(`/livedns/domains/${domain}/records`, params);
return json({
domain,
records: records.map(r => ({
name: r.rrset_name,
type: r.rrset_type,
ttl: r.rrset_ttl,
values: r.rrset_values
})),
count: records.length
});
} catch (err: any) {
if (err.message.includes('404')) {
return error(`Domain '${domain}' not found or LiveDNS not enabled`);
}
return error(`Failed to list DNS records: ${err.message}`);
}
},
};
/**
* Get specific DNS record
*/
const getDNSRecordTool: ToolDefinition = {
name: "gandi_dns_record_get",
description: "Get a specific DNS record by name and type",
inputSchema: {
type: "object",
properties: {
domain: {
type: "string",
description: "Domain name (e.g., example.com)",
},
name: {
type: "string",
description: "Record name (e.g., www, @, subdomain)",
},
type: {
type: "string",
description: "Record type",
enum: DNS_RECORD_TYPES,
},
},
required: ["domain", "name", "type"],
},
handler: async (args) => {
const domain = args.domain as string;
const name = args.name as string;
const type = args.type as DNSRecordType;
try {
const record = await gandiClient.get<GandiDNSRecord>(`/livedns/domains/${domain}/records/${name}/${type}`);
return json({
domain,
record: {
name: record.rrset_name,
type: record.rrset_type,
ttl: record.rrset_ttl,
values: record.rrset_values
}
});
} catch (err: any) {
if (err.message.includes('404')) {
return error(`DNS record '${name}' (${type}) not found for domain '${domain}'`);
}
return error(`Failed to get DNS record: ${err.message}`);
}
},
};
/**
* Create DNS record
*/
const createDNSRecordTool: ToolDefinition = {
name: "gandi_dns_record_create",
description: "Create a new DNS record",
inputSchema: {
type: "object",
properties: {
domain: {
type: "string",
description: "Domain name (e.g., example.com)",
},
name: {
type: "string",
description: "Record name (e.g., www, @, subdomain)",
},
type: {
type: "string",
description: "Record type",
enum: DNS_RECORD_TYPES,
},
values: {
type: "array",
items: { type: "string" },
description: "Record values (e.g., IP addresses, CNAME target)",
},
ttl: {
type: "number",
description: "TTL in seconds (optional, defaults to 300)",
minimum: 300,
maximum: 2592000,
},
},
required: ["domain", "name", "type", "values"],
},
handler: async (args) => {
const domain = args.domain as string;
const name = args.name as string;
const type = args.type as DNSRecordType;
const values = args.values as string[];
const ttl = (args.ttl as number) || 300;
try {
const recordData: GandiDNSRecordCreate = {
rrset_name: name,
rrset_type: type,
rrset_ttl: ttl,
rrset_values: values,
};
await gandiClient.post(`/livedns/domains/${domain}/records`, recordData);
return json({
success: true,
message: `DNS record '${name}' (${type}) created successfully`,
domain,
record: {
name,
type,
ttl,
values
}
});
} catch (err: any) {
return error(`Failed to create DNS record: ${err.message}`);
}
},
};
/**
* Update DNS record
*/
const updateDNSRecordTool: ToolDefinition = {
name: "gandi_dns_record_update",
description: "Update an existing DNS record",
inputSchema: {
type: "object",
properties: {
domain: {
type: "string",
description: "Domain name (e.g., example.com)",
},
name: {
type: "string",
description: "Record name (e.g., www, @, subdomain)",
},
type: {
type: "string",
description: "Record type",
enum: DNS_RECORD_TYPES,
},
values: {
type: "array",
items: { type: "string" },
description: "New record values",
},
ttl: {
type: "number",
description: "New TTL in seconds (optional)",
minimum: 300,
maximum: 2592000,
},
},
required: ["domain", "name", "type", "values"],
},
handler: async (args) => {
const domain = args.domain as string;
const name = args.name as string;
const type = args.type as DNSRecordType;
const values = args.values as string[];
const ttl = args.ttl as number | undefined;
try {
const updateData: GandiDNSRecordUpdate = {
rrset_values: values,
};
if (ttl !== undefined) {
updateData.rrset_ttl = ttl;
}
await gandiClient.put(`/livedns/domains/${domain}/records/${name}/${type}`, updateData);
return json({
success: true,
message: `DNS record '${name}' (${type}) updated successfully`,
domain,
record: {
name,
type,
values,
...(ttl && { ttl })
}
});
} catch (err: any) {
if (err.message.includes('404')) {
return error(`DNS record '${name}' (${type}) not found for domain '${domain}'`);
}
return error(`Failed to update DNS record: ${err.message}`);
}
},
};
/**
* Delete DNS record
*/
const deleteDNSRecordTool: ToolDefinition = {
name: "gandi_dns_record_delete",
description: "Delete a DNS record",
inputSchema: {
type: "object",
properties: {
domain: {
type: "string",
description: "Domain name (e.g., example.com)",
},
name: {
type: "string",
description: "Record name (e.g., www, @, subdomain)",
},
type: {
type: "string",
description: "Record type",
enum: DNS_RECORD_TYPES,
},
},
required: ["domain", "name", "type"],
},
handler: async (args) => {
const domain = args.domain as string;
const name = args.name as string;
const type = args.type as DNSRecordType;
try {
await gandiClient.delete(`/livedns/domains/${domain}/records/${name}/${type}`);
return json({
success: true,
message: `DNS record '${name}' (${type}) deleted successfully`,
domain,
record: {
name,
type
}
});
} catch (err: any) {
if (err.message.includes('404')) {
return error(`DNS record '${name}' (${type}) not found for domain '${domain}'`);
}
return error(`Failed to delete DNS record: ${err.message}`);
}
},
};
return [
listDNSRecordsTool,
getDNSRecordTool,
createDNSRecordTool,
updateDNSRecordTool,
deleteDNSRecordTool,
];
}