Files
namecheap-api/mcp_server.py
kaffa 896699535d Initial commit: Namecheap API library with REST/MCP servers
Features:
- Domain management (check, register, renew, contacts)
- DNS management (nameservers, records)
- Glue records (child nameserver) support
- TLD price tracking with KRW conversion
- FastAPI REST server with OpenAI schema
- MCP server for Claude integration

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-15 10:21:46 +09:00

271 lines
6.4 KiB
Python

#!/usr/bin/env python3
"""
Namecheap MCP Server
"""
import os
from dotenv import load_dotenv
from mcp.server.fastmcp import FastMCP
from namecheap import NamecheapAPI, NamecheapConfig, RegistrantInfo
load_dotenv()
# Initialize MCP server
mcp = FastMCP("namecheap")
# Initialize Namecheap API
config = NamecheapConfig(
api_user=os.getenv("NAMECHEAP_API_USER", ""),
api_key=os.getenv("NAMECHEAP_API_KEY", ""),
username=os.getenv("NAMECHEAP_USERNAME", ""),
client_ip=os.getenv("NAMECHEAP_CLIENT_IP", ""),
sandbox=os.getenv("NAMECHEAP_SANDBOX", "false").lower() == "true",
)
api = NamecheapAPI(config)
# ===== Domain Tools =====
@mcp.tool()
def domains_check(domains: str) -> dict:
"""
Check domain availability.
Args:
domains: Comma-separated domain names (e.g., "example.com,example.net")
"""
domain_list = [d.strip() for d in domains.split(",")]
return api.domains_check(domain_list)
@mcp.tool()
def domains_list(page: int = 1, page_size: int = 20) -> list[dict]:
"""
Get list of domains in account.
Args:
page: Page number (default: 1)
page_size: Number of domains per page (default: 20)
"""
return api.domains_get_list(page=page, page_size=page_size)
@mcp.tool()
def domains_info(domain: str) -> dict:
"""
Get detailed info about a domain.
Args:
domain: Domain name (e.g., "example.com")
"""
return api.domains_get_info(domain)
@mcp.tool()
def domains_renew(domain: str, years: int = 1) -> dict:
"""
Renew a domain. WARNING: This will charge your account.
Args:
domain: Domain name to renew
years: Number of years (1-10)
"""
return api.domains_renew(domain, years=years)
@mcp.tool()
def domains_get_contacts(domain: str) -> dict:
"""
Get domain contact information.
Args:
domain: Domain name (e.g., "example.com")
"""
return api.domains_get_contacts(domain)
# ===== DNS Tools =====
@mcp.tool()
def dns_get_nameservers(domain: str) -> dict:
"""
Get nameserver information for a domain.
Args:
domain: Domain name (e.g., "example.com" or "sub.it.com")
"""
parts = domain.rsplit(".", 1)
if len(parts) == 2:
sld, tld = parts
else:
return {"error": "Invalid domain format"}
return api.dns_get_list(sld, tld)
@mcp.tool()
def dns_set_nameservers(domain: str, nameservers: str) -> dict:
"""
Set custom nameservers for a domain.
Args:
domain: Domain name (e.g., "example.com")
nameservers: Comma-separated nameservers (e.g., "ns1.cloudflare.com,ns2.cloudflare.com")
"""
parts = domain.rsplit(".", 1)
if len(parts) == 2:
sld, tld = parts
else:
return {"error": "Invalid domain format"}
ns_list = [ns.strip() for ns in nameservers.split(",")]
success = api.dns_set_custom(sld, tld, ns_list)
return {"success": success, "domain": domain, "nameservers": ns_list}
@mcp.tool()
def dns_set_default(domain: str) -> dict:
"""
Set default Namecheap nameservers for a domain.
Args:
domain: Domain name (e.g., "example.com")
"""
parts = domain.rsplit(".", 1)
if len(parts) == 2:
sld, tld = parts
else:
return {"error": "Invalid domain format"}
success = api.dns_set_default(sld, tld)
return {"success": success, "domain": domain}
@mcp.tool()
def dns_get_records(domain: str) -> list[dict]:
"""
Get DNS records for a domain. Only works if using Namecheap DNS.
Args:
domain: Domain name (e.g., "example.com")
"""
parts = domain.rsplit(".", 1)
if len(parts) == 2:
sld, tld = parts
else:
return [{"error": "Invalid domain format"}]
return api.dns_get_hosts(sld, tld)
# ===== Glue Record (Child Nameserver) Tools =====
@mcp.tool()
def glue_create(domain: str, nameserver: str, ip: str) -> dict:
"""
Create a glue record (child nameserver) for a domain.
Use this when you want to use your own domain as a nameserver (e.g., ns1.example.com for example.com).
Args:
domain: Domain name (e.g., "example.com")
nameserver: Full nameserver hostname (e.g., "ns1.example.com")
ip: IP address for the nameserver
"""
parts = domain.rsplit(".", 1)
if len(parts) == 2:
sld, tld = parts
else:
return {"error": "Invalid domain format"}
return api.ns_create(sld, tld, nameserver, ip)
@mcp.tool()
def glue_get(domain: str, nameserver: str) -> dict:
"""
Get info about a glue record (child nameserver).
Args:
domain: Domain name (e.g., "example.com")
nameserver: Full nameserver hostname (e.g., "ns1.example.com")
"""
parts = domain.rsplit(".", 1)
if len(parts) == 2:
sld, tld = parts
else:
return {"error": "Invalid domain format"}
return api.ns_get_info(sld, tld, nameserver)
@mcp.tool()
def glue_update(domain: str, nameserver: str, old_ip: str, ip: str) -> dict:
"""
Update a glue record (child nameserver) IP address.
Args:
domain: Domain name (e.g., "example.com")
nameserver: Full nameserver hostname (e.g., "ns1.example.com")
old_ip: Current IP address
ip: New IP address
"""
parts = domain.rsplit(".", 1)
if len(parts) == 2:
sld, tld = parts
else:
return {"error": "Invalid domain format"}
return api.ns_update(sld, tld, nameserver, old_ip, ip)
@mcp.tool()
def glue_delete(domain: str, nameserver: str) -> dict:
"""
Delete a glue record (child nameserver).
Args:
domain: Domain name (e.g., "example.com")
nameserver: Full nameserver hostname to delete (e.g., "ns1.example.com")
"""
parts = domain.rsplit(".", 1)
if len(parts) == 2:
sld, tld = parts
else:
return {"error": "Invalid domain format"}
return api.ns_delete(sld, tld, nameserver)
# ===== Account Tools =====
@mcp.tool()
def account_balance() -> dict:
"""Get account balance."""
return api.users_get_balances()
@mcp.tool()
def price_check(tld: str) -> dict:
"""
Get registration price for a TLD.
Args:
tld: TLD to check (e.g., "com", "net", "io")
"""
from db import get_prices, init_db
init_db()
prices = get_prices()
for p in prices:
if p["tld"] == tld:
return {"tld": tld, "usd": p["usd"], "krw": p["krw"]}
return {"error": f"TLD '{tld}' not found"}
if __name__ == "__main__":
mcp.run()