Files
caddy-mcp-server/handlers.go
T

306 lines
9.1 KiB
Go

package main
import (
"encoding/json"
"fmt"
"os"
)
// Site Management Handlers
func (s *MCPServer) handleListSites(id interface{}) {
sites, err := s.client.ListSites()
if err != nil {
s.sendError(id, -32000, err.Error())
return
}
var output string
for _, site := range sites {
domain, _ := site["domain"].(string)
upstreams := s.client.extractUpstreams(site["route"].(map[string]interface{}))
output += fmt.Sprintf("📍 %s\n", domain)
if len(upstreams) > 0 {
output += fmt.Sprintf(" → %v\n", upstreams)
}
if s.client.hasBasicAuth(site["route"].(map[string]interface{})) {
output += " 🔒 Auth enabled\n"
}
output += "\n"
}
if len(sites) == 0 {
output = "No sites configured\n"
}
s.sendTextResult(id, output)
}
func (s *MCPServer) handleGetSite(id interface{}, args map[string]interface{}) {
domain, _ := args["domain"].(string)
site, err := s.client.GetSite(domain)
if err != nil {
s.sendError(id, -32000, err.Error())
return
}
output := fmt.Sprintf("Domain: %s\n", domain)
output += fmt.Sprintf("Server: %s\n", site["server"])
output += fmt.Sprintf("Upstreams: %v\n", site["upstreams"])
output += fmt.Sprintf("Auth: %v\n", site["has_auth"])
handlers, _ := json.MarshalIndent(site["handlers"], "", " ")
output += fmt.Sprintf("Handlers: %s\n", string(handlers))
s.sendTextResult(id, output)
}
func (s *MCPServer) handleAddSite(id interface{}, args map[string]interface{}) {
domain, _ := args["domain"].(string)
if err := validateDomain(domain); err != nil {
s.sendError(id, -32000, err.Error())
return
}
upstream, _ := args["upstream"].(string)
if err := s.client.AddSite(domain, upstream); err != nil {
s.sendError(id, -32000, err.Error())
return
}
s.sendTextResult(id, fmt.Sprintf("✅ Added %s → %s", domain, upstream))
}
func (s *MCPServer) handleRemoveSite(id interface{}, args map[string]interface{}) {
domain, _ := args["domain"].(string)
if err := s.client.RemoveSite(domain); err != nil {
s.sendError(id, -32000, err.Error())
return
}
s.sendTextResult(id, fmt.Sprintf("✅ Removed %s", domain))
}
func (s *MCPServer) handleUpdateUpstream(id interface{}, args map[string]interface{}) {
domain, _ := args["domain"].(string)
upstream, _ := args["upstream"].(string)
if err := s.client.UpdateUpstream(domain, upstream); err != nil {
s.sendError(id, -32000, err.Error())
return
}
s.sendTextResult(id, fmt.Sprintf("✅ Updated %s → %s", domain, upstream))
}
// Path Route Handlers
func (s *MCPServer) handleAddPathRoute(id interface{}, args map[string]interface{}) {
domain, _ := args["domain"].(string)
if err := validateDomain(domain); err != nil {
s.sendError(id, -32000, err.Error())
return
}
path, _ := args["path"].(string)
if err := validatePath(path); err != nil {
s.sendError(id, -32000, err.Error())
return
}
upstream, _ := args["upstream"].(string)
if err := s.client.AddPathRoute(domain, path, upstream); err != nil {
s.sendError(id, -32000, err.Error())
return
}
s.sendTextResult(id, fmt.Sprintf("✅ Added %s%s/* → %s", domain, path, upstream))
}
func (s *MCPServer) handleRemovePathRoute(id interface{}, args map[string]interface{}) {
domain, _ := args["domain"].(string)
if err := validateDomain(domain); err != nil {
s.sendError(id, -32000, err.Error())
return
}
path, _ := args["path"].(string)
if err := validatePath(path); err != nil {
s.sendError(id, -32000, err.Error())
return
}
if err := s.client.RemovePathRoute(domain, path); err != nil {
s.sendError(id, -32000, err.Error())
return
}
s.sendTextResult(id, fmt.Sprintf("✅ Removed %s%s/*", domain, path))
}
// Auth Handlers
func (s *MCPServer) handleAddBasicAuth(id interface{}, args map[string]interface{}) {
domain, _ := args["domain"].(string)
username, _ := args["username"].(string)
password, _ := args["password"].(string)
if err := s.client.AddBasicAuth(domain, username, password); err != nil {
s.sendError(id, -32000, err.Error())
return
}
s.sendTextResult(id, fmt.Sprintf("✅ Added basic auth for %s (user: %s)", domain, username))
}
func (s *MCPServer) handleRemoveBasicAuth(id interface{}, args map[string]interface{}) {
domain, _ := args["domain"].(string)
if err := s.client.RemoveBasicAuth(domain); err != nil {
s.sendError(id, -32000, err.Error())
return
}
s.sendTextResult(id, fmt.Sprintf("✅ Removed basic auth from %s", domain))
}
// Header Handlers
func (s *MCPServer) handleAddRequestHeader(id interface{}, args map[string]interface{}) {
domain, _ := args["domain"].(string)
if err := validateDomain(domain); err != nil {
s.sendError(id, -32000, err.Error())
return
}
header, _ := args["header"].(string)
if err := validateHeaderName(header); err != nil {
s.sendError(id, -32000, err.Error())
return
}
value, _ := args["value"].(string)
if err := s.client.AddHeaderUp(domain, header, value); err != nil {
s.sendError(id, -32000, err.Error())
return
}
s.sendTextResult(id, fmt.Sprintf("✅ Added request header %s: %s for %s", header, value, domain))
}
func (s *MCPServer) handleAddResponseHeader(id interface{}, args map[string]interface{}) {
domain, _ := args["domain"].(string)
if err := validateDomain(domain); err != nil {
s.sendError(id, -32000, err.Error())
return
}
header, _ := args["header"].(string)
if err := validateHeaderName(header); err != nil {
s.sendError(id, -32000, err.Error())
return
}
value, _ := args["value"].(string)
if err := s.client.AddHeaderDown(domain, header, value); err != nil {
s.sendError(id, -32000, err.Error())
return
}
s.sendTextResult(id, fmt.Sprintf("✅ Added response header %s: %s for %s", header, value, domain))
}
// File Server Handlers
func (s *MCPServer) handleAddFileServer(id interface{}, args map[string]interface{}) {
domain, _ := args["domain"].(string)
root, _ := args["root"].(string)
browse, _ := args["browse"].(bool)
if err := s.client.AddFileServer(domain, root, browse); err != nil {
s.sendError(id, -32000, err.Error())
return
}
s.sendTextResult(id, fmt.Sprintf("✅ Added file server %s → %s (browse: %v)", domain, root, browse))
}
func (s *MCPServer) handleUpdateFileRoot(id interface{}, args map[string]interface{}) {
domain, _ := args["domain"].(string)
root, _ := args["root"].(string)
if err := s.client.UpdateFileServerRoot(domain, root); err != nil {
s.sendError(id, -32000, err.Error())
return
}
s.sendTextResult(id, fmt.Sprintf("✅ Updated %s root → %s", domain, root))
}
// Review Environment Handler
func (s *MCPServer) handleAddWipEnvironment(id interface{}, args map[string]interface{}) {
project, _ := args["project"].(string)
portFloat, _ := args["port"].(float64)
port := int(portFloat)
reviewDomain := os.Getenv("REVIEW_DOMAIN")
if reviewDomain == "" {
reviewDomain = "review.example.com"
}
path := fmt.Sprintf("/%s/wip", project)
upstream := fmt.Sprintf("localhost:%d", port)
if err := s.client.AddPathRoute(reviewDomain, path, upstream); err != nil {
s.sendError(id, -32000, err.Error())
return
}
s.sendTextResult(id, fmt.Sprintf("✅ Added WIP https://%s%s/* → %s", reviewDomain, path, upstream))
}
// Config Handlers
func (s *MCPServer) handleExportConfig(id interface{}) {
config, err := s.client.GetConfig()
if err != nil {
s.sendError(id, -32000, err.Error())
return
}
data, _ := json.MarshalIndent(config, "", " ")
s.sendTextResult(id, string(data))
}
func (s *MCPServer) handleAdaptCaddyfile(id interface{}, args map[string]interface{}) {
caddyfile, _ := args["caddyfile"].(string)
result, err := s.client.AdaptCaddyfile(caddyfile)
if err != nil {
s.sendError(id, -32000, err.Error())
return
}
data, _ := json.MarshalIndent(result, "", " ")
s.sendTextResult(id, string(data))
}
func (s *MCPServer) handleValidateConfig(id interface{}, args map[string]interface{}) {
configArg, _ := args["config"].(map[string]interface{})
if err := s.client.ValidateConfig(configArg); err != nil {
s.sendError(id, -32000, err.Error())
return
}
s.sendTextResult(id, "✅ Configuration is valid")
}
// Control Handlers
func (s *MCPServer) handleCaddyStatus(id interface{}) {
sites, err := s.client.ListSites()
if err != nil {
s.sendTextResult(id, fmt.Sprintf("❌ Caddy unreachable: %v", err))
return
}
s.sendTextResult(id, fmt.Sprintf("✅ Caddy running (%d sites configured)", len(sites)))
}
func (s *MCPServer) handleStopCaddy(id interface{}) {
if err := s.client.Stop(); err != nil {
s.sendError(id, -32000, err.Error())
return
}
s.sendTextResult(id, "✅ Caddy stopped")
}
// Helper functions
func (s *MCPServer) sendTextResult(id interface{}, text string) {
s.sendResult(id, map[string]interface{}{
"content": []interface{}{
map[string]interface{}{"type": "text", "text": text},
},
})
}
func (s *MCPServer) sendResult(id interface{}, result interface{}) {
resp := map[string]interface{}{
"jsonrpc": "2.0",
"id": id,
"result": result,
}
data, _ := json.Marshal(resp)
fmt.Println(string(data))
}
func (s *MCPServer) sendError(id interface{}, code int, message string) {
resp := map[string]interface{}{
"jsonrpc": "2.0",
"id": id,
"error": map[string]interface{}{
"code": code,
"message": message,
},
}
data, _ := json.Marshal(resp)
fmt.Println(string(data))
}