@fastmcp-oauth/rest-api-delegation
v1.0.0
Published
REST API delegation module for FastMCP OAuth framework - HTTP/JSON API integration with token exchange support
Downloads
37
Maintainers
Readme
@fastmcp-oauth/rest-api-delegation
REST API delegation module for the MCP OAuth framework - provides HTTP/JSON API integration with token exchange support.
Overview
This package provides a production-ready delegation module for integrating MCP tools with external REST APIs. It's the most common use case for the MCP OAuth framework, enabling AI agents to securely interact with backend services.
Key Features
- ✅ Token Exchange Support - Exchange requestor JWT for API-specific tokens
- ✅ API Key Fallback - Use static API keys when token exchange unavailable
- ✅ Comprehensive Error Handling - Graceful degradation and detailed audit logging
- ✅ Timeout Support - Configurable request timeouts
- ✅ Custom Headers - Add default headers to all requests
- ✅ Multiple HTTP Methods - GET, POST, PUT, PATCH, DELETE support
- ✅ Session Context Propagation - Automatic user ID and role headers
Installation
npm install @fastmcp-oauth/rest-api-delegationThis package is an optional dependency of fastmcp-oauth. The core framework works without REST API support.
Quick Start
Basic Usage with Token Exchange
import { RestAPIDelegationModule } from '@fastmcp-oauth/rest-api-delegation';
import { FastMCPOAuthServer } from 'fastmcp-oauth';
// Create server
const server = new FastMCPOAuthServer({
configPath: './config.json'
});
// Get core context
const coreContext = server.getCoreContext();
// Create and register REST API module
const restApiModule = new RestAPIDelegationModule();
await restApiModule.initialize({
baseUrl: 'https://api.example.com',
useTokenExchange: true,
tokenExchangeAudience: 'urn:api:example'
});
coreContext.delegationRegistry.register(restApiModule);Using API Key (Fallback)
await restApiModule.initialize({
baseUrl: 'https://api.example.com',
useTokenExchange: false,
apiKey: process.env.API_KEY
});Creating MCP Tools
Use the createDelegationTool() factory to create OAuth-secured tools in 5 lines:
import { createDelegationTool } from 'fastmcp-oauth';
import { z } from 'zod';
// Tool 1: Get user profile
const getUserProfileTool = createDelegationTool('rest-api', {
name: 'get-user-profile',
description: 'Get user profile from backend API',
parameters: z.object({
userId: z.string().describe('User ID to fetch')
}),
action: 'users/profile',
requiredPermission: 'api:read',
// Transform params for API
transformParams: (params) => ({
endpoint: `users/${params.userId}/profile`,
method: 'GET'
}),
// Transform API response for LLM
transformResult: (apiResponse: any) => ({
displayName: apiResponse.fullName,
email: apiResponse.email,
department: apiResponse.department
// Hide sensitive fields
})
}, coreContext);
// Tool 2: Update user settings
const updateUserSettingsTool = createDelegationTool('rest-api', {
name: 'update-user-settings',
description: 'Update user settings',
parameters: z.object({
userId: z.string(),
settings: z.record(z.any())
}),
action: 'users/settings',
requiredPermission: 'api:write',
transformParams: (params) => ({
endpoint: `users/${params.userId}/settings`,
method: 'PUT',
data: params.settings
})
}, coreContext);
// Register tools
server.registerTools([getUserProfileTool, updateUserSettingsTool]);Configuration
RestAPIConfig Interface
interface RestAPIConfig {
/** Base URL of the REST API (e.g., 'https://api.example.com') */
baseUrl: string;
/** Optional API key for fallback authentication */
apiKey?: string;
/** Whether to use token exchange for authentication */
useTokenExchange: boolean;
/** Audience for token exchange requests (default: 'urn:api:rest') */
tokenExchangeAudience?: string;
/** Optional OAuth scopes to request during token exchange (space-separated) */
scope?: string;
/** Optional default request timeout in milliseconds */
timeout?: number;
/** Optional custom headers to include in all requests */
defaultHeaders?: Record<string, string>;
}Example Configuration
await restApiModule.initialize({
baseUrl: 'https://api.example.com',
useTokenExchange: true,
tokenExchangeAudience: 'urn:api:example',
scope: 'openid profile api:read api:write', // Request specific OAuth scopes
timeout: 30000, // 30 seconds
defaultHeaders: {
'X-API-Version': 'v2',
'X-Client-ID': 'mcp-server'
}
});OAuth Scope Support:
- Request fine-grained permissions during token exchange
- Example scopes:
api:read,api:write,api:admin - IDP determines which scopes to grant based on user roles
- Enables least-privilege access patterns
Token Exchange Flow
When useTokenExchange: true, the module performs RFC 8693 token exchange:
- Requestor JWT - User's JWT from OAuth provider (e.g., Keycloak)
- Exchange - Module exchanges requestor JWT for API-specific token at IDP
- Delegation Token (TE-JWT) - IDP returns token scoped for your API
- API Request - Module calls your API with
Authorization: Bearer <TE-JWT>
Benefits:
- API receives tokens with correct audience binding
- IDP controls API permissions (privilege elevation/reduction)
- Centralized token revocation
- Cached tokens reduce IDP load by 90%
API Request Parameters
The delegate() method accepts these parameters:
const result = await coreContext.delegationRegistry.delegate(
'rest-api',
session,
'action-name',
{
// Optional: Override endpoint (default: uses action name)
endpoint: 'users/123/profile',
// Optional: HTTP method (default: 'POST')
method: 'GET',
// Optional: Request body data (for POST/PUT/PATCH)
data: { key: 'value' },
// Optional: Additional headers
headers: { 'X-Custom': 'header' }
}
);Security Features
Automatic Headers
The module automatically adds:
Authorization: Bearer <token>- Token exchange or API keyX-User-ID- User ID from sessionX-User-Role- User role from sessionContent-Type: application/json- JSON content type
Audit Logging
All requests are logged with:
- Timestamp
- User ID
- Action name
- HTTP method and endpoint
- Authentication method (token-exchange or api-key)
- Success/failure status
- Error details (if failed)
Error Handling
- Network errors caught and returned as
DelegationResult - Timeout errors with clear messaging
- HTTP error responses with status code and body
- No sensitive data exposed in error messages
Health Check
The module provides a health check endpoint:
const healthy = await restApiModule.healthCheck();
if (!healthy) {
console.log('API is not responding');
}Health check attempts GET /health with optional API key authentication.
Complete Example
import { FastMCPOAuthServer, createDelegationTool } from 'fastmcp-oauth';
import { RestAPIDelegationModule } from '@fastmcp-oauth/rest-api-delegation';
import { z } from 'zod';
async function main() {
// 1. Create server
const server = new FastMCPOAuthServer({
configPath: './config.json'
});
const coreContext = server.getCoreContext();
// 2. Create and register REST API module
const restApiModule = new RestAPIDelegationModule();
await restApiModule.initialize({
baseUrl: 'https://api.example.com',
useTokenExchange: true,
tokenExchangeAudience: 'urn:api:example',
timeout: 30000
});
coreContext.delegationRegistry.register(restApiModule);
// 3. Create tools
const getUserTool = createDelegationTool('rest-api', {
name: 'get-user',
description: 'Get user data',
parameters: z.object({
userId: z.string()
}),
action: 'users',
requiredPermission: 'api:read',
transformParams: (params) => ({
endpoint: `users/${params.userId}`,
method: 'GET'
})
}, coreContext);
// 4. Register tools
server.registerTools([getUserTool]);
// 5. Start server
await server.start({
transportType: 'httpStream',
httpStream: { port: 3000, endpoint: '/mcp' },
stateless: true
});
console.log('MCP OAuth Server running on http://localhost:3000/mcp');
}
main().catch(console.error);API Reference
RestAPIDelegationModule
Methods
initialize(config: RestAPIConfig): Promise<void>
Initialize module with configuration.
delegate<T>(session: UserSession, action: string, params: any, context?: { sessionId?: string; coreContext?: any }): Promise<DelegationResult<T>>
Delegate operation to REST API.
healthCheck(): Promise<boolean>
Check if API is accessible.
destroy(): Promise<void>
Cleanup resources.
setTokenExchangeService(service: any, config: any): void
Set token exchange service (called by ConfigOrchestrator).
Use Cases
1. AI Agent → Internal API
LLM agents querying internal REST APIs with user context
2. Multi-Service Orchestration
Coordinate calls to multiple REST APIs with single OAuth token
3. Legacy System Integration
Connect modern AI tools to legacy REST/SOAP services
4. Third-Party API Integration
Integrate with external SaaS APIs using token exchange
Best Practices
- Use Token Exchange - Preferred over API keys for production
- Set Timeouts - Prevent hung requests (recommended: 30 seconds)
- Transform Results - Hide sensitive data before returning to LLM
- Use Custom Headers - Add versioning and client identification
- Health Checks - Monitor API availability in production
- Cache Tokens - Enable session-based token caching (81% latency reduction)
Troubleshooting
"No authentication method configured"
Either enable token exchange or provide an API key:
apiKey: process.env.API_KEY,
useTokenExchange: false"TokenExchangeService not available"
Ensure token exchange is configured in your IDP settings:
{
"trustedIDPs": [{
"tokenExchange": {
"tokenEndpoint": "https://idp.com/token",
"clientId": "mcp-server",
"clientSecret": "SECRET"
}
}]
}"Session missing access_token"
User session must include access_token claim for token exchange. Verify JWT contains access token.
License
MIT
Support
- Documentation: MCP OAuth Framework Docs
- Issues: GitHub Issues
- Extension Guide: Docs/EXTENDING.md
