@trishchuk/coolors-mcp 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (197) hide show
  1. package/.claude/settings.local.json +39 -0
  2. package/.env +2 -0
  3. package/.github/ISSUE_TEMPLATE/bug_report.md +73 -0
  4. package/.github/ISSUE_TEMPLATE/feature_request.md +71 -0
  5. package/.github/pull_request_template.md +97 -0
  6. package/.github/workflows/ci.yml +127 -0
  7. package/.github/workflows/deploy-docs.yml +56 -0
  8. package/.github/workflows/release.yml +99 -0
  9. package/.mcp.json +12 -0
  10. package/.prettierignore +1 -0
  11. package/CLAUDE.md +201 -0
  12. package/DOCUMENTATION.md +274 -0
  13. package/GEMINI.md +54 -0
  14. package/LICENSE +21 -0
  15. package/README.md +401 -0
  16. package/demo/content_based_color.png +0 -0
  17. package/demo/music-player.html +621 -0
  18. package/demo/podcast-player.html +903 -0
  19. package/dist/bin/coolors-mcp.d.ts +1 -0
  20. package/dist/bin/coolors-mcp.js +154 -0
  21. package/dist/bin/coolors-mcp.js.map +1 -0
  22. package/dist/bin/server.d.ts +1 -0
  23. package/dist/bin/server.js +3292 -0
  24. package/dist/bin/server.js.map +1 -0
  25. package/dist/chunk-IQ7NN26V.js +114 -0
  26. package/dist/chunk-IQ7NN26V.js.map +1 -0
  27. package/dist/chunk-P3ARRKLS.js +1214 -0
  28. package/dist/chunk-P3ARRKLS.js.map +1 -0
  29. package/dist/color/index.d.ts +716 -0
  30. package/dist/color/index.js +153 -0
  31. package/dist/color/index.js.map +1 -0
  32. package/dist/coolors-mcp.d.ts +136 -0
  33. package/dist/coolors-mcp.js +7 -0
  34. package/dist/coolors-mcp.js.map +1 -0
  35. package/docs/.vitepress/cache/deps/@braintree_sanitize-url.js +93 -0
  36. package/docs/.vitepress/cache/deps/@braintree_sanitize-url.js.map +7 -0
  37. package/docs/.vitepress/cache/deps/_metadata.json +127 -0
  38. package/docs/.vitepress/cache/deps/chunk-BUSYA2B4.js +9 -0
  39. package/docs/.vitepress/cache/deps/chunk-BUSYA2B4.js.map +7 -0
  40. package/docs/.vitepress/cache/deps/chunk-JD3CXNQ6.js +12683 -0
  41. package/docs/.vitepress/cache/deps/chunk-JD3CXNQ6.js.map +7 -0
  42. package/docs/.vitepress/cache/deps/chunk-SYPOPCWC.js +9719 -0
  43. package/docs/.vitepress/cache/deps/chunk-SYPOPCWC.js.map +7 -0
  44. package/docs/.vitepress/cache/deps/cytoscape-cose-bilkent.js +4710 -0
  45. package/docs/.vitepress/cache/deps/cytoscape-cose-bilkent.js.map +7 -0
  46. package/docs/.vitepress/cache/deps/cytoscape.js +30278 -0
  47. package/docs/.vitepress/cache/deps/cytoscape.js.map +7 -0
  48. package/docs/.vitepress/cache/deps/dayjs.js +285 -0
  49. package/docs/.vitepress/cache/deps/dayjs.js.map +7 -0
  50. package/docs/.vitepress/cache/deps/debug.js +468 -0
  51. package/docs/.vitepress/cache/deps/debug.js.map +7 -0
  52. package/docs/.vitepress/cache/deps/package.json +3 -0
  53. package/docs/.vitepress/cache/deps/prismjs.js +1466 -0
  54. package/docs/.vitepress/cache/deps/prismjs.js.map +7 -0
  55. package/docs/.vitepress/cache/deps/prismjs_components_prism-bash.js +228 -0
  56. package/docs/.vitepress/cache/deps/prismjs_components_prism-bash.js.map +7 -0
  57. package/docs/.vitepress/cache/deps/prismjs_components_prism-javascript.js +142 -0
  58. package/docs/.vitepress/cache/deps/prismjs_components_prism-javascript.js.map +7 -0
  59. package/docs/.vitepress/cache/deps/prismjs_components_prism-json.js +27 -0
  60. package/docs/.vitepress/cache/deps/prismjs_components_prism-json.js.map +7 -0
  61. package/docs/.vitepress/cache/deps/prismjs_components_prism-python.js +65 -0
  62. package/docs/.vitepress/cache/deps/prismjs_components_prism-python.js.map +7 -0
  63. package/docs/.vitepress/cache/deps/prismjs_components_prism-typescript.js +53 -0
  64. package/docs/.vitepress/cache/deps/prismjs_components_prism-typescript.js.map +7 -0
  65. package/docs/.vitepress/cache/deps/prismjs_components_prism-yaml.js +73 -0
  66. package/docs/.vitepress/cache/deps/prismjs_components_prism-yaml.js.map +7 -0
  67. package/docs/.vitepress/cache/deps/vitepress___@vue_devtools-api.js +4507 -0
  68. package/docs/.vitepress/cache/deps/vitepress___@vue_devtools-api.js.map +7 -0
  69. package/docs/.vitepress/cache/deps/vitepress___@vueuse_core.js +584 -0
  70. package/docs/.vitepress/cache/deps/vitepress___@vueuse_core.js.map +7 -0
  71. package/docs/.vitepress/cache/deps/vitepress___@vueuse_integrations_useFocusTrap.js +1146 -0
  72. package/docs/.vitepress/cache/deps/vitepress___@vueuse_integrations_useFocusTrap.js.map +7 -0
  73. package/docs/.vitepress/cache/deps/vitepress___mark__js_src_vanilla__js.js +1667 -0
  74. package/docs/.vitepress/cache/deps/vitepress___mark__js_src_vanilla__js.js.map +7 -0
  75. package/docs/.vitepress/cache/deps/vitepress___minisearch.js +1814 -0
  76. package/docs/.vitepress/cache/deps/vitepress___minisearch.js.map +7 -0
  77. package/docs/.vitepress/cache/deps/vue.js +344 -0
  78. package/docs/.vitepress/cache/deps/vue.js.map +7 -0
  79. package/docs/.vitepress/components/ClientGrid.vue +125 -0
  80. package/docs/.vitepress/components/CodeBlock.vue +231 -0
  81. package/docs/.vitepress/components/ConfigModal.vue +477 -0
  82. package/docs/.vitepress/components/DiagramModal.vue +528 -0
  83. package/docs/.vitepress/components/TroubleshootingModal.vue +472 -0
  84. package/docs/.vitepress/config.js +162 -0
  85. package/docs/.vitepress/theme/FundingLayout.vue +251 -0
  86. package/docs/.vitepress/theme/Layout.vue +134 -0
  87. package/docs/.vitepress/theme/components/AdBanner.vue +317 -0
  88. package/docs/.vitepress/theme/components/AdPlaceholder.vue +78 -0
  89. package/docs/.vitepress/theme/components/FundingEffects.vue +322 -0
  90. package/docs/.vitepress/theme/components/FundingHero.vue +345 -0
  91. package/docs/.vitepress/theme/components/SupportSection.vue +511 -0
  92. package/docs/.vitepress/theme/custom-app.css +339 -0
  93. package/docs/.vitepress/theme/custom.css +699 -0
  94. package/docs/.vitepress/theme/index.js +25 -0
  95. package/docs/README.md +198 -0
  96. package/docs/concepts/accessibility.md +473 -0
  97. package/docs/concepts/color-spaces.md +222 -0
  98. package/docs/concepts/distance-metrics.md +384 -0
  99. package/docs/concepts/hct.md +261 -0
  100. package/docs/concepts/image-analysis.md +396 -0
  101. package/docs/concepts/material-design.md +306 -0
  102. package/docs/concepts/theme-matching.md +399 -0
  103. package/docs/examples/basic-colors.md +490 -0
  104. package/docs/examples/creating-themes.md +898 -0
  105. package/docs/examples/css-refactoring.md +824 -0
  106. package/docs/examples/image-extraction.md +882 -0
  107. package/docs/getting-started.md +366 -0
  108. package/docs/index.md +190 -0
  109. package/docs/installation.md +157 -0
  110. package/docs/tools/README.md +234 -0
  111. package/docs/tools/accessibility.md +614 -0
  112. package/docs/tools/color-operations.md +374 -0
  113. package/docs/tools/image-extraction.md +624 -0
  114. package/docs/tools/material-design.md +347 -0
  115. package/docs/tools/theme-matching.md +552 -0
  116. package/eslint.config.ts +14 -0
  117. package/examples/theme-matching.md +113 -0
  118. package/jsr.json +7 -0
  119. package/mcp-config.json +8 -0
  120. package/note.md +35 -0
  121. package/package.json +122 -0
  122. package/research_results.md +53 -0
  123. package/src/bin/coolors-mcp.ts +194 -0
  124. package/src/bin/server.ts +61 -0
  125. package/src/color/__tests__/conversions-argb.test.ts +198 -0
  126. package/src/color/__tests__/extract-colors.test.ts +360 -0
  127. package/src/color/__tests__/image-utils.test.ts +242 -0
  128. package/src/color/__tests__/reference-colors.test.ts +278 -0
  129. package/src/color/__tests__/round-trip.test.ts +197 -0
  130. package/src/color/conversions.test.ts +402 -0
  131. package/src/color/conversions.ts +393 -0
  132. package/src/color/dislike/__tests__/dislike-analyzer.test.ts +248 -0
  133. package/src/color/dislike/dislike-analyzer.ts +114 -0
  134. package/src/color/extract-colors.ts +228 -0
  135. package/src/color/hct/__tests__/hct-class.test.ts +232 -0
  136. package/src/color/hct/harmonization.ts +204 -0
  137. package/src/color/hct/hct-class.ts +109 -0
  138. package/src/color/hct/hct-solver.ts +168 -0
  139. package/src/color/hct/index.ts +39 -0
  140. package/src/color/hct/tonal-palette.ts +211 -0
  141. package/src/color/hct/types.ts +88 -0
  142. package/src/color/image-utils.ts +79 -0
  143. package/src/color/index.ts +87 -0
  144. package/src/color/material-theme.ts +157 -0
  145. package/src/color/metrics.test.ts +276 -0
  146. package/src/color/metrics.ts +281 -0
  147. package/src/color/quantize/__tests__/quantizer_celebi.test.ts +195 -0
  148. package/src/color/quantize/lab_point_provider.ts +55 -0
  149. package/src/color/quantize/point_provider.ts +27 -0
  150. package/src/color/quantize/quantizer_celebi.ts +51 -0
  151. package/src/color/quantize/quantizer_celebi_test.ts +71 -0
  152. package/src/color/quantize/quantizer_map.ts +47 -0
  153. package/src/color/quantize/quantizer_wsmeans.ts +232 -0
  154. package/src/color/quantize/quantizer_wu.ts +472 -0
  155. package/src/color/score/__tests__/score.test.ts +224 -0
  156. package/src/color/score/score.ts +175 -0
  157. package/src/color/types.ts +151 -0
  158. package/src/color/utils/color_utils.ts +292 -0
  159. package/src/color/utils/math_utils.ts +145 -0
  160. package/src/color/utils.test.ts +403 -0
  161. package/src/color/utils.ts +315 -0
  162. package/src/constants.ts +5 -0
  163. package/src/coolors-mcp.ts +37 -0
  164. package/src/examples/addition.ts +333 -0
  165. package/src/examples/color-demo.ts +125 -0
  166. package/src/examples/custom-logger.ts +201 -0
  167. package/src/examples/oauth-server.ts +113 -0
  168. package/src/examples/session-context.ts +269 -0
  169. package/src/session.ts +116 -0
  170. package/src/theme/__tests__/matcher.test.ts +180 -0
  171. package/src/theme/__tests__/parser.test.ts +148 -0
  172. package/src/theme/__tests__/refactor.test.ts +224 -0
  173. package/src/theme/index.ts +34 -0
  174. package/src/theme/matcher.ts +395 -0
  175. package/src/theme/parser.ts +392 -0
  176. package/src/theme/refactor.ts +360 -0
  177. package/src/theme/types.ts +152 -0
  178. package/src/tools/__tests__/gradient-generator.test.ts +206 -0
  179. package/src/tools/__tests__/palette-with-locks.test.ts +109 -0
  180. package/src/tools/color-conversion.tool.ts +54 -0
  181. package/src/tools/color-distance.tool.ts +41 -0
  182. package/src/tools/colors.ts +31 -0
  183. package/src/tools/contrast-checker.tool.ts +37 -0
  184. package/src/tools/dislike-analyzer.tool.ts +247 -0
  185. package/src/tools/gradient-generator.tool.ts +250 -0
  186. package/src/tools/image-extraction.tools.ts +289 -0
  187. package/src/tools/index.ts +39 -0
  188. package/src/tools/material-theme.tools.ts +250 -0
  189. package/src/tools/palette-generator.tool.ts +135 -0
  190. package/src/tools/palette-with-locks.tool.ts +221 -0
  191. package/src/tools/registry.ts +142 -0
  192. package/src/tools/simple-tools.ts +37 -0
  193. package/src/tools/theme-matching.tools.ts +334 -0
  194. package/src/types.ts +182 -0
  195. package/src/utils.ts +22 -0
  196. package/tsconfig.json +8 -0
  197. package/vitest.config.js +15 -0
package/note.md ADDED
@@ -0,0 +1,35 @@
1
+ Phase 1: Core Infrastructure
2
+
3
+ - Integrate Material Color Utilities HCT system into existing codebase
4
+ - Build theme variable parser for CSS custom properties
5
+ - Implement HCT-based color distance calculations
6
+
7
+ Phase 2: Matching Engine
8
+
9
+ - Create efficient color lookup using spatial indexing (k-d tree)
10
+ - Implement multi-factor scoring algorithm (perceptual + semantic +
11
+ accessibility)
12
+ - Add context-aware matching for different UI elements
13
+
14
+ Phase 3: CSS Refactoring
15
+
16
+ - Build CSS parser to extract legacy colors
17
+ - Generate refactored CSS with theme variable replacements
18
+ - Include confidence scores and alternative suggestions
19
+
20
+ Phase 4: MCP Integration
21
+
22
+ - Add new MCP tools: match_theme_color, refactor_css_colors,
23
+ analyze_theme_quality
24
+ - Extend existing tools to support HCT color space
25
+
26
+ This approach leverages Material Color Utilities for sophisticated color
27
+ science while integrating with your existing infrastructure for maximum utility
28
+ in UI development.
29
+
30
+ ---
31
+
32
+ [material-color-utilities](researcher/material-color-utilities)
33
+
34
+
35
+ https://github.com/material-foundation/material-color-utilities#readme
package/package.json ADDED
@@ -0,0 +1,122 @@
1
+ {
2
+ "name": "@trishchuk/coolors-mcp",
3
+ "version": "1.0.0",
4
+ "main": "dist/CoolorsMCP.js",
5
+ "scripts": {
6
+ "build": "tsup",
7
+ "lint": "prettier --check . && eslint . && tsc --noEmit",
8
+ "test": "vitest run",
9
+ "format": "prettier --write . && eslint --fix .",
10
+ "docs:dev": "vitepress dev docs",
11
+ "docs:build": "vitepress build docs",
12
+ "docs:preview": "vitepress preview docs"
13
+ },
14
+ "bin": {
15
+ "coolors-mcp": "dist/bin/server.js"
16
+ },
17
+ "keywords": [
18
+ "mcp",
19
+ "model-context-protocol",
20
+ "color",
21
+ "colors",
22
+ "material-design",
23
+ "theme",
24
+ "css",
25
+ "hct",
26
+ "lab",
27
+ "rgb",
28
+ "hsl",
29
+ "palette",
30
+ "gradient",
31
+ "wcag",
32
+ "accessibility",
33
+ "contrast",
34
+ "image-extraction"
35
+ ],
36
+ "type": "module",
37
+ "author": "Taras Trishchuk <x51xxx@gmail.com>",
38
+ "license": "MIT",
39
+ "description": "Advanced color operations MCP server with Material Design 3 support, CSS theme matching, image color extraction, and accessibility compliance. Features HCT color space for perceptually accurate operations.",
40
+ "module": "dist/coolors-mcp.js",
41
+ "types": "dist/coolors-mcp.d.ts",
42
+ "dependencies": {
43
+ "@modelcontextprotocol/sdk": "^1.17.2",
44
+ "@standard-schema/spec": "^1.0.0",
45
+ "culori": "^4.0.2",
46
+ "execa": "^9.6.0",
47
+ "file-type": "^21.0.0",
48
+ "fuse.js": "^7.1.0",
49
+ "mcp-proxy": "^5.5.4",
50
+ "strict-event-emitter-types": "^2.0.0",
51
+ "undici": "^7.13.0",
52
+ "uri-templates": "^0.2.0",
53
+ "xsschema": "0.3.5",
54
+ "yargs": "^18.0.0",
55
+ "zod": "^3.25.76",
56
+ "zod-to-json-schema": "^3.24.6"
57
+ },
58
+ "repository": {
59
+ "type": "git",
60
+ "url": "https://github.com/x51xxx/coolors-mcp"
61
+ },
62
+ "homepage": "https://github.com/x51xxx/coolors-mcp",
63
+ "bugs": {
64
+ "url": "https://github.com/x51xxx/coolors-mcp/issues"
65
+ },
66
+ "release": {
67
+ "branches": [
68
+ "main"
69
+ ],
70
+ "plugins": [
71
+ "@semantic-release/commit-analyzer",
72
+ "@semantic-release/release-notes-generator",
73
+ "@semantic-release/npm",
74
+ "@semantic-release/github",
75
+ "@sebbo2002/semantic-release-jsr"
76
+ ]
77
+ },
78
+ "devDependencies": {
79
+ "@eslint/js": "^9.33.0",
80
+ "@modelcontextprotocol/inspector": "^0.16.2",
81
+ "@sebbo2002/semantic-release-jsr": "^3.0.1",
82
+ "@tsconfig/node22": "^22.0.2",
83
+ "@types/node": "^24.2.1",
84
+ "@types/uri-templates": "^0.1.34",
85
+ "@types/yargs": "^17.0.33",
86
+ "@valibot/to-json-schema": "^1.3.0",
87
+ "@wong2/mcp-cli": "^1.13.0",
88
+ "arktype": "^2.1.20",
89
+ "eslint": "^9.33.0",
90
+ "eslint-config-prettier": "^10.1.8",
91
+ "eslint-plugin-perfectionist": "^4.15.0",
92
+ "eslint-plugin-prettier": "^5.5.4",
93
+ "eventsource-client": "^1.1.4",
94
+ "get-port-please": "^3.2.0",
95
+ "jiti": "^2.5.1",
96
+ "jsr": "^0.13.5",
97
+ "prettier": "^3.6.2",
98
+ "semantic-release": "^24.2.7",
99
+ "tsup": "^8.5.0",
100
+ "typescript": "^5.9.2",
101
+ "typescript-eslint": "^8.39.0",
102
+ "valibot": "^1.1.0",
103
+ "vitepress": "^1.6.4",
104
+ "vitepress-plugin-mermaid": "^2.0.17",
105
+ "vitest": "^3.2.4"
106
+ },
107
+ "tsup": {
108
+ "entry": [
109
+ "src/coolors-mcp.ts",
110
+ "src/bin/coolors-mcp.ts",
111
+ "src/bin/server.ts",
112
+ "src/color/index.ts"
113
+ ],
114
+ "format": [
115
+ "esm"
116
+ ],
117
+ "dts": true,
118
+ "splitting": true,
119
+ "sourcemap": true,
120
+ "clean": true
121
+ }
122
+ }
@@ -0,0 +1,53 @@
1
+ # Research Results
2
+
3
+ ## chromaticity-color-utilities
4
+
5
+ Based on the search results, "chromaticity-color-utilities" seems to be a general term for libraries that provide color science calculations. There are many libraries available for different languages.
6
+
7
+ For JavaScript/Node.js, some popular libraries are:
8
+
9
+ - **Culori**: A comprehensive color library that supports a wide range of color spaces and difference calculations.
10
+ - **Color.js**: A library for color conversion and manipulation.
11
+ - **Chroma.js**: A small library for color conversions and scales.
12
+
13
+ For Python, some popular libraries are:
14
+
15
+ - **Colour**: A powerful color science library with a wide range of features.
16
+ - **ColorPy**: A library for color calculations and visualization.
17
+ - **ColorAide**: A modern color library with a focus on ease of use.
18
+
19
+ The user should specify the programming language and the specific functionality they need to get a more specific recommendation.
20
+
21
+ ## encodable
22
+
23
+ "Encodable" is a general term in software engineering that refers to the ability of data or an object to be converted into a specific format for storage, transmission, or processing.
24
+
25
+ Common types of encoding include:
26
+
27
+ - **Data Serialization**: Converting data structures or object states into a format that can be stored or transmitted and reconstructed later (e.g., JSON, XML, Protocol Buffers).
28
+ - **Character Encoding**: Representing text characters in a digital format (e.g., UTF-8, ASCII).
29
+ - **Binary-to-Text Encoding**: Converting binary data into a text-based format (e.g., Base64, Hexadecimal).
30
+ - **URL Encoding**: Converting characters in a URL into a format that can be safely transmitted.
31
+
32
+ The user should provide more context on what they mean by "encodable" to get a more specific answer.
33
+
34
+ ## material-color-utilities
35
+
36
+ "Material Color Utilities" (MCU) is a set of color libraries developed by Material Design. It provides algorithms and utilities for generating dynamic color themes and schemes, particularly for Material You.
37
+
38
+ MCU is available for various programming languages, including:
39
+
40
+ - **TypeScript** (via npm): `@material/material-color-utilities`
41
+ - **Dart** (via Pub.dev): `material_color_utilities`
42
+ - **Rust**: `material-color-utilities`
43
+
44
+ The core concepts of MCU include:
45
+
46
+ - **Dynamic Color**: Generating a color palette from a single seed color, often extracted from a user's wallpaper.
47
+ - **Tonal Palettes**: A set of 13 tones for each color in the palette, which provides a range of shades for different UI elements.
48
+
49
+ MCU can be used to:
50
+
51
+ - Create personalized color themes for applications.
52
+ - Ensure color harmony and accessibility in UIs.
53
+ - Implement Material You features in an application.
@@ -0,0 +1,194 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { execa } from "execa";
4
+ import yargs from "yargs";
5
+ import { hideBin } from "yargs/helpers";
6
+
7
+ await yargs(hideBin(process.argv))
8
+ .scriptName("coolors-mcp")
9
+ .command(
10
+ "dev <file>",
11
+ "Start a development server",
12
+ (yargs) => {
13
+ return yargs
14
+ .positional("file", {
15
+ demandOption: true,
16
+ describe: "The path to the server file",
17
+ type: "string",
18
+ })
19
+
20
+ .option("watch", {
21
+ alias: "w",
22
+ default: false,
23
+ describe: "Watch for file changes and restart server",
24
+ type: "boolean",
25
+ })
26
+
27
+ .option("verbose", {
28
+ alias: "v",
29
+ default: false,
30
+ describe: "Enable verbose logging",
31
+ type: "boolean",
32
+ });
33
+ },
34
+
35
+ async (argv) => {
36
+ try {
37
+ const command = argv.watch
38
+ ? `npx @wong2/mcp-cli npx tsx --watch ${argv.file}`
39
+ : `npx @wong2/mcp-cli npx tsx ${argv.file}`;
40
+
41
+ if (argv.verbose) {
42
+ console.log(`[CoolorsMCP] Starting server: ${command}`);
43
+ console.log(`[CoolorsMCP] File: ${argv.file}`);
44
+ console.log(
45
+ `[CoolorsMCP] Watch mode: ${argv.watch ? "enabled" : "disabled"}`,
46
+ );
47
+ }
48
+
49
+ const { stdout } = await execa({
50
+ shell: true,
51
+ stderr: "inherit",
52
+ stdin: "inherit",
53
+ })`${command}`;
54
+
55
+ console.log(stdout);
56
+ } catch (error) {
57
+ console.error(
58
+ "[CoolorsMCP Error] Failed to start development server:",
59
+ error instanceof Error ? error.message : String(error),
60
+ );
61
+
62
+ if (argv.verbose && error instanceof Error && error.stack) {
63
+ console.error("[CoolorsMCP Debug] Stack trace:", error.stack);
64
+ }
65
+
66
+ process.exit(1);
67
+ }
68
+ },
69
+ )
70
+
71
+ .command(
72
+ "inspect <file>",
73
+ "Inspect a server file",
74
+ (yargs) => {
75
+ return yargs.positional("file", {
76
+ demandOption: true,
77
+ describe: "The path to the server file",
78
+ type: "string",
79
+ });
80
+ },
81
+
82
+ async (argv) => {
83
+ try {
84
+ await execa({
85
+ stderr: "inherit",
86
+ stdout: "inherit",
87
+ })`npx @modelcontextprotocol/inspector npx tsx ${argv.file}`;
88
+ } catch (error) {
89
+ console.error(
90
+ "[CoolorsMCP Error] Failed to inspect server:",
91
+ error instanceof Error ? error.message : String(error),
92
+ );
93
+
94
+ process.exit(1);
95
+ }
96
+ },
97
+ )
98
+
99
+ .command(
100
+ "validate <file>",
101
+ "Validate a CoolorsMCP server file for syntax and basic structure",
102
+ (yargs) => {
103
+ return yargs
104
+ .positional("file", {
105
+ demandOption: true,
106
+ describe: "The path to the server file",
107
+ type: "string",
108
+ })
109
+
110
+ .option("strict", {
111
+ alias: "s",
112
+ default: false,
113
+ describe: "Enable strict validation (type checking)",
114
+ type: "boolean",
115
+ });
116
+ },
117
+
118
+ async (argv) => {
119
+ try {
120
+ const { existsSync } = await import("fs");
121
+ const { resolve } = await import("path");
122
+ const filePath = resolve(argv.file);
123
+
124
+ if (!existsSync(filePath)) {
125
+ console.error(`[CoolorsMCP Error] File not found: ${filePath}`);
126
+ process.exit(1);
127
+ }
128
+
129
+ console.log(`[CoolorsMCP] Validating server file: ${filePath}`);
130
+
131
+ const command = argv.strict
132
+ ? `npx tsc --noEmit --strict ${filePath}`
133
+ : `npx tsc --noEmit ${filePath}`;
134
+
135
+ try {
136
+ await execa({
137
+ shell: true,
138
+ stderr: "pipe",
139
+ stdout: "pipe",
140
+ })`${command}`;
141
+
142
+ console.log("[CoolorsMCP] ✓ TypeScript compilation successful");
143
+ } catch (tsError) {
144
+ console.error("[CoolorsMCP] ✗ TypeScript compilation failed");
145
+
146
+ if (tsError instanceof Error && "stderr" in tsError) {
147
+ console.error(tsError.stderr);
148
+ }
149
+
150
+ process.exit(1);
151
+ }
152
+
153
+ try {
154
+ await execa({
155
+ shell: true,
156
+ stderr: "pipe",
157
+ stdout: "pipe",
158
+ })`node -e "
159
+ (async () => {
160
+ try {
161
+ const { CoolorsMCP } = await import('coolors-mcp');
162
+ await import('file://${filePath}');
163
+ console.log('[CoolorsMCP] ✓ Server structure validation passed');
164
+ } catch (error) {
165
+ console.error('[CoolorsMCP] ✗ Server structure validation failed:', error.message);
166
+ process.exit(1);
167
+ }
168
+ })();
169
+ "`;
170
+ } catch {
171
+ console.error("[CoolorsMCP] ✗ Server structure validation failed");
172
+ console.error(
173
+ "Make sure the file properly imports and uses CoolorsMCP",
174
+ );
175
+
176
+ process.exit(1);
177
+ }
178
+
179
+ console.log(
180
+ "[CoolorsMCP] ✓ All validations passed! Server file looks good.",
181
+ );
182
+ } catch (error) {
183
+ console.error(
184
+ "[CoolorsMCP Error] Validation failed:",
185
+ error instanceof Error ? error.message : String(error),
186
+ );
187
+
188
+ process.exit(1);
189
+ }
190
+ },
191
+ )
192
+
193
+ .help()
194
+ .parseAsync();
@@ -0,0 +1,61 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Coolors MCP Server - Advanced Color Operations & Theme Intelligence
5
+ *
6
+ * A comprehensive Model Context Protocol server providing:
7
+ * - Color space conversions (RGB, HSL, HSV, LAB, XYZ, HCT)
8
+ * - Material Design 3 theme generation with tonal palettes
9
+ * - Intelligent CSS theme matching with multi-factor scoring
10
+ * - Image color extraction using Celebi quantization
11
+ * - WCAG accessibility compliance checking
12
+ * - Universal color preference analysis (dislike detection)
13
+ * - Context-aware color selection for UI components
14
+ *
15
+ * Built on Google's HCT color space for perceptually uniform operations
16
+ * and Material Color Utilities algorithms for professional-grade results.
17
+ */
18
+
19
+ import { CoolorsMcp } from "../coolors-mcp.js";
20
+ import * as tools from "../tools/index.js";
21
+
22
+ // Create the MCP server
23
+ const server = new CoolorsMcp({
24
+ instructions:
25
+ "Advanced color operations server with Material Design 3 support, CSS theme matching, image extraction, and accessibility compliance. Uses HCT color space for perceptually accurate operations.",
26
+ name: "coolors-mcp",
27
+ version: "1.0.0",
28
+ });
29
+
30
+ // Core color operations: conversion, distance metrics, accessibility
31
+ server.addTool(tools.colorConversionTool);
32
+ server.addTool(tools.colorDistanceTool);
33
+ server.addTool(tools.contrastCheckerTool);
34
+ server.addTool(tools.paletteGeneratorTool);
35
+ server.addTool(tools.paletteWithLocksTool);
36
+ server.addTool(tools.gradientGeneratorTool);
37
+
38
+ // Material Design 3: theme generation, harmonization, tonal palettes
39
+ server.addTool(tools.generateMaterialThemeTool);
40
+ server.addTool(tools.harmonizeColorsTool);
41
+ server.addTool(tools.generateTonalPaletteTool);
42
+
43
+ // CSS theme intelligence: matching, refactoring, migration
44
+ server.addTool(tools.matchThemeColorTool);
45
+ server.addTool(tools.refactorCssWithThemeTool);
46
+ server.addTool(tools.matchThemeColorsBatchTool);
47
+ server.addTool(tools.generateThemeCssTool);
48
+
49
+ // Image analysis: color extraction, theme generation from photos
50
+ server.addTool(tools.extractImageColorsTool);
51
+ server.addTool(tools.generateThemeFromImageTool);
52
+
53
+ // Color psychology: detect and fix universally disliked colors
54
+ server.addTool(tools.analyzeColorLikabilityTool);
55
+ server.addTool(tools.fixDislikedColorsBatchTool);
56
+
57
+ // Start the server
58
+ server.start().catch((error) => {
59
+ console.error("Failed to start server:", error);
60
+ process.exit(1);
61
+ });
@@ -0,0 +1,198 @@
1
+ /**
2
+ * Tests for ARGB conversion functions
3
+ */
4
+
5
+ import { describe, expect, it } from "vitest";
6
+
7
+ import { argbToRgb, rgbToArgb } from "../conversions.js";
8
+
9
+ describe("ARGB Conversions", () => {
10
+ describe("rgbToArgb", () => {
11
+ it("should convert RGB to ARGB with full opacity", () => {
12
+ const argb = rgbToArgb({ b: 64, g: 128, r: 255 });
13
+
14
+ // Check alpha channel (should be 0xff)
15
+ expect((argb >> 24) & 0xff).toBe(0xff);
16
+
17
+ // Check RGB channels
18
+ expect((argb >> 16) & 0xff).toBe(255); // Red
19
+ expect((argb >> 8) & 0xff).toBe(128); // Green
20
+ expect(argb & 0xff).toBe(64); // Blue
21
+ });
22
+
23
+ it("should handle primary colors", () => {
24
+ const red = rgbToArgb({ b: 0, g: 0, r: 255 });
25
+ const green = rgbToArgb({ b: 0, g: 255, r: 0 });
26
+ const blue = rgbToArgb({ b: 255, g: 0, r: 0 });
27
+
28
+ // Use >>> 0 to convert expected values to unsigned
29
+ expect(red).toBe(0xffff0000 >>> 0);
30
+ expect(green).toBe(0xff00ff00 >>> 0);
31
+ expect(blue).toBe(0xff0000ff >>> 0);
32
+ });
33
+
34
+ it("should handle black and white", () => {
35
+ const black = rgbToArgb({ b: 0, g: 0, r: 0 });
36
+ const white = rgbToArgb({ b: 255, g: 255, r: 255 });
37
+
38
+ expect(black).toBe(0xff000000 >>> 0);
39
+ expect(white).toBe(0xffffffff >>> 0);
40
+ });
41
+
42
+ it("should clamp values above 255", () => {
43
+ const argb = rgbToArgb({ b: 1000, g: 256, r: 300 });
44
+
45
+ expect((argb >> 16) & 0xff).toBe(255); // Red clamped
46
+ expect((argb >> 8) & 0xff).toBe(255); // Green clamped
47
+ expect(argb & 0xff).toBe(255); // Blue clamped
48
+ });
49
+
50
+ it("should clamp negative values to 0", () => {
51
+ const argb = rgbToArgb({ b: -1, g: -100, r: -10 });
52
+
53
+ expect((argb >> 16) & 0xff).toBe(0); // Red clamped
54
+ expect((argb >> 8) & 0xff).toBe(0); // Green clamped
55
+ expect(argb & 0xff).toBe(0); // Blue clamped
56
+ });
57
+
58
+ it("should round floating point values", () => {
59
+ const argb = rgbToArgb({ b: 127.5, g: 127.3, r: 127.7 });
60
+
61
+ expect((argb >> 16) & 0xff).toBe(128); // Rounded up
62
+ expect((argb >> 8) & 0xff).toBe(127); // Rounded down
63
+ expect(argb & 0xff).toBe(128); // Rounded up (0.5 rounds up)
64
+ });
65
+
66
+ it("should produce correct 32-bit integer", () => {
67
+ const argb = rgbToArgb({ b: 0x56, g: 0x34, r: 0x12 });
68
+
69
+ expect(argb).toBe(0xff123456 >>> 0);
70
+ expect(argb.toString(16)).toBe("ff123456");
71
+ });
72
+ });
73
+
74
+ describe("argbToRgb", () => {
75
+ it("should convert ARGB back to RGB", () => {
76
+ const argb = 0xff804020; // Alpha: 255, R: 128, G: 64, B: 32
77
+ const rgb = argbToRgb(argb);
78
+
79
+ expect(rgb.r).toBe(128);
80
+ expect(rgb.g).toBe(64);
81
+ expect(rgb.b).toBe(32);
82
+ });
83
+
84
+ it("should ignore alpha channel", () => {
85
+ const argbFullAlpha = 0xff123456;
86
+ const argbNoAlpha = 0x00123456;
87
+
88
+ const rgb1 = argbToRgb(argbFullAlpha);
89
+ const rgb2 = argbToRgb(argbNoAlpha);
90
+
91
+ // RGB values should be the same regardless of alpha
92
+ expect(rgb1).toEqual(rgb2);
93
+ expect(rgb1.r).toBe(0x12);
94
+ expect(rgb1.g).toBe(0x34);
95
+ expect(rgb1.b).toBe(0x56);
96
+ });
97
+
98
+ it("should handle primary colors", () => {
99
+ const red = argbToRgb(0xffff0000);
100
+ const green = argbToRgb(0xff00ff00);
101
+ const blue = argbToRgb(0xff0000ff);
102
+
103
+ expect(red).toEqual({ b: 0, g: 0, r: 255 });
104
+ expect(green).toEqual({ b: 0, g: 255, r: 0 });
105
+ expect(blue).toEqual({ b: 255, g: 0, r: 0 });
106
+ });
107
+
108
+ it("should handle black and white", () => {
109
+ const black = argbToRgb(0xff000000);
110
+ const white = argbToRgb(0xffffffff);
111
+
112
+ expect(black).toEqual({ b: 0, g: 0, r: 0 });
113
+ expect(white).toEqual({ b: 255, g: 255, r: 255 });
114
+ });
115
+
116
+ it("should handle grayscale values", () => {
117
+ const gray = argbToRgb(0xff808080);
118
+
119
+ expect(gray).toEqual({ b: 128, g: 128, r: 128 });
120
+ });
121
+ });
122
+
123
+ describe("round-trip conversion", () => {
124
+ it("should maintain values through round-trip", () => {
125
+ const originalRgb = { b: 67, g: 45, r: 123 };
126
+ const argb = rgbToArgb(originalRgb);
127
+ const resultRgb = argbToRgb(argb);
128
+
129
+ expect(resultRgb).toEqual(originalRgb);
130
+ });
131
+
132
+ it("should handle all possible byte values", () => {
133
+ // Test a sampling of values
134
+ for (let i = 0; i < 256; i += 17) {
135
+ const originalRgb = { b: (i + 170) % 256, g: (i + 85) % 256, r: i };
136
+ const argb = rgbToArgb(originalRgb);
137
+ const resultRgb = argbToRgb(argb);
138
+
139
+ expect(resultRgb).toEqual(originalRgb);
140
+ }
141
+ });
142
+
143
+ it("should maintain clamped values", () => {
144
+ const originalRgb = { b: 127.8, g: -50, r: 300 };
145
+ const argb = rgbToArgb(originalRgb);
146
+ const resultRgb = argbToRgb(argb);
147
+
148
+ // Values should be clamped and rounded
149
+ expect(resultRgb).toEqual({ b: 128, g: 0, r: 255 });
150
+ });
151
+ });
152
+
153
+ describe("edge cases", () => {
154
+ it("should handle zero values", () => {
155
+ const argb = rgbToArgb({ b: 0, g: 0, r: 0 });
156
+ expect(argb).toBe(0xff000000 >>> 0);
157
+
158
+ const rgb = argbToRgb(0);
159
+ expect(rgb).toEqual({ b: 0, g: 0, r: 0 });
160
+ });
161
+
162
+ it("should handle maximum values", () => {
163
+ const argb = rgbToArgb({ b: 255, g: 255, r: 255 });
164
+ expect(argb).toBe(0xffffffff >>> 0);
165
+
166
+ const rgb = argbToRgb(0xffffffff);
167
+ expect(rgb).toEqual({ b: 255, g: 255, r: 255 });
168
+ });
169
+
170
+ it("should handle single channel values", () => {
171
+ const redOnly = rgbToArgb({ b: 0, g: 0, r: 255 });
172
+ const greenOnly = rgbToArgb({ b: 0, g: 255, r: 0 });
173
+ const blueOnly = rgbToArgb({ b: 255, g: 0, r: 0 });
174
+
175
+ expect(redOnly & 0x00ffffff).toBe(0x00ff0000);
176
+ expect(greenOnly & 0x00ffffff).toBe(0x0000ff00);
177
+ expect(blueOnly & 0x00ffffff).toBe(0x000000ff);
178
+ });
179
+
180
+ it("should preserve bit patterns", () => {
181
+ // Test specific bit patterns
182
+ const patterns = [
183
+ 0xff000000 >>> 0, // Black
184
+ 0xffffffff >>> 0, // White
185
+ 0xff808080 >>> 0, // Gray
186
+ 0xffaa55aa >>> 0, // Mixed pattern
187
+ 0xff123456 >>> 0, // Sequential
188
+ 0xfffedcba >>> 0, // Reverse sequential
189
+ ];
190
+
191
+ for (const pattern of patterns) {
192
+ const rgb = argbToRgb(pattern);
193
+ const result = rgbToArgb(rgb);
194
+ expect(result).toBe(pattern);
195
+ }
196
+ });
197
+ });
198
+ });