396 lines
11 KiB
Text
396 lines
11 KiB
Text
|
|
#!/usr/bin/env nu
|
||
|
|
# MCP Integration Manager for AuroraFrame
|
||
|
|
#
|
||
|
|
# Manages the connection between AuroraFrame and the Nushell MCP server
|
||
|
|
# Provides seamless AI integration for content generation, schema intelligence,
|
||
|
|
# error resolution, and asset optimization
|
||
|
|
|
||
|
|
# MCP Server Configuration
|
||
|
|
let MCP_CONFIG = {
|
||
|
|
server_path: "./auroraframe-mcp-server/mcp-server.nu"
|
||
|
|
connection_timeout: 30000 # 30 seconds
|
||
|
|
max_retries: 3
|
||
|
|
log_level: "info"
|
||
|
|
}
|
||
|
|
|
||
|
|
# Check if MCP server is available and functional
|
||
|
|
export def check_mcp_availability [] {
|
||
|
|
let server_exists = ($MCP_CONFIG.server_path | path exists)
|
||
|
|
|
||
|
|
if not $server_exists {
|
||
|
|
return {
|
||
|
|
available: false
|
||
|
|
reason: "MCP server not found"
|
||
|
|
path: $MCP_CONFIG.server_path
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Test basic MCP server functionality
|
||
|
|
let test_result = try {
|
||
|
|
nu $MCP_CONFIG.server_path --help | complete
|
||
|
|
} catch {
|
||
|
|
return {
|
||
|
|
available: false
|
||
|
|
reason: "MCP server failed to start"
|
||
|
|
error: $env.LAST_EXIT_CODE
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if $test_result.exit_code != 0 {
|
||
|
|
return {
|
||
|
|
available: false
|
||
|
|
reason: "MCP server startup error"
|
||
|
|
stderr: $test_result.stderr
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
{
|
||
|
|
available: true
|
||
|
|
version: "1.0.0"
|
||
|
|
server_path: $MCP_CONFIG.server_path
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Initialize MCP server connection
|
||
|
|
export def init_mcp_connection [verbose: bool = false] {
|
||
|
|
if $verbose { print "🔌 Initializing MCP server connection..." }
|
||
|
|
|
||
|
|
let availability = (check_mcp_availability)
|
||
|
|
|
||
|
|
if not $availability.available {
|
||
|
|
if $verbose {
|
||
|
|
print $"❌ MCP server unavailable: ($availability.reason)"
|
||
|
|
if "path" in $availability {
|
||
|
|
print $" Server path: ($availability.path)"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return { connected: false, reason: $availability.reason }
|
||
|
|
}
|
||
|
|
|
||
|
|
if $verbose {
|
||
|
|
print $"✅ MCP server available at: ($availability.server_path)"
|
||
|
|
print $"📡 Connection established (version: ($availability.version))"
|
||
|
|
}
|
||
|
|
|
||
|
|
{
|
||
|
|
connected: true
|
||
|
|
server: $availability
|
||
|
|
config: $MCP_CONFIG
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Execute MCP tool with error handling and retries
|
||
|
|
export def execute_mcp_tool [
|
||
|
|
tool_name: string
|
||
|
|
arguments: record
|
||
|
|
--timeout: int = 30000
|
||
|
|
--retries: int = 3
|
||
|
|
--verbose: bool = false
|
||
|
|
] {
|
||
|
|
if $verbose { print $"🔧 Executing MCP tool: ($tool_name)" }
|
||
|
|
|
||
|
|
let connection = (init_mcp_connection $verbose)
|
||
|
|
|
||
|
|
if not $connection.connected {
|
||
|
|
return {
|
||
|
|
success: false
|
||
|
|
error: $"MCP connection failed: ($connection.reason)"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Prepare MCP request
|
||
|
|
let mcp_request = {
|
||
|
|
jsonrpc: "2.0"
|
||
|
|
id: (random uuid)
|
||
|
|
method: "tools/call"
|
||
|
|
params: {
|
||
|
|
name: $tool_name
|
||
|
|
arguments: $arguments
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
mut attempts = 0
|
||
|
|
mut last_error = ""
|
||
|
|
|
||
|
|
# Retry loop
|
||
|
|
while $attempts < $retries {
|
||
|
|
$attempts = ($attempts + 1)
|
||
|
|
|
||
|
|
if $verbose and $attempts > 1 {
|
||
|
|
print $"🔄 Retry attempt ($attempts)/($retries)"
|
||
|
|
}
|
||
|
|
|
||
|
|
let result = try {
|
||
|
|
# In a real implementation, this would communicate with the MCP server
|
||
|
|
# For now, we'll simulate the response
|
||
|
|
execute_mcp_request $mcp_request $connection.server.server_path $verbose
|
||
|
|
} catch { |error|
|
||
|
|
$last_error = $error.msg
|
||
|
|
if $verbose { print $"❌ MCP execution failed (attempt ($attempts)): ($error.msg)" }
|
||
|
|
continue
|
||
|
|
}
|
||
|
|
|
||
|
|
if "error" not-in $result {
|
||
|
|
if $verbose { print $"✅ MCP tool executed successfully" }
|
||
|
|
return {
|
||
|
|
success: true
|
||
|
|
result: $result
|
||
|
|
attempts: $attempts
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
$last_error = $result.error
|
||
|
|
if $verbose { print $"❌ MCP tool error (attempt ($attempts)): ($result.error)" }
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# All attempts failed
|
||
|
|
{
|
||
|
|
success: false
|
||
|
|
error: $"MCP execution failed after ($retries) attempts: ($last_error)"
|
||
|
|
attempts: $attempts
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Execute MCP request (simulated for now)
|
||
|
|
def execute_mcp_request [request: record, server_path: string, verbose: bool] {
|
||
|
|
# This is a mock implementation
|
||
|
|
# In production, this would:
|
||
|
|
# 1. Start the MCP server process
|
||
|
|
# 2. Send JSON-RPC request via stdin
|
||
|
|
# 3. Read JSON-RPC response from stdout
|
||
|
|
# 4. Handle errors and timeouts
|
||
|
|
|
||
|
|
let tool_name = $request.params.name
|
||
|
|
let args = $request.params.arguments
|
||
|
|
|
||
|
|
# Mock responses for demonstration
|
||
|
|
match $tool_name {
|
||
|
|
"generate_content" => {
|
||
|
|
let prompt = $args.prompt
|
||
|
|
let format = ($args.format | default "markdown")
|
||
|
|
|
||
|
|
{
|
||
|
|
jsonrpc: "2.0"
|
||
|
|
id: $request.id
|
||
|
|
result: {
|
||
|
|
content: [{
|
||
|
|
type: "text"
|
||
|
|
text: $"# AI-Generated Content\n\nGenerated content for prompt: \"($prompt)\"\n\nFormat: ($format)\n\nThis would be actual AI-generated content in production."
|
||
|
|
}]
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
"enhance_content" => {
|
||
|
|
let enhancements = ($args.enhancements | str join ", ")
|
||
|
|
|
||
|
|
{
|
||
|
|
jsonrpc: "2.0"
|
||
|
|
id: $request.id
|
||
|
|
result: {
|
||
|
|
content: [{
|
||
|
|
type: "text"
|
||
|
|
text: $"Enhanced content with improvements: ($enhancements)\n\nOriginal content has been optimized for better performance and user experience."
|
||
|
|
}]
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
"generate_schema" => {
|
||
|
|
let description = $args.description
|
||
|
|
|
||
|
|
{
|
||
|
|
jsonrpc: "2.0"
|
||
|
|
id: $request.id
|
||
|
|
result: {
|
||
|
|
content: [{
|
||
|
|
type: "text"
|
||
|
|
text: $"Generated KCL Schema based on: \"($description)\"\n\n```kcl\nschema GeneratedContent:\n title: str\n description: str\n created_at: str\n tags: [str] = []\n featured: bool = false\n```"
|
||
|
|
}]
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
"resolve_error" => {
|
||
|
|
let error_msg = $args.error.message
|
||
|
|
|
||
|
|
{
|
||
|
|
jsonrpc: "2.0"
|
||
|
|
id: $request.id
|
||
|
|
result: {
|
||
|
|
content: [{
|
||
|
|
type: "text"
|
||
|
|
text: $"Error Analysis for: \"($error_msg)\"\n\n## Suggested Fixes:\n1. Check configuration syntax\n2. Validate required fields\n3. Ensure proper file permissions\n\n## Prevention:\n- Use KCL schema validation\n- Enable strict type checking"
|
||
|
|
}]
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
_ => {
|
||
|
|
{
|
||
|
|
jsonrpc: "2.0"
|
||
|
|
id: $request.id
|
||
|
|
error: {
|
||
|
|
code: -32601
|
||
|
|
message: $"Method not found: ($tool_name)"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# MCP-powered content generation
|
||
|
|
export def mcp_generate_content [
|
||
|
|
prompt: string
|
||
|
|
schema: record = {}
|
||
|
|
format: string = "markdown"
|
||
|
|
--verbose: bool = false
|
||
|
|
] {
|
||
|
|
let result = (execute_mcp_tool "generate_content" {
|
||
|
|
prompt: $prompt
|
||
|
|
schema: $schema
|
||
|
|
format: $format
|
||
|
|
} --verbose=$verbose)
|
||
|
|
|
||
|
|
if $result.success {
|
||
|
|
$result.result.result.content.0.text
|
||
|
|
} else {
|
||
|
|
throw $result.error
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# MCP-powered content enhancement
|
||
|
|
export def mcp_enhance_content [
|
||
|
|
content: string
|
||
|
|
enhancements: list = ["seo"]
|
||
|
|
--verbose: bool = false
|
||
|
|
] {
|
||
|
|
let result = (execute_mcp_tool "enhance_content" {
|
||
|
|
content: $content
|
||
|
|
enhancements: $enhancements
|
||
|
|
} --verbose=$verbose)
|
||
|
|
|
||
|
|
if $result.success {
|
||
|
|
$result.result.result.content.0.text
|
||
|
|
} else {
|
||
|
|
throw $result.error
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# MCP-powered schema generation
|
||
|
|
export def mcp_generate_schema [
|
||
|
|
description: string
|
||
|
|
examples: list = []
|
||
|
|
--verbose: bool = false
|
||
|
|
] {
|
||
|
|
let result = (execute_mcp_tool "generate_schema" {
|
||
|
|
description: $description
|
||
|
|
examples: $examples
|
||
|
|
} --verbose=$verbose)
|
||
|
|
|
||
|
|
if $result.success {
|
||
|
|
$result.result.result.content.0.text
|
||
|
|
} else {
|
||
|
|
throw $result.error
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# MCP-powered error resolution
|
||
|
|
export def mcp_resolve_error [
|
||
|
|
error_info: record
|
||
|
|
project_context: record = {}
|
||
|
|
--verbose: bool = false
|
||
|
|
] {
|
||
|
|
let result = (execute_mcp_tool "resolve_error" {
|
||
|
|
error: $error_info
|
||
|
|
project_context: $project_context
|
||
|
|
} --verbose=$verbose)
|
||
|
|
|
||
|
|
if $result.success {
|
||
|
|
$result.result.result.content.0.text
|
||
|
|
} else {
|
||
|
|
throw $result.error
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Integration with existing framework commands
|
||
|
|
export def integrate_mcp_with_framework [] {
|
||
|
|
# Add MCP status to framework info
|
||
|
|
let mcp_status = (check_mcp_availability)
|
||
|
|
|
||
|
|
print "🤖 MCP Integration Status:"
|
||
|
|
if $mcp_status.available {
|
||
|
|
print $" ✅ Available (version: ($mcp_status.version))"
|
||
|
|
print $" 📍 Server: ($mcp_status.server_path)"
|
||
|
|
} else {
|
||
|
|
print $" ❌ Unavailable: ($mcp_status.reason)"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# MCP health check and diagnostics
|
||
|
|
export def mcp_diagnostics [--verbose: bool = false] {
|
||
|
|
print "🏥 MCP Server Diagnostics"
|
||
|
|
print "========================="
|
||
|
|
|
||
|
|
# Check server file
|
||
|
|
let server_exists = ($MCP_CONFIG.server_path | path exists)
|
||
|
|
print $"Server file: (if $server_exists { '✅' } else { '❌' }) ($MCP_CONFIG.server_path)"
|
||
|
|
|
||
|
|
if not $server_exists {
|
||
|
|
print "❌ MCP server not found. Please ensure the server is installed."
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
# Check dependencies
|
||
|
|
print "\n📦 Dependencies:"
|
||
|
|
|
||
|
|
# Check Nushell version
|
||
|
|
let nu_version = (version | get version)
|
||
|
|
print $" Nushell: ✅ ($nu_version)"
|
||
|
|
|
||
|
|
# Check OpenAI API key (if configured)
|
||
|
|
let openai_key = ($env.OPENAI_API_KEY? | default "")
|
||
|
|
if ($openai_key | is-empty) {
|
||
|
|
print " OpenAI API: ⚠️ Not configured (optional)"
|
||
|
|
} else {
|
||
|
|
print " OpenAI API: ✅ Configured"
|
||
|
|
}
|
||
|
|
|
||
|
|
# Test basic functionality
|
||
|
|
print "\n🧪 Functionality Tests:"
|
||
|
|
|
||
|
|
let connection_test = try {
|
||
|
|
init_mcp_connection false
|
||
|
|
} catch {
|
||
|
|
{ connected: false, reason: "Connection test failed" }
|
||
|
|
}
|
||
|
|
|
||
|
|
if $connection_test.connected {
|
||
|
|
print " Connection: ✅ Success"
|
||
|
|
|
||
|
|
# Test a simple MCP call
|
||
|
|
let tool_test = try {
|
||
|
|
execute_mcp_tool "generate_schema" { description: "test schema" } --verbose=false
|
||
|
|
} catch {
|
||
|
|
{ success: false, error: "Tool test failed" }
|
||
|
|
}
|
||
|
|
|
||
|
|
if $tool_test.success {
|
||
|
|
print " Tool Execution: ✅ Success"
|
||
|
|
} else {
|
||
|
|
print $" Tool Execution: ❌ ($tool_test.error)"
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
print $" Connection: ❌ ($connection_test.reason)"
|
||
|
|
}
|
||
|
|
|
||
|
|
print "\n📊 Configuration:"
|
||
|
|
print $" Timeout: ($MCP_CONFIG.connection_timeout)ms"
|
||
|
|
print $" Max Retries: ($MCP_CONFIG.max_retries)"
|
||
|
|
print $" Log Level: ($MCP_CONFIG.log_level)"
|
||
|
|
|
||
|
|
if $verbose {
|
||
|
|
print "\n🔍 Detailed Configuration:"
|
||
|
|
$MCP_CONFIG | table
|
||
|
|
}
|
||
|
|
}
|