S Oauth
БесплатноДавно не обновлялся (393д)Express middleware library for MCP (Model Context Protocol) OAuth authentication
Описание
Express middleware library for MCP (Model Context Protocol) OAuth authentication
README
Universal OAuth middleware library for MCP (Model Context Protocol) servers with support for any OAuth provider.
Overview
This library provides OAuth authentication for MCP servers using a flexible connector pattern. It handles the complete OAuth flow for any OAuth provider and provides an authenticated /mcp endpoint where you create your own MCP server with tools. Built using the official MCP TypeScript SDK.
Features
- 🔐 Universal OAuth Support - Works with 20+ OAuth providers including GitHub, Google, Slack, and more
- 🔌 Connector Pattern - Pre-built connectors for popular services + easily add support for new OAuth providers
- 🚀 Express Middleware - Simple integration with
app.use() - 🛠️ Bring Your Own MCP Server - Create MCP server in your handler function
- 📊 Session Management - Automatic session handling via MCP SDK
- 🌐 Authenticated Context - Access OAuth tokens in your tools
- 🎯 Production Ready - Built with official MCP SDK components
- 🔑 Minimal Scopes - Uses minimal OAuth scopes for enhanced security
Installation
npm install
Quick Start
Basic Usage
import express from "express"
import { Server } from "@modelcontextprotocol/sdk/server/index.js"
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js"
import { McpOAuth } from "mcp-s-oauth"
import type { McpOAuthConfig } from "mcp-s-oauth"
const app = express()
// Choose your OAuth provider connector
import { githubConnector } from "mcp-s-oauth"
// or import { googleConnector } from "mcp-s-oauth"
// or create your own custom connector
// Configure OAuth with any provider
const config: McpOAuthConfig = {
baseUrl: "http://localhost:3000",
clientId: "your-oauth-client-id",
clientSecret: "your-oauth-client-secret",
connector: githubConnector // or any other connector
}
// Create your MCP handler - this is where YOU create the MCP server
const mcpHandler = async (req: express.Request, res: express.Response, { authInfo }) => {
// Access the OAuth token from any provider
const oauthToken = authInfo.token
// Create transport and your MCP server
const transport = new StreamableHTTPServerTransport(/* options */)
const mcpServer = new Server({ name: "my-server", version: "1.0.0" })
// Register your tools (customize based on your OAuth provider)
mcpServer.setRequestHandler(ListToolsRequestSchema, async () => ({
tools: [{
name: "get_profile",
description: "Get authenticated user profile",
inputSchema: { type: "object" }
}]
}))
mcpServer.setRequestHandler(CallToolRequestSchema, async (request) => {
if (request.params.name === "get_profile") {
// Call your OAuth provider's API using the token
// Example for GitHub: https://api.github.com/user
// Example for Google: https://www.googleapis.com/oauth2/v2/userinfo
const apiUrl = "https://api.github.com/user" // adjust for your provider
const response = await fetch(apiUrl, {
headers: { "Authorization": `Bearer ${authInfo.token}` }
})
const userData = await response.json()
return {
content: [{ type: "text", text: `Profile: ${JSON.stringify(userData, null, 2)}` }]
}
}
})
// Handle the MCP request
await mcpServer.connect(transport)
await transport.handleRequest(req, res, req.body)
}
// Use the library
const mcpOAuth = McpOAuth(config, mcpHandler)
app.use("/", mcpOAuth.router)
app.listen(3000)
OAuth Provider Setup
GitHub OAuth App Setup
- Go to GitHub Developer Settings
- Create a new OAuth App:
- Authorization callback URL:
${baseUrl}/oauth/callback(e.g.,http://localhost:3000/oauth/callback)
- Authorization callback URL:
- Use the Client ID and Secret in your config
Google OAuth App Setup
- Go to Google Cloud Console
- Create a new project or select existing
- Enable the "Google+ API" or "People API"
- Create OAuth 2.0 credentials:
- Authorized redirect URIs:
${baseUrl}/oauth/callback(e.g.,http://localhost:3000/oauth/callback)
- Authorized redirect URIs:
- Use the Client ID and Secret in your config
Custom OAuth Provider Setup
For any OAuth 2.0 provider, you'll need:
- Client ID and Client Secret from your provider
- Authorization callback URL set to:
${baseUrl}/oauth/callback
Available Connectors
This library includes pre-built connectors for popular OAuth providers with minimal scopes for enhanced security:
| Service | Connector |
|---|---|
slackConnector |
|
gmailConnector |
|
googleCalendarConnector |
|
jiraConnector |
|
trelloConnector |
|
asanaConnector |
|
notionConnector |
|
mondayConnector |
|
githubConnector |
|
gitlabConnector |
|
googleWorkspaceConnector |
|
googleDriveConnector |
|
googleSheetsConnector |
|
googleFormsConnector |
|
googleSlidesConnector |
|
salesforceConnector |
|
figmaConnector |
|
zeplinConnector |
|
amplitudeConnector |
|
googleAnalyticsConnector |
|
googleMapsConnector |
|
discordConnector |
|
spotifyConnector |
|
twitterConnector |
Example Usage with GitHub
import { githubConnector } from "mcp-s-oauth"
const config: McpOAuthConfig = {
baseUrl: "http://localhost:3000",
clientId: process.env.GITHUB_CLIENT_ID!,
clientSecret: process.env.GITHUB_CLIENT_SECRET!,
connector: githubConnector,
}
Custom Connector
For any OAuth provider not listed above:
import type { Connector } from "mcp-s-oauth"
const myCustomConnector: Connector = {
authUrl: "https://your-provider.com/oauth/authorize",
tokenUrl: "https://your-provider.com/oauth/token",
scopes: ["read", "write"],
codeExchangeConfig: {
isForm: true,
modelCredentialsMapping: `{
"access_token": access_token,
"expires_at": $fromMillis($millis() + expires_in * 1000),
"refresh_token": refresh_token,
"scope": scope,
"token_type": token_type
}`,
},
authInitUrlParams: {
prompt: "consent",
},
}
Creating Custom Connectors
The Connector interface allows you to integrate any OAuth 2.0 provider. Here's how to create your own:
Connector Interface
export interface Connector {
authUrl?: string // OAuth authorization endpoint
tokenUrl?: string // OAuth token exchange endpoint
refreshTokenUrl?: string // Token refresh endpoint (defaults to tokenUrl)
scopes?: string[] | readonly string[] // OAuth scopes to request
codeExchangeConfig?: {
modelCredentialsMapping?: JsonataString<OAuthCredentials> | ((config: any) => OAuthCredentials)
isForm?: boolean // Use form encoding vs JSON for token exchange
authorizationMapping?: JsonataString<string> | ((config: any) => string)
}
authInitUrlParams?: Record<string, string> // Additional OAuth params
}
Step-by-Step Guide
Find OAuth Documentation for your provider (authorization URL, token URL, scopes)
Create Connector File:
// src/connectors/my-provider.ts
import type { Connector } from "../types/connector.types.js"
export const myProviderConnector: Connector = {
authUrl: "https://api.myprovider.com/oauth/authorize",
tokenUrl: "https://api.myprovider.com/oauth/token",
scopes: ["read", "write"],
codeExchangeConfig: {
isForm: true, // Most providers use form encoding
modelCredentialsMapping: `{
"access_token": access_token,
"expires_at": $fromMillis($millis() + expires_in * 1000),
"refresh_token": refresh_token,
"scope": scope,
"token_type": token_type
}`,
},
}
- Handle Special Cases:
// Provider requires special auth parameters
export const specialProviderConnector: Connector = {
authUrl: "https://special.com/oauth/authorize",
tokenUrl: "https://special.com/oauth/token",
scopes: ["user:read"],
authInitUrlParams: {
access_type: "offline",
prompt: "consent",
response_mode: "query",
},
codeExchangeConfig: {
isForm: false, // This provider uses JSON
},
}
- Use Function for Complex Mapping:
export const complexProviderConnector: Connector = {
authUrl: "https://complex.com/oauth/authorize",
tokenUrl: "https://complex.com/oauth/token",
scopes: ["api"],
codeExchangeConfig: {
isForm: true,
// Use function for complex response mapping
modelCredentialsMapping: (tokenResponse) => ({
access_token: tokenResponse.accessToken, // Different field name
expires_at: new Date(Date.now() + tokenResponse.expiresIn * 1000).toISOString(),
refresh_token: tokenResponse.refreshToken,
refresh_token_expires_at: null,
scope: tokenResponse.scope,
token_type: "Bearer",
}),
},
}
Common OAuth Patterns
| Provider | Auth URL | Token URL | Form Encoding | Special Notes |
|---|---|---|---|---|
| GitHub | /login/oauth/authorize |
/login/oauth/access_token |
❌ JSON | Simple flow |
/o/oauth2/v2/auth |
/oauth2/token |
✅ Form | Use access_type: offline |
|
| Discord | /api/oauth2/authorize |
/api/oauth2/token |
✅ Form | Standard OAuth |
/i/oauth2/authorize |
/2/oauth2/token |
✅ Form | Requires PKCE | |
/authorization |
/accessToken |
✅ Form | Different field names |
Testing Your Connector
- Create test config:
const config: McpOAuthConfig = {
baseUrl: "http://localhost:3000",
clientId: process.env.MY_PROVIDER_CLIENT_ID!,
clientSecret: process.env.MY_PROVIDER_CLIENT_SECRET!,
connector: myProviderConnector,
}
Test OAuth flow:
- Visit
/auth/authorize - Complete OAuth on provider
- Check console logs for token exchange
- Test API calls with the token
- Visit
Common Issues:
- Form vs JSON: Check provider docs for token endpoint format
- Field Names: Response might use different field names
- Scopes: Ensure scopes are valid for your provider
- Callback URL: Must match OAuth app configuration
Example Tools Implementation
The tools you create depend on your OAuth provider and their APIs. The library provides the OAuth token - you implement the tools. Here's a complete GitHub example:
GitHub Tools Example
// In your mcpHandler function
mcpServer.setRequestHandler(ListToolsRequestSchema, async () => ({
tools: [
{
name: "github_me",
description: "Get authenticated user's GitHub profile",
inputSchema: { type: "object", properties: {} }
},
{
name: "github_repos",
description: "List user's repositories",
inputSchema: {
type: "object",
properties: {
type: { type: "string", enum: ["all", "owner", "member"] }
}
}
},
{
name: "github_issues",
description: "List user's issues",
inputSchema: {
type: "object",
properties: {
state: { type: "string", enum: ["open", "closed", "all"] }
}
}
}
]
}))
mcpServer.setRequestHandler(CallToolRequestSchema, async (request, { authInfo }) => {
if (request.params.name === "github_me") {
const response = await fetch("https://api.github.com/user", {
headers: { "Authorization": `Bearer ${authInfo.token}` }
})
return { content: [{ type: "text", text: await response.text() }] }
}
if (request.params.name === "github_repos") {
const { type = "all" } = request.params.arguments || {}
const response = await fetch(`https://api.github.com/user/repos?type=${type}`, {
headers: { "Authorization": `Bearer ${authInfo.token}` }
})
return { content: [{ type: "text", text: await response.text() }] }
}
if (request.params.name === "github_issues") {
const { state = "open" } = request.params.arguments || {}
const response = await fetch(`https://api.github.com/issues?state=${state}`, {
headers: { "Authorization": `Bearer ${authInfo.token}` }
})
return { content: [{ type: "text", text: await response.text() }] }
}
})
Other Provider Examples
For other OAuth providers, follow the same pattern using their respective APIs:
- Slack: Use
https://slack.com/api/endpoints - Google Services: Use Google API endpoints (Gmail, Drive, Sheets, etc.)
- Notion: Use
https://api.notion.com/v1/endpoints - Jira: Use Atlassian REST API endpoints
- And more... - Each connector works with the provider's standard OAuth API
MCP Client Usage
Using with MCP Clients
Your OAuth-authenticated MCP server implements the MCP (Model Context Protocol) and can be used with any MCP-compatible client:
import { Client } from "@modelcontextprotocol/sdk/client/index.js"
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js"
const client = new Client({
name: "oauth-mcp-client",
version: "1.0.0"
})
const transport = new StreamableHTTPClientTransport(
new URL("http://localhost:3000/mcp")
)
await client.connect(transport)
// List available tools (depends on your implementation)
const tools = await client.listTools()
console.log("Available tools:", tools)
// Call any tool you've implemented
const result = await client.callTool({
name: "get_profile", // or any tool name you've implemented
arguments: {}
})
console.log("Result:", result)
Authentication Flow
- Start OAuth Flow: Make a request to
/auth/authorizeto initiate OAuth with your provider - User Authorization: User is redirected to OAuth provider to authorize your application
- Token Exchange: Provider redirects back with an authorization code
- MCP Access: Use the obtained token to make authenticated MCP requests to
/mcp
API Reference
Server Information
- GET / - Server information, available tools, and authentication endpoints
- GET /health - Health check endpoint
Authentication Endpoints
- POST /auth/authorize - Start OAuth flow with configured provider
- POST /auth/token - Exchange authorization code for access token
- GET /oauth/callback - OAuth callback handler (used by the provider)
MCP Protocol
- ALL /mcp - Main MCP endpoint supporting all MCP protocol methods
- Requires Bearer token authentication
- Supports session management with
mcp-session-idheader - Handles tools/list and tools/call requests
- Returns tools you've implemented in your mcpHandler
Testing the Server
Test the MCP server using the official SDK client:
import { Client } from "@modelcontextprotocol/sdk/client/index.js"
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js"
// Connect to the server
const client = new Client({ name: "test-client", version: "1.0.0" })
const transport = new StreamableHTTPClientTransport(
new URL("http://localhost:3000/mcp"),
{
requestInit: {
headers: {
'Authorization': 'Bearer your-oauth-token-here'
}
}
}
)
await client.connect(transport)
// Test listing tools
const tools = await client.listTools()
console.log("Available tools:", tools.tools)
// Test calling any tool you've implemented
const result = await client.callTool({
name: "get_profile", // or any tool name you've implemented
arguments: {}
})
console.log("Result:", result.content)
Development
Project Structure
src/
├── index.ts # Library exports
├── server.ts # MCP server implementation
├── lib.ts # Core utilities
├── connectors/ # OAuth provider connectors
├── services/ # Database & auth services
└── types/ # TypeScript types
Building and Running
# Install dependencies
npm install
# Development mode with auto-reload
npm run dev
# Build for production
npm run build
# Run production build
npm start
# Run tests
npm test
# Lint code
npm run lint
# Format code
npm run format
Adding New Tools
To add new MCP tools to your server:
- Update the tools list in
ListToolsRequestSchemahandler - Add tool implementation in
CallToolRequestSchemahandler - Use the OAuth token to call your provider's APIs
Example (provider-agnostic):
// In ListToolsRequestSchema handler
{
name: "get_user_data",
description: "Get user data from OAuth provider",
inputSchema: {
type: "object",
properties: {
fields: {
type: "array",
items: { type: "string" },
description: "Fields to retrieve"
}
}
}
}
// In CallToolRequestSchema handler
if (name === "get_user_data") {
const { fields = [] } = request.params.arguments || {}
// Use the OAuth token to call your provider's API
const apiUrl = "https://api.your-provider.com/user" // adjust for your provider
const response = await fetch(apiUrl, {
headers: {
"Authorization": `Bearer ${authInfo.token}`,
"Accept": "application/json"
}
})
const userData = await response.json()
return {
content: [{
type: "text",
text: JSON.stringify(userData, null, 2)
}]
}
}
Security Considerations
- OAuth Secrets: Never commit OAuth client secrets to version control
- HTTPS: Use HTTPS in production for secure OAuth flows
- Environment Variables: Store all sensitive configuration in environment variables
- Token Storage: Tokens are managed by the MCP SDK OAuth provider
- OAuth App Configuration: Configure your OAuth app with correct callback URLs
- Scope Limitation: Request only the OAuth scopes your application needs
- Token Validation: The library handles token validation automatically
Troubleshooting
Common Issues
"Missing required environment variables"
- Ensure your OAuth provider's
CLIENT_IDandCLIENT_SECRETare set - Check environment variable names match your configuration
- Ensure your OAuth provider's
OAuth callback errors
- Verify your
BASE_URLmatches your OAuth app configuration - Check that Authorization callback URL is set to
${baseUrl}/oauth/callback - Ensure your OAuth provider app is configured correctly
- Verify your
Token exchange errors
- Check
isFormsetting in your connector - most providers use form encoding - Verify
tokenUrlis correct for your provider - Check if provider requires special headers or parameters
- Check
API rate limits
- Authenticated requests usually have higher rate limits
- Consider implementing caching for frequently accessed data
- Check your provider's rate limiting documentation
MCP client connection issues
- Ensure you're using the correct MCP endpoint URL:
/mcp - Verify Bearer token authentication is properly configured
- Check that your tools are properly registered in the mcpHandler
- Ensure you're using the correct MCP endpoint URL:
Connector issues
- Verify OAuth URLs are correct for your provider
- Check scopes are valid for your provider
- Test OAuth flow manually in browser first
Debug Mode
Enable detailed logging by setting environment variables:
DEBUG=mcp:*
NODE_ENV=development
Contributing
Contributions are welcome! Please read our contributing guidelines and submit pull requests to our repository.
License
MIT License - see LICENSE file for details.
Support
- 📚 Documentation
- 🐛 Issues
- 💬 Discussions
Related Projects
Hosted Solution
Visit webrix.ai for our fully managed hosting solution with advanced features:
Zero Configuration: Get started in seconds without any setup Enterprise-grade Security: Advanced SSO authentication for all MCP interactions 20+ Pre-built Connectors: Fast plug-and-play integration with hundreds of tools Roles & Permissions: Granular access control with custom role definitions Monitoring & Analytics: Real-time insights into your MCP usage High Availability: 99.9% uptime SLA with global CDN Premium Support: Direct access to our engineering team Custom Integrations: Build and deploy custom MCP connectors
Установить S Oauth в Claude Desktop, Claude Code, Cursor
unyly install s-oauthСтавит в Claude Desktop, Claude Code, Cursor и VS Code — сам разбирается с npx, uvx и сборкой из исходников.
Впервые? Поставь CLI: curl -fsSL https://unyly.org/install | sh
Или настроить вручную
Выполни в терминале:
claude mcp add s-oauth --env GITHUB_CLIENT_ID="" --env GITHUB_CLIENT_SECRET="" --env MY_PROVIDER_CLIENT_ID="" --env MY_PROVIDER_CLIENT_SECRET="" -- npx -y mcp-s-oauthПошаговые гайды: как установить S Oauth
FAQ
S Oauth MCP бесплатный?
Да, S Oauth MCP бесплатный — установка в пару кликов через Unyly без оплаты.
Нужен ли API-ключ для S Oauth?
Да, требуются переменные окружения: GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET, MY_PROVIDER_CLIENT_ID, MY_PROVIDER_CLIENT_SECRET. Unyly подставит их в конфиг при установке.
S Oauth — hosted или self-hosted?
Self-hosted: сервер запускается локально на твоей машине командой из раздела установки.
Как установить S Oauth в Claude Desktop, Claude Code или Cursor?
Открой S Oauth на unyly.org, выбери вкладку своего клиента (Claude Desktop, Claude Code, Cursor) и нажми Install — конфиг сгенерируется автоматически, без правки JSON.
Изменения
Версии и запрашиваемые доступы со временем.
- Новая версия опубликована
- Новая версия опубликована
- Новая версия опубликована
- Новая версия опубликована
- Новая версия опубликована
- Новая версия опубликована
Похожие MCP
GitHub
PRs, issues, code search, CI status
автор: GitHubFilesystem
Secure file operations with configurable access controls.
Memory
Knowledge graph-based persistent memory system.
Template MCP Server
A CLI tool to create a new Model Context Protocol server project with TypeScript support, dual transport options, and an extensible structure
автор: mcpdotdirectAmap Maps Mcp Server
MCP server for using the AMap Maps API
автор: duxiaohuiSupabase
Database, auth and storage
автор: SupabaseEverything
Reference / test server with prompts, resources, and tools.
Git
Tools to read, search, and manipulate Git repositories.
Sequential Thinking
Dynamic and reflective problem-solving through thought sequences.
Time
Time and timezone conversion capabilities.
Compare S Oauth with
Не уверен что выбрать?
Найди свой стек за 60 секунд
Автор?
Embed-бейдж для README
Похожее
Все в категории development
