Skip to main content
Glama
yoda-digital

Cerebra Legal MCP Server

by yoda-digital
LegalAskFollowupQuestionTool.ts6.86 kB
import { DomainDetector } from '../shared/DomainDetector.js'; import { LegalKnowledgeBase } from '../shared/LegalKnowledgeBase.js'; import { LegalAskFollowupQuestionInput, LegalAskFollowupQuestionResponse, ToolResponse } from '../shared/types.js'; import { logger } from '../utils/logger.js'; /** * LegalAskFollowupQuestionTool class for implementing the legal_ask_followup_question tool */ export class LegalAskFollowupQuestionTool { private domainDetector: DomainDetector; private legalKnowledgeBase: LegalKnowledgeBase; /** * Constructor * @param domainDetector - Domain detector instance * @param legalKnowledgeBase - Legal knowledge base instance */ constructor( domainDetector: DomainDetector, legalKnowledgeBase: LegalKnowledgeBase ) { this.domainDetector = domainDetector; this.legalKnowledgeBase = legalKnowledgeBase; logger.info('LegalAskFollowupQuestionTool initialized'); } /** * Process a question request * @param input - The input data * @returns Tool response */ public processQuestion(input: unknown): ToolResponse { try { logger.debug('Processing question request', input); // Validate input const validatedInput = this.validateQuestionData(input as LegalAskFollowupQuestionInput); // Detect domain from question and context const textToAnalyze = validatedInput.context ? `${validatedInput.question} ${validatedInput.context}` : validatedInput.question; const domain = this.domainDetector.detectDomain(textToAnalyze); // If no options provided, suggest domain-specific options let options = validatedInput.options; if (!options || options.length === 0) { options = this.suggestDomainSpecificOptions(validatedInput.question, domain); } // Format the question with legal terminology const formattedQuestion = this.formatLegalQuestion(validatedInput.question, domain); // Prepare response const response: LegalAskFollowupQuestionResponse = { question: formattedQuestion, options: options, detectedDomain: domain }; logger.debug('Question processed successfully', response); return { content: [{ type: "text", text: JSON.stringify(response, null, 2) }] }; } catch (error) { // Log and handle errors logger.error('Error processing question', error as Error); return { content: [{ type: "text", text: JSON.stringify({ error: error instanceof Error ? error.message : String(error), status: 'failed' }, null, 2) }], isError: true }; } } /** * Validate question data * @param input - The input to validate * @returns Validated input * @throws Error if validation fails */ private validateQuestionData(input: LegalAskFollowupQuestionInput): LegalAskFollowupQuestionInput { if (!input) { throw new Error('Input is required'); } if (!input.question || typeof input.question !== 'string') { throw new Error('Question must be a non-empty string'); } // Validate options if provided if (input.options) { if (!Array.isArray(input.options)) { throw new Error('Options must be an array'); } if (input.options.length > 0 && input.options.length < 2) { throw new Error('Options must contain at least 2 items'); } if (input.options.length > 5) { throw new Error('Options must contain at most 5 items'); } for (const option of input.options) { if (typeof option !== 'string' || option.trim() === '') { throw new Error('Each option must be a non-empty string'); } } } return { question: input.question, options: input.options, context: input.context }; } /** * Suggest domain-specific options based on the question and domain * @param question - The question * @param domain - The detected domain * @returns Array of suggested options */ private suggestDomainSpecificOptions(question: string, domain: string): string[] { // Get domain-specific question templates const templates = this.legalKnowledgeBase.getQuestionTemplates(domain); // Select most relevant templates based on question const relevantTemplates = this.selectRelevantTemplates(question, templates); // Return up to 4 options return relevantTemplates.slice(0, 4); } /** * Select the most relevant templates based on the question * @param question - The question * @param templates - Available templates * @returns Array of relevant templates */ private selectRelevantTemplates(question: string, templates: string[]): string[] { // Simple relevance scoring based on keyword matching const scoredTemplates = templates.map(template => { const words = question.toLowerCase().split(/\s+/); let score = 0; for (const word of words) { if (word.length > 3 && template.toLowerCase().includes(word)) { score += 1; } } return { template, score }; }); // Sort by score (descending) scoredTemplates.sort((a, b) => b.score - a.score); // Return templates return scoredTemplates.map(item => item.template); } /** * Format a question with appropriate legal terminology * @param question - The original question * @param domain - The detected domain * @returns Formatted question */ private formatLegalQuestion(question: string, domain: string): string { // Add domain-specific legal terminology if not present if (domain === 'ansc_contestation') { if (!question.includes('procurement') && !question.includes('tender') && !question.includes('ANSC')) { question = question.replace(/specifications/i, 'procurement specifications'); question = question.replace(/requirements/i, 'tender requirements'); } } else if (domain === 'consumer_protection') { if (!question.includes('warranty') && !question.includes('consumer')) { question = question.replace(/product/i, 'consumer product'); question = question.replace(/refund/i, 'consumer refund'); } } else if (domain === 'contract_analysis') { if (!question.includes('clause') && !question.includes('contract')) { question = question.replace(/agreement/i, 'contractual agreement'); question = question.replace(/terms/i, 'contractual terms'); } } // Ensure question ends with a question mark if (!question.endsWith('?')) { question += '?'; } return question; } }

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/yoda-digital/mcp-cerebra-legal-server'

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