@mcpjam/inspector 3.12.3 → 3.12.5

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.
Files changed (37) hide show
  1. package/README.md +29 -21
  2. package/bin/access-link.mjs +53 -0
  3. package/bin/start.js +47 -14
  4. package/dist/client/assets/OAuthDesktopReturnNotice-B_x9xTE-.css +2 -0
  5. package/dist/client/assets/OAuthDesktopReturnNotice-LlC451lX.js +11 -0
  6. package/dist/client/assets/{app-bootstrap-C1Jn01kP.js → app-bootstrap-2jatN7gw.js} +376 -374
  7. package/dist/client/assets/{button-RD2Dghjp.js → button-B2OH2ei2.js} +2 -2
  8. package/dist/client/assets/{chunk-YOKDWASO-DTTU1wSE.js → chunk-YOKDWASO-uJ3KOQV7.js} +5 -5
  9. package/dist/client/assets/{dead-clicks-autocapture-CDkbT21a.js → dead-clicks-autocapture-D055GjVp.js} +2 -2
  10. package/dist/client/assets/{error-reporting-Dg5b1JwS.js → error-reporting-DGP36KLx.js} +57 -57
  11. package/dist/client/assets/{error-reporting-_SEhX6IL.js → error-reporting-FWZKbZxG.js} +1 -1
  12. package/dist/client/assets/{exception-autocapture-CtxHwPtn.js → exception-autocapture-103gdJjL.js} +2 -2
  13. package/dist/client/assets/{failed-request-tracker-kUaJ-sVM.js → failed-request-tracker-Cp9_VFMm.js} +2 -2
  14. package/dist/client/assets/{highlighted-body-KPVGNVTW-CBC2hHHb.js → highlighted-body-KPVGNVTW-Dx70h1nm.js} +2 -2
  15. package/dist/client/assets/index-rskHnM3O.js +4 -0
  16. package/dist/client/assets/{jszip.min-B3Qii_az.js → jszip.min-CwJyI5tb.js} +2 -2
  17. package/dist/client/assets/{mermaid-HWGCJPDP-BzT3-9sO.js → mermaid-HWGCJPDP-Ck3prJKl.js} +1 -1
  18. package/dist/client/assets/{posthog-recorder-B06ULcLl.js → posthog-recorder-tKuMFijV.js} +2 -2
  19. package/dist/client/assets/{preload-helper-DvWwGI6x.js → preload-helper-DrcoTQ49.js} +2 -2
  20. package/dist/client/assets/{rolldown-runtime-DVMSi0Yr.js → rolldown-runtime-7FnpGOz6.js} +1 -1
  21. package/dist/client/assets/{surveys-D941hgn3.js → surveys-BsZYxM6N.js} +2 -2
  22. package/dist/client/assets/{trace-timeline-Bk3hAXNq.js → trace-timeline-BOZvHcOG.js} +1 -1
  23. package/dist/client/assets/{trace-timeline-DVZqlQSW.js → trace-timeline-Bf9Oai70.js} +8 -8
  24. package/dist/client/assets/{web-vitals-DZUBt4dL.js → web-vitals-DdzaVN3H.js} +2 -2
  25. package/dist/client/index.html +7 -7
  26. package/dist/server/chunk-3EDQFXTF.js +4801 -0
  27. package/dist/server/{chunk-5RE7KJ2M.js → chunk-4PYR7GMQ.js} +16 -197
  28. package/dist/server/{chunk-WGJHSGJP.js → chunk-QA6VJT6A.js} +961 -963
  29. package/dist/server/chunk-SH24KJBI.js +194 -0
  30. package/dist/server/{consent-lifetime-PTGAZQSU.js → consent-lifetime-M7PS6RUU.js} +3 -2
  31. package/dist/server/harness-install-cli.js +1 -1
  32. package/dist/server/index.js +15110 -16012
  33. package/dist/server/local-turn-XXOSZHMT.js +12 -0
  34. package/package.json +14 -11
  35. package/dist/client/assets/OAuthDesktopReturnNotice-C5D90OSm.js +0 -11
  36. package/dist/client/assets/OAuthDesktopReturnNotice-C95FI7VH.css +0 -2
  37. package/dist/client/assets/index-yOjxp36p.js +0 -4
package/README.md CHANGED
@@ -78,32 +78,40 @@ Network access requires **Docker**. A native (`npx`) install binds to
78
78
  `127.0.0.1` (localhost only) and has no bind-address override, so it is not
79
79
  reachable from another machine. The Docker image binds `0.0.0.0`, so it is.
80
80
 
81
- For security, the inspector only issues its session token to `localhost`. When
82
- you open a Docker install from another machine (e.g. `http://192.168.1.50:6274`),
83
- it will otherwise dead-end on an authentication error. To allow a specific host,
84
- set `MCPJAM_ALLOWED_HOSTS` to that hostname (or a comma-separated list; wildcards
85
- like `*.example.com` are supported), and publish the port on your network
86
- interface (drop the `127.0.0.1:` prefix from `-p`):
81
+ Open the private link printed in the terminal (or `docker logs <container>`) to
82
+ sign this browser in. A plain address displays instructions to open that link.
83
+ The browser remembers access for this origin until the Inspector restarts.
84
+ Keep the link private: it grants control of the local Inspector and its tools.
85
+
86
+ For another computer, set `MCPJAM_ALLOWED_HOSTS` to the hostname or IP you use,
87
+ and publish the port on your network interface (this exposes the port on all interfaces):
87
88
 
88
89
  ```bash
89
90
  docker run -p 6274:6274 -e MCPJAM_ALLOWED_HOSTS=192.168.1.50 mcpjam/mcp-inspector:local
90
91
  ```
91
92
 
92
- For an IPv6 host, bracket the entry: `MCPJAM_ALLOWED_HOSTS=[fd00::50]`.
93
-
94
- If you use a **wildcard** entry (e.g. `MCPJAM_ALLOWED_HOSTS=*.lan`), also set
95
- `MCPJAM_ALLOW_WILDCARD_ORIGINS=true`. Wildcards deliver the session token on
96
- their own, but for security the request-origin check ignores wildcard hosts
97
- unless you opt in with that variable — without it, API calls still 403. A
98
- single exact host (like the IP above) needs no extra flag.
99
-
100
- Only add hosts you trust. Allowlisting a host does more than expose the session
101
- token: the same host is accepted as a request Origin, which also reaches the
102
- local shell and agent-browser tools that are enabled by default in self-hosted
103
- mode. Any client that can reach an allowlisted host can obtain the session token
104
- and drive those tools. Set `MCPJAM_LOCAL_COMPUTER_ENABLED=false` and
105
- `MCPJAM_LOCAL_BROWSER_ENABLED=false` if you don't want that. Tunnel/relay domains
106
- are never allowed, even if listed.
93
+ Alternatively, keep the remote port bound to loopback and use
94
+ `ssh -L 6274:127.0.0.1:6274 user@host`; open the terminal link at the forwarded address.
95
+
96
+ Open the printed Network link, or paste the link/code into the access screen at
97
+ that address. If ports are remapped, keep the `#token=…` fragment and change the
98
+ address. `MCPJAM_INSPECTOR_FRONTEND_URL=http://devbox.local:8080` sets the printed
99
+ browser address explicitly. Cross-tab continuation works only on the same origin.
100
+
101
+ For IPv6, bracket the allowlist entry: `MCPJAM_ALLOWED_HOSTS=[fd00::50]`.
102
+ Wildcards such as `*.lan` additionally require
103
+ `MCPJAM_ALLOW_WILDCARD_ORIGINS=true` for the request-origin check. The allowlist
104
+ never grants credentials by itself.
105
+
106
+ Optionally set `MCPJAM_SESSION_TOKEN` to a strong random URL-safe secret (at least
107
+ 24 characters) to keep a link across restarts. Generate one with
108
+ `node -e "process.stdout.write(require('crypto').randomBytes(24).toString('base64url'))"`.
109
+ The default is a new random credential on each launch. Local CLI attachment reads
110
+ a same-user discovery file under `~/.mcpjam/inspector/`, readable only by its owner;
111
+ update `@mcpjam/cli` alongside the Inspector.
112
+
113
+ Set `MCPJAM_LOCAL_COMPUTER_ENABLED=false` and
114
+ `MCPJAM_LOCAL_BROWSER_ENABLED=false` to disable the local computer/browser tools.
107
115
 
108
116
  # Key features
109
117
 
@@ -0,0 +1,53 @@
1
+ import { randomBytes } from "node:crypto";
2
+
3
+ export function createLaunchToken(env = process.env) {
4
+ if (env.VITE_MCPJAM_HOSTED_MODE === "true") return undefined;
5
+ const token =
6
+ env.MCPJAM_SESSION_TOKEN ?? randomBytes(24).toString("base64url");
7
+ if (!/^[A-Za-z0-9_-]{24,}$/.test(token))
8
+ throw new Error(
9
+ "MCPJAM_SESSION_TOKEN must contain at least 24 URL-safe letters, digits, underscores or hyphens",
10
+ );
11
+ return token;
12
+ }
13
+ export function createAccessLink(base, token, tab) {
14
+ const url = new URL(base);
15
+ if (token)
16
+ url.hash = new URLSearchParams({
17
+ token,
18
+ ...(tab ? { tab } : {}),
19
+ }).toString();
20
+ else if (tab) url.hash = tab;
21
+ return url.href;
22
+ }
23
+ export function networkAccessLinks(base, token, allowedHosts = "", tab) {
24
+ return allowedHosts
25
+ .split(",")
26
+ .map((host) => host.trim())
27
+ .filter((host) => host && !host.includes("*"))
28
+ .flatMap((host) => {
29
+ try {
30
+ // Configuration names hosts, not schemes, paths or credentials.
31
+ const authority = new URL(`http://${host}`);
32
+ if (
33
+ authority.username ||
34
+ authority.password ||
35
+ authority.pathname !== "/" ||
36
+ authority.search ||
37
+ authority.hash
38
+ )
39
+ return [];
40
+ const url = new URL(base);
41
+ url.hostname = authority.hostname;
42
+ if (authority.port) url.port = authority.port;
43
+ return [createAccessLink(url.href, token, tab)];
44
+ } catch {
45
+ return [];
46
+ }
47
+ });
48
+ }
49
+
50
+ /** CLI-owned launches open their own link; redirected launcher logs stay credential-free. */
51
+ export function shouldPrintAccessLink(token, env = process.env) {
52
+ return Boolean(token) && env.MCPJAM_INSPECTOR_SUPPRESS_AUTO_OPEN !== "1";
53
+ }
package/bin/start.js CHANGED
@@ -7,6 +7,12 @@ import { createServer, createConnection } from "net";
7
7
  import { execSync } from "child_process";
8
8
  import { existsSync, readFileSync } from "fs";
9
9
  import open from "open";
10
+ import {
11
+ createLaunchToken,
12
+ shouldPrintAccessLink,
13
+ createAccessLink,
14
+ networkAccessLinks,
15
+ } from "./access-link.mjs";
10
16
  import { launchWorkspaceCandidate } from "./launch-workspace.mjs";
11
17
 
12
18
  const __dirname = dirname(fileURLToPath(import.meta.url));
@@ -1003,13 +1009,17 @@ async function main() {
1003
1009
  // to become the installed package's root and the server would otherwise
1004
1010
  // have no way back to where the user actually was.
1005
1011
  const launchWorkspace = launchWorkspaceCandidate({ projectRoot });
1012
+ const launchToken = createLaunchToken();
1006
1013
  const serverProcess = spawn("node", [distServerPath], {
1007
1014
  env: {
1008
1015
  ...process.env,
1016
+ ...(launchToken ? { MCPJAM_SESSION_TOKEN: launchToken } : {}),
1009
1017
  MCPJAM_INSPECTOR_PARENT_PID: process.pid.toString(),
1010
1018
  NODE_ENV: "production",
1011
1019
  PORT: PORT,
1012
- ...(launchWorkspace ? { MCPJAM_LAUNCH_WORKSPACE: launchWorkspace } : {}),
1020
+ ...(launchWorkspace
1021
+ ? { MCPJAM_LAUNCH_WORKSPACE: launchWorkspace }
1022
+ : {}),
1013
1023
  ...(verboseLogs && { VERBOSE_LOGS: "true" }),
1014
1024
  },
1015
1025
  cwd: projectRoot,
@@ -1095,21 +1105,44 @@ async function main() {
1095
1105
  logWarning(
1096
1106
  `Server did not become ready within 30s. Please visit ${apiBaseUrl} manually.`,
1097
1107
  );
1098
- } else if (!cancelled && openBrowser) {
1099
- let url = await resolveBrowserBaseUrl(apiBaseUrl);
1100
-
1101
- // Append initial tab hash if specified
1102
- if (initialTab) {
1103
- url = `${url}#${initialTab}`;
1108
+ } else if (!cancelled) {
1109
+ const base = await resolveBrowserBaseUrl(apiBaseUrl);
1110
+ const url = createAccessLink(base, launchToken, initialTab);
1111
+ const docker = process.env.DOCKER_CONTAINER === "true";
1112
+ let opened = false;
1113
+ if (openBrowser && !docker) {
1114
+ try {
1115
+ await open(url);
1116
+ opened = true;
1117
+ } catch {
1118
+ logWarning("Could not open your browser automatically.");
1119
+ }
1104
1120
  }
1105
-
1106
- try {
1107
- await open(url);
1108
- logSuccess(`🌐 Browser opened at ${url}`);
1109
- } catch (error) {
1110
- logWarning(
1111
- `Could not open browser automatically. Please visit ${url} manually.`,
1121
+ if (shouldPrintAccessLink(launchToken)) {
1122
+ logSuccess("MCPJam Inspector is ready");
1123
+ log("");
1124
+ const printLink = (label, link) => {
1125
+ log(` ${colors.green}➜ ${colors.bright}${label}${colors.reset}`);
1126
+ log(link, colors.primary);
1127
+ };
1128
+ printLink(docker ? "Open MCPJam" : "Local", url);
1129
+ for (const link of networkAccessLinks(
1130
+ base,
1131
+ launchToken,
1132
+ process.env.MCPJAM_ALLOWED_HOSTS,
1133
+ initialTab,
1134
+ ))
1135
+ printLink("Network", link);
1136
+ log("");
1137
+ log(
1138
+ opened
1139
+ ? "Opened in your browser. Keep this link private: it signs a browser in."
1140
+ : "Open this link in your browser. Keep it private: it signs a browser in.",
1112
1141
  );
1142
+ if (docker)
1143
+ log(
1144
+ "Using another port or computer? Keep the #token=… part and change the address.",
1145
+ );
1113
1146
  }
1114
1147
  }
1115
1148
  }