@mcpjam/inspector 0.3.4 → 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.
@@ -3,7 +3,6 @@
3
3
 
4
4
  /* Custom animations and modern styling for the MCP Inspector */
5
5
  #root {
6
- margin: 0 auto;
7
6
  font-family:
8
7
  "Inter",
9
8
  -apple-system,
@@ -1052,9 +1051,6 @@ video {
1052
1051
  .-right-4 {
1053
1052
  right: -1rem;
1054
1053
  }
1055
- .-top-0\.5 {
1056
- top: -0.125rem;
1057
- }
1058
1054
  .-top-1\.5 {
1059
1055
  top: -0.375rem;
1060
1056
  }
@@ -1076,6 +1072,9 @@ video {
1076
1072
  .right-2 {
1077
1073
  right: 0.5rem;
1078
1074
  }
1075
+ .right-3 {
1076
+ right: 0.75rem;
1077
+ }
1079
1078
  .right-4 {
1080
1079
  right: 1rem;
1081
1080
  }
@@ -1138,6 +1137,9 @@ video {
1138
1137
  margin-top: auto;
1139
1138
  margin-bottom: auto;
1140
1139
  }
1140
+ .-ml-1 {
1141
+ margin-left: -0.25rem;
1142
+ }
1141
1143
  .mb-1 {
1142
1144
  margin-bottom: 0.25rem;
1143
1145
  }
@@ -1171,9 +1173,6 @@ video {
1171
1173
  .ml-7 {
1172
1174
  margin-left: 1.75rem;
1173
1175
  }
1174
- .ml-8 {
1175
- margin-left: 2rem;
1176
- }
1177
1176
  .ml-auto {
1178
1177
  margin-left: auto;
1179
1178
  }
@@ -1238,9 +1237,6 @@ video {
1238
1237
  width: 1rem;
1239
1238
  height: 1rem;
1240
1239
  }
1241
- .h-0\.5 {
1242
- height: 0.125rem;
1243
- }
1244
1240
  .h-1 {
1245
1241
  height: 0.25rem;
1246
1242
  }
@@ -1322,6 +1318,9 @@ video {
1322
1318
  .max-h-\[90vh\] {
1323
1319
  max-height: 90vh;
1324
1320
  }
1321
+ .max-h-\[calc\(100vh-300px\)\] {
1322
+ max-height: calc(100vh - 300px);
1323
+ }
1325
1324
  .max-h-screen {
1326
1325
  max-height: 100vh;
1327
1326
  }
@@ -1482,6 +1481,10 @@ video {
1482
1481
  --tw-translate-y: -50%;
1483
1482
  transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
1484
1483
  }
1484
+ .rotate-0 {
1485
+ --tw-rotate: 0deg;
1486
+ transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
1487
+ }
1485
1488
  .rotate-180 {
1486
1489
  --tw-rotate: 180deg;
1487
1490
  transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
@@ -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
  }
@@ -1619,11 +1625,6 @@ video {
1619
1625
  margin-right: calc(0.75rem * var(--tw-space-x-reverse));
1620
1626
  margin-left: calc(0.75rem * calc(1 - var(--tw-space-x-reverse)));
1621
1627
  }
1622
- .space-x-4 > :not([hidden]) ~ :not([hidden]) {
1623
- --tw-space-x-reverse: 0;
1624
- margin-right: calc(1rem * var(--tw-space-x-reverse));
1625
- margin-left: calc(1rem * calc(1 - var(--tw-space-x-reverse)));
1626
- }
1627
1628
  .space-y-1 > :not([hidden]) ~ :not([hidden]) {
1628
1629
  --tw-space-y-reverse: 0;
1629
1630
  margin-top: calc(0.25rem * calc(1 - var(--tw-space-y-reverse)));
@@ -1741,10 +1742,6 @@ video {
1741
1742
  .border-dashed {
1742
1743
  border-style: dashed;
1743
1744
  }
1744
- .border-amber-200 {
1745
- --tw-border-opacity: 1;
1746
- border-color: rgb(253 230 138 / var(--tw-border-opacity, 1));
1747
- }
1748
1745
  .border-amber-300 {
1749
1746
  --tw-border-opacity: 1;
1750
1747
  border-color: rgb(252 211 77 / var(--tw-border-opacity, 1));
@@ -1797,6 +1794,10 @@ video {
1797
1794
  --tw-border-opacity: 1;
1798
1795
  border-color: rgb(209 213 219 / var(--tw-border-opacity, 1));
1799
1796
  }
1797
+ .border-gray-400 {
1798
+ --tw-border-opacity: 1;
1799
+ border-color: rgb(156 163 175 / var(--tw-border-opacity, 1));
1800
+ }
1800
1801
  .border-green-200 {
1801
1802
  --tw-border-opacity: 1;
1802
1803
  border-color: rgb(187 247 208 / var(--tw-border-opacity, 1));
@@ -1863,10 +1864,6 @@ video {
1863
1864
  --tw-bg-opacity: 1;
1864
1865
  background-color: rgb(254 243 199 / var(--tw-bg-opacity, 1));
1865
1866
  }
1866
- .bg-amber-50 {
1867
- --tw-bg-opacity: 1;
1868
- background-color: rgb(255 251 235 / var(--tw-bg-opacity, 1));
1869
- }
1870
1867
  .bg-background {
1871
1868
  background-color: hsl(var(--background));
1872
1869
  }
@@ -1893,15 +1890,9 @@ video {
1893
1890
  --tw-bg-opacity: 1;
1894
1891
  background-color: rgb(239 246 255 / var(--tw-bg-opacity, 1));
1895
1892
  }
1896
- .bg-blue-500\/10 {
1897
- background-color: rgb(59 130 246 / 0.1);
1898
- }
1899
1893
  .bg-border {
1900
1894
  background-color: hsl(var(--border));
1901
1895
  }
1902
- .bg-border\/50 {
1903
- background-color: hsl(var(--border) / 0.5);
1904
- }
1905
1896
  .bg-card {
1906
1897
  background-color: hsl(var(--card));
1907
1898
  }
@@ -1920,6 +1911,10 @@ video {
1920
1911
  --tw-bg-opacity: 1;
1921
1912
  background-color: rgb(249 250 251 / var(--tw-bg-opacity, 1));
1922
1913
  }
1914
+ .bg-gray-600 {
1915
+ --tw-bg-opacity: 1;
1916
+ background-color: rgb(75 85 99 / var(--tw-bg-opacity, 1));
1917
+ }
1923
1918
  .bg-gray-900 {
1924
1919
  --tw-bg-opacity: 1;
1925
1920
  background-color: rgb(17 24 39 / var(--tw-bg-opacity, 1));
@@ -2062,11 +2057,6 @@ video {
2062
2057
  --tw-gradient-to: rgb(55 65 81 / 0) var(--tw-gradient-to-position);
2063
2058
  --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to);
2064
2059
  }
2065
- .from-muted\/20 {
2066
- --tw-gradient-from: hsl(var(--muted) / 0.2) var(--tw-gradient-from-position);
2067
- --tw-gradient-to: hsl(var(--muted) / 0) var(--tw-gradient-to-position);
2068
- --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to);
2069
- }
2070
2060
  .from-muted\/30 {
2071
2061
  --tw-gradient-from: hsl(var(--muted) / 0.3) var(--tw-gradient-from-position);
2072
2062
  --tw-gradient-to: hsl(var(--muted) / 0) var(--tw-gradient-to-position);
@@ -2286,12 +2276,27 @@ video {
2286
2276
  .pb-4 {
2287
2277
  padding-bottom: 1rem;
2288
2278
  }
2279
+ .pl-12 {
2280
+ padding-left: 3rem;
2281
+ }
2289
2282
  .pl-2 {
2290
2283
  padding-left: 0.5rem;
2291
2284
  }
2285
+ .pl-4 {
2286
+ padding-left: 1rem;
2287
+ }
2292
2288
  .pr-10 {
2293
2289
  padding-right: 2.5rem;
2294
2290
  }
2291
+ .pr-12 {
2292
+ padding-right: 3rem;
2293
+ }
2294
+ .pr-3 {
2295
+ padding-right: 0.75rem;
2296
+ }
2297
+ .pr-4 {
2298
+ padding-right: 1rem;
2299
+ }
2295
2300
  .pr-6 {
2296
2301
  padding-right: 1.5rem;
2297
2302
  }
@@ -2384,14 +2389,6 @@ video {
2384
2389
  --tw-text-opacity: 1;
2385
2390
  color: rgb(217 119 6 / var(--tw-text-opacity, 1));
2386
2391
  }
2387
- .text-amber-700 {
2388
- --tw-text-opacity: 1;
2389
- color: rgb(180 83 9 / var(--tw-text-opacity, 1));
2390
- }
2391
- .text-amber-800 {
2392
- --tw-text-opacity: 1;
2393
- color: rgb(146 64 14 / var(--tw-text-opacity, 1));
2394
- }
2395
2392
  .text-blue-500 {
2396
2393
  --tw-text-opacity: 1;
2397
2394
  color: rgb(59 130 246 / var(--tw-text-opacity, 1));
@@ -2622,14 +2619,6 @@ video {
2622
2619
  --tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color);
2623
2620
  box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
2624
2621
  }
2625
- .shadow-black\/10 {
2626
- --tw-shadow-color: rgb(0 0 0 / 0.1);
2627
- --tw-shadow: var(--tw-shadow-colored);
2628
- }
2629
- .shadow-black\/5 {
2630
- --tw-shadow-color: rgb(0 0 0 / 0.05);
2631
- --tw-shadow: var(--tw-shadow-colored);
2632
- }
2633
2622
  .outline-none {
2634
2623
  outline: 2px solid transparent;
2635
2624
  outline-offset: 2px;
@@ -2684,21 +2673,25 @@ video {
2684
2673
  transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
2685
2674
  transition-duration: 150ms;
2686
2675
  }
2676
+ .transition-shadow {
2677
+ transition-property: box-shadow;
2678
+ transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
2679
+ transition-duration: 150ms;
2680
+ }
2681
+ .transition-transform {
2682
+ transition-property: transform;
2683
+ transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
2684
+ transition-duration: 150ms;
2685
+ }
2687
2686
  .duration-200 {
2688
2687
  transition-duration: 200ms;
2689
2688
  }
2690
2689
  .duration-300 {
2691
2690
  transition-duration: 300ms;
2692
2691
  }
2693
- .duration-500 {
2694
- transition-duration: 500ms;
2695
- }
2696
2692
  .ease-in-out {
2697
2693
  transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
2698
2694
  }
2699
- .ease-out {
2700
- transition-timing-function: cubic-bezier(0, 0, 0.2, 1);
2701
- }
2702
2695
  @keyframes enter {
2703
2696
 
2704
2697
  from {
@@ -2734,15 +2727,9 @@ video {
2734
2727
  .duration-300 {
2735
2728
  animation-duration: 300ms;
2736
2729
  }
2737
- .duration-500 {
2738
- animation-duration: 500ms;
2739
- }
2740
2730
  .ease-in-out {
2741
2731
  animation-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
2742
2732
  }
2743
- .ease-out {
2744
- animation-timing-function: cubic-bezier(0, 0, 0.2, 1);
2745
- }
2746
2733
  .running {
2747
2734
  animation-play-state: running;
2748
2735
  }
@@ -2865,6 +2852,11 @@ h1 {
2865
2852
  border-color: hsl(var(--border) / 0.6);
2866
2853
  }
2867
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
+
2868
2860
  .hover\:border-primary\/20:hover {
2869
2861
  border-color: hsl(var(--primary) / 0.2);
2870
2862
  }
@@ -2910,6 +2902,11 @@ h1 {
2910
2902
  background-color: hsl(var(--destructive) / 0.9);
2911
2903
  }
2912
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
+
2913
2910
  .hover\:bg-gray-800\/10:hover {
2914
2911
  background-color: rgb(31 41 55 / 0.1);
2915
2912
  }
@@ -3001,41 +2998,22 @@ h1 {
3001
2998
  background-color: rgb(30 41 59 / var(--tw-bg-opacity, 1));
3002
2999
  }
3003
3000
 
3004
- .hover\:bg-gradient-to-r:hover {
3005
- background-image: linear-gradient(to right, var(--tw-gradient-stops));
3006
- }
3007
-
3008
3001
  .hover\:from-blue-700:hover {
3009
3002
  --tw-gradient-from: #1d4ed8 var(--tw-gradient-from-position);
3010
3003
  --tw-gradient-to: rgb(29 78 216 / 0) var(--tw-gradient-to-position);
3011
3004
  --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to);
3012
3005
  }
3013
3006
 
3014
- .hover\:from-muted\/30:hover {
3015
- --tw-gradient-from: hsl(var(--muted) / 0.3) var(--tw-gradient-from-position);
3016
- --tw-gradient-to: hsl(var(--muted) / 0) var(--tw-gradient-to-position);
3017
- --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to);
3018
- }
3019
-
3020
3007
  .hover\:from-secondary\/30:hover {
3021
3008
  --tw-gradient-from: hsl(var(--secondary) / 0.3) var(--tw-gradient-from-position);
3022
3009
  --tw-gradient-to: hsl(var(--secondary) / 0) var(--tw-gradient-to-position);
3023
3010
  --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to);
3024
3011
  }
3025
3012
 
3026
- .hover\:via-muted\/40:hover {
3027
- --tw-gradient-to: hsl(var(--muted) / 0) var(--tw-gradient-to-position);
3028
- --tw-gradient-stops: var(--tw-gradient-from), hsl(var(--muted) / 0.4) var(--tw-gradient-via-position), var(--tw-gradient-to);
3029
- }
3030
-
3031
3013
  .hover\:to-blue-800:hover {
3032
3014
  --tw-gradient-to: #1e40af var(--tw-gradient-to-position);
3033
3015
  }
3034
3016
 
3035
- .hover\:to-muted\/30:hover {
3036
- --tw-gradient-to: hsl(var(--muted) / 0.3) var(--tw-gradient-to-position);
3037
- }
3038
-
3039
3017
  .hover\:to-secondary\/20:hover {
3040
3018
  --tw-gradient-to: hsl(var(--secondary) / 0.2) var(--tw-gradient-to-position);
3041
3019
  }
@@ -3062,6 +3040,11 @@ h1 {
3062
3040
  color: hsl(var(--foreground));
3063
3041
  }
3064
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
+
3065
3048
  .hover\:text-primary:hover {
3066
3049
  color: hsl(var(--primary));
3067
3050
  }
@@ -3155,6 +3138,11 @@ h1 {
3155
3138
  --tw-ring-color: rgb(59 130 246 / var(--tw-ring-opacity, 1));
3156
3139
  }
3157
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
+
3158
3146
  .focus\:ring-primary\/20:focus {
3159
3147
  --tw-ring-color: hsl(var(--primary) / 0.2);
3160
3148
  }
@@ -3487,11 +3475,6 @@ h1 {
3487
3475
  border-color: rgb(217 119 6 / var(--tw-border-opacity, 1));
3488
3476
  }
3489
3477
 
3490
- .dark\:border-amber-800:is(.dark *) {
3491
- --tw-border-opacity: 1;
3492
- border-color: rgb(146 64 14 / var(--tw-border-opacity, 1));
3493
- }
3494
-
3495
3478
  .dark\:border-blue-800:is(.dark *) {
3496
3479
  --tw-border-opacity: 1;
3497
3480
  border-color: rgb(30 64 175 / var(--tw-border-opacity, 1));
@@ -3587,10 +3570,6 @@ h1 {
3587
3570
  border-color: rgb(133 77 14 / 0.5);
3588
3571
  }
3589
3572
 
3590
- .dark\:bg-amber-900\/30:is(.dark *) {
3591
- background-color: rgb(120 53 15 / 0.3);
3592
- }
3593
-
3594
3573
  .dark\:bg-amber-900\/50:is(.dark *) {
3595
3574
  background-color: rgb(120 53 15 / 0.5);
3596
3575
  }
@@ -3751,16 +3730,6 @@ h1 {
3751
3730
  --tw-gradient-to: rgb(30 41 59 / 0.5) var(--tw-gradient-to-position);
3752
3731
  }
3753
3732
 
3754
- .dark\:text-amber-200:is(.dark *) {
3755
- --tw-text-opacity: 1;
3756
- color: rgb(253 230 138 / var(--tw-text-opacity, 1));
3757
- }
3758
-
3759
- .dark\:text-amber-300:is(.dark *) {
3760
- --tw-text-opacity: 1;
3761
- color: rgb(252 211 77 / var(--tw-text-opacity, 1));
3762
- }
3763
-
3764
3733
  .dark\:text-amber-400:is(.dark *) {
3765
3734
  --tw-text-opacity: 1;
3766
3735
  color: rgb(251 191 36 / var(--tw-text-opacity, 1));
@@ -3972,6 +3941,11 @@ h1 {
3972
3941
  --tw-gradient-to: hsl(var(--secondary) / 0.3) var(--tw-gradient-to-position);
3973
3942
  }
3974
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
+
3975
3949
  .dark\:hover\:text-slate-100:hover:is(.dark *) {
3976
3950
  --tw-text-opacity: 1;
3977
3951
  color: rgb(241 245 249 / var(--tw-text-opacity, 1));
@@ -4060,6 +4034,17 @@ h1 {
4060
4034
  .md\:max-w-\[420px\] {
4061
4035
  max-width: 420px;
4062
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
+ }
4063
4048
  }
4064
4049
 
4065
4050
  .\[\&\+div\]\:text-xs+div {
@@ -5,10 +5,10 @@
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-B_8Xm9gw.js"></script>
9
- <link rel="stylesheet" crossorigin href="/assets/index-BT47S2Qb.css">
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
- <div id="root"></div>
12
+ <div id="root" class="w-full"></div>
13
13
  </body>
14
14
  </html>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mcpjam/inspector",
3
- "version": "0.3.4",
3
+ "version": "0.3.6",
4
4
  "description": "MCPJam inspector",
5
5
  "license": "Apache-2.0",
6
6
  "author": "MCPJam (https://mcpjam.com)",
@@ -51,6 +51,7 @@
51
51
  "ajv": "^8.17.1",
52
52
  "concurrently": "^9.0.1",
53
53
  "dotenv": "^16.5.0",
54
+ "lucide-react": "^0.525.0",
54
55
  "open": "^10.1.0",
55
56
  "openai": "^5.7.0",
56
57
  "shell-quote": "^1.8.2",
@@ -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
+ }