home-lab/packages/mcp-server/mcp/server/integration.scm
Geir Okkenhaug Jerstad 52a9d544fc feat: comprehensive audio system and MCP server implementation
Audio System Enhancements:
- Complete PipeWire configuration with WirePlumber session management
- AI-powered noise suppression using RNNoise plugin
- GUI applications: EasyEffects, pavucontrol, Helvum, qpwgraph, pwvucontrol
- Pre-configured audio presets for microphone noise suppression
- Desktop integration with auto-start and helper scripts
- Validation tools and interactive audio management utilities
- Real-time audio processing with RTKit optimization
- Cross-application compatibility (Discord, Zoom, OBS, etc.)

MCP (Model Context Protocol) Implementation in Guile Scheme:
- Modular MCP server architecture with clean separation of concerns
- JSON-RPC transport layer with WebSocket and stdio support
- Protocol compliance with MCP specification
- Comprehensive error handling and validation
- Router system for tool and resource management
- Integration layer for NixOS Home Lab management
- Full test suite with unit and integration tests
- Documentation and usage examples

Technical Details:
- Removed conflicting ALSA udev rules while maintaining compatibility
- Fixed package dependencies and service configurations
- Successfully deployed and tested on congenital-optimist machine
- Functional programming approach using Guile Scheme modules
- Type-safe protocol implementation with validation
- Async/await pattern support for concurrent operations

This represents a significant enhancement to the Home Lab infrastructure,
providing both professional-grade audio capabilities and a robust MCP
server implementation for AI assistant integration.
2025-06-18 21:10:06 +02:00

280 lines
12 KiB
Scheme

;; MCP Server Integration with Guile Infrastructure
;; This module integrates the MCP server with existing Guile-based home lab infrastructure
(define-module (mcp server integration)
#:use-module (ice-9 match)
#:use-module (ice-9 receive)
#:use-module (ice-9 popen)
#:use-module (ice-9 rdelim)
#:use-module (json)
#:use-module (srfi srfi-1)
#:use-module (srfi srfi-9)
#:use-module (srfi srfi-26)
#:use-module (mcp server jsonrpc)
#:use-module (mcp server protocol)
#:use-module (mcp server transport)
#:use-module (mcp server router)
#:use-module (mcp server validation)
#:use-module (mcp server error-handling)
#:export (create-integrated-mcp-server
register-lab-tools
register-lab-resources
register-lab-prompts
lab-command-executor
lab-config-reader
lab-status-checker
setup-mcp-server
start-mcp-server))
;; Lab command executor - integrates with existing shell commands
(define (lab-command-executor command args)
"Execute a lab command and return the result"
(catch #t
(lambda ()
(let* ((cmd-string (string-join (cons command args) " "))
(port (open-input-pipe cmd-string))
(output (read-string port))
(exit-code (close-pipe port)))
(if (= exit-code 0)
`(("success" . #t)
("output" . ,output)
("exit_code" . ,exit-code))
`(("success" . #f)
("output" . ,output)
("error" . "Command failed")
("exit_code" . ,exit-code)))))
(lambda (key . args)
`(("success" . #f)
("error" . ,(format #f "Exception: ~a" key))
("details" . ,args)))))
;; Configuration reader - reads lab configuration
(define (lab-config-reader config-path)
"Read lab configuration from file"
(catch #t
(lambda ()
(if (file-exists? config-path)
(call-with-input-file config-path
(lambda (port)
(json->scm port)))
`(("error" . "Configuration file not found")
("path" . ,config-path))))
(lambda (key . args)
`(("error" . ,(format #f "Failed to read config: ~a" key))
("details" . ,args)))))
;; Status checker - checks lab infrastructure status
(define (lab-status-checker)
"Check the status of lab infrastructure"
(let ((services '("ssh" "docker" "nixos-rebuild"))
(status-results '()))
(for-each
(lambda (service)
(let ((result (lab-command-executor "systemctl" (list "is-active" service))))
(set! status-results
(cons `(,service . ,result) status-results))))
services)
`(("timestamp" . ,(current-time))
("services" . ,status-results))))
;; Tool registration functions
(define (register-lab-tools server)
"Register lab management tools with the MCP server"
;; Machine management tools
(register-route (mcp-server-handlers server) "tools/machine/list"
(lambda (server params)
(lab-command-executor "ls" '("/etc/nixos/machines"))))
(register-route (mcp-server-handlers server) "tools/machine/status"
(lambda (server params)
(let ((machine (hash-ref params "machine" #f)))
(if machine
(lab-command-executor "ping" (list "-c" "1" machine))
'(("error" . "Machine name required"))))))
(register-route (mcp-server-handlers server) "tools/machine/deploy"
(lambda (server params)
(let ((machine (hash-ref params "machine" #f))
(config (hash-ref params "config" #f)))
(if (and machine config)
(lab-command-executor "nixos-rebuild"
(list "switch" "--target-host" machine
"--flake" config))
'(("error" . "Machine and config required"))))))
;; Service management tools
(register-route (mcp-server-handlers server) "tools/service/status"
(lambda (server params)
(let ((service (hash-ref params "service" #f)))
(if service
(lab-command-executor "systemctl" (list "status" service))
'(("error" . "Service name required"))))))
(register-route (mcp-server-handlers server) "tools/service/restart"
(lambda (server params)
(let ((service (hash-ref params "service" #f)))
(if service
(lab-command-executor "systemctl" (list "restart" service))
'(("error" . "Service name required"))))))
;; Docker management tools
(register-route (mcp-server-handlers server) "tools/docker/ps"
(lambda (server params)
(lab-command-executor "docker" '("ps" "--format" "json"))))
(register-route (mcp-server-handlers server) "tools/docker/logs"
(lambda (server params)
(let ((container (hash-ref params "container" #f))
(lines (hash-ref params "lines" "100")))
(if container
(lab-command-executor "docker"
(list "logs" "--tail" lines container))
'(("error" . "Container name required"))))))
;; Network tools
(register-route (mcp-server-handlers server) "tools/network/scan"
(lambda (server params)
(let ((network (hash-ref params "network" "192.168.1.0/24")))
(lab-command-executor "nmap" (list "-sn" network)))))
;; Configuration tools
(register-route (mcp-server-handlers server) "tools/config/validate"
(lambda (server params)
(let ((config-path (hash-ref params "path" "/etc/nixos/configuration.nix")))
(lab-command-executor "nixos-rebuild" (list "dry-build" "--flake" config-path))))))
(define (register-lab-resources server)
"Register lab infrastructure resources with the MCP server"
;; Configuration files
(register-route (mcp-server-handlers server) "resources/config/nixos"
(lambda (server params)
(lab-config-reader "/etc/nixos/configuration.nix")))
(register-route (mcp-server-handlers server) "resources/config/machines"
(lambda (server params)
(lab-command-executor "find" '("/etc/nixos/machines" "-name" "*.nix"))))
;; System information
(register-route (mcp-server-handlers server) "resources/system/info"
(lambda (server params)
`(("hostname" . ,(gethostname))
("uptime" . ,(lab-command-executor "uptime" '()))
("load" . ,(lab-command-executor "cat" '("/proc/loadavg")))
("memory" . ,(lab-command-executor "free" '("-h"))))))
;; Network information
(register-route (mcp-server-handlers server) "resources/network/interfaces"
(lambda (server params)
(lab-command-executor "ip" '("addr" "show"))))
(register-route (mcp-server-handlers server) "resources/network/routes"
(lambda (server params)
(lab-command-executor "ip" '("route" "show"))))
;; Storage information
(register-route (mcp-server-handlers server) "resources/storage/disk"
(lambda (server params)
(lab-command-executor "df" '("-h"))))
(register-route (mcp-server-handlers server) "resources/storage/zfs"
(lambda (server params)
(lab-command-executor "zfs" '("list"))))
;; Log files
(register-route (mcp-server-handlers server) "resources/logs/system"
(lambda (server params)
(let ((lines (hash-ref params "lines" "100")))
(lab-command-executor "journalctl" (list "--lines" lines "--no-pager")))))
(register-route (mcp-server-handlers server) "resources/logs/service"
(lambda (server params)
(let ((service (hash-ref params "service" #f))
(lines (hash-ref params "lines" "100")))
(if service
(lab-command-executor "journalctl"
(list "-u" service "--lines" lines "--no-pager"))
'(("error" . "Service name required")))))))
(define (register-lab-prompts server)
"Register lab management prompts with the MCP server"
;; Deployment prompts
(register-route (mcp-server-handlers server) "prompts/deploy/machine"
(lambda (server params)
`(("prompt" . "Deploy configuration to machine")
("description" . "Deploy NixOS configuration to a target machine")
("parameters" . (("machine" . (("type" . "string")
("description" . "Target machine hostname")))
("config" . (("type" . "string")
("description" . "Configuration flake path")))
("dry_run" . (("type" . "boolean")
("description" . "Perform dry run only"))))))))
;; Troubleshooting prompts
(register-route (mcp-server-handlers server) "prompts/troubleshoot/service"
(lambda (server params)
`(("prompt" . "Troubleshoot service issues")
("description" . "Diagnose and troubleshoot service problems")
("parameters" . (("service" . (("type" . "string")
("description" . "Service name to troubleshoot")))
("include_logs" . (("type" . "boolean")
("description" . "Include service logs"))))))))
;; Monitoring prompts
(register-route (mcp-server-handlers server) "prompts/monitor/system"
(lambda (server params)
`(("prompt" . "Monitor system health")
("description" . "Check overall system health and performance")
("parameters" . (("detailed" . (("type" . "boolean")
("description" . "Include detailed metrics")))
("alerts_only" . (("type" . "boolean")
("description" . "Show only alerts and warnings")))))))))
;; Main integration setup
(define* (setup-mcp-server #:key (name "home-lab-mcp") (version "1.0.0") (transport-type 'stdio) (port 8080))
"Set up and configure the integrated MCP server"
(let* ((server (create-mcp-server name version))
(router (create-default-router))
(error-handler (create-default-error-handler))
(transport (case transport-type
((stdio) (stdio-transport))
((http) (http-transport port))
((websocket) (websocket-transport port))
(else (stdio-transport)))))
;; Register lab-specific handlers
(register-lab-tools server)
(register-lab-resources server)
(register-lab-prompts server)
;; Return configured server and transport
(values server transport router error-handler)))
(define* (start-mcp-server #:key (transport-type 'stdio) (port 8080))
"Start the integrated MCP server"
(receive (server transport router error-handler)
(setup-mcp-server #:transport-type transport-type #:port port)
(format (current-error-port) "Starting MCP server with ~a transport~%" transport-type)
;; Start the server
(catch #t
(lambda ()
(run-mcp-server server transport))
(lambda (key . args)
(handle-error error-handler 'internal-error
(cons key args)
"MCP server startup")))
(format (current-error-port) "MCP server stopped~%")))
;; Convenience function for creating integrated server
(define (create-integrated-mcp-server)
"Create a fully integrated MCP server with all lab tools"
(receive (server transport router error-handler)
(setup-mcp-server)
server))