@the_cfdude/productboard-mcp
Version:
Model Context Protocol server for Productboard REST API with dynamic tool loading
100 lines (99 loc) • 3.24 kB
JavaScript
/**
* Custom error types for Productboard MCP server
*/
import { ErrorCode } from '@modelcontextprotocol/sdk/types.js';
export class ProductboardError extends Error {
code;
originalError;
constructor(code, message, originalError) {
super(message);
this.code = code;
this.originalError = originalError;
this.name = 'ProductboardError';
}
}
export class ValidationError extends ProductboardError {
field;
constructor(message, field) {
super(ErrorCode.InvalidRequest, message);
this.field = field;
this.name = 'ValidationError';
}
}
export class AuthenticationError extends ProductboardError {
constructor(message = 'Authentication failed') {
super(ErrorCode.InvalidRequest, message);
this.name = 'AuthenticationError';
}
}
export class RateLimitError extends ProductboardError {
retryAfter;
constructor(retryAfter) {
super(ErrorCode.InvalidRequest, `Rate limit exceeded${retryAfter ? `. Retry after ${retryAfter}s` : ''}`);
this.retryAfter = retryAfter;
this.name = 'RateLimitError';
}
}
export class NetworkError extends ProductboardError {
constructor(message, originalError) {
super(ErrorCode.InternalError, message, originalError);
this.name = 'NetworkError';
}
}
export class ConfigurationError extends ProductboardError {
constructor(message) {
super(ErrorCode.InternalError, message);
this.name = 'ConfigurationError';
}
}
/**
* Sanitize error messages to prevent information leakage
* Enhanced with contextual documentation hints
*/
export function sanitizeErrorMessage(error, toolName) {
const docHint = toolName
? ` Use 'get_${getEntityTypeFromTool(toolName)}_docs()' for complete API documentation.`
: '';
if (error instanceof ValidationError) {
const message = error.field ? `Invalid ${error.field}` : 'Invalid input';
return `${message}.${docHint}`;
}
if (error instanceof AuthenticationError) {
return `Authentication failed.${docHint}`;
}
if (error instanceof RateLimitError) {
return `${error.message}.${docHint}`;
}
if (error instanceof NetworkError) {
return `Network error occurred.${docHint}`;
}
if (error instanceof ConfigurationError) {
return `Configuration error.${docHint}`;
}
// Generic error - don't expose details
return `An error occurred processing your request.${docHint}`;
}
/**
* Extract entity type from tool name for contextual documentation
*/
function getEntityTypeFromTool(toolName) {
if (toolName.includes('feature'))
return 'feature';
if (toolName.includes('note'))
return 'note';
if (toolName.includes('component'))
return 'component';
if (toolName.includes('product'))
return 'product';
if (toolName.includes('company'))
return 'company';
if (toolName.includes('user'))
return 'user';
if (toolName.includes('objective'))
return 'objective';
if (toolName.includes('initiative'))
return 'initiative';
if (toolName.includes('release'))
return 'release';
return 'general';
}