#
tokens: 14774/50000 15/15 files
lines: on (toggle) GitHub
raw markdown copy reset
# Directory Structure

```
├── .gitignore
├── .npmignore
├── CHANGELOG.md
├── create-ad.js
├── DEMO-VISTA.md
├── EPIC-UNICODE-ART.md
├── examples
│   ├── all-templates.js
│   ├── basic-usage.js
│   └── mcp-client.js
├── LICENSE
├── mcp.json
├── package-lock.json
├── package.json
├── README.md
├── src
│   ├── integrations
│   │   └── symbl.js
│   ├── server
│   │   └── index.js
│   ├── steganography
│   │   └── manager.js
│   └── templates
│       └── engine.js
├── test-puzzle.js
├── test-simple.js
└── VISUAL-DEMO.md
```

# Files

--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------

```
 1 | node_modules/
 2 | *.log
 3 | *.tmp
 4 | .DS_Store
 5 | .env
 6 | dist/
 7 | build/
 8 | coverage/
 9 | .vscode/
10 | .idea/
11 | *.swp
12 | *.swo
13 | *~
14 | 
```

--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------

```
 1 | # Development files
 2 | test-puzzle.js
 3 | DEMO-VISTA.md
 4 | VISUAL-DEMO.md
 5 | *.test.js
 6 | *.spec.js
 7 | 
 8 | # Config files
 9 | .eslintrc*
10 | .prettierrc*
11 | jest.config.js
12 | 
13 | # Dev dependencies
14 | node_modules/
15 | coverage/
16 | .nyc_output/
17 | 
18 | # Editor files
19 | .vscode/
20 | .idea/
21 | *.swp
22 | *.swo
23 | *~
24 | 
25 | # OS files
26 | .DS_Store
27 | Thumbs.db
28 | 
29 | # Git
30 | .git/
31 | .gitignore
32 | 
33 | # Logs
34 | *.log
35 | npm-debug.log*
36 | 
37 | # Examples (they're in README)
38 | # Keep examples/ for users to reference!
39 | 
40 | # CI/CD
41 | .github/
42 | .travis.yml
43 | .circleci/
```

--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------

```markdown
 1 | # 🌌 Unicode Puzzles MCP
 2 | 
 3 | [![npm version](https://badge.fury.io/js/unicode-puzzles-mcp.svg)](https://www.npmjs.com/package/unicode-puzzles-mcp)
 4 | [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
 5 | [![MCP Compatible](https://img.shields.io/badge/MCP-Compatible-green.svg)](https://modelcontextprotocol.io)
 6 | 
 7 | Quantum steganography puzzles powered by MCP. Create and manage encoded messages using zero-width characters and advanced Unicode techniques.
 8 | 
 9 | ## 🎯 Features
10 | 
11 | - Advanced Unicode steganography (zero-width characters, combining marks)
12 | - Quantum-themed puzzle templates
13 | - symbl.cc integration for character discovery
14 | - Full MCP memory system integration
15 | - Multiple encoding patterns and difficulty levels
16 | - Real-time puzzle generation and verification
17 | 
18 | ## 🛠️ Installation
19 | 
20 | ```bash
21 | npm install unicode-puzzles-mcp
22 | ```
23 | 
24 | ## 💫 Quick Start
25 | 
26 | ```javascript
27 | import { UnicodePuzzlesMCP } from 'unicode-puzzles-mcp';
28 | 
29 | // Initialize MCP server
30 | const mcp = new UnicodePuzzlesMCP();
31 | 
32 | // Create a quantum puzzle
33 | const puzzle = await mcp.createPuzzle({
34 |   template: 'quantum',
35 |   message: 'System integrity compromised',
36 |   secret: 'LIBRAXIS://repair-protocol-7A'
37 | });
38 | 
39 | // Decode an encoded message
40 | const decoded = await mcp.decodePuzzle(encodedText);
41 | ```
42 | 
43 | ## 🌟 Puzzle Templates
44 | 
45 | - **Quantum** - Messages encoded using quantum superposition principles
46 | - **Orbital** - Circular pattern encoding using orbital mechanics
47 | - **Glitch** - Random noise patterns with hidden data
48 | - **Void** - Space-based encoding using astronomical symbols
49 | 
50 | ## 🔮 Examples
51 | 
52 | ### Creating a Quantum Puzzle
53 | ```javascript
54 | const quantumPuzzle = await mcp.createPuzzle({
55 |   template: 'quantum',
56 |   message: 'Reality distortion detected',
57 |   secret: 'Coordinates: α-359-ω',
58 |   difficulty: 'advanced'
59 | });
60 | 
61 | // Result: 【𝚀𝚄𝙰𝙽𝚃𝚄𝙼】∎∎∎Reality⠀distortion⠀detected∎∎∎
62 | // (with hidden ZWSP characters encoding the secret)
```

--------------------------------------------------------------------------------
/mcp.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "name": "unicode-puzzles-mcp",
 3 |   "version": "0.1.0",
 4 |   "description": "MCP server for quantum steganography puzzles using Unicode",
 5 |   "author": "MCP Division",
 6 |   "license": "MIT",
 7 |   "main": "src/server/index.js",
 8 |   "mcp": {
 9 |     "serverType": "stdio",
10 |     "runtime": "node",
11 |     "command": "node",
12 |     "args": ["src/server/index.js"]
13 |   },
14 |   "capabilities": {
15 |     "tools": [
16 |       "create_puzzle",
17 |       "decode_puzzle", 
18 |       "list_templates",
19 |       "encode_message",
20 |       "decode_message",
21 |       "search_characters",
22 |       "get_zero_width_chars"
23 |     ]
24 |   }
25 | }
```

--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------

```markdown
 1 | # Changelog
 2 | 
 3 | All notable changes to unicode-puzzles-mcp will be documented in this file.
 4 | 
 5 | ## [0.1.0] - 2025-07-21
 6 | 
 7 | ### 🎉 Initial Release
 8 | 
 9 | #### Features
10 | - 🌟 Four unique puzzle templates: Quantum, Orbital, Glitch, and Void
11 | - 🔐 Binary, trinary, and random encoding methods
12 | - 🎚️ Three difficulty levels (easy, medium, hard)
13 | - 🔍 Integration with symbl.cc for Unicode character discovery
14 | - 🛠️ Full MCP (Model Context Protocol) server implementation
15 | - 📚 Comprehensive examples and documentation
16 | 
17 | #### Templates
18 | - **Quantum**: Superposition-based encoding with quantum symbols
19 | - **Orbital**: Circular patterns with orbital mechanics
20 | - **Glitch**: Visual noise patterns for obfuscation
21 | - **Void**: Space-themed constellation encoding
22 | 
23 | #### Zero-Width Characters Support
24 | - ZWSP (U+200B) - Zero Width Space
25 | - ZWNJ (U+200C) - Zero Width Non-Joiner  
26 | - ZWJ (U+200D) - Zero Width Joiner
27 | - And 9 more invisible Unicode characters!
28 | 
29 | ---
30 | 
31 | Made with 🧠 by LibraxisAI MCP Division
```

--------------------------------------------------------------------------------
/test-simple.js:
--------------------------------------------------------------------------------

```javascript
 1 | #!/usr/bin/env node
 2 | /**
 3 |  * Simple test to verify the package works
 4 |  */
 5 | 
 6 | import { StegoPuzzleManager } from './src/steganography/manager.js';
 7 | import { TemplateEngine } from './src/templates/engine.js';
 8 | import { SymblConnector } from './src/integrations/symbl.js';
 9 | 
10 | console.log('🧪 Running package verification tests...\n');
11 | 
12 | try {
13 |   // Test 1: Can create instances
14 |   console.log('✓ StegoPuzzleManager instantiated');
15 |   const manager = new StegoPuzzleManager();
16 |   
17 |   console.log('✓ TemplateEngine instantiated');
18 |   const templates = new TemplateEngine();
19 |   
20 |   console.log('✓ SymblConnector instantiated');
21 |   const symbl = new SymblConnector();
22 |   
23 |   // Test 2: Basic encoding works
24 |   const encoded = await manager.encodeSecret('test', 'secret', {
25 |     pattern: 'binary',
26 |     difficulty: 'easy'
27 |   });
28 |   console.log('✓ Binary encoding works');
29 |   
30 |   // Test 3: Templates are available
31 |   const templateList = templates.listTemplates();
32 |   console.log(`✓ Found ${templateList.length} templates`);
33 |   
34 |   // Test 4: Zero-width characters defined
35 |   const zwCount = Object.keys(manager.zeroWidthChars).length;
36 |   console.log(`✓ ${zwCount} zero-width characters available`);
37 |   
38 |   console.log('\n✅ All tests passed! Package is ready for publishing.');
39 |   process.exit(0);
40 |   
41 | } catch (error) {
42 |   console.error('\n❌ Test failed:', error.message);
43 |   process.exit(1);
44 | }
```

--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "name": "unicode-puzzles-mcp",
 3 |   "version": "0.1.0",
 4 |   "description": "MCP server for quantum steganography puzzles using Unicode - hide secrets in plain sight using zero-width characters",
 5 |   "main": "src/server/index.js",
 6 |   "type": "module",
 7 |   "bin": {
 8 |     "unicode-puzzles-mcp": "./src/server/index.js"
 9 |   },
10 |   "scripts": {
11 |     "start": "node src/server/index.js",
12 |     "dev": "nodemon src/server/index.js",
13 |     "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js",
14 |     "test:local": "node test-puzzle.js",
15 |     "lint": "eslint src/",
16 |     "prepublishOnly": "node test-simple.js"
17 |   },
18 |   "dependencies": {
19 |     "@modelcontextprotocol/sdk": "^0.6.0",
20 |     "jsdom": "^23.0.0",
21 |     "node-fetch": "^3.3.2"
22 |   },
23 |   "devDependencies": {
24 |     "jest": "^27.0.6",
25 |     "nodemon": "^2.0.12",
26 |     "eslint": "^7.32.0",
27 |     "prettier": "^2.3.2"
28 |   },
29 |   "keywords": [
30 |     "mcp",
31 |     "model-context-protocol",
32 |     "unicode",
33 |     "steganography",
34 |     "puzzle",
35 |     "quantum",
36 |     "zero-width",
37 |     "hidden-messages",
38 |     "encoding",
39 |     "claude-desktop",
40 |     "libraxis"
41 |   ],
42 |   "author": "Maciej Gad <[email protected]>",
43 |   "license": "MIT",
44 |   "repository": {
45 |     "type": "git",
46 |     "url": "git+https://github.com/maciejgad/unicode-puzzles-mcp.git"
47 |   },
48 |   "bugs": {
49 |     "url": "https://github.com/maciejgad/unicode-puzzles-mcp/issues"
50 |   },
51 |   "homepage": "https://github.com/maciejgad/unicode-puzzles-mcp#readme",
52 |   "engines": {
53 |     "node": ">=18.0.0"
54 |   },
55 |   "files": [
56 |     "src/",
57 |     "LICENSE",
58 |     "README.md",
59 |     "mcp.json"
60 |   ]
61 | }
```

--------------------------------------------------------------------------------
/examples/basic-usage.js:
--------------------------------------------------------------------------------

```javascript
 1 | #!/usr/bin/env node
 2 | /**
 3 |  * Basic usage example for unicode-puzzles-mcp
 4 |  * This example shows how to use the steganography functions directly
 5 |  */
 6 | 
 7 | import { StegoPuzzleManager } from '../src/steganography/manager.js';
 8 | import { TemplateEngine } from '../src/templates/engine.js';
 9 | 
10 | async function main() {
11 |   const manager = new StegoPuzzleManager();
12 |   const templates = new TemplateEngine();
13 |   
14 |   console.log('🌌 Unicode Puzzles - Basic Usage Example\n');
15 |   
16 |   // Example 1: Simple message encoding
17 |   console.log('1. Simple Binary Encoding:');
18 |   const encoded = await manager.encodeSecret(
19 |     'Hello World', 
20 |     'secret123',
21 |     { pattern: 'binary', difficulty: 'easy' }
22 |   );
23 |   console.log('Visible text:', encoded);
24 |   console.log('Looks normal but contains hidden data!\n');
25 |   
26 |   // Example 2: Create a Quantum Puzzle
27 |   console.log('2. Quantum Puzzle:');
28 |   const quantumTemplate = templates.getTemplate('quantum', 'medium');
29 |   const puzzle = await manager.createPuzzle({
30 |     template: quantumTemplate,
31 |     message: 'Meeting at midnight',
32 |     secret: 'Location: 40.7128,-74.0060',
33 |     difficulty: 'medium'
34 |   });
35 |   console.log('Puzzle:', puzzle);
36 |   
37 |   // Example 3: Decode the puzzle
38 |   console.log('\n3. Decoding the Puzzle:');
39 |   const decoded = await manager.decodePuzzle(puzzle);
40 |   console.log('Visible message:', decoded.visibleText);
41 |   console.log('Hidden secret:', decoded.hiddenMessage);
42 |   
43 |   // Example 4: Show zero-width character usage
44 |   console.log('\n4. Zero-Width Character Analysis:');
45 |   const zwChars = encoded.match(/[\u200B-\u200F\u2060-\u206F]/g);
46 |   console.log('Total zero-width characters:', zwChars ? zwChars.length : 0);
47 |   console.log('These are completely invisible to users!');
48 | }
49 | 
50 | main().catch(console.error);
```

--------------------------------------------------------------------------------
/test-puzzle.js:
--------------------------------------------------------------------------------

```javascript
 1 | import { StegoPuzzleManager } from './src/steganography/manager.js';
 2 | import { TemplateEngine } from './src/templates/engine.js';
 3 | 
 4 | // Test the puzzle creation locally
 5 | async function testPuzzle() {
 6 |   const manager = new StegoPuzzleManager();
 7 |   const templates = new TemplateEngine();
 8 |   
 9 |   console.log('🧪 Testing Unicode Puzzles...\n');
10 |   
11 |   // Test 1: Create a quantum puzzle
12 |   console.log('1️⃣ Creating Quantum Puzzle...');
13 |   const quantumTemplate = templates.getTemplate('quantum', 'medium');
14 |   const quantumPuzzle = await manager.createPuzzle({
15 |     template: quantumTemplate,
16 |     message: 'Reality distortion detected',
17 |     secret: 'LIBRAXIS://repair-protocol-7A',
18 |     difficulty: 'medium'
19 |   });
20 |   console.log('Result:', quantumPuzzle);
21 |   console.log('');
22 |   
23 |   // Test 2: Decode the puzzle
24 |   console.log('2️⃣ Decoding Quantum Puzzle...');
25 |   const decoded = await manager.decodePuzzle(quantumPuzzle);
26 |   console.log('Decoded:', decoded);
27 |   console.log('');
28 |   
29 |   // Test 3: Simple binary encoding
30 |   console.log('3️⃣ Testing Binary Encoding...');
31 |   const binaryEncoded = await manager.encodeSecret(
32 |     'Hello World',
33 |     'Secret123',
34 |     { pattern: 'binary', difficulty: 'easy' }
35 |   );
36 |   console.log('Binary Encoded:', binaryEncoded);
37 |   console.log('Length:', binaryEncoded.length);
38 |   
39 |   // Count zero-width characters
40 |   const zwChars = binaryEncoded.match(/[\u200B-\u200F\u2060-\u206F]/g);
41 |   console.log('Zero-width characters:', zwChars ? zwChars.length : 0);
42 |   console.log('');
43 |   
44 |   // Test 4: List all templates
45 |   console.log('4️⃣ Available Templates:');
46 |   const templateList = templates.listTemplates();
47 |   templateList.forEach(t => {
48 |     console.log(`- ${t.name}: ${t.description}`);
49 |     console.log(`  Difficulties: ${t.difficulties.join(', ')}`);
50 |   });
51 | }
52 | 
53 | // Run tests
54 | testPuzzle().catch(console.error);
```

--------------------------------------------------------------------------------
/examples/all-templates.js:
--------------------------------------------------------------------------------

```javascript
 1 | #!/usr/bin/env node
 2 | /**
 3 |  * Showcase all available puzzle templates
 4 |  */
 5 | 
 6 | import { StegoPuzzleManager } from '../src/steganography/manager.js';
 7 | import { TemplateEngine } from '../src/templates/engine.js';
 8 | 
 9 | async function showcaseTemplates() {
10 |   const manager = new StegoPuzzleManager();
11 |   const templates = new TemplateEngine();
12 |   
13 |   console.log('🎨 Unicode Puzzles - Template Showcase\n');
14 |   console.log('Each template creates unique visual patterns while hiding your secrets!\n');
15 |   
16 |   const secretMessage = 'LIBRAXIS-2025';
17 |   const visibleMessage = 'The future is distributed';
18 |   
19 |   // Get all template names
20 |   const templateList = templates.listTemplates();
21 |   
22 |   for (const templateInfo of templateList) {
23 |     console.log(`\n${'='.repeat(60)}`);
24 |     console.log(`📦 Template: ${templateInfo.name.toUpperCase()}`);
25 |     console.log(`📝 ${templateInfo.description}`);
26 |     console.log(`🎚️  Difficulties: ${templateInfo.difficulties.join(', ')}`);
27 |     console.log(`${'='.repeat(60)}\n`);
28 |     
29 |     // Show each difficulty level
30 |     for (const difficulty of templateInfo.difficulties) {
31 |       const template = templates.getTemplate(templateInfo.name, difficulty);
32 |       const puzzle = await manager.createPuzzle({
33 |         template,
34 |         message: visibleMessage,
35 |         secret: secretMessage,
36 |         difficulty
37 |       });
38 |       
39 |       console.log(`[${difficulty.toUpperCase()}]:`);
40 |       console.log(puzzle);
41 |       
42 |       // Analyze the encoding
43 |       const hiddenChars = puzzle.match(/[\u200B-\u200F\u2060-\u206F]/g);
44 |       console.log(`Hidden characters: ${hiddenChars ? hiddenChars.length : 0}`);
45 |       console.log('');
46 |     }
47 |   }
48 |   
49 |   console.log('\n💡 TIP: Copy any puzzle above and it will maintain the hidden message!');
50 |   console.log('The zero-width characters are preserved in clipboard operations.');
51 | }
52 | 
53 | showcaseTemplates().catch(console.error);
```

--------------------------------------------------------------------------------
/examples/mcp-client.js:
--------------------------------------------------------------------------------

```javascript
 1 | #!/usr/bin/env node
 2 | /**
 3 |  * Example of using unicode-puzzles-mcp as an MCP client
 4 |  * This shows how Claude Desktop or other MCP clients would interact
 5 |  */
 6 | 
 7 | import { Client } from '@modelcontextprotocol/sdk/client/index.js';
 8 | import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
 9 | import { spawn } from 'child_process';
10 | 
11 | async function main() {
12 |   console.log('🔌 Connecting to Unicode Puzzles MCP Server...\n');
13 |   
14 |   // Spawn the MCP server
15 |   const serverProcess = spawn('node', ['../src/server/index.js'], {
16 |     stdio: ['pipe', 'pipe', 'pipe']
17 |   });
18 |   
19 |   // Create transport and client
20 |   const transport = new StdioClientTransport({
21 |     stdin: serverProcess.stdout,
22 |     stdout: serverProcess.stdin,
23 |     stderr: serverProcess.stderr
24 |   });
25 |   
26 |   const client = new Client({
27 |     name: 'unicode-puzzles-client',
28 |     version: '1.0.0'
29 |   }, {
30 |     capabilities: {}
31 |   });
32 |   
33 |   // Connect to server
34 |   await client.connect(transport);
35 |   console.log('✅ Connected to MCP server!\n');
36 |   
37 |   // List available tools
38 |   console.log('📋 Available Tools:');
39 |   const tools = await client.listTools();
40 |   tools.tools.forEach(tool => {
41 |     console.log(`- ${tool.name}: ${tool.description}`);
42 |   });
43 |   
44 |   // Example 1: Create a puzzle
45 |   console.log('\n🎯 Creating a Quantum Puzzle...');
46 |   const puzzleResult = await client.callTool('create_puzzle', {
47 |     template: 'quantum',
48 |     message: 'System breach detected',
49 |     secret: 'Access code: DELTA-7-ALPHA',
50 |     difficulty: 'hard'
51 |   });
52 |   
53 |   const puzzleData = JSON.parse(puzzleResult.content[0].text);
54 |   console.log('Created:', puzzleData.puzzle);
55 |   
56 |   // Example 2: List templates
57 |   console.log('\n📚 Available Templates:');
58 |   const templatesResult = await client.callTool('list_templates', {});
59 |   const templates = JSON.parse(templatesResult.content[0].text);
60 |   console.log(templates);
61 |   
62 |   // Example 3: Search for zero-width characters
63 |   console.log('\n🔍 Zero-Width Characters:');
64 |   const zwResult = await client.callTool('get_zero_width_chars', {});
65 |   const zwChars = JSON.parse(zwResult.content[0].text);
66 |   console.log('Found', zwChars.chars.length, 'zero-width characters');
67 |   
68 |   // Cleanup
69 |   await client.close();
70 |   serverProcess.kill();
71 |   console.log('\n👋 Disconnected from server');
72 | }
73 | 
74 | main().catch(console.error);
```

--------------------------------------------------------------------------------
/src/integrations/symbl.js:
--------------------------------------------------------------------------------

```javascript
  1 | import fetch from 'node-fetch';
  2 | import jsdom from 'jsdom';
  3 | const { JSDOM } = jsdom;
  4 | 
  5 | export class SymblConnector {
  6 |   constructor() {
  7 |     this.baseUrl = 'https://symbl.cc/en';
  8 |     this.cache = new Map();
  9 |     this.rateLimit = {
 10 |       requests: 0,
 11 |       lastReset: Date.now(),
 12 |       limit: 100  // requests per minute
 13 |     };
 14 | 
 15 |     // Initialize character categories
 16 |     this.categories = {
 17 |       zeroWidth: [
 18 |         '200B', '200C', '200D', '200E', '200F',
 19 |         '2060', '206A', '206B', '206C', '206D',
 20 |         '206E', '206F'
 21 |       ],
 22 |       quantum: [
 23 |         '0278', '0299', '1D487', '1D688', '1D689',
 24 |         '1D68A', '1D68B', '1D68C', '1D68D', '1D68E'
 25 |       ],
 26 |       special: [
 27 |         '2022', '2023', '25A0', '25A1', '25CF',
 28 |         '25CB', '25D0', '25D1', '25D2', '25D3'
 29 |       ]
 30 |     };
 31 |   }
 32 | 
 33 |   async searchCharacters(query, category = null) {
 34 |     await this.checkRateLimit();
 35 | 
 36 |     // Check cache first
 37 |     const cacheKey = `search:${query}:${category}`;
 38 |     if(this.cache.has(cacheKey)) {
 39 |       return this.cache.get(cacheKey);
 40 |     }
 41 | 
 42 |     try {
 43 |       // Fetch search results from symbl.cc
 44 |       const response = await fetch(`${this.baseUrl}/search/?q=${encodeURIComponent(query)}`);
 45 |       const html = await response.text();
 46 |       
 47 |       // Parse results using jsdom
 48 |       const dom = new JSDOM(html);
 49 |       const document = dom.window.document;
 50 |       
 51 |       // Extract character data
 52 |       const results = Array.from(document.querySelectorAll('.char-block')).map(block => {
 53 |         const char = block.querySelector('.char').textContent;
 54 |         const code = block.querySelector('.code').textContent;
 55 |         const name = block.querySelector('.name').textContent;
 56 |         
 57 |         return {
 58 |           char,
 59 |           code: code.replace('U+', ''),
 60 |           name,
 61 |           category: this.determineCategory(code)
 62 |         };
 63 |       });
 64 | 
 65 |       // Filter by category if specified
 66 |       const filtered = category ? 
 67 |         results.filter(r => r.category === category) : 
 68 |         results;
 69 | 
 70 |       // Cache results
 71 |       this.cache.set(cacheKey, filtered);
 72 |       
 73 |       // Update rate limit counter
 74 |       this.rateLimit.requests++;
 75 |       
 76 |       return filtered;
 77 | 
 78 |     } catch (error) {
 79 |       throw new Error(`Failed to search symbl.cc: ${error.message}`);
 80 |     }
 81 |   }
 82 | 
 83 |   async getZeroWidthCharacters() {
 84 |     return this.getCharactersByCategory('zeroWidth');
 85 |   }
 86 | 
 87 |   async getQuantumCharacters() {
 88 |     return this.getCharactersByCategory('quantum');
 89 |   }
 90 | 
 91 |   async getSpecialCharacters() {
 92 |     return this.getCharactersByCategory('special');
 93 |   }
 94 | 
 95 |   async getCharactersByCategory(category) {
 96 |     if (!this.categories[category]) {
 97 |       throw new Error(`Invalid category: ${category}`);
 98 |     }
 99 | 
100 |     const results = [];
101 |     for (const code of this.categories[category]) {
102 |       const char = await this.getCharacterByCode(code);
103 |       if (char) results.push(char);
104 |     }
105 | 
106 |     return results;
107 |   }
108 | 
109 |   async getCharacterByCode(code) {
110 |     await this.checkRateLimit();
111 | 
112 |     // Check cache
113 |     const cacheKey = `char:${code}`;
114 |     if(this.cache.has(cacheKey)) {
115 |       return this.cache.get(cacheKey);
116 |     }
117 | 
118 |     try {
119 |       const response = await fetch(`${this.baseUrl}/${code}/`);
120 |       const html = await response.text();
121 |       
122 |       const dom = new JSDOM(html);
123 |       const document = dom.window.document;
124 |       
125 |       const charBlock = document.querySelector('.char-block');
126 |       if (!charBlock) return null;
127 | 
128 |       const result = {
129 |         char: charBlock.querySelector('.char').textContent,
130 |         code,
131 |         name: charBlock.querySelector('.name').textContent,
132 |         category: this.determineCategory(code)
133 |       };
134 | 
135 |       // Cache result
136 |       this.cache.set(cacheKey, result);
137 |       
138 |       // Update rate limit
139 |       this.rateLimit.requests++;
140 |       
141 |       return result;
142 | 
143 |     } catch (error) {
144 |       throw new Error(`Failed to fetch character ${code}: ${error.message}`);
145 |     }
146 |   }
147 | 
148 |   determineCategory(code) {
149 |     code = code.replace('U+', '');
150 |     
151 |     if(this.categories.zeroWidth.includes(code)) return 'zeroWidth';
152 |     if(this.categories.quantum.includes(code)) return 'quantum';
153 |     if(this.categories.special.includes(code)) return 'special';
154 |     return 'other';
155 |   }
156 | 
157 |   async checkRateLimit() {
158 |     const now = Date.now();
159 |     const timeSinceReset = now - this.rateLimit.lastReset;
160 | 
161 |     // Reset counter if a minute has passed
162 |     if(timeSinceReset >= 60000) {
163 |       this.rateLimit.requests = 0;
164 |       this.rateLimit.lastReset = now;
165 |       return;
166 |     }
167 | 
168 |     // Check if we've hit the limit
169 |     if(this.rateLimit.requests >= this.rateLimit.limit) {
170 |       const waitTime = 60000 - timeSinceReset;
171 |       throw new Error(`Rate limit exceeded. Please wait ${Math.ceil(waitTime/1000)} seconds.`);
172 |     }
173 |   }
174 | 
175 |   // Memory integration methods
176 |   async saveToMemory(mcpMemory) {
177 |     const timestamp = new Date().toISOString();
178 |     
179 |     // Store cache statistics
180 |     await mcpMemory.create_entities([{
181 |       name: `symbl_cache_${timestamp}`,
182 |       entityType: 'Cache',
183 |       observations: [
184 |         `Total Cached Items: ${this.cache.size}`,
185 |         `Rate Limit Status: ${this.rateLimit.requests}/${this.rateLimit.limit}`,
186 |         `Last Reset: ${new Date(this.rateLimit.lastReset).toISOString()}`
187 |       ]
188 |     }]);
189 | 
190 |     // Store category statistics
191 |     for(const [category, codes] of Object.entries(this.categories)) {
192 |       await mcpMemory.create_entities([{
193 |         name: `symbl_category_${category}_${timestamp}`,
194 |         entityType: 'CharacterCategory',
195 |         observations: [
196 |           `Category: ${category}`,
197 |           `Total Characters: ${codes.length}`,
198 |           `Codes: ${codes.join(', ')}`
199 |         ]
200 |       }]);
201 |     }
202 |   }
203 | 
204 |   clearCache() {
205 |     this.cache.clear();
206 |     this.rateLimit.requests = 0;
207 |     this.rateLimit.lastReset = Date.now();
208 |   }
209 | }
```

--------------------------------------------------------------------------------
/src/steganography/manager.js:
--------------------------------------------------------------------------------

```javascript
  1 | export class StegoPuzzleManager {
  2 |   constructor() {
  3 |     this.zeroWidthChars = {
  4 |       ZWSP: '\u200B',  // Zero width space
  5 |       ZWNJ: '\u200C',  // Zero width non-joiner
  6 |       ZWJ: '\u200D',   // Zero width joiner
  7 |       LRM: '\u200E',   // Left-to-right mark
  8 |       RLM: '\u200F',   // Right-to-left mark
  9 |       WJ: '\u2060',    // Word joiner
 10 |       ISS: '\u206A',   // Inhibit symmetric swapping
 11 |       ASS: '\u206B',   // Activate symmetric swapping
 12 |       IAFS: '\u206C',  // Inhibit arabic form shaping
 13 |       AAFS: '\u206D',  // Activate arabic form shaping
 14 |       NADS: '\u206E',  // National digit shapes
 15 |       NODS: '\u206F'   // Nominal digit shapes
 16 |     };
 17 | 
 18 |     this.patterns = {
 19 |       quantum: {
 20 |         prefix: '【𝚀𝚄𝙰𝙽𝚃𝚄𝙼】',
 21 |         separator: '∎∎∎',
 22 |         encoding: 'binary'
 23 |       },
 24 |       orbital: {
 25 |         prefix: '◉',
 26 |         separator: '◯',
 27 |         encoding: 'trinary'
 28 |       },
 29 |       glitch: {
 30 |         prefix: '[ERR0R]',
 31 |         separator: '',
 32 |         encoding: 'random'
 33 |       }
 34 |     };
 35 |   }
 36 | 
 37 |   async createPuzzle({ template, message, secret, difficulty = 'medium' }) {
 38 |     // Get encoding pattern based on template and difficulty
 39 |     const pattern = this.patterns[template.name];
 40 |     
 41 |     // Encode secret message
 42 |     const encodedText = await this.encodeSecret(message, secret, {
 43 |       pattern: pattern.encoding,
 44 |       difficulty
 45 |     });
 46 |     
 47 |     // Apply template formatting
 48 |     return this.applyTemplate(encodedText, template);
 49 |   }
 50 | 
 51 |   async encodeSecret(message, secret, options) {
 52 |     const { pattern, difficulty } = options;
 53 |     
 54 |     // Convert secret to binary
 55 |     const binarySecret = this.textToBinary(secret);
 56 |     
 57 |     // Initialize encoded text
 58 |     let encoded = '';
 59 |     let charIndex = 0;
 60 |     
 61 |     // Apply encoding based on pattern
 62 |     switch(pattern) {
 63 |       case 'binary':
 64 |         encoded = this.binaryEncode(message, binarySecret, difficulty);
 65 |         break;
 66 |       case 'trinary':
 67 |         encoded = this.trinaryEncode(message, binarySecret, difficulty);
 68 |         break;
 69 |       case 'random':
 70 |         encoded = this.randomEncode(message, binarySecret, difficulty);
 71 |         break;
 72 |       default:
 73 |         throw new Error('Invalid encoding pattern');
 74 |     }
 75 |     
 76 |     return encoded;
 77 |   }
 78 | 
 79 |   binaryEncode(message, binarySecret, difficulty) {
 80 |     let encoded = '';
 81 |     let secretIndex = 0;
 82 |     
 83 |     for(let i = 0; i < message.length; i++) {
 84 |       encoded += message[i];
 85 |       
 86 |       if(secretIndex < binarySecret.length) {
 87 |         // Insert zero-width character based on binary value
 88 |         if(binarySecret[secretIndex] === '1') {
 89 |           encoded += this.zeroWidthChars.ZWSP;
 90 |         } else {
 91 |           encoded += this.zeroWidthChars.ZWNJ;
 92 |         }
 93 |         secretIndex++;
 94 |       }
 95 |       
 96 |       // Add noise for higher difficulties
 97 |       if(difficulty === 'hard') {
 98 |         if(Math.random() > 0.7) {
 99 |           encoded += this.getRandomZeroWidth();
100 |         }
101 |       }
102 |     }
103 |     
104 |     return encoded;
105 |   }
106 | 
107 |   trinaryEncode(message, binarySecret, difficulty) {
108 |     let encoded = '';
109 |     let secretIndex = 0;
110 |     
111 |     // Convert binary to trinary for more complex encoding
112 |     const trinarySecret = this.binaryToTrinary(binarySecret);
113 |     
114 |     for(let i = 0; i < message.length; i++) {
115 |       encoded += message[i];
116 |       
117 |       if(secretIndex < trinarySecret.length) {
118 |         // Use three zero-width characters for trinary encoding
119 |         switch(trinarySecret[secretIndex]) {
120 |           case '0':
121 |             encoded += this.zeroWidthChars.ZWSP;
122 |             break;
123 |           case '1':
124 |             encoded += this.zeroWidthChars.ZWNJ;
125 |             break;
126 |           case '2':
127 |             encoded += this.zeroWidthChars.ZWJ;
128 |             break;
129 |         }
130 |         secretIndex++;
131 |       }
132 |     }
133 |     
134 |     return encoded;
135 |   }
136 | 
137 |   randomEncode(message, binarySecret, difficulty) {
138 |     let encoded = '';
139 |     let secretIndex = 0;
140 |     
141 |     const chars = Object.values(this.zeroWidthChars);
142 |     
143 |     for(let i = 0; i < message.length; i++) {
144 |       encoded += message[i];
145 |       
146 |       // Random noise insertion
147 |       if(Math.random() > 0.5) {
148 |         encoded += chars[Math.floor(Math.random() * chars.length)];
149 |       }
150 |       
151 |       // Secret encoding
152 |       if(secretIndex < binarySecret.length) {
153 |         if(binarySecret[secretIndex] === '1') {
154 |           encoded += this.zeroWidthChars.WJ;
155 |         }
156 |         secretIndex++;
157 |       }
158 |     }
159 |     
160 |     return encoded;
161 |   }
162 | 
163 |   textToBinary(text) {
164 |     return text.split('').map(char => 
165 |       char.charCodeAt(0).toString(2).padStart(8, '0')
166 |     ).join('');
167 |   }
168 | 
169 |   binaryToTrinary(binary) {
170 |     // Convert binary to decimal
171 |     const decimal = parseInt(binary, 2);
172 |     // Convert decimal to trinary
173 |     return decimal.toString(3);
174 |   }
175 | 
176 |   getRandomZeroWidth() {
177 |     const chars = Object.values(this.zeroWidthChars);
178 |     return chars[Math.floor(Math.random() * chars.length)];
179 |   }
180 | 
181 |   applyTemplate(encodedText, template) {
182 |     return `${template.prefix}${template.separator}${encodedText}${template.separator}`;
183 |   }
184 | 
185 |   // Decoding methods
186 |   async decodePuzzle(encodedText) {
187 |     // Detect template
188 |     const template = this.detectTemplate(encodedText);
189 |     
190 |     // Remove template formatting
191 |     const stripped = this.stripTemplate(encodedText, template);
192 |     
193 |     // Extract and decode hidden message
194 |     return this.decodeSecret(stripped, template.encoding);
195 |   }
196 | 
197 |   detectTemplate(encodedText) {
198 |     for(const [name, pattern] of Object.entries(this.patterns)) {
199 |       if(encodedText.startsWith(pattern.prefix)) {
200 |         return { name, ...pattern };
201 |       }
202 |     }
203 |     throw new Error('Unknown puzzle template');
204 |   }
205 | 
206 |   stripTemplate(encodedText, template) {
207 |     return encodedText
208 |       .replace(template.prefix, '')
209 |       .split(template.separator)[1];
210 |   }
211 | 
212 |   decodeSecret(text, encoding) {
213 |     let binary = '';
214 |     let visibleText = '';
215 |     
216 |     for(let i = 0; i < text.length; i++) {
217 |       const char = text[i];
218 |       
219 |       // Check if it's a zero-width character
220 |       if(Object.values(this.zeroWidthChars).includes(char)) {
221 |         switch(encoding) {
222 |           case 'binary':
223 |             binary += char === this.zeroWidthChars.ZWSP ? '1' : '0';
224 |             break;
225 |           case 'trinary':
226 |             if(char === this.zeroWidthChars.ZWSP) binary += '0';
227 |             else if(char === this.zeroWidthChars.ZWNJ) binary += '1';
228 |             else if(char === this.zeroWidthChars.ZWJ) binary += '2';
229 |             break;
230 |           case 'random':
231 |             if(char === this.zeroWidthChars.WJ) binary += '1';
232 |             break;
233 |         }
234 |       } else {
235 |         visibleText += char;
236 |       }
237 |     }
238 |     
239 |     return {
240 |       visibleText,
241 |       hiddenMessage: this.binaryToText(binary)
242 |     };
243 |   }
244 | 
245 |   binaryToText(binary) {
246 |     // Split binary into 8-bit chunks
247 |     const bytes = binary.match(/.{1,8}/g) || [];
248 |     
249 |     // Convert each byte to character
250 |     return bytes.map(byte => 
251 |       String.fromCharCode(parseInt(byte, 2))
252 |     ).join('');
253 |   }
254 | }
```

--------------------------------------------------------------------------------
/src/templates/engine.js:
--------------------------------------------------------------------------------

```javascript
  1 | export class TemplateEngine {
  2 |   constructor() {
  3 |     this.templates = {
  4 |       quantum: {
  5 |         name: 'quantum',
  6 |         prefix: '【𝚀𝚄𝙰𝙽𝚃𝚄𝙼】',
  7 |         patterns: {
  8 |           easy: {
  9 |             opening: '∎',
 10 |             closing: '∎',
 11 |             separator: '⠀', // Unicode space
 12 |             noiseChance: 0.1
 13 |           },
 14 |           medium: {
 15 |             opening: '∎∎',
 16 |             closing: '∎∎',
 17 |             separator: '⠀',
 18 |             noiseChance: 0.3
 19 |           },
 20 |           hard: {
 21 |             opening: '∎∎∎',
 22 |             closing: '∎∎∎',
 23 |             separator: '⠀',
 24 |             noiseChance: 0.5
 25 |           }
 26 |         },
 27 |         quantumChars: ['α', 'β', 'γ', 'δ', 'ψ', 'Ψ', 'Φ', 'ℏ', '∞'],
 28 |         description: 'Quantum superposition encoding with variable noise'
 29 |       },
 30 |       
 31 |       orbital: {
 32 |         name: 'orbital',
 33 |         prefix: '◉',
 34 |         patterns: {
 35 |           easy: {
 36 |             opening: '◯',
 37 |             closing: '◯',
 38 |             separator: '·',
 39 |             rotationSteps: 4
 40 |           },
 41 |           medium: {
 42 |             opening: '◐',
 43 |             closing: '◑',
 44 |             separator: '∘',
 45 |             rotationSteps: 8
 46 |           },
 47 |           hard: {
 48 |             opening: '◒',
 49 |             closing: '◓',
 50 |             separator: '⋅',
 51 |             rotationSteps: 12
 52 |           }
 53 |         },
 54 |         orbitalChars: ['⌾', '☉', '⊕', '⊗', '⊙', '◎', '⚪', '⚫'],
 55 |         description: 'Circular pattern encoding with orbital mechanics'
 56 |       },
 57 |       
 58 |       glitch: {
 59 |         name: 'glitch',
 60 |         prefix: '[ERR0R]',
 61 |         patterns: {
 62 |           easy: {
 63 |             opening: '█',
 64 |             closing: '█',
 65 |             separator: ' ',
 66 |             glitchIntensity: 0.2
 67 |           },
 68 |           medium: {
 69 |             opening: '▓▒',
 70 |             closing: '▒▓',
 71 |             separator: '',
 72 |             glitchIntensity: 0.4
 73 |           },
 74 |           hard: {
 75 |             opening: '▓▒░',
 76 |             closing: '░▒▓',
 77 |             separator: '',
 78 |             glitchIntensity: 0.6
 79 |           }
 80 |         },
 81 |         glitchChars: ['░', '▒', '▓', '█', '☐', '☑', '☒', '✓', '✗'],
 82 |         description: 'Glitch-based encoding with visual noise'
 83 |       },
 84 |       
 85 |       void: {
 86 |         name: 'void',
 87 |         prefix: '✧・゚:*',
 88 |         patterns: {
 89 |           easy: {
 90 |             opening: '⋆',
 91 |             closing: '⋆',
 92 |             separator: ' ',
 93 |             constellationSize: 3
 94 |           },
 95 |           medium: {
 96 |             opening: '⋆⋆',
 97 |             closing: '⋆⋆',
 98 |             separator: '・',
 99 |             constellationSize: 5
100 |           },
101 |           hard: {
102 |             opening: '⋆⋆⋆',
103 |             closing: '⋆⋆⋆',
104 |             separator: '⋆',
105 |             constellationSize: 7
106 |           }
107 |         },
108 |         spaceChars: ['✧', '✦', '★', '☆', '✯', '✩', '✫', '✬', '✭'],
109 |         description: 'Space-themed encoding with constellation patterns'
110 |       }
111 |     };
112 |   }
113 | 
114 |   getTemplate(name, difficulty = 'medium') {
115 |     const template = this.templates[name];
116 |     if (!template) {
117 |       throw new Error(`Template '${name}' not found`);
118 |     }
119 | 
120 |     const pattern = template.patterns[difficulty];
121 |     if (!pattern) {
122 |       throw new Error(`Difficulty '${difficulty}' not found for template '${name}'`);
123 |     }
124 | 
125 |     return {
126 |       ...template,
127 |       pattern,
128 |       difficulty
129 |     };
130 |   }
131 | 
132 |   generatePattern(template, length, options = {}) {
133 |     const { name, pattern } = template;
134 |     let result = '';
135 | 
136 |     switch (name) {
137 |       case 'quantum':
138 |         result = this.generateQuantumPattern(pattern, length, options);
139 |         break;
140 |       case 'orbital':
141 |         result = this.generateOrbitalPattern(pattern, length, options);
142 |         break;
143 |       case 'glitch':
144 |         result = this.generateGlitchPattern(pattern, length, options);
145 |         break;
146 |       case 'void':
147 |         result = this.generateVoidPattern(pattern, length, options);
148 |         break;
149 |       default:
150 |         throw new Error(`Unknown template type: ${name}`);
151 |     }
152 | 
153 |     return result;
154 |   }
155 | 
156 |   generateQuantumPattern(pattern, length, { seed = Math.random() } = {}) {
157 |     let result = pattern.opening;
158 |     const template = this.templates.quantum;
159 | 
160 |     for (let i = 0; i < length; i++) {
161 |       // Add content character
162 |       result += pattern.separator;
163 | 
164 |       // Add quantum noise based on difficulty
165 |       if (Math.random() < pattern.noiseChance) {
166 |         const quantumChar = template.quantumChars[
167 |           Math.floor(Math.random() * template.quantumChars.length)
168 |         ];
169 |         result += quantumChar;
170 |       }
171 |     }
172 | 
173 |     return result + pattern.closing;
174 |   }
175 | 
176 |   generateOrbitalPattern(pattern, length, { rotation = 0 } = {}) {
177 |     let result = pattern.opening;
178 |     const template = this.templates.orbital;
179 |     const stepSize = (2 * Math.PI) / pattern.rotationSteps;
180 | 
181 |     for (let i = 0; i < length; i++) {
182 |       // Calculate orbital position
183 |       const angle = (rotation + i) * stepSize;
184 |       const orbitalIndex = Math.floor((angle / (2 * Math.PI)) * template.orbitalChars.length);
185 |       const orbitalChar = template.orbitalChars[orbitalIndex % template.orbitalChars.length];
186 | 
187 |       result += pattern.separator + orbitalChar;
188 |     }
189 | 
190 |     return result + pattern.closing;
191 |   }
192 | 
193 |   generateGlitchPattern(pattern, length, { intensity = 1.0 } = {}) {
194 |     let result = pattern.opening;
195 |     const template = this.templates.glitch;
196 |     const effectiveIntensity = pattern.glitchIntensity * intensity;
197 | 
198 |     for (let i = 0; i < length; i++) {
199 |       result += pattern.separator;
200 | 
201 |       // Add glitch artifacts based on intensity
202 |       if (Math.random() < effectiveIntensity) {
203 |         const glitchLength = Math.floor(Math.random() * 3) + 1;
204 |         for (let j = 0; j < glitchLength; j++) {
205 |           const glitchChar = template.glitchChars[
206 |             Math.floor(Math.random() * template.glitchChars.length)
207 |           ];
208 |           result += glitchChar;
209 |         }
210 |       }
211 |     }
212 | 
213 |     return result + pattern.closing;
214 |   }
215 | 
216 |   generateVoidPattern(pattern, length, { constellation = [] } = {}) {
217 |     let result = pattern.opening;
218 |     const template = this.templates.void;
219 | 
220 |     // Create constellation pattern
221 |     const constellationPoints = constellation.length > 0 ? 
222 |       constellation : 
223 |       this.generateConstellation(pattern.constellationSize);
224 | 
225 |     for (let i = 0; i < length; i++) {
226 |       result += pattern.separator;
227 | 
228 |       // Add space characters at constellation points
229 |       if (constellationPoints.includes(i)) {
230 |         const spaceChar = template.spaceChars[
231 |           Math.floor(Math.random() * template.spaceChars.length)
232 |         ];
233 |         result += spaceChar;
234 |       }
235 |     }
236 | 
237 |     return result + pattern.closing;
238 |   }
239 | 
240 |   generateConstellation(size) {
241 |     const points = new Set();
242 |     while (points.size < size) {
243 |       points.add(Math.floor(Math.random() * size * 2));
244 |     }
245 |     return Array.from(points).sort((a, b) => a - b);
246 |   }
247 | 
248 |   // MCP Memory Integration
249 |   async saveToMemory(mcpMemory) {
250 |     const timestamp = new Date().toISOString();
251 | 
252 |     // Store template metadata
253 |     for (const [name, template] of Object.entries(this.templates)) {
254 |       await mcpMemory.create_entities([{
255 |         name: `template_${name}_${timestamp}`,
256 |         entityType: 'PuzzleTemplate',
257 |         observations: [
258 |           `Name: ${name}`,
259 |           `Description: ${template.description}`,
260 |           `Prefix: ${template.prefix}`,
261 |           `Available Difficulties: ${Object.keys(template.patterns).join(', ')}`
262 |         ]
263 |       }]);
264 |     }
265 | 
266 |     // Log template usage statistics if needed
267 |   }
268 | 
269 |   listTemplates() {
270 |     return Object.entries(this.templates).map(([name, template]) => ({
271 |       name,
272 |       description: template.description,
273 |       difficulties: Object.keys(template.patterns)
274 |     }));
275 |   }
276 | }
```

--------------------------------------------------------------------------------
/src/server/index.js:
--------------------------------------------------------------------------------

```javascript
  1 | #!/usr/bin/env node
  2 | 
  3 | import { Server } from '@modelcontextprotocol/sdk/server/index.js';
  4 | import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
  5 | import {
  6 |   CallToolRequestSchema,
  7 |   ListResourcesRequestSchema,
  8 |   ListToolsRequestSchema,
  9 |   ReadResourceRequestSchema,
 10 |   ErrorCode,
 11 |   McpError
 12 | } from '@modelcontextprotocol/sdk/types.js';
 13 | import { StegoPuzzleManager } from '../steganography/manager.js';
 14 | import { SymblConnector } from '../integrations/symbl.js';
 15 | import { TemplateEngine } from '../templates/engine.js';
 16 | 
 17 | class UnicodePuzzlesMCP {
 18 |   constructor() {
 19 |     this.server = new Server(
 20 |       {
 21 |         name: 'unicode-puzzles-mcp',
 22 |         version: '0.1.0'
 23 |       },
 24 |       {
 25 |         capabilities: {
 26 |           tools: {},
 27 |           resources: {}
 28 |         }
 29 |       }
 30 |     );
 31 |     
 32 |     this.puzzleManager = new StegoPuzzleManager();
 33 |     this.symbl = new SymblConnector();
 34 |     this.templates = new TemplateEngine();
 35 |     
 36 |     this.setupTools();
 37 |   }
 38 | 
 39 |   async setupTools() {
 40 |     // Register tools handler
 41 |     this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
 42 |       switch (request.params.name) {
 43 |         case 'create_puzzle':
 44 |           return await this.createPuzzle(request.params.arguments);
 45 |         case 'decode_puzzle':
 46 |           return await this.decodePuzzle(request.params.arguments);
 47 |         case 'list_templates':
 48 |           return await this.getTemplates();
 49 |         case 'encode_message':
 50 |           return await this.encodeMessage(request.params.arguments);
 51 |         case 'decode_message':
 52 |           return await this.decodeMessage(request.params.arguments);
 53 |         case 'search_characters':
 54 |           return await this.searchCharacters(request.params.arguments);
 55 |         case 'get_zero_width_chars':
 56 |           return await this.getZeroWidthChars();
 57 |         default:
 58 |           throw new McpError(
 59 |             ErrorCode.MethodNotFound,
 60 |             `Unknown tool: ${request.params.name}`
 61 |           );
 62 |       }
 63 |     });
 64 | 
 65 |     // Register list tools handler
 66 |     this.server.setRequestHandler(ListToolsRequestSchema, async () => {
 67 |       return {
 68 |         tools: [
 69 |           {
 70 |             name: 'create_puzzle',
 71 |             description: 'Create a Unicode steganography puzzle',
 72 |             inputSchema: {
 73 |               type: 'object',
 74 |               properties: {
 75 |                 template: { type: 'string', enum: ['quantum', 'orbital', 'glitch', 'void'] },
 76 |                 message: { type: 'string' },
 77 |                 secret: { type: 'string' },
 78 |                 difficulty: { type: 'string', enum: ['easy', 'medium', 'hard'], default: 'medium' }
 79 |               },
 80 |               required: ['template', 'message', 'secret']
 81 |             }
 82 |           },
 83 |           {
 84 |             name: 'decode_puzzle',
 85 |             description: 'Decode a Unicode steganography puzzle',
 86 |             inputSchema: {
 87 |               type: 'object',
 88 |               properties: {
 89 |                 encodedText: { type: 'string' }
 90 |               },
 91 |               required: ['encodedText']
 92 |             }
 93 |           },
 94 |           {
 95 |             name: 'list_templates',
 96 |             description: 'List available puzzle templates'
 97 |           },
 98 |           {
 99 |             name: 'encode_message',
100 |             description: 'Encode a message using steganography',
101 |             inputSchema: {
102 |               type: 'object',
103 |               properties: {
104 |                 message: { type: 'string' },
105 |                 secret: { type: 'string' },
106 |                 method: { type: 'string', enum: ['binary', 'trinary', 'random'], default: 'binary' }
107 |               },
108 |               required: ['message', 'secret']
109 |             }
110 |           },
111 |           {
112 |             name: 'decode_message',
113 |             description: 'Decode a steganographic message',
114 |             inputSchema: {
115 |               type: 'object',
116 |               properties: {
117 |                 encodedText: { type: 'string' },
118 |                 method: { type: 'string', enum: ['binary', 'trinary', 'random'], default: 'binary' }
119 |               },
120 |               required: ['encodedText']
121 |             }
122 |           },
123 |           {
124 |             name: 'search_characters',
125 |             description: 'Search for Unicode characters',
126 |             inputSchema: {
127 |               type: 'object',
128 |               properties: {
129 |                 query: { type: 'string' },
130 |                 category: { type: 'string', enum: ['zeroWidth', 'quantum', 'special'] }
131 |               },
132 |               required: ['query']
133 |             }
134 |           },
135 |           {
136 |             name: 'get_zero_width_chars',
137 |             description: 'Get list of zero-width Unicode characters'
138 |           }
139 |         ]
140 |       };
141 |     });
142 |   }
143 | 
144 |   // Tool implementations
145 |   async createPuzzle(args) {
146 |     try {
147 |       const { template, message, secret, difficulty = 'medium' } = args;
148 |       
149 |       // Get template configuration
150 |       const templateConfig = await this.templates.getTemplate(template, difficulty);
151 |       
152 |       // Create puzzle using selected template
153 |       const puzzle = await this.puzzleManager.createPuzzle({
154 |         template: templateConfig,
155 |         message,
156 |         secret,
157 |         difficulty
158 |       });
159 | 
160 |       return {
161 |         content: [
162 |           {
163 |             type: 'text',
164 |             text: JSON.stringify({
165 |               status: 'success',
166 |               puzzle,
167 |               metadata: {
168 |                 template,
169 |                 difficulty,
170 |                 encodingType: templateConfig.encoding
171 |               }
172 |             }, null, 2)
173 |           }
174 |         ]
175 |       };
176 |     } catch (error) {
177 |       throw new McpError(
178 |         ErrorCode.InternalError,
179 |         `Failed to create puzzle: ${error.message}`
180 |       );
181 |     }
182 |   }
183 | 
184 |   async decodePuzzle(args) {
185 |     try {
186 |       const { encodedText } = args;
187 |       const decoded = await this.puzzleManager.decodePuzzle(encodedText);
188 |       return {
189 |         content: [
190 |           {
191 |             type: 'text',
192 |             text: JSON.stringify({ decoded }, null, 2)
193 |           }
194 |         ]
195 |       };
196 |     } catch (error) {
197 |       throw new McpError(
198 |         ErrorCode.InternalError,
199 |         `Failed to decode puzzle: ${error.message}`
200 |       );
201 |     }
202 |   }
203 | 
204 |   async getTemplates() {
205 |     try {
206 |       const templates = this.templates.listTemplates();
207 |       return {
208 |         content: [
209 |           {
210 |             type: 'text',
211 |             text: JSON.stringify({ templates }, null, 2)
212 |           }
213 |         ]
214 |       };
215 |     } catch (error) {
216 |       throw new McpError(
217 |         ErrorCode.InternalError,
218 |         `Failed to list templates: ${error.message}`
219 |       );
220 |     }
221 |   }
222 | 
223 |   async encodeMessage(args) {
224 |     try {
225 |       const { message, secret, method = 'binary' } = args;
226 |       const encoded = await this.puzzleManager.encodeSecret(message, secret, {
227 |         pattern: method,
228 |         difficulty: 'medium'
229 |       });
230 |       return {
231 |         content: [
232 |           {
233 |             type: 'text',
234 |             text: JSON.stringify({ encoded }, null, 2)
235 |           }
236 |         ]
237 |       };
238 |     } catch (error) {
239 |       throw new McpError(
240 |         ErrorCode.InternalError,
241 |         `Failed to encode message: ${error.message}`
242 |       );
243 |     }
244 |   }
245 | 
246 |   async decodeMessage(args) {
247 |     try {
248 |       const { encodedText, method = 'binary' } = args;
249 |       const decoded = this.puzzleManager.decodeSecret(encodedText, method);
250 |       return {
251 |         content: [
252 |           {
253 |             type: 'text',
254 |             text: JSON.stringify({ decoded }, null, 2)
255 |           }
256 |         ]
257 |       };
258 |     } catch (error) {
259 |       throw new McpError(
260 |         ErrorCode.InternalError,
261 |         `Failed to decode message: ${error.message}`
262 |       );
263 |     }
264 |   }
265 | 
266 |   async searchCharacters(args) {
267 |     try {
268 |       const { query, category } = args;
269 |       const results = await this.symbl.searchCharacters(query, category);
270 |       return {
271 |         content: [
272 |           {
273 |             type: 'text',
274 |             text: JSON.stringify({ results }, null, 2)
275 |           }
276 |         ]
277 |       };
278 |     } catch (error) {
279 |       throw new McpError(
280 |         ErrorCode.InternalError,
281 |         `Failed to search characters: ${error.message}`
282 |       );
283 |     }
284 |   }
285 | 
286 |   async getZeroWidthChars() {
287 |     try {
288 |       const chars = await this.symbl.getZeroWidthCharacters();
289 |       return {
290 |         content: [
291 |           {
292 |             type: 'text',
293 |             text: JSON.stringify({ chars }, null, 2)
294 |           }
295 |         ]
296 |       };
297 |     } catch (error) {
298 |       throw new McpError(
299 |         ErrorCode.InternalError,
300 |         `Failed to get zero-width characters: ${error.message}`
301 |       );
302 |     }
303 |   }
304 | 
305 |   async start() {
306 |     const transport = new StdioServerTransport();
307 |     await this.server.connect(transport);
308 |     console.error('Unicode Puzzles MCP server started');
309 |   }
310 | }
311 | 
312 | // Initialize and start server
313 | const server = new UnicodePuzzlesMCP();
314 | server.start().catch(console.error);
```