527 lines
18 KiB
Plaintext
Raw Normal View History

#!/usr/bin/env nu
# AuroraFrame MCP Server - Native Nushell Implementation
#
# Model Context Protocol server providing AI-powered tools for AuroraFrame:
# - Content generation from KCL schemas
# - Schema intelligence and validation
# - Multi-format content optimization
# - Error resolution and debugging
# - Asset generation and optimization
# Global configuration
let MCP_CONFIG = {
name: "auroraframe-mcp-server"
version: "1.0.0"
openai_model: "gpt-4"
openai_api_key: ($env.OPENAI_API_KEY? | default "")
project_path: ($env.AURORAFRAME_PROJECT_PATH? | default (pwd))
default_language: ($env.AURORAFRAME_DEFAULT_LANGUAGE? | default "en")
max_tokens: 4000
temperature: 0.7
}
# Import tool modules
use content-generator.nu *
use schema-intelligence.nu *
use error-resolver.nu *
use asset-generator.nu *
# MCP Protocol Implementation
export def main [
--debug(-d) # Enable debug logging
--config(-c): string # Custom config file path
2025-10-07 10:32:04 +01:00
] {
if $debug {
print "🔥 Starting AuroraFrame MCP Server in debug mode"
print $" Configuration: ($MCP_CONFIG)"
}
# Load custom config if provided
let config = if ($config | is-not-empty) {
load_custom_config $config
} else {
$MCP_CONFIG
}
# Start MCP server loop
mcp_server_loop $config $debug
}
# Main MCP server event loop
def mcp_server_loop [config: record, debug: bool] {
if $debug { print "📡 Starting MCP server event loop" }
loop {
# Read MCP message from stdin
let input_line = try { input } catch { break }
if ($input_line | is-empty) { continue }
# Parse JSON message
let message = try {
$input_line | from json
} catch {
if $debug { print $"❌ Failed to parse JSON: ($input_line)" }
continue
}
# Process MCP message and send response
let response = (handle_mcp_message $message $config $debug)
$response | to json --raw | print
}
}
# Handle incoming MCP messages
def handle_mcp_message [message: record, config: record, debug: bool] {
if $debug { print $"📨 Received MCP message: ($message.method)" }
match $message.method {
"initialize" => (handle_initialize $message $config)
"tools/list" => (handle_tools_list $message)
"tools/call" => (handle_tool_call $message $config $debug)
_ => (create_error_response $message.id "Method not found" -32601)
}
}
# Handle MCP initialize request
def handle_initialize [message: record, config: record] {
{
jsonrpc: "2.0"
id: $message.id
result: {
protocolVersion: "2024-11-05"
capabilities: {
tools: {}
}
serverInfo: {
name: $config.name
version: $config.version
}
}
}
}
# Handle tools list request
def handle_tools_list [message: record] {
{
jsonrpc: "2.0"
id: $message.id
result: {
tools: [
# Content Generation Tools
{
name: "generate_content"
description: "Generate content from KCL schema and prompt"
inputSchema: {
type: "object"
properties: {
schema: {
type: "object"
description: "KCL schema definition for content structure"
}
prompt: {
type: "string"
description: "Content generation prompt"
}
format: {
type: "string"
enum: ["markdown", "html", "json"]
default: "markdown"
description: "Output format"
}
}
required: ["schema", "prompt"]
}
}
{
name: "enhance_content"
description: "Enhance existing content with AI improvements"
inputSchema: {
type: "object"
properties: {
content: {
type: "string"
description: "Existing content to enhance"
}
enhancements: {
type: "array"
items: {
type: "string"
enum: ["seo", "readability", "structure", "metadata", "images"]
}
description: "Types of enhancements to apply"
}
}
required: ["content", "enhancements"]
}
}
{
name: "generate_variations"
description: "Generate content variations for A/B testing"
inputSchema: {
type: "object"
properties: {
content: {
type: "string"
description: "Base content to create variations from"
}
count: {
type: "number"
default: 3
description: "Number of variations to generate"
}
focus: {
type: "string"
enum: ["tone", "length", "structure", "conversion"]
description: "Aspect to vary"
}
}
required: ["content"]
}
}
# Schema Intelligence Tools
{
name: "generate_schema"
description: "Generate KCL schema from natural language description"
inputSchema: {
type: "object"
properties: {
description: {
type: "string"
description: "Natural language description of desired schema"
}
examples: {
type: "array"
items: { type: "object" }
description: "Example data objects to inform schema"
}
}
required: ["description"]
}
}
{
name: "validate_schema"
description: "Validate and suggest improvements for KCL schema"
inputSchema: {
type: "object"
properties: {
schema: {
type: "string"
description: "KCL schema to validate"
}
data: {
type: "array"
items: { type: "object" }
description: "Sample data to validate against schema"
}
}
required: ["schema"]
}
}
{
name: "migrate_schema"
description: "Help migrate data between schema versions"
inputSchema: {
type: "object"
properties: {
old_schema: {
type: "string"
description: "Previous schema version"
}
new_schema: {
type: "string"
description: "New schema version"
}
data: {
type: "array"
items: { type: "object" }
description: "Data to migrate"
}
}
required: ["old_schema", "new_schema"]
}
}
# Error Resolution Tools
{
name: "resolve_error"
description: "Analyze and suggest fixes for AuroraFrame errors"
inputSchema: {
type: "object"
properties: {
error: {
type: "object"
properties: {
message: { type: "string" }
code: { type: "string" }
file: { type: "string" }
line: { type: "number" }
context: { type: "string" }
}
description: "Error details from AuroraFrame"
}
project_context: {
type: "object"
description: "Project context for better error resolution"
}
}
required: ["error"]
}
}
{
name: "analyze_build"
description: "Analyze build performance and suggest optimizations"
inputSchema: {
type: "object"
properties: {
build_log: {
type: "string"
description: "Build log output from AuroraFrame"
}
metrics: {
type: "object"
description: "Build performance metrics"
}
}
required: ["build_log"]
}
}
# Asset Generation Tools
{
name: "generate_images"
description: "Generate images from text descriptions"
inputSchema: {
type: "object"
properties: {
prompt: {
type: "string"
description: "Image generation prompt"
}
count: {
type: "number"
default: 1
description: "Number of images to generate"
}
size: {
type: "string"
enum: ["1024x1024", "1024x1792", "1792x1024"]
default: "1024x1024"
description: "Image dimensions"
}
style: {
type: "string"
enum: ["natural", "vivid"]
default: "natural"
description: "Image style"
}
}
required: ["prompt"]
}
}
{
name: "optimize_assets"
description: "Optimize images and assets for web delivery"
inputSchema: {
type: "object"
properties: {
assets: {
type: "array"
items: {
type: "object"
properties: {
path: { type: "string" }
type: { type: "string" }
}
}
description: "List of assets to optimize"
}
targets: {
type: "array"
items: {
type: "string"
enum: ["web", "email", "mobile"]
}
description: "Target formats for optimization"
}
}
required: ["assets"]
}
}
]
}
}
}
# Handle tool call request
def handle_tool_call [message: record, config: record, debug: bool] {
let tool_name = $message.params.name
let args = $message.params.arguments
if $debug { print $"🔧 Calling tool: ($tool_name)" }
let result = match $tool_name {
# Content Generation Tools
"generate_content" => (generate_content_tool $args $config $debug)
"enhance_content" => (enhance_content_tool $args $config $debug)
"generate_variations" => (generate_variations_tool $args $config $debug)
# Schema Intelligence Tools
"generate_schema" => (generate_schema_tool $args $config $debug)
"validate_schema" => (validate_schema_tool $args $config $debug)
"migrate_schema" => (migrate_schema_tool $args $config $debug)
# Error Resolution Tools
"resolve_error" => (resolve_error_tool $args $config $debug)
"analyze_build" => (analyze_build_tool $args $config $debug)
# Asset Generation Tools
"generate_images" => (generate_images_tool $args $config $debug)
"optimize_assets" => (optimize_assets_tool $args $config $debug)
_ => { error: $"Unknown tool: ($tool_name)" }
}
if "error" in $result {
create_error_response $message.id $result.error -32603
} else {
{
jsonrpc: "2.0"
id: $message.id
result: {
content: $result.content
}
}
}
}
# Create MCP error response
def create_error_response [id: any, message: string, code: int] {
{
jsonrpc: "2.0"
id: $id
error: {
code: $code
message: $message
}
}
}
# Load custom configuration
def load_custom_config [config_path: string] {
if ($config_path | path exists) {
let custom_config = (open $config_path)
$MCP_CONFIG | merge $custom_config
} else {
print $"⚠️ Config file not found: ($config_path)"
$MCP_CONFIG
}
}
# OpenAI API call helper
export def call_openai_api [
messages: list
config: record
temperature: float = 0.7
max_tokens: int = 4000
] {
if ($config.openai_api_key | is-empty) {
return { error: "OpenAI API key not configured" }
}
let payload = {
model: $config.openai_model
messages: $messages
temperature: $temperature
max_tokens: $max_tokens
}
let response = try {
http post "https://api.openai.com/v1/chat/completions"
--headers [
"Content-Type" "application/json"
"Authorization" $"Bearer ($config.openai_api_key)"
]
$payload
} catch { |e|
return { error: $"OpenAI API call failed: ($e.msg)" }
}
if "error" in $response {
{ error: $response.error.message }
} else {
{ content: $response.choices.0.message.content }
}
}
# Utility: Extract frontmatter from content
export def extract_frontmatter [content: string] {
let lines = ($content | lines)
if ($lines | first) == "---" {
let end_idx = ($lines | skip 1 | enumerate | where { |it| $it.item == "---" } | first?.index)
if ($end_idx | is-not-empty) {
let frontmatter_lines = ($lines | skip 1 | first ($end_idx))
let content_lines = ($lines | skip ($end_idx + 2))
{
frontmatter: ($frontmatter_lines | str join "\n" | from yaml)
content: ($content_lines | str join "\n")
}
} else {
{ frontmatter: {}, content: $content }
}
} else {
{ frontmatter: {}, content: $content }
}
}
# Utility: Generate frontmatter
export def generate_frontmatter [title: string, additional: record = {}] {
let base_frontmatter = {
title: $title
date: (date now | format date "%Y-%m-%d")
generated: true
generator: "auroraframe-mcp-server"
}
$base_frontmatter | merge $additional | to yaml
}
# Utility: Validate KCL syntax (basic check)
export def validate_kcl_syntax [kcl_content: string] {
# Basic KCL syntax validation
let issues = []
# Check for schema definitions
if not ($kcl_content | str contains "schema ") {
$issues = ($issues | append "No schema definitions found")
}
# Check for proper schema syntax
let schema_matches = ($kcl_content | str find-replace -ar 'schema\s+(\w+):' 'SCHEMA_FOUND')
if not ($schema_matches | str contains "SCHEMA_FOUND") {
$issues = ($issues | append "Invalid schema syntax")
}
# Check for type annotations
if not (($kcl_content | str contains ": str") or ($kcl_content | str contains ": int") or ($kcl_content | str contains ": bool")) {
$issues = ($issues | append "No type annotations found")
}
if ($issues | length) > 0 {
{ valid: false, issues: $issues }
} else {
{ valid: true, issues: [] }
}
}
# Debug helper
def debug_log [message: string, debug: bool] {
if $debug {
print $"🐛 DEBUG: ($message)"
}
}