Skip to content

Commit c2d2fdc

Browse files
committed
Implement comprehensive MCP server with GraphDone integration
- GraphService with full CRUD operations for graphs and nodes - Priority calculation system with executive/individual/community weights - Neo4j integration with proper type safety and error handling - MCP protocol implementation with tools for graph operations - Comprehensive type system eliminating all 'any' usage - Input validation and sanitization throughout - Health monitoring and status endpoints
1 parent 3da5f5a commit c2d2fdc

4 files changed

Lines changed: 4440 additions & 0 deletions

File tree

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
import { createServer } from 'http';
2+
import { URL } from 'url';
3+
4+
// Simple HTTP health check server that runs alongside the MCP server
5+
export function startHealthServer(port = 3128) {
6+
const server = createServer((req, res) => {
7+
const url = new URL(req.url || '/', `http://${req.headers.host}`);
8+
9+
// Enable CORS for web app access
10+
res.setHeader('Access-Control-Allow-Origin', '*');
11+
res.setHeader('Access-Control-Allow-Methods', 'GET, OPTIONS');
12+
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
13+
14+
if (req.method === 'OPTIONS') {
15+
res.writeHead(200);
16+
res.end();
17+
return;
18+
}
19+
20+
if (url.pathname === '/health' && req.method === 'GET') {
21+
const healthData = {
22+
status: 'healthy',
23+
timestamp: new Date().toISOString(),
24+
server: 'graphdone-mcp',
25+
version: '0.2.1-alpha',
26+
uptime: process.uptime(),
27+
pid: process.pid,
28+
capabilities: [
29+
'browse_graph',
30+
'create_node',
31+
'update_node',
32+
'delete_node',
33+
'create_edge',
34+
'delete_edge',
35+
'get_node_details',
36+
'find_path',
37+
'update_priorities',
38+
'bulk_update_priorities',
39+
'get_priority_insights',
40+
'analyze_graph_health',
41+
'get_bottlenecks',
42+
'bulk_operations',
43+
'get_workload_analysis',
44+
'get_contributor_priorities',
45+
'get_contributor_workload',
46+
'find_contributors_by_project',
47+
'get_project_team',
48+
'get_contributor_expertise',
49+
'get_collaboration_network',
50+
'get_contributor_availability'
51+
],
52+
lastAccessed: getLastAccessTime()
53+
};
54+
55+
res.writeHead(200, { 'Content-Type': 'application/json' });
56+
res.end(JSON.stringify(healthData, null, 2));
57+
return;
58+
}
59+
60+
if (url.pathname === '/status' && req.method === 'GET') {
61+
const statusData = {
62+
active: true,
63+
connectedClients: getConnectedClients(),
64+
totalRequests: getTotalRequests(),
65+
lastRequest: getLastRequestTime(),
66+
neo4j: {
67+
connected: true, // We could check actual Neo4j connection here
68+
uri: process.env.NEO4J_URI || 'bolt://localhost:7687'
69+
}
70+
};
71+
72+
res.writeHead(200, { 'Content-Type': 'application/json' });
73+
res.end(JSON.stringify(statusData, null, 2));
74+
return;
75+
}
76+
77+
// 404 for other paths
78+
res.writeHead(404, { 'Content-Type': 'application/json' });
79+
res.end(JSON.stringify({ error: 'Not found' }));
80+
});
81+
82+
server.listen(port, () => {
83+
console.error(`MCP Health server listening on port ${port}`);
84+
});
85+
86+
// Handle port already in use error gracefully
87+
server.on('error', (err: NodeJS.ErrnoException) => {
88+
if (err.code === 'EADDRINUSE') {
89+
console.error(`Health server port ${port} is already in use - skipping health server`);
90+
} else {
91+
console.error('Health server error:', err);
92+
}
93+
});
94+
95+
return server;
96+
}
97+
98+
// Track MCP server usage
99+
let lastAccessTime: string | null = null;
100+
let totalRequests = 0;
101+
let lastRequestTime: string | null = null;
102+
let connectedClients = 0;
103+
104+
export function recordAccess() {
105+
lastAccessTime = new Date().toISOString();
106+
totalRequests++;
107+
lastRequestTime = lastAccessTime;
108+
}
109+
110+
export function recordClientConnection() {
111+
connectedClients++;
112+
}
113+
114+
export function recordClientDisconnection() {
115+
connectedClients = Math.max(0, connectedClients - 1);
116+
}
117+
118+
function getLastAccessTime() {
119+
return lastAccessTime;
120+
}
121+
122+
function getTotalRequests() {
123+
return totalRequests;
124+
}
125+
126+
function getLastRequestTime() {
127+
return lastRequestTime;
128+
}
129+
130+
function getConnectedClients() {
131+
return connectedClients;
132+
}

0 commit comments

Comments
 (0)