codeatlas-mcp-server 2.20.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +338 -0
- package/dist/index.js +261 -0
- package/dist/index.js.map +1 -0
- package/dist/src/analyzer/parser.js +1072 -0
- package/dist/src/analyzer/parser.js.map +1 -0
- package/dist/src/analyzer/parser.test.js +73 -0
- package/dist/src/analyzer/parser.test.js.map +1 -0
- package/dist/src/analyzer/phpParser.js +147 -0
- package/dist/src/analyzer/phpParser.js.map +1 -0
- package/dist/src/analyzer/pythonParser.js +185 -0
- package/dist/src/analyzer/pythonParser.js.map +1 -0
- package/dist/src/analyzer/types.js +2 -0
- package/dist/src/analyzer/types.js.map +1 -0
- package/dist/src/context.js +3 -0
- package/dist/src/context.js.map +1 -0
- package/dist/src/memoryGenerator.js +293 -0
- package/dist/src/memoryGenerator.js.map +1 -0
- package/dist/src/oracleDatabase.js +298 -0
- package/dist/src/oracleDatabase.js.map +1 -0
- package/dist/src/presentation/httpServer.js +306 -0
- package/dist/src/presentation/httpServer.js.map +1 -0
- package/dist/src/presentation/mcpServer.js +1487 -0
- package/dist/src/presentation/mcpServer.js.map +1 -0
- package/dist/src/repositories.js +144 -0
- package/dist/src/repositories.js.map +1 -0
- package/dist/src/securityScanner.js +69 -0
- package/dist/src/securityScanner.js.map +1 -0
- package/dist/src/services/authService.js +24 -0
- package/dist/src/services/authService.js.map +1 -0
- package/dist/src/services/dreamingService.js +119 -0
- package/dist/src/services/dreamingService.js.map +1 -0
- package/dist/src/services/dreamingService.test.js +179 -0
- package/dist/src/services/dreamingService.test.js.map +1 -0
- package/dist/src/services/projectService.js +1068 -0
- package/dist/src/services/projectService.js.map +1 -0
- package/dist/src/services/projectService.test.js +217 -0
- package/dist/src/services/projectService.test.js.map +1 -0
- package/dist/src/services/watcherService.js +164 -0
- package/dist/src/services/watcherService.js.map +1 -0
- package/dist/src/services/watcherService.test.js +65 -0
- package/dist/src/services/watcherService.test.js.map +1 -0
- package/dist/src/types.js +2 -0
- package/dist/src/types.js.map +1 -0
- package/package.json +61 -0
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
import express from "express";
|
|
2
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
|
+
import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
|
|
4
|
+
import * as fs from "fs";
|
|
5
|
+
import * as path from "path";
|
|
6
|
+
import { getAuth } from "firebase-admin/auth";
|
|
7
|
+
import { getFirestore } from "firebase-admin/firestore";
|
|
8
|
+
import { checkAuth } from "../services/authService.js";
|
|
9
|
+
import { discoverProjectsAsync, loadAnalysisAsync, getStats, fileExists } from "../services/projectService.js";
|
|
10
|
+
import { authStorage } from "../context.js";
|
|
11
|
+
import { registerTools } from "./mcpServer.js";
|
|
12
|
+
import { CodeAnalyzer } from "../analyzer/parser.js";
|
|
13
|
+
// Setup Express app to serve as both MCP SSE and REST API
|
|
14
|
+
export const app = express();
|
|
15
|
+
app.use(express.json());
|
|
16
|
+
// Enable CORS for dashboard
|
|
17
|
+
app.use((req, res, next) => {
|
|
18
|
+
res.header('Access-Control-Allow-Origin', '*');
|
|
19
|
+
res.header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
|
|
20
|
+
res.header('Access-Control-Allow-Headers', 'Content-Type, x-api-key, Authorization');
|
|
21
|
+
if (req.method === 'OPTIONS')
|
|
22
|
+
return res.sendStatus(200);
|
|
23
|
+
next();
|
|
24
|
+
});
|
|
25
|
+
// Authentication middleware for ALL API routes
|
|
26
|
+
export const authMiddleware = async (req, res, next) => {
|
|
27
|
+
// 1. Support Firebase ID Token (Bearer Token) for Dashboard
|
|
28
|
+
const authHeader = req.headers["authorization"];
|
|
29
|
+
if (authHeader && authHeader.startsWith("Bearer ")) {
|
|
30
|
+
const token = authHeader.substring(7);
|
|
31
|
+
try {
|
|
32
|
+
const decodedToken = await getAuth().verifyIdToken(token);
|
|
33
|
+
let role = decodedToken.role || "user";
|
|
34
|
+
if (role !== "admin") {
|
|
35
|
+
try {
|
|
36
|
+
const userDoc = await getFirestore().collection("users").doc(decodedToken.uid).get();
|
|
37
|
+
if (userDoc.exists) {
|
|
38
|
+
role = userDoc.data()?.role || userDoc.data()?.tier || "user";
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
catch (e) {
|
|
42
|
+
console.error("Failed to fetch user role from Firestore:", e);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
const auth = {
|
|
46
|
+
tier: "enterprise",
|
|
47
|
+
uid: decodedToken.uid,
|
|
48
|
+
email: decodedToken.email,
|
|
49
|
+
role: role,
|
|
50
|
+
keyId: "firebase-session"
|
|
51
|
+
};
|
|
52
|
+
req.auth = auth;
|
|
53
|
+
// Gán auth context cho toàn bộ luồng bất đồng bộ bên dưới
|
|
54
|
+
authStorage.run(auth, () => {
|
|
55
|
+
next();
|
|
56
|
+
});
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
catch (err) {
|
|
60
|
+
res.status(401).json({ error: `Invalid Firebase ID Token: ${(err instanceof Error ? err.message : String(err))}` });
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
// 2. Support both header and query param for flexibility (Dashboard legacy vs MCP)
|
|
65
|
+
const clientKey = req.headers["x-api-key"] || req.query.apiKey;
|
|
66
|
+
try {
|
|
67
|
+
const auth = await checkAuth(clientKey);
|
|
68
|
+
req.auth = auth; // Attach auth result to request
|
|
69
|
+
// Gán auth context cho toàn bộ luồng bất đồng bộ bên dưới
|
|
70
|
+
authStorage.run(auth, () => {
|
|
71
|
+
next();
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
catch (err) {
|
|
75
|
+
res.status(401).json({ error: (err instanceof Error ? err.message : String(err)) });
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
// REST API: Get all discovered projects
|
|
79
|
+
app.get("/api/projects", authMiddleware, async (req, res) => {
|
|
80
|
+
try {
|
|
81
|
+
const auth = authStorage.getStore();
|
|
82
|
+
const tenantId = auth ? auth.uid : undefined;
|
|
83
|
+
const projects = await discoverProjectsAsync(tenantId);
|
|
84
|
+
res.json(projects.map(p => ({ name: p.name, dir: p.dir, modifiedAt: p.modifiedAt })));
|
|
85
|
+
}
|
|
86
|
+
catch (err) {
|
|
87
|
+
res.status(500).json({ error: (err instanceof Error ? err.message : String(err)) });
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
// REST API: Get analysis data
|
|
91
|
+
app.get("/api/analysis", authMiddleware, async (req, res) => {
|
|
92
|
+
try {
|
|
93
|
+
const projectDir = req.query.projectDir || req.query.project;
|
|
94
|
+
const loaded = await loadAnalysisAsync(projectDir);
|
|
95
|
+
if (!loaded)
|
|
96
|
+
return res.status(404).json({ error: "No analysis found" });
|
|
97
|
+
// Support legacy thin client format (which only expects the inner analysis object)
|
|
98
|
+
if (req.query.project && !req.query.projectDir) {
|
|
99
|
+
res.json(loaded.analysis);
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
res.json(loaded);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
catch (err) {
|
|
106
|
+
res.status(500).json({ error: (err instanceof Error ? err.message : String(err)) });
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
// REST API: Trigger re-index
|
|
110
|
+
app.post("/api/reindex", authMiddleware, async (req, res) => {
|
|
111
|
+
try {
|
|
112
|
+
const auth = authStorage.getStore();
|
|
113
|
+
const tenantId = auth ? auth.uid : undefined;
|
|
114
|
+
const bodyProjectDir = req.body.projectDir;
|
|
115
|
+
let projectPath = bodyProjectDir || process.env.CODEATLAS_PROJECT_DIR || process.cwd();
|
|
116
|
+
// In multi-tenant mode, strictly validate that they own/can access this project directory!
|
|
117
|
+
if (process.env.CODEATLAS_MULTI_TENANT === "true" && tenantId && tenantId !== "admin") {
|
|
118
|
+
const userProjects = await discoverProjectsAsync(tenantId);
|
|
119
|
+
const match = userProjects.find(p => p.dir === projectPath);
|
|
120
|
+
if (!match) {
|
|
121
|
+
return res.status(403).json({ error: "Access denied: You do not own or have access to this project directory" });
|
|
122
|
+
}
|
|
123
|
+
projectPath = match.dir;
|
|
124
|
+
}
|
|
125
|
+
console.error(`[API] Triggering re-index for: ${projectPath}`);
|
|
126
|
+
const analyzer = new CodeAnalyzer(projectPath, 5000);
|
|
127
|
+
const result = await analyzer.analyzeProject();
|
|
128
|
+
const codeatlasDir = path.join(projectPath, ".codeatlas");
|
|
129
|
+
if (!(await fileExists(codeatlasDir))) {
|
|
130
|
+
await fs.promises.mkdir(codeatlasDir, { recursive: true });
|
|
131
|
+
}
|
|
132
|
+
await fs.promises.writeFile(path.join(codeatlasDir, "analysis.json"), JSON.stringify(result, null, 2));
|
|
133
|
+
res.json({ success: true, stats: getStats(result) });
|
|
134
|
+
}
|
|
135
|
+
catch (err) {
|
|
136
|
+
console.error(`[API] Re-index failed: ${(err instanceof Error ? err.message : String(err))}`);
|
|
137
|
+
res.status(500).json({ error: (err instanceof Error ? err.message : String(err)) });
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
// Serve static files from built dashboard
|
|
141
|
+
const dashboardDistPath = path.join(process.cwd(), "dashboard", "dist");
|
|
142
|
+
if (fs.existsSync(dashboardDistPath)) {
|
|
143
|
+
app.use(express.static(dashboardDistPath));
|
|
144
|
+
// SPA support: redirect all non-API routes to index.html
|
|
145
|
+
app.get(/^\/(?!sse|messages|api).*/, (req, res) => {
|
|
146
|
+
res.sendFile(path.join(dashboardDistPath, "index.html"));
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
// Auth middleware for SSE endpoints
|
|
150
|
+
app.use("/sse", authMiddleware);
|
|
151
|
+
app.use("/messages", authMiddleware);
|
|
152
|
+
// Multi-session support for concurrent users/reconnections
|
|
153
|
+
const transports = new Map();
|
|
154
|
+
const sessionServers = new Map();
|
|
155
|
+
const sessionOwnership = new Map();
|
|
156
|
+
app.get("/sse", async (req, res) => {
|
|
157
|
+
console.error("[SSE] New connection request");
|
|
158
|
+
// Critical for Cloudflare/Nginx/Proxies to prevent buffering
|
|
159
|
+
res.setHeader('Content-Type', 'text/event-stream');
|
|
160
|
+
res.setHeader('Cache-Control', 'no-cache');
|
|
161
|
+
res.setHeader('Connection', 'keep-alive');
|
|
162
|
+
res.setHeader('X-Accel-Buffering', 'no');
|
|
163
|
+
const apiKey = req.query.apiKey || req.headers["x-api-key"] || "";
|
|
164
|
+
const messagesUrl = apiKey ? `/messages?apiKey=${encodeURIComponent(apiKey)}` : "/messages";
|
|
165
|
+
const transport = new SSEServerTransport(messagesUrl, res);
|
|
166
|
+
// Store transport by sessionId immediately to prevent race conditions during initialize
|
|
167
|
+
const sessionId = transport.sessionId;
|
|
168
|
+
if (sessionId) {
|
|
169
|
+
// If a session with this ID already exists, clean up its server and transport first to avoid conflicts
|
|
170
|
+
if (transports.has(sessionId)) {
|
|
171
|
+
console.error(`[SSE] Session ${sessionId} already exists. Cleaning up the old connection before establishing new one.`);
|
|
172
|
+
const oldTransport = transports.get(sessionId);
|
|
173
|
+
const oldServer = sessionServers.get(sessionId);
|
|
174
|
+
transports.delete(sessionId);
|
|
175
|
+
sessionServers.delete(sessionId);
|
|
176
|
+
sessionOwnership.delete(sessionId);
|
|
177
|
+
if (oldServer) {
|
|
178
|
+
try {
|
|
179
|
+
await oldServer.close();
|
|
180
|
+
}
|
|
181
|
+
catch (err) {
|
|
182
|
+
// Ignore
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
if (oldTransport) {
|
|
186
|
+
try {
|
|
187
|
+
await oldTransport.close();
|
|
188
|
+
}
|
|
189
|
+
catch (err) {
|
|
190
|
+
// Ignore
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
// Dynamically create a session-specific server to isolate state and support concurrent clients
|
|
195
|
+
const sessionServer = new McpServer({
|
|
196
|
+
name: "CodeAtlas",
|
|
197
|
+
version: "2.9.4",
|
|
198
|
+
}, {
|
|
199
|
+
capabilities: {
|
|
200
|
+
resources: {},
|
|
201
|
+
tools: {},
|
|
202
|
+
logging: {},
|
|
203
|
+
},
|
|
204
|
+
});
|
|
205
|
+
registerTools(sessionServer);
|
|
206
|
+
transports.set(sessionId, transport);
|
|
207
|
+
sessionServers.set(sessionId, sessionServer);
|
|
208
|
+
const auth = req.auth;
|
|
209
|
+
if (auth && auth.uid) {
|
|
210
|
+
sessionOwnership.set(sessionId, auth.uid);
|
|
211
|
+
}
|
|
212
|
+
console.error(`[SSE] Session established: ${sessionId}`);
|
|
213
|
+
// Send a heartbeat ping every 15 seconds to prevent proxy/load balancer timeouts
|
|
214
|
+
const heartbeatInterval = setInterval(() => {
|
|
215
|
+
if (!res.writableEnded) {
|
|
216
|
+
res.write(":\n\n"); // SSE comment - keeps the HTTP connection active
|
|
217
|
+
}
|
|
218
|
+
}, 15000);
|
|
219
|
+
// Cleanup on connection close with a 3-minute grace period
|
|
220
|
+
res.on("close", async () => {
|
|
221
|
+
clearInterval(heartbeatInterval);
|
|
222
|
+
console.error(`[SSE] Session connection closed: ${sessionId}. Keeping session alive for 3-minute grace period.`);
|
|
223
|
+
// Keep the session in the map for a 3-minute grace period to prevent immediate 404 errors
|
|
224
|
+
setTimeout(async () => {
|
|
225
|
+
if (transports.has(sessionId)) {
|
|
226
|
+
console.error(`[SSE] Grace period expired. Cleaning up session: ${sessionId}`);
|
|
227
|
+
transports.delete(sessionId);
|
|
228
|
+
const oldServer = sessionServers.get(sessionId);
|
|
229
|
+
sessionServers.delete(sessionId);
|
|
230
|
+
sessionOwnership.delete(sessionId);
|
|
231
|
+
if (oldServer) {
|
|
232
|
+
try {
|
|
233
|
+
await oldServer.close();
|
|
234
|
+
}
|
|
235
|
+
catch (err) {
|
|
236
|
+
// Ignore
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
try {
|
|
240
|
+
await transport.close();
|
|
241
|
+
}
|
|
242
|
+
catch (err) {
|
|
243
|
+
// Ignore
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}, 180000); // 3 minutes
|
|
247
|
+
});
|
|
248
|
+
await sessionServer.connect(transport);
|
|
249
|
+
}
|
|
250
|
+
else {
|
|
251
|
+
console.error("[SSE] Critical: failed to retrieve sessionId from transport.");
|
|
252
|
+
res.status(500).send("Failed to initialize session");
|
|
253
|
+
}
|
|
254
|
+
});
|
|
255
|
+
app.post("/messages", async (req, res) => {
|
|
256
|
+
let sessionId = req.query.sessionId;
|
|
257
|
+
let transport = sessionId ? transports.get(sessionId) : undefined;
|
|
258
|
+
if (transport) {
|
|
259
|
+
const auth = req.auth;
|
|
260
|
+
const ownerUid = sessionOwnership.get(sessionId);
|
|
261
|
+
if (ownerUid && ownerUid !== auth?.uid) {
|
|
262
|
+
console.error(`[SSE] Security: session ownership mismatch. Session ${sessionId} belongs to ${ownerUid}, but request is from ${auth?.uid || 'unauthenticated'}`);
|
|
263
|
+
res.status(403).send("Forbidden: session ownership mismatch");
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
await transport.handlePostMessage(req, res, req.body);
|
|
267
|
+
}
|
|
268
|
+
else {
|
|
269
|
+
console.error(`[SSE] Critical: session not found. Requested: "${sessionId || ''}". No active transports available.`);
|
|
270
|
+
res.status(404).send("Session not found");
|
|
271
|
+
}
|
|
272
|
+
});
|
|
273
|
+
// Secure endpoint to serve markdown documentation
|
|
274
|
+
app.get("/api/docs/quick-setup", (req, res) => {
|
|
275
|
+
try {
|
|
276
|
+
const docPath = path.join(process.cwd(), "docs", "QUICK_SETUP.md");
|
|
277
|
+
if (!fs.existsSync(docPath)) {
|
|
278
|
+
return res.status(404).send("Documentation guide not found.");
|
|
279
|
+
}
|
|
280
|
+
res.setHeader("Content-Type", "text/plain; charset=utf-8");
|
|
281
|
+
res.sendFile(docPath);
|
|
282
|
+
}
|
|
283
|
+
catch (e) {
|
|
284
|
+
res.status(500).send((e instanceof Error ? e.message : String(e)));
|
|
285
|
+
}
|
|
286
|
+
});
|
|
287
|
+
/**
|
|
288
|
+
* Start the HTTP/SSE Express server on a specified port
|
|
289
|
+
*/
|
|
290
|
+
export function startHttpServer(port) {
|
|
291
|
+
return new Promise((resolve) => {
|
|
292
|
+
app.listen(port, () => {
|
|
293
|
+
console.error(`CodeAtlas MCP SSE server running on port ${port}`);
|
|
294
|
+
console.error(`- SSE endpoint: http://localhost:${port}/sse`);
|
|
295
|
+
console.error(`- Message endpoint: http://localhost:${port}/messages`);
|
|
296
|
+
if (process.env.CODEATLAS_API_KEY) {
|
|
297
|
+
console.error(`- Security: API Key enabled`);
|
|
298
|
+
}
|
|
299
|
+
else {
|
|
300
|
+
console.error(`- Security: DISABLED (Set CODEATLAS_API_KEY to enable)`);
|
|
301
|
+
}
|
|
302
|
+
resolve();
|
|
303
|
+
});
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
//# sourceMappingURL=httpServer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"httpServer.js","sourceRoot":"","sources":["../../../src/presentation/httpServer.ts"],"names":[],"mappings":"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"}
|