@volue/wave-mcp 0.1.0-next.6 → 0.1.0-next.8

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 CHANGED
@@ -12,6 +12,7 @@
12
12
  | `list_patterns` | List all UX patterns grouped by category |
13
13
  | `get_pattern` | Retrieve detailed guidance for a specific pattern |
14
14
  | `get_color_usage` | Get color token usage and guidelines |
15
+ | `get_tokens` | Get design tokens and usage examples |
15
16
  | `list_icons` | List all available icons in the Wave icon library |
16
17
  | `get_icon` | Get SVG code and usage information for a specific icon |
17
18
 
@@ -47,7 +48,7 @@ Use the CLI:
47
48
  cd your-awesome-project
48
49
 
49
50
  # 2. Add Wave MCP server
50
- claude mcp add wave -- npx -y @volue/wave-mcp@latest
51
+ claude mcp add wave --scope project -- npx -y @volue/wave-mcp@latest
51
52
  ```
52
53
 
53
54
  Or manually add to your Claude Code MCP servers configuration:
@@ -0,0 +1,121 @@
1
+ var W=Object.defineProperty;var a=(e,t)=>W(e,"name",{value:t,configurable:!0});import{a as m,f as p,u as g,g as d}from"./server-BxXSw3gh.js";import D from"@volue/design-colors/generic";import*as P from"@volue/design-icons";import k from"@volue/wave-react/tokens";import N from"remark-parse";import U from"unified";import{z as f}from"zod";const M=U().use(N),w={Components:"component","UX patterns":"pattern"};function z(e,t){const o=M.parse(e);let n=null;return o.children.reduce((r,i)=>{if(m(i,"heading")&&i.depth===2)return n=j(i),r;if(!n||!m(i,"list"))return r;const s=n,c=i.children.map(l=>A(l,s,t)).filter(l=>l!==null);return r.concat(c)},[])}a(z,"parseLlmsIndex");function j(e){const[t]=e.children;if(!t||!m(t,"text"))return null;const o=t.value.trim();if(!(o in w))return null;const n=w[o];return{title:o,type:n}}a(j,"extractSectionContext");function A(e,t,o){const[n]=e.children;if(!n||!m(n,"paragraph")||n.children.length!==2)return null;const[r,i]=n.children;if(!m(r,"link")||!m(i,"text")||r.children.length!==1)return null;const s=r.children[0];if(!m(s,"text"))return null;const c=s.value.trim(),l=r.url.replace(/^\//,""),R=new URL(l,`${o}/`).toString(),I=O(l),L=F(t.title,l,t.type),_=G(i.value);return{name:c,slug:I,category:L,section:t.title,type:t.type,url:R,description:_??void 0}}a(A,"listItemToResource");function O(e){return e.replace(/\.md$/,"").split("/").pop()??""}a(O,"deriveSlug");function F(e,t,o){const n=t.replace(/\.md$/,"").split("/");if(o==="component"||o==="pattern"){const r=n.length>=3?n[n.length-2]:null;return r?`${e} / ${H(r)}`:e}return e}a(F,"deriveCategory");function H(e){return e.split("-").filter(Boolean).map(t=>t.charAt(0).toUpperCase()+t.slice(1)).join(" ")}a(H,"formatSegment");function G(e){if(!e)return null;const t=e.replace(/^\s*:\s*/,"").trim();return t.toLowerCase()==="no description available"?null:t}a(G,"normalizeDescription");const h=process.env.USE_STABLE_DOCS==="true"||process.env.USE_STABLE_DOCS==="1"?"https://wave.volue.com":"https://wave-design-system.vercel.app",V=`${h}/llms.txt`,X=1e3*60*15,Y=process.env.WAVE_RESOURCES_CACHE_TIME?Number.parseInt(process.env.WAVE_RESOURCES_CACHE_TIME,10):X;function y(e){const t=new URL(e,h);return t.pathname.endsWith(".md")||(t.pathname+=".md"),t.toString()}a(y,"createUrl");let v=null,T=0;async function J(){if(v!==null&&Date.now()<T)return v;const e=await q();return v=e,T=Date.now()+Y,e}a(J,"listCachedResources");let u=null;async function q(){return u||(u=K().finally(()=>{u=null})),u}a(q,"idempotentLoadResourcesFromLlms");async function K(){const e=await p(V,void 0,"fetch llms.txt");return z(e,h)}a(K,"loadResourcesFromLlms");async function Q(e){return p(e.url,void 0,`fetch ${e.name} documentation`)}a(Q,"fetchComponent");function Z(e){return p(e.url,void 0,`fetch ${e.name} pattern`)}a(Z,"fetchPattern");async function ee(){return p(y("get-started/developing"),void 0,"fetch developing guide")}a(ee,"fetchDevelopingGuide");async function te(){return p(y("tokens/colors"),void 0,"fetch color usage guidelines")}a(te,"fetchColorUsageGuidelines");function x(){return Object.entries(P).map(([e,t])=>({name:e,svg:t}))}a(x,"listIcons");function ne(){const e=x();return g(e.map(t=>t.name))}a(ne,"getIconNames");function oe(e,t){const o=t.trim().toLowerCase();return e.find(n=>n.name.toLowerCase()===o)}a(oe,"findIconByName");async function C(e){return(await J()).filter(o=>o.type===e)}a(C,"listResourcesByType");function E(e,t){const o=t.trim().toLowerCase();return e.find(n=>n.name.toLowerCase()===o)}a(E,"findResourceByName");function S(){return C("component")}a(S,"listComponents");async function re(){const e=await S();return g(e.map(t=>t.name))}a(re,"getComponentNames");function b(){return C("pattern")}a(b,"listPatterns");async function ie(){const e=await b();return g(e.map(t=>t.name))}a(ie,"getPatternNames");function $(e){return e.reduce((t,o)=>(t[o.category]||(t[o.category]=[]),t[o.category].push(o),t),{})}a($,"groupResourcesByCategory");const ae={name:"get_color_usage",description:"Retrieve the Wave Design System color tokens and guidelines for applying color in user interfaces.",exec(e,{name:t,description:o}){e.tool(t,o,async()=>{try{const n=await te();return{content:[{type:"text",text:JSON.stringify(D)},{type:"text",text:`Here are the Wave Design System color usage guidelines:
2
+
3
+ ${n}
4
+
5
+ ---
6
+ Source: ${y("tokens/colors")}`}]}}catch(n){return{isError:!0,content:[{type:"text",text:`Failed to retrieve color usage guidelines: ${d(n)}`}]}}})}},se={name:"get_component",description:"Retrieve comprehensive documentation for a specific Wave Design System component by name. This tool retrieves the import instructions, basic usage and advanced configuration examples, code snippets for common scenarios, available props/properties table and some general guidelines for a given Wave Design System component.",async ctx(){try{return{componentNames:await re()}}catch(e){throw new Error(`Failed to initialize component tool: ${d(e)}`)}},exec(e,{ctx:t,name:o,description:n}){e.tool(o,n,{name:f.enum(t.componentNames).describe("The name of the component to retrieve documentation for. This can be derived from calling the `get_components` tool.")},async({name:r})=>{try{const i=await S(),s=E(i,r);if(!s)throw new Error("Component not found");const c=await Q(s);return c?{content:[{type:"text",text:`Here is the documentation for the \`${s.name}\` component from the Wave Design System:
7
+
8
+ ${c}
9
+
10
+ ---
11
+ Source: ${s.url}`}]}:{content:[{type:"text",text:`No documentation content found for the \`${s.name}\` component.`}]}}catch(i){return{isError:!0,content:[{type:"text",text:`Failed to retrieve documentation for \`${r}\`: ${d(i)}`}]}}})}},ce={name:"get_icon",description:"Retrieve a specific icon information by name from Wave Design System.",exec(e,{name:t,description:o}){e.tool(t,o,{name:f.enum(ne()).describe("The icon name to retrieve. This can be derived from calling the `list_icon` tool.")},async({name:n})=>{try{const r=x(),i=oe(r,n);if(!i)throw new Error("Icon not found.");const s=`<SvgIcon iconName="${i.name}" />`,c=`<div class="svgIcon svgIcon--stroked">
12
+ <svg focusable="false" aria-hidden="true">
13
+ <use xlink:href="#svg--${i.name}"></use>
14
+ </svg>
15
+ </div>`;return{content:[{type:"text",text:`# ${i.name} icon
16
+
17
+ ## React component:
18
+
19
+ \`\`\`tsx
20
+ ${s}
21
+ \`\`\`
22
+
23
+ ## HTML markup:
24
+
25
+ \`\`\`html
26
+ ${c}
27
+ \`\`\`
28
+
29
+ ## Raw SVG code:
30
+
31
+ \`\`\`svg
32
+ ${i.svg}
33
+ \`\`\``}]}}catch(r){return{isError:!0,content:[{type:"text",text:`Failed to retrieve icon \`${n}\`: ${d(r)}`}]}}})}},le={name:"get_pattern",description:"Retrieve documentation for a specific Wave Design System UX pattern by name. This tool provides guidance, examples and components that implement the selected pattern.",async ctx(){try{return{patternNames:await ie()}}catch(e){throw new Error(`Failed to initialize pattern tool: ${d(e)}`)}},exec(e,{ctx:t,name:o,description:n}){e.tool(o,n,{name:f.enum(t.patternNames).describe("The name of the UX pattern to retrieve documentation for. This can be derived from calling the `list_patterns` tool.")},async({name:r})=>{try{const i=await b(),s=E(i,r);if(!s)throw new Error("Pattern not found");const c=await Z(s);return{content:[{type:"text",text:`Here are the guidelines for the \`${s.name}\` UX pattern from the Wave Design System:
34
+
35
+ ${c}
36
+
37
+ ---
38
+ Source: ${s.url}`}]}}catch(i){return{isError:!0,content:[{type:"text",text:`Failed to retrieve documentation for \`${r}\`: ${d(i)}`}]}}})}},de={colors:["background","backgroundColor","backgroundImage","border","borderBlock","borderBlockEnd","borderBlockStart","borderBottom","borderBottomColor","borderColor","borderInline","borderInlineEnd","borderInlineStart","borderLeft","borderLeftColor","borderRight","borderRightColor","borderTop","borderTopColor","caretColor","color","columnRuleColor","fill","outlineColor","stroke","textDecorationColor"],fonts:["fontFamily"],fontSizes:["fontSize"],fontWeights:["fontWeight"],lineHeights:["lineHeight"],letterSpacings:["letterSpacing"],radii:["borderRadius","borderTopLeftRadius","borderTopRightRadius","borderBottomRightRadius","borderBottomLeftRadius"],sizes:["blockSize","minBlockSize","maxBlockSize","inlineSize","minInlineSize","maxInlineSize","width","minWidth","maxWidth","height","minHeight","maxHeight","flexBasis","gridTemplateColumns","gridTemplateRows"],space:["gap","gridGap","columnGap","gridColumnGap","rowGap","gridRowGap","inset","insetBlock","insetBlockEnd","insetBlockStart","insetInline","insetInlineEnd","insetInlineStart","margin","marginTop","marginRight","marginBottom","marginLeft","marginBlock","marginBlockEnd","marginBlockStart","marginInline","marginInlineEnd","marginInlineStart","padding","paddingTop","paddingRight","paddingBottom","paddingLeft","paddingBlock","paddingBlockEnd","paddingBlockStart","paddingInline","paddingInlineEnd","paddingInlineStart","top","right","bottom","left","scrollMargin","scrollMarginTop","scrollMarginRight","scrollMarginBottom","scrollMarginLeft","scrollMarginX","scrollMarginY","scrollMarginBlock","scrollMarginBlockEnd","scrollMarginBlockStart","scrollMarginInline","scrollMarginInlineEnd","scrollMarginInlineStart","scrollPadding","scrollPaddingTop","scrollPaddingRight","scrollPaddingBottom","scrollPaddingLeft","scrollPaddingX","scrollPaddingY","scrollPaddingBlock","scrollPaddingBlockEnd","scrollPaddingBlockStart","scrollPaddingInline","scrollPaddingInlineEnd","scrollPaddingInlineStart"],zIndices:["zIndex"],shadows:["boxShadow","textShadow"],transitions:["transition"],borderWidths:["borderWidth","borderTopWidth","borderRightWidth","borderBottomWidth","borderLeftWidth"],borderStyles:["borderStyle","borderTopStyle","borderRightStyle","borderBottomStyle","borderLeftStyle"]},me={name:"get_tokens",description:"Retrieve the Wave Design System design tokens (colors, fonts, spacing, font styles, etc.) exposed by the `@volue/wave-react` package. Includes token type mappings to CSS properties and usage examples.",exec(e,{name:t,description:o}){e.tool(t,o,async()=>{const n=Object.entries(de).map(([r,i])=>`| ${r} | ${i.join(", ")} |`).join(`
39
+ `);return{content:[{type:"text",text:`Below is a list of design tokens available from Wave Design System.
40
+ There are ${Object.keys(k).length} token types available:
41
+
42
+ ${JSON.stringify(k)}`},{type:"text",text:`## Token Type to CSS Property Mapping
43
+
44
+ Token types are automatically mapped to CSS Properties:
45
+
46
+ | Token | Properties |
47
+ |-------|------------|
48
+ ${n}
49
+
50
+ ## Using tokens
51
+
52
+ Tokens can be used to style components.
53
+
54
+ \`\`\`tsx
55
+ import { styled } from '@volue/wave-react';
56
+
57
+ const Button = styled('button', {
58
+ backgroundColor: '$backgroundAccentStrong'
59
+ });
60
+
61
+ () => <Button>Button</Button>;
62
+ \`\`\`
63
+
64
+ Tokens also work inside the \`css\` prop.
65
+
66
+ \`\`\`tsx
67
+ const Button = styled('button', {});
68
+
69
+ () => (
70
+ <Button
71
+ css={{
72
+ backgroundColor: '$backgroundAccentStrong'
73
+ }}
74
+ >
75
+ Button
76
+ </Button>
77
+ );
78
+ \`\`\`
79
+
80
+ You can pick a token from any of available token types by prefixing them with the type name, in case they aren't automatically mapped.
81
+
82
+ \`\`\`tsx
83
+ const Button = styled('button', {
84
+ // use a token from the sizes scale
85
+ marginTop: '$sizes$6'
86
+ });
87
+ \`\`\`
88
+ `}]}})}},pe={name:"init",description:"Get guide on how to setup or create a project that includes Wave Design System.",exec(e,{name:t,description:o}){e.tool(t,o,async()=>{try{return{content:[{type:"text",text:`The getting started documentation for developing with Wave Design System is included below.
89
+
90
+ It's **important** that if the project is using a tool like Vite or Next.js, one of the pre-configured starter templates should be used instead of manual configuration:
91
+
92
+ - https://github.com/Volue/wave-vite-example (Vite template)
93
+ - https://github.com/Volue/wave-nextjs-app-router-example (Next.js App Router template)
94
+
95
+ ---
96
+
97
+ ${await ee()}
98
+ `}]}}catch(n){return{isError:!0,content:[{type:"text",text:`Failed to retrieve getting started documentation: ${d(n)}`}]}}})}},ue={name:"list_components",description:"List all components available from the Wave Design System. This tool retrieves the names of all available Wave Design System components grouped by category.",exec(e,{name:t,description:o}){e.tool(t,o,async()=>{try{const n=await S(),r=$(n);return{content:[{type:"text",text:`The following components are available in the Wave Design System:
99
+
100
+ ${Object.entries(r).map(([s,c])=>`## ${s}
101
+ ${c.map(l=>`- ${l.name}`).join(`
102
+ `)}`).join(`
103
+
104
+ `)}
105
+
106
+ Use the \`get_component\` tool to get more information about a specific component.
107
+
108
+ Use these components from the @volue/wave-react package.`}]}}catch(n){return{isError:!0,content:[{type:"text",text:`Failed to retrieve the component index: ${d(n)}`}]}}})}},ge={name:"list_icons",description:"List all icons available from the Wave Design System. Icons are sourced directly from the `@volue/design-icons` package.",exec(e,{name:t,description:o}){e.tool(t,o,async()=>{try{return{content:[{type:"text",text:`The following icons are available in the Wave Design System:
109
+
110
+ ${x().map(i=>`- ${i.name}`).join(`
111
+ `)}
112
+
113
+ Use the \`get_icon\` tool to retrieve the SVG markup and usage guidelines for a specific icon.`}]}}catch(n){return{isError:!0,content:[{type:"text",text:`Failed to retrieve the icon data: ${d(n)}`}]}}})}},fe={name:"list_patterns",description:"List all UX patterns available from the Wave Design System. This tool retrieves the names of all available Wave Design System patterns grouped by category.",exec(e,{name:t,description:o}){e.tool(t,o,async()=>{try{const n=await b(),r=$(n);return{content:[{type:"text",text:`The following UX patterns are available in the Wave Design System:
114
+
115
+ ${Object.entries(r).map(([s,c])=>`## ${s}
116
+ ${c.map(l=>`- ${l.name}`).join(`
117
+ `)}`).join(`
118
+
119
+ `)}
120
+
121
+ Use the \`get_pattern\` tool to access detailed guidance for a specific pattern.`}]}}catch(n){return{isError:!0,content:[{type:"text",text:`Failed to retrieve the pattern index: ${d(n)}`}]}}})}},he=[pe,ue,se,fe,le,ae,ge,ce,me],B=new Set;async function ye(e){await Promise.all(he.map(async t=>{if(B.has(t.name))return;const o=await t.ctx?.();B.add(t.name),t.exec(e,{name:t.name,description:t.description,ctx:o})}))}a(ye,"initializeTools");export{ye as i};
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env node
2
- var e=Object.defineProperty;var t=(o,r)=>e(o,"name",{value:r,configurable:!0});import{i}from"./server-Bn99IvSq.js";import{s as g}from"./server-Bn99IvSq.js";import"node:fs";import"node:url";import"@modelcontextprotocol/sdk/server/mcp.js";if(i(import.meta.url)){const r=process.argv.slice(2)[0]||"stdio";async function s(){try{switch(r){case"stdio":await import("./transports/stdio.js");break;case"http":process.argv.push("--auto-run"),await import("./transports/http.js");break;default:console.error(`Unknown transport: ${r}`),console.error("Available transports: stdio, http"),process.exit(1)}}catch(a){console.error("Error running transport:",a),process.exit(1)}}t(s,"run"),s()}export{g as server};
2
+ var e=Object.defineProperty;var t=(o,r)=>e(o,"name",{value:r,configurable:!0});import{i}from"./server-BxXSw3gh.js";import{s as g}from"./server-BxXSw3gh.js";import"node:fs";import"node:url";import"@modelcontextprotocol/sdk/server/mcp.js";if(i(import.meta.url)){const r=process.argv.slice(2)[0]||"stdio";async function s(){try{switch(r){case"stdio":await import("./transports/stdio.js");break;case"http":process.argv.push("--auto-run"),await import("./transports/http.js");break;default:console.error(`Unknown transport: ${r}`),console.error("Available transports: stdio, http"),process.exit(1)}}catch(a){console.error("Error running transport:",a),process.exit(1)}}t(s,"run"),s()}export{g as server};
@@ -1 +1 @@
1
- var i=Object.defineProperty;var t=(e,r)=>i(e,"name",{value:r,configurable:!0});import{realpathSync as c}from"node:fs";import{pathToFileURL as f}from"node:url";import{McpServer as p}from"@modelcontextprotocol/sdk/server/mcp.js";async function u(e,r,n){const s=await fetch(e,r);if(!s.ok){const a=n??`fetch ${e}`;throw new Error(`Failed to ${a}: ${s.status} ${s.statusText}`)}return s.text()}t(u,"fetchMarkdown");function m(e,r){return e.type===r}t(m,"isNodeType");function v(e){return Array.from(new Set(e))}t(v,"uniq");function h(e){return e instanceof Error?e.message:"Unknown error"}t(h,"getErrorMessage");function g(e){if(!process.argv[1])return!1;const r=c(process.argv[1]),n=f(r);return e===n.href}t(g,"isEntryFile");var l="0.1.0-next.6",o={version:l};const w=new p({name:"Wave Design System",version:o.version,capabilities:{prompts:{},resources:{},tools:{}}});export{m as a,u as f,h as g,g as i,o as p,w as s,v as u};
1
+ var i=Object.defineProperty;var t=(e,r)=>i(e,"name",{value:r,configurable:!0});import{realpathSync as c}from"node:fs";import{pathToFileURL as f}from"node:url";import{McpServer as p}from"@modelcontextprotocol/sdk/server/mcp.js";async function u(e,r,n){const s=await fetch(e,r);if(!s.ok){const a=n??`fetch ${e}`;throw new Error(`Failed to ${a}: ${s.status} ${s.statusText}`)}return s.text()}t(u,"fetchMarkdown");function m(e,r){return e.type===r}t(m,"isNodeType");function v(e){return Array.from(new Set(e))}t(v,"uniq");function h(e){return e instanceof Error?e.message:"Unknown error"}t(h,"getErrorMessage");function g(e){if(!process.argv[1])return!1;const r=c(process.argv[1]),n=f(r);return e===n.href}t(g,"isEntryFile");var l="0.1.0-next.8",o={version:l};const w=new p({name:"Wave Design System",version:o.version,capabilities:{prompts:{},resources:{},tools:{}}});export{m as a,u as f,h as g,g as i,o as p,w as s,v as u};
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env node
2
- var h=Object.defineProperty;var i=(e,s)=>h(e,"name",{value:s,configurable:!0});import{StreamableHTTPServerTransport as f}from"@modelcontextprotocol/sdk/server/streamableHttp.js";import{isInitializeRequest as g}from"@modelcontextprotocol/sdk/types.js";import I from"cors";import l from"express";import{randomUUID as S}from"node:crypto";import{s as m,p as T,i as w}from"../server-Bn99IvSq.js";import{i as y}from"../index-DBfwM3Oy.js";import"node:fs";import"node:url";import"@modelcontextprotocol/sdk/server/mcp.js";import"@volue/design-colors/generic";import"@volue/design-icons";import"remark-parse";import"unified";import"zod";const t=l(),P=process.env.CORS_ORIGIN?.split(",")??"*";t.use(I({origin:P,exposedHeaders:["Mcp-Session-Id"],allowedHeaders:["Content-Type","mcp-session-id"]})),t.use(l.json());const r=new Map;t.post("/mcp",async(e,s)=>{const n=e.headers["mcp-session-id"];let o;if(n&&r.has(n))o=r.get(n);else if(!n&&g(e.body))o=new f({sessionIdGenerator:i(()=>S(),"sessionIdGenerator"),onsessioninitialized:i(v=>{r.set(v,o)},"onsessioninitialized")}),o.onclose=()=>{o.sessionId&&r.has(o.sessionId)&&r.delete(o.sessionId)},await y(m),await m.connect(o);else return s.status(400).json({error:{message:"Bad Request: No valid session ID provided"}});await o.handleRequest(e,s,e.body)});const d=i(async(e,s)=>{const n=e.headers["mcp-session-id"];if(!n||!r.has(n))return s.status(404).send("Invalid or missing session ID");await r.get(n).handleRequest(e,s)},"handleSessionRequest");t.get("/mcp",d),t.delete("/mcp",d),t.get("/",(e,s)=>{s.json({name:"Wave MCP Server",version:T.version,description:"MCP server for Wave Design System",endpoints:{"/":"Server information (this response)","/mcp":"Streamable HTTP endpoint for MCP connection","/health":"Health check endpoint"}})}),t.get("/health",(e,s)=>{s.json({status:"healthy",timestamp:new Date().toISOString(),uptime:process.uptime()})});const a=process.env.HOST??"localhost",p=process.env.PORT?Number(process.env.PORT):3e3;let c=null;(process.argv.includes("--auto-run")||w(import.meta.url))&&(c=t.listen(p,a,e=>{e&&(console.error("\u274C Failed to start server:",e),process.exit(1)),console.log(`\u{1F680} Wave MCP Server running on http://${a}:${p}`),console.log(`\u{1F517} Connect via http://${a}:${p}/mcp`)}));const u=i(async()=>{const e=Array.from(r.values()).map(s=>s.close());c&&e.push(new Promise(s=>c.close(()=>s()))),await Promise.allSettled(e),console.log("\u{1F44B} Server shut down gracefully"),process.exit(0)},"cleanup");process.on("SIGTERM",u),process.on("SIGINT",u);export{t as default};
2
+ var h=Object.defineProperty;var i=(e,s)=>h(e,"name",{value:s,configurable:!0});import{StreamableHTTPServerTransport as f}from"@modelcontextprotocol/sdk/server/streamableHttp.js";import{isInitializeRequest as g}from"@modelcontextprotocol/sdk/types.js";import I from"cors";import l from"express";import{randomUUID as S}from"node:crypto";import{s as m,p as T,i as w}from"../server-BxXSw3gh.js";import{i as y}from"../index-381M0Zp2.js";import"node:fs";import"node:url";import"@modelcontextprotocol/sdk/server/mcp.js";import"@volue/design-colors/generic";import"@volue/design-icons";import"@volue/wave-react/tokens";import"remark-parse";import"unified";import"zod";const t=l(),P=process.env.CORS_ORIGIN?.split(",")??"*";t.use(I({origin:P,exposedHeaders:["Mcp-Session-Id"],allowedHeaders:["Content-Type","mcp-session-id"]})),t.use(l.json());const r=new Map;t.post("/mcp",async(e,s)=>{const n=e.headers["mcp-session-id"];let o;if(n&&r.has(n))o=r.get(n);else if(!n&&g(e.body))o=new f({sessionIdGenerator:i(()=>S(),"sessionIdGenerator"),onsessioninitialized:i(v=>{r.set(v,o)},"onsessioninitialized")}),o.onclose=()=>{o.sessionId&&r.has(o.sessionId)&&r.delete(o.sessionId)},await y(m),await m.connect(o);else return s.status(400).json({error:{message:"Bad Request: No valid session ID provided"}});await o.handleRequest(e,s,e.body)});const d=i(async(e,s)=>{const n=e.headers["mcp-session-id"];if(!n||!r.has(n))return s.status(404).send("Invalid or missing session ID");await r.get(n).handleRequest(e,s)},"handleSessionRequest");t.get("/mcp",d),t.delete("/mcp",d),t.get("/",(e,s)=>{s.json({name:"Wave MCP Server",version:T.version,description:"MCP server for Wave Design System",endpoints:{"/":"Server information (this response)","/mcp":"Streamable HTTP endpoint for MCP connection","/health":"Health check endpoint"}})}),t.get("/health",(e,s)=>{s.json({status:"healthy",timestamp:new Date().toISOString(),uptime:process.uptime()})});const a=process.env.HOST??"localhost",p=process.env.PORT?Number(process.env.PORT):3e3;let c=null;(process.argv.includes("--auto-run")||w(import.meta.url))&&(c=t.listen(p,a,e=>{e&&(console.error("\u274C Failed to start server:",e),process.exit(1)),console.log(`\u{1F680} Wave MCP Server running on http://${a}:${p}`),console.log(`\u{1F517} Connect via http://${a}:${p}/mcp`)}));const u=i(async()=>{const e=Array.from(r.values()).map(s=>s.close());c&&e.push(new Promise(s=>c.close(()=>s()))),await Promise.allSettled(e),console.log("\u{1F44B} Server shut down gracefully"),process.exit(0)},"cleanup");process.on("SIGTERM",u),process.on("SIGINT",u);export{t as default};
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env node
2
- var s=Object.defineProperty;var t=(o,r)=>s(o,"name",{value:r,configurable:!0});import{StdioServerTransport as e}from"@modelcontextprotocol/sdk/server/stdio.js";import{s as i}from"../server-Bn99IvSq.js";import{i as a}from"../index-DBfwM3Oy.js";import"node:fs";import"node:url";import"@modelcontextprotocol/sdk/server/mcp.js";import"@volue/design-colors/generic";import"@volue/design-icons";import"remark-parse";import"unified";import"zod";async function p(){await a(i);const o=new e;await i.connect(o);const r=t(async()=>{await o.close(),process.exit(0)},"cleanup");process.on("SIGTERM",r),process.on("SIGINT",r)}t(p,"main"),p().catch(o=>{console.error("\u274C Failed to start server:",o),process.exit(1)});
2
+ var s=Object.defineProperty;var t=(o,r)=>s(o,"name",{value:r,configurable:!0});import{StdioServerTransport as e}from"@modelcontextprotocol/sdk/server/stdio.js";import{s as i}from"../server-BxXSw3gh.js";import{i as p}from"../index-381M0Zp2.js";import"node:fs";import"node:url";import"@modelcontextprotocol/sdk/server/mcp.js";import"@volue/design-colors/generic";import"@volue/design-icons";import"@volue/wave-react/tokens";import"remark-parse";import"unified";import"zod";async function a(){await p(i);const o=new e;await i.connect(o);const r=t(async()=>{await o.close(),process.exit(0)},"cleanup");process.on("SIGTERM",r),process.on("SIGINT",r)}t(a,"main"),a().catch(o=>{console.error("\u274C Failed to start server:",o),process.exit(1)});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@volue/wave-mcp",
3
- "version": "0.1.0-next.6",
3
+ "version": "0.1.0-next.8",
4
4
  "description": "An MCP server that connects AI tools to the Wave Design System",
5
5
  "license": "UNLICENSED",
6
6
  "repository": {
@@ -44,7 +44,7 @@
44
44
  "test": "run-p lint:types lint \"_prettier --check\"",
45
45
  "clean": "premove dist",
46
46
  "build": "yarn run clean && pkgroll --minify",
47
- "start": "yarn run build && node dist/transports/http.js",
47
+ "start": "yarn run build && yarn node dist/transports/http.js",
48
48
  "dev": "tsx watch --clear-screen=false src/transports/http.ts",
49
49
  "prepack": "yarn run build",
50
50
  "inspect": "yarn run build && yarn dlx -q @modelcontextprotocol/inspector --transport=stdio node dist/transports/stdio.js",
@@ -55,8 +55,9 @@
55
55
  "@types/cors": "2.8.19",
56
56
  "@types/express": "5.0.3",
57
57
  "@types/express-serve-static-core": "5.0.7",
58
- "@volue/design-colors": "^3.0.10-next.4",
59
- "@volue/design-icons": "^1.9.4-next.4",
58
+ "@volue/design-colors": "^3.0.10-next.5",
59
+ "@volue/design-icons": "^1.9.4-next.5",
60
+ "@volue/wave-react": "^1.3.0-next.9",
60
61
  "cors": "2.8.5",
61
62
  "express": "5.1.0",
62
63
  "remark-parse": "8.0.3",
@@ -1,71 +0,0 @@
1
- var k=Object.defineProperty;var r=(e,t)=>k(e,"name",{value:t,configurable:!0});import{a as u,f as p,u as f,g as m}from"./server-Bn99IvSq.js";import N from"@volue/design-colors/generic";import*as W from"@volue/design-icons";import I from"remark-parse";import A from"unified";import{z as g}from"zod";const j=A().use(I),$={Components:"component","UX patterns":"pattern"};function F(e,t){const o=j.parse(e);let n=null;return o.children.reduce((a,i)=>{if(u(i,"heading")&&i.depth===2)return n=B(i),a;if(!n||!u(i,"list"))return a;const s=n,c=i.children.map(l=>P(l,s,t)).filter(l=>l!==null);return a.concat(c)},[])}r(F,"parseLlmsIndex");function B(e){const[t]=e.children;if(!t||!u(t,"text"))return null;const o=t.value.trim();if(!(o in $))return null;const n=$[o];return{title:o,type:n}}r(B,"extractSectionContext");function P(e,t,o){const[n]=e.children;if(!n||!u(n,"paragraph")||n.children.length!==2)return null;const[a,i]=n.children;if(!u(a,"link")||!u(i,"text")||a.children.length!==1)return null;const s=a.children[0];if(!u(s,"text"))return null;const c=s.value.trim(),l=a.url.replace(/^\//,""),L=new URL(l,`${o}/`).toString(),R=O(l),D=M(t.title,l,t.type),U=z(i.value);return{name:c,slug:R,category:D,section:t.title,type:t.type,url:L,description:U??void 0}}r(P,"listItemToResource");function O(e){return e.replace(/\.md$/,"").split("/").pop()??""}r(O,"deriveSlug");function M(e,t,o){const n=t.replace(/\.md$/,"").split("/");if(o==="component"||o==="pattern"){const a=n.length>=3?n[n.length-2]:null;return a?`${e} / ${V(a)}`:e}return e}r(M,"deriveCategory");function V(e){return e.split("-").filter(Boolean).map(t=>t.charAt(0).toUpperCase()+t.slice(1)).join(" ")}r(V,"formatSegment");function z(e){if(!e)return null;const t=e.replace(/^\s*:\s*/,"").trim();return t.toLowerCase()==="no description available"?null:t}r(z,"normalizeDescription");const h=process.env.USE_STABLE_DOCS==="true"||process.env.USE_STABLE_DOCS==="1"?"https://wave.volue.com":"https://wave-design-system.vercel.app",H=`${h}/llms.txt`,X=1e3*60*15,G=process.env.WAVE_RESOURCES_CACHE_TIME?Number.parseInt(process.env.WAVE_RESOURCES_CACHE_TIME,10):X;function y(e){const t=new URL(e,h);return t.pathname.endsWith(".md")||(t.pathname+=".md"),t.toString()}r(y,"createUrl");let v=null,E=0;async function q(){if(v!==null&&Date.now()<E)return v;const e=await J();return v=e,E=Date.now()+G,e}r(q,"listCachedResources");let d=null;async function J(){return d||(d=Y().finally(()=>{d=null})),d}r(J,"idempotentLoadResourcesFromLlms");async function Y(){const e=await p(H,void 0,"fetch llms.txt");return F(e,h)}r(Y,"loadResourcesFromLlms");async function K(e){return p(e.url,void 0,`fetch ${e.name} documentation`)}r(K,"fetchComponent");function Q(e){return p(e.url,void 0,`fetch ${e.name} pattern`)}r(Q,"fetchPattern");async function Z(){return p(y("get-started/developing"),void 0,"fetch developing guide")}r(Z,"fetchDevelopingGuide");async function ee(){return p(y("tokens/colors"),void 0,"fetch color usage guidelines")}r(ee,"fetchColorUsageGuidelines");function x(){return Object.entries(W).map(([e,t])=>({name:e,svg:t}))}r(x,"listIcons");function te(){const e=x();return f(e.map(t=>t.name))}r(te,"getIconNames");function ne(e,t){const o=t.trim().toLowerCase();return e.find(n=>n.name.toLowerCase()===o)}r(ne,"findIconByName");async function C(e){return(await q()).filter(o=>o.type===e)}r(C,"listResourcesByType");function T(e,t){const o=t.trim().toLowerCase();return e.find(n=>n.name.toLowerCase()===o)}r(T,"findResourceByName");function w(){return C("component")}r(w,"listComponents");async function oe(){const e=await w();return f(e.map(t=>t.name))}r(oe,"getComponentNames");function S(){return C("pattern")}r(S,"listPatterns");async function re(){const e=await S();return f(e.map(t=>t.name))}r(re,"getPatternNames");function b(e){return e.reduce((t,o)=>(t[o.category]||(t[o.category]=[]),t[o.category].push(o),t),{})}r(b,"groupResourcesByCategory");const ae={name:"get_color_usage",description:"Retrieve the Wave Design System color tokens and guidelines for applying color in user interfaces.",exec(e,{name:t,description:o}){e.tool(t,o,async()=>{try{const n=await ee();return{content:[{type:"text",text:JSON.stringify(N)},{type:"text",text:`Here are the Wave Design System color usage guidelines:
2
-
3
- ${n}
4
-
5
- ---
6
- Source: ${y("tokens/colors")}`}]}}catch(n){return{isError:!0,content:[{type:"text",text:`Failed to retrieve color usage guidelines: ${m(n)}`}]}}})}},ie={name:"get_component",description:"Retrieve comprehensive documentation for a specific Wave Design System component by name. This tool retrieves the import instructions, basic usage and advanced configuration examples, code snippets for common scenarios, available props/properties table and some general guidelines for a given Wave Design System component.",async ctx(){try{return{componentNames:await oe()}}catch(e){throw new Error(`Failed to initialize component tool: ${m(e)}`)}},exec(e,{ctx:t,name:o,description:n}){e.tool(o,n,{name:g.enum(t.componentNames).describe("The name of the component to retrieve documentation for. This can be derived from calling the `get_components` tool.")},async({name:a})=>{try{const i=await w(),s=T(i,a);if(!s)throw new Error("Component not found");const c=await K(s);return c?{content:[{type:"text",text:`Here is the documentation for the \`${s.name}\` component from the Wave Design System:
7
-
8
- ${c}
9
-
10
- ---
11
- Source: ${s.url}`}]}:{content:[{type:"text",text:`No documentation content found for the \`${s.name}\` component.`}]}}catch(i){return{isError:!0,content:[{type:"text",text:`Failed to retrieve documentation for \`${a}\`: ${m(i)}`}]}}})}},se={name:"get_icon",description:"Retrieve a specific icon information by name from Wave Design System.",exec(e,{name:t,description:o}){e.tool(t,o,{name:g.enum(te()).describe("The icon name to retrieve. This can be derived from calling the `list_icon` tool.")},async({name:n})=>{try{const a=x(),i=ne(a,n);if(!i)throw new Error("Icon not found.");const s=`<SvgIcon iconName="${i.name}" />`,c=`<div class="svgIcon svgIcon--stroked">
12
- <svg focusable="false" aria-hidden="true">
13
- <use xlink:href="#svg--${i.name}"></use>
14
- </svg>
15
- </div>`;return{content:[{type:"text",text:`# ${i.name} icon
16
-
17
- ## React component:
18
-
19
- \`\`\`tsx
20
- ${s}
21
- \`\`\`
22
-
23
- ## HTML markup:
24
-
25
- \`\`\`html
26
- ${c}
27
- \`\`\`
28
-
29
- ## Raw SVG code:
30
-
31
- \`\`\`svg
32
- ${i.svg}
33
- \`\`\``}]}}catch(a){return{isError:!0,content:[{type:"text",text:`Failed to retrieve icon \`${n}\`: ${m(a)}`}]}}})}},ce={name:"get_pattern",description:"Retrieve documentation for a specific Wave Design System UX pattern by name. This tool provides guidance, examples and components that implement the selected pattern.",async ctx(){try{return{patternNames:await re()}}catch(e){throw new Error(`Failed to initialize pattern tool: ${m(e)}`)}},exec(e,{ctx:t,name:o,description:n}){e.tool(o,n,{name:g.enum(t.patternNames).describe("The name of the UX pattern to retrieve documentation for. This can be derived from calling the `list_patterns` tool.")},async({name:a})=>{try{const i=await S(),s=T(i,a);if(!s)throw new Error("Pattern not found");const c=await Q(s);return{content:[{type:"text",text:`Here are the guidelines for the \`${s.name}\` UX pattern from the Wave Design System:
34
-
35
- ${c}
36
-
37
- ---
38
- Source: ${s.url}`}]}}catch(i){return{isError:!0,content:[{type:"text",text:`Failed to retrieve documentation for \`${a}\`: ${m(i)}`}]}}})}},le={name:"init",description:"Get guide on how to setup or create a project that includes Wave Design System.",exec(e,{name:t,description:o}){e.tool(t,o,async()=>{try{return{content:[{type:"text",text:`The getting started documentation for developing with Wave Design System is included below.
39
-
40
- It's **important** that if the project is using a tool like Vite or Next.js, one of the pre-configured starter templates should be used instead of manual configuration:
41
-
42
- - https://github.com/Volue/wave-vite-example (Vite template)
43
- - https://github.com/Volue/wave-nextjs-app-router-example (Next.js App Router template)
44
-
45
- ---
46
-
47
- ${await Z()}
48
- `}]}}catch(n){return{isError:!0,content:[{type:"text",text:`Failed to retrieve getting started documentation: ${m(n)}`}]}}})}},me={name:"list_components",description:"List all components available from the Wave Design System. This tool retrieves the names of all available Wave Design System components grouped by category.",exec(e,{name:t,description:o}){e.tool(t,o,async()=>{try{const n=await w(),a=b(n);return{content:[{type:"text",text:`The following components are available in the Wave Design System:
49
-
50
- ${Object.entries(a).map(([s,c])=>`## ${s}
51
- ${c.map(l=>`- ${l.name}`).join(`
52
- `)}`).join(`
53
-
54
- `)}
55
-
56
- Use the \`get_component\` tool to get more information about a specific component.
57
-
58
- Use these components from the @volue/wave-react package.`}]}}catch(n){return{isError:!0,content:[{type:"text",text:`Failed to retrieve the component index: ${m(n)}`}]}}})}},ue={name:"list_icons",description:"List all icons available from the Wave Design System. Icons are sourced directly from the `@volue/design-icons` package.",exec(e,{name:t,description:o}){e.tool(t,o,async()=>{try{return{content:[{type:"text",text:`The following icons are available in the Wave Design System:
59
-
60
- ${x().map(i=>`- ${i.name}`).join(`
61
- `)}
62
-
63
- Use the \`get_icon\` tool to retrieve the SVG markup and usage guidelines for a specific icon.`}]}}catch(n){return{isError:!0,content:[{type:"text",text:`Failed to retrieve the icon data: ${m(n)}`}]}}})}},pe={name:"list_patterns",description:"List all UX patterns available from the Wave Design System. This tool retrieves the names of all available Wave Design System patterns grouped by category.",exec(e,{name:t,description:o}){e.tool(t,o,async()=>{try{const n=await S(),a=b(n);return{content:[{type:"text",text:`The following UX patterns are available in the Wave Design System:
64
-
65
- ${Object.entries(a).map(([s,c])=>`## ${s}
66
- ${c.map(l=>`- ${l.name}`).join(`
67
- `)}`).join(`
68
-
69
- `)}
70
-
71
- Use the \`get_pattern\` tool to access detailed guidance for a specific pattern.`}]}}catch(n){return{isError:!0,content:[{type:"text",text:`Failed to retrieve the pattern index: ${m(n)}`}]}}})}},de=[le,me,ie,pe,ce,ae,ue,se],_=new Set;async function fe(e){await Promise.all(de.map(async t=>{if(_.has(t.name))return;const o=await t.ctx?.();_.add(t.name),t.exec(e,{name:t.name,description:t.description,ctx:o})}))}r(fe,"initializeTools");export{fe as i};