@equidam/mcp-server
Version:
Equidam MCP Server - Bridge between AI assistants and Equidam's company valuation API
293 lines (256 loc) • 10.8 kB
JavaScript
/**
* Industry Classification Tool for MCP
* Handles the classify_company_industry tool calls
*/
/**
* Tool definition for industry classification
*/
const CLASSIFY_TOOL_DEFINITION = {
name: "classify_company_industry",
description: `Classify a company's industry from natural language description and return the industry code needed for valuation.
PURPOSE: This tool analyzes business descriptions and returns standardized TRBC industry codes that can be used with the get_company_valuation tool.
USAGE TIPS:
- Ask for detailed business descriptions including products, services, target market
- Be specific about the company's primary revenue source
- The returned industry_code is required for valuation calculations
- If confidence is low, the tool will guide you to ask for more specific business details
- If multiple options are returned, use select_industry_classification to let user choose
IMPORTANT: This tool can return different response types:
1. 'needs_more_information' - Ask user for better business description using provided guidance
2. 'multiple_options_available' - Present options to user and use select_industry_classification
3. 'classification_complete' - Use the industry_code for valuation
VALIDATION: If errors occur, they contain detailed guidance on how to ask users for better descriptions.`,
inputSchema: {
type: "object",
properties: {
description: {
type: "string",
description: "Natural language description of the company's business (REQUIRED, 3-1000 characters). Be specific about business model, products/services, and target market. Examples: 'We develop mobile apps for food delivery', 'AI-powered medical diagnostic software'",
minLength: 3,
maxLength: 1000
},
context: {
type: "array",
description: "Optional additional context to improve classification accuracy (max 10 items). Examples: ['B2B SaaS', 'AI-powered', 'consumer marketplace']",
items: {
type: "string",
maxLength: 500
},
maxItems: 10
}
},
required: ["description"]
}
};
/**
* Handle industry classification tool calls
* @param {object} apiClient - Equidam API client instance
* @param {Function} debugLog - Debug logging function
* @returns {Function} - Tool handler function
*/
function createClassifyHandler(apiClient, debugLog) {
return async (params) => {
debugLog('Processing industry classification request:', {
description: params.description?.substring(0, 100) + (params.description?.length > 100 ? '...' : ''),
contextItems: params.context?.length || 0
});
try {
// Validate input parameters
if (!params.description || typeof params.description !== 'string') {
throw new Error('description parameter is required and must be a string');
}
if (params.description.trim().length < 3) {
throw new Error('description must be at least 3 characters long');
}
if (params.description.length > 1000) {
throw new Error('description must be less than 1000 characters long');
}
if (params.context && !Array.isArray(params.context)) {
throw new Error('context parameter must be an array of strings');
}
if (params.context && params.context.some(item => typeof item !== 'string')) {
throw new Error('all context items must be strings');
}
// Call the API
const result = await apiClient.classifyIndustry({
description: params.description,
context: params.context
});
debugLog('Industry classification successful:', {
industry_code: result.industry_code,
industry_name: result.industry_name,
confidence: result.confidence
});
// Handle enhanced response with UX scenarios
return handleEnhancedClassificationResponse(result);
} catch (error) {
debugLog('Industry classification error:', error.message);
// Return enhanced error information for LLM
return {
isError: true,
error: error.message,
code: 'CLASSIFICATION_ERROR',
llm_guidance: 'This error contains validation details. Please read the error message carefully and ask the user for more specific information about their business. The description should include business model, products/services, and target market.'
};
}
};
}
/**
* Handle enhanced classification response with UX scenarios
* @param {object} result - API response
* @returns {object} - Formatted MCP response
*/
function handleEnhancedClassificationResponse(result) {
// Check for new response_type field first (new format)
if (result.response_type === 'multiple_options_available') {
return {
success: true,
response_type: 'multiple_options_available',
message: result.message,
ai_recommendation: result.ai_recommendation,
alternatives: result.alternatives,
llm_instruction: formatMultipleOptionsPresentation(result),
guidance: result.llm_guidance,
selection_required: result.selection_required,
usage_note: result.usage_note,
next_step: "User should select an option, then use select_industry_classification tool"
};
}
// Check if this is an enhanced response with legacy status field
if (result.status) {
switch (result.status) {
case 'needs_more_information':
return {
success: false,
status: 'needs_more_information',
message: result.message,
confidence: result.confidence,
llm_instruction: result.llm_guidance?.example_followup ||
"I need more details about your business to classify it accurately. Can you describe your main products/services, target customers, business model, and primary revenue streams?",
guidance: result.llm_guidance,
partial_result: result.partial_result
};
case 'multiple_options_available':
return {
success: true,
status: 'multiple_options_available',
message: result.message,
options: result.options,
llm_instruction: result.llm_guidance?.example_presentation ||
`I found several possible industry classifications for your business:\n\n${result.options.map((opt, idx) =>
`${idx + 1}. ${opt.name} (${opt.code}) - ${opt.description}`
).join('\n')}\n\nWhich one best describes your company's primary business?`,
guidance: result.llm_guidance,
next_step: "User should select an option, then use select_industry_classification tool"
};
case 'classification_complete':
return formatClassificationResponse(result);
default:
// Fallback to standard formatting
return formatClassificationResponse(result);
}
}
// Legacy response format - use standard formatting
return formatClassificationResponse(result);
}
/**
* Format multiple options presentation for new response format
* @param {object} result - API response with ai_recommendation and alternatives
* @returns {string} - Formatted presentation string
*/
function formatMultipleOptionsPresentation(result) {
const aiRec = result.ai_recommendation;
const alternatives = result.alternatives || [];
let presentation = `Based on your business description, I recommend **${aiRec.name}** as the best fit, but here are all the options:\n\n`;
// Add AI recommendation with 🎯 emoji
presentation += `🎯 **Recommended**: ${aiRec.name} (${aiRec.code}) - ${Math.round(aiRec.confidence * 100)}% confidence\n`;
presentation += ` ${aiRec.description}\n\n`;
// Add alternatives with 📋 emoji
if (alternatives.length > 0) {
presentation += `📋 **Other Options**:\n`;
alternatives.forEach((alt, idx) => {
presentation += `${idx + 2}. ${alt.name} (${alt.code}) - ${Math.round(alt.confidence * 100)}% confidence\n`;
presentation += ` ${alt.description}\n`;
});
presentation += `\n`;
}
presentation += `Which option best describes your company's primary business? You can choose the recommended option or any alternative that fits better.`;
return presentation;
}
/**
* Format classification response for MCP (legacy and complete responses)
* @param {object} result - API response
* @returns {object} - Formatted MCP response
*/
function formatClassificationResponse(result) {
const response = {
success: true,
status: result.status || 'classification_complete',
industry_code: result.industry_code,
industry_name: result.industry_name,
confidence: result.confidence
};
// Include alternatives if available
if (result.alternatives && result.alternatives.length > 0) {
response.alternatives = result.alternatives.map(alt => ({
code: alt.code,
name: alt.name,
confidence: alt.confidence
}));
}
// Add helper text for users
response.usage_note = result.usage_note || "Use the 'industry_code' from this result as input for the get_company_valuation tool.";
// Add confidence interpretation
response.confidence_level = result.confidence_level || getConfidenceLevel(result.confidence || 0);
if (result.confidence < 0.6) {
response.suggestion = "Consider providing more specific details about the company's business model or industry.";
}
return response;
}
/**
* Get confidence level from score
* @param {number} confidence - Confidence score
* @returns {string} - Confidence level
*/
function getConfidenceLevel(confidence) {
if (confidence >= 0.8) {
return "High";
} else if (confidence >= 0.6) {
return "Medium";
} else {
return "Low";
}
}
/**
* Get example inputs for the classification tool
* @returns {Array} - Array of example inputs
*/
function getClassificationExamples() {
return [
{
description: "A software company that builds project management tools for remote teams",
context: ["B2B", "SaaS", "productivity software"]
},
{
description: "We manufacture electric vehicle batteries and charging infrastructure"
},
{
description: "Mobile app for food delivery connecting restaurants with customers",
context: ["marketplace", "on-demand", "mobile-first"]
},
{
description: "AI-powered medical diagnostic software for radiology departments"
},
{
description: "E-commerce platform selling handmade crafts and artisan products"
}
];
}
module.exports = {
CLASSIFY_TOOL_DEFINITION,
createClassifyHandler,
handleEnhancedClassificationResponse,
formatMultipleOptionsPresentation,
formatClassificationResponse,
getClassificationExamples
};