Files
mcp-use__mcp-use/docs/inspector/connection-settings.mdx
Andrew Khadder e17cd7b8ca Canary (#2216)
* feat(client): support mixed OAuth servers

* fix(inspector): pause mixed-auth tool calls

* Revert "fix(inspector): pause mixed-auth tool calls"

This reverts commit 9bac9ddfe7.

* chore: finalize mixed OAuth changeset

* docs: explain mixed OAuth client flows

* fix: bound mixed auth metadata discovery

* docs(server): add runnable mixed oauth example

* fix(inspector): recover stale local connections

* fix(inspector): resume tools after mixed auth

* fix: address mixed auth review feedback

* fix(inspector): scope mixed auth retries

* test(inspector): remove jsdom-only regressions

* chore: enter canary prerelease mode

* chore(typescript): version packages (canary)

* fix(inspector): stream v2 subscription acknowledgements

* fix(client): discover mixed auth after ready

* test(client): preserve mocked connection compatibility

* fix(client): defer mixed auth discovery until ready

* fix(client): discover mixed auth after ready paint

* perf(client): expose tools before auxiliary inventories

* fix(client): refresh mixed auth discovery after reconnect

* chore(typescript): version packages (canary)

* fix(client): make codeMode custom executor functions actually work (#2123)

* fix(client): make codeMode custom executor functions actually work

`_ensureCodeExecutor()` handled a function-valued `codeMode.executor` by
assigning `this._customCodeExecutor` and then throwing
"Custom executor function should be handled in executeCode". Since
`executeCode()` read that field *before* calling `_ensureCodeExecutor()`,
and only `_ensureCodeExecutor()` ever populated it, the first
`executeCode()` call always rejected and only the second succeeded.
`searchTools()` had no such fallback, so it rejected on every call --
including via the `search_tools` meta tool on `CodeModeConnector`. Because
`_codeExecutor` stayed null, `close()` also skipped executor cleanup.

Route function executors through a new `FunctionCodeExecutor` adapter so
they participate in the normal executor lifecycle, and drop the now-unused
`_customCodeExecutor` field and its pre-check in `executeCode()`.

Also fix `detail_level` validation in `CodeModeConnector.callTool`: it
used `detailLevel in ["names", "descriptions", "full"]`, and `in` tests
property keys, so an array literal only has `"0"`/`"1"`/`"2"`/`"length"`.
Every valid detail level failed the guard and was silently rewritten to
`"full"`, so an agent requesting `"names"` received full input schemas for
every tool. Replaced with a `Set` membership test.

Adds 10 unit tests: first-call success, timeout forwarding, `searchTools`,
`close()` cleanup, the `BaseCodeExecutor` instance path, each valid
`detail_level`, and the unknown/omitted fallbacks.

Closes #2122

* fix(client): preserve `this` for custom executors, tighten tests, document the contract

Addresses review feedback on the code-mode custom-executor fix.

The `this` binding regression is real -- I measured it both ways. On the
pre-fix code the executor function was invoked as
`this._customCodeExecutor(code, timeout)`, so a non-arrow function saw the
`MCPClient` as its `this`; through the new adapter it saw the
`FunctionCodeExecutor`. `FunctionCodeExecutor.execute` now calls
`this.fn.call(this.client, ...)` so a `function`-form executor keeps the same
context it had before, and a test asserts it.

Two tests were weaker than their titles claimed:

- the `searchTools` test ran against an empty client, so it only proved the
  call did not throw. It now registers a stub session with one tool and
  asserts the full `{ meta, results }` payload, including the namespace and
  the tool's `input_schema`.
- the `close()` test only asserted the promise resolved, which would pass
  even if cleanup were skipped. It now spies on the resolved executor's
  `cleanup()` and asserts it ran exactly once.

Documentation: the API reference listed one "Custom" executor row saying to
implement `execute()` + `cleanup()`, which is only true for the
`BaseCodeExecutor` subclass form. Split it into separate class and function
rows, add the `CodeExecutorFunction` signature to the types block, and add a
worked example to the code-mode guide (current and v2) stating the `this`
context and that the function owns its runtime cleanup.

* docs(client): use a non-arrow custom executor in the code-mode example

The example demonstrated the documented `this` context with an arrow function,
which has lexical `this` and therefore cannot observe it. Switched to
`async function (this: MCPClient, code, timeout)` and had it actually call
`this.getServerNames()`, so the snippet exercises the contract it describes.
Type-checked the snippet shape against the real `MCPClient` type with
`tsc --noEmit` before committing.

Also reworded the surrounding paragraph: the `this` binding is specific to the
non-arrow form, whereas the cleanup-ownership rule applies to every custom
function.

* docs(client): drop v1 code-mode custom executor docs

This change is v2-only; keep the custom-executor contract on the v2 docs path.

* chore(typescript): version packages (canary)

* fix(create-app): sanitize the npm name for named projects, not just "." (#2209)

deriveProjectInfo only ran sanitizePackageName on the "." branch. A named
project passed the raw argument straight through as packageName, which is
then written into package.json and substituted into the template's index.ts.

The CLI rejects path separators, ".." and a few protected names, but not
spaces, quotes or capitals, so `create-mcp-use-app 'My "App"'` emitted
`name: "My "App""` in index.ts, which is not valid TypeScript.

Sanitize on both branches. The directory still uses the name as typed.

* chore(typescript): version packages (canary)

* fix: enable skills tab after HMR (#2220)

* chore(typescript): version packages (canary)

* fix(create-app): strip leading underscores when sanitizing a package name (#2221)

sanitizePackageName removed leading dots and dashes but not underscores, so
create-mcp-use-app _foo wrote "name": "_foo" into package.json.

npm publish rejects that outright:

  npm error code EINVALIDPACKAGENAME
  npm error Invalid package name "_foo": name cannot start with an underscore.

Widen the leading-character class to [._-] and cover both the sanitizer and a
named project starting with an underscore.

Closes #2219

* chore(typescript): version packages (canary)

* fix(client): surface auth for protected operations

* fix(inspector): resume mixed-auth chat tools (#2226)

* chore(typescript): version packages (canary)

* fix: harden stable mixed-auth flows

---------

Co-authored-by: Enrico <2827496+tonxxd@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: LHMQ878 <72402929@cityu-dg.edu.cn>
Co-authored-by: Ayaan Gazali <ayaangazali.work@gmail.com>
2026-08-11 12:52:52 +02:00

113 lines
5.0 KiB
Plaintext

---
title: "Connection settings"
description: "Choose how the Inspector connects to an MCP server."
icon: "settings"
---
{/* TODO: Add Inspector media when a screenshot or short clip would clarify the workflow. */}
Most servers work with only a transport and URL. Change connection settings when the browser cannot reach the server directly, when you want clearer names for saved servers, when OAuth needs pre-registered credentials, or when long-running tools need more time.
## Choose Auto, Direct, or Via Proxy
The Inspector uses **Auto** mode by default: it tries a direct browser connection first, then falls back to the configured Inspector proxy if direct access fails because of CORS or network policy.
| Connection mode | Use it when | Avoid it when |
| --- | --- | --- |
| **Auto** | You want the Inspector to try Direct first and fall back to the proxy when needed. | You need to test one specific connection path. |
| **Direct** | The server is local, public, or reachable from your browser. | The browser blocks the request because of CORS or network policy. |
| **Via Proxy** | The browser is blocked by CORS, or you need to test proxy behavior. | The server works directly; proxying adds another moving part. |
## Name saved servers
Set a display name when several saved servers have similar URLs.
Changing only the display name updates labels in the dashboard, server list, header, command palette, and server picker. It does not reconnect the server or clear auth tokens.
## Add headers only when the server requires them
Use custom headers for server-specific requirements such as bearer tokens, API keys, or version headers.
Header values are used for the live connection only. They are intentionally not
saved or restored after a reload, so supply them again at runtime. Prefer OAuth
when the server supports it.
<Warning>
Copy Config includes current form values. Remove OAuth tokens, API keys, and
other secrets before sharing exported configuration.
</Warning>
## Configure OAuth
By default the inspector relies on Dynamic Client Registration (DCR), so no credentials are needed. Use the Authentication dialog when the upstream auth server doesn't expose `registration_endpoint` (common for proxy-mode servers fronting Slack, WorkOS, or GitHub). OAuth client secrets are runtime-only and are not restored after a reload.
| Field | When to set it |
| --- | --- |
| Client ID | Use a pre-registered OAuth client instead of DCR. |
| Client Secret | Use a confidential client; the SDK switches token endpoint auth away from `none`. |
| Scope | Request a provider-specific space-separated scope list. |
When a server protects the whole connection, it enters `pending_auth`. Click
**Authenticate**, complete the provider flow, and return to the Inspector. If a
popup is blocked, use the open-auth-page fallback link.
Mixed-auth servers behave differently: the anonymous connection remains
`ready`, and the Inspector shows **This server is using mixed auth** with an
**Authenticate** action. Public operations remain available. You can authenticate
up front, or wait for a protected tool, resource, or prompt to return a
wire-level OAuth challenge and then authenticate.
The classification comes from RFC 9728 protected-resource metadata discovered
by the official MCP SDK after a successful anonymous connection. The Inspector
does not use host-specific rules or interpret tool-level `isError` text as an
OAuth challenge.
Browser OAuth session values are encrypted at rest with AES-256-GCM. The
non-extractable origin key is kept in IndexedDB, while versioned ciphertext
envelopes remain in localStorage so popup storage events and reload persistence
continue to work.
## Configuration Import/Export
Use **Copy Config** to export the current connection form as JSON. Paste JSON into the URL field to populate the form in another Inspector instance.
Example configuration:
```json
{
"url": "https://mcp.example.com/mcp",
"transportType": "http",
"connectionMode": "auto",
"headers": {
"Authorization": "Bearer token123"
},
"requestTimeout": 10000,
"resetTimeoutOnProgress": true,
"maxTotalTimeout": 60000,
"oauth": {
"clientId": "your-client-id",
"clientSecret": "your-client-secret",
"scope": "read write"
}
}
```
<Note>
The paste detection only works in the URL field. Remove OAuth tokens, API keys, and other secrets before sharing a copied config.
</Note>
## URL and tabs
The Inspector keeps the active tab in the page URL (`?tab=...`). Switching tabs updates the query string so a refresh or shared link restores the same view.
## Tune timeouts for long work
Use timeout settings only when a valid tool call or resource read needs more time.
| Setting | Default | What it controls |
| --- | --- | --- |
| Request timeout | `10000` ms | Time allowed for one request. |
| Maximum total timeout | `60000` ms | Total time allowed across retries and progress updates. |
If a request times out, first confirm the server eventually responds. Then raise the timeout to match the expected tool runtime.