> For the complete documentation index, see [llms.txt](https://docs.ovaledge.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.ovaledge.com/release8.1/mcp-server/deployment-options/remote-mcp.md).

# Remote MCP

Remote MCP (HTTP) enables MCP tools to run over HTTP by using FastAPI and Mangum with the entrypoints/lambda\_handler.py entry point. The deployment supports multiple authentication modes, configured via the AUTH\_MODE environment variable at process startup. This guide describes the supported authentication modes, deployment configuration, local HTTP setup, validation procedures, and client integrations for Cursor, VS Code, GitHub Copilot, and Claude Code.

The article also provides guidance on configuring secure communication, validating token-exchange workflows, and deploying the Remote MCP service in both local and cloud environments.

## Prerequisites

Before configuring Remote MCP (HTTP), ensure that the following prerequisites are available:

* Python and Poetry are installed.
* FastAPI, Mangum, and project dependencies are installed.
* Access to the OvalEdge environment is available.
* Valid OvalEdge user token and secret are available for remote\_credentials authentication.
* HTTPS or a TLS termination proxy is configured for protected routes.
* AWS SAM and Lambda permissions are available for cloud deployment.
* Environment variables are configured in the .env file or exported through the shell.
* The repository is cloned locally.

## Authentication Modes

The Remote MCP deployment supports multiple authentication modes.&#x20;

| Authentication Mode | Client Credentials                         | OAuth or Discovery Routes                        | Description                                                                                                                 |
| ------------------- | ------------------------------------------ | ------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------- |
| remote\_credentials | `X-OvalEdge-Token` and `X-OvalEdge-Secret` | Minimal /.well-known/\* stubs (no browser OAuth) | Recommended authentication mode for production deployments. The server caches OvalEdge JWT tokens based on credential keys. |

The following routes are shared across all authentication modes:

* `POST/mcp`
* `GET/health`
* `GET/`

All environment variables are documented in the `.env.example` file below.

```
# =============================================================================
# OvalEdge MCP Configuration
# =============================================================================
# Choose your mode via AUTH_MODE, then fill only that mode's section.
# - Local MCP  (stdio):  poetry run oe-mcp-local
# - Remote MCP (HTTP):   uvicorn entrypoints.lambda_handler:app
# =============================================================================
# Shared (used by both Local and Remote MCP)
# =============================================================================
OVALEDGE_BASE_URL=http://localhost:8080/ovaledge
OVALEDGE_TIMEOUT_SECONDS=30
OVALEDGE_LOG_HTTP_REQUESTS=true
OVALEDGE_MAX_RETRIES=3
OVALEDGE_RETRY_BACKOFF_SECONDS=0.5
# Optional: when token/generate returns 200 with empty body, read JWT from this header.
# OVALEDGE_TOKEN_EXCHANGE_FALLBACK_HEADER=X-Your-Token-Header
# =============================================================================
# Mode Selection
# =============================================================================
# local                 -> stdio MCP, uses OVALEDGE_USER_TOKEN + OVALEDGE_USER_SECRET
# remote                -> HTTP MCP, uses OAuth/OIDC access tokens (Bearer)
# remote_credentials    -> HTTP MCP, per-user OvalEdge token+secret in request headers
AUTH_MODE=local
# =============================================================================
# Local MCP Section (required when AUTH_MODE=local)
# =============================================================================
# Auth scheme used for outbound OvalEdge API calls in local mode.
# Usually this should be jwt when using OvalEdge-issued tokens.
OVALEDGE_HTTP_AUTH_SCHEME=jwt
OVALEDGE_USER_TOKEN=your-ovaledge-user-token
OVALEDGE_USER_SECRET=your-ovaledge-user-secret
# =============================================================================
# Remote MCP Section (required when AUTH_MODE=remote)
# =============================================================================
# WIP: OAuth/OIDC remote mode is not fully validated end-to-end yet. Prefer
# AUTH_MODE=remote_credentials or AUTH_MODE=local until OAuth flows are stable.
#
# Issuer base for MCP discovery proxy. JWT validation uses access token ``iss``.
# Discovery:
#   {OAUTH_ISSUER}/.well-known/openid-configuration
#   then {OAUTH_ISSUER}/.well-known/oauth-authorization-server
OAUTH_ISSUER=https://integrator-3017728.okta.com/oauth2/default
# Resource identifier; must match access token ``aud``.
OAUTH_AUDIENCE=api://ovaledge-mcp
# Public base URL of this MCP server (registration_endpoint in discovery).
# Local:  MCP_PUBLIC_BASE_URL=http://127.0.0.1:8000
# Lambda: MCP_PUBLIC_BASE_URL=https://xxxx.execute-api.region.amazonaws.com
MCP_PUBLIC_BASE_URL=http://127.0.0.1:8000
# If true, skip POST /api/user/token/generate and forward validated IdP token to OvalEdge.
OVALEDGE_REMOTE_FORWARD_IDP_TOKEN=true
# Auth scheme for forwarded IdP token in remote mode (commonly Bearer).
# Change only when AUTH_MODE=remote.
# OVALEDGE_HTTP_AUTH_SCHEME=Bearer
# Optional — default us-east-1
AWS_REGION=us-east-1
# Optional — override MCP product strings
# MCP_SERVER_NAME=OvalEdge MCP Server
# MCP_SERVER_VERSION=0.1.0
# =============================================================================
# Remote MCP — per-user credentials (required when AUTH_MODE=remote_credentials)
# =============================================================================
# Clients send these on every POST /mcp (and other protected routes):
#   X-OvalEdge-Token: <OvalEdge user token>
#   X-OvalEdge-Secret: <OvalEdge user secret>
# The server exchanges them for an OvalEdge JWT, caches per credential key in-process,
# and refreshes ~60 seconds before JWT expiry. Use HTTPS only.
#
# AUTH_MODE=remote_credentials
# OVALEDGE_HTTP_AUTH_SCHEME=jwt
# CREDENTIALS_CACHE_MAX_ENTRIES=10000
#
# Cursor / local HTTP MCP: set false so GET /mcp is registered (SSE fallback after Streamable HTTP).
# Lambda / production: leave default true (stateless POST/DELETE only).
# MCP_HTTP_STATELESS=false
```

### Remote Credentials Authentication

The `remote_credentials` authentication mode uses request headers to validate credentials.&#x20;

#### **Authentication Workflow**

The middleware performs the following actions:

1. Reads the `X-OvalEdge-Token` and `X-OvalEdge-Secret` headers.
2. Exchanges the credentials with OvalEdge.
3. Caches JWT tokens by using a digest of the token and secret.
4. Sets `current_oe_jwt` and `current_oe_credential_cache_key` for the request.

#### **HTTPS Enforcement**

Protected routes require HTTPS communication.

The application validates HTTPS by using one of the following methods:

* `request.url.scheme == "https"`
* `X-Forwarded-Proto: https`

If the request uses plain HTTP without the required header, the application returns the following response:

```
400 tls_required
```

#### **Cache Handling**

If OvalEdge APIs return a downstream 401 response:

1. The application removes the cached credential entry.
2. The MCP client retries the request with the same headers.
3. The application performs a new credential exchange.

#### **Configuration Parameter**&#x20;

The cache limit is controlled by the following parameter:

```
CREDENTIALS_CACHE_MAX_ENTRIES
```

#### **Implementation Files**

The `remote_credentials` implementation uses the following files:

* `server/auth/middleware.py`
* `server/auth/credentials_cache.py`
* `server/auth/token_exchange.py`
* `server/auth/context.py`
* `server/client.py`
* `server/constants.py`&#x20;

### Application Entry Point and Deployment

The application entry point is:

```
entrypoints/lambda_handler.py
```

The application behavior changes according to the configured authentication mode:

* `remote` mode loads the OAuth routers.
* `remote_credentials` mode loads `server/auth/remote_credentials_discovery.py`.

### MCP HTTP Stateless Configuration&#x20;

The `MCP_HTTP_STATELESS` parameter controls HTTP behavior.&#x20;

<table><thead><tr><th width="174">Parameter Value</th><th>Description</th></tr></thead><tbody><tr><td>true </td><td>Recommended for AWS Lambda deployments. </td></tr><tr><td>false </td><td>Enables GET/mcp registration for SSE fallback support. Required for Cursor and similar HTTP MCP clients. </td></tr></tbody></table>

{% hint style="info" %}
If `MCP_HTTP_STATELESS=false` is not configured for supported clients, the application may return an incorrect `Content-Type` response during `GET` requests.
{% endhint %}

### AWS Lambda and SAM Deployment

The SAM template file is located at:&#x20;

```
infra/template.yaml
```

#### **Supported Parameters**

The template supports the following parameters:

* `AuthMode`
* `OAuthIssuer`
* `OAuthAudience`
* `McpHttpStateless`&#x20;

#### **Deployment Procedure**

Perform the following steps to deploy the application:

1. Navigate to the repository root directory.
2. Configure the `OVALEDGE_BASE_URL` environment variable.
3. Run the deployment script.

   ```
   infra/template.yaml
   ```

To display deployment help information, run the following command:

```
./scripts/deploy.sh --help
```

For detailed deployment instructions, refer to:

```
infra/DEPLOY.md
```

### Local HTTP Configuration

&#x20;Follow these steps to configure the application locally using uvicorn.

#### Configure Environment Variables

* Configure the following environment variables:

  ```
  export AUTH_MODE=remote_credentials
  export OVALEDGE_BASE_URL=<OVALEDGE_BASE_URL>
  export OVALEDGE_HTTP_AUTH_SCHEME=jwt
  ```

#### **Start the HTTP Application**

* Navigate to the repository directory and start the application.

  ```
  cd /path/to/oe_mcp
  export AUTH_MODE=remote_credentials
  export MCP_HTTP_STATELESS=false
  poetry run uvicorn entrypoints.lambda_handler:app --host 127.0.0.1 --port 8000
  ```

### Local Validation and Testing

Protected routes require HTTPS communication or the `X-Forwarded-Proto: https` header.

Plain `http://127.0.0.1` requests without the required header return the following response:

```
400 tls_required
```

#### **Configure OvalEdge Credentials**

* Export the required credentials before validation.

  ```
  export AUTH_MODE=remote_credentials
  export OVALEDGE_USER_TOKEN='your-token'
  export OVALEDGE_USER_SECRET='your-secret'
  ```

#### Validate Token Exchange

* Run the validation script.

  ```
  poetry run python scripts/validate_remote_mcp.py --credentials
  ```

#### **Validate Health Endpoint**

* Run the following command:

  ```
  curl -sS -D - http://127.0.0.1:8000/health \
  -H 'X-Forwarded-Proto: https'
  ```
* Expected result:
  * HTTP `200` response

#### **Validate MCP Initialization**

* Run the following command:

  ```
  curl -sS -D - http://127.0.0.1:8000/mcp \
  -H 'X-Forwarded-Proto: https' \
  -H 'X-OvalEdge-Token: YOUR_USER_TOKEN' \
  -H 'X-OvalEdge-Secret: YOUR_USER_SECRET' \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  --data-binary '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"curl","version":"0.0.1"}}}'
  ```
* Expected Results:
  * Successful authentication returns a valid MCP HTTP response.
  * HTTP `401` indicates invalid credentials or rejected authentication.

### Automated Testing

* Run the following automated tests:

  ```
  poetry run pytest tests/auth/test_middleware_remote_credentials.py \
  tests/auth/test_remote_credentials_discovery.py \
  tests/auth/test_credentials_cache.py \
  tests/client/test_remote_credentials_401_retry.py -q
  ```

### Optional HTTPS Configuration

Configure HTTPS locally by using one of the following methods:

* Configure a reverse proxy such as Caddy or NGINX.
* Run uvicorn with SSL certificates.

Example:

```
uvicorn entrypoints.lambda_handler:app \
--ssl-keyfile <KEY_FILE> \
--ssl-certfile <CERTIFICATE_FILE>
```

### Cursor HTTP MCP Configuration

* Cursor resolves ${env:VAR} values from the process environment instead of the repository .env file.
* Configure the following parameter on the server:

  ```
  MCP_HTTP_STATELESS=false
  ```
* Example mcp.json Configuration

  ```json
  {
    "mcpServers": {
      "ovaledge-remote": {
        "url": "https://YOUR_PUBLIC_MCP_BASE_URL/mcp",
        "headers": {
          "X-OvalEdge-Token": "${env:OVALEDGE_USER_TOKEN}",
          "X-OvalEdge-Secret": "${env:OVALEDGE_USER_SECRET}"
        }
      }
    }
  }
  ```

  <br>
* Each user must use a unique token and secret combination. The server maintains a separate JWT cache entry for each credential pair.
* The MCP endpoint supports both of the following formats:
  * <http://127.0.0.1:8000/mcp>
  * <http://127.0.0.1:8000/mcp/>
* The application normalizes slashless/mcp requests to prevent redirect-related issues.

### VS Code and GitHub Copilot Configuration

VS Code and GitHub Copilot use a top-level servers object with `type: "http"` entries.&#x20;

#### **Configuration Locations**

Use one of the following configuration methods:

* Workspace configuration: `.vscode/mcp.json`
* User configuration: Command Palette `→ MCP: Open User Configuration`
* Guided configuration: Command Palette `→ MCP: Add Server`

#### **Server Requirement**

* Configure the following parameter on the server:&#x20;

  ```
  MCP_HTTP_STATELESS=false
  ```
* Example:

  ```json
  {
  "inputs": [
  {
  "type": "promptString",
  "id": "ovaledge-token",
  "description": "OvalEdge user token",
  "password": true
  },
  {
  "type": "promptString",
  "id": "ovaledge-secret",
  "description": "OvalEdge user secret",
  "password": true
  }
  ],
  "servers": {
  "ovaledge-remote": {
  "type": "http",
  "url": "https://YOUR_API_ID.execute-api.REGION.amazonaws.com/mcp",
  "headers": {
  "X-OvalEdge-Token": "${input:ovaledge-token}",
  "X-OvalEdge-Secret": "${input:ovaledge-secret}"
  }
  }
  }
  }
  ```

### Claude Code HTTP MCP Configuration

Claude Code requires HTTP transport registration through the claude mcp command.&#x20;

#### **Install Claude Code CLI**

* Use one of the following installation methods.&#x20;
  * macOS, Linux, or WSL&#x20;

    ```
    curl -fsSL https://claude.ai/install.sh | bash 
    ```
  * Windows PowerShell

    ```
    irm https://claude.ai/install.ps1 | iex 
    ```
  * Alternative Installation Methods

    ```
    brew install --cask claude-code 
    winget install Anthropic.ClaudeCode 
    ```

#### **Complete CLI Authentication**

* Run the following command and complete the authentication flow:

  ```
  claude
  ```

#### **Configure MCP HTTP Stateless Mode**&#x20;

* Configure the following parameter:

  ```
  MCP_HTTP_STATELESS=false
  ```

#### **Register the Remote MCP Server**&#x20;

* Run the following command from the required workspace directory:

  ```
  claude mcp add --transport http ovaledge-remote <MCP_BASE_URL> \
  --header "X-OvalEdge-Token: YOUR_USER_TOKEN" \
  --header "X-OvalEdge-Secret: YOUR_USER_SECRET"
  ```

{% hint style="info" %}
Replace the placeholder values with valid OvalEdge credentials.
{% endhint %}

#### **Use Claude Code**&#x20;

* Open Claude Code and run the required sessions or commands.&#x20;

#### **Remove the Remote MCP Configuration**&#x20;

* Run the following command:

  ```
  claude mcp remove ovaledge-remote
  ```

### Validation Script Execution&#x20;

* Run the following validation commands from the repository root directory.

  ```
  poetry run python scripts/validate_remote_mcp.py --settings 
  poetry run python scripts/validate_remote_mcp.py --credentials
  ```

#### **OAuth Validation**&#x20;

* Configure the OAuth environment variables from `.env.example` before running OAuth validation.

  ```
  export AUTH_MODE=remote
  poetry run python scripts/validate_remote_mcp.py --all --token "$OAUTH_TEST_ACCESS_TOKEN"
  ```
* The `--all` option validates the following components:
  * Settings validation
  * OIDC discovery
  * OvalEdge token exchange
  * MCP validation
  * Optional credential validation
* Refer to the validation script documentation for additional parameters such as:
  * `--discovery`
  * `--ovaledge`
  * `--mcp`

## Security Guidelines

### Remote Credentials Authentication

The `remote_credential`s mode sends long-lived OvalEdge credentials through request headers.

Follow these security guidelines:

* Terminate TLS at the edge by using API Gateway or ALB.
* Do not log credential header values.
* Use HTTPS for all production deployments.

### OAuth 2.x Remote MCP

Treat IdP tokens as sensitive credentials during transmission.

Configure the following parameters carefully after the OAuth implementation becomes stable:

* `OAUTH_AUDIENCE`
* Issuer discovery settings

## Remote MCP Directory Layout

The following files are relevant to Remote MCP deployment and authentication.&#x20;

| File Path                                     | Description                           |
| --------------------------------------------- | ------------------------------------- |
| entrypoints/lambda\_handler.py                | HTTP application and Mangum handler   |
| server/auth/middleware.py                     | Authentication mode handling          |
| server/auth/metadata.py                       | OAuth metadata handling               |
| server/auth/registration.py                   | OAuth registration handling           |
| server/auth/remote\_credentials\_discovery.py | Remote credentials discovery handling |
| infra/template.yaml                           | Sample deployment template            |

***

Copyright © 2026, OvalEdge LLC, Peachtree Corners, GA, USA.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.ovaledge.com/release8.1/mcp-server/deployment-options/remote-mcp.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
