Skip to main content
Glama
ewilderj

Fountain Pen Ink MCP Server

get_color_palette

Generate themed or harmony-based fountain pen ink palettes using predefined themes, custom color lists, or color harmony rules from a base color.

Instructions

Generate a themed or harmony-based palette of inks. Supports three modes: 1) Predefined themes (warm, cool, earth, ocean, autumn, spring, summer, winter, pastel, vibrant, monochrome, sunset, forest), 2) Custom hex color lists (comma-separated), 3) Color harmony generation from a base hex color.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
themeYesTheme name (e.g., "warm", "ocean"), comma-separated hex colors (e.g., "#FF0000,#00FF00"), or single hex color for harmony generation (e.g., "#FF0000").
palette_sizeNoNumber of inks in the palette (default: 5)
harmonyNoColor harmony rule to apply when theme is a single hex color. Options: "complementary", "analogous", "triadic", "split-complementary". Requires theme to be a valid hex color.

Implementation Reference

  • Main handler function that executes the get_color_palette tool. Handles theme parsing, color harmony generation, and finds closest matching fountain pen inks for each palette color.
    private getColorPalette( theme: string, paletteSize: number, harmony?: Harmony, ): MCPTextResponse { const themeColors: { [key: string]: [number, number, number][] } = { warm: [ [255, 100, 50], [255, 150, 0], [200, 80, 80], [180, 120, 60], [220, 180, 100], ], cool: [ [50, 150, 255], [100, 200, 200], [150, 100, 255], [80, 180, 150], [120, 120, 200], ], earth: [ [139, 69, 19], [160, 82, 45], [210, 180, 140], [107, 142, 35], [85, 107, 47], ], ocean: [ [0, 119, 190], [0, 150, 136], [72, 201, 176], [135, 206, 235], [25, 25, 112], ], autumn: [ [255, 140, 0], [255, 69, 0], [220, 20, 60], [184, 134, 11], [139, 69, 19], ], spring: [ [154, 205, 50], [124, 252, 0], [173, 255, 47], [50, 205, 50], [0, 255, 127], ], summer: [ [255, 235, 59], [255, 193, 7], [76, 175, 80], [139, 195, 74], [3, 169, 244], ], winter: [ [224, 224, 224], [144, 164, 174], [96, 125, 139], [33, 150, 243], [0, 0, 128], ], pastel: [ [255, 204, 204], [204, 255, 204], [204, 204, 255], [255, 255, 204], [255, 204, 255], ], vibrant: [ [255, 0, 0], [0, 255, 0], [0, 0, 255], [255, 255, 0], [255, 0, 255], ], monochrome: [ [255, 255, 255], [224, 224, 224], [192, 192, 192], [128, 128, 128], [64, 64, 64], [0, 0, 0], ], sunset: [ [255, 224, 130], [255, 170, 85], [255, 110, 80], [200, 80, 120], [100, 60, 110], ], forest: [ [34, 85, 34], [20, 60, 20], [60, 100, 60], [100, 140, 100], [140, 180, 140], ], }; let targetColors: [number, number, number][]; const lowerCaseTheme = theme.toLowerCase(); if (harmony) { try { const baseRgb = hexToRgb(theme); const baseHsl = rgbToHsl(baseRgb); const harmonyHsl = generateHarmonyColors(baseHsl, harmony); targetColors = harmonyHsl.map((hsl) => hslToRgb(hsl)); } catch { throw new Error('Invalid base color for harmony rule. Please use a single valid hex code.'); } } else if (themeColors[lowerCaseTheme]) { targetColors = themeColors[lowerCaseTheme]; } else if (theme.startsWith('#') || theme.includes(',')) { try { targetColors = theme.split(',').map((hex) => hexToRgb(hex.trim())); } catch { throw new Error( 'Invalid custom palette format. Please use a comma-separated list of hex codes, e.g., "#FF0000,#00FF00,#0000FF"', ); } } else { throw new Error( `Unknown theme: "${theme}". Available themes are: ${Object.keys(themeColors).join(', ')}`, ); } const paletteInks: SearchResult[] = []; const usedInkIds = new Set<string>(); for (let i = 0; i < Math.min(paletteSize, targetColors.length); i++) { const targetRgb = targetColors[i]; const closestInks = findClosestInks(targetRgb, this.inkColors, 5).filter( (ink) => !usedInkIds.has(ink.ink_id), ); if (closestInks.length > 0) { const ink = closestInks[0]; usedInkIds.add(ink.ink_id); const metadata = this.getInkMetadata(ink.ink_id); paletteInks.push(createSearchResult(ink, metadata, ink.distance)); } } const palette: PaletteResult = { theme, inks: paletteInks, description: `A curated palette of ${paletteInks.length} fountain pen inks matching the ${theme} theme.`, }; return { content: [ { type: 'text', text: JSON.stringify(palette, null, 2), }, ], } satisfies MCPTextResponse; }
  • Tool schema definition provided in listTools response, specifying input parameters: theme (required), palette_size, harmony.
    { name: 'get_color_palette', description: 'Generate a themed or harmony-based palette of inks. Supports three modes: 1) Predefined themes (warm, cool, earth, ocean, autumn, spring, summer, winter, pastel, vibrant, monochrome, sunset, forest), 2) Custom hex color lists (comma-separated), 3) Color harmony generation from a base hex color.', inputSchema: { type: 'object', properties: { theme: { type: 'string', description: 'Theme name (e.g., "warm", "ocean"), comma-separated hex colors (e.g., "#FF0000,#00FF00"), or single hex color for harmony generation (e.g., "#FF0000").', }, palette_size: { type: 'number', description: 'Number of inks in the palette (default: 5)', default: 5, }, harmony: { type: 'string', description: 'Color harmony rule to apply when theme is a single hex color. Options: "complementary", "analogous", "triadic", "split-complementary". Requires theme to be a valid hex color.', enum: ['complementary', 'analogous', 'triadic', 'split-complementary'], }, }, required: ['theme'], additionalProperties: false, }, },
  • src/index.ts:295-300 (registration)
    Tool call dispatch in the CallToolRequestSchema handler, routing to the getColorPalette implementation.
    case 'get_color_palette': return this.getColorPalette( args.theme as string, (args.palette_size as number) || 5, args.harmony as Harmony, );
  • Helper function to generate color harmony variants (complementary, analogous, etc.) from base HSL color, used when harmony parameter is provided.
    export function generateHarmonyColors( baseHsl: [number, number, number], harmony: 'complementary' | 'analogous' | 'triadic' | 'split-complementary', ): [number, number, number][] { const [h, s, l] = baseHsl; const harmonyHues: { [key: string]: number[] } = { complementary: [h, (h + 180) % 360], analogous: [h, (h + 30) % 360, (h + 330) % 360], triadic: [h, (h + 120) % 360, (h + 240) % 360], 'split-complementary': [h, (h + 150) % 360, (h + 210) % 360], }; const hues = harmonyHues[harmony] || [h]; return hues.map((hue) => [hue, s, l]); }
  • Core helper to find closest fountain pen inks to a target RGB color using distance metric, used repeatedly in palette generation.
    export function findClosestInks( targetRgb: [number, number, number], inkColors: InkColor[], maxResults: number = 20, ): InkWithDistance[] { const distances = inkColors.map((ink) => ({ ...ink, distance: calculateColorDistance(targetRgb, ink.rgb), // Now both are RGB! })); // Sort by distance (closest first) distances.sort((a, b) => a.distance - b.distance); return distances.slice(0, maxResults); }

Latest Blog Posts

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/ewilderj/inks-mcp'

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