@mcpjam/inspector 0.3.5 → 0.3.6
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/README.md +1 -0
- package/cli/build/cli.js +52 -16
- package/client/dist/assets/{OAuthCallback-CaYMoLGO.js → OAuthCallback-Bgz6lAmx.js} +2 -1
- package/client/dist/assets/{OAuthDebugCallback-CBFeYzo9.js → OAuthDebugCallback-Gd08QO37.js} +1 -1
- package/client/dist/assets/{index-DQYTYcqe.js → index-Bgrnc5s2.js} +1505 -976
- package/client/dist/assets/{index-DegSReJM.css → index-CWDemo1t.css} +65 -3
- package/client/dist/index.html +2 -2
- package/package.json +1 -1
- package/server/build/database/DatabaseManager.js +108 -0
- package/server/build/database/index.js +8 -0
- package/server/build/database/routes.js +86 -0
- package/server/build/database/types.js +27 -0
- package/server/build/database/utils.js +86 -0
- package/server/build/index.js +109 -131
- package/server/build/shared/MCPProxyService.js +221 -0
- package/server/build/shared/TransportFactory.js +130 -0
- package/server/build/shared/index.js +4 -0
- package/server/build/shared/types.js +1 -0
- package/server/build/shared/utils.js +27 -0
- package/server/build/test-server.js +145 -0
- package/server/build/testing/HealthCheck.js +42 -0
- package/server/build/testing/TestExecutor.js +240 -0
- package/server/build/testing/TestRunner.js +198 -0
- package/server/build/testing/TestServer.js +440 -0
- package/server/build/testing/types.js +1 -0
|
@@ -1072,6 +1072,9 @@ video {
|
|
|
1072
1072
|
.right-2 {
|
|
1073
1073
|
right: 0.5rem;
|
|
1074
1074
|
}
|
|
1075
|
+
.right-3 {
|
|
1076
|
+
right: 0.75rem;
|
|
1077
|
+
}
|
|
1075
1078
|
.right-4 {
|
|
1076
1079
|
right: 1rem;
|
|
1077
1080
|
}
|
|
@@ -1134,6 +1137,9 @@ video {
|
|
|
1134
1137
|
margin-top: auto;
|
|
1135
1138
|
margin-bottom: auto;
|
|
1136
1139
|
}
|
|
1140
|
+
.-ml-1 {
|
|
1141
|
+
margin-left: -0.25rem;
|
|
1142
|
+
}
|
|
1137
1143
|
.mb-1 {
|
|
1138
1144
|
margin-bottom: 0.25rem;
|
|
1139
1145
|
}
|
|
@@ -1167,9 +1173,6 @@ video {
|
|
|
1167
1173
|
.ml-7 {
|
|
1168
1174
|
margin-left: 1.75rem;
|
|
1169
1175
|
}
|
|
1170
|
-
.ml-8 {
|
|
1171
|
-
margin-left: 2rem;
|
|
1172
|
-
}
|
|
1173
1176
|
.ml-auto {
|
|
1174
1177
|
margin-left: auto;
|
|
1175
1178
|
}
|
|
@@ -1525,6 +1528,9 @@ video {
|
|
|
1525
1528
|
.cursor-default {
|
|
1526
1529
|
cursor: default;
|
|
1527
1530
|
}
|
|
1531
|
+
.cursor-help {
|
|
1532
|
+
cursor: help;
|
|
1533
|
+
}
|
|
1528
1534
|
.cursor-not-allowed {
|
|
1529
1535
|
cursor: not-allowed;
|
|
1530
1536
|
}
|
|
@@ -1788,6 +1794,10 @@ video {
|
|
|
1788
1794
|
--tw-border-opacity: 1;
|
|
1789
1795
|
border-color: rgb(209 213 219 / var(--tw-border-opacity, 1));
|
|
1790
1796
|
}
|
|
1797
|
+
.border-gray-400 {
|
|
1798
|
+
--tw-border-opacity: 1;
|
|
1799
|
+
border-color: rgb(156 163 175 / var(--tw-border-opacity, 1));
|
|
1800
|
+
}
|
|
1791
1801
|
.border-green-200 {
|
|
1792
1802
|
--tw-border-opacity: 1;
|
|
1793
1803
|
border-color: rgb(187 247 208 / var(--tw-border-opacity, 1));
|
|
@@ -1901,6 +1911,10 @@ video {
|
|
|
1901
1911
|
--tw-bg-opacity: 1;
|
|
1902
1912
|
background-color: rgb(249 250 251 / var(--tw-bg-opacity, 1));
|
|
1903
1913
|
}
|
|
1914
|
+
.bg-gray-600 {
|
|
1915
|
+
--tw-bg-opacity: 1;
|
|
1916
|
+
background-color: rgb(75 85 99 / var(--tw-bg-opacity, 1));
|
|
1917
|
+
}
|
|
1904
1918
|
.bg-gray-900 {
|
|
1905
1919
|
--tw-bg-opacity: 1;
|
|
1906
1920
|
background-color: rgb(17 24 39 / var(--tw-bg-opacity, 1));
|
|
@@ -2262,15 +2276,27 @@ video {
|
|
|
2262
2276
|
.pb-4 {
|
|
2263
2277
|
padding-bottom: 1rem;
|
|
2264
2278
|
}
|
|
2279
|
+
.pl-12 {
|
|
2280
|
+
padding-left: 3rem;
|
|
2281
|
+
}
|
|
2265
2282
|
.pl-2 {
|
|
2266
2283
|
padding-left: 0.5rem;
|
|
2267
2284
|
}
|
|
2285
|
+
.pl-4 {
|
|
2286
|
+
padding-left: 1rem;
|
|
2287
|
+
}
|
|
2268
2288
|
.pr-10 {
|
|
2269
2289
|
padding-right: 2.5rem;
|
|
2270
2290
|
}
|
|
2291
|
+
.pr-12 {
|
|
2292
|
+
padding-right: 3rem;
|
|
2293
|
+
}
|
|
2271
2294
|
.pr-3 {
|
|
2272
2295
|
padding-right: 0.75rem;
|
|
2273
2296
|
}
|
|
2297
|
+
.pr-4 {
|
|
2298
|
+
padding-right: 1rem;
|
|
2299
|
+
}
|
|
2274
2300
|
.pr-6 {
|
|
2275
2301
|
padding-right: 1.5rem;
|
|
2276
2302
|
}
|
|
@@ -2826,6 +2852,11 @@ h1 {
|
|
|
2826
2852
|
border-color: hsl(var(--border) / 0.6);
|
|
2827
2853
|
}
|
|
2828
2854
|
|
|
2855
|
+
.hover\:border-gray-500:hover {
|
|
2856
|
+
--tw-border-opacity: 1;
|
|
2857
|
+
border-color: rgb(107 114 128 / var(--tw-border-opacity, 1));
|
|
2858
|
+
}
|
|
2859
|
+
|
|
2829
2860
|
.hover\:border-primary\/20:hover {
|
|
2830
2861
|
border-color: hsl(var(--primary) / 0.2);
|
|
2831
2862
|
}
|
|
@@ -2871,6 +2902,11 @@ h1 {
|
|
|
2871
2902
|
background-color: hsl(var(--destructive) / 0.9);
|
|
2872
2903
|
}
|
|
2873
2904
|
|
|
2905
|
+
.hover\:bg-gray-700:hover {
|
|
2906
|
+
--tw-bg-opacity: 1;
|
|
2907
|
+
background-color: rgb(55 65 81 / var(--tw-bg-opacity, 1));
|
|
2908
|
+
}
|
|
2909
|
+
|
|
2874
2910
|
.hover\:bg-gray-800\/10:hover {
|
|
2875
2911
|
background-color: rgb(31 41 55 / 0.1);
|
|
2876
2912
|
}
|
|
@@ -3004,6 +3040,11 @@ h1 {
|
|
|
3004
3040
|
color: hsl(var(--foreground));
|
|
3005
3041
|
}
|
|
3006
3042
|
|
|
3043
|
+
.hover\:text-gray-600:hover {
|
|
3044
|
+
--tw-text-opacity: 1;
|
|
3045
|
+
color: rgb(75 85 99 / var(--tw-text-opacity, 1));
|
|
3046
|
+
}
|
|
3047
|
+
|
|
3007
3048
|
.hover\:text-primary:hover {
|
|
3008
3049
|
color: hsl(var(--primary));
|
|
3009
3050
|
}
|
|
@@ -3097,6 +3138,11 @@ h1 {
|
|
|
3097
3138
|
--tw-ring-color: rgb(59 130 246 / var(--tw-ring-opacity, 1));
|
|
3098
3139
|
}
|
|
3099
3140
|
|
|
3141
|
+
.focus\:ring-indigo-400:focus {
|
|
3142
|
+
--tw-ring-opacity: 1;
|
|
3143
|
+
--tw-ring-color: rgb(129 140 248 / var(--tw-ring-opacity, 1));
|
|
3144
|
+
}
|
|
3145
|
+
|
|
3100
3146
|
.focus\:ring-primary\/20:focus {
|
|
3101
3147
|
--tw-ring-color: hsl(var(--primary) / 0.2);
|
|
3102
3148
|
}
|
|
@@ -3895,6 +3941,11 @@ h1 {
|
|
|
3895
3941
|
--tw-gradient-to: hsl(var(--secondary) / 0.3) var(--tw-gradient-to-position);
|
|
3896
3942
|
}
|
|
3897
3943
|
|
|
3944
|
+
.dark\:hover\:text-gray-300:hover:is(.dark *) {
|
|
3945
|
+
--tw-text-opacity: 1;
|
|
3946
|
+
color: rgb(209 213 219 / var(--tw-text-opacity, 1));
|
|
3947
|
+
}
|
|
3948
|
+
|
|
3898
3949
|
.dark\:hover\:text-slate-100:hover:is(.dark *) {
|
|
3899
3950
|
--tw-text-opacity: 1;
|
|
3900
3951
|
color: rgb(241 245 249 / var(--tw-text-opacity, 1));
|
|
@@ -3983,6 +4034,17 @@ h1 {
|
|
|
3983
4034
|
.md\:max-w-\[420px\] {
|
|
3984
4035
|
max-width: 420px;
|
|
3985
4036
|
}
|
|
4037
|
+
|
|
4038
|
+
.md\:grid-cols-2 {
|
|
4039
|
+
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
4040
|
+
}
|
|
4041
|
+
}
|
|
4042
|
+
|
|
4043
|
+
@media (min-width: 1024px) {
|
|
4044
|
+
|
|
4045
|
+
.lg\:grid-cols-3 {
|
|
4046
|
+
grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
4047
|
+
}
|
|
3986
4048
|
}
|
|
3987
4049
|
|
|
3988
4050
|
.\[\&\+div\]\:text-xs+div {
|
package/client/dist/index.html
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
<link rel="icon" type="image/svg+xml" href="/mcp_jam.svg" />
|
|
6
6
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
7
|
<title>MCPJam Inspector</title>
|
|
8
|
-
<script type="module" crossorigin src="/assets/index-
|
|
9
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
8
|
+
<script type="module" crossorigin src="/assets/index-Bgrnc5s2.js"></script>
|
|
9
|
+
<link rel="stylesheet" crossorigin href="/assets/index-CWDemo1t.css">
|
|
10
10
|
</head>
|
|
11
11
|
<body>
|
|
12
12
|
<div id="root" class="w-full"></div>
|
package/package.json
CHANGED
|
@@ -0,0 +1,108 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
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";
|
|
@@ -0,0 +1,86 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
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
|
+
}
|