github-manager MCP Server
import { Octokit } from '@octokit/rest';
import { ErrorCode } from '@modelcontextprotocol/sdk/types.js';
import { GitHubError } from '../../types.js';
import { createGitHubError } from '../error/errorUtils.js';
export interface AuthResult {
username: string;
scopes: string[];
headers?: Record<string, string>;
}
export class GitHubAuthService {
constructor(private octokit: Octokit) {}
async verifyAuth(): Promise<AuthResult> {
try {
const { data: user, headers } = await this.octokit.users.getAuthenticated();
const scopes = headers['x-oauth-scopes'] || '';
const scopesList = scopes.split(',').map(s => s.trim());
return {
username: user.login,
scopes: scopesList,
headers: headers as Record<string, string>
};
} catch (error: any) {
throw createGitHubError({
message: 'Unable to authenticate',
code: ErrorCode.InternalError,
error,
context: {
action: 'verify_auth',
attempted_operation: 'authenticate_user'
}
});
}
}
verifyRequiredScopes(currentScopes: string[], requiredScopes: string[]): void {
const missingScopes = requiredScopes.filter(scope => !currentScopes.includes(scope));
if (missingScopes.length > 0) {
throw createGitHubError({
message: 'Insufficient permissions',
code: ErrorCode.InvalidParams,
error: new Error('Missing required scopes'),
context: {
action: 'verify_scopes',
required_scopes: requiredScopes,
current_scopes: currentScopes,
missing_scopes: missingScopes,
documentation: 'https://docs.github.com/apps/building-oauth-apps/understanding-scopes-for-oauth-apps'
}
});
}
}
async verifyAuthAndScopes(requiredScopes: string[]): Promise<AuthResult> {
const authResult = await this.verifyAuth();
this.verifyRequiredScopes(authResult.scopes, requiredScopes);
return authResult;
}
getRateLimitInfo(headers: Record<string, string>) {
return {
limit: headers['x-ratelimit-limit'],
remaining: headers['x-ratelimit-remaining'],
reset: headers['x-ratelimit-reset'],
used: headers['x-ratelimit-used']
};
}
}