
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
mcp-client-auth
Advanced tools
A set of useful utils for building MCP clients, starting with reference OAuth implementations.
A TypeScript library providing OAuth2 authentication utilities for Model Context Protocol (MCP) clients. This library simplifies the process of adding OAuth authentication to MCP client implementations.
MCP OAuth is extra tricky because the dynamic client registration and metadata discovery steps are not supported by typical oauth implementations. This library simplifies everything to 2 function calls.
If you like this project, please consider starring it and giving me a follow on X/Twitter. This project is sponsored by Aomni.
Key capabilities:
npm install mcp-client-auth
Init the client
import { McpClient } from 'mcp-client-auth';
const client = new McpClient({
url: 'https://mcp.example.com',
oauthRedirectUri: 'localhost:3000/mcp/oauth/callback',
// store: -- add your own database store here --
});
There are only 2 methods that are needed to connect to a MCP server (and handle OAuth if needed).
The isAuthRequired() method returns an AuthStatus object that indicates the authentication state. This status can be one of three types:
{ isRequired: true, isAuthenticated: false, authorizationRequest: AuthorizationRequest } - Authentication is required and not yet completed. The authorizationRequest contains the URL and state needed to start the OAuth flow.
{ isRequired: false, isAuthenticated: true } - No authentication is needed for this server.
{ isRequired: true, isAuthenticated: true } - Authentication is required and has already been completed successfully.
This status object helps you determine whether to redirect the user to the OAuth authorization page or proceed with using the client directly.
// Check if authentication is required
const authStatus = await client.isAuthRequired();
if (authStatus.isRequired && !authStatus.isAuthenticated) {
console.log('Please visit:', authStatus.authorizationRequest.url);
// ... REDIRECT USER ...
}
Note you should save the AuthorizationRequest object for the next step.
The handleAuthByCode method is used to complete the OAuth flow by exchanging the authorization code for access tokens. It takes two parameters:
code: The authorization code received from the OAuth server after user authorizationauthRequest: The original authorization request object containing the state and code verifier needed for PKCEThis method should be called in your server callback route, as defined by the oauthRedirectUri.
function callback() {
// After user authorizes, exchange code for token
// Realistically - this would be in a different callback route
const token = await client.handleAuthByCode(
code,
authStatus.authorizationRequest,
);
}
If a store is provided (ideally connected to a database), the token returned will be automatically saved via store, which means next time isAuthRequired is called it will automatically return isAuthenticated of true, and no redirect will be needed.
// Use the client - auth is handled automatically
const tools = await client.listTools();
const result = await client.callTool('search', { query: 'example' });
This is normally not needed - only do this if you have some custom auth logic you want to implement.
import { McpOAuth } from 'mcp-client-auth';
// Create OAuth instance
const oauth = new McpOAuth({
serverUrl: 'https://mcp.example.com',
clientId: 'your-client-id', // Optional
redirectUri: 'http://localhost:3334/callback', // Optional
});
// Initialize (discovers metadata, registers client if needed)
await oauth.init();
// Generate authorization URL with PKCE
const authRequest = await oauth.createAuthorizationRequest();
console.log('Visit:', authRequest.url);
// Exchange authorization code for tokens
const token = await oauth.exchangeCodeForToken(
code,
state,
authRequest.codeVerifier,
);
// Get authenticated HTTP client
const ky = await oauth.ky();
const data = await ky.get('api/data').json();
High-level MCP client with integrated OAuth support.
class McpClient {
constructor(options: McpClientOptions);
// Check if auth is required and get auth status
isAuthRequired(): Promise<AuthStatus>;
// Get OAuth instance for manual auth flow
getOAuth(): Promise<McpOAuth | undefined>;
// MCP operations
listTools(): Promise<McpTool[]>;
callTool(name: string, args: any): Promise<any>;
disconnect(): Promise<void>;
}
Core OAuth2 implementation for MCP servers.
class McpOAuth {
constructor(options: McpOAuthOptions);
// Initialize OAuth (required before use)
init(): Promise<void>;
// Check if server requires authentication
checkAuthRequired(): Promise<boolean>;
// OAuth flow methods
createAuthorizationRequest(): Promise<AuthorizationRequest>;
exchangeCodeForToken(
code: string,
state: string,
codeVerifier: string,
): Promise<StoredToken>;
// Token management
getAccessToken(): Promise<string>;
hasValidToken(): boolean;
// Get authenticated HTTP client
ky(): Promise<KyInstance>;
// Reset tokens
reset(clearStorage?: boolean): Promise<void>;
// Revoke tokens
revokeToken(): Promise<void>;
}
interface McpClientOptions {
url: string; // MCP server URL
oauth?: McpOAuth; // Pre-configured OAuth instance
store?: OAuthStore; // Token storage implementation
clientId?: string; // OAuth client ID
clientSecret?: string; // OAuth client secret
oauthRedirectUri?: string; // OAuth redirect URI
protocolVersion?: string; // MCP protocol version
}
interface McpOAuthOptions {
serverUrl: string; // MCP server URL
clientId?: string; // Pre-registered client ID
clientSecret?: string; // Client secret (for confidential clients)
redirectUri?: string; // Default: 'http://localhost:3334/callback'
store?: OAuthStore; // Token storage implementation
kyOpts?: KyOptions; // Additional HTTP client options
protocolVersion?: string; // Default: '2024-11-05'
}
By default, tokens are stored in a local JSON file (.mcp-oauth.json). You can provide a custom storage implementation:
interface OAuthStore {
load(): Promise<StoredOAuthData | undefined>;
save(data: StoredOAuthData): Promise<void>;
clear(): Promise<void>;
}
// Example: Custom in-memory store
class MemoryStore implements OAuthStore {
private data?: StoredOAuthData;
async load() {
return this.data;
}
async save(data: StoredOAuthData) {
this.data = data;
}
async clear() {
this.data = undefined;
}
}
const oauth = new McpClient({
url: 'https://mcp.example.com',
store: new MemoryStore(),
});
If you are curious about some of the business logic.
The library handles the complete OAuth flow automatically:
/.well-known/oauth-authorization-serverThe MCP client automatically selects the best transport method for connecting to MCP servers:
This ensures maximum compatibility across different server implementations and network configurations without requiring manual transport configuration.
MIT License - feel free to use and modify as needed.
FAQs
A set of useful utils for building MCP clients, starting with reference OAuth implementations.
The npm package mcp-client-auth receives a total of 4 weekly downloads. As such, mcp-client-auth popularity was classified as not popular.
We found that mcp-client-auth demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.