Skip to main content
Glama

UNO-MCP

index.js18.2 kB
#!/usr/bin/env node import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { CallToolRequestSchema, ErrorCode, ListToolsRequestSchema, McpError } from '@modelcontextprotocol/sdk/types.js'; // UNO schema definitions const analyzeTextInputSchema = { type: 'object', properties: { text: { type: 'string', description: 'The story page text to analyze or enhance' } }, required: ['text'] }; const enhanceTextInputSchema = { type: 'object', properties: { text: { type: 'string', description: 'The story page text to enhance' }, expansionTarget: { type: 'number', description: 'Target expansion percentage (default: 200)', minimum: 100, maximum: 500 } }, required: ['text'] }; const customEnhanceTextInputSchema = { type: 'object', properties: { text: { type: 'string', description: 'The story page text to enhance' }, expansionTarget: { type: 'number', description: 'Target expansion percentage (default: 150)', minimum: 100, maximum: 500 }, enableGoldenShadow: { type: 'boolean', description: 'Develop underdeveloped elements' }, enableEnvironmental: { type: 'boolean', description: 'Enhance settings with immersive details' }, enableActionScene: { type: 'boolean', description: 'Enhance action sequences' }, enableProseSmoother: { type: 'boolean', description: 'Improve flow and rhythm' }, enableRepetitionElimination: { type: 'boolean', description: 'Reduce unintentional repetition' } }, required: ['text'] }; // Simple text analysis function function analyzeText(text) { const wordCount = text.split(/\s+/).filter(Boolean).length; const charCount = text.length; // Basic analysis calculations const averageSentenceLength = wordCount / (text.match(/[.!?]+/g)?.length || 1); // Simple repetition detection (counts words that appear more than once) const words = text.toLowerCase().match(/\b\w+\b/g) || []; const wordFreq = {}; words.forEach(word => { wordFreq[word] = (wordFreq[word] || 0) + 1; }); const repeatedWords = Object.entries(wordFreq) .filter(([_, count]) => count > 1) .sort((a, b) => b[1] - a[1]) .slice(0, 5) .map(([word, count]) => `"${word}" (${count} times)`); // Detect scene type let sceneType = 'exposition'; if (text.includes('!') || text.match(/run|jump|fight|chase|grab|throw|dash|leap|slam/gi)) { sceneType = 'action'; } else if ((text.match(/"|'|said|asked|replied|whispered|shouted/g) || []).length > wordCount/20) { sceneType = 'dialogue'; } // Detect mood let mood = 'neutral'; const positiveWords = text.match(/happy|joy|smile|laugh|wonderful|beautiful|success|love|hope/gi) || []; const negativeWords = text.match(/sad|fear|angry|hate|despair|pain|suffer|terrible|awful/gi) || []; if (positiveWords.length > negativeWords.length) { mood = 'positive'; } else if (negativeWords.length > positiveWords.length) { mood = 'negative'; } // Create an analysis report in markdown format return `UNO Analysis Report ## Text Statistics - **Original Word Count**: ${wordCount} - **Original Character Count**: ${charCount} - **Target Word Count (200%)**: ${wordCount * 2} - **Target Character Count (200%)**: ${charCount * 2} ## Contextual Assessment ### Narrative Position - **Position**: ${text.length < 200 ? 'beginning' : (text.length > 1000 ? 'climax/turning point' : 'middle')} - **Introduction Markers**: ${text.length < 300 ? 'Present' : 'Absent'} - **Climax Markers**: ${text.match(/suddenly|realized|moment|revelation|truth/gi) ? 'Present' : 'Absent'} - **Resolution Markers**: ${text.match(/finally|end|last|resolution|conclusion/gi) ? 'Present' : 'Absent'} ### Character Focus - **Point of View**: ${text.match(/\bI\b|\bme\b|\bmy\b/gi) ? 'first-person' : 'third-person'} - **Potential Characters**: ${Array.from(new Set(text.match(/[A-Z][a-z]+/g) || [])).slice(0, 7).join(' ')} - **Pronoun Distribution**: - First Person: ${(text.match(/\bI\b|\bme\b|\bmy\b|\bmine\b|\bmyself\b/gi) || []).length} - Second Person: ${(text.match(/\byou\b|\byour\b|\byours\b|\byourself\b/gi) || []).length} - Third Person: ${(text.match(/\bhe\b|\bshe\b|\bit\b|\bhim\b|\bher\b|\bhis\b|\bits\b|\bthey\b|\bthem\b|\btheir\b/gi) || []).length} ### Scene Type - **Dominant Type**: ${sceneType} - **Action Elements**: ${sceneType === 'action' ? 'Strong' : 'Weak'} - **Dialogue Elements**: ${sceneType === 'dialogue' ? 'Strong' : 'Weak'} - **Exposition Elements**: ${sceneType === 'exposition' ? 'Strong' : 'Weak'} ### Mood and Tone - **Dominant Mood**: ${mood} - **Positive Elements**: ${positiveWords.length > 0 ? 'Present' : 'Absent'} - **Negative Elements**: ${negativeWords.length > 0 ? 'Present' : 'Absent'} - **Suspense Elements**: ${text.match(/mystery|unknown|wonder|question|curious|suspense/gi) ? 'Present' : 'Absent'} ## Enhancement Recommendations ### Golden Shadow Enhancement - **Need Level**: ${wordCount < 100 ? 'high' : (wordCount < 300 ? 'medium' : 'low')} - **Underdeveloped Characters**: ${Array.from(new Set(text.match(/[A-Z][a-z]+/g) || [])).slice(0, 4).join(' ')} - **Underdeveloped Plot Elements**: ${text.length < 500 ? 'Present' : 'Absent'} ### Environmental Expansion - **Need Level**: ${(text.match(/saw|looked|appeared|seemed|felt|heard|smelled|tasted/gi) || []).length < wordCount/20 ? 'high' : 'low'} - **Sensory Richness (0-4)**: ${Math.min(4, Math.floor((text.match(/saw|looked|appeared|seemed|felt|heard|smelled|tasted/gi) || []).length / (wordCount/100)))} - **Setting Description**: ${text.match(/room|house|building|street|city|forest|mountain|ocean|sky/gi) ? 'Present' : 'Absent'} - **Areas to Enhance**: - Visual: ${text.match(/saw|looked|appeared|seemed|watched|observed/gi) ? 'Sufficient' : 'Needs improvement'} - Auditory: ${text.match(/heard|sound|noise|voice|whisper|shout|bang|crash/gi) ? 'Sufficient' : 'Needs improvement'} - Tactile: ${text.match(/felt|touch|rough|smooth|hot|cold|soft|hard/gi) ? 'Sufficient' : 'Needs improvement'} - Olfactory: ${text.match(/smell|scent|odor|fragrance|stench/gi) ? 'Sufficient' : 'Needs improvement'} ### Action Scene Enhancement - **Applicability**: ${sceneType === 'action' ? 'Applicable' : 'Not applicable'} ${sceneType === 'action' ? ` - **Current Intensity (0-4)**: ${Math.min(4, (text.match(/run|jump|fight|chase|grab|throw|dash|leap|slam/gi) || []).length)} - **Sensory Detail in Action**: ${(text.match(/saw|looked|appeared|seemed|felt|heard|smelled|tasted/gi) || []).length > (text.match(/run|jump|fight|chase|grab|throw|dash|leap|slam/gi) || []).length ? 'Sufficient' : 'Needs improvement'} - **Time Manipulation**: ${text.match(/suddenly|instant|moment|second|minute|time slowed|froze/gi) ? 'Present' : 'Absent'} - **Environmental Interaction**: ${text.match(/against|through|over|under|between|around/gi) ? 'Present' : 'Absent'}` : ''} ### Prose Smoothing - **Need Level**: ${averageSentenceLength > 20 || averageSentenceLength < 8 ? 'high' : 'low'} - **Average Sentence Length**: ${averageSentenceLength.toFixed(1)} words - **Sentence Length Variety**: ${(100 * (text.match(/\b\w{7,}\b/g)?.length || 0) / (text.match(/\b\w+\b/g)?.length || 1)).toFixed(1)}% - **Transition Words**: ${text.match(/however|therefore|meanwhile|subsequently|conversely|furthermore/gi) ? 'Present' : 'Absent'} - **Paragraph Length Variety**: ${text.split('\n\n').length > 1 ? 'Present' : 'Absent'} ### Repetition Elimination - **Severity**: ${repeatedWords.length > 10 ? 'high' : (repeatedWords.length > 5 ? 'medium' : 'low')} - **Repeated Word Count**: ${repeatedWords.length} - **Top Repeated Words**: - ${repeatedWords[0] || 'None'} ${repeatedWords[1] ? ` - ${repeatedWords[1]}` : ''} ## Repetition Patterns ### Repeated Words ${repeatedWords.slice(0, 4).map(word => `- ${word}`).join('\n') || '- No significant word repetition detected'} ### Repeated Phrases - No significant phrase repetition detected ### Repeated Sentence Structures - ${text.match(/[A-Z][^.!?]*\b(he|she|it|they)\b[^.!?]*/gi) ? 'pronoun-start pattern detected' : 'No significant structure repetition detected'} - ${text.match(/[A-Z][^.!?]*\b(was|were|had been)\b[^.!?]*/gi) ? 'passive-voice pattern detected' : ''} `; } // Text enhancement function (basic implementation) function enhanceText(text, expansionTarget = 200) { // A simple enhancement that roughly doubles the text length let sentences = text.split(/(?<=[.!?])\s+/); let enhancedText = []; for (const sentence of sentences) { // Add the original sentence enhancedText.push(sentence); // Add enhancement sentences based on the original const words = sentence.split(' '); if (words.length > 3) { // Extract subject (simplistic approach) const potentialSubject = words[0].match(/[A-Z][a-z]+/) ? words[0] : 'It'; // Detect verbs (simplistic approach) const actionVerbs = sentence.match(/\b(walk|run|look|see|feel|think|say|go|come|take|make|know|find)\w*\b/i); const verb = actionVerbs ? actionVerbs[0].toLowerCase() : 'was'; // Generate enhancements based on sentence type if (sentence.includes('?')) { // Question enhancement enhancedText.push(`The question hung in the air, demanding an answer.`); } else if (sentence.includes('!')) { // Exclamation enhancement enhancedText.push(`The words reverberated with unmistakable emotion.`); } else if (verb === 'saw' || verb === 'looked' || verb === 'observed' || verb === 'noticed') { // Visual enhancement enhancedText.push(`${potentialSubject} took in every detail, noting the subtle textures and colors that others might have missed.`); } else if (verb === 'felt' || verb === 'touched') { // Tactile enhancement enhancedText.push(`A subtle sensation lingered, impossible to ignore yet difficult to describe.`); } else if (verb === 'heard' || verb === 'listened') { // Auditory enhancement enhancedText.push(`The sound seemed to come from everywhere and nowhere at once, filling the space with its presence.`); } else if (words.length > 10) { // Complex sentence elaboration enhancedText.push(`This complexity revealed layers of meaning beneath the surface.`); } else { // Default enhancement enhancedText.push(`${potentialSubject} paused briefly, taking in the moment before continuing.`); } } } // Check if we've reached the target expansion and add more if needed let currentExpansion = (enhancedText.join(' ').length / text.length) * 100; if (currentExpansion < expansionTarget) { enhancedText.push(`\n\nThe subtle details of this moment would remain etched in memory long after other experiences had faded. There was something uniquely significant about it, something that transcended ordinary perception and touched upon deeper truths.`); } return enhancedText.join(' '); } // Custom text enhancement function function customEnhanceText(params) { const { text, expansionTarget = 150, enableGoldenShadow = true, enableEnvironmental = true, enableActionScene = true, enableProseSmoother = true, enableRepetitionElimination = true } = params; // A simplified implementation that applies different enhancements based on flags let enhancedText = text; let sentences = text.split(/(?<=[.!?])\s+/); let newSentences = []; // Apply Golden Shadow Enhancement (develop underdeveloped elements) if (enableGoldenShadow) { // Extract character names (simplified approach) const potentialCharacters = Array.from(new Set(text.match(/[A-Z][a-z]+/g) || [])); if (potentialCharacters.length > 0) { for (const character of potentialCharacters.slice(0, 2)) { newSentences.push(`${character}'s presence added significance to the moment, bringing an energy that was uniquely their own.`); } } } // Apply Environmental Expansion if (enableEnvironmental) { newSentences.push(`The surrounding environment wrapped around the scene, not just a backdrop but an active participant in the unfolding narrative. Subtle details—the quality of light, the temperature of the air, the distant sounds—all contributed to the tapestry of the moment.`); } // Apply Action Scene Enhancement if (enableActionScene && text.match(/run|jump|fight|chase|grab|throw|dash|leap|slam/gi)) { newSentences.push(`Time seemed to stretch and compress, heartbeats marking the passage of crucial moments. Each movement had consequence, each action rippling through the fabric of the scene with heightened intensity.`); } // Apply Prose Smoothing (connect sentences better) if (enableProseSmoother) { for (let i = 0; i < sentences.length - 1; i++) { newSentences.push(sentences[i]); // Add transitions between some sentences if (i % 3 === 0) { const transitions = [ "Meanwhile, ", "In that moment, ", "Through it all, ", "Nevertheless, ", "Consequently, " ]; const randomTransition = transitions[Math.floor(Math.random() * transitions.length)]; newSentences.push(randomTransition + "the narrative continued to unfold in unexpected ways."); } } // Add the last sentence if (sentences.length > 0) { newSentences.push(sentences[sentences.length - 1]); } } // Apply Repetition Elimination (simplified - just add the original text) if (!enableRepetitionElimination) { // If not eliminating repetition, just use the enhanced sentences enhancedText = [...sentences, ...newSentences].join(' '); } else { // With repetition elimination, just use the newly created sentences enhancedText = sentences.join(' ') + ' ' + newSentences.join(' '); } // Check if we've reached the target expansion const currentExpansion = (enhancedText.length / text.length) * 100; if (currentExpansion < expansionTarget) { enhancedText += `\n\nBeneath the surface of what was said and done lay currents of meaning, subtle but powerful, shaping experience in ways both immediate and lasting. This was the deeper dimension of the narrative, the space where true significance resided.`; } return enhancedText; } class UnoServer { constructor() { // Initialize the server this.server = new Server( { name: 'UNO-MCP', version: '1.0.0', }, { capabilities: { tools: {}, }, } ); // Set up tools this.setupToolHandlers(); // Error handling this.server.onerror = (error) => console.error('[MCP Error]', error); process.on('SIGINT', async () => { await this.server.close(); process.exit(0); }); } setupToolHandlers() { // List available tools this.server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: [ { name: 'analyze_text', description: 'Analyzes text and generates a comprehensive report', inputSchema: analyzeTextInputSchema, }, { name: 'enhance_text', description: 'Expands text using all five enhancement techniques', inputSchema: enhanceTextInputSchema, }, { name: 'custom_enhance_text', description: 'Allows selection of specific enhancement techniques', inputSchema: customEnhanceTextInputSchema, }, ], })); // Handle tool calls this.server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; switch (name) { case 'analyze_text': if (!args.text || typeof args.text !== 'string') { throw new McpError( ErrorCode.InvalidParams, 'Text parameter is required and must be a string' ); } return { content: [ { type: 'text', text: analyzeText(args.text), }, ], }; case 'enhance_text': if (!args.text || typeof args.text !== 'string') { throw new McpError( ErrorCode.InvalidParams, 'Text parameter is required and must be a string' ); } return { content: [ { type: 'text', text: enhanceText(args.text, args.expansionTarget || 200), }, ], }; case 'custom_enhance_text': if (!args.text || typeof args.text !== 'string') { throw new McpError( ErrorCode.InvalidParams, 'Text parameter is required and must be a string' ); } return { content: [ { type: 'text', text: customEnhanceText(args), }, ], }; default: throw new McpError( ErrorCode.MethodNotFound, `Unknown tool: ${name}` ); } }); } async run() { const transport = new StdioServerTransport(); await this.server.connect(transport); console.error('UNO MCP server running on stdio'); } } // Start the server const server = new UnoServer(); server.run().catch(console.error);

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/MushroomFleet/UNO-MCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server