@mcpjam/inspector 0.3.9 ā 0.8.0
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/.next/BUILD_ID +1 -0
- package/.next/app-build-manifest.json +89 -0
- package/.next/app-path-routes-manifest.json +13 -0
- package/.next/build-manifest.json +33 -0
- package/.next/cache/.previewinfo +1 -0
- package/.next/cache/.rscinfo +1 -0
- package/.next/cache/.tsbuildinfo +1 -0
- package/.next/cache/eslint/.cache_11b5ofe +1 -0
- package/.next/cache/webpack/client-production/0.pack +0 -0
- package/.next/cache/webpack/client-production/index.pack +0 -0
- package/.next/cache/webpack/edge-server-production/0.pack +0 -0
- package/.next/cache/webpack/edge-server-production/index.pack +0 -0
- package/.next/cache/webpack/server-production/0.pack +0 -0
- package/.next/cache/webpack/server-production/index.pack +0 -0
- package/.next/diagnostics/build-diagnostics.json +6 -0
- package/.next/diagnostics/framework.json +1 -0
- package/.next/export-marker.json +6 -0
- package/.next/images-manifest.json +57 -0
- package/.next/next-minimal-server.js.nft.json +1 -0
- package/.next/next-server.js.nft.json +1 -0
- package/.next/package.json +1 -0
- package/.next/prerender-manifest.json +41 -0
- package/.next/react-loadable-manifest.json +1 -0
- package/.next/required-server-files.json +318 -0
- package/.next/routes-manifest.json +65 -0
- package/.next/server/app/_not-found/page.js +2 -0
- package/.next/server/app/_not-found/page.js.nft.json +1 -0
- package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -0
- package/.next/server/app/api/mcp/chat/route.js +45 -0
- package/.next/server/app/api/mcp/chat/route.js.nft.json +1 -0
- package/.next/server/app/api/mcp/chat/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/mcp/connect/route.js +1 -0
- package/.next/server/app/api/mcp/connect/route.js.nft.json +1 -0
- package/.next/server/app/api/mcp/connect/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/mcp/prompts/get/route.js +1 -0
- package/.next/server/app/api/mcp/prompts/get/route.js.nft.json +1 -0
- package/.next/server/app/api/mcp/prompts/get/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/mcp/prompts/list/route.js +1 -0
- package/.next/server/app/api/mcp/prompts/list/route.js.nft.json +1 -0
- package/.next/server/app/api/mcp/prompts/list/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/mcp/resources/list/route.js +1 -0
- package/.next/server/app/api/mcp/resources/list/route.js.nft.json +1 -0
- package/.next/server/app/api/mcp/resources/list/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/mcp/resources/read/route.js +1 -0
- package/.next/server/app/api/mcp/resources/read/route.js.nft.json +1 -0
- package/.next/server/app/api/mcp/resources/read/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/mcp/tools/route.js +21 -0
- package/.next/server/app/api/mcp/tools/route.js.nft.json +1 -0
- package/.next/server/app/api/mcp/tools/route_client-reference-manifest.js +1 -0
- package/.next/server/app/favicon.ico/route.js +1 -0
- package/.next/server/app/favicon.ico/route.js.nft.json +1 -0
- package/.next/server/app/favicon.ico.body +0 -0
- package/.next/server/app/favicon.ico.meta +1 -0
- package/.next/server/app/oauth/callback/page.js +2 -0
- package/.next/server/app/oauth/callback/page.js.nft.json +1 -0
- package/.next/server/app/oauth/callback/page_client-reference-manifest.js +1 -0
- package/.next/server/app/page.js +16 -0
- package/.next/server/app/page.js.nft.json +1 -0
- package/.next/server/app/page_client-reference-manifest.js +1 -0
- package/.next/server/app-paths-manifest.json +13 -0
- package/.next/server/chunks/175.js +8 -0
- package/.next/server/chunks/260.js +82 -0
- package/.next/server/chunks/546.js +1 -0
- package/.next/server/chunks/548.js +6 -0
- package/.next/server/chunks/55.js +1 -0
- package/.next/server/chunks/985.js +22 -0
- package/.next/server/functions-config-manifest.json +4 -0
- package/.next/server/interception-route-rewrite-manifest.js +1 -0
- package/.next/server/middleware-build-manifest.js +1 -0
- package/.next/server/middleware-manifest.json +6 -0
- package/.next/server/middleware-react-loadable-manifest.js +1 -0
- package/.next/server/next-font-manifest.js +1 -0
- package/.next/server/next-font-manifest.json +1 -0
- package/.next/server/pages/500.html +1 -0
- package/.next/server/pages/_app.js +1 -0
- package/.next/server/pages/_app.js.nft.json +1 -0
- package/.next/server/pages/_document.js +1 -0
- package/.next/server/pages/_document.js.nft.json +1 -0
- package/.next/server/pages/_error.js +19 -0
- package/.next/server/pages/_error.js.nft.json +1 -0
- package/.next/server/pages-manifest.json +5 -0
- package/.next/server/server-reference-manifest.js +1 -0
- package/.next/server/server-reference-manifest.json +1 -0
- package/.next/server/webpack-runtime.js +1 -0
- package/.next/static/chunks/14-ae3a01e72ea53777.js +1 -0
- package/.next/static/chunks/214-cc4c35d88f2695ed.js +1 -0
- package/.next/static/chunks/4bd1b696-cf72ae8a39fa05aa.js +1 -0
- package/.next/static/chunks/866-04c19dda4c52f2bf.js +1 -0
- package/.next/static/chunks/964-eda38e26c0391a47.js +1 -0
- package/.next/static/chunks/app/_not-found/page-d7e832b54474da82.js +1 -0
- package/.next/static/chunks/app/api/mcp/chat/route-0341498a8bf5f2da.js +1 -0
- package/.next/static/chunks/app/api/mcp/connect/route-0341498a8bf5f2da.js +1 -0
- package/.next/static/chunks/app/api/mcp/prompts/get/route-0341498a8bf5f2da.js +1 -0
- package/.next/static/chunks/app/api/mcp/prompts/list/route-0341498a8bf5f2da.js +1 -0
- package/.next/static/chunks/app/api/mcp/resources/list/route-0341498a8bf5f2da.js +1 -0
- package/.next/static/chunks/app/api/mcp/resources/read/route-0341498a8bf5f2da.js +1 -0
- package/.next/static/chunks/app/api/mcp/tools/route-0341498a8bf5f2da.js +1 -0
- package/.next/static/chunks/app/layout-fb6e1ad5933381f3.js +1 -0
- package/.next/static/chunks/app/oauth/callback/page-d8b3908ea67ba3e3.js +1 -0
- package/.next/static/chunks/app/page-81e35b2a61edb363.js +1 -0
- package/.next/static/chunks/framework-7c95b8e5103c9e90.js +1 -0
- package/.next/static/chunks/main-app-7d61da15faa6c1af.js +1 -0
- package/.next/static/chunks/main-bbdafee21a7bd1d6.js +1 -0
- package/.next/static/chunks/pages/_app-0a0020ddd67f79cf.js +1 -0
- package/.next/static/chunks/pages/_error-03529f2c21436739.js +1 -0
- package/.next/static/chunks/polyfills-42372ed130431b0a.js +1 -0
- package/.next/static/chunks/webpack-cdfccaf38062dd25.js +1 -0
- package/.next/static/css/1e852d83e9c1d0c6.css +1 -0
- package/.next/static/css/f30152c0704fba31.css +1 -0
- package/.next/static/css/fe751fdbe975e9ca.css +1 -0
- package/.next/static/media/569ce4b8f30dc480-s.p.woff2 +0 -0
- package/.next/static/media/747892c23ea88013-s.woff2 +0 -0
- package/.next/static/media/8d697b304b401681-s.woff2 +0 -0
- package/.next/static/media/93f479601ee12b01-s.p.woff2 +0 -0
- package/.next/static/media/9610d9e46709d722-s.woff2 +0 -0
- package/.next/static/media/ba015fad6dcf6784-s.woff2 +0 -0
- package/.next/static/media/ollama_dark.9af45ac0.png +0 -0
- package/.next/static/media/ollama_logo.9f08a95b.svg +7 -0
- package/.next/static/media/openai_logo.3f83154a.png +0 -0
- package/.next/static/wgHmsxKAquUu9gOMW6Qd5/_buildManifest.js +1 -0
- package/.next/static/wgHmsxKAquUu9gOMW6Qd5/_ssgManifest.js +1 -0
- package/.next/trace +35 -0
- package/.next/types/app/api/mcp/chat/route.ts +347 -0
- package/.next/types/app/api/mcp/connect/route.ts +347 -0
- package/.next/types/app/api/mcp/prompts/get/route.ts +347 -0
- package/.next/types/app/api/mcp/prompts/list/route.ts +347 -0
- package/.next/types/app/api/mcp/resources/list/route.ts +347 -0
- package/.next/types/app/api/mcp/resources/read/route.ts +347 -0
- package/.next/types/app/api/mcp/tools/route.ts +347 -0
- package/.next/types/app/layout.ts +84 -0
- package/.next/types/app/oauth/callback/page.ts +84 -0
- package/.next/types/app/page.ts +84 -0
- package/.next/types/cache-life.d.ts +141 -0
- package/.next/types/package.json +1 -0
- package/README.md +76 -161
- package/bin/start.js +504 -0
- package/next.config.ts +7 -0
- package/package.json +71 -54
- package/public/claude_logo.png +0 -0
- package/public/demo_1.png +0 -0
- package/public/demo_2.png +0 -0
- package/public/demo_3.png +0 -0
- package/public/file.svg +1 -0
- package/public/globe.svg +1 -0
- package/public/mcp.svg +1 -0
- package/public/next.svg +1 -0
- package/public/ollama_dark.png +0 -0
- package/public/ollama_logo.svg +7 -0
- package/public/openai_logo.png +0 -0
- package/public/vercel.svg +1 -0
- package/public/window.svg +1 -0
- package/LICENSE +0 -200
- package/cli/build/cli.js +0 -251
- package/cli/build/client/connection.js +0 -33
- package/cli/build/client/index.js +0 -6
- package/cli/build/client/prompts.js +0 -23
- package/cli/build/client/resources.js +0 -30
- package/cli/build/client/tools.js +0 -64
- package/cli/build/client/types.js +0 -1
- package/cli/build/error-handler.js +0 -18
- package/cli/build/index.js +0 -166
- package/cli/build/transport.js +0 -47
- package/client/bin/client.js +0 -71
- package/client/bin/start.js +0 -143
- package/client/dist/assets/OAuthCallback-BSOXmPlE.js +0 -56
- package/client/dist/assets/OAuthDebugCallback-DyzqkofK.js +0 -44
- package/client/dist/assets/index-BT03cD-1.js +0 -63301
- package/client/dist/assets/index-Bwd_BFIj.css +0 -4164
- package/client/dist/index.html +0 -14
- package/client/dist/ollama_logo.png +0 -0
- package/client/dist/openai_logo.png +0 -0
- package/server/build/database/DatabaseManager.js +0 -108
- package/server/build/database/index.js +0 -8
- package/server/build/database/routes.js +0 -86
- package/server/build/database/types.js +0 -27
- package/server/build/database/utils.js +0 -86
- package/server/build/index.js +0 -331
- package/server/build/mcpProxy.js +0 -54
- package/server/build/shared/MCPProxyService.js +0 -221
- package/server/build/shared/TransportFactory.js +0 -130
- package/server/build/shared/index.js +0 -4
- package/server/build/shared/types.js +0 -1
- package/server/build/shared/utils.js +0 -27
- package/server/build/test-server.js +0 -145
- package/server/build/testing/HealthCheck.js +0 -42
- package/server/build/testing/TestExecutor.js +0 -240
- package/server/build/testing/TestRunner.js +0 -198
- package/server/build/testing/TestServer.js +0 -440
- package/server/build/testing/types.js +0 -1
- /package/{client/dist/claude_logo.png ā .next/static/media/claude_logo.d33b25b0.png} +0 -0
- /package/{client/dist ā public}/mcp_jam.svg +0 -0
- /package/{client/dist ā public}/mcp_jam_dark.png +0 -0
- /package/{client/dist ā public}/mcp_jam_light.png +0 -0
package/client/dist/index.html
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
<!doctype html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8" />
|
|
5
|
-
<link rel="icon" type="image/svg+xml" href="/mcp_jam.svg" />
|
|
6
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
|
-
<title>MCPJam Inspector</title>
|
|
8
|
-
<script type="module" crossorigin src="/assets/index-BT03cD-1.js"></script>
|
|
9
|
-
<link rel="stylesheet" crossorigin href="/assets/index-Bwd_BFIj.css">
|
|
10
|
-
</head>
|
|
11
|
-
<body>
|
|
12
|
-
<div id="root" class="w-full"></div>
|
|
13
|
-
</body>
|
|
14
|
-
</html>
|
|
Binary file
|
|
Binary file
|
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* DatabaseManager - Basic libSQL database manager for MCPJam Inspector
|
|
3
|
-
* Simple local SQLite database foundation
|
|
4
|
-
*/
|
|
5
|
-
import { createClient } from "@libsql/client";
|
|
6
|
-
import { readFileSync } from "fs";
|
|
7
|
-
import { join, dirname } from "path";
|
|
8
|
-
import { fileURLToPath } from "url";
|
|
9
|
-
import { ensureDirectoryExists, ensureMCPJamDirectory, getResolvedDatabasePath, } from "./utils.js";
|
|
10
|
-
import { DatabaseError, QueryError, } from "./types.js";
|
|
11
|
-
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
12
|
-
export class DatabaseManager {
|
|
13
|
-
client;
|
|
14
|
-
initialized = false;
|
|
15
|
-
config;
|
|
16
|
-
constructor(config) {
|
|
17
|
-
this.config = config || { localPath: getResolvedDatabasePath() };
|
|
18
|
-
this.client = this.createClient();
|
|
19
|
-
}
|
|
20
|
-
createClient() {
|
|
21
|
-
// Use the configured database path
|
|
22
|
-
const dbPath = this.config.localPath;
|
|
23
|
-
return createClient({
|
|
24
|
-
url: `file:${dbPath}`,
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
async initialize() {
|
|
28
|
-
if (this.initialized)
|
|
29
|
-
return;
|
|
30
|
-
try {
|
|
31
|
-
console.log("š Initializing database...");
|
|
32
|
-
// Ensure .mcpjam directory exists and database directory
|
|
33
|
-
await ensureMCPJamDirectory();
|
|
34
|
-
const dbPath = getResolvedDatabasePath();
|
|
35
|
-
await ensureDirectoryExists(dbPath);
|
|
36
|
-
// Read and execute schema
|
|
37
|
-
const schemaPath = join(__dirname, "schema.sql");
|
|
38
|
-
const schema = readFileSync(schemaPath, "utf-8");
|
|
39
|
-
await this.client.executeMultiple(schema);
|
|
40
|
-
this.initialized = true;
|
|
41
|
-
console.log("ā
Database initialized successfully");
|
|
42
|
-
}
|
|
43
|
-
catch (error) {
|
|
44
|
-
throw new DatabaseError("Failed to initialize database", "INIT_ERROR", error);
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
// ============================================================================
|
|
48
|
-
// APP METADATA OPERATIONS
|
|
49
|
-
// ============================================================================
|
|
50
|
-
async getMetadata(key) {
|
|
51
|
-
try {
|
|
52
|
-
const result = await this.client.execute({
|
|
53
|
-
sql: "SELECT value FROM app_metadata WHERE key = ?",
|
|
54
|
-
args: [key],
|
|
55
|
-
});
|
|
56
|
-
if (result.rows.length === 0)
|
|
57
|
-
return null;
|
|
58
|
-
return result.rows[0].value;
|
|
59
|
-
}
|
|
60
|
-
catch (error) {
|
|
61
|
-
throw new QueryError("Failed to get metadata", undefined, error);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
async setMetadata(key, value) {
|
|
65
|
-
try {
|
|
66
|
-
await this.client.execute({
|
|
67
|
-
sql: "INSERT OR REPLACE INTO app_metadata (key, value) VALUES (?, ?)",
|
|
68
|
-
args: [key, value],
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
catch (error) {
|
|
72
|
-
throw new QueryError("Failed to set metadata", undefined, error);
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
async getAllMetadata() {
|
|
76
|
-
try {
|
|
77
|
-
const result = await this.client.execute({
|
|
78
|
-
sql: "SELECT * FROM app_metadata ORDER BY key",
|
|
79
|
-
args: [],
|
|
80
|
-
});
|
|
81
|
-
return result.rows.map((row) => ({
|
|
82
|
-
key: row.key,
|
|
83
|
-
value: row.value,
|
|
84
|
-
createdAt: new Date(row.created_at),
|
|
85
|
-
updatedAt: new Date(row.updated_at),
|
|
86
|
-
}));
|
|
87
|
-
}
|
|
88
|
-
catch (error) {
|
|
89
|
-
throw new QueryError("Failed to get all metadata", undefined, error);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
async deleteMetadata(key) {
|
|
93
|
-
try {
|
|
94
|
-
await this.client.execute({
|
|
95
|
-
sql: "DELETE FROM app_metadata WHERE key = ?",
|
|
96
|
-
args: [key],
|
|
97
|
-
});
|
|
98
|
-
}
|
|
99
|
-
catch (error) {
|
|
100
|
-
throw new QueryError("Failed to delete metadata", undefined, error);
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
async close() {
|
|
104
|
-
if (this.client) {
|
|
105
|
-
this.client.close();
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Database module exports for MCPJam Inspector
|
|
3
|
-
* Provides comprehensive libSQL database functionality
|
|
4
|
-
*/
|
|
5
|
-
export { DatabaseManager } from "./DatabaseManager.js";
|
|
6
|
-
export { createDatabaseRoutes } from "./routes.js";
|
|
7
|
-
export * from "./types.js";
|
|
8
|
-
export * from "./utils.js";
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Database API routes for MCPJam Inspector
|
|
3
|
-
* Basic endpoints for app metadata operations
|
|
4
|
-
*/
|
|
5
|
-
import { Router } from "express";
|
|
6
|
-
export function createDatabaseRoutes(databaseManager) {
|
|
7
|
-
const router = Router();
|
|
8
|
-
// Error handler wrapper
|
|
9
|
-
const asyncHandler = (fn) => (req, res, next) => {
|
|
10
|
-
Promise.resolve(fn(req, res, next)).catch(next);
|
|
11
|
-
};
|
|
12
|
-
// ============================================================================
|
|
13
|
-
// APP METADATA OPERATIONS
|
|
14
|
-
// ============================================================================
|
|
15
|
-
// Get all metadata
|
|
16
|
-
router.get("/metadata", asyncHandler(async (req, res) => {
|
|
17
|
-
const metadata = await databaseManager.getAllMetadata();
|
|
18
|
-
res.json({
|
|
19
|
-
success: true,
|
|
20
|
-
data: metadata,
|
|
21
|
-
count: metadata.length,
|
|
22
|
-
});
|
|
23
|
-
}));
|
|
24
|
-
// Get single metadata value
|
|
25
|
-
router.get("/metadata/:key", asyncHandler(async (req, res) => {
|
|
26
|
-
const value = await databaseManager.getMetadata(req.params.key);
|
|
27
|
-
if (value === null) {
|
|
28
|
-
res.status(404).json({
|
|
29
|
-
success: false,
|
|
30
|
-
error: "Metadata key not found",
|
|
31
|
-
});
|
|
32
|
-
return;
|
|
33
|
-
}
|
|
34
|
-
res.json({
|
|
35
|
-
success: true,
|
|
36
|
-
data: { key: req.params.key, value },
|
|
37
|
-
});
|
|
38
|
-
}));
|
|
39
|
-
// Set metadata value
|
|
40
|
-
router.post("/metadata/:key", asyncHandler(async (req, res) => {
|
|
41
|
-
const { value } = req.body;
|
|
42
|
-
if (value === undefined) {
|
|
43
|
-
res.status(400).json({
|
|
44
|
-
success: false,
|
|
45
|
-
error: "Missing required field: value",
|
|
46
|
-
});
|
|
47
|
-
return;
|
|
48
|
-
}
|
|
49
|
-
await databaseManager.setMetadata(req.params.key, value);
|
|
50
|
-
res.json({
|
|
51
|
-
success: true,
|
|
52
|
-
message: "Metadata stored successfully",
|
|
53
|
-
});
|
|
54
|
-
}));
|
|
55
|
-
// Delete metadata key
|
|
56
|
-
router.delete("/metadata/:key", asyncHandler(async (req, res) => {
|
|
57
|
-
await databaseManager.deleteMetadata(req.params.key);
|
|
58
|
-
res.json({
|
|
59
|
-
success: true,
|
|
60
|
-
message: "Metadata deleted successfully",
|
|
61
|
-
});
|
|
62
|
-
}));
|
|
63
|
-
// ============================================================================
|
|
64
|
-
// HEALTH CHECK
|
|
65
|
-
// ============================================================================
|
|
66
|
-
router.get("/health", asyncHandler(async (req, res) => {
|
|
67
|
-
res.json({
|
|
68
|
-
success: true,
|
|
69
|
-
message: "Database API is healthy",
|
|
70
|
-
timestamp: new Date().toISOString(),
|
|
71
|
-
});
|
|
72
|
-
}));
|
|
73
|
-
// Error handling middleware
|
|
74
|
-
router.use((error, req, res, next) => {
|
|
75
|
-
console.error("Database API Error:", error);
|
|
76
|
-
const statusCode = error.status || 500;
|
|
77
|
-
const message = error.message || "Internal server error";
|
|
78
|
-
res.status(statusCode).json({
|
|
79
|
-
success: false,
|
|
80
|
-
error: message,
|
|
81
|
-
code: error.code,
|
|
82
|
-
...(process.env.NODE_ENV === "development" && { stack: error.stack }),
|
|
83
|
-
});
|
|
84
|
-
});
|
|
85
|
-
return router;
|
|
86
|
-
}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Database types and interfaces for MCPJam Inspector
|
|
3
|
-
* Basic foundation types for local SQLite database
|
|
4
|
-
*/
|
|
5
|
-
// ============================================================================
|
|
6
|
-
// ERROR TYPES
|
|
7
|
-
// ============================================================================
|
|
8
|
-
export class DatabaseError extends Error {
|
|
9
|
-
code;
|
|
10
|
-
cause;
|
|
11
|
-
constructor(message, code, cause) {
|
|
12
|
-
super(message);
|
|
13
|
-
this.code = code;
|
|
14
|
-
this.cause = cause;
|
|
15
|
-
this.name = "DatabaseError";
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
export class QueryError extends Error {
|
|
19
|
-
query;
|
|
20
|
-
cause;
|
|
21
|
-
constructor(message, query, cause) {
|
|
22
|
-
super(message);
|
|
23
|
-
this.query = query;
|
|
24
|
-
this.cause = cause;
|
|
25
|
-
this.name = "QueryError";
|
|
26
|
-
}
|
|
27
|
-
}
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Database utilities for MCPJam Inspector
|
|
3
|
-
* Basic utilities for local SQLite database setup
|
|
4
|
-
*/
|
|
5
|
-
import { mkdir, access } from "fs/promises";
|
|
6
|
-
import { dirname } from "path";
|
|
7
|
-
import { homedir } from "os";
|
|
8
|
-
import { join } from "path";
|
|
9
|
-
/**
|
|
10
|
-
* Ensures the .mcpjam directory exists in the user's home directory
|
|
11
|
-
*/
|
|
12
|
-
export async function ensureMCPJamDirectory() {
|
|
13
|
-
const mcpjamDir = join(homedir(), ".mcpjam");
|
|
14
|
-
try {
|
|
15
|
-
await access(mcpjamDir);
|
|
16
|
-
}
|
|
17
|
-
catch {
|
|
18
|
-
// Directory doesn't exist, create it
|
|
19
|
-
await mkdir(mcpjamDir, { recursive: true });
|
|
20
|
-
console.log(`š Created MCPJam directory: ${mcpjamDir}`);
|
|
21
|
-
}
|
|
22
|
-
return mcpjamDir;
|
|
23
|
-
}
|
|
24
|
-
/**
|
|
25
|
-
* Ensures the directory for a given file path exists
|
|
26
|
-
*/
|
|
27
|
-
export async function ensureDirectoryExists(filePath) {
|
|
28
|
-
const dir = dirname(filePath);
|
|
29
|
-
try {
|
|
30
|
-
await access(dir);
|
|
31
|
-
}
|
|
32
|
-
catch {
|
|
33
|
-
await mkdir(dir, { recursive: true });
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
/**
|
|
37
|
-
* Gets the resolved database path - THE SINGLE SOURCE OF TRUTH
|
|
38
|
-
* Priority: MCPJAM_DB_PATH env var > default ~/.mcpjam/data.db
|
|
39
|
-
*/
|
|
40
|
-
export function getResolvedDatabasePath() {
|
|
41
|
-
return process.env.MCPJAM_DB_PATH || join(homedir(), ".mcpjam", "data.db");
|
|
42
|
-
}
|
|
43
|
-
/**
|
|
44
|
-
* Environment configuration helper
|
|
45
|
-
*/
|
|
46
|
-
export function getDatabaseConfig() {
|
|
47
|
-
return {
|
|
48
|
-
localPath: getResolvedDatabasePath(),
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* Checks if the database file exists
|
|
53
|
-
*/
|
|
54
|
-
export async function databaseExists(databasePath) {
|
|
55
|
-
try {
|
|
56
|
-
await access(databasePath);
|
|
57
|
-
return true;
|
|
58
|
-
}
|
|
59
|
-
catch {
|
|
60
|
-
return false;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
/**
|
|
64
|
-
* Database connection test
|
|
65
|
-
*/
|
|
66
|
-
export async function testDatabaseConnection(config) {
|
|
67
|
-
try {
|
|
68
|
-
const { createClient } = await import("@libsql/client");
|
|
69
|
-
// Use the single source of truth for database path
|
|
70
|
-
const dbPath = config?.localPath || getResolvedDatabasePath();
|
|
71
|
-
await ensureDirectoryExists(dbPath);
|
|
72
|
-
const client = createClient({
|
|
73
|
-
url: `file:${dbPath}`,
|
|
74
|
-
});
|
|
75
|
-
// Test the connection with a simple query
|
|
76
|
-
await client.execute("SELECT 1");
|
|
77
|
-
client.close();
|
|
78
|
-
return { success: true };
|
|
79
|
-
}
|
|
80
|
-
catch (error) {
|
|
81
|
-
return {
|
|
82
|
-
success: false,
|
|
83
|
-
error: error instanceof Error ? error.message : "Unknown error",
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
}
|
package/server/build/index.js
DELETED
|
@@ -1,331 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import cors from "cors";
|
|
3
|
-
import { parseArgs } from "node:util";
|
|
4
|
-
import { parse as shellParseArgs } from "shell-quote";
|
|
5
|
-
import { createServer } from "node:net";
|
|
6
|
-
import { SseError } from "@modelcontextprotocol/sdk/client/sse.js";
|
|
7
|
-
import { getDefaultEnvironment } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
8
|
-
import express from "express";
|
|
9
|
-
import { randomUUID } from "node:crypto";
|
|
10
|
-
import { DatabaseManager } from "./database/DatabaseManager.js";
|
|
11
|
-
import { createDatabaseRoutes } from "./database/routes.js";
|
|
12
|
-
import { getDatabaseConfig } from "./database/utils.js";
|
|
13
|
-
import { MCPProxyService, ConsoleLogger } from "./shared/index.js";
|
|
14
|
-
const SSE_HEADERS_PASSTHROUGH = ["authorization"];
|
|
15
|
-
const STREAMABLE_HTTP_HEADERS_PASSTHROUGH = [
|
|
16
|
-
"authorization",
|
|
17
|
-
"mcp-session-id",
|
|
18
|
-
"last-event-id",
|
|
19
|
-
];
|
|
20
|
-
const defaultEnvironment = {
|
|
21
|
-
...getDefaultEnvironment(),
|
|
22
|
-
...(process.env.MCP_ENV_VARS ? JSON.parse(process.env.MCP_ENV_VARS) : {}),
|
|
23
|
-
};
|
|
24
|
-
const serverConfigs = process.env.MCP_SERVER_CONFIGS
|
|
25
|
-
? JSON.parse(process.env.MCP_SERVER_CONFIGS)
|
|
26
|
-
: null;
|
|
27
|
-
const { values } = parseArgs({
|
|
28
|
-
args: process.argv.slice(2),
|
|
29
|
-
options: {
|
|
30
|
-
env: { type: "string", default: "" },
|
|
31
|
-
args: { type: "string", default: "" },
|
|
32
|
-
},
|
|
33
|
-
});
|
|
34
|
-
const app = express();
|
|
35
|
-
app.use(cors());
|
|
36
|
-
app.use((req, res, next) => {
|
|
37
|
-
res.header("Access-Control-Expose-Headers", "mcp-session-id");
|
|
38
|
-
next();
|
|
39
|
-
});
|
|
40
|
-
// Initialize database
|
|
41
|
-
let databaseManager = null;
|
|
42
|
-
const initializeDatabase = async () => {
|
|
43
|
-
try {
|
|
44
|
-
const dbConfig = getDatabaseConfig();
|
|
45
|
-
databaseManager = new DatabaseManager(dbConfig);
|
|
46
|
-
await databaseManager.initialize();
|
|
47
|
-
// Add database routes after successful initialization
|
|
48
|
-
app.use("/api/db", express.json({ limit: "10mb" }), // JSON middleware only for database routes
|
|
49
|
-
(req, res, next) => {
|
|
50
|
-
if (!databaseManager) {
|
|
51
|
-
res.status(503).json({
|
|
52
|
-
success: false,
|
|
53
|
-
error: "Database not available",
|
|
54
|
-
});
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
next();
|
|
58
|
-
}, createDatabaseRoutes(databaseManager));
|
|
59
|
-
console.log("ā
Database API routes registered");
|
|
60
|
-
}
|
|
61
|
-
catch (error) {
|
|
62
|
-
console.error("ā Failed to initialize database:", error);
|
|
63
|
-
// Don't exit the process - continue without database functionality
|
|
64
|
-
}
|
|
65
|
-
};
|
|
66
|
-
// Initialize MCPProxyService
|
|
67
|
-
const mcpProxyService = new MCPProxyService({
|
|
68
|
-
logger: new ConsoleLogger(),
|
|
69
|
-
maxConnections: 50,
|
|
70
|
-
});
|
|
71
|
-
// Helper function to convert request query to ServerConfig
|
|
72
|
-
const createServerConfigFromRequest = (req) => {
|
|
73
|
-
const query = req.query;
|
|
74
|
-
const transportType = query.transportType;
|
|
75
|
-
const config = {
|
|
76
|
-
id: randomUUID(),
|
|
77
|
-
type: transportType,
|
|
78
|
-
name: `server-${Date.now()}`,
|
|
79
|
-
};
|
|
80
|
-
if (transportType === "stdio") {
|
|
81
|
-
config.command = query.command;
|
|
82
|
-
config.args = query.args
|
|
83
|
-
? shellParseArgs(query.args)
|
|
84
|
-
: undefined;
|
|
85
|
-
// Safely parse env - only if it's a valid JSON string
|
|
86
|
-
if (query.env) {
|
|
87
|
-
try {
|
|
88
|
-
config.env = JSON.parse(query.env);
|
|
89
|
-
}
|
|
90
|
-
catch (error) {
|
|
91
|
-
console.warn(`Failed to parse env as JSON: ${query.env}, using empty object`);
|
|
92
|
-
config.env = {};
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
else if (transportType === "sse" || transportType === "streamable-http") {
|
|
97
|
-
config.url = query.url;
|
|
98
|
-
}
|
|
99
|
-
return config;
|
|
100
|
-
};
|
|
101
|
-
// Helper function to extract headers for transport
|
|
102
|
-
const extractRequestHeaders = (req) => {
|
|
103
|
-
const headers = {};
|
|
104
|
-
const headersToPass = req.query.transportType === "sse"
|
|
105
|
-
? SSE_HEADERS_PASSTHROUGH
|
|
106
|
-
: STREAMABLE_HTTP_HEADERS_PASSTHROUGH;
|
|
107
|
-
for (const key of headersToPass) {
|
|
108
|
-
const value = req.headers[key];
|
|
109
|
-
if (value !== undefined) {
|
|
110
|
-
headers[key] = Array.isArray(value) ? value[value.length - 1] : value;
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
return headers;
|
|
114
|
-
};
|
|
115
|
-
app.get("/mcp", async (req, res) => {
|
|
116
|
-
const sessionId = req.headers["mcp-session-id"];
|
|
117
|
-
console.log(`š„ Received GET message for sessionId ${sessionId}`);
|
|
118
|
-
try {
|
|
119
|
-
const transport = mcpProxyService.getWebAppTransport(sessionId);
|
|
120
|
-
if (!transport) {
|
|
121
|
-
res.status(404).end("Session not found");
|
|
122
|
-
return;
|
|
123
|
-
}
|
|
124
|
-
else {
|
|
125
|
-
await transport.handleRequest(req, res);
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
catch (error) {
|
|
129
|
-
console.error("ā Error in /mcp route:", error);
|
|
130
|
-
res.status(500).json(error);
|
|
131
|
-
}
|
|
132
|
-
});
|
|
133
|
-
app.post("/mcp", async (req, res) => {
|
|
134
|
-
const sessionId = req.headers["mcp-session-id"];
|
|
135
|
-
console.log(`š„ Received POST message for sessionId ${sessionId}`);
|
|
136
|
-
if (!sessionId) {
|
|
137
|
-
try {
|
|
138
|
-
console.log("š New streamable-http connection");
|
|
139
|
-
// Create server config and headers from request
|
|
140
|
-
const serverConfig = createServerConfigFromRequest(req);
|
|
141
|
-
const requestHeaders = extractRequestHeaders(req);
|
|
142
|
-
try {
|
|
143
|
-
// Use MCPProxyService to create the streamable HTTP connection
|
|
144
|
-
const { sessionId: newSessionId, webAppTransport } = await mcpProxyService.createStreamableHTTPConnection(serverConfig, requestHeaders);
|
|
145
|
-
console.log(`⨠Connected MCP client to backing server transport for session ${newSessionId}`);
|
|
146
|
-
await webAppTransport.handleRequest(req, res, req.body);
|
|
147
|
-
}
|
|
148
|
-
catch (error) {
|
|
149
|
-
if (error instanceof SseError && error.code === 401) {
|
|
150
|
-
console.error("š Received 401 Unauthorized from MCP server:", error.message);
|
|
151
|
-
res.status(401).json(error);
|
|
152
|
-
return;
|
|
153
|
-
}
|
|
154
|
-
throw error;
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
catch (error) {
|
|
158
|
-
console.error("ā Error in /mcp POST route:", error);
|
|
159
|
-
res.status(500).json(error);
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
else {
|
|
163
|
-
try {
|
|
164
|
-
const transport = mcpProxyService.getWebAppTransport(sessionId);
|
|
165
|
-
if (!transport) {
|
|
166
|
-
res.status(404).end("Transport not found for sessionId " + sessionId);
|
|
167
|
-
}
|
|
168
|
-
else {
|
|
169
|
-
await transport.handleRequest(req, res);
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
catch (error) {
|
|
173
|
-
console.error("ā Error in /mcp route:", error);
|
|
174
|
-
res.status(500).json(error);
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
});
|
|
178
|
-
app.get("/stdio", async (req, res) => {
|
|
179
|
-
try {
|
|
180
|
-
console.log("š New stdio/sse connection");
|
|
181
|
-
// Create server config and headers from request
|
|
182
|
-
const serverConfig = createServerConfigFromRequest(req);
|
|
183
|
-
const requestHeaders = extractRequestHeaders(req);
|
|
184
|
-
try {
|
|
185
|
-
// Use MCPProxyService to create the SSE connection (handles STDIO stderr automatically)
|
|
186
|
-
const { sessionId } = await mcpProxyService.createSSEConnection(serverConfig, res, requestHeaders);
|
|
187
|
-
console.log(`⨠Connected MCP client to backing server transport for session ${sessionId}`);
|
|
188
|
-
}
|
|
189
|
-
catch (error) {
|
|
190
|
-
if (error instanceof SseError && error.code === 401) {
|
|
191
|
-
console.error("š Received 401 Unauthorized from MCP server:", error.message);
|
|
192
|
-
res.status(401).json(error);
|
|
193
|
-
return;
|
|
194
|
-
}
|
|
195
|
-
throw error;
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
catch (error) {
|
|
199
|
-
console.error("ā Error in /stdio route:", error);
|
|
200
|
-
// Can't send a 500 response if headers already sent (which they are for SSE)
|
|
201
|
-
}
|
|
202
|
-
});
|
|
203
|
-
app.get("/sse", async (req, res) => {
|
|
204
|
-
try {
|
|
205
|
-
console.log("š New sse connection");
|
|
206
|
-
// Create server config and headers from request
|
|
207
|
-
const serverConfig = createServerConfigFromRequest(req);
|
|
208
|
-
const requestHeaders = extractRequestHeaders(req);
|
|
209
|
-
try {
|
|
210
|
-
// Use MCPProxyService to create the SSE connection
|
|
211
|
-
const { sessionId } = await mcpProxyService.createSSEConnection(serverConfig, res, requestHeaders);
|
|
212
|
-
console.log(`⨠Connected MCP client to backing server transport for session ${sessionId}`);
|
|
213
|
-
}
|
|
214
|
-
catch (error) {
|
|
215
|
-
if (error instanceof SseError && error.code === 401) {
|
|
216
|
-
console.error("š Received 401 Unauthorized from MCP server:", error.message);
|
|
217
|
-
res.status(401).json(error);
|
|
218
|
-
return;
|
|
219
|
-
}
|
|
220
|
-
throw error;
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
catch (error) {
|
|
224
|
-
console.error("ā Error in /sse route:", error);
|
|
225
|
-
// Can't send a 500 response if headers already sent (which they are for SSE)
|
|
226
|
-
}
|
|
227
|
-
});
|
|
228
|
-
app.post("/message", async (req, res) => {
|
|
229
|
-
try {
|
|
230
|
-
const sessionId = req.query.sessionId;
|
|
231
|
-
console.log(`š„ Received message for sessionId ${sessionId}`);
|
|
232
|
-
const transport = mcpProxyService.getWebAppTransport(sessionId);
|
|
233
|
-
if (!transport) {
|
|
234
|
-
res.status(404).end("Session not found");
|
|
235
|
-
return;
|
|
236
|
-
}
|
|
237
|
-
await transport.handlePostMessage(req, res);
|
|
238
|
-
}
|
|
239
|
-
catch (error) {
|
|
240
|
-
console.error("ā Error in /message route:", error);
|
|
241
|
-
res.status(500).json(error);
|
|
242
|
-
}
|
|
243
|
-
});
|
|
244
|
-
app.get("/health", (req, res) => {
|
|
245
|
-
res.json({
|
|
246
|
-
status: "ok",
|
|
247
|
-
});
|
|
248
|
-
});
|
|
249
|
-
app.get("/config", (req, res) => {
|
|
250
|
-
try {
|
|
251
|
-
res.json({
|
|
252
|
-
defaultEnvironment,
|
|
253
|
-
defaultCommand: values.env,
|
|
254
|
-
defaultArgs: values.args,
|
|
255
|
-
serverConfigs,
|
|
256
|
-
});
|
|
257
|
-
}
|
|
258
|
-
catch (error) {
|
|
259
|
-
console.error("ā Error in /config route:", error);
|
|
260
|
-
res.status(500).json(error);
|
|
261
|
-
}
|
|
262
|
-
});
|
|
263
|
-
// Database API routes - will be added after database initialization
|
|
264
|
-
// Function to find an available port
|
|
265
|
-
const findAvailablePort = async (startPort) => {
|
|
266
|
-
return new Promise((resolve, reject) => {
|
|
267
|
-
const server = createServer();
|
|
268
|
-
server.listen(startPort, () => {
|
|
269
|
-
const port = server.address()?.port;
|
|
270
|
-
server.close(() => {
|
|
271
|
-
resolve(port);
|
|
272
|
-
});
|
|
273
|
-
});
|
|
274
|
-
server.on("error", (err) => {
|
|
275
|
-
if (err.code === "EADDRINUSE") {
|
|
276
|
-
// Port is in use, try the next one
|
|
277
|
-
findAvailablePort(startPort + 1)
|
|
278
|
-
.then(resolve)
|
|
279
|
-
.catch(reject);
|
|
280
|
-
}
|
|
281
|
-
else {
|
|
282
|
-
reject(err);
|
|
283
|
-
}
|
|
284
|
-
});
|
|
285
|
-
});
|
|
286
|
-
};
|
|
287
|
-
const PORT = process.env.PORT || 6277;
|
|
288
|
-
// Store the actual running port
|
|
289
|
-
let actualPort;
|
|
290
|
-
// Add endpoint to get the actual running port
|
|
291
|
-
app.get("/port", (req, res) => {
|
|
292
|
-
res.json({
|
|
293
|
-
port: actualPort,
|
|
294
|
-
});
|
|
295
|
-
});
|
|
296
|
-
// Start server with dynamic port finding
|
|
297
|
-
const startServer = async () => {
|
|
298
|
-
try {
|
|
299
|
-
// Initialize database first
|
|
300
|
-
await initializeDatabase();
|
|
301
|
-
const availablePort = await findAvailablePort(Number(PORT));
|
|
302
|
-
actualPort = availablePort;
|
|
303
|
-
const server = app.listen(availablePort);
|
|
304
|
-
server.on("listening", () => {
|
|
305
|
-
if (availablePort !== Number(PORT)) {
|
|
306
|
-
console.log(`ā ļø Port ${PORT} was in use, using available port ${availablePort} instead`);
|
|
307
|
-
}
|
|
308
|
-
console.log(`\x1b[32m%s\x1b[0m`, `āļø Proxy server listening on port ${availablePort}`);
|
|
309
|
-
});
|
|
310
|
-
server.on("error", (err) => {
|
|
311
|
-
console.error(`ā Server error: ${err.message}`);
|
|
312
|
-
process.exit(1);
|
|
313
|
-
});
|
|
314
|
-
// Graceful shutdown
|
|
315
|
-
process.on("SIGINT", async () => {
|
|
316
|
-
console.log("\nš Shutting down server...");
|
|
317
|
-
server.close();
|
|
318
|
-
await mcpProxyService.closeAllConnections();
|
|
319
|
-
if (databaseManager) {
|
|
320
|
-
await databaseManager.close();
|
|
321
|
-
console.log("ā
Database connection closed");
|
|
322
|
-
}
|
|
323
|
-
process.exit(0);
|
|
324
|
-
});
|
|
325
|
-
}
|
|
326
|
-
catch (error) {
|
|
327
|
-
console.error(`ā Failed to start server: ${error}`);
|
|
328
|
-
process.exit(1);
|
|
329
|
-
}
|
|
330
|
-
};
|
|
331
|
-
startServer();
|