@frontegg/mcp-sdk-extensions
v1.1.0
Published
DPoP transport for MCP SDK
Readme
@frontegg/mcp-sdk-extensions
DPoP transport for the MCP SDK. Drop-in replacement for StreamableHTTPClientTransport that adds DPoP proof-of-possession and handles the OAuth authorization code flow.
Install
npm install @frontegg/mcp-sdk-extensions @modelcontextprotocol/sdkUsage
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { DPoPTransport } from '@frontegg/mcp-sdk-extensions';
const transport = new DPoPTransport('https://your-app.mcp-gw.frontegg.com', {
clientMetadata: {
client_name: 'my-app',
redirect_uris: ['http://localhost:3000/callback'],
grant_types: ['authorization_code'],
response_types: ['code'],
token_endpoint_auth_method: 'none',
},
onAuthorizationUrl: async (url) => {
// Open the browser, start a callback server, return the authorization code.
// This is entirely up to you — the transport doesn't assume a runtime.
},
});
const client = new Client({ name: 'my-app', version: '1.0.0' });
await client.connect(transport);
const { tools } = await client.listTools();
console.log(tools);How it works
When client.connect(transport) is called, DPoPTransport.start() runs the following sequence before any MCP messages are sent:
- Key generation — generates an ephemeral ES256 key pair (or imports one you provide).
- OAuth discovery — fetches
/.well-known/oauth-authorization-serverfrom the MCP server to find the real authorization server and token endpoint. - Client registration — if no
clientIdis provided, registers dynamically via RFC 7591 (DCR). - Authorization — calls your
onAuthorizationUrlcallback with the authorization URL and waits for you to return the authorization code. - Token exchange — exchanges the code for tokens, attaching a DPoP proof to the token request.
- Connect — creates an inner
StreamableHTTPClientTransportwith afetchwrapper that attaches a DPoP proof andAuthorization: Bearerheader to every MCP request.
After start() completes, all MCP operations (listTools, callTool, etc.) are authenticated with DPoP-bound tokens.
API
new DPoPTransport(serverUrl, options)
| Parameter | Type | Description |
| ---------------------------- | ---------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| serverUrl | string | MCP server URL |
| options.clientMetadata | OAuthClientMetadata & { client_id?: string } | OAuth client metadata. redirect_uris is required. Include client_id to skip DCR. Uses the SDK's OAuthClientMetadata type. |
| options.onAuthorizationUrl | (url: URL) => Promise<string> | Called when authorization is needed. Receives the auth URL, must return the authorization code. |
| options.privateJwk | JsonWebKey? | ES256 private key as JWK. Omit to generate an ephemeral key per session. |
Implements Transport
DPoPTransport implements the MCP SDK's Transport interface (start, send, close, onmessage, onerror, onclose), so it works anywhere the SDK expects a transport.
Examples
Self-contained examples with their own package.json:
examples/basic— CLI MCP client that lists and calls tools.examples/langchain— LangChain agent that uses MCP tools via DPoP.
To run an example:
cd examples/basic
cp .env.example .env # fill in your values
npm install
npm run devRequirements
- Node.js >= 22
@modelcontextprotocol/sdk>= 1.20.0
