// MCP Tools for Character Production Pipeline
// These tools will be exposed through the MCP server for LM Studio access
// Removed deprecated character-pipeline.js import - using corrected AffogatoClient from guidance notes
import { getProductionToolDefinitions, getProductionToolHandlers } from './production-tools.js';
import { getVideoProductionToolDefinitions, getVideoProductionToolHandlers } from './video-production-tools.js';
import { getStorylineToolDefinitions, getStorylineToolHandlers } from './storyline-tools.js';
import { getAgentManagementToolDefinitions, getAgentManagementToolHandlers } from './agent-management-tools.js';
import { DatabaseSchemaEnhancer } from '../integrations/database-schema-enhancer.js';
import path from 'path';
import fs from 'fs';
// Legacy pipeline removed - these tools now use the corrected Affogato integration
// const pipeline = new CharacterProductionPipeline(process.env.AFFOGATO_API_KEY);
export const characterTools = {
// Tool 1: Create character from text description
create_character_from_description: {
name: "create_character_from_description",
description: "Create a complete puppet character from a text description using Claude AI analysis and Affogato image generation. Generates 11 images (7 emotions + 4 directional views) with authentic puppet mechanics.",
inputSchema: {
type: "object",
properties: {
character_name: {
type: "string",
description: "Name of the character to create"
},
description: {
type: "string",
description: "Detailed description of the character (appearance, personality, background)"
},
cultural_background: {
type: "string",
description: "Optional cultural background for authentic representation (e.g., 'Brazilian', 'Irish', 'Japanese')"
}
},
required: ["character_name", "description"]
},
handler: async (args) => {
try {
// Construct proper characterData object for pipeline
const characterData = {
name: args.character_name,
description: args.description,
characterType: 'Main Character',
personalityTraits: [],
voiceDescription: '',
characterTraits: {
cultural_background: args.cultural_background || 'Not specified',
physical: {},
clothing: {},
personality: {},
puppet_specs: {}
}
};
const result = await pipeline.createCharacterFromDescription(characterData);
if (result.success) {
return {
success: true,
message: `Character "${args.character_name}" created successfully with ${result.character.images.length} images`,
character: {
name: result.character.name,
description: result.character.description,
affogato_id: result.character.affogatoId,
output_path: result.character.outputPath,
image_count: result.character.images.length,
emotions_generated: result.character.images.filter(img => img.type === 'emotion').length,
directions_generated: result.character.images.filter(img => img.type === 'direction').length
}
};
} else {
return {
success: false,
error: result.error
};
}
} catch (error) {
return {
success: false,
error: error.message
};
}
}
},
// Tool 2: Analyze existing character images
analyze_character_images: {
name: "analyze_character_images",
description: "Analyze existing character images with Claude AI to extract detailed traits and save to database. Perfect for adding existing characters to the production pipeline.",
inputSchema: {
type: "object",
properties: {
character_name: {
type: "string",
description: "Name of the character being analyzed"
},
image_paths: {
type: "array",
items: { type: "string" },
description: "Array of file paths to character images"
}
},
required: ["character_name", "image_paths"]
},
handler: async (args) => {
try {
const result = await pipeline.analyzeExistingCharacterImages(
args.character_name,
args.image_paths
);
if (result.success) {
return {
success: true,
message: `Character "${args.character_name}" analyzed successfully from ${result.imageCount} images`,
analysis: {
character_name: args.character_name,
images_analyzed: result.imageCount,
traits_extracted: Object.keys(result.analysis.traits).length,
database_saved: true
}
};
} else {
return {
success: false,
error: result.error
};
}
} catch (error) {
return {
success: false,
error: error.message
};
}
}
},
// Tool 3: Generate scene with character consistency
generate_character_scene: {
name: "generate_character_scene",
description: "Generate a scene featuring an existing character while maintaining perfect consistency. Character traits are automatically pulled from the database.",
inputSchema: {
type: "object",
properties: {
character_name: {
type: "string",
description: "Name of existing character in database"
},
scene_description: {
type: "string",
description: "Description of the scene to generate"
},
scene_title: {
type: "string",
description: "Title for the scene"
},
directional_overrides: {
type: "object",
description: "Optional overrides for character direction/pose",
properties: {
direction: {
type: "string",
enum: ["front", "left", "right", "back"],
description: "Character facing direction"
},
emotion: {
type: "string",
description: "Character emotion override"
}
}
}
},
required: ["character_name", "scene_description", "scene_title"]
},
handler: async (args) => {
try {
const sceneData = {
sceneDescription: args.scene_description,
sceneTitle: args.scene_title
};
const result = await pipeline.generateScene(
args.character_name,
sceneData,
args.directional_overrides || {}
);
if (result.success) {
return {
success: true,
message: `Scene "${args.scene_title}" generated successfully with character consistency`,
scene: {
title: args.scene_title,
character: args.character_name,
file_path: result.scene.filepath,
consistency_score: result.scene.consistency?.score || 'N/A'
}
};
} else {
return {
success: false,
error: result.error
};
}
} catch (error) {
return {
success: false,
error: error.message
};
}
}
},
// Tool 4: Generate multi-character scene
generate_multi_character_scene: {
name: "generate_multi_character_scene",
description: "Generate a scene with multiple characters maintaining individual consistency. All characters must exist in the database.",
inputSchema: {
type: "object",
properties: {
character_names: {
type: "array",
items: { type: "string" },
description: "Array of character names to include in scene"
},
scene_description: {
type: "string",
description: "Description of the multi-character scene"
},
scene_title: {
type: "string",
description: "Title for the scene"
},
character_interactions: {
type: "string",
description: "Optional description of how characters interact",
default: "standing together"
},
lighting_setup: {
type: "string",
description: "Optional lighting setup",
default: "studio_standard"
}
},
required: ["character_names", "scene_description", "scene_title"]
},
handler: async (args) => {
try {
const sceneData = {
sceneDescription: args.scene_description,
sceneTitle: args.scene_title,
characterInteractions: args.character_interactions,
lightingSetup: args.lighting_setup
};
const result = await pipeline.generateMultiCharacterScene(
args.character_names,
sceneData
);
if (result.success) {
return {
success: true,
message: `Multi-character scene "${args.scene_title}" generated with ${args.character_names.length} characters`,
scene: {
title: args.scene_title,
characters: result.scene.characters,
file_path: result.scene.filepath,
consistency_validation: result.scene.consistency?.promptValidation || 'N/A'
}
};
} else {
return {
success: false,
error: result.error
};
}
} catch (error) {
return {
success: false,
error: error.message
};
}
}
},
// Tool 5: List available characters
list_characters: {
name: "list_characters",
description: "List all characters available in the production database with their key details.",
inputSchema: {
type: "object",
properties: {
include_traits: {
type: "boolean",
description: "Include detailed character traits in response",
default: false
}
}
},
handler: async (args) => {
try {
const notion = await pipeline.getNotionClient();
if (!notion || !notion.databases || !notion.databases.query) {
throw new Error('Notion client not properly initialized');
}
const response = await notion.databases.query({
database_id: process.env.CHARACTERS_MASTER_DB || '5b96c172-96b2-4b53-a52c-60d4874779f4'
});
const characters = response.results.map(page => {
const basic = {
name: page.properties['Character Name']?.title[0]?.text?.content || 'Unnamed',
description: page.properties['Description']?.rich_text[0]?.text?.content || 'No description',
cultural_background: page.properties['Cultural Background']?.rich_text[0]?.text?.content || 'Not specified',
affogato_id: page.properties['Voice ID']?.rich_text[0]?.text?.content || 'None',
created: page.created_time,
page_id: page.id
};
if (args.include_traits) {
// Extract detailed traits if requested
if (!pipeline.dbEnhancer) {
pipeline.dbEnhancer = new DatabaseSchemaEnhancer(notion);
}
basic.traits = pipeline.dbEnhancer.extractCharacterTraits(page);
}
return basic;
});
return {
success: true,
message: `Found ${characters.length} characters in database`,
characters: characters,
total_count: characters.length
};
} catch (error) {
return {
success: false,
error: error.message
};
}
}
},
// Tool 6: Get character details
get_character_details: {
name: "get_character_details",
description: "Get detailed information about a specific character including all traits and production history.",
inputSchema: {
type: "object",
properties: {
character_name: {
type: "string",
description: "Name of the character to retrieve details for"
}
},
required: ["character_name"]
},
handler: async (args) => {
try {
const characterData = await pipeline.getCharacterTraitsFromNotion(args.character_name);
return {
success: true,
message: `Retrieved details for character "${args.character_name}"`,
character: {
name: args.character_name,
affogato_id: characterData.affogatoId,
traits: characterData.traits,
notion_page_id: characterData.page.id,
last_updated: characterData.page.last_edited_time
}
};
} catch (error) {
return {
success: false,
error: error.message
};
}
}
}
};
// Export tool definitions for MCP server registration
export const getCharacterToolDefinitions = () => {
const characterToolDefs = Object.values(characterTools).map(tool => ({
name: tool.name,
description: tool.description,
inputSchema: tool.inputSchema
}));
// Combine with production, storyline, and agent management tools
const productionToolDefs = getProductionToolDefinitions();
const videoToolDefs = getVideoProductionToolDefinitions();
const storylineToolDefs = getStorylineToolDefinitions();
const agentToolDefs = getAgentManagementToolDefinitions();
return [...characterToolDefs, ...productionToolDefs, ...videoToolDefs, ...storylineToolDefs, ...agentToolDefs];
};
// Export tool handlers for MCP server execution
export const getCharacterToolHandlers = () => {
const handlers = {};
// Add character tool handlers
Object.values(characterTools).forEach(tool => {
handlers[tool.name] = tool.handler;
});
// Add production tool handlers
const productionHandlers = getProductionToolHandlers();
Object.assign(handlers, productionHandlers);
// Add video tool handlers
const videoTools = getVideoProductionToolHandlers();
Object.values(videoTools).forEach((tool, index) => {
const toolName = Object.keys(videoTools)[index];
handlers[toolName] = tool.handler;
});
// Add storyline tool handlers
const storylineHandlers = getStorylineToolHandlers();
Object.assign(handlers, storylineHandlers);
// Add agent management tool handlers
const agentHandlers = getAgentManagementToolHandlers();
Object.assign(handlers, agentHandlers);
return handlers;
};