miromiro-mcp 0.3.0 → 0.4.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.
- package/README.md +5 -2
- package/package.json +1 -1
- package/src/index.mjs +26 -14
package/README.md
CHANGED
|
@@ -68,7 +68,7 @@ claude mcp add miromiro -s user \
|
|
|
68
68
|
|---|---|---|
|
|
69
69
|
| `extract_code` | A section of a live page as a paste-ready component (Tailwind, HTML+CSS, JSX or Vue) plus the tokens it uses - start here to rebuild real UI | 25 |
|
|
70
70
|
| `extract_brand` | Named color roles (primary/accent/background/text), palette, fonts split by role, logo, social profiles, and a 0-1 confidence score | 15 |
|
|
71
|
-
| `extract_design_tokens` | Full token system with usage counts; `format: css` or `tailwind` for paste-ready output | 10 |
|
|
71
|
+
| `extract_design_tokens` | Full token system with usage counts; `format: css` or `tailwind` for paste-ready output, `dtcg` for a W3C Design Tokens file (Style Dictionary / Figma variables) | 10 |
|
|
72
72
|
| `extract_fonts` | Every font file and family the site loads, with weights, formats, and file URLs | 5 |
|
|
73
73
|
| `extract_videos` | Video files, `og:video`, and player embeds (YouTube, Vimeo, Wistia, Loom), tagged by source | 1 |
|
|
74
74
|
| `extract_audio` | Audio files, `og:audio`, and podcast enclosures, tagged by source | 1 |
|
|
@@ -87,7 +87,10 @@ Remote results are trimmed by default so a big page cannot flood the chat contex
|
|
|
87
87
|
|
|
88
88
|
The REST API and this local npm server always return everything untrimmed, so `limit` and
|
|
89
89
|
`full_output` apply to the remote server only. Every tool on both servers accepts
|
|
90
|
-
`render: true
|
|
90
|
+
`render: true`, plus two more shared arguments:
|
|
91
|
+
|
|
92
|
+
- `fresh: true` - skip the 24-hour cache and re-extract the live page (charged normally); use when the site just changed
|
|
93
|
+
- `screenshot: true` (requires `render: true`) - the result gains a `screenshot` field: a public URL of a 1440x900 capture of the page, live for 7 days, at no extra credits - show it to the user to verify an extraction
|
|
91
94
|
|
|
92
95
|
## Examples
|
|
93
96
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "miromiro-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "MCP server for the MiroMiro design-extraction API — give your coding agent the real code, design tokens, assets, SVGs, fonts, and Lottie of any website.",
|
|
5
5
|
"mcpName": "app.miromiro/miromiro",
|
|
6
6
|
"type": "module",
|
package/src/index.mjs
CHANGED
|
@@ -42,13 +42,25 @@ const RENDER_ARG = {
|
|
|
42
42
|
description: 'Run the page in a real browser first so its JavaScript executes - use for client-rendered (React/Next/SPA) sites, or when a normal call came back thin. Slower, and adds 5 credits to the call.'
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
+
// Shared input arg: skip the 24h cache for this one call (charged normally).
|
|
46
|
+
const FRESH_ARG = {
|
|
47
|
+
type: 'boolean',
|
|
48
|
+
description: 'Skip the 24-hour cache and re-extract the live page - use when the site just changed and a cached result would be stale. Charged normally; the fresh result replaces the cached copy.'
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Shared input arg: a screenshot URL alongside the data (requires render=true).
|
|
52
|
+
const SCREENSHOT_ARG = {
|
|
53
|
+
type: 'boolean',
|
|
54
|
+
description: 'Requires render=true. Adds a screenshot field to the result: a public URL of a 1440x900 capture of the page (live 7 days), taken by the same browser that rendered it. No extra credits beyond the render surcharge. Useful for showing the user what the extracted site looks like.'
|
|
55
|
+
}
|
|
56
|
+
|
|
45
57
|
const TOOLS = [
|
|
46
58
|
{
|
|
47
59
|
name: 'extract_code',
|
|
48
60
|
title: 'Extract section as code',
|
|
49
61
|
endpoint: 'code',
|
|
50
62
|
description:
|
|
51
|
-
"Turn a section of a LIVE website into clean, paste-ready component code. Give it a URL and (optionally) a CSS selector; it resolves the page's real CSS cascade and returns a self-contained component in Tailwind, plain HTML+CSS, React (JSX) or Vue — plus the design tokens that section actually uses. The response also includes `sections`: every extractable section on the page with a human-readable label and a ready selector — when the user wants a specific part (pricing, footer, testimonials), find it there and call again with that selector. USE THIS whenever the user asks to rebuild, clone, port, or copy a section of a real website: it returns the actual code with true colors, fonts, spacing and copy, so you adapt real values instead of guessing from a screenshot. Note: it reads static HTML/CSS by default -
|
|
63
|
+
"Turn a section of a LIVE website into clean, paste-ready component code. Give it a URL and (optionally) a CSS selector; it resolves the page's real CSS cascade and returns a self-contained component in Tailwind, plain HTML+CSS, React (JSX) or Vue — plus the design tokens that section actually uses. The response also includes `sections`: every extractable section on the page with a human-readable label and a ready selector — when the user wants a specific part (pricing, footer, testimonials), find it there and call again with that selector. For jsx/vue, repeated structures (pricing tiers, testimonial cards, feature lists) are collapsed into a data array rendered with .map()/v-for - one template plus the data, like a human would write it. The section's ::before/::after decorations come back as real elements, dark-mode styles as dark: variants, and its @keyframes ship in the css field. USE THIS whenever the user asks to rebuild, clone, port, or copy a section of a real website: it returns the actual code with true colors, fonts, spacing and copy, so you adapt real values instead of guessing from a screenshot. Note: it reads static HTML/CSS by default - summary.styledCoverage (0-100) tells you how much styling resolved, and a client-rendered app that returns little includes a hint field saying to call again with render=true (+5 credits). Follow it.",
|
|
52
64
|
inputSchema: {
|
|
53
65
|
type: 'object',
|
|
54
66
|
properties: {
|
|
@@ -56,7 +68,7 @@ const TOOLS = [
|
|
|
56
68
|
selector: { type: 'string', description: 'CSS selector for the section to extract, e.g. "#hero" or ".pricing-card". Omit to auto-detect the hero.' },
|
|
57
69
|
framework: { type: 'string', enum: ['tailwind', 'html', 'jsx', 'vue'], description: 'The code to generate (default tailwind).' },
|
|
58
70
|
name: { type: 'string', description: 'Component name for the jsx/vue targets (default ExtractedSection).' },
|
|
59
|
-
render: RENDER_ARG
|
|
71
|
+
render: RENDER_ARG, fresh: FRESH_ARG, screenshot: SCREENSHOT_ARG
|
|
60
72
|
},
|
|
61
73
|
required: ['url']
|
|
62
74
|
}
|
|
@@ -69,7 +81,7 @@ const TOOLS = [
|
|
|
69
81
|
"Get a website's curated brand identity: color roles (primary, accent, background, text) read from the site's own CSS variables and logo — each as hex plus a human-readable name like 'Royal Blue' — dark/light theme detection, the brand palette, fonts split by role (primary/mono), logo, social image, the brand's social profiles (X, GitHub, LinkedIn, …), and a 0-1 confidence score for how much the site declared vs how much was inferred. Use this when you only need a site's STYLE (colors/fonts) rather than its code — to build new UI 'in the style of' a reference site. If you need the actual markup of a section, use extract_code instead.",
|
|
70
82
|
inputSchema: {
|
|
71
83
|
type: 'object',
|
|
72
|
-
properties: { url: { type: 'string', description: 'The website URL, e.g. stripe.com' }, render: RENDER_ARG },
|
|
84
|
+
properties: { url: { type: 'string', description: 'The website URL, e.g. stripe.com' }, render: RENDER_ARG, fresh: FRESH_ARG, screenshot: SCREENSHOT_ARG },
|
|
73
85
|
required: ['url']
|
|
74
86
|
}
|
|
75
87
|
},
|
|
@@ -78,13 +90,13 @@ const TOOLS = [
|
|
|
78
90
|
title: 'Extract design tokens',
|
|
79
91
|
endpoint: 'extract',
|
|
80
92
|
description:
|
|
81
|
-
"Extract the full design-token system of a URL: every color, font family, font size, border radius, box shadow, line height and z-index (with usage counts). Pass format='css' for a :root {} block
|
|
93
|
+
"Extract the full design-token system of a URL: every color, font family, font size, border radius, box shadow, line height and z-index (with usage counts). Pass format='css' for a :root {} block, format='tailwind' for a tailwind.config, or format='dtcg' for a standalone W3C Design Tokens file (drops into Style Dictionary / Figma variables pipelines). Use when you need the complete token set, not just the brand summary.",
|
|
82
94
|
inputSchema: {
|
|
83
95
|
type: 'object',
|
|
84
96
|
properties: {
|
|
85
97
|
url: { type: 'string', description: 'The website URL' },
|
|
86
|
-
format: { type: 'string', enum: ['json', 'css', 'tailwind'], description:
|
|
87
|
-
render: RENDER_ARG
|
|
98
|
+
format: { type: 'string', enum: ['json', 'css', 'tailwind', 'dtcg'], description: "Output shape (default json). 'dtcg' returns a W3C Design Tokens file." },
|
|
99
|
+
render: RENDER_ARG, fresh: FRESH_ARG, screenshot: SCREENSHOT_ARG
|
|
88
100
|
},
|
|
89
101
|
required: ['url']
|
|
90
102
|
}
|
|
@@ -97,7 +109,7 @@ const TOOLS = [
|
|
|
97
109
|
"List every image on a page (img, srcset, picture, CSS background, favicon, og:image) as resolved URLs tagged by source. Use to recover imagery from a site or pull reference assets. Best-effort from static HTML: if images are mounted by JavaScript, call again with render=true (+5 credits).",
|
|
98
110
|
inputSchema: {
|
|
99
111
|
type: 'object',
|
|
100
|
-
properties: { url: { type: 'string', description: 'The website URL' }, render: RENDER_ARG },
|
|
112
|
+
properties: { url: { type: 'string', description: 'The website URL' }, render: RENDER_ARG, fresh: FRESH_ARG, screenshot: SCREENSHOT_ARG },
|
|
101
113
|
required: ['url']
|
|
102
114
|
}
|
|
103
115
|
},
|
|
@@ -109,7 +121,7 @@ const TOOLS = [
|
|
|
109
121
|
"Extract inline SVGs (as paste-ready code) and SVG file references from a page. Use to grab icons and vector logos. Best-effort from static HTML: if icons are mounted by JavaScript, call again with render=true (+5 credits).",
|
|
110
122
|
inputSchema: {
|
|
111
123
|
type: 'object',
|
|
112
|
-
properties: { url: { type: 'string', description: 'The website URL' }, render: RENDER_ARG },
|
|
124
|
+
properties: { url: { type: 'string', description: 'The website URL' }, render: RENDER_ARG, fresh: FRESH_ARG, screenshot: SCREENSHOT_ARG },
|
|
113
125
|
required: ['url']
|
|
114
126
|
}
|
|
115
127
|
},
|
|
@@ -124,7 +136,7 @@ const TOOLS = [
|
|
|
124
136
|
properties: {
|
|
125
137
|
url: { type: 'string', description: 'The website URL' },
|
|
126
138
|
fields: { type: 'string', description: "Optional comma-separated fields to return (e.g. 'families')" },
|
|
127
|
-
render: RENDER_ARG
|
|
139
|
+
render: RENDER_ARG, fresh: FRESH_ARG, screenshot: SCREENSHOT_ARG
|
|
128
140
|
},
|
|
129
141
|
required: ['url']
|
|
130
142
|
}
|
|
@@ -137,7 +149,7 @@ const TOOLS = [
|
|
|
137
149
|
"Find Lottie/animation JSON files declared on a page. Best-effort from static HTML - most Lotties are runtime-injected, so pass render=true to execute the page JS first and catch those too (+5 credits). Use to recover animations.",
|
|
138
150
|
inputSchema: {
|
|
139
151
|
type: 'object',
|
|
140
|
-
properties: { url: { type: 'string', description: 'The website URL' }, render: RENDER_ARG },
|
|
152
|
+
properties: { url: { type: 'string', description: 'The website URL' }, render: RENDER_ARG, fresh: FRESH_ARG, screenshot: SCREENSHOT_ARG },
|
|
141
153
|
required: ['url']
|
|
142
154
|
}
|
|
143
155
|
},
|
|
@@ -149,7 +161,7 @@ const TOOLS = [
|
|
|
149
161
|
'List every video a page declares: <video>/<source> files, og:video, player embeds (YouTube, Vimeo, Wistia, Loom) and direct video-file links - each tagged by source, with a poster image when declared. Note `source: "embed"` is a player page, not a downloadable file. Best-effort from static HTML: most sites mount their player with JavaScript, so if the result is thin or empty, call again with render=true to execute the page JS first (+5 credits).',
|
|
150
162
|
inputSchema: {
|
|
151
163
|
type: 'object',
|
|
152
|
-
properties: { url: { type: 'string', description: 'The website URL' }, render: RENDER_ARG },
|
|
164
|
+
properties: { url: { type: 'string', description: 'The website URL' }, render: RENDER_ARG, fresh: FRESH_ARG, screenshot: SCREENSHOT_ARG },
|
|
153
165
|
required: ['url']
|
|
154
166
|
}
|
|
155
167
|
},
|
|
@@ -161,7 +173,7 @@ const TOOLS = [
|
|
|
161
173
|
'List every audio file a page declares: <audio>/<source> files, og:audio, and direct audio-file links such as podcast enclosures and download buttons - each tagged by source. Best-effort from static HTML: if a JavaScript player mounts the audio at runtime, call again with render=true (+5 credits).',
|
|
162
174
|
inputSchema: {
|
|
163
175
|
type: 'object',
|
|
164
|
-
properties: { url: { type: 'string', description: 'The website URL' }, render: RENDER_ARG },
|
|
176
|
+
properties: { url: { type: 'string', description: 'The website URL' }, render: RENDER_ARG, fresh: FRESH_ARG, screenshot: SCREENSHOT_ARG },
|
|
165
177
|
required: ['url']
|
|
166
178
|
}
|
|
167
179
|
}
|
|
@@ -169,7 +181,7 @@ const TOOLS = [
|
|
|
169
181
|
|
|
170
182
|
// Query params a tool may forward to the API, beyond `url`. Anything else in the
|
|
171
183
|
// tool arguments is ignored, so a hallucinated param can't reach the endpoint.
|
|
172
|
-
const FORWARDED_PARAMS = ['format', 'selector', 'framework', 'name', 'fields', 'render']
|
|
184
|
+
const FORWARDED_PARAMS = ['format', 'selector', 'framework', 'name', 'fields', 'render', 'fresh', 'screenshot']
|
|
173
185
|
|
|
174
186
|
async function callApi(endpoint, args) {
|
|
175
187
|
const q = new URLSearchParams({ url: args.url })
|
|
@@ -192,7 +204,7 @@ async function callApi(endpoint, args) {
|
|
|
192
204
|
}
|
|
193
205
|
|
|
194
206
|
const server = new Server(
|
|
195
|
-
{ name: 'miromiro', version: '0.
|
|
207
|
+
{ name: 'miromiro', version: '0.4.0' },
|
|
196
208
|
{ capabilities: { tools: {} } }
|
|
197
209
|
)
|
|
198
210
|
|