Skip to main content
Glama
index.ts6.66 kB
// Helper function to format text with proper line breaks export function formatText(text: string): string { if (!text) return ""; // Replace multiple spaces with single spaces, but preserve intentional line breaks let formatted = text.replace(/\s+/g, " ").trim(); // Convert markdown-style line breaks formatted = formatted // Convert ## headers to have line breaks .replace(/##\s+/g, "\n\n## ") // Convert - list items to have line breaks .replace(/\s+-\s+/g, "\n- ") // Convert ✅ checkmarks to have line breaks .replace(/\s+✅/g, "\n\n✅") // Convert numbered lists .replace(/\s+(\d+\.)\s+/g, "\n$1 ") // Convert [ ] checkboxes to have line breaks .replace(/\s+-\s+\[\s*\]/g, "\n- [ ]") // Convert [x] checkboxes to have line breaks .replace(/\s+-\s+\[x\]/g, "\n- [x]") // Add line breaks before "## " sections .replace(/([^#])(##\s+)/g, "$1\n\n$2") // Add line breaks before status indicators .replace( /([^\n])(##\s+Current Status|##\s+Testing|##\s+Requirements)/g, "$1\n\n$2" ); return formatted; } // Helper function to format API responses for MCP export function formatResponse(data: any): any { // Format the data first (for text fields) const formattedData = formatDataFields(data); // Return in MCP response format return { content: [ { type: "text" as const, text: JSON.stringify(formattedData, null, 2), }, ], }; } // Helper function to format data fields function formatDataFields(data: any): any { if (!data) return data; // If it's an array, format each item if (Array.isArray(data)) { return data.map(formatDataFields); } // If it's an object, format specific fields if (typeof data === "object" && data !== null) { const formatted = { ...data }; // Format description fields if (formatted.description && typeof formatted.description === 'string') { formatted.description = formatText(formatted.description); } // Format comment fields if (formatted.comment && typeof formatted.comment === 'string') { formatted.comment = formatText(formatted.comment); } return formatted; } return data; } // Delete safety validation functions import { config } from "../config/index.js"; export type DeleteType = "board" | "task" | "label"; export interface DeleteSafetyError { allowed: false; reason: string; code: "DELETES_DISABLED" | "DELETE_TYPE_NOT_ALLOWED" | "CONFIRMATION_REQUIRED"; } export interface DeleteSafetySuccess { allowed: true; } export type DeleteSafetyResult = DeleteSafetyError | DeleteSafetySuccess; /** * Check if a delete operation is allowed based on configuration */ export function validateDeleteOperation( deleteType: DeleteType, confirmDelete?: boolean | string ): DeleteSafetyResult { const { deleteSafety } = config; // Check if deletes are enabled at all if (!deleteSafety.enableDeletes) { return { allowed: false, reason: `Delete operations are disabled. Set ENABLE_DELETES=true in environment to enable.`, code: "DELETES_DISABLED" }; } // Check if this specific delete type is allowed if (deleteSafety.allowedDeleteTypes.length > 0 && !deleteSafety.allowedDeleteTypes.includes(deleteType)) { return { allowed: false, reason: `Delete operations for '${deleteType}' are not allowed. Allowed types: ${deleteSafety.allowedDeleteTypes.join(', ')}`, code: "DELETE_TYPE_NOT_ALLOWED" }; } // Check confirmation requirement if (deleteSafety.requireConfirmation) { const confirmValue = typeof confirmDelete === "string" ? confirmDelete.toLowerCase() : confirmDelete; if (confirmValue !== true && confirmValue !== "yes" && confirmValue !== "confirm") { return { allowed: false, reason: `Confirmation required for delete operations. Add 'confirm_delete: true' or 'confirm_delete: "yes"' parameter.`, code: "CONFIRMATION_REQUIRED" }; } } return { allowed: true }; } /** * Create a standardized error for delete safety violations */ export function createDeleteSafetyError(result: DeleteSafetyError) { return { error: "Delete operation not allowed", reason: result.reason, code: result.code, message: "Delete operation blocked by safety configuration" }; } // Board focus validation functions export interface BoardFocusError { allowed: false; reason: string; code: "OUT_OF_FOCUS" | "FOCUS_BOARD_ONLY"; } export interface BoardFocusSuccess { allowed: true; } export type BoardFocusResult = BoardFocusError | BoardFocusSuccess; /** * Check if access to a specific board is allowed based on board focus configuration */ export function validateBoardAccess(boardId: number): BoardFocusResult { const { boardFocus } = config; // If board focus is not enabled, allow all boards if (!boardFocus.enabled || !boardFocus.boardId) { return { allowed: true }; } // Check if the requested board matches the focused board if (boardId !== boardFocus.boardId) { return { allowed: false, reason: `Operations are focused on board ${boardFocus.boardId}. Access to board ${boardId} is outside the current focus scope.`, code: "OUT_OF_FOCUS" }; } return { allowed: true }; } /** * Check if board-wide operations are allowed (like creating/listing boards) */ export function validateBoardWideOperation(): BoardFocusResult { const { boardFocus } = config; // If board focus is enabled, streamline to focus board operations only if (boardFocus.enabled && boardFocus.boardId) { return { allowed: false, reason: `Operations are streamlined for board ${boardFocus.boardId}. Use get_board with board_id ${boardFocus.boardId} to access board details.`, code: "FOCUS_BOARD_ONLY" }; } return { allowed: true }; } /** * Create a standardized error for board focus scope violations */ export function createBoardFocusError(result: BoardFocusError) { return { error: "Operation outside board focus scope", reason: result.reason, code: result.code, message: "Operation not available in board focus mode" }; } /** * Get the focused board ID if board focus is enabled */ export function getFocusedBoardId(): number | null { const { boardFocus } = config; return boardFocus.enabled && boardFocus.boardId ? boardFocus.boardId : null; } /** * Check if board focus mode is enabled */ export function isBoardFocusEnabled(): boolean { const { boardFocus } = config; return boardFocus.enabled && !!boardFocus.boardId; }

Implementation Reference

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/danieliser/fluent-boards-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server