66 lines
1.9 KiB
Python
66 lines
1.9 KiB
Python
#!/usr/bin/env python3
|
|
"""Read-only STRATO DNS MCP proof of concept."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import os
|
|
|
|
from mcp.server.fastmcp import FastMCP
|
|
|
|
from strato_client import StratoClient, StratoConfig, StratoError
|
|
|
|
|
|
mcp = FastMCP(
|
|
"strato-dns-readonly",
|
|
instructions=(
|
|
"Read the configured STRATO DNS zone. This experimental server is "
|
|
"strictly read-only and cannot create, change, or delete DNS records."
|
|
),
|
|
host="0.0.0.0",
|
|
port=int(os.environ.get("PORT", "8000")),
|
|
stateless_http=True,
|
|
)
|
|
|
|
|
|
def _json(value: object) -> str:
|
|
return json.dumps(value, ensure_ascii=False, separators=(",", ":"))
|
|
|
|
|
|
@mcp.tool()
|
|
def strato_connection_status() -> str:
|
|
"""Log in and verify that the configured DNS zone can be read. Makes no change."""
|
|
try:
|
|
config = StratoConfig.from_env()
|
|
records = StratoClient(config).list_txt_and_cname_records()
|
|
return _json({
|
|
"connected": True,
|
|
"domain": config.domain,
|
|
"record_count": len(records),
|
|
"cname_count": sum(record.type == "CNAME" for record in records),
|
|
"read_only": True,
|
|
})
|
|
except StratoError as exc:
|
|
return _json({"connected": False, "error": str(exc), "read_only": True})
|
|
|
|
|
|
@mcp.tool()
|
|
def strato_list_cnames() -> str:
|
|
"""List CNAME records for the one configured STRATO zone. Makes no change."""
|
|
try:
|
|
config = StratoConfig.from_env()
|
|
records = StratoClient(config).list_cnames()
|
|
return _json({
|
|
"domain": config.domain,
|
|
"count": len(records),
|
|
"records": [record.as_dict() for record in records[:200]],
|
|
"truncated": len(records) > 200,
|
|
"read_only": True,
|
|
})
|
|
except StratoError as exc:
|
|
return _json({"error": str(exc), "read_only": True})
|
|
|
|
|
|
if __name__ == "__main__":
|
|
mcp.run(transport=os.environ.get("MCP_TRANSPORT", "streamable-http"))
|