
HTTP OAuth MCP Server
A reference implementation for creating an MCP server supporting Streamable HTTP & SSE Transports with OAuth authorization, allowing developers to build OAuth-authorized MCP servers with minimal configuration.
README
🌊 HTTP + SSE MCP Server w/ OAuth
Introduction
This repo provides a reference implementation for creating a remote MCP server that supports the Streamable HTTP & SSE Transports, authorized with OAuth based on the MCP specification.
Note that the MCP server in this repo is logically separate from the application that handles the report SSE + HTTP transports, and from OAuth.
As a result, you can easily fork this repo, and plug in your own MCP server and OAuth credentials for a working SSE/HTTP + OAuth MCP server with your own functionality.
But, why?
Great question! The MCP specification added the authorization specification based on OAuth on March 25, 2025. At present, as of May 1, 2025:
- The Typescript SDK contains many of the building blocks for accomplishing an OAuth-authorized MCP server with streamable HTTP, but there is no documentation or tutorial on how to build such a server
- The Python SDK contains neither an implementation of the streamable HTTP transport, nor an implementation of the OAuth building blocks that are present in the typescript SDK
- The Streamable HTTP transport is broadly unsupported by MCP host applications such as Cursor and Claude desktop, though it may be intgrated directly into agents written in JavaScript using the JS/TS SDK's
StreamableHttpClientTransport
class
At Naptha AI, we really wanted to build an OAuth-authorized MCP server on the streamable HTTP transport, and couldn't find any reference implementations, so we decided to build one ourselves!
Dependencies
Bun, a fast all-in-one JavaScript runtime, is the recommended runtime and package manager for this repository. Limited compatibility testing has been done with npm
+ tsc
.
Overview
This repository provides the following:
- An MCP server, which you can easily replace with your own
- An express.js application that manages both the SSE and Streamable HTTP transports and OAuth authorization.
This express application is what you plug your credentials and MCP server into.
Note that while this express app implements the required OAuth endpoints including /authorize
and the Authorization Server Metadata endpoint (RFC8414), it does not implement an OAuth authorization server!
This example proxies OAuth to an upstream OAuth server which supports dynamic client registration (RFC7591). To use this example, you will need to bring your own authorization server. We recommend using Auth0; see the "Setting up OAuth" Section below.
Configuring your server
Notes on OAuth & Dynamic Client Registration
To use this example, you need an OAuth authorization server. Do not implement this yourself! For the purposes of creating our demo, we used Auth0 -- this is a great option, though there are many others.
The MCP specification requires support for an uncommon OAuth feature, specifically RFC7591, Dynamic Client Registration. The MCP specification specifies that MCP clients and servers should support the Dynamic client registration protocol, so that MCP clients (whever your client transport lives) can obtain Client IDs without user registration. This allows new clients (agents, apps, etc.) to automatically register with new servers. More details on this can be found in the authorization section of the MCP specification, but this means that unfortunately, you cannot simply proxy directly to a provider like Google or GitHub, which do not support dynamic client registration (they require you to register clients in their UI).
This leaves you with two options:
- Pick an upstream OAuth provider like Auth0 which allows you to use OIDC IDPs like Google and GitHub for authentication, and which does support dynamic client registration, or
- implement dynamic client registration in the application yourself (i.e., the express application becomes not just a simple OAuth proxy but a complete or partially-complete OAuth server). Cloudflare implemented something like this for their Workers OAuth MCP servers, which we may extend this project with later. You can find that here.
For simplicity, we have opted for the former option using Auth0.
[!NOTE]
Since this implementation proxies the upstream OAuth server, the default approach of forwarding the access token from the OAuth server to the client would expose the user's upstream access token to the downstream client & MCP host. This is not suitable for many use-cases, so this approach re-implements some@modelcontextprotocol/typescript-sdk
classes to fix this issue.
Note that while we are proxying the upstream authorization server, we are not returning the end-user's auth token to the MCP client / host - instead, we are issuing our own, and allowing the client / host to use that token to authorize with our server. This prevents a malicious client or host from abusing the token, or from it being abused if it's leaked.
Setting up OAuth with Auth0
To get started with Auth0:
- Create an Auth0 account at Auth0.com.
- Create at least one connection to an IDP such as Google or GitHub. You can learn how to do this here.
- Promote the connection to a domain-level connection. Since new OAuth clients are registered by each MCP client, you can't configure your IDP connections on a per-application/client basis. This means your connections need to be available for all apps in your domain. You can learn how do this here.
- Enable Dynamic Client Registration (auth0 also calls this "Dynamic Application Registration"). You can learn how to do this here.
Once all of this has been set up, you will need the following information:
- your Auth0 client ID
- your Auth0 client secret
- your Auth0 tenant domain
Make sure to fill this information into your .env
. Copy .env.template
and then update the values with your configurations & secrets.
Running the server
This repository includes two separate stand-alone servers:
- a stateless implementation of the streamable HTTP server at
src/app.stateless.ts
. This only supports the streamable HTTP transport, and is (theoretically) suitable for serverless deployment - a stateful implementation of both SSE and streamable HTTP at
src/app.stateful.ts
. This app offers both transports, but maintains in-memory state even when using theredis
storage strategy (connections must be persisted in-memory), so it is not suitable for serverless deployment or trivial horizontal scaling.
You can run either of them with bun
:
bun run src/app.stateless.ts
# or,
bun run src/app.stateful.ts
Putting it All Together
To test out our MCP server with streamable HTTP and OAuth support, you have a couple options.
As noted above, the Python MCP SDK does not support these features, so currently you can either plug our remote server into an MCP host like Cursor or Claude Desktop, or into a TypeScript/JavaScript application directly - but not into a Python one.
Plugging your server into your MCP Host (Cursor / Claude)
Since most MCP hosts don't support either streamable HTTP (which is superior to SSE in a number of ways) or OAuth, we recommend using the mcp-remote
npm package which will handle the OAuth authorization, and bridging the remote transport into a STDIO transport for your host.
the command will look like this:
bunx mcp-remote --transport http-first https://some-domain.server.com/mcp
# or,
npx mcp-remote --transport http-first https://some-domain.server.com/mcp
You have a couple of options for the --transport
option:
http-first
(default): Tries HTTP transport first, falls back to SSE if HTTP fails with a 404 errorsse-first
: Tries SSE transport first, falls back to HTTP if SSE fails with a 405 errorhttp-only
: Only uses HTTP transport, fails if the server doesn't support itsse-only
: Only uses SSE transport, fails if the server doesn't support it
[!NOTE] If you launch the stateless version of the server with
src/app.stateless.ts
, the SSE transport is not available, so you should use--transport http-only
. SSE transport should not be expected to work if you use this entrypoint.
Plugging you server into your agent
You can plug your Streamable HTTP server into an agent in JS/TS using StreamableHTTPClientTransport
. However, this will not work with OAuth-protected servers. Instead, you should use the Authorization
header on the client side, with a valid access token on the server side.
You can implement this with client credentials, API keys or something else. That pattern is not supported in this repository, but it would look like this using the Vercel AI SDK:
import { openai } from '@ai-sdk/openai';
import { experimental_createMCPClient as createMcpClient, generateText } from 'ai';
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
const mcpClient = await createMcpClient({
transport: new StreamableHTTPClientTransport(
new URL("http://localhost:5050/mcp"), {
requestInit: {
headers: {
Authorization: "Bearer YOUR TOKEN HERE",
},
},
// TODO add OAuth client provider if you want
authProvider: undefined,
}),
});
const tools = await mcpClient.tools();
await generateText({
model: openai("gpt-4o"),
prompt: "Hello, world!",
tools: {
...(await mcpClient.tools())
}
});
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.

VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.

E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.