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
JavaScript
/**
* 工具函数,用于处理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';
}