@neuctra/ui-mcp 0.4.5 → 0.4.7
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 +116 -312
- package/data/design-rules.json +337 -0
- package/data/layouts.json +3249 -765
- package/data/seo-guide.json +367 -0
- package/package.json +3 -3
- package/src/load-data.mjs +2 -2
- package/src/tools/get-design-rules/index.mjs +46 -24
- package/src/tools/neuctra-ui-page-builder/index.mjs +25 -14
- package/src/tools/neuctra-ui-seo-setup/index.mjs +59 -20
- package/data/aiDesignRules.json +0 -325
- package/data/seoGuide.json +0 -180
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "SEO Agent Rules",
|
|
3
|
+
"role": "Autonomous SEO engineer for source code, CMS, APIs, and authorized browser tools. Handles technical SEO, on-page SEO, off-page SEO, local SEO, GEO, and AEO.",
|
|
4
|
+
|
|
5
|
+
"workflow": [
|
|
6
|
+
"Inspect architecture, routes, templates, rendering, metadata, content, indexability, performance, and available tools.",
|
|
7
|
+
"Identify website type, business goals, audience, target market, and search intent.",
|
|
8
|
+
"Audit applicable rules using evidence, not assumptions.",
|
|
9
|
+
"Prioritize critical technical issues, indexability, content quality, user experience, and relevant authority opportunities.",
|
|
10
|
+
"Implement minimal changes using existing architecture, dependencies, and conventions.",
|
|
11
|
+
"Validate changes using rendered pages, HTTP responses, tests, builds, and available SEO tools.",
|
|
12
|
+
"Report findings, changes, verification results, unresolved issues, and limitations."
|
|
13
|
+
],
|
|
14
|
+
|
|
15
|
+
"mode": {
|
|
16
|
+
"default": "read_only_audit",
|
|
17
|
+
"require_authorization": [
|
|
18
|
+
"Destructive changes or bulk deletion",
|
|
19
|
+
"Major URL migrations",
|
|
20
|
+
"Production deployment",
|
|
21
|
+
"External outreach or publishing",
|
|
22
|
+
"Paid links or marketing expenditure"
|
|
23
|
+
]
|
|
24
|
+
},
|
|
25
|
+
|
|
26
|
+
"on_page_checklist": [
|
|
27
|
+
{
|
|
28
|
+
"id": 1,
|
|
29
|
+
"name": "Keywords and Search Intent",
|
|
30
|
+
"rules": [
|
|
31
|
+
"Identify the primary topic, target keywords, related terms, entities, search intent, and relevant user prompts using available evidence.",
|
|
32
|
+
"Use the primary topic naturally in the title, H1, introduction, URL slug, and relevant subheadings where appropriate.",
|
|
33
|
+
"Avoid keyword stuffing, arbitrary keyword density, forced exact matches, and keyword cannibalization.",
|
|
34
|
+
"Create pages for distinct user needs, not minor keyword variations."
|
|
35
|
+
]
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"id": 2,
|
|
39
|
+
"name": "Title Tags",
|
|
40
|
+
"rules": [
|
|
41
|
+
"Give each indexable page a unique, descriptive title that accurately reflects its content.",
|
|
42
|
+
"Place the primary topic prominently when natural and useful.",
|
|
43
|
+
"Keep titles concise; approximately 50–60 characters is a guideline, not a strict limit.",
|
|
44
|
+
"Align the title with the page purpose and visible H1.",
|
|
45
|
+
"Avoid misleading claims, repetitive templates, and keyword stuffing."
|
|
46
|
+
]
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
"id": 3,
|
|
50
|
+
"name": "URL Slugs",
|
|
51
|
+
"rules": [
|
|
52
|
+
"Use readable, descriptive, concise, and stable URLs with hyphens where appropriate.",
|
|
53
|
+
"Avoid unnecessary parameters, meaningless identifiers, and excessive URL depth.",
|
|
54
|
+
"Do not change established URLs solely to add keywords.",
|
|
55
|
+
"For necessary URL changes, map old URLs to relevant destinations and implement appropriate permanent redirects."
|
|
56
|
+
]
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"id": 4,
|
|
60
|
+
"name": "Meta Descriptions",
|
|
61
|
+
"rules": [
|
|
62
|
+
"Write unique, accurate, compelling summaries for important pages when useful.",
|
|
63
|
+
"Explain the page's value and match its likely search intent.",
|
|
64
|
+
"Include the target topic naturally when relevant.",
|
|
65
|
+
"Approximately 105–160 characters may be a useful drafting range, not a fixed requirement.",
|
|
66
|
+
"Meta descriptions are not a direct ranking factor, and search engines may generate different snippets."
|
|
67
|
+
]
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"id": 5,
|
|
71
|
+
"name": "Headings and Structure",
|
|
72
|
+
"rules": [
|
|
73
|
+
"Use a clear main heading and a logical hierarchy of descriptive H2, H3, and deeper headings.",
|
|
74
|
+
"Use semantic HTML and paragraphs, lists, tables, or steps where useful.",
|
|
75
|
+
"Make headings informative rather than keyword containers.",
|
|
76
|
+
"Answer the heading directly when appropriate and make sections understandable in context."
|
|
77
|
+
]
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
"id": 6,
|
|
81
|
+
"name": "Helpful, Original Content",
|
|
82
|
+
"rules": [
|
|
83
|
+
"Answer the user's main question clearly and early, then provide sufficient useful detail.",
|
|
84
|
+
"Match search intent and demonstrate relevant expertise with evidence, examples, and practical guidance.",
|
|
85
|
+
"Verify factual claims and cite trustworthy sources when needed.",
|
|
86
|
+
"Update outdated facts, broken links, and obsolete instructions when meaningful.",
|
|
87
|
+
"Avoid copied, thin, misleading, repetitive, or mass-produced content designed primarily to manipulate rankings.",
|
|
88
|
+
"Never invent credentials, reviews, statistics, sources, or first-hand experience."
|
|
89
|
+
]
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
"id": 7,
|
|
93
|
+
"name": "Internal Links",
|
|
94
|
+
"rules": [
|
|
95
|
+
"Link relevant pages using descriptive, natural anchor text.",
|
|
96
|
+
"Ensure important pages are discoverable through crawlable links.",
|
|
97
|
+
"Review broken links, orphan pages, redirecting links, and unnecessary click depth.",
|
|
98
|
+
"Avoid excessive linking and repetitive exact-match anchors."
|
|
99
|
+
]
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
"id": 8,
|
|
103
|
+
"name": "External Links and Citations",
|
|
104
|
+
"rules": [
|
|
105
|
+
"Link to relevant, trustworthy sources when they support claims or help readers.",
|
|
106
|
+
"Use accurate, descriptive anchor text and verify important citations.",
|
|
107
|
+
"Do not add links merely to simulate authority or meet arbitrary link counts.",
|
|
108
|
+
"Use rel=\"sponsored\" for paid links and rel=\"ugc\" for applicable user-generated links; use nofollow where appropriate."
|
|
109
|
+
]
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
"id": 9,
|
|
113
|
+
"name": "Images and Alt Text",
|
|
114
|
+
"rules": [
|
|
115
|
+
"Use descriptive filenames and meaningful alt text that communicates an image's relevant content or function.",
|
|
116
|
+
"Use empty alt text for purely decorative images.",
|
|
117
|
+
"Avoid keyword stuffing and unnecessary phrases such as 'image of'.",
|
|
118
|
+
"Use suitable dimensions, responsive images, modern formats, and compression while preserving quality.",
|
|
119
|
+
"Ensure loading behavior supports accessibility and does not unnecessarily delay the main content."
|
|
120
|
+
]
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
"id": 10,
|
|
124
|
+
"name": "Page Speed and User Experience",
|
|
125
|
+
"rules": [
|
|
126
|
+
"Measure performance before changing code; use field data when available and laboratory tests for diagnosis.",
|
|
127
|
+
"Optimize critical images, fonts, JavaScript execution, caching, server responses, and layout stability where relevant.",
|
|
128
|
+
"Use lazy loading appropriately; do not lazy-load the primary above-the-fold image when it delays discovery or loading.",
|
|
129
|
+
"Assess Core Web Vitals: LCP <= 2.5 seconds, INP <= 200 milliseconds, and CLS <= 0.1, measured at the 75th percentile where applicable.",
|
|
130
|
+
"Preserve functionality, accessibility, analytics, security, and content.",
|
|
131
|
+
"Do not equate a laboratory score with real-user performance."
|
|
132
|
+
]
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
"id": 11,
|
|
136
|
+
"name": "Schema Markup",
|
|
137
|
+
"rules": [
|
|
138
|
+
"Implement relevant, supported structured data that accurately represents visible page content.",
|
|
139
|
+
"Choose appropriate schema types, such as Article, Product, Organization, or LocalBusiness, when applicable.",
|
|
140
|
+
"Validate JSON-LD syntax, required properties, and eligibility using relevant testing tools.",
|
|
141
|
+
"Never fabricate prices, ratings, reviews, availability, or business details.",
|
|
142
|
+
"Do not promise rich results, rankings, indexing, or AI citations."
|
|
143
|
+
]
|
|
144
|
+
}
|
|
145
|
+
],
|
|
146
|
+
|
|
147
|
+
"technical_seo": {
|
|
148
|
+
"crawlability_indexability": [
|
|
149
|
+
"Verify HTTP status codes, robots.txt, robots meta directives, canonicals, redirects, internal links, and sitemap consistency.",
|
|
150
|
+
"Ensure important public pages render correctly and are indexable when intended.",
|
|
151
|
+
"Do not block crawling when crawlers need to read a noindex directive.",
|
|
152
|
+
"Protect private content through authentication and authorization, not robots.txt.",
|
|
153
|
+
"Prevent accidental indexing of staging environments and confidential pages."
|
|
154
|
+
],
|
|
155
|
+
"http_status": {
|
|
156
|
+
"rule": "Use 200 for successful responses, 301 or 308 for permanent redirects, 302 or 307 for temporary redirects, 404 for resources not found, and 410 when a resource has been permanently removed and that status is appropriate. Choose status codes according to the resource state and migration intent. Do not redirect unrelated missing URLs to the homepage."
|
|
157
|
+
},
|
|
158
|
+
"sitemaps_canonicals": [
|
|
159
|
+
"Include canonical, indexable URLs in XML sitemaps.",
|
|
160
|
+
"Exclude errors, redirects, and intentionally excluded pages.",
|
|
161
|
+
"Keep canonical tags, internal links, redirects, and sitemap URLs consistent.",
|
|
162
|
+
"Investigate duplicate URLs and consolidate only when appropriate."
|
|
163
|
+
],
|
|
164
|
+
"javascript_mobile_international": [
|
|
165
|
+
"Test rendering, hydration, direct navigation, missing routes, and API failures.",
|
|
166
|
+
"Ensure essential content, metadata, and crawlable links are available to supported crawlers.",
|
|
167
|
+
"Maintain HTTPS, mobile usability, and accessible interactions.",
|
|
168
|
+
"Configure hreflang and regional targeting correctly when applicable."
|
|
169
|
+
]
|
|
170
|
+
},
|
|
171
|
+
|
|
172
|
+
"off_page_seo": [
|
|
173
|
+
"Earn relevant editorial links through useful resources, original research, legitimate partnerships, and digital PR.",
|
|
174
|
+
"Evaluate relevance, editorial context, audience value, and source quality rather than relying solely on domain metrics.",
|
|
175
|
+
"Avoid paid ranking-credit links, link schemes, private networks, automated spam, and manipulative reciprocal linking.",
|
|
176
|
+
"Ensure guest posts provide original value and are not produced at scale primarily to manipulate rankings.",
|
|
177
|
+
"Keep brand mentions and PR claims accurate; request corrections or attribution when useful.",
|
|
178
|
+
"Disclose sponsorships and qualify paid placements appropriately.",
|
|
179
|
+
"Use social media for discovery, engagement, referrals, and brand awareness without assuming social metrics directly improve rankings.",
|
|
180
|
+
"Never guarantee backlinks, coverage, or ranking increases."
|
|
181
|
+
],
|
|
182
|
+
|
|
183
|
+
"local_seo": [
|
|
184
|
+
"Apply local SEO only when a business serves a meaningful local market.",
|
|
185
|
+
"Keep public business names, addresses, phone numbers, hours, and other details accurate.",
|
|
186
|
+
"Maintain eligible business profiles and relevant listings.",
|
|
187
|
+
"Use authentic, policy-compliant reviews; never fabricate, buy, or manipulate reviews.",
|
|
188
|
+
"Create location pages only when each serves a distinct audience with useful, accurate information.",
|
|
189
|
+
"Use accurate local business schema when applicable; avoid fake locations and keyword-stuffed business names."
|
|
190
|
+
],
|
|
191
|
+
|
|
192
|
+
"geo_checklist": [
|
|
193
|
+
{
|
|
194
|
+
"id": 1,
|
|
195
|
+
"name": "AI Crawler Access and Rendering",
|
|
196
|
+
"checks": [
|
|
197
|
+
"Verify relevant AI search crawlers can access intended public pages under the site's robots.txt and access policies.",
|
|
198
|
+
"Check HTTP responses, rendered HTML, JavaScript dependencies, and essential content availability.",
|
|
199
|
+
"Ensure important content is not unintentionally blocked, hidden, or dependent on user interaction."
|
|
200
|
+
]
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
"id": 2,
|
|
204
|
+
"name": "AI-Readable Content",
|
|
205
|
+
"checks": [
|
|
206
|
+
"Ensure important content communicates its subject clearly and provides sufficient context when extracted.",
|
|
207
|
+
"Use clear headings and structured content where they improve understanding.",
|
|
208
|
+
"Preserve essential qualifications, definitions, and relationships so extracted passages are not misleading."
|
|
209
|
+
]
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
"id": 3,
|
|
213
|
+
"name": "Brand Authority and Accuracy",
|
|
214
|
+
"checks": [
|
|
215
|
+
"Review relevant third-party websites and publications for accurate brand representation.",
|
|
216
|
+
"Build genuine authority through expertise, useful resources, original research, legitimate partnerships, and editorial coverage.",
|
|
217
|
+
"Keep important brand and organization information accurate across relevant sources.",
|
|
218
|
+
"Treat unlinked mentions as potential visibility signals, not guaranteed ranking factors.",
|
|
219
|
+
"Avoid fabricated mentions, manipulative link schemes, and deceptive endorsements."
|
|
220
|
+
]
|
|
221
|
+
},
|
|
222
|
+
{
|
|
223
|
+
"id": 4,
|
|
224
|
+
"name": "Community and Third-Party Presence",
|
|
225
|
+
"checks": [
|
|
226
|
+
"Identify relevant industry publications, communities, review platforms, and user-generated content sources.",
|
|
227
|
+
"Participate genuinely where the audience is active and follow platform policies.",
|
|
228
|
+
"Disclose sponsorships where required.",
|
|
229
|
+
"Do not fabricate reviews or manipulate discussions; no single platform, including Wikipedia, is mandatory for every business."
|
|
230
|
+
]
|
|
231
|
+
},
|
|
232
|
+
{
|
|
233
|
+
"id": 5,
|
|
234
|
+
"name": "AI Search Visibility Measurement",
|
|
235
|
+
"checks": [
|
|
236
|
+
"Track brand mentions, citations, cited URLs, sentiment, and share of voice where reliable data is available.",
|
|
237
|
+
"Test representative user prompts across relevant AI search platforms.",
|
|
238
|
+
"Compare results over time alongside organic visibility, traffic, and conversions.",
|
|
239
|
+
"Record the platform, prompt, date, and evidence; treat results as variable rather than guaranteed."
|
|
240
|
+
]
|
|
241
|
+
}
|
|
242
|
+
],
|
|
243
|
+
|
|
244
|
+
"aeo_checklist": [
|
|
245
|
+
{
|
|
246
|
+
"id": 1,
|
|
247
|
+
"name": "Question and Prompt Research",
|
|
248
|
+
"checks": [
|
|
249
|
+
"Identify real questions, conversational queries, and user prompts related to the website's topics, products, services, and audience needs.",
|
|
250
|
+
"Use keyword research, search suggestions, People Also Ask, customer questions, relevant communities, and available AI prompt research tools.",
|
|
251
|
+
"Prioritize questions by user intent, business relevance, audience needs, and available evidence.",
|
|
252
|
+
"Avoid creating separate pages for minor question variations when one useful page can answer them."
|
|
253
|
+
]
|
|
254
|
+
},
|
|
255
|
+
{
|
|
256
|
+
"id": 2,
|
|
257
|
+
"name": "Direct and Extractable Answers",
|
|
258
|
+
"checks": [
|
|
259
|
+
"Answer the main question clearly near the beginning of the relevant section.",
|
|
260
|
+
"Use the question or a natural variation as a descriptive H2 or H3 when appropriate.",
|
|
261
|
+
"Follow the direct answer with supporting explanations, steps, examples, limitations, or evidence.",
|
|
262
|
+
"Keep answers understandable when extracted from the page while preserving necessary context and qualifications.",
|
|
263
|
+
"Use structured data only when relevant and accurate; it does not guarantee AI citations or answer inclusion."
|
|
264
|
+
]
|
|
265
|
+
},
|
|
266
|
+
{
|
|
267
|
+
"id": 3,
|
|
268
|
+
"name": "Expertise and Evidence",
|
|
269
|
+
"checks": [
|
|
270
|
+
"Demonstrate relevant first-hand experience, practical expertise, or original research when genuinely available.",
|
|
271
|
+
"Support important factual claims with trustworthy sources, verified data, relevant quotations, or documented examples.",
|
|
272
|
+
"Provide accurate author biographies and organizational credentials where they help establish accountability.",
|
|
273
|
+
"Use surveys, experiments, case studies, and expert interviews only when genuinely conducted and accurately represented.",
|
|
274
|
+
"Never fabricate personal experience, expert endorsements, research findings, credentials, statistics, or citations."
|
|
275
|
+
]
|
|
276
|
+
},
|
|
277
|
+
{
|
|
278
|
+
"id": 4,
|
|
279
|
+
"name": "Content Freshness and Attribution",
|
|
280
|
+
"checks": [
|
|
281
|
+
"Update statistics, examples, product information, recommendations, and instructions when they materially change.",
|
|
282
|
+
"Display publication or modification dates when useful and accurate.",
|
|
283
|
+
"Maintain datePublished and dateModified structured data when applicable and consistent with the visible page.",
|
|
284
|
+
"Preserve useful, accurate content instead of changing dates or making superficial edits solely to appear fresh.",
|
|
285
|
+
"Do not assume a particular update frequency or timestamp guarantees AI citation."
|
|
286
|
+
]
|
|
287
|
+
},
|
|
288
|
+
{
|
|
289
|
+
"id": 5,
|
|
290
|
+
"name": "AEO Visibility and Performance Measurement",
|
|
291
|
+
"checks": [
|
|
292
|
+
"Test representative audience questions across relevant AI answer platforms and record whether the brand, page, or product appears.",
|
|
293
|
+
"Track available brand mentions, citations, cited URLs, answer accuracy, competitor presence, and share of voice.",
|
|
294
|
+
"Monitor branded search queries, impressions, organic traffic, referral traffic, and conversions using available analytics and search reporting tools.",
|
|
295
|
+
"Record the platform, prompt, date, response, cited sources, and testing method so results can be compared consistently.",
|
|
296
|
+
"Investigate gaps between traditional search visibility and AI answer visibility.",
|
|
297
|
+
"Treat manual prompt tests and third-party visibility estimates as snapshots that may vary by platform, query, location, and time.",
|
|
298
|
+
"Never claim AEO success based on unverified citations, assumed AI traffic, or guaranteed inclusion in generated answers."
|
|
299
|
+
]
|
|
300
|
+
}
|
|
301
|
+
],
|
|
302
|
+
|
|
303
|
+
"safe_implementation": [
|
|
304
|
+
"Inspect existing code, CMS fields, configuration, architecture, and conventions before editing.",
|
|
305
|
+
"Reuse existing utilities and dependencies; avoid unrelated refactoring.",
|
|
306
|
+
"Preserve business logic, authentication, analytics, accessibility, security, and user experience.",
|
|
307
|
+
"Use verified data and approved sources; never invent business details, locations, offers, reviews, or credentials.",
|
|
308
|
+
"Review risky changes and establish a rollback path.",
|
|
309
|
+
"Never expose secrets or sensitive data.",
|
|
310
|
+
"Do not publish, contact third parties, purchase placements, or deploy without required authorization.",
|
|
311
|
+
"Treat SEO practices as context-dependent, not mandatory for every page."
|
|
312
|
+
],
|
|
313
|
+
|
|
314
|
+
"validation": {
|
|
315
|
+
"checks": [
|
|
316
|
+
"Run the 11-item on-page checklist where applicable.",
|
|
317
|
+
"Run the 5-item GEO checklist where applicable.",
|
|
318
|
+
"Run the 5-item AEO checklist where applicable.",
|
|
319
|
+
"Verify rendered content, metadata, HTTP status codes, redirects, and crawlable links.",
|
|
320
|
+
"Check robots directives, canonical tags, sitemap consistency, and intended indexability.",
|
|
321
|
+
"Validate structured data when present.",
|
|
322
|
+
"Test mobile functionality and relevant performance metrics.",
|
|
323
|
+
"Run available tests, linting, and production builds when code changes are made.",
|
|
324
|
+
"Review applicable off-page and local SEO requirements.",
|
|
325
|
+
"Mark unavailable or untested checks as unverified; never claim a check passed without evidence."
|
|
326
|
+
],
|
|
327
|
+
"tools": [
|
|
328
|
+
"Google Search Console",
|
|
329
|
+
"Google Analytics",
|
|
330
|
+
"PageSpeed Insights",
|
|
331
|
+
"Lighthouse",
|
|
332
|
+
"Website crawlers",
|
|
333
|
+
"Rich Results Test",
|
|
334
|
+
"Schema Markup Validator",
|
|
335
|
+
"Google Business Profile reporting"
|
|
336
|
+
],
|
|
337
|
+
"missing_evidence": "Mark unavailable checks as unverified. Never invent measurements, rankings, traffic, backlinks, citations, or test results."
|
|
338
|
+
},
|
|
339
|
+
|
|
340
|
+
"reporting": {
|
|
341
|
+
"fields": [
|
|
342
|
+
"Issue and supporting evidence",
|
|
343
|
+
"Category and priority",
|
|
344
|
+
"Affected URL, file, or CMS field",
|
|
345
|
+
"Recommended or completed action",
|
|
346
|
+
"Reason and expected user benefit",
|
|
347
|
+
"Actual verification result",
|
|
348
|
+
"Unresolved issues and limitations"
|
|
349
|
+
],
|
|
350
|
+
"rules": [
|
|
351
|
+
"Prioritize by impact, confidence, and implementation effort.",
|
|
352
|
+
"Separate audit findings, implemented changes, and independently verified outcomes.",
|
|
353
|
+
"Explain when a recommendation is optional, inapplicable, or carries policy risks."
|
|
354
|
+
]
|
|
355
|
+
},
|
|
356
|
+
|
|
357
|
+
"references": [
|
|
358
|
+
"https://developers.google.com/search/docs/fundamentals/seo-starter-guide",
|
|
359
|
+
"https://developers.google.com/search/docs/essentials",
|
|
360
|
+
"https://developers.google.com/search/docs/crawling-indexing/",
|
|
361
|
+
"https://developers.google.com/search/docs/appearance/structured-data/",
|
|
362
|
+
"https://developers.google.com/search/docs/essentials/spam-policies",
|
|
363
|
+
"https://web.dev/articles/vitals"
|
|
364
|
+
],
|
|
365
|
+
|
|
366
|
+
"principle": "Inspect -> Audit -> Prioritize -> Implement -> Validate -> Report. Follow evidence, website architecture, business goals, and user needs. Never prioritize ranking manipulation over useful content, accessibility, safety, or compliance."
|
|
367
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@neuctra/ui-mcp",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.7",
|
|
4
4
|
"description": "MCP server exposing the @neuctra/ui component registry (props, defaults, examples, theme tokens) so AI coding tools generate accurate Neuctra UI code, plus SEO/AEO/GEO tools (per-page meta, woven JSON-LD, audits).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -30,8 +30,8 @@
|
|
|
30
30
|
".": "./src/server.mjs",
|
|
31
31
|
"./data/components.json": "./data/components.json",
|
|
32
32
|
"./data/theme.json": "./data/theme.json",
|
|
33
|
-
"./data/
|
|
34
|
-
"./data/
|
|
33
|
+
"./data/design-rules.json": "./data/design-rules.json",
|
|
34
|
+
"./data/seo-guide.json": "./data/seo-guide.json",
|
|
35
35
|
"./package.json": "./package.json"
|
|
36
36
|
},
|
|
37
37
|
"files": [
|
package/src/load-data.mjs
CHANGED
|
@@ -13,8 +13,8 @@ export function loadDataFromDisk() {
|
|
|
13
13
|
return {
|
|
14
14
|
registry: readJson("components.json"),
|
|
15
15
|
theme: readJson("theme.json"),
|
|
16
|
-
aiDesignRules: readJson("
|
|
17
|
-
seoGuide: readJson("
|
|
16
|
+
aiDesignRules: readJson("design-rules.json"),
|
|
17
|
+
seoGuide: readJson("seo-guide.json"),
|
|
18
18
|
layouts: readJson("layouts.json"),
|
|
19
19
|
};
|
|
20
20
|
}
|
|
@@ -1,21 +1,45 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
const BLOCK_NAMES = [
|
|
4
|
+
"core",
|
|
5
|
+
"layout",
|
|
6
|
+
"components",
|
|
7
|
+
"accessibilityInteraction",
|
|
8
|
+
"modernDesign",
|
|
9
|
+
"antiAiDesignRules",
|
|
10
|
+
];
|
|
11
|
+
|
|
12
|
+
function makeProductDesignRules(aiDesignRules, blockNames, sectionNumbers) {
|
|
13
|
+
const selected = sectionNumbers ? new Set(sectionNumbers) : null;
|
|
14
|
+
return Object.fromEntries(
|
|
15
|
+
blockNames
|
|
16
|
+
.filter((name) => name !== "antiAiDesignRules")
|
|
17
|
+
.map((name) => [
|
|
18
|
+
name,
|
|
19
|
+
(aiDesignRules.blocks?.[name] ?? []).filter((section) => !selected || selected.has(section.number)),
|
|
20
|
+
])
|
|
21
|
+
.filter(([, sections]) => sections.length),
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function getDesignRulesContext(theme, aiDesignRules, sectionNumbers, requestedBlocks) {
|
|
4
26
|
const { rules, antiAiLookRules } = theme;
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
27
|
+
const availableBlocks = aiDesignRules.blocks ?? {};
|
|
28
|
+
const requested = requestedBlocks?.length
|
|
29
|
+
? requestedBlocks
|
|
30
|
+
: sectionNumbers
|
|
31
|
+
? BLOCK_NAMES.filter((name) => name === "antiAiDesignRules" || (availableBlocks[name] ?? []).some((section) => sectionNumbers.includes(section.number)))
|
|
32
|
+
: ["core", "antiAiDesignRules"];
|
|
33
|
+
const blockNames = [...new Set(requested)];
|
|
8
34
|
|
|
9
|
-
const selected = new Set(sectionNumbers);
|
|
10
35
|
return {
|
|
11
36
|
stylingRules: rules,
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
intro: aiDesignRules.intro,
|
|
16
|
-
sections: aiDesignRules.sections.filter((section) => selected.has(section.number)),
|
|
17
|
-
goldenRule: aiDesignRules.goldenRule,
|
|
37
|
+
antiAiDesignRules: {
|
|
38
|
+
...(availableBlocks.antiAiDesignRules?.length && { productDesign: availableBlocks.antiAiDesignRules }),
|
|
39
|
+
theme: antiAiLookRules,
|
|
18
40
|
},
|
|
41
|
+
productDesignRules: makeProductDesignRules(aiDesignRules, blockNames, sectionNumbers),
|
|
42
|
+
...(aiDesignRules.goldenRule && { goldenRule: aiDesignRules.goldenRule }),
|
|
19
43
|
};
|
|
20
44
|
}
|
|
21
45
|
|
|
@@ -25,18 +49,16 @@ export function registerGetDesignRulesTool(server, { theme, aiDesignRules }) {
|
|
|
25
49
|
{
|
|
26
50
|
title: "Get Neuctra UI design rules",
|
|
27
51
|
description:
|
|
28
|
-
"
|
|
29
|
-
inputSchema: {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
return {
|
|
33
|
-
content: [
|
|
34
|
-
{
|
|
35
|
-
type: "text",
|
|
36
|
-
text: JSON.stringify(getDesignRulesContext(theme, aiDesignRules), null, 2),
|
|
37
|
-
},
|
|
38
|
-
],
|
|
39
|
-
};
|
|
52
|
+
"Return structured Neuctra UI design guidance in focused blocks: core, layout, components, accessibilityInteraction, modernDesign, and antiAiDesignRules. By default returns core guidance and anti-AI rules; request additional blocks when needed. The page builder supplies only the sections relevant to its selected layout.",
|
|
53
|
+
inputSchema: {
|
|
54
|
+
blocks: z.array(z.enum(BLOCK_NAMES)).optional().describe("Named design rule blocks to return. Defaults to core and antiAiDesignRules."),
|
|
55
|
+
},
|
|
40
56
|
},
|
|
41
|
-
|
|
57
|
+
async ({ blocks }) => ({
|
|
58
|
+
content: [{
|
|
59
|
+
type: "text",
|
|
60
|
+
text: JSON.stringify(getDesignRulesContext(theme, aiDesignRules, undefined, blocks), null, 2),
|
|
61
|
+
}],
|
|
62
|
+
}),
|
|
63
|
+
);
|
|
42
64
|
}
|
|
@@ -4,35 +4,45 @@ import { findNeuctraUiComponents } from "../get-neuctra-ui-component/index.mjs";
|
|
|
4
4
|
import { getDesignRulesContext } from "../get-design-rules/index.mjs";
|
|
5
5
|
import { buildSeoGuideContext } from "../neuctra-ui-seo-setup/index.mjs";
|
|
6
6
|
|
|
7
|
+
function getLayouts(layoutData) {
|
|
8
|
+
const grouped = (layoutData?.layoutGroups ?? []).flatMap((group) =>
|
|
9
|
+
(group.layouts ?? []).map((layout) => ({ ...layout, category: layout.category ?? group.id, categoryName: group.name })),
|
|
10
|
+
);
|
|
11
|
+
const legacy = layoutData?.layouts ?? [];
|
|
12
|
+
return [...grouped, ...legacy];
|
|
13
|
+
}
|
|
14
|
+
|
|
7
15
|
function resolveLayout(request, requestedType, layoutData) {
|
|
8
|
-
const layouts = layoutData
|
|
16
|
+
const layouts = getLayouts(layoutData);
|
|
9
17
|
if (requestedType !== "auto") {
|
|
10
18
|
const explicit = layouts.find((layout) => layout.id === requestedType);
|
|
11
19
|
if (explicit) return { layout: explicit, confidence: 1, evidence: [`Explicit page type: ${requestedType}`] };
|
|
12
20
|
}
|
|
13
21
|
|
|
14
|
-
const normalized = request.toLowerCase();
|
|
22
|
+
const normalized = request.toLowerCase().replace(/[^a-z0-9]+/g, " ").trim();
|
|
15
23
|
const scored = layouts
|
|
16
24
|
.filter((layout) => layout.id !== "custom")
|
|
17
25
|
.map((layout) => {
|
|
18
26
|
let score = 0;
|
|
19
27
|
const evidence = [];
|
|
20
28
|
for (const alias of layout.aliases ?? []) {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
29
|
+
const phrase = alias.toLowerCase().replace(/[^a-z0-9]+/g, " ").trim();
|
|
30
|
+
if (phrase && (` ${normalized} `).includes(` ${phrase} `)) {
|
|
31
|
+
const weight = 5 + Math.min(phrase.split(" ").length, 4) * 2;
|
|
32
|
+
score += weight;
|
|
33
|
+
evidence.push(`layout phrase: ${alias}`);
|
|
24
34
|
}
|
|
25
35
|
}
|
|
26
36
|
for (const keyword of layout.keywords ?? []) {
|
|
27
|
-
const
|
|
28
|
-
if (
|
|
29
|
-
score +=
|
|
30
|
-
evidence.push(keyword);
|
|
37
|
+
const term = keyword.toLowerCase().replace(/[^a-z0-9]+/g, " ").trim();
|
|
38
|
+
if (term && (` ${normalized} `).includes(` ${term} `)) {
|
|
39
|
+
score += 2;
|
|
40
|
+
evidence.push(`topic: ${keyword}`);
|
|
31
41
|
}
|
|
32
42
|
}
|
|
33
|
-
return { layout, score, evidence };
|
|
43
|
+
return { layout, score, evidence, specificity: Math.max(...(layout.aliases ?? []).map((alias) => alias.split(/\s+/).length), 0) };
|
|
34
44
|
})
|
|
35
|
-
.sort((a, b) => b.score - a.score);
|
|
45
|
+
.sort((a, b) => b.score - a.score || b.specificity - a.specificity);
|
|
36
46
|
|
|
37
47
|
const best = scored[0];
|
|
38
48
|
const custom = layouts.find((layout) => layout.id === "custom") ?? layouts[0];
|
|
@@ -71,7 +81,7 @@ function getComponentGuidance(registry, request, layout) {
|
|
|
71
81
|
}
|
|
72
82
|
|
|
73
83
|
export function registerNeuctraUiPageBuilderTool(server, data) {
|
|
74
|
-
const layouts = data.layouts
|
|
84
|
+
const layouts = getLayouts(data.layouts);
|
|
75
85
|
const pageTypeOptions = ["auto", ...layouts.map((layout) => layout.id)];
|
|
76
86
|
|
|
77
87
|
server.registerTool(
|
|
@@ -79,10 +89,10 @@ export function registerNeuctraUiPageBuilderTool(server, data) {
|
|
|
79
89
|
{
|
|
80
90
|
title: "Analyze and plan a Neuctra UI page",
|
|
81
91
|
description:
|
|
82
|
-
"Analyze a page request
|
|
92
|
+
"Analyze a page request and choose from every layout in the grouped real-world catalog in data/layouts.json, including marketing, SaaS dashboards, commerce, publishing, support, portfolios, communities, events, and system pages. Use pageType=auto to select the closest specific layout from the request, or choose an explicit pageType. Returns the selected recipe, matching @neuctra/ui component specs, relevant design rules, and SEO guidance.",
|
|
83
93
|
inputSchema: {
|
|
84
94
|
request: z.string().min(8).describe("Describe the page to create and the main user task."),
|
|
85
|
-
pageType: z.enum(pageTypeOptions).default("auto").describe("
|
|
95
|
+
pageType: z.enum(pageTypeOptions).default("auto").describe(`Layout ID from the full catalog (${layouts.map((layout) => layout.id).join(", ")}) or auto to infer the best match from the request.`),
|
|
86
96
|
framework: z.enum(["auto", ...FRAMEWORKS, "remix"]).default("auto").describe("Framework and router for framework-specific SEO implementation guidance."),
|
|
87
97
|
preferences: z.object({
|
|
88
98
|
visualDirection: z.string().optional(),
|
|
@@ -116,6 +126,7 @@ export function registerNeuctraUiPageBuilderTool(server, data) {
|
|
|
116
126
|
request,
|
|
117
127
|
inferredPageType: layout.id,
|
|
118
128
|
layoutName: layout.name,
|
|
129
|
+
layoutCategory: layout.categoryName ?? layout.category ?? "general",
|
|
119
130
|
confidence,
|
|
120
131
|
evidence,
|
|
121
132
|
detectedTaskSignals: signals,
|