* chore: v1 deprecation notices in all four packages, bump to 1.0.1
Phase 2 of the v2 go-live runbook (#1804 §4). v1 publishes four separately
installable names, so each gets its own notice — a root-README-only change is
invisible to anyone who installed a sub-package. `cli/` and `server/` ship no
README at all, so for those two the runtime banner plus the forthcoming
`npm deprecate` (#1816) are the only notice their users ever get.
Notices, all using identical wording so the runtime banner and the npm warning
agree:
- root `README.md` and `client/README.md`
- `cli/src/cli.ts` — stderr banner in `main()`. Also covers the root
`mcp-inspector` bin, which is `cli/build/cli.js`. Deliberately **stderr**:
`--cli` mode emits JSON on stdout and callers pipe it, so a banner there
would corrupt output. Verified against a real server — stdout stays
parseable JSON while the banner goes to stderr.
- `server/src/index.ts` — alongside the existing proxy listening log
- `client/bin/start.js` — alongside the existing startup URL log
- `client/src/components/DeprecationBanner.tsx` — dismissible in-app banner,
dismissal persisted in localStorage with both read and write guarded so a
storage failure degrades to "banner reappears" rather than breaking the app
AGENTS.md is replaced with a hard stop: v1 takes security fixes only, by issue
only, and agents must never open a PR against v1/main.
Version bumped to 1.0.1 across all four package.json files plus the lockfile
(`npm run update-version`); `check-version` passes. The lockfile diff is
restricted to the version fields — the `libc` churn a newer npm wanted to
introduce was reverted as unrelated.
`publish-all` is deliberately NOT changed here: 1.0.1 must take `latest`, which
is the entire point of shipping this notice to npx users. Adding `--tag v1` is
#1816, immediately after this publishes.
Note for review: `client/src/App.tsx` shows ~836 changed lines but `git diff -w`
shows 8 — wrapping the layout in a flex column added one nesting level and
prettier re-indented the subtree. Review it with `-w`.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Txmv2qqv3yeKgRzoqXytzD
* docs: replace the README screenshot with one showing the deprecation banner
Captured from this branch's build: v1.0.1 in the sidebar heading, the
dismissible deprecation banner across the top, connected to the everything
server with tools listed.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Txmv2qqv3yeKgRzoqXytzD
* docs: pin the README screenshot to v1/main instead of main
The image URL must stay absolute — a relative path breaks on the npm package
page, which renders the README outside any repo context. But it was pinned to
`main`, so the v1 README rendered whatever `main` happened to hold: today the
pre-deprecation screenshot, and after the v2 tree swap (#1817) either the v2
screenshot or a 404 if that path doesn't exist there.
Pinning to `v1/main` keeps it absolute for npm, shows the deprecation banner
once this merges, and survives the swap. Verified all candidate refs resolve
200 — GitHub disambiguates the slash in `v1/main` as the ref without needing a
`refs/heads/` prefix.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Txmv2qqv3yeKgRzoqXytzD
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(server): guard the /fetch proxy against SSRF to link-local/metadata
The /fetch proxy forwarded any user-supplied http/https URL straight into
fetch(), so a malicious remote MCP server could advertise OAuth metadata
pointing at the cloud metadata endpoint (169.254.169.254) and have the proxy
exfiltrate instance credentials (CodeQL js/request-forgery, alert #53).
Add a targeted SSRF guard: resolve the target host and reject link-local /
cloud-metadata addresses (169.254.0.0/16, IPv6 link-local, AWS IPv6 IMDS).
Loopback and RFC1918/private LAN targets stay reachable, since connecting to
local and self-hosted MCP servers is a core Inspector use case. Redirects are
now followed manually so every hop is re-validated, closing the
redirect-to-internal bypass. Returns 403 on a blocked target.
Adds endpoint tests for a direct metadata target, a redirect into a blocked
address, and normal redirects between allowed hosts.
Resolves code-scanning alert #53. Part of #1706.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HiccCEh9mwCfVzE8qYcop1
* fix(server): block IPv4-mapped IPv6 form of metadata IP in /fetch guard
The IPv4-mapped IPv6 branch of isBlockedProxyAddress only matched the
dotted-decimal form (::ffff:169.254.169.254), but the WHATWG URL parser
serializes IPv4-mapped addresses in hex (::ffff:a9fe:a9fe), so
http://[::ffff:169.254.169.254]/ resolved past the guard and still reached
the cloud metadata service on dual-stack hosts — the exact vector this guard
targets.
Extract the embedded IPv4 from both the hex and dotted forms and re-check it.
Adds a regression test for the IPv4-mapped IPv6 metadata address.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HiccCEh9mwCfVzE8qYcop1
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(server): sanitize error responses to prevent stack trace exposure
Replace raw error objects passed to res.json() with generic sanitized
messages so internal error details are not leaked to clients. Full
errors continue to be logged server-side via console.error.
Also adds a missing return in the /sse ECONNREFUSED branch, which
previously fell through and attempted a second response after headers
had already been sent.
Resolves CodeQL js/stack-trace-exposure alerts in server/src/index.ts.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(server): address review feedback on error sanitization
- Sanitize /fetch route catch block: previously leaked error.message to
clients and silently swallowed errors with no server-side logging.
Now logs via console.error and returns a generic sanitized response.
- Replace JSON.stringify(error).includes("ECONNREFUSED") in the /sse
handler with a check against error.message and String(error.cause).
Error fields are non-enumerable so JSON.stringify(new Error(...))
produces "{}" — the old check only worked by accident when the error
happened to carry enumerable properties.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Ola Hungerford <olahungerford@gmail.com>
* Fix MCP Apps rendering issue and add comprehensive logging
- Fixed AppRenderer useEffect dependency array to include resourceContent
This ensures the component re-evaluates when resource content arrives
- Added detailed console logging throughout the app lifecycle:
* Resource fetch and response tracking in App.tsx
* Setup conditions and AppBridge creation in AppRenderer.tsx
* HTML parsing and iframe rendering steps
* PostMessageTransport and AppBridge connection status
* App tool filtering and selection in AppsTab.tsx
- Refactored AppsTab selectedTool rendering for better tracking
The issue was that resourceContent prop updates weren't triggering
the AppRenderer setup effect. Now the effect properly responds to
both resourceUri and resourceContent changes.
Co-authored-by: Cliff Hall <cliffhall@users.noreply.github.com>
* Fix MCP Apps iframe rendering issue
The app was getting stuck on 'Loading MCP App...' because the iframe was
hidden (display: none) until the oninitialized event fired. However, the
PostMessage handshake requires the iframe to be visible to complete.
This fix:
- Sets loading to false immediately after writing HTML to the iframe
- Makes the iframe visible before establishing PostMessage transport
- Allows the AppBridge initialization handshake to complete successfully
- Removes redundant setLoading(false) from oninitialized callback
The iframe is now visible and ready for PostMessage communication before
the AppBridge connect() call, enabling proper initialization.
Co-authored-by: Cliff Hall <cliffhall@users.noreply.github.com>
* Fix MCP Apps HTML extraction to match spec
The AppRenderer was incorrectly checking for a 'type' field in resource
contents, but TextResourceContents objects only have uri, mimeType, and
text fields according to the MCP specification.
Fixed by checking for the presence of the 'text' field directly instead
of checking a non-existent 'type' field. This allows the HTML content
to be properly extracted and rendered in the iframe.
Co-authored-by: Cliff Hall <cliffhall@users.noreply.github.com>
* Add comprehensive tests for MCP Apps support
- Add tests for AppsTab component (13 tests)
- Add tests for AppRenderer component (17 tests)
- Update jest.config.cjs to handle ES modules from @modelcontextprotocol/ext-apps
- All 478 tests pass successfully
Co-authored-by: Cliff Hall <cliffhall@users.noreply.github.com>
* Add MCP Apps support to Inspector
- Add AppsTab component for detecting and listing MCP apps
- Add AppRenderer component with full AppBridge integration
- Implement UI resource fetching and sandboxed iframe rendering
- Add PostMessage transport for bidirectional JSON-RPC communication
- Include comprehensive test coverage (30 new tests)
- Auto-populate apps when tab becomes active
- Support theme awareness and configurable permissions
Co-authored-by: Cliff Hall <cliffhall@users.noreply.github.com>
* Prefer structuredContent over content field in tool responses
Some MCP servers return different data in structuredContent vs content fields.
This change ensures that when structuredContent is present, it is used
exclusively for display instead of showing both fields.
Changes:
- Modified ToolResults.tsx to only show content when structuredContent is absent
- Removed unused checkContentCompatibility function
- Updated test cases to reflect new behavior
Co-authored-by: Cliff Hall <cliffhall@users.noreply.github.com>
* Revert "Prefer structuredContent over content field in tool responses"
This reverts commit 3b054b4da08517cce53ef23e60c07bb32b0fa8f5.
Claude did not do the right thing.
* feat: integrate @mcp-ui/client for MCP application rendering
This commit implements the integration of `@mcp-ui/client` to handle the
rendering of Model Context Protocol (MCP) applications within the inspector.
It includes refactoring the rendering logic, improving resource fetching
in the main application state, and setting up a secure sandbox environment.
Changes per file:
- client/package.json:
- Added `@mcp-ui/client` as a dependency.
- client/src/components/AppRenderer.tsx:
- Refactored to use `McpUiAppRenderer` from `@mcp-ui/client`.
- Implemented HTML parsing logic for MCP resource responses.
- Configured host context (theme) and sandbox URL for the renderer.
- Replaced iframe-based manual rendering with the official component.
- client/src/App.tsx:
- Added `fetchingResources` state to prevent duplicate concurrent resource requests.
- Enhanced `readResource` with better error handling and state tracking.
- Optimized resource content mapping to better support application state.
- client/src/components/AppsTab.tsx:
- Updated to use `getToolUiResourceUri` utility from `@modelcontextprotocol/ext-apps`
instead of manual metadata property access.
- Simplified tool filtering and selection logic.
- client/public/sandbox_proxy.html:
- Added a sandbox proxy page to facilitate secure communication between
the inspector and the rendered MCP applications.
- client/bin/client.js:
- Added server rewrites to ensure `sandbox_proxy.html` is served correctly.
- Implemented specific `Cache-Control` headers for `sandbox_proxy.html` to
prevent stale cached versions.
- client/vite.config.ts:
- Explicitly configured `publicDir: "public"` to ensure the sandbox proxy
is included in the build output.
- client/src/components/__tests__/AppRenderer.test.tsx:
- Updated tests to mock the new `@mcp-ui/client` component.
- Adjusted assertions to verify correct props are passed to the renderer.
- Enhanced mock MCP client to include required methods like `getServerCapabilities`.
* Potential fix for code scanning alert no. 37: Client-side cross-site scripting
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
* Update package-lock.json
- npm install
- npm audit fix
* Potential fix for code scanning alert no. 38: Client-side cross-site scripting
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
* Potential fix for code scanning alert no. 39: Client-side cross-site scripting
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
* prettier
* Update client/src/components/AppsTab.tsx
Co-authored-by: Ola Hungerford <olahungerford@gmail.com>
* prettier
* In AppsTab.test.tsx, fetch button by aria-label
* relative imports
* Remove sanitization logic from sandbox_proxy.html. It's breaking the app rendering. Will sort out what best practices for this HTML is later
* In sandbox_proxy.html,formatting
In AppsTab.tsx
- Add app window
- when an app is selected,
- show input form for apps that have an input schema
- button shows app
- if app is shown, show maximize button
- if maximized,
- show minimize button
- hide app list
* In AppsTab.test.tsx
- test new layout and controls
* In AppRenderer.tsx
- accept toolInput
- pass to McpUiAppRenderer
* In AppsTab.tsx, if an app has no inputSchema, just show it, otherwise show the form and the "back to form" button when showing the app.
* In AppsTab.test.tsx
- test new behavior
* In ListPane.tsx
- remove the Clear button
* In ListPane.test.tsx
- remove test for clear button
* In AppRenderer.tsx,
- remove onReadResource and resourceContent, not needed since mcpClient is being passed
* In App.tsx and AppsTab.tsx,
- remove the passing of these variables
* In AppRenderer.test.tsx, and AppsTab.test.tsx
- remove tests that fail after having removed onReadResource and resourceContent
* Serving the sandbox_proxy.html from a separate port, using the proxy instead of the webclient server.
* In App.tsx
- pass the path to the sandbox endpoint on the proxy to the AppsTab
* In AppsTab.tsx
- accept the sandboxPath property and pass it to the AppRenderer
* In AppRenderer.tsx
- accept the sandboxPath property and pass it to the McpUiAppRenderer
* In client.js
- remove the rewrite and header config for sandbox_proxy.html
* In server/src/index.ts
- add a /sandbox endpoint that reads and returns the sandbox_proxy.html file with no-cache header
* In server/package.json
- add shx for cross-platform copy function
- in build script, copy static folder to build folder
* Moved sandbox_proxy.html from client/public to server/static
* In client.js
- return to original state
* In vite.config.ts
- return to original state
* Potential fix for code scanning alert no. 41: Missing rate limiting
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
* In AppRenderer.tsx
- add open link handler that handles link requests from the UI. Makes sure that the URL starts with http or https
* In sandbox_proxy.html
- refactor to match [basic-host](https://github.com/modelcontextprotocol/ext-apps/tree/main/examples/basic-host) example
- creates an nested iframe for security.
- in this implementation, for simplicity the sandbox.ts is inlined in sandbox_proxy.html as javascript
* prettier
* In AppRenderer.tsx
- add support for handling McpUiMessageRequest messages from the UI
- show message in a toast
* Add logging message handler to AppRenderer
In App.tsx
- pass an onNotification function to the AppsTab that adds a notification to the notification array
In AppsTab.tsx
- Accept the onNotification function and pass it to the AppRenderer
In AppRenderer.tsx
- Accept the onNotification function
- added an handleLoggingMessage function that takes a LoggingMessageNotificationParams object, wraps it with a method and params prop to make it a ServerNotification shape, and pass it to the onNotification function
- pass handleLoggingMessage to McpUiAppRenderer
* In ResourcesTab.test.tsx
- fix @ import that wasn't resolving
* In AppRenderer.tsx
- remove fetch and evaluation of resourceUri, as the mcpClient handles that (review request)
* In AppRenderer.test.tsx
- remove test for no resourceUri found
* Merge branch 'main' into full-apps-support-final
Resolved Conflicts:
- package-lock.json
* Fixed mismatch with sanboxRateLimiter and the express version
---------
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Cliff Hall <cliffhall@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
Co-authored-by: Ola Hungerford <olahungerford@gmail.com>
The server-side error handling only checked for SseError instances
when detecting 401 responses from MCP servers. StreamableHTTPClientTransport
throws a different error type (generic Error with "HTTP 401" message)
when there's no authProvider configured.
This caused the proxy to return 500 instead of 401 to the client,
preventing the OAuth discovery and redirect flow from triggering.
Added is401Error() helper that checks for:
- SseError with code 401
- StreamableHTTPError with code 401
- Generic Error with "HTTP 401" or "(401)" in message
Fixes#960🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1. createWebReadableStream: Add closed flag and cancel() callback to
prevent double-close crashes when SSE streams end. This fixes the
"Controller is already closed" error that occurs when the SDK calls
response.body.cancel() on 202 responses.
2. DELETE handler: Call serverTransport.close() after terminateSession()
to properly cleanup the transport and cancel pending reconnections.
- terminateSession() notifies the server (sends DELETE request)
- close() cleans up client-side resources (abort controller, timeouts)
- Both are needed for a complete disconnect
When failing to connect to an MCP server, its very hard to understand
why. There is only an opaque "Connection Error" message with no
additional info. This also doesn't change at all on repeated attempts,
so there is no indication we attempted again and failed.
This change introduces a `toast` to visualize the error, and adds the
`cause` into the error message for further debugging
- in createCustomFetch function
- convert finalHeaders to headers object for node-fetch compatibility
- for SSE streams, convert node stream to response body to web ReadableStream since EventSource polyfill expects web-compatible stream
* In package-lock.json and package.json
- add node-fetch as a dependency
This fixes#600
- Introduced CustomHeaders component for managing custom headers.
- Updated Sidebar to include CustomHeaders component.
- Enhanced useConnection hook to handle custom headers and legacy auth migration.
- Added tests for custom headers functionality.
- Updated package.json and package-lock.json for new dependencies.
* In `src/server/index.ts`,
- Added `updateHeadersInPlace` helper function to solve the stale header reference issue in `SSEClientTransport`. It mutates the header object in-place, ensuring the transport sees all updates, while carefully preserving the original `Accept` header required by the transport.
- in `/mcp GET`, `/mcp POST`, and `/message POST`, use `updateHeadersInPlace` to replace current headers with new headers, retaining the Accept header.
Adds a mechanism to dynamically inject and update HTTP headers for ongoing proxy sessions, resolving an issue where headers introduced after the initial handshake (e.g, Mcp-Protocol-Version) were not being forwarded to the server.
The core problem was that the `transportToServer` instance was created once with a static set of headers. This meant that critical, dynamically added headers like `mcp-protocol-version` and `last-event-id` were being dropped in subsequent requests.
The solution implemented here is to wrap the `fetch` function used by the HTTP-based transports (`StreamableHttp` and `SSE`). This custom wrapper merges the latest headers from the client with the headers of each outgoing request from the proxy, ensuring all headers are preserved for the lifetime of the session.
Changes:
In `src/index.ts`:
- Added `sessionHeaderHolders`, a `Map` to store the most recent set of headers for each active session ID.
- Added `createCustomFetch`, a new helper function that creates a `fetch` wrapper. This wrapper merges the session headers from `sessionHeaderHolders` with the request-specific headers from the SDK (like `Content-Type`)
- In `createTransport`, use `createCustomFetch` for both the `StreamableHTTPClientTransport` and `SSEClientTransport`. This injects the dynamic header logic into the transport layer.
- In `/mcp`, `/sse`, `/message` route handlers, added logic to update the `sessionHeaderHolders` map with the latest headers from every incoming client request.
- Added cleanup logic to the `onsessionclosed` callback and the `/mcp` DELETE handler to remove session data from `sessionHeaderHolders`.
- In `getHttpHeaders`, more robust handling of `string[]` and `undefined` values from `req.headers`, satisfying the `"strict": true` TypeScript configuration.
The STDIO and SSE transports use SSE between the client and the proxy
server. SSE requires the client to initiate the MCP conversation
(event-stream) at the endpoint provided by the server. The endpoint
provided by the server must obey where the client sees the server,
rather than being assumed to be server-root `/message`.
The Streamable HTTP endpoint does not need the full proxy address
because the response is an event-stream directly, and does not use SSE.
* Inspect the stderr output of STDIO servers and attempt to assign an appropriate RFC 5424 Syslog Protocol level before sending a leveled logging message to the client
* Inspect the stderr output of STDIO servers and attempt to assign an appropriate RFC 5424 Syslog Protocol level before sending a leveled logging message to the client
- Add --transport and --server-url support to client/bin/start.js
- Pass transport configuration through server to client via /config endpoint
- Update client App.tsx to use defaultTransport and defaultServerUrl from server
- Ensure SSE and HTTP transport configs work properly from CLI
When running the inspector with command-line arguments (e.g.,
`npx @modelcontextprotocol/inspector node build/index.js arg1 arg2`),
the command and arguments were not being properly passed through to
the UI for pre-filling.
Changes:
- cli.ts now passes command and args to start.js
- start.js uses --command for the command and --args for arguments
- Server parses the new --command parameter
- /config endpoint returns correct values for UI pre-filling
This ensures the UI correctly displays the command and arguments
passed on the command line instead of showing old localStorage values.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Simplifies the startup flow by consolidating browser opening
in the client script rather than the start script for prod.
We were duplicating a lot of logging, making it easy for
logs to go out of sync - this is a proposal to consolidate:
- server only logs info about itself
- client only logs info about itself
To reduce the number of places we print connection information
to the user.
- Update client to read MCP_PROXY_PORT from URL parameters
- Update server to include port in displayed URL when non-default
- Update start scripts to pass SERVER_PORT to client
- Use DEFAULT_MCP_PROXY_LISTEN_PORT constant instead of magic numbers
This fixes the issue where the client couldn't connect to the proxy
when SERVER_PORT was set to a non-default value.
Per PR feedback from cliffhall:
- Changed PORT to SERVER_PORT in server/src/index.ts
- Changed PORT to CLIENT_PORT in client/bin/client.js
- Added parseInt() for CLIENT_PORT consistency
- Updated start.js to pass correct env var names
This improves clarity by using specific environment variables for
server and client ports instead of the generic PORT variable.
- Extract duplicated URL generation code into getClientUrl() helper function in start.js
- Replace all 127.0.0.1 references with localhost for consistency across codebase
- Update server to respect HOST environment variable for URL generation
- Remove 127.0.0.1 from default allowed origins in CORS configuration
- Update documentation to use localhost instead of 127.0.0.1
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Unified start.js to handle both dev and production modes with --dev flag
- Generate session token in parent process, pass via MCP_PROXY_TOKEN env var
- Enable browser auto-open even when authentication is enabled by including token in URL
- Auto-reloads now work seamlessly with persistent tokens across hot reloads
- Simplified npm scripts - dev and dev:windows now use the same unified script
- Better developer experience with consistent token handling
The token is generated once per session and remains stable through server/client
reloads, making development smoother while maintaining security.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Changed proxy authentication to use a custom header (X-MCP-Proxy-Auth) instead of the standard Authorization header. This prevents conflicts when the proxy needs to forward the client's Authorization header to upstream MCP servers.
- Updated client to send proxy auth token in X-MCP-Proxy-Auth header
- Updated server auth middleware to check X-MCP-Proxy-Auth header
- Applies to all transport types (SSE, stdio, streamable-http)
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Auto-open browser only works when DANGEROUSLY_OMIT_AUTH=true
- When auth is enabled (default), users must use the secure URL with token
- Server displays clear message that auto-open is disabled with auth
- Updates documentation to reflect this behavior
This improves UX by preventing the browser from opening without auth token,
forcing users to use the secure pre-filled URL instead.
- Add origin validation middleware to check Origin header
- Default allowed origins respect CLIENT_PORT environment variable
- Support ALLOWED_ORIGINS environment variable for additional origins
- Apply validation to all protected endpoints before auth check
- Return 403 Forbidden with clear message for invalid origins
- Add DNS Rebinding Protection section to README
This completes the security hardening by preventing malicious websites
from making requests to the local proxy server.
- Generate random session token on server startup using crypto.randomBytes
- Add authentication middleware requiring Bearer token for all sensitive endpoints
- Apply auth to /mcp, /stdio, /sse, and /message endpoints
- Display session token in console on startup
- Add DANGEROUSLY_OMIT_AUTH environment variable to disable auth for development
- Update README with authentication documentation
This prevents unauthorized access to the proxy server's ability to execute
local processes and connect to MCP servers.
- Change default binding from 0.0.0.0 (all interfaces) to 127.0.0.1 (localhost only)
- Add HOST environment variable to override binding address when needed
- Update console output to show actual binding address
- Document security change in README with warnings about binding to all interfaces
This prevents remote attackers from accessing the MCP Inspector proxy server,
which has the ability to execute local processes. The proxy should only be
accessible from the local machine unless explicitly configured otherwise.
* In server/src/index.ts
- slight format tweak of the Client <-> Proxy message so that the two messages will line up when displayed
* In server/src/mcpProxy.ts
- add reportedServerSession boolean initialized to false
- in transportToServer.onmessage,
- if reportedServerSession isn't set yet, report the sessionId if present on the transport, and then set reportedServerSession to true