// Vercel API route handler
// Note: @vercel/node types are provided by Vercel runtime
interface VercelRequest {
method?: string
url?: string
body?: any
headers?: Record<string, string>
}
interface VercelResponse {
statusCode?: number
setHeader(name: string, value: string): void
status(code: number): VercelResponse
json(data: any): void
send(data: any): void
end(data?: any): void
}
export default async function handler(req: VercelRequest, res: VercelResponse) {
// Set CORS headers and optimization headers
res.setHeader('Access-Control-Allow-Origin', '*')
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS')
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization')
res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate')
res.setHeader('Connection', 'keep-alive')
// Handle preflight requests
if (req.method === 'OPTIONS') {
res.status(200).end()
return
}
// Simple health check for ChatGPT Connector (fastest possible response)
if (url === '/health' || url === '/ping') {
res.setHeader('Content-Type', 'application/json')
res.status(200).json({ status: 'ok', timestamp: Date.now() })
return
}
try {
// Route handling
// Landing page
if (url === '/') {
const html = `
<!DOCTYPE html>
<html>
<head>
<title>🚀 AURA MCP Server</title>
<meta charset="utf-8">
<style>
body { font-family: Arial, sans-serif; margin: 40px; background: #f5f5f5; }
.container { max-width: 800px; margin: 0 auto; background: white; padding: 30px; border-radius: 10px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }
h1 { color: #2563eb; }
.endpoint { background: #f8fafc; padding: 15px; margin: 10px 0; border-radius: 5px; border-left: 4px solid #2563eb; }
code { background: #e2e8f0; padding: 2px 6px; border-radius: 3px; }
</style>
</head>
<body>
<div class="container">
<h1>🚀 AURA MCP Server</h1>
<p>Bridge LLMs with AURA API and EVM for on-chain intelligence</p>
<div class="endpoint">
<h3>📡 Health Check</h3>
<p><code>GET /api/health</code> - Check server status</p>
</div>
<div class="endpoint">
<h3>💰 Portfolio Analysis</h3>
<p><code>POST /api/portfolio/balance</code> - Get wallet balance and positions</p>
</div>
<div class="endpoint">
<h3>🎯 Strategy Proposals</h3>
<p><code>POST /api/strategy/propose</code> - Generate AI-powered trading strategies</p>
</div>
<div class="endpoint">
<h3>🔄 Transaction Simulation</h3>
<p><code>POST /api/transaction/simulate</code> - Simulate transactions safely</p>
</div>
<div class="endpoint">
<h3>🛡️ Guard Management</h3>
<p><code>POST /api/guard/setRules</code> - Configure risk management rules</p>
</div>
<div class="endpoint">
<h3>⚙️ System Health</h3>
<p><code>GET /api/system/health</code> - Check system status and services</p>
</div>
<p><strong>Status:</strong> ✅ Server is running and ready to handle requests!</p>
</div>
</body>
</html>
`
res.setHeader('Content-Type', 'text/html')
res.status(200).send(html)
return
}
// Health check endpoint
if (url === '/api/health') {
const response = {
success: true,
data: {
status: 'healthy',
timestamp: new Date().toISOString(),
version: '1.0.0',
uptime: process.uptime(),
environment: 'vercel'
}
}
res.setHeader('Content-Type', 'application/json')
res.status(200).json(response)
return
}
// System health endpoint
if (url === '/api/system/health') {
const response = {
success: true,
data: {
status: 'operational',
services: {
auraApi: 'connected',
guardEngine: 'active',
emergencyStop: false
},
timestamp: new Date().toISOString(),
environment: 'vercel'
}
}
res.setHeader('Content-Type', 'application/json')
res.status(200).json(response)
return
}
// Portfolio balance endpoint
if (url === '/api/portfolio/balance' && req.method === 'POST') {
const { address } = req.body
if (!address) {
res.status(400).json({
success: false,
error: { code: 'MISSING_ADDRESS', message: 'Address is required' }
})
return
}
// Mock response for now (you can integrate with AURA API later)
const response = {
success: true,
data: {
address,
totalValueUsd: 4897.50,
positions: [
{
token: 'ETH',
balance: '1.234',
valueUsd: 2456.75,
chain: 'ethereum'
},
{
token: 'USDC',
balance: '2440.75',
valueUsd: 2440.75,
chain: 'ethereum'
}
],
chains: ['ethereum', 'base', 'arbitrum'],
lastUpdated: new Date().toISOString()
}
}
res.setHeader('Content-Type', 'application/json')
res.status(200).json(response)
return
}
// Strategy proposal endpoint
if (url === '/api/strategy/propose' && req.method === 'POST') {
const { intent, params, address } = req.body
if (!intent || !address) {
res.status(400).json({
success: false,
error: { code: 'MISSING_PARAMS', message: 'Intent and address are required' }
})
return
}
// Mock response for now
const response = {
success: true,
data: {
intent,
strategy: {
type: intent,
params,
recommendations: [
'Consider DCA approach for volatile assets',
'Set stop-loss at 10% drawdown',
'Monitor gas prices before execution'
],
riskScore: 7.5,
expectedReturn: '12-15% annually'
},
address,
timestamp: new Date().toISOString()
}
}
res.setHeader('Content-Type', 'application/json')
res.status(200).json(response)
return
}
// Transaction simulation endpoint
if (url === '/api/transaction/simulate' && req.method === 'POST') {
const { intentId, txParams } = req.body
if (!intentId || !txParams) {
res.status(400).json({
success: false,
error: { code: 'MISSING_PARAMS', message: 'IntentId and txParams are required' }
})
return
}
// Mock response for now
const response = {
success: true,
data: {
intentId,
simulation: {
gasUsed: '21000',
gasPrice: '20000000000',
costUsd: 10.50,
slippagePct: 0.5,
success: true
},
guards: {
passed: true,
triggeredGuards: [],
warnings: []
},
timestamp: new Date().toISOString()
}
}
res.setHeader('Content-Type', 'application/json')
res.status(200).json(response)
return
}
// Guard rules endpoint
if (url === '/api/guard/setRules' && req.method === 'POST') {
const { rules } = req.body
if (!rules) {
res.status(400).json({
success: false,
error: { code: 'MISSING_RULES', message: 'Rules are required' }
})
return
}
// Mock response for now
const response = {
success: true,
data: {
success: true,
rulesSet: Object.keys(rules).length,
timestamp: new Date().toISOString()
}
}
res.setHeader('Content-Type', 'application/json')
res.status(200).json(response)
return
}
// MCP Protocol endpoint for ChatGPT Connector - SSE compatible
if (url === '/mcp' || url === '/mcp/') {
// Set SSE headers for long-lived connection
res.setHeader('Content-Type', 'text/event-stream')
res.setHeader('Cache-Control', 'no-cache')
res.setHeader('Connection', 'keep-alive')
res.setHeader('Access-Control-Allow-Origin', '*')
res.setHeader('Access-Control-Allow-Headers', '*')
if (req.method === 'GET') {
// Send SSE stream for MCP protocol
res.status(200)
// Send initial MCP handshake
res.write(`data: ${JSON.stringify({
jsonrpc: "2.0",
id: 1,
result: {
protocolVersion: "2024-11-05",
capabilities: {
tools: {},
resources: {}
},
serverInfo: {
name: "aura-mcp-server",
version: "1.0.0"
}
}
})}\n\n`)
// Keep connection alive
const keepAlive = setInterval(() => {
res.write(`data: ${JSON.stringify({ type: 'ping', timestamp: Date.now() })}\n\n`)
}, 30000)
// Clean up on connection close
req.on('close', () => {
clearInterval(keepAlive)
})
return
}
if (req.method === 'POST') {
// Handle MCP JSON-RPC requests with SSE
const body = req.body || {}
res.status(200)
if (body.method === 'initialize') {
res.write(`data: ${JSON.stringify({
jsonrpc: "2.0",
id: body.id,
result: {
protocolVersion: "2024-11-05",
capabilities: {
tools: {},
resources: {}
},
serverInfo: {
name: "aura-mcp-server",
version: "1.0.0"
}
}
})}\n\n`)
} else if (body.method === 'tools/list') {
res.write(`data: ${JSON.stringify({
jsonrpc: "2.0",
id: body.id,
result: {
tools: [
{
name: "get_portfolio_balance",
description: "Analyze wallet portfolio balance and positions across multiple chains",
inputSchema: {
type: "object",
properties: {
address: {
type: "string",
description: "Ethereum wallet address to analyze"
}
},
required: ["address"]
}
},
{
name: "propose_strategy",
description: "Generate AI-powered trading strategy recommendations",
inputSchema: {
type: "object",
properties: {
intent: {
type: "string",
description: "Strategy type"
},
address: {
type: "string",
description: "Wallet address for strategy"
}
},
required: ["intent", "address"]
}
}
]
}
})}\n\n`)
} else {
res.write(`data: ${JSON.stringify({
jsonrpc: "2.0",
id: body.id,
error: {
code: -32601,
message: "Method not found"
}
})}\n\n`)
}
// Keep connection alive
const keepAlive = setInterval(() => {
res.write(`data: ${JSON.stringify({ type: 'ping', timestamp: Date.now() })}\n\n`)
}, 30000)
req.on('close', () => {
clearInterval(keepAlive)
})
return
}
}
// ChatGPT Connector specific endpoint
if (url === '/chatgpt/mcp') {
const chatgptResponse = {
name: "aura-mcp-server",
version: "1.0.0",
protocol: "mcp",
capabilities: {
tools: true,
resources: true
},
endpoints: {
initialize: "/mcp",
tools: "/mcp/tools"
},
status: "ready",
timestamp: new Date().toISOString()
}
res.setHeader('Content-Type', 'application/json')
res.status(200).json(chatgptResponse)
return
}
// Alternative MCP endpoint for ChatGPT Connector
if (url === '/mcp/info') {
const infoResponse = {
protocol: "mcp",
version: "2024-11-05",
name: "aura-mcp-server",
capabilities: ["tools", "resources"],
status: "ready"
}
res.setHeader('Content-Type', 'application/json')
res.status(200).json(infoResponse)
return
}
// MCP Tools list endpoint
if (url === '/mcp/tools') {
const toolsResponse = {
jsonrpc: "2.0",
id: 1,
result: {
tools: [
{
name: "get_portfolio_balance",
description: "Analyze wallet portfolio balance and positions across multiple chains",
inputSchema: {
type: "object",
properties: {
address: {
type: "string",
description: "Ethereum wallet address to analyze"
},
chain: {
type: "string",
description: "Blockchain network (ethereum, base, arbitrum)",
default: "ethereum"
}
},
required: ["address"]
}
},
{
name: "propose_strategy",
description: "Generate AI-powered trading strategy recommendations",
inputSchema: {
type: "object",
properties: {
intent: {
type: "string",
description: "Strategy type (dca_event_aware, liquidation_guard, basket_rotation)",
enum: ["dca_event_aware", "liquidation_guard", "basket_rotation"]
},
params: {
type: "object",
description: "Strategy parameters"
},
address: {
type: "string",
description: "Wallet address for strategy"
}
},
required: ["intent", "address"]
}
}
]
}
}
res.setHeader('Content-Type', 'application/json')
res.status(200).json(toolsResponse)
return
}
// ChatGPT/OpenAI compatible endpoints
if (url === '/openai/functions') {
const functions = {
functions: [
{
name: "get_portfolio_balance",
description: "Analyze wallet portfolio balance and positions across multiple chains",
parameters: {
type: "object",
properties: {
address: {
type: "string",
description: "Ethereum wallet address to analyze"
},
chain: {
type: "string",
description: "Blockchain network (ethereum, base, arbitrum)",
default: "ethereum"
}
},
required: ["address"]
}
},
{
name: "propose_strategy",
description: "Generate AI-powered trading strategy recommendations",
parameters: {
type: "object",
properties: {
intent: {
type: "string",
description: "Strategy type (dca_event_aware, liquidation_guard, basket_rotation)",
enum: ["dca_event_aware", "liquidation_guard", "basket_rotation"]
},
params: {
type: "object",
description: "Strategy parameters"
},
address: {
type: "string",
description: "Wallet address for strategy"
}
},
required: ["intent", "address"]
}
},
{
name: "simulate_transaction",
description: "Simulate transaction with risk assessment",
parameters: {
type: "object",
properties: {
intentId: {
type: "string",
description: "Transaction intent ID"
},
txParams: {
type: "object",
description: "Transaction parameters"
}
},
required: ["intentId", "txParams"]
}
},
{
name: "set_guard_rules",
description: "Configure risk management guard rules",
parameters: {
type: "object",
properties: {
rules: {
type: "object",
description: "Guard rules configuration"
}
},
required: ["rules"]
}
}
]
}
res.setHeader('Content-Type', 'application/json')
res.status(200).json(functions)
return
}
// 404 for unknown routes
res.status(404).json({
success: false,
error: { code: 'NOT_FOUND', message: `Route ${url} not found` }
})
} catch (error) {
console.error('Handler error:', error)
res.status(500).json({
success: false,
error: {
code: 'INTERNAL_ERROR',
message: error instanceof Error ? error.message : 'Internal server error'
}
})
}
}