mcp-sdk-direct-auth
v0.1.2
Published
Enhanced Model Context Protocol SDK with direct access token support
Maintainers
Readme
MCP SDK with Direct Access Token Support
Enhanced Model Context Protocol SDK with direct access token support and multi-server capabilities
This package extends the Model Context Protocol (MCP) SDK to add support for direct access token authentication and multi-server connections.
📋 Table of Contents
- MCP SDK with Direct Access Token Support
📦 Installation
npm install mcp-sdk-direct-auth✨ Features
- Direct Token Authentication: Use access tokens directly without going through the OAuth flow
- Multi-Server Support: Connect to multiple MCP servers simultaneously
- Backward Compatibility: Still supports the standard OAuth flow for applications that need it
- Token Validation: Server-side validation of tokens for security
- Service Integration: Designed with service integration (like Gmail) in mind
- Transport Header Support: Automatically adds authorization headers to transports
- GitHub API Integration: Built-in utilities and schemas for working with the GitHub API
🤔 Why This Extension?
The standard MCP SDK has two limitations this package addresses:
OAuth Flow Only: It uses a complete OAuth flow which works well for many applications, but some scenarios require using an existing access token:
- When integrating with services like Gmail where you already have an access token from another authentication process
- When building applications that use token-based authentication but don't need the full OAuth flow
- When developing prototypes or testing tools where a simplified auth flow is preferred
Single Server Connection: The standard SDK only supports connecting to one server at a time. Our extension adds support for:
- Connecting to multiple servers simultaneously
- Routing requests to specific servers
- Managing multiple server connections with a single client
GitHub API Integration: This extension includes ready-to-use GitHub API support:
- Built-in utility functions for common GitHub API operations
- Zod schemas for GitHub entities (users, repositories, issues, code results)
- Search capabilities for users, repositories, issues, and code
- Simplified authentication with GitHub access tokens
🚀 Usage
Basic Usage with Direct Access Token
import { Client, StdioClientTransport } from '@modelcontextprotocol/sdk-direct-auth';
// Initialize the client
const client = new Client({
name: "MyGmailClient",
version: "1.0.0"
});
// Set the access token directly
client.useDirectAccessToken("your-gmail-access-token");
// Connect to the server
const transport = new StdioClientTransport({
command: "node",
args: ["gmail-server.js"]
});
const serverId = await client.connect(transport);
// Now you can use tools with the pre-authenticated token
const result = await client.callTool({
name: "gmail-send-email",
arguments: {
to: "[email protected]",
subject: "Hello from MCP",
body: "This is a test email"
}
});Multi-Server Usage
import { Client, StdioClientTransport } from '@modelcontextprotocol/sdk-direct-auth';
// Initialize the client
const client = new Client({
name: "MultiServerClient",
version: "1.0.0"
});
// Set the access token for services that need it
client.useDirectAccessToken("your-gmail-access-token");
// Connect to multiple servers with identifiers
const gmailServerId = await client.connect(
new StdioClientTransport({
command: "node",
args: ["gmail-server.js"]
}),
"gmail" // Server identifier
);
const weatherServerId = await client.connect(
new StdioClientTransport({
command: "node",
args: ["weather-server.js"]
}),
"weather" // Server identifier
);
// Get information about all connected servers
const servers = client.getConnectedServers();
// [
// { serverId: 'gmail', serverInfo: {...}, isDefault: true },
// { serverId: 'weather', serverInfo: {...}, isDefault: false }
// ]
// Call tools on specific servers
const emailResult = await client.callTool({
name: "gmail-send-email",
arguments: { /* ... */ }
}, undefined, "gmail"); // Specify server ID
const weatherResult = await client.callTool({
name: "get-forecast",
arguments: { /* ... */ }
}, undefined, "weather"); // Specify server ID
// Set a default server for subsequent operations
client.setDefaultServer("weather");
// Now we can call the weather server without specifying the ID
const forecast = await client.callTool({
name: "get-forecast",
arguments: { /* ... */ }
});
// Close a specific connection
await client.closeConnection("gmail");
// Close all connections
await client.closeAll();Creating a Server that Accepts Direct Access Tokens
import { McpServer, StdioServerTransport } from '@modelcontextprotocol/sdk-direct-auth';
import { z } from "zod";
// Create a server that can validate Gmail tokens
const server = new McpServer({
name: "GmailServer",
version: "1.0.0"
}, {
tokenValidator: async (tokenType, token) => {
// Verify the token with Google's token info endpoint
const response = await fetch(`https://oauth2.googleapis.com/tokeninfo?access_token=${token}`);
return response.ok;
}
});
// Add a tool to send emails
server.tool(
"gmail-send-email",
{
to: z.string().email(),
subject: z.string(),
body: z.string()
},
async ({ to, subject, body }, context) => {
// The access token is available in the context
const accessToken = context.auth?.token;
// Use the token to call Gmail API
const response = await fetch('https://gmail.googleapis.com/gmail/v1/users/me/messages/send', {
method: 'POST',
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
raw: btoa(`To: ${to}\nSubject: ${subject}\n\n${body}`)
})
});
if (!response.ok) {
return {
content: [{ type: "text", text: "Failed to send email" }],
isError: true
}
}
return {
content: [{ type: "text", text: "Email sent successfully" }]
}
}
);
// Start the server
const transport = new StdioServerTransport();
await server.connect(transport);📖 API Reference
Client API
Client
class Client {
constructor(clientInfo: { name: string; version: string });
useDirectAccessToken(accessToken: string, tokenType?: string): Client;
connect(transport: any, serverId?: string): Promise<string>;
closeConnection(serverId: string): Promise<void>;
closeAll(): Promise<void>;
close(): Promise<void>; // Legacy method for backward compatibility
setDefaultServer(serverId: string): void;
getConnectedServers(): Array<{ serverId: string; serverInfo: any; isDefault: boolean }>;
// Standard MCP methods with server routing
ping(options?: any, serverId?: string): Promise<any>;
complete(params: any, options?: any, serverId?: string): Promise<any>;
setLoggingLevel(level: any, options?: any, serverId?: string): Promise<any>;
getPrompt(params: any, options?: any, serverId?: string): Promise<any>;
listPrompts(params?: any, options?: any, serverId?: string): Promise<any>;
listResources(params?: any, options?: any, serverId?: string): Promise<any>;
listResourceTemplates(params?: any, options?: any, serverId?: string): Promise<any>;
readResource(params: any, options?: any, serverId?: string): Promise<any>;
subscribeResource(params: any, options?: any, serverId?: string): Promise<any>;
unsubscribeResource(params: any, options?: any, serverId?: string): Promise<any>;
listTools(params?: any, options?: any, serverId?: string): Promise<any>;
callTool(params: any, options?: any, serverId?: string): Promise<any>;
}DirectAccessTokenProvider
interface DirectAccessTokenProvider {
getAccessToken(): string | Promise<string>;
getTokenType(): string | Promise<string>;
}Server API
McpServer
class McpServer {
constructor(
serverInfo: { name: string; version: string },
options?: TokenValidationOptions & { capabilities?: any }
);
connect(transport: any): Promise<void>;
tool(name: string, inputSchema: any, handler: (params: any, context?: any) => Promise<any>): void;
resource(name: string, template: any, handler: (uri: any, params: any, context?: any) => Promise<any>): void;
}TokenValidationOptions
interface TokenValidationOptions {
tokenValidator?: (tokenType: string, token: string) => Promise<boolean>;
}AuthContext
interface AuthContext {
token: string;
tokenType: string;
}Transport Extensions
StdioClientTransport
class StdioClientTransport {
constructor(options: { command: string; args?: string[] });
setRequestHeader(name: string, value: string): void;
}SSEClientTransport
class SSEClientTransport {
constructor(baseUrl: string, options?: any);
setRequestHeader(name: string, value: string): void;
}🔄 Differences from Standard MCP SDK
- Added
DirectAccessTokenProviderinterface - Enhanced
Clientclass withuseDirectAccessTokenmethod - Added multi-server support to the client
- Modified transports to support authorization headers
- Added token validation to the server
- Enhanced tool/resource context with auth information
📚 Examples
The /examples directory contains complete working examples:
gmail-server.js: An MCP server that integrates with Gmailgmail-client.js: An MCP client that uses a direct Gmail access tokenmulti-server-client.js: A client that connects to multiple servers simultaneously
To run the examples:
# Build the package
npm run build
# Run the multi-server example
node dist/esm/examples/multi-server-client.js
# Run the Gmail client example
node dist/esm/examples/gmail-client.js🌐 GitHub API Integration
This SDK extension includes built-in support for GitHub API integration, making it easy to build GitHub-powered tools and applications.
GitHub Utilities
The SDK provides utility functions for working with the GitHub API:
// Build a URL with query parameters
await buildUrl(baseUrl, params);
// Make a request to the GitHub API
await githubRequest(url, options);
// Get the authenticated user's profile
await getCurrentUser(token);GitHub Search Functions
The SDK includes comprehensive GitHub search capabilities:
// Search for GitHub users
await searchUsers(params, token);
// Search for GitHub issues
await searchIssues(params, token);
// Search for GitHub repositories
await searchRepos(params, token);
// Search for code in GitHub repositories
await searchCode(params, token);Creating a GitHub Server
Here's an example of creating an MCP server that provides GitHub functionality:
import { McpServer, StdioServerTransport } from '@modelcontextprotocol/sdk-direct-auth';
import * as search from './common/search.js';
import { getCurrentUser } from './common/utils.js';
// Create the MCP server with GitHub token validation
const server = new McpServer(
{
name: "GitHubServer",
version: "1.0.0",
},
{
// Validate token with GitHub API
tokenValidator: async (tokenType, token) => {
try {
const response = await fetch("https://api.github.com/user", {
headers: {
Authorization: `${tokenType} ${token}`,
Accept: "application/vnd.github.v3+json",
"User-Agent": "MCP-GitHub-Client",
},
});
return response.status === 200;
} catch (error) {
return false;
}
},
}
);
// Register GitHub search tools
server.tool(
"search_users",
search.SearchUsersSchema.shape,
async (args, context) => {
const token = context.auth?.token;
if (!token) throw new Error("Authentication required");
const results = await search.searchUsers(args, token);
return {
content: [{ type: "text", text: JSON.stringify(results, null, 2) }],
};
}
);
// Start the server
const transport = new StdioServerTransport();
server.connect(transport);Creating a GitHub Client
Connect to a GitHub server and make authenticated requests:
import { Client, StdioClientTransport } from '@modelcontextprotocol/sdk-direct-auth';
const client = new Client({
name: "github-client",
version: "1.0.0",
});
// Connect to the GitHub server
const transport = new StdioClientTransport({
command: "node",
args: ["./github-server.js"],
});
const serverId = await client.connect(transport);
// Use direct access token authentication with GitHub
client.useDirectAccessToken(githubToken, "Bearer");
// Search for GitHub users
const userResults = await client.callTool({
name: "search_users",
arguments: {
q: "octocat",
sort: "followers",
order: "desc",
per_page: 3,
},
});
// Get the authenticated user profile
const profile = await client.callTool({
name: "get_current_user",
arguments: {},
});🤝 Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the project
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
📄 License
This project is licensed under the MIT License - see the LICENSE file for details.
