Commit graph inspector/server/src
Author SHA1 Message Date
Felix Weinberger
d06f3b5ebc
feat: Enable auto-open with authentication and unify start scripts
- 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>
2025-06-18 10:23:03 +01:00
Jerome
fdae89ecbf
fix: use X-MCP-Proxy-Auth header for proxy authentication
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>
2025-06-14 13:07:02 +01:00
Jerome
3207959af0
Linting 2025-06-13 16:04:25 +01:00
Felix Weinberger
17740daaf5
fix: address @jenn-newton comments
- Add authentication and origin validation middleware to /config endpoint
- Implement timing-safe token comparison using crypto.timingSafeEqual()
- Add config read to initial env setup s.t. /config call is authenticated
2025-06-12 18:30:56 +01:00
Felix Weinberger
9dbd17343c
feat: disable auto-open when authentication is enabled
- 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.
2025-06-10 18:16:38 +01:00
Felix Weinberger
15ecb59a96
feat: add origin validation to prevent DNS rebinding attacks
- 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.
2025-06-10 18:16:35 +01:00
Felix Weinberger
111e282386
feat: add session token authentication to 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.
2025-06-10 18:16:28 +01:00
Felix Weinberger
e8e990987c
fix: bind to localhost by default to prevent DNS rebinding attacks
- 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.
2025-06-10 18:16:24 +01:00
cliffhall
c485e57a39 Add reporting of the Proxy <-> Server sessionId. It's only possible to get the session id for this leg of the proxy if it is a StreamableHttp connection.
* 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
2025-06-03 17:46:57 -04:00
Cliff Hall
789c90cc0b
Merge branch 'main' into normalize-connection-logging 2025-06-02 10:25:30 -04:00
Cliff Hall
7df0ac40c5
Merge pull request #470 from cliffhall/send-delete-on-streamable-http-disconnect
Send HTTP DELETE on streamable transport disconnect
2025-06-02 10:05:30 -04:00
Cliff Hall
021e6a423b
Merge branch 'main' into fix/header 2025-05-30 18:39:01 -04:00
cliffhall
b732ab4085 prettier 2025-05-30 17:51:22 -04:00
cliffhall
2df723804b Normalize the reporting of connection setup and connection errors. The logging is verbose and different for every server type. This is an attempt to make the console output cleaner and more readable.
* In server/index.js
  - in createTransport()
    - stringify query params to put them on one line
    - remove logging of transport creation (done in callers)
  - in /mcp POST handler
    - report POST request if session id is present
    - otherwise, report new StreamableHttp connection request
    - report creation of server transport
    - report creation of client transport
  - in /stdio GET handler
    - report new STDIO connection request
    - report creation of server transport
    - report creation of client transport
    - report 401 as authentication error without stack
    - in stderr data handler
      - if it includes "MODULE_NOT_FOUND"
        - report "Command not found"
        - remove transports
      - otherwise send to client as usual
  - in /sse GET handler
    - report SSE connection request
    - report 401 as authentication error without stack
    - report 404 as server that may not support SSE
    - report error with "ECONNREFUSED" as "Connection refused" without stack
    - only create, map, and proxy transports if serverTransport was successfully created
  - in /message POST handler
    - report received POST message

* In mcpProxy.ts
  - in onServerError()
    - if error message includes 404 OR error.cause includes ECONNREFUSED, report "Connection refused."
2025-05-30 17:13:53 -04:00
xiaoli
3510e1a561 fix: preserve capitalization in custom headers
Express converts all header names to lowercase, which prevents custom headers with uppercase characters from being properly passed to the target service. This fix ensures that custom headers preserve their original capitalization when forwarded through the proxy.
2025-05-30 21:34:40 +08:00
cliffhall
02aacb46a2 Send HTTP/DELETE when disconnecting client
* In server/src/index.ts
  - add delete handler for /mcp endpoint
    - gets the server transport for the sessionId
    - calls terminateSession on it
    - removes the webapp and server transports for the sessionId from the maps
    - returns status 200 to the client.

* In client/src/lib/hooks/useConnection.ts
  - import Transport
  - add useState for clientTransport, type Transport or null initialized to null
  - in connect() function
    - move creation of client transport down a ways, just before calling client.connect with it
    - immendiately efter calling client.connect, call setClientTransport with the connected transport (has to happen after, so that what's saved has the abort controller, etc. otherwise it doesn't work to save it prior.
    - in disconnect() function
      - immediately call clientTransport.terminateSession if transportType is "streamable-http"
      - setClientTransport to null
2025-05-29 19:54:36 -04:00
Xiaoli
ee8c29b3ad
Merge branch 'main' into fix/header 2025-05-29 23:30:11 +08:00
cliffhall
0c1962c2d0 prettier 2025-05-28 15:46:07 -04:00
cliffhall
9bc6bd725e Address [comment](https://github.com/modelcontextprotocol/inspector/pull/428/files/f04470ace7080f53233d1387e2dbb4d232bd5f7d#r2109509222) [by](https://github.com/modelcontextprotocol/inspector/pull/428/files/f04470ace7080f53233d1387e2dbb4d232bd5f7d#r2108137150) @olaservo 2025-05-28 13:46:58 -04:00
cliffhall
bc90f11dc8 Address [comment](https://github.com/modelcontextprotocol/inspector/pull/428/files/f04470ace7080f53233d1387e2dbb4d232bd5f7d#r2109509222) by @olaservo 2025-05-28 13:44:55 -04:00
Cliff Hall
692c863f5b
Revert "fix: handle the client disconnect so that the server does not crash." 2025-05-28 12:56:55 -04:00
xiaoli
2870441fea fix: fix review comments, again😉
- Remove unnecessary auth header name check
- Extract operations on headers into a function
2025-05-25 11:17:37 +08:00
cliffhall
f04470ace7 Allow multiple client connections to the MCP server, by making a unique server tranpsort for each web app transport.
* In server/src/index.ts
  - add serverTransports map

  - remove backingServerTransport var

  - in /mcp POST handler, when a new connection is being made
    - create a server transport
    - map the server transport using the session id from the web app connection
    - pass serverTransport to the mcpProxy instead of backingServerTransport

  - in /stdio GET handler, when a new connection is being made
    - create a server transport
    - map the server transport using the session id from the web app connection
    - pass serverTransport to the mcpProxy instead of backingServerTransport

  - in /sse GET handler, when a new connection is being made
    - create a server transport
    - map the server transport using the session id from the web app connection
    - pass serverTransport to the mcpProxy instead of backingServerTransport
2025-05-21 17:45:19 -04:00
Cliff Hall
efa4959ec4
Merge branch 'main' into main 2025-05-21 16:27:13 -04:00
Shane
a61a1b0df2
format update with prettier 2025-05-20 09:25:47 -07:00
xiaoli
13f736033a fix: fix review comments
- Avoid calling .lowerCase twice
- Keep 'Bearer ' prefix when header equals 'Authorization'
- Remove unnecessary Array type checks
2025-05-20 13:10:55 +08:00
xiaoli
618f24a9ac feat: support custom authorization headers, fix #395 2025-05-20 10:38:03 +08:00
ihrpr
2f6a9fca11
format 2025-05-19 19:03:22 +01:00
ihrpr
13eb077329
fix auth conect 2025-05-19 18:29:42 +01:00
Shane
7df1936b3c
fixed the error handling in async call 2025-05-18 23:33:19 -07:00
Shane
b9b3682350
format fix 2025-05-18 21:45:39 -07:00
Shane
fa236ea2c7
handle the case that client disconnects so that the server does not crash 2025-05-18 21:45:38 -07:00
cliffhall
5d0c3c48f6 Prettier 2025-04-24 12:01:02 -04:00
cliffhall
7b9cd1e74d In server/index.ts
- Add last-event-id to STREAMABLE_HTTP_HEADERS_PASSTHROUGH.
2025-04-24 11:39:48 -04:00
Shiv Deepak Muddada
1ec4e3b556 fix cors issue with accessing mcp-session-id header 2025-04-23 01:43:49 -07:00
cliffhall
6e4dcd6120 WIP: Attempting to proxy streamable-http connections. Inspector still works fine with STDIO and SSE servers.
* In index.ts,
  - refactor transport webAppTransports to be a map with the session id as key and transport as value.

* Implement /mcp GET and POST endpoints using StreamableHTTPServerTransport and doing the new session in the POST (opposite from SSE) handler.

* In package.json
  - update the SDK to 1.10.2

* In useConnection.ts
  - import StreamableHTTPClientTransport
    - NOTE: while we NEED to do this, it causes useConnection.test.ts to fail with " ReferenceError: TransformStream is not defined"
  - in connect method
    - instantiate the appropriate transport
2025-04-22 18:25:47 -04:00
cliffhall
3a2e248527 Prettier 2025-04-21 11:40:01 -04:00
cliffhall
e5f6524eb6 Fix support for streamable-http connections.
* In server/index.js
  - add get/post handlers for /mcp
  - amend console log on SSE connect, with deprecation message
  - add /stdio GET handler and refactored /sse GET handler to not also do stdio. Each transport has its own handler now
  - add appropriate headers to streamable-http request

* In /client/src/lib/hooks/useConnection.ts
  - in connect function
    - create server url properly based on new transport type.
2025-04-21 11:34:55 -04:00
Shiv Deepak Muddada
8213402185 attach auth headers to the streamable http request 2025-04-17 21:34:17 -07:00
Shiv Deepak Muddada
f43a9140ef run prettier-fix 2025-04-09 21:09:32 -07:00
Shiv Deepak Muddada
638603c0f3 add support for streamable http server 2025-04-09 20:47:53 -07:00
Pulkit Sharma
51c7eda6a6 Add MCP proxy address config support, better error messages 2025-04-01 19:21:19 +05:30
Abdelkader Boudih
6c67bf6d6d
Merge branch 'main' into main 2025-03-31 18:32:18 +00:00
Abdelkader Boudih
80f5ab1136
fix: typo 2025-03-31 18:28:40 +00:00
Cliff Hall
fb29ca0113
Merge branch 'main' into cleanup-old-transports 2025-03-31 12:36:34 -04:00
Abdelkader Boudih
da9dd09765
refactor: Update default ports for MCPI client and MPCP server
Changes the default ports used by the MCP Inspector client UI and the MCP Proxy server to avoid conflicts with common development ports and provide a memorable mnemonic based on T9 mapping.
2025-03-31 00:31:28 +00:00
cliffhall
054741be03 Run prettier. 2025-03-29 12:36:03 -04:00
cliffhall
1b754f52ca This fixes #214 where when the inspector is started, it can report that the inspector is up, when in fact it isn't because the address is already in use. It catches this condition, as well as the condition where the proxy server port is in use, reports it, and exits.
* In bin/cli.js
  - in the delay function, have the setTimeout return a true value.
  - try the server's spawnPromise call and within the try block, use Promise.race to get the return value of the first promise to resolve. If the server is up, it will not resolve and the 2 second delay will resolve with true, telling us the server is ok. Any error will have been reported by the server startup process, so we will not pile on with more output in the catch block.
  - If the server started ok, then we will await the spawnPromise call for starting the client. If the client fails to start it will report and exit, otherwise we are done and both servers are running and have reported as much. If an error is caught and it isn't SIGINT or if process.env.DEBUG is true then the error will be thrown before exiting.
* In client/bin/cli.js
  - add a "listening" handler to the server, logging that the MCP inspector is up at the given port
  - Add an "error" handler to the server that reports  that the client port is in use if the error message includes "EADDRINUSE", otherwise throw the error so the entire contents can be seen.
* In server/src/index.ts
  - add a "listening" handler to the server, logging that the Proxy server is up at the given port
  - Add an "error" handler to the server that reports  that the server port is in use if the error message includes "EADDRINUSE", otherwise throw the error so the entire contents can be seen.
* In package.json
  - in preview script
    - add --port 5173 to start the client on the proper port. This was useful in getting an instance of the client running before trying the start script. otherwise it starts on 4173
2025-03-28 11:59:21 -04:00
Simon Knott
353d6b549b
fix: clean up previous transport processes 2025-03-27 09:52:35 +01:00
lloydzhou
aeaf32fa45 fix 2025-03-15 12:58:11 +08:00