UNPKG

cnb-mcp-server

Version:

MCP Server for the cnb API, enabling file operations, repository management, search functionality, and more.

114 lines (113 loc) 4.06 kB
/** * 工具函数,用于处理API请求和响应 */ import { CNBError, CNBValidationError, CNBResourceNotFoundError, CNBAuthenticationError, CNBPermissionError, CNBRateLimitError, CNBConflictError } from './errors.js'; /** * 发送请求到CNB API */ export async function makeRequest(endpoint, options = {}, accessToken) { const baseUrl = getBaseUrl(); const url = `${baseUrl}${endpoint.startsWith('/') ? endpoint : `/${endpoint}`}`; // 设置默认请求头 const headers = { 'Accept': 'application/json', 'Content-Type': 'application/json', ...(options.headers || {}) }; // 添加授权头 if (accessToken || process.env.CNB_ACCESS_TOKEN) { headers['Authorization'] = `${getAccessToken(accessToken)}`; } // 创建请求选项 const requestOptions = { method: options.method || 'GET', headers, body: options.body }; try { const response = await fetch(url, requestOptions); // 处理特定的HTTP状态码 if (response.status === 401) { throw new CNBAuthenticationError('Authentication failed. Please check your credentials.'); } else if (response.status === 403) { throw new CNBPermissionError('You do not have permission to access this resource.'); } else if (response.status === 404) { throw new CNBResourceNotFoundError('The requested resource was not found.'); } else if (response.status === 409) { throw new CNBConflictError('Conflict detected. The resource may have been modified by another request.'); } else if (response.status === 422) { const data = await response.json(); throw new CNBValidationError('Validation failed.', data); } else if (response.status === 429) { // 处理速率限制 const resetAt = new Date(response.headers.get('X-RateLimit-Reset') || Date.now() + 60000); throw new CNBRateLimitError('API rate limit exceeded.', resetAt); } else if (!response.ok) { // 处理其他错误 const data = await response.text(); throw new CNBError(`Request failed with status ${response.status}: ${data}`); } // 判断响应内容类型 const contentType = response.headers.get('Content-Type') || ''; if (contentType.includes('application/json')) { return await response.json(); } else { return await response.text(); } } catch (error) { if (error instanceof CNBError) { throw error; } else { throw new CNBError(`Request failed: ${error instanceof Error ? error.message : String(error)}`); } } } /** * 获取查询参数对象 */ export function getQueryParams(params) { const queryParams = new URLSearchParams(); Object.entries(params) .filter(([_, value]) => value !== undefined && value !== null) .forEach(([key, value]) => { if (Array.isArray(value)) { value.forEach(item => queryParams.append(key, String(item))); } else { queryParams.append(key, String(value)); } }); const queryString = queryParams.toString(); return queryString ? `?${queryString}` : ''; } /** * 获取当前用户身份信息 */ export async function getCurrentUser(accessToken) { return makeRequest('/user', {}, accessToken); } /** * 获取CNB API访问令牌,优先使用传入的token,否则从环境变量获取 */ export function getAccessToken(accessToken) { const token = accessToken || process.env.CNB_ACCESS_TOKEN; if (!token) { throw new CNBAuthenticationError('No access token provided. Set CNB_ACCESS_TOKEN environment variable or pass token directly.'); } return token; } /** * 获取CNB API的基础URL */ export function getBaseUrl() { return process.env.CNB_API_URL || 'https://api.cnb.cool'; }