user-majico-mcp 0.7.5

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 (66) hide show
  1. package/README.md +144 -0
  2. package/dist/agent-bootstrap.d.ts +8 -0
  3. package/dist/agent-bootstrap.js +21 -0
  4. package/dist/auth-prompt.d.ts +13 -0
  5. package/dist/auth-prompt.js +15 -0
  6. package/dist/client-disconnect.d.ts +4 -0
  7. package/dist/client-disconnect.js +17 -0
  8. package/dist/credentials.d.ts +40 -0
  9. package/dist/credentials.js +60 -0
  10. package/dist/http-handler.d.ts +6 -0
  11. package/dist/http-handler.js +28 -0
  12. package/dist/index.d.ts +12 -0
  13. package/dist/index.js +22 -0
  14. package/dist/present-interactive.d.ts +92 -0
  15. package/dist/present-interactive.js +479 -0
  16. package/dist/present-types.d.ts +17 -0
  17. package/dist/present-types.js +1 -0
  18. package/dist/project-relevance.d.ts +27 -0
  19. package/dist/project-relevance.js +95 -0
  20. package/dist/project-selection-hints.d.ts +16 -0
  21. package/dist/project-selection-hints.js +32 -0
  22. package/dist/project-selection.d.ts +25 -0
  23. package/dist/project-selection.js +42 -0
  24. package/dist/recommended-external-skills.d.ts +39 -0
  25. package/dist/recommended-external-skills.js +319 -0
  26. package/dist/sdk-surface.d.ts +10 -0
  27. package/dist/sdk-surface.js +24 -0
  28. package/dist/server-branding.d.ts +17 -0
  29. package/dist/server-branding.js +40 -0
  30. package/dist/server.d.ts +3 -0
  31. package/dist/server.js +24 -0
  32. package/dist/svg-preview-block.d.ts +14 -0
  33. package/dist/svg-preview-block.js +82 -0
  34. package/dist/tools/constants.d.ts +47 -0
  35. package/dist/tools/constants.js +95 -0
  36. package/dist/tools/dispatch-branding-studio.d.ts +5 -0
  37. package/dist/tools/dispatch-branding-studio.js +197 -0
  38. package/dist/tools/dispatch-pulse-blog.d.ts +3 -0
  39. package/dist/tools/dispatch-pulse-blog.js +158 -0
  40. package/dist/tools/dispatch-research-assets.d.ts +3 -0
  41. package/dist/tools/dispatch-research-assets.js +132 -0
  42. package/dist/tools/handle-tool-call-pre.d.ts +4 -0
  43. package/dist/tools/handle-tool-call-pre.js +47 -0
  44. package/dist/tools/handle-tool-call.d.ts +3 -0
  45. package/dist/tools/handle-tool-call.js +56 -0
  46. package/dist/tools/tool-call-helpers.d.ts +22 -0
  47. package/dist/tools/tool-call-helpers.js +104 -0
  48. package/dist/tools/tool-catalog.d.ts +14 -0
  49. package/dist/tools/tool-catalog.js +54 -0
  50. package/dist/tools/tool-definitions-blog-git.d.ts +2 -0
  51. package/dist/tools/tool-definitions-blog-git.js +207 -0
  52. package/dist/tools/tool-definitions-branding.d.ts +2 -0
  53. package/dist/tools/tool-definitions-branding.js +197 -0
  54. package/dist/tools/tool-definitions-research-aliases.d.ts +2 -0
  55. package/dist/tools/tool-definitions-research-aliases.js +340 -0
  56. package/dist/tools/tool-definitions-studio-pulse.d.ts +2 -0
  57. package/dist/tools/tool-definitions-studio-pulse.js +235 -0
  58. package/dist/tools/tool-matrix.d.ts +12 -0
  59. package/dist/tools/tool-matrix.js +36 -0
  60. package/dist/tools.d.ts +5 -0
  61. package/dist/tools.js +3 -0
  62. package/dist/ui-ux-skills.d.ts +33 -0
  63. package/dist/ui-ux-skills.js +157 -0
  64. package/dist/user-pick-policy.d.ts +18 -0
  65. package/dist/user-pick-policy.js +21 -0
  66. package/package.json +71 -0
@@ -0,0 +1,25 @@
1
+ /** Project ambiguity hints for MCP ping / branding workflows. */
2
+ import { type RankableProject, type RankedProject } from "./project-relevance.js";
3
+ export declare const PROJECT_SELECTION_HINT = "Ask the user before branding tools: use an existing Majico project (pick from relevantProjects) or create a new one (create_project). Present each option with name and description; pass projectId on tool calls once confirmed.";
4
+ export type ProjectSummary = RankableProject;
5
+ export type ProjectSelectionFields = {
6
+ projectSelectionRequired: boolean;
7
+ relevantProjects: RankedProject[];
8
+ totalProjectCount: number;
9
+ hint?: string;
10
+ suggestedProjectId?: string;
11
+ suggestedProjectName?: string;
12
+ repoHints?: string[];
13
+ };
14
+ export { inferRepoNameHints, projectNameMatchesHints, findSuggestedProject, } from "./project-selection-hints.js";
15
+ /**
16
+ * Surface ranked project options on ping when scope is not confirmed for this request.
17
+ */
18
+ export declare function buildProjectSelectionFields(params: {
19
+ projects: ProjectSummary[];
20
+ activeProjectId: string;
21
+ activeProjectName: string;
22
+ explicitProjectId?: string;
23
+ consumerRepoPath?: string;
24
+ requestContext?: string;
25
+ }): ProjectSelectionFields | null;
@@ -0,0 +1,42 @@
1
+ /** Project ambiguity hints for MCP ping / branding workflows. */
2
+ import { pickRelevantProjects, } from "./project-relevance.js";
3
+ export const PROJECT_SELECTION_HINT = "Ask the user before branding tools: use an existing Majico project (pick from relevantProjects) or create a new one (create_project). Present each option with name and description; pass projectId on tool calls once confirmed.";
4
+ export { inferRepoNameHints, projectNameMatchesHints, findSuggestedProject, } from "./project-selection-hints.js";
5
+ import { inferRepoNameHints, projectNameMatchesHints, findSuggestedProject, } from "./project-selection-hints.js";
6
+ /**
7
+ * Surface ranked project options on ping when scope is not confirmed for this request.
8
+ */
9
+ export function buildProjectSelectionFields(params) {
10
+ const { projects, activeProjectId, activeProjectName, explicitProjectId, consumerRepoPath, requestContext, } = params;
11
+ const hasExplicitProjectId = Boolean(explicitProjectId?.trim());
12
+ const relevanceContext = {
13
+ consumerRepoPath,
14
+ requestContext,
15
+ };
16
+ const repoHints = inferRepoNameHints(consumerRepoPath);
17
+ const activeProject = projects.find((p) => p.id === activeProjectId);
18
+ const scopedProject = hasExplicitProjectId
19
+ ? projects.find((p) => p.id === explicitProjectId?.trim())
20
+ : activeProject;
21
+ const scopedName = scopedProject?.name ?? activeProjectName;
22
+ const scopedMatchesRepo = projectNameMatchesHints(scopedName, repoHints);
23
+ const suggested = findSuggestedProject(projects, repoHints);
24
+ const projectSelectionRequired = !hasExplicitProjectId || (repoHints.length > 0 && !scopedMatchesRepo);
25
+ if (!projectSelectionRequired)
26
+ return null;
27
+ const relevantProjects = pickRelevantProjects(projects, relevanceContext);
28
+ const fields = {
29
+ projectSelectionRequired,
30
+ relevantProjects,
31
+ totalProjectCount: projects.length,
32
+ hint: PROJECT_SELECTION_HINT,
33
+ };
34
+ if (repoHints.length > 0) {
35
+ fields.repoHints = repoHints;
36
+ }
37
+ if (suggested && suggested.id !== activeProjectId) {
38
+ fields.suggestedProjectId = suggested.id;
39
+ fields.suggestedProjectName = suggested.name;
40
+ }
41
+ return fields;
42
+ }
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Researched external Cursor UI/UX skills — optional installs for consumer repos.
3
+ * Majico DB skills stay flexible; these are recommendations with install hints.
4
+ * Source: docs/internal/cursor-ui-ux-skills-research.md
5
+ */
6
+ export type ExternalSkillKind = "ui" | "ux" | "workflow";
7
+ export type RecommendedExternalSkill = {
8
+ id: string;
9
+ name: string;
10
+ kind: ExternalSkillKind;
11
+ author: string;
12
+ why: string;
13
+ whenToUse: string;
14
+ installCommand: string;
15
+ /** Cursor plugin slug if available without npx */
16
+ pluginRef?: string;
17
+ tier: 1 | 2;
18
+ stackHints?: string[];
19
+ };
20
+ /** Tier 1 — highest impact UI craft skills */
21
+ export declare const KILLER_UI_SKILLS: readonly RecommendedExternalSkill[];
22
+ /** Tier 1 — highest impact UX skills */
23
+ export declare const KILLER_UX_SKILLS: readonly RecommendedExternalSkill[];
24
+ export declare const WORKFLOW_SKILLS: readonly RecommendedExternalSkill[];
25
+ export type RecommendedSkillsBundle = {
26
+ id: string;
27
+ label: string;
28
+ skills: string[];
29
+ note: string;
30
+ };
31
+ export declare const RECOMMENDED_SKILL_BUNDLES: readonly RecommendedSkillsBundle[];
32
+ export declare function buildRecommendedExternalSkillsPayload(): {
33
+ killerUi: RecommendedExternalSkill[];
34
+ killerUx: RecommendedExternalSkill[];
35
+ workflow: RecommendedExternalSkill[];
36
+ bundles: RecommendedSkillsBundle[];
37
+ catalogUrl: string;
38
+ researchDoc: string;
39
+ };
@@ -0,0 +1,319 @@
1
+ /**
2
+ * Researched external Cursor UI/UX skills — optional installs for consumer repos.
3
+ * Majico DB skills stay flexible; these are recommendations with install hints.
4
+ * Source: docs/internal/cursor-ui-ux-skills-research.md
5
+ */
6
+ /** Tier 1 — highest impact UI craft skills */
7
+ export const KILLER_UI_SKILLS = [
8
+ {
9
+ id: "ui-skills-root",
10
+ name: "UI Skills Root",
11
+ kind: "ui",
12
+ author: "ibelick",
13
+ why: "Routes to the smallest useful skill set by topic and stack.",
14
+ whenToUse: "Start of any UI task — avoids loading the full 134-skill catalog.",
15
+ installCommand: "npx ui-skills add ui-skills-root",
16
+ tier: 1,
17
+ },
18
+ {
19
+ id: "baseline-ui",
20
+ name: "Baseline UI",
21
+ kind: "ui",
22
+ author: "ibelick",
23
+ why: "Fast deslop: spacing, hierarchy, typography, motion caps, a11y baseline.",
24
+ whenToUse: "After first UI draft; polish pass before ship.",
25
+ installCommand: "npx ui-skills add baseline-ui",
26
+ tier: 1,
27
+ stackHints: ["tailwind", "react"],
28
+ },
29
+ {
30
+ id: "make-interfaces-feel-better",
31
+ name: "Make Interfaces Feel Better",
32
+ kind: "ui",
33
+ author: "jakubkrehel",
34
+ why: "Micro-interactions, radii, hit areas, stagger — high craft ROI.",
35
+ whenToUse: "Buttons, cards, navigation, forms, modals.",
36
+ installCommand: "npx ui-skills add make-interfaces-feel-better",
37
+ tier: 1,
38
+ },
39
+ {
40
+ id: "fixing-accessibility",
41
+ name: "Fixing Accessibility",
42
+ kind: "ui",
43
+ author: "ibelick",
44
+ why: "Prioritized WCAG fixes: names, keyboard, focus, forms.",
45
+ whenToUse: "Interactive controls, dialogs, forms, audits.",
46
+ installCommand: "npx ui-skills add fixing-accessibility",
47
+ tier: 1,
48
+ },
49
+ {
50
+ id: "fixing-motion-performance",
51
+ name: "Fixing Motion Performance",
52
+ kind: "ui",
53
+ author: "ibelick",
54
+ why: "Compositor-safe motion; kills jank and layout-thrashing animations.",
55
+ whenToUse: "CSS/JS transitions, scroll-linked motion.",
56
+ installCommand: "npx ui-skills add fixing-motion-performance",
57
+ tier: 1,
58
+ },
59
+ {
60
+ id: "frontend-design",
61
+ name: "Frontend Design",
62
+ kind: "ui",
63
+ author: "anthropics",
64
+ why: "Distinctive marketing-grade UI that avoids generic AI aesthetics.",
65
+ whenToUse: "Landing/marketing when brand docs allow creative direction.",
66
+ installCommand: "npx ui-skills add frontend-design",
67
+ tier: 1,
68
+ },
69
+ {
70
+ id: "web-design-guidelines",
71
+ name: "Web Design Guidelines",
72
+ kind: "ui",
73
+ author: "vercel-labs",
74
+ why: "Audit UI against interface guidelines (a11y + UX patterns).",
75
+ whenToUse: "Pre-ship review of pages and components.",
76
+ installCommand: "npx skills add vercel-labs/agent-skills --skill web-design-guidelines",
77
+ tier: 1,
78
+ stackHints: ["react", "next"],
79
+ },
80
+ {
81
+ id: "12-principles-of-animation",
82
+ name: "12 Principles of Animation",
83
+ kind: "ui",
84
+ author: "raphaelsalaja",
85
+ why: "Disney animation principles applied to web — natural motion language.",
86
+ whenToUse: "Hero entrances, lists, modals, icon morphs.",
87
+ installCommand: "npx ui-skills add 12-principles-of-animation",
88
+ tier: 1,
89
+ },
90
+ {
91
+ id: "oklch-skill",
92
+ name: "OKLCH Color",
93
+ kind: "ui",
94
+ author: "jakubkrehel",
95
+ why: "Build accessible, tunable color systems in OKLCH.",
96
+ whenToUse: "Extending DESIGN.md tokens into full ramps.",
97
+ installCommand: "npx ui-skills add oklch-skill",
98
+ tier: 1,
99
+ },
100
+ {
101
+ id: "ui-design-brain",
102
+ name: "UI Design Brain",
103
+ kind: "ui",
104
+ author: "carmahhawwari",
105
+ why: "60+ component best practices, layouts, anti-patterns from component.gallery.",
106
+ whenToUse: "Greenfield components (tables, modals, nav, etc.).",
107
+ installCommand: "npx skills add carmahhawwari/ui-design-brain",
108
+ tier: 1,
109
+ },
110
+ {
111
+ id: "interface-design",
112
+ name: "Interface Design",
113
+ kind: "ui",
114
+ author: "Dammyjay93",
115
+ why: "Dashboard/admin/SaaS app patterns with craft focus.",
116
+ whenToUse: "App shell, settings, data-dense UI — not marketing landings.",
117
+ installCommand: "npx ui-skills add interface-design",
118
+ tier: 1,
119
+ stackHints: ["react"],
120
+ },
121
+ {
122
+ id: "ui-motion-expressive",
123
+ name: "UI Motion Expressive",
124
+ kind: "ui",
125
+ author: "majico",
126
+ why: "Per-brand motion from DESIGN.md §7 — intensity tiers, Motion One guidance, reduced-motion checklist.",
127
+ whenToUse: "Consumer repo handoff when user wants expressive motion; pair with sync_cursor_skills.",
128
+ installCommand: "Majico MCP: sync_cursor_skills (ships ui-motion-expressive from project DB)",
129
+ tier: 1,
130
+ stackHints: ["react", "next", "css"],
131
+ },
132
+ {
133
+ id: "shadcn",
134
+ name: "shadcn/ui",
135
+ kind: "ui",
136
+ author: "shadcn-ui",
137
+ why: "Project-aware shadcn compose, add, and fix patterns.",
138
+ whenToUse: "Repos already using shadcn/ui.",
139
+ installCommand: "npx ui-skills add shadcn",
140
+ tier: 1,
141
+ stackHints: ["react", "tailwind", "shadcn"],
142
+ },
143
+ ];
144
+ /** Tier 1 — highest impact UX skills */
145
+ export const KILLER_UX_SKILLS = [
146
+ {
147
+ id: "shape",
148
+ name: "Shape (UX brief)",
149
+ kind: "ux",
150
+ author: "pbakaus",
151
+ why: "Structured design interview → actionable brief before coding.",
152
+ whenToUse: "New feature or screen with unclear UX requirements.",
153
+ installCommand: "npx ui-skills add shape",
154
+ tier: 1,
155
+ },
156
+ {
157
+ id: "clarify",
158
+ name: "Clarify",
159
+ kind: "ux",
160
+ author: "pbakaus",
161
+ why: "Improves labels, microcopy, and action clarity.",
162
+ whenToUse: "Forms, onboarding, CTAs, empty states.",
163
+ installCommand: "npx ui-skills add clarify",
164
+ tier: 1,
165
+ },
166
+ {
167
+ id: "critique",
168
+ name: "Critique",
169
+ kind: "ux",
170
+ author: "pbakaus",
171
+ why: "Structured UX scoring with persona checks and fixes.",
172
+ whenToUse: "Review existing UI for UX quality.",
173
+ installCommand: "npx ui-skills add critique",
174
+ tier: 1,
175
+ },
176
+ {
177
+ id: "harden",
178
+ name: "Harden",
179
+ kind: "ux",
180
+ author: "pbakaus",
181
+ why: "Production UX: empty/error/edge cases, onboarding, i18n resilience.",
182
+ whenToUse: "Pre-launch hardening pass.",
183
+ installCommand: "npx ui-skills add harden",
184
+ tier: 1,
185
+ },
186
+ {
187
+ id: "distill",
188
+ name: "Distill",
189
+ kind: "ux",
190
+ author: "pbakaus",
191
+ why: "Simplify overloaded interfaces; restore focus.",
192
+ whenToUse: "Busy dashboards, settings, feature-creep screens.",
193
+ installCommand: "npx ui-skills add distill",
194
+ tier: 1,
195
+ },
196
+ {
197
+ id: "polish",
198
+ name: "Polish",
199
+ kind: "ux",
200
+ author: "pbakaus",
201
+ why: "Final alignment/spacing/consistency pass for launch readiness.",
202
+ whenToUse: "Last mile before ship (pairs with ui-craft-polish).",
203
+ installCommand: "npx ui-skills add polish",
204
+ tier: 1,
205
+ },
206
+ {
207
+ id: "interaction-design",
208
+ name: "Interaction Design",
209
+ kind: "ux",
210
+ author: "wshobson",
211
+ why: "Microinteractions, feedback, transitions for delightful flows.",
212
+ whenToUse: "Wizards, multi-step flows, async states.",
213
+ installCommand: "npx ui-skills add interaction-design",
214
+ tier: 1,
215
+ },
216
+ {
217
+ id: "uxauditor",
218
+ name: "UXAuditor",
219
+ kind: "ux",
220
+ author: "aihxp",
221
+ why: "End-to-end UX audit with scored uxaudit.md report.",
222
+ whenToUse: "Full product UX review; handoff to fix agents.",
223
+ installCommand: "npx skills add aihxp/uxauditor",
224
+ tier: 1,
225
+ },
226
+ {
227
+ id: "ux-expert",
228
+ name: "UX Expert",
229
+ kind: "ux",
230
+ author: "felixgeelhaar",
231
+ why: "Heuristics, IA, WCAG, dark patterns, agentic UI patterns.",
232
+ whenToUse: "Strategic UX questions and heuristic evaluation.",
233
+ installCommand: "npx skills add felixgeelhaar/skills --skill ux-expert",
234
+ tier: 1,
235
+ },
236
+ {
237
+ id: "wcag-audit-patterns",
238
+ name: "WCAG Audit Patterns",
239
+ kind: "ux",
240
+ author: "wshobson",
241
+ why: "WCAG 2.2 audit playbook with remediation strategies.",
242
+ whenToUse: "Compliance sprint or a11y lawsuit prep.",
243
+ installCommand: "npx ui-skills add wcag-audit-patterns",
244
+ tier: 1,
245
+ },
246
+ ];
247
+ export const WORKFLOW_SKILLS = [
248
+ {
249
+ id: "brainstorming",
250
+ name: "Brainstorming",
251
+ kind: "workflow",
252
+ author: "obra/superpowers",
253
+ why: "Explore options before committing to layout or architecture.",
254
+ whenToUse: "Greenfield screens; user hasn't picked direction.",
255
+ installCommand: "npx skills add obra/superpowers --skill brainstorming",
256
+ pluginRef: "brainstorming",
257
+ tier: 2,
258
+ },
259
+ {
260
+ id: "verification-before-completion",
261
+ name: "Verification Before Completion",
262
+ kind: "workflow",
263
+ author: "obra/superpowers",
264
+ why: "Evidence before claiming UI work is done.",
265
+ whenToUse: "Before PR, commit, or ack_cursor_handoff.",
266
+ installCommand: "npx skills add obra/superpowers --skill verification-before-completion",
267
+ pluginRef: "verification-before-completion",
268
+ tier: 2,
269
+ },
270
+ ];
271
+ export const RECOMMENDED_SKILL_BUNDLES = [
272
+ {
273
+ id: "marketing-landing",
274
+ label: "Marketing / landing",
275
+ skills: [
276
+ "ui-skills-root",
277
+ "baseline-ui",
278
+ "make-interfaces-feel-better",
279
+ "ui-motion-expressive",
280
+ "fixing-accessibility",
281
+ "clarify",
282
+ "polish",
283
+ ],
284
+ note: "Pair with Majico sync_cursor_skills + BRAND.md + DESIGN.md.",
285
+ },
286
+ {
287
+ id: "saas-app",
288
+ label: "SaaS app UI",
289
+ skills: [
290
+ "ui-skills-root",
291
+ "interface-design",
292
+ "harden",
293
+ "fixing-accessibility",
294
+ "web-design-guidelines",
295
+ ],
296
+ note: "Add react-best-practices for Next/React repos.",
297
+ },
298
+ {
299
+ id: "design-system",
300
+ label: "Design-system repo",
301
+ skills: [
302
+ "shadcn",
303
+ "oklch-skill",
304
+ "fixing-accessibility",
305
+ "wcag-audit-patterns",
306
+ ],
307
+ note: "Add team-authored component-usage + token-reference skills.",
308
+ },
309
+ ];
310
+ export function buildRecommendedExternalSkillsPayload() {
311
+ return {
312
+ killerUi: [...KILLER_UI_SKILLS],
313
+ killerUx: [...KILLER_UX_SKILLS],
314
+ workflow: [...WORKFLOW_SKILLS],
315
+ bundles: [...RECOMMENDED_SKILL_BUNDLES],
316
+ catalogUrl: "https://www.ui-skills.com/skills/",
317
+ researchDoc: "docs/internal/cursor-ui-ux-skills-research.md",
318
+ };
319
+ }
@@ -0,0 +1,10 @@
1
+ import type { MajicoClient } from "@majico/sdk";
2
+ /**
3
+ * Resources required by user-majico-mcp tool dispatch.
4
+ * npm @majico/sdk@1.0.1 omitted these and caused staging
5
+ * "Cannot read properties of undefined" on ping / palette / blog.
6
+ */
7
+ export declare const MCP_REQUIRED_SDK_RESOURCES: readonly ["projects", "palette", "blog", "pulse", "research", "cursorSkills"];
8
+ export type McpRequiredSdkResource = (typeof MCP_REQUIRED_SDK_RESOURCES)[number];
9
+ /** Returns an error message when the client is too old for this MCP server. */
10
+ export declare function mcpSdkSurfaceError(client: Pick<MajicoClient, McpRequiredSdkResource> | Record<string, unknown>): string | null;
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Resources required by user-majico-mcp tool dispatch.
3
+ * npm @majico/sdk@1.0.1 omitted these and caused staging
4
+ * "Cannot read properties of undefined" on ping / palette / blog.
5
+ */
6
+ export const MCP_REQUIRED_SDK_RESOURCES = [
7
+ "projects",
8
+ "palette",
9
+ "blog",
10
+ "pulse",
11
+ "research",
12
+ "cursorSkills",
13
+ ];
14
+ /** Returns an error message when the client is too old for this MCP server. */
15
+ export function mcpSdkSurfaceError(client) {
16
+ for (const key of MCP_REQUIRED_SDK_RESOURCES) {
17
+ if (!(key in client) || client[key] == null) {
18
+ return ("Incompatible @majico/sdk: need >= 1.1.0 with projects, palette, blog, " +
19
+ "pulse, research, and cursorSkills. Published 1.0.1 is too old for " +
20
+ "user-majico-mcp >= 0.6.0.");
21
+ }
22
+ }
23
+ return null;
24
+ }
@@ -0,0 +1,17 @@
1
+ /** MCP serverInfo branding (icons, title) for Cursor and other MCP clients. */
2
+ export declare const MAJICO_MCP_SERVER_TITLE = "Majico";
3
+ export declare const MAJICO_MCP_SERVER_DESCRIPTION = "Brand guidelines, design tokens, and studio canvas for Majico projects.";
4
+ export declare const MAJICO_MCP_WEBSITE_URL = "https://majico.xyz";
5
+ export declare const MAJICO_MCP_ICON_SVG_PATH = "/brand/mcp-icon.svg";
6
+ export declare const MAJICO_MCP_ICON_PNG_PATH = "/brand/mcp-icon-96.png";
7
+ export type McpServerIcon = {
8
+ src: string;
9
+ mimeType: string;
10
+ sizes?: string[];
11
+ theme?: "light" | "dark";
12
+ };
13
+ /**
14
+ * Build absolute HTTPS icon URLs for MCP `serverInfo.icons`.
15
+ * Falls back to production when no public base is available (stdio).
16
+ */
17
+ export declare function buildMcpServerIcons(publicBaseUrl?: string, iconBaseUrl?: string): McpServerIcon[];
@@ -0,0 +1,40 @@
1
+ /** MCP serverInfo branding (icons, title) for Cursor and other MCP clients. */
2
+ export const MAJICO_MCP_SERVER_TITLE = "Majico";
3
+ export const MAJICO_MCP_SERVER_DESCRIPTION = "Brand guidelines, design tokens, and studio canvas for Majico projects.";
4
+ export const MAJICO_MCP_WEBSITE_URL = "https://majico.xyz";
5
+ export const MAJICO_MCP_ICON_SVG_PATH = "/brand/mcp-icon.svg";
6
+ export const MAJICO_MCP_ICON_PNG_PATH = "/brand/mcp-icon-96.png";
7
+ /**
8
+ * Build absolute HTTPS icon URLs for MCP `serverInfo.icons`.
9
+ * Falls back to production when no public base is available (stdio).
10
+ */
11
+ export function buildMcpServerIcons(publicBaseUrl, iconBaseUrl) {
12
+ const base = normalizePublicBaseUrl(iconBaseUrl ?? publicBaseUrl);
13
+ return [
14
+ {
15
+ src: `${base}${MAJICO_MCP_ICON_SVG_PATH}`,
16
+ mimeType: "image/svg+xml",
17
+ sizes: ["any"],
18
+ },
19
+ {
20
+ src: `${base}${MAJICO_MCP_ICON_PNG_PATH}`,
21
+ mimeType: "image/png",
22
+ sizes: ["96x96"],
23
+ },
24
+ ];
25
+ }
26
+ function normalizePublicBaseUrl(publicBaseUrl) {
27
+ const trimmed = publicBaseUrl?.trim().replace(/\/$/, "");
28
+ if (trimmed) {
29
+ try {
30
+ const url = new URL(trimmed);
31
+ if (url.protocol === "http:" || url.protocol === "https:") {
32
+ return url.origin;
33
+ }
34
+ }
35
+ catch {
36
+ /* fall through */
37
+ }
38
+ }
39
+ return "https://majico.xyz";
40
+ }
@@ -0,0 +1,3 @@
1
+ import { Server } from "@modelcontextprotocol/sdk/server";
2
+ import type { CredentialSource } from "./credentials.js";
3
+ export declare function createMajicoMcpServer(defaultCredentials?: CredentialSource): Server;
package/dist/server.js ADDED
@@ -0,0 +1,24 @@
1
+ import { Server } from "@modelcontextprotocol/sdk/server";
2
+ import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
3
+ import { buildMcpServerIcons, MAJICO_MCP_SERVER_DESCRIPTION, MAJICO_MCP_SERVER_TITLE, MAJICO_MCP_WEBSITE_URL, } from "./server-branding.js";
4
+ import { handleMajicoToolCall, listMcpTools, MCP_SERVER_VERSION, } from "./tools.js";
5
+ export function createMajicoMcpServer(defaultCredentials) {
6
+ const server = new Server({
7
+ name: "user-majico",
8
+ title: MAJICO_MCP_SERVER_TITLE,
9
+ version: MCP_SERVER_VERSION,
10
+ description: MAJICO_MCP_SERVER_DESCRIPTION,
11
+ websiteUrl: MAJICO_MCP_WEBSITE_URL,
12
+ icons: buildMcpServerIcons(defaultCredentials?.publicBaseUrl, defaultCredentials?.iconBaseUrl),
13
+ }, { capabilities: { tools: {} } });
14
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({
15
+ tools: listMcpTools({
16
+ includeAdminTools: Boolean(defaultCredentials?.includeAdminTools),
17
+ }),
18
+ }));
19
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
20
+ const { name, arguments: args } = request.params;
21
+ return handleMajicoToolCall(name, (args ?? {}), defaultCredentials);
22
+ });
23
+ return server;
24
+ }
@@ -0,0 +1,14 @@
1
+ import type { McpContentBlock } from "./present-types.js";
2
+ /**
3
+ * Ink currentColor and ensure sharp has a root xmlns + explicit size.
4
+ * Avoids wrapping in a second SVG (librsvg + Turbopack `">` corruption).
5
+ */
6
+ export declare function prepareSvgMarkupForRaster(svg: string): string;
7
+ /** @deprecated Use prepareSvgMarkupForRaster — kept for call-site compatibility. */
8
+ export declare function prepareSvgForChatPreview(svg: string): string;
9
+ /**
10
+ * Rasterize inline SVG to a PNG MCP image block (Cursor renders PNG, not SVG).
11
+ * Pads on a light canvas via sharp.composite (no wrapper SVG string).
12
+ * Soft-fails to a text note when sharp cannot rasterize.
13
+ */
14
+ export declare function svgPreviewBlock(svg: string): Promise<McpContentBlock>;
@@ -0,0 +1,82 @@
1
+ import sharp from "sharp";
2
+ const PREVIEW_PAD = 24;
3
+ const PREVIEW_MARK_SIZE = 96;
4
+ const PREVIEW_BG = { r: 0xf4, g: 0xf4, b: 0xf5, alpha: 1 };
5
+ const PREVIEW_FG = "#111111";
6
+ const IMAGE_ANNOTATIONS = {
7
+ audience: ["user", "assistant"],
8
+ priority: 0.9,
9
+ };
10
+ /** Runtime `>` so Turbopack/SWC cannot strip `">` from folded template literals. */
11
+ function gt() {
12
+ return String.fromCharCode(0x3e);
13
+ }
14
+ /**
15
+ * Ink currentColor and ensure sharp has a root xmlns + explicit size.
16
+ * Avoids wrapping in a second SVG (librsvg + Turbopack `">` corruption).
17
+ */
18
+ export function prepareSvgMarkupForRaster(svg) {
19
+ let markup = svg
20
+ .trim()
21
+ .replace(/\bcurrentColor\b/gi, PREVIEW_FG)
22
+ .replace(/\bcurrentcolour\b/gi, PREVIEW_FG);
23
+ // Repair truncated viewBox smashed into the next tag (Turbopack artifact).
24
+ markup = markup.replace(/(viewBox\s*=\s*["'][^"']*?)\s*(<[a-zA-Z/])/g, (_, vb, next) => `${vb}"${gt()}${next}`);
25
+ if (!/\sxmlns=/i.test(markup)) {
26
+ markup = markup.replace(/<svg\b/i, `<svg xmlns="http://www.w3.org/2000/svg"`);
27
+ }
28
+ if (!/\swidth=/i.test(markup)) {
29
+ const close = gt();
30
+ markup = markup.replace(/<svg\b([^>]*)>/i, (_m, attrs) => [
31
+ `<svg${attrs} width="${PREVIEW_MARK_SIZE}" height="${PREVIEW_MARK_SIZE}"`,
32
+ close,
33
+ ].join(""));
34
+ }
35
+ return markup;
36
+ }
37
+ /** @deprecated Use prepareSvgMarkupForRaster — kept for call-site compatibility. */
38
+ export function prepareSvgForChatPreview(svg) {
39
+ return prepareSvgMarkupForRaster(svg);
40
+ }
41
+ /**
42
+ * Rasterize inline SVG to a PNG MCP image block (Cursor renders PNG, not SVG).
43
+ * Pads on a light canvas via sharp.composite (no wrapper SVG string).
44
+ * Soft-fails to a text note when sharp cannot rasterize.
45
+ */
46
+ export async function svgPreviewBlock(svg) {
47
+ try {
48
+ const markup = prepareSvgMarkupForRaster(svg);
49
+ const markPng = await sharp(Buffer.from(markup, "utf8"))
50
+ .resize(PREVIEW_MARK_SIZE, PREVIEW_MARK_SIZE, {
51
+ fit: "contain",
52
+ background: { r: 0, g: 0, b: 0, alpha: 0 },
53
+ })
54
+ .png()
55
+ .toBuffer();
56
+ const size = PREVIEW_MARK_SIZE + PREVIEW_PAD * 2;
57
+ const png = await sharp({
58
+ create: {
59
+ width: size,
60
+ height: size,
61
+ channels: 4,
62
+ background: PREVIEW_BG,
63
+ },
64
+ })
65
+ .composite([{ input: markPng, left: PREVIEW_PAD, top: PREVIEW_PAD }])
66
+ .png()
67
+ .toBuffer();
68
+ return {
69
+ type: "image",
70
+ data: png.toString("base64"),
71
+ mimeType: "image/png",
72
+ annotations: IMAGE_ANNOTATIONS,
73
+ };
74
+ }
75
+ catch (err) {
76
+ const message = err instanceof Error ? err.message : String(err);
77
+ return {
78
+ type: "text",
79
+ text: `_(PNG preview unavailable: ${message})_`,
80
+ };
81
+ }
82
+ }