UNPKG

@prsna_ai/mcp-server

Version:

Model Context Protocol server for PRSNA personality profiles and communication insights

285 lines 13.6 kB
import { z } from 'zod'; import { logger } from '../utils/logger.js'; import { PRSNAApiClient } from '../api/client.js'; import { safeJSONStringify, cleanObject } from '../utils/json.js'; // Input schemas const GetCommunicationTipsSchema = z.object({ profileId: z.string().optional(), name: z.string().optional(), scenario: z.string().optional() }).refine(data => data.profileId || data.name, { message: "Either profileId or name must be provided" }); // Helper to get API client function getApiClient() { const token = process.env.PRSNA_API_TOKEN; if (!token) { throw new Error('PRSNA_API_TOKEN environment variable is required. Please authenticate first.'); } return new PRSNAApiClient(token); } export async function getCommunicationTips(args) { try { const { profileId, name, scenario } = GetCommunicationTipsSchema.parse(args); logger.info('Getting communication tips', { profileId, name, scenario }); const client = getApiClient(); let profile; if (profileId) { profile = await client.getProfile(profileId); } else if (name) { profile = await client.findProfileByName(name); if (!profile) { client.destroy(); return { content: [{ type: "text", text: safeJSONStringify({ success: false, message: `No profile found for name: ${name}` }, 2) }] }; } } client.destroy(); if (!profile) { throw new Error('Profile not found'); } // Build comprehensive communication tips const tips = { success: true, profile: { id: profile._id, name: profile.name, jobTitle: profile.jobTitle, company: profile.company }, scenario: scenario || 'General Communication', // Core Communication Recommendations communicationStyle: { overview: profile.personalitySummary || 'No summary available', preferences: profile.communicationPreferences || 'No specific preferences noted', operatingStyle: profile.operatingStyle || 'Standard professional approach' }, // Dimension-based guidance dimensionGuidance: profile.dimensions.map(dim => ({ dimension: dim.dimension, dominantPole: dim.dominant_pole, confidence: dim.confidence_percentage, guidance: getDimensionCommunicationGuidance(dim.dimension, dim.dominant_pole, scenario) })), // Stored recommendations storedRecommendations: profile.communicationRecommendations || [], // Scenario-specific tips scenarioTips: generateScenarioTips(profile, scenario), // Key behaviors to adopt/avoid doAndDont: generateDoAndDont(profile), // Meeting and collaboration preferences collaborationTips: generateCollaborationTips(profile), // Additional context keyTraits: profile.keyTraits || [], professionalContext: profile.professionalContext || '', notes: profile.notes || '' }; logger.info('Communication tips generated', { profileId: profile._id, name: profile.name, scenario: scenario || 'general' }); return { content: [{ type: "text", text: safeJSONStringify(cleanObject(tips), 2) }] }; } catch (error) { const errorMessage = error.message; logger.error('Failed to get communication tips', { error: errorMessage }); return { content: [{ type: "text", text: safeJSONStringify({ success: false, message: 'Failed to get communication tips', error: errorMessage }, 2) }] }; } } // Helper functions for generating communication guidance function getDimensionCommunicationGuidance(dimension, pole, scenario) { const guidance = { expression: { 'Internal': 'Give them time to process. Send information in advance when possible. Respect their need for reflection before expecting responses.', 'External': 'Engage them in discussion. They think out loud, so encourage verbal processing. Schedule brainstorming sessions and interactive meetings.' }, reasoning: { 'Logic': 'Present facts, data, and logical arguments. Focus on objective analysis and rational decision-making criteria. Avoid emotional appeals.', 'Feeling': 'Consider the human impact of decisions. Acknowledge feelings and values. Show how proposals align with team harmony and individual well-being.' }, flexibility: { 'Structured': 'Provide clear agendas, timelines, and expectations. Give advance notice of changes. Respect their need for organization and planning.', 'Adaptive': 'Be flexible with meetings and deadlines. They thrive with options and spontaneity. Present multiple approaches and let them choose.' }, work_style: { 'Process-Driven': 'Respect established procedures. Explain the steps and methodology. Value thoroughness over speed. Provide detailed documentation.', 'Results-Driven': 'Focus on outcomes and efficiency. Cut to the chase quickly. Emphasize impact and results. Minimize unnecessary process discussion.' }, tempo: { 'Fast-Paced': 'Keep communications concise and action-oriented. Make quick decisions when possible. Maintain energy and momentum in interactions.', 'Deliberate-Paced': 'Allow time for careful consideration. Don\'t rush decisions. Provide thorough information and respect their methodical approach.' } }; const baseGuidance = guidance[dimension]?.[pole] || `Adapt communication style for ${pole} preference in ${dimension}`; if (scenario) { return `${baseGuidance} (Especially important for ${scenario.toLowerCase()} scenarios)`; } return baseGuidance; } function generateScenarioTips(profile, scenario) { const tips = []; if (!scenario) { return [ 'Consider their personality dimensions when choosing communication channels', 'Adapt your message timing and format to their preferences', 'Be mindful of their work style and tempo preferences' ]; } const scenarioLower = scenario.toLowerCase(); if (scenarioLower.includes('meeting')) { tips.push('Schedule meetings according to their tempo preference', 'Provide agenda in advance for structured personalities', 'Allow processing time for internal processors'); } if (scenarioLower.includes('feedback') || scenarioLower.includes('review')) { tips.push('Frame feedback according to their reasoning style (logic vs feeling)', 'Give specific examples and actionable suggestions', 'Consider their expression preference for delivery method'); } if (scenarioLower.includes('project') || scenarioLower.includes('collaboration')) { tips.push('Align project structure with their flexibility preference', 'Consider their work style when assigning tasks', 'Establish communication rhythms matching their tempo'); } if (scenarioLower.includes('conflict') || scenarioLower.includes('difficult')) { tips.push('Use their preferred reasoning style to address issues', 'Respect their need for processing time', 'Focus on solutions that align with their work style'); } return tips.length > 0 ? tips : ['Adapt communication approach based on their personality dimensions']; } function generateDoAndDont(profile) { const doList = []; const dontList = []; profile.dimensions.forEach((dim) => { switch (dim.dimension) { case 'expression': if (dim.dominant_pole === 'Internal') { doList.push('Give them time to think before expecting responses'); dontList.push('Put them on the spot in large group settings'); } else { doList.push('Engage them in verbal discussion and brainstorming'); dontList.push('Send complex information without follow-up discussion'); } break; case 'reasoning': if (dim.dominant_pole === 'Logic') { doList.push('Present data and objective analysis'); dontList.push('Make purely emotional appeals'); } else { doList.push('Consider impact on people and relationships'); dontList.push('Ignore the human element in decisions'); } break; case 'flexibility': if (dim.dominant_pole === 'Structured') { doList.push('Provide clear timelines and expectations'); dontList.push('Make last-minute changes without good reason'); } else { doList.push('Remain flexible with plans and approaches'); dontList.push('Insist on rigid adherence to original plans'); } break; case 'work_style': if (dim.dominant_pole === 'Process-Driven') { doList.push('Follow established procedures and protocols'); dontList.push('Skip steps or rush through processes'); } else { doList.push('Focus on outcomes and efficiency'); dontList.push('Get bogged down in unnecessary process details'); } break; case 'tempo': if (dim.dominant_pole === 'Fast-Paced') { doList.push('Keep communications concise and action-oriented'); dontList.push('Drag out discussions or decisions unnecessarily'); } else { doList.push('Allow adequate time for consideration and planning'); dontList.push('Rush them into quick decisions'); } break; } }); return { do: doList, dont: dontList }; } function generateCollaborationTips(profile) { const tips = []; // General collaboration approach based on dominant traits const internalProcessor = profile.dimensions.some((d) => d.dimension === 'expression' && d.dominant_pole === 'Internal'); const logicOriented = profile.dimensions.some((d) => d.dimension === 'reasoning' && d.dominant_pole === 'Logic'); const structured = profile.dimensions.some((d) => d.dimension === 'flexibility' && d.dominant_pole === 'Structured'); const processOriented = profile.dimensions.some((d) => d.dimension === 'work_style' && d.dominant_pole === 'Process-Driven'); const fastPaced = profile.dimensions.some((d) => d.dimension === 'tempo' && d.dominant_pole === 'Fast-Paced'); if (internalProcessor) { tips.push('Share meeting materials in advance to allow processing time'); tips.push('Consider async communication for complex topics'); } if (logicOriented) { tips.push('Come prepared with data and objective rationale'); tips.push('Focus discussions on facts and logical outcomes'); } if (structured) { tips.push('Establish clear meeting agendas and stick to them'); tips.push('Define roles, responsibilities, and deadlines upfront'); } if (processOriented) { tips.push('Respect established workflows and procedures'); tips.push('Document decisions and next steps thoroughly'); } if (fastPaced) { tips.push('Keep meetings focused and time-bounded'); tips.push('Make decisions quickly when possible'); } else { tips.push('Allow sufficient time for deliberation and consensus-building'); tips.push('Avoid rushing important decisions'); } // Add general tips if no specific patterns detected if (tips.length === 0) { tips.push('Adapt meeting style to their personality preferences', 'Be mindful of their communication and work style needs', 'Establish clear expectations and follow-through processes'); } return tips; } // Tool definition for MCP export const contextTool = { name: "get_communication_tips", description: "Get specific communication tips for interacting with a person", inputSchema: { type: "object", properties: { profileId: { type: "string", description: "Profile ID (optional if name is provided)" }, name: { type: "string", description: "Person's name (optional if profileId is provided)" }, scenario: { type: "string", description: "Specific scenario context (e.g., 'feedback meeting', 'project collaboration', 'conflict resolution')" } } } }; //# sourceMappingURL=context.js.map