@prsna_ai/mcp-server
Version:
Model Context Protocol server for PRSNA personality profiles and communication insights
285 lines • 13.6 kB
JavaScript
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