{"token_count": 3672}

# Log In to OAuth-Protected MCP Servers

Some remote MCP servers require an OAuth access token issued by their own authorization server, separate from your Teleport login. The `tsh mcp login` command runs the MCP authorization flow in your browser, stores the resulting tokens on your workstation, and makes `tsh` attach them to every request it sends to that MCP server.

Teleport still authenticates you and enforces your roles, including which MCP tools you can call. The OAuth token only satisfies the MCP server itself.

## How it works

When you run `tsh mcp login`, `tsh` first sends an unauthenticated MCP `initialize` request to the server through Teleport. If the server accepts it, no login is needed and the command exits. If the server answers with HTTP `401`, `tsh` continues:

- It finds the authorization server named in the MCP server's OAuth protected resource metadata, then reads that authorization server's metadata.
- It registers an OAuth client named `Teleport tsh` using dynamic client registration, unless you supply a pre-registered client with `--client-id`.
- It opens your browser to the provider's authorization page and listens on a loopback callback address, `http://127.0.0.1:<port>/callback` by default, for the result. You have three minutes to finish authorizing.
- It exchanges the authorization code for tokens and saves them in `$TELEPORT_HOME/mcp/<proxy>/<user>/<cluster>/<name>.oauth.json`, readable only by your user. `TELEPORT_HOME` defaults to `~/.tsh`.

Requests to the MCP server and its protected resource metadata travel through the Teleport Application Service, so the MCP server does not need to be reachable from your workstation. Requests to the authorization server go directly from your workstation, or through the proxy set in `HTTPS_PROXY`. The authorization server must use HTTPS and resolve to public IP addresses; `tsh` refuses to contact OAuth endpoints on loopback, private, link-local, or other non-public addresses.

After you log in, `tsh mcp connect` and `tsh proxy mcp` send the stored access token in the `Authorization` header. When the access token expires, `tsh` refreshes it. If the refresh fails, `tsh` opens your browser to log in again using the same client and redirect URI as your original login.

Stored credentials are bound to the MCP server's URI and to the authorization server that issued them. If your Teleport administrator changes the URI of the MCP server, run `tsh mcp login` again.

## Prerequisites

- A running Teleport (v18.11.1 or higher) cluster accessible at a hostname with a valid TLS certificate. If you want to get started with Teleport, [sign up](https://goteleport.com/signup) for a free trial or [set up a demo environment](https://goteleport.com/docs/get-started/deploy-community.md).

- The `tsh` client.

  Installing `tsh` client

  1. Determine the version of your Teleport cluster. The `tsh` client must be at most one major version behind your Teleport cluster version. Send a GET request to the Proxy Service at `/v1/webapi/find` and use a JSON query tool to obtain your cluster version. Replace teleport.example.com:443 with the web address of your Teleport Proxy Service:

     **Mac/Linux**

     ```
     $ TELEPORT_DOMAIN=teleport.example.com:443
     $ TELEPORT_VERSION="$(curl -s https://$TELEPORT_DOMAIN/v1/webapi/find | jq -r '.server_version')"
     ```

     **Windows - Powershell**

     ```
     $ $TELEPORT_DOMAIN = "teleport.example.com:443"
     $ $TELEPORT_VERSION = (Invoke-RestMethod -Uri "https://${TELEPORT_DOMAIN}/v1/webapi/find").server_version
     ```

  2. Follow the instructions for your platform to install `tsh` client:

     **Mac**

     Download the signed macOS .pkg installer for Teleport, which includes the `tsh` client:

     ```
     $ curl -O https://cdn.teleport.dev/teleport-${TELEPORT_VERSION?}.pkg
     ```

     In Finder double-click the `pkg` file to begin installation.

     ---

     DANGER

     Using Homebrew to install Teleport is not supported. The Teleport package in Homebrew is not maintained by Teleport and we can't guarantee its reliability or security.

     ---

     **Windows - Powershell**

     ```
     $ curl.exe -O https://cdn.teleport.dev/teleport-v$TELEPORT_VERSION-windows-amd64-bin.zip
     Unzip the archive and move the `tsh` client to your %PATH%
     NOTE: Do not place the `tsh` client in the System32 directory, as this can cause issues when using WinSCP.
     Use %SystemRoot% (C:\Windows) or %USERPROFILE% (C:\Users\<username>) instead.
     ```

     **Linux**

     All of the Teleport binaries in Linux installations include the `tsh` client. For more options (including RPM/DEB packages and downloads for i386/ARM/ARM64) see our [installation page](https://goteleport.com/docs/installation/single-machine.md).

     ```
     $ curl -O https://cdn.teleport.dev/teleport-v${TELEPORT_VERSION?}-linux-amd64-bin.tar.gz
     $ tar -xzf teleport-v${TELEPORT_VERSION?}-linux-amd64-bin.tar.gz
     $ cd teleport
     $ sudo ./install
     Teleport binaries have been copied to /usr/local/bin
     ```

  Connecting with TLS routing disabled

  This guide's commands assume your Teleport cluster uses TLS routing (`proxy_listener_mode: multiplex`), where the `tsh` client reach every Teleport service through the Proxy Service's web address on port `443`. If you're not sure whether this applies to your cluster, check with whoever manages it.

  If your cluster uses separate listener ports instead, adjust ports as follows:

  - **`tsh` commands** (e.g., `tsh login --proxy=...`): continue using the Proxy Service web address on port `3080` (or `443` if behind a load balancer). Do not change these to port `3025`.

  - **Direct `tctl` or Auth Service API commands**: use port `3025` for the Auth Service gRPC listener:

    ```
    $ tctl status --auth-server=teleport.example.com:3025
    ```

* An MCP server that uses streamable-HTTP transport, requires OAuth, and is enrolled in Teleport. See [MCP Access with Streamable-HTTP MCP Server](https://goteleport.com/docs/enroll-resources/mcp-access/enrolling-mcp-servers/streamable-http.md).
* A web browser on the machine where you run `tsh`. If you run `tsh` over SSH, see [Troubleshooting](#the-login-times-out) to finish the login in your local browser.
* HTTPS access from your workstation to the MCP server's OAuth authorization server.

## Step 1/2. Log in to the MCP server

Log in to your Teleport cluster and find the name of the MCP server, assigning teleport.example.com to the web address of your Teleport Proxy Service and my\_user to your Teleport username:

```
$ tsh login --proxy=teleport.example.com --user=my_user
$ tsh mcp ls
```

Log in to the MCP server, replacing my-mcp-server with its name:

```
$ tsh mcp login my-mcp-server
Requesting scopes required by the MCP server: mcp:read mcp:write
Registering OAuth client "Teleport tsh" for MCP server "my-mcp-server"...
Opening browser for authorization. If it does not open, visit:

  https://auth.example.com/authorize?client_id=...

Authorization complete. Tokens stored in /home/alice/.tsh/mcp/teleport.example.com/alice/teleport.example.com/my-mcp-server.oauth.json.
MCP server "my-mcp-server" is ready — restart your MCP clients if already running.
```

Approve the request in your browser. When the browser shows "Login complete", return to the terminal.

## Step 2/2. Connect your MCP client

---

WARNING

Do not use your MCP client's built-in OAuth login for a Teleport MCP server, and do not set an `Authorization` header with `-H` on `tsh mcp connect` or `--header` on `tsh mcp config`. That header replaces the credentials stored by `tsh mcp login`.

---

If your MCP client runs `tsh mcp connect`, you are done. This is the setup that `tsh mcp config` creates, and `tsh mcp connect` uses the stored credentials automatically. Restart the MCP client if it was already running. If you have not configured your MCP client yet, follow [Access MCP Servers with Teleport](https://goteleport.com/docs/connect-your-client/model-context-protocol/mcp-access.md).

Use `tsh proxy mcp` only if your MCP client can't launch `tsh mcp connect` and must connect over streamable HTTP. Start it after you log in, or restart it if it was already running:

```
$ tsh proxy mcp my-mcp-server -p 8888
```

## Log out of an MCP server

Remove the stored credentials for one MCP server:

```
$ tsh mcp logout my-mcp-server
```

Omit the name to remove the credentials for every MCP server in the current cluster. `tsh logout` also removes MCP OAuth credentials along with your Teleport credentials.

## `tsh mcp login` flags

By default, `tsh mcp login` needs no flags. Use them when the OAuth provider does not support dynamic client registration or expects particular values.

| Flag              | Purpose                                                                                                                                                                                                                                 |
| ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `--client-id`     | Uses an OAuth client that is already registered with the provider instead of registering a new one.                                                                                                                                     |
| `--client-secret` | Prompts for the secret of a confidential pre-registered client. Requires `--client-id`. The secret is stored with the tokens so `tsh` can refresh them.                                                                                 |
| `--callback-port` | Listens on a fixed port, making the redirect URI `http://127.0.0.1:<port>/callback`. Set it to match the redirect URI registered for your client.                                                                                       |
| `--redirect-uri`  | Sets the exact loopback redirect URI, such as `http://localhost:3118/callback`. Use it when the registered redirect URI uses `localhost` or another loopback address instead of `127.0.0.1`. Cannot be combined with `--callback-port`. |
| `--oauth-scope`   | Sets the OAuth scopes to request. Separate scopes with commas or spaces, or repeat the flag. Without it, `tsh` requests the scopes named in the server's `401` challenge, then the scopes listed in its protected resource metadata.    |
| `--browser`       | Set to `none` to print the authorization URL instead of opening a browser.                                                                                                                                                              |

To log in with a pre-registered client, register `http://127.0.0.1:3118/callback` as a redirect URI with the provider and run:

```
$ tsh mcp login my-mcp-server --client-id=client-id --callback-port=3118
```

If the client is registered with `http://localhost:3118/callback` instead, use `--redirect-uri`:

```
$ tsh mcp login my-mcp-server --client-id=client-id --redirect-uri=http://localhost:3118/callback
```

Add `--client-secret` to either command if the client is confidential. `tsh` prompts for the secret so it does not end up in your shell history.

Later refreshes and automatic logins reuse the client ID, secret, redirect URI, and scopes from this login, so you only pass these flags once.

## Troubleshooting

Add `--debug` to `tsh mcp login` for more detail when a step fails.

### The provider does not support dynamic client registration

```
The MCP server's OAuth provider does not support dynamic client registration.

```

The authorization server does not publish a registration endpoint. Register an OAuth client with the provider, or use a client ID the provider publishes for MCP clients, then log in with `--client-id` and `--callback-port` or `--redirect-uri` as shown in [`tsh mcp login` flags](#tsh-mcp-login-flags).

### The provider rejected the client registration

```
The MCP server's OAuth provider rejected the client registration.

```

Some providers only let an approved set of MCP clients register. Ask the provider's administrator to approve Teleport or to issue a client ID, then log in with `--client-id`.

### The provider reports a redirect URI mismatch

Providers compare the redirect URI exactly, including the port and whether the host is `127.0.0.1` or `localhost`. Without `--callback-port` or `--redirect-uri`, `tsh` picks a random port, which a pre-registered client usually does not allow. Find the redirect URI registered for your client and pass it with `--redirect-uri`, or pass its port with `--callback-port` if it uses `127.0.0.1`.

### The login times out

```
timed out waiting for the browser authorization to complete

```

The browser did not reach the callback address within three minutes. This happens when the browser runs on a different machine from `tsh`, for example when you run `tsh` over SSH. The callback address is a loopback address on the machine running `tsh`, so forward a fixed port to it, replacing remote-host with the machine where you run `tsh`:

```
$ ssh -L 3118:127.0.0.1:3118 remote-host
$ tsh mcp login my-mcp-server --callback-port=3118 --browser=none
```

Open the printed authorization URL in your local browser.

### The callback port is already in use

```
listen tcp 127.0.0.1:3118: bind: address already in use

```

Another process, often another `tsh mcp login`, is listening on the callback port. Stop that process or choose a different port. If you use a pre-registered client, the new port must also be registered with the provider.

### An OAuth endpoint uses a prohibited network address

```
OAuth authorization endpoint resolves to a prohibited network address

```

`tsh` only contacts authorization servers over HTTPS at public IP addresses. Authorization servers on private networks or served over plain HTTP are not supported.

### The MCP client asks you to log in

```
Authentication with MCP server "my-mcp-server" is required or has expired. Run `tsh mcp login my-mcp-server` in a terminal, complete authorization in the browser, then retry the request.

```

```
MCP server "my-mcp-server" rejected the request with HTTP 401. Do not use the MCP client's built-in OAuth login for a Teleport endpoint.

```

`tsh` has no usable credentials for the MCP server, or could not refresh them and could not open a browser to log in again. Run `tsh mcp login` and retry the request in your MCP client.

### `tsh` says login is not required

```
MCP server "my-mcp-server" accepted an unauthenticated request, so OAuth login is not required.

```

The MCP server accepted an `initialize` request without a token, so `tsh` did not start an OAuth flow. Connect to the server without logging in.

### The MCP server does not use HTTP transport

```
MCP server "my-mcp-server" does not use HTTP transport; OAuth login only applies to HTTP MCP servers

```

`tsh mcp login` only applies to MCP servers enrolled with streamable-HTTP transport, whose URI starts with `mcp+http://` or `mcp+https://`. Stdio and SSE MCP servers do not use MCP OAuth.

## Next steps

- [Access MCP Servers with Teleport](https://goteleport.com/docs/connect-your-client/model-context-protocol/mcp-access.md)
- [MCP Access Control](https://goteleport.com/docs/enroll-resources/mcp-access/rbac.md)
- [`tsh` CLI reference](https://goteleport.com/docs/reference/cli/tsh.md)
