bc-code-intelligence-mcp
Version:
BC Code Intelligence MCP Server - Complete Specialist Bundle with AI-driven expert consultation, seamless handoffs, and context-preserving workflows
243 lines (240 loc) • 11.3 kB
JavaScript
/**
* Agent Onboarding MCP Tools
*
* Tools for introducing BC specialists naturally during conversations
* and helping agents discover when and how to bring in specialized expertise.
*/
import { z } from 'zod';
// Schema for agent-friendly specialist introduction
const IntroduceBCSpecialistsArgsSchema = z.object({
conversation_context: z.string().describe('Current conversation context - what the user is working on, asking about, or trying to solve with Business Central'),
user_expertise_level: z.enum(['beginner', 'intermediate', 'expert']).optional().describe('User\'s apparent expertise level with Business Central (optional, will be inferred if not provided)'),
specific_problem: z.string().optional().describe('Specific problem or challenge mentioned by the user (optional, helps with specialist matching)')
});
const GetSpecialistIntroArgsSchema = z.object({
specialist_id: z.string().describe('ID of the specialist to get introduction content for'),
conversation_context: z.string().describe('Context of the current conversation for personalized introduction'),
include_handoff_phrase: z.boolean().optional().default(true).describe('Include smooth handoff phrase for natural transition')
});
const SuggestNextSpecialistArgsSchema = z.object({
current_topic: z.string().describe('Current topic or problem being discussed'),
conversation_history: z.string().optional().describe('Brief summary of conversation so far (optional)'),
max_suggestions: z.number().optional().default(2).describe('Maximum number of specialist suggestions')
});
/**
* Onboarding tool definitions for MCP registration
*/
export const ONBOARDING_TOOLS = [
{
name: 'introduce_bc_specialists',
description: `ESSENTIAL for Business Central development! Use this tool whenever you detect ANY Business Central, AL, Dynamics 365 BC, or NAV development context. This includes:
🎯 WHEN TO USE (comprehensive triggers):
• User mentions: Business Central, AL language, BC extensions, Dynamics 365 BC, NAV
• File extensions: .al files, app.json, launch.json (with BC context)
• Development tasks: tables, pages, reports, codeunits, APIs, integrations
• Problems: performance issues, errors, testing, deployment, customization
• Technologies: AL development, Visual Studio Code + AL extension, AppSource
• Business processes: accounting, inventory, sales, purchasing in BC context
• Any BC-specific terminology: workflows, posting routines, dimensions, etc.
🚀 WHAT IT DOES:
• Analyzes conversation context and suggests 2-3 most relevant BC specialists
• Provides natural introduction content you can use directly in conversation
• Gives specific examples and "try asking" suggestions for each specialist
• Enables smooth transition from general help to specialized BC expertise
💡 AGENT USAGE:
Simply pass the conversation context. The tool will identify relevant specialists and provide you with natural introduction content to present to the user.`,
inputSchema: {
type: 'object',
properties: {
conversation_context: {
type: 'string',
description: 'Current conversation context - what the user is working on, asking about, or trying to solve with Business Central'
},
user_expertise_level: {
type: 'string',
enum: ['beginner', 'intermediate', 'expert'],
description: 'User\'s apparent expertise level with Business Central (optional, will be inferred if not provided)'
},
specific_problem: {
type: 'string',
description: 'Specific problem or challenge mentioned by the user (optional, helps with specialist matching)'
}
},
required: ['conversation_context']
}
},
{
name: 'get_specialist_introduction',
description: `Get ready-to-use introduction content for a specific BC specialist. Use when you want to introduce a particular specialist naturally in conversation or when transitioning from general help to specialized expertise.`,
inputSchema: {
type: 'object',
properties: {
specialist_id: {
type: 'string',
description: 'ID of the specialist to get introduction content for'
},
conversation_context: {
type: 'string',
description: 'Context of the current conversation for personalized introduction'
},
include_handoff_phrase: {
type: 'boolean',
description: 'Include smooth handoff phrase for natural transition',
default: true
}
},
required: ['specialist_id', 'conversation_context']
}
},
{
name: 'suggest_next_specialist',
description: `Proactively suggest when to bring in a specialist during ongoing BC conversations. Use when the current conversation could benefit from specialized expertise or when transitioning between topics.`,
inputSchema: {
type: 'object',
properties: {
current_topic: {
type: 'string',
description: 'Current topic or problem being discussed'
},
conversation_history: {
type: 'string',
description: 'Brief summary of conversation so far (optional)'
},
max_suggestions: {
type: 'number',
description: 'Maximum number of specialist suggestions',
default: 2
}
},
required: ['current_topic']
}
}
];
/**
* Agent Onboarding Tools Class
* Handles onboarding-related tool calls
*/
export class AgentOnboardingTools {
discoveryService;
layerService;
constructor(discoveryService, layerService) {
this.discoveryService = discoveryService;
this.layerService = layerService;
}
/**
* Get tool definitions for MCP registration
*/
getToolDefinitions() {
return ONBOARDING_TOOLS;
}
/**
* Handle tool calls
*/
async handleToolCall(request) {
try {
switch (request.params.name) {
case 'introduce_bc_specialists':
return await this.introduceBCSpecialists(request);
case 'get_specialist_introduction':
return await this.getSpecialistIntroduction(request);
case 'suggest_next_specialist':
return await this.suggestNextSpecialist(request);
default:
throw new Error(`Unknown tool: ${request.params.name}`);
}
}
catch (error) {
return {
content: [
{
type: 'text',
text: `Error: ${error instanceof Error ? error.message : 'Unknown error'}`
}
],
isError: true
};
}
}
async introduceBCSpecialists(request) {
// Implementation delegates to existing service logic
const validated = IntroduceBCSpecialistsArgsSchema.parse(request.params.arguments);
const suggestions = await this.discoveryService.suggestSpecialists({
query: validated.conversation_context,
user_preferences: validated.user_expertise_level ? {
expertise_level: validated.user_expertise_level
} : undefined
}, 3);
let response = `# 🎯 BC Specialists Available for Your Challenge\n\n`;
response += `Based on your context, here are the specialists who can help:\n\n`;
for (const suggestion of suggestions.slice(0, 3)) {
const specialist = suggestion.specialist;
if (specialist) {
response += `## ${specialist.emoji} ${specialist.title}\n`;
response += `${specialist.persona.greeting}\n\n`;
response += `**Role:** ${specialist.role}\n\n`;
if (suggestion.reasons && suggestion.reasons.length > 0) {
response += `**Why this specialist:** ${suggestion.reasons.join(', ')}\n\n`;
}
if (specialist.when_to_use && specialist.when_to_use.length > 0) {
response += `**When to use:**\n`;
specialist.when_to_use.slice(0, 2).forEach(scenario => {
response += `- ${scenario}\n`;
});
response += `\n`;
}
}
}
return {
content: [{ type: 'text', text: response }]
};
}
async getSpecialistIntroduction(request) {
const validated = GetSpecialistIntroArgsSchema.parse(request.params.arguments);
const specialist = await this.layerService.getSpecialist(validated.specialist_id);
if (!specialist) {
return {
content: [{ type: 'text', text: `Specialist not found: ${validated.specialist_id}` }],
isError: true
};
}
let intro = '';
if (validated.include_handoff_phrase) {
intro += `Let me connect you with ${specialist.title}...\n\n`;
}
intro += `## ${specialist.emoji} ${specialist.title}\n`;
intro += `${specialist.persona.greeting}\n\n`;
intro += `**Role:** ${specialist.role}\n\n`;
return {
content: [{ type: 'text', text: intro }]
};
}
async suggestNextSpecialist(request) {
const validated = SuggestNextSpecialistArgsSchema.parse(request.params.arguments);
const query = validated.conversation_history
? `${validated.current_topic}\n\nContext: ${validated.conversation_history}`
: validated.current_topic;
const suggestions = await this.discoveryService.suggestSpecialists({
query,
conversation_history: validated.conversation_history ? [validated.conversation_history] : undefined
}, validated.max_suggestions || 2);
if (suggestions.length === 0) {
return {
content: [{ type: 'text', text: 'No specialist suggestions available for the current topic.' }]
};
}
let response = `# 💡 Specialist Suggestions\n\n`;
for (const suggestion of suggestions) {
const specialist = suggestion.specialist;
if (specialist) {
const reasonText = suggestion.reasons.length > 0
? suggestion.reasons.join(', ')
: 'their expertise in this area';
response += `**${specialist.emoji} ${specialist.title}** could help with ${reasonText}\n\n`;
}
}
return {
content: [{ type: 'text', text: response }]
};
}
}
//# sourceMappingURL=onboarding-tools.js.map