[{"data":1,"prerenderedAt":2227},["ShallowReactive",2],{"article:building-an-mcp-server-for-a-vue-design-system":3,"\u002Fblog\u002Fbuilding-an-mcp-server-for-a-vue-design-system-surround":2216},{"id":4,"title":5,"archived":6,"author":7,"body":8,"date":2202,"description":2203,"extension":2204,"image":2205,"meta":2206,"minRead":284,"navigation":606,"path":2207,"published":606,"seo":2208,"sitemap":2209,"stem":2210,"tags":2211,"__hash__":2215},"blog\u002Fblog\u002Fbuilding-an-mcp-server-for-a-vue-design-system.md","Building an MCP Server for a Vue Design System",false,"Baljeet Singh",{"type":9,"value":10,"toc":2188},"minimark",[11,15,18,45,48,53,56,63,69,75,83,87,90,97,107,114,117,121,124,129,132,515,522,526,529,899,921,925,935,1064,1067,1276,1279,1585,1588,1594,1611,1617,1621,1780,1784,1920,1927,2024,2028,2031,2129,2132,2139,2143,2156,2160,2163,2168,2175,2178,2181,2184],[12,13,14],"p",{},"I maintain a Vue design system called Empathy DS. Sixty components, each with its own props, variants and slots, published to npm and documented on a site.",[12,16,17],{},"For a while, every AI assistant I pointed at it wrote code that looked right and was wrong.",[12,19,20,24,25,28,29,32,33,36,37,40,41,44],{},[21,22,23],"code",{},"\u003CEInput variant=\"ghost\" \u002F>",". There is no ",[21,26,27],{},"ghost"," variant on ",[21,30,31],{},"EInput",". ",[21,34,35],{},"size=\"md\""," passed to a component that takes ",[21,38,39],{},"dense",". A ",[21,42,43],{},"DataTable"," imported confidently, because most design systems have one and mine does not.",[12,46,47],{},"None of it was a syntax error. It was plausible, well-formed, and silently incorrect — the worst kind. You only find out when the styles do not apply.",[49,50,52],"h2",{"id":51},"what-i-tried-first","What I Tried First",[12,54,55],{},"The obvious things, in the obvious order.",[12,57,58,62],{},[59,60,61],"strong",{},"Better prompts."," I described the naming conventions. I explained that variants are semantic, not visual. This worked for about three messages, then the model drifted back.",[12,64,65,68],{},[59,66,67],{},"More examples in context."," I pasted component usage into the system prompt. Sixty components will not fit, so I pasted the ten I used most. The model got those ten right and invented harder for the other fifty.",[12,70,71,74],{},[59,72,73],{},"A longer system message."," I wrote a document about the design system's philosophy. It made the model more confident, not more correct.",[12,76,77,78,82],{},"Every attempt was the same idea: ",[79,80,81],"em",{},"if I describe this well enough, it will stop making things up."," That idea is wrong, and it took me too long to see why.",[49,84,86],{"id":85},"the-reframe","The Reframe",[12,88,89],{},"The model was not failing to understand my design system. It had never seen my design system. It was doing what it does when it lacks information — producing the most probable-looking answer.",[12,91,92,93,96],{},"And ",[21,94,95],{},"variant=\"ghost\""," is a very probable-looking answer. Shadcn has it. Chakra has something like it. The model is not hallucinating in a vacuum. It's completing a pattern from every other component library it has read, because mine was not available to it.",[12,98,99,100,103,104],{},"So the question is not ",[79,101,102],{},"how do I describe my components better."," It is ",[59,105,106],{},"why is it guessing at all?",[12,108,109,110,113],{},"I already had the answer in my repo. I generate a ",[21,111,112],{},"registry.json"," for the docs site — every component with its name, description, category, props and examples. 112KB of exactly what the model was inventing.",[12,115,116],{},"It just had no way to ask for it.",[49,118,120],{"id":119},"the-fix","The Fix",[12,122,123],{},"I published the registry as an MCP server. Here's the whole thing, in build order. It's small enough to copy.",[125,126,128],"h3",{"id":127},"_1-generate-a-registry","1. Generate a Registry",[12,130,131],{},"You probably already have this data. I emit one JSON file from the monorepo at build time and ship it with the docs:",[133,134,139],"pre",{"className":135,"code":136,"language":137,"meta":138,"style":138},"language-json shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","{\n  \"version\": \"1.0.0\",\n  \"packageName\": \"@empathyds\u002Fvue\",\n  \"totalComponents\": 60,\n  \"components\": [\n    {\n      \"name\": \"accordion\",\n      \"description\": \"A vertically stacked set of interactive headings.\",\n      \"category\": \"Layout\",\n      \"props\": [\n        { \"name\": \"modelValue\", \"type\": \"string | string[]\", \"description\": \"Open item(s)\" },\n        { \"name\": \"type\", \"type\": \"'single' | 'multiple'\", \"default\": \"'single'\" }\n      ],\n      \"examples\": [\"\u003CEAccordion type=\\\"single\\\" collapsible>…\u003C\u002FEAccordion>\"],\n      \"docsUrl\": \"https:\u002F\u002Fempathyds.com\u002Fcomponents\u002Faccordion\"\n    }\n  ]\n}\n","json","",[21,140,141,150,178,199,217,232,238,261,282,303,317,377,434,440,477,497,503,509],{"__ignoreMap":138},[142,143,146],"span",{"class":144,"line":145},"line",1,[142,147,149],{"class":148},"sMK4o","{\n",[142,151,153,156,160,163,166,169,173,175],{"class":144,"line":152},2,[142,154,155],{"class":148},"  \"",[142,157,159],{"class":158},"spNyl","version",[142,161,162],{"class":148},"\"",[142,164,165],{"class":148},":",[142,167,168],{"class":148}," \"",[142,170,172],{"class":171},"sfazB","1.0.0",[142,174,162],{"class":148},[142,176,177],{"class":148},",\n",[142,179,181,183,186,188,190,192,195,197],{"class":144,"line":180},3,[142,182,155],{"class":148},[142,184,185],{"class":158},"packageName",[142,187,162],{"class":148},[142,189,165],{"class":148},[142,191,168],{"class":148},[142,193,194],{"class":171},"@empathyds\u002Fvue",[142,196,162],{"class":148},[142,198,177],{"class":148},[142,200,202,204,207,209,211,215],{"class":144,"line":201},4,[142,203,155],{"class":148},[142,205,206],{"class":158},"totalComponents",[142,208,162],{"class":148},[142,210,165],{"class":148},[142,212,214],{"class":213},"sbssI"," 60",[142,216,177],{"class":148},[142,218,220,222,225,227,229],{"class":144,"line":219},5,[142,221,155],{"class":148},[142,223,224],{"class":158},"components",[142,226,162],{"class":148},[142,228,165],{"class":148},[142,230,231],{"class":148}," [\n",[142,233,235],{"class":144,"line":234},6,[142,236,237],{"class":148},"    {\n",[142,239,241,244,248,250,252,254,257,259],{"class":144,"line":240},7,[142,242,243],{"class":148},"      \"",[142,245,247],{"class":246},"sBMFI","name",[142,249,162],{"class":148},[142,251,165],{"class":148},[142,253,168],{"class":148},[142,255,256],{"class":171},"accordion",[142,258,162],{"class":148},[142,260,177],{"class":148},[142,262,264,266,269,271,273,275,278,280],{"class":144,"line":263},8,[142,265,243],{"class":148},[142,267,268],{"class":246},"description",[142,270,162],{"class":148},[142,272,165],{"class":148},[142,274,168],{"class":148},[142,276,277],{"class":171},"A vertically stacked set of interactive headings.",[142,279,162],{"class":148},[142,281,177],{"class":148},[142,283,285,287,290,292,294,296,299,301],{"class":144,"line":284},9,[142,286,243],{"class":148},[142,288,289],{"class":246},"category",[142,291,162],{"class":148},[142,293,165],{"class":148},[142,295,168],{"class":148},[142,297,298],{"class":171},"Layout",[142,300,162],{"class":148},[142,302,177],{"class":148},[142,304,306,308,311,313,315],{"class":144,"line":305},10,[142,307,243],{"class":148},[142,309,310],{"class":246},"props",[142,312,162],{"class":148},[142,314,165],{"class":148},[142,316,231],{"class":148},[142,318,320,323,325,327,329,331,333,336,338,341,343,346,348,350,352,355,357,359,361,363,365,367,369,372,374],{"class":144,"line":319},11,[142,321,322],{"class":148},"        {",[142,324,168],{"class":148},[142,326,247],{"class":213},[142,328,162],{"class":148},[142,330,165],{"class":148},[142,332,168],{"class":148},[142,334,335],{"class":171},"modelValue",[142,337,162],{"class":148},[142,339,340],{"class":148},",",[142,342,168],{"class":148},[142,344,345],{"class":213},"type",[142,347,162],{"class":148},[142,349,165],{"class":148},[142,351,168],{"class":148},[142,353,354],{"class":171},"string | string[]",[142,356,162],{"class":148},[142,358,340],{"class":148},[142,360,168],{"class":148},[142,362,268],{"class":213},[142,364,162],{"class":148},[142,366,165],{"class":148},[142,368,168],{"class":148},[142,370,371],{"class":171},"Open item(s)",[142,373,162],{"class":148},[142,375,376],{"class":148}," },\n",[142,378,380,382,384,386,388,390,392,394,396,398,400,402,404,406,408,411,413,415,417,420,422,424,426,429,431],{"class":144,"line":379},12,[142,381,322],{"class":148},[142,383,168],{"class":148},[142,385,247],{"class":213},[142,387,162],{"class":148},[142,389,165],{"class":148},[142,391,168],{"class":148},[142,393,345],{"class":171},[142,395,162],{"class":148},[142,397,340],{"class":148},[142,399,168],{"class":148},[142,401,345],{"class":213},[142,403,162],{"class":148},[142,405,165],{"class":148},[142,407,168],{"class":148},[142,409,410],{"class":171},"'single' | 'multiple'",[142,412,162],{"class":148},[142,414,340],{"class":148},[142,416,168],{"class":148},[142,418,419],{"class":213},"default",[142,421,162],{"class":148},[142,423,165],{"class":148},[142,425,168],{"class":148},[142,427,428],{"class":171},"'single'",[142,430,162],{"class":148},[142,432,433],{"class":148}," }\n",[142,435,437],{"class":144,"line":436},13,[142,438,439],{"class":148},"      ],\n",[142,441,443,445,448,450,452,455,457,460,464,467,469,472,474],{"class":144,"line":442},14,[142,444,243],{"class":148},[142,446,447],{"class":246},"examples",[142,449,162],{"class":148},[142,451,165],{"class":148},[142,453,454],{"class":148}," [",[142,456,162],{"class":148},[142,458,459],{"class":171},"\u003CEAccordion type=",[142,461,463],{"class":462},"sTEyZ","\\\"",[142,465,466],{"class":171},"single",[142,468,463],{"class":462},[142,470,471],{"class":171}," collapsible>…\u003C\u002FEAccordion>",[142,473,162],{"class":148},[142,475,476],{"class":148},"],\n",[142,478,480,482,485,487,489,491,494],{"class":144,"line":479},15,[142,481,243],{"class":148},[142,483,484],{"class":246},"docsUrl",[142,486,162],{"class":148},[142,488,165],{"class":148},[142,490,168],{"class":148},[142,492,493],{"class":171},"https:\u002F\u002Fempathyds.com\u002Fcomponents\u002Faccordion",[142,495,496],{"class":148},"\"\n",[142,498,500],{"class":144,"line":499},16,[142,501,502],{"class":148},"    }\n",[142,504,506],{"class":144,"line":505},17,[142,507,508],{"class":148},"  ]\n",[142,510,512],{"class":144,"line":511},18,[142,513,514],{"class":148},"}\n",[12,516,517,518,521],{},"Mine is 112KB for 60 components. The important bit is that it is ",[59,519,520],{},"generated",", so it cannot drift from the components.",[125,523,525],{"id":524},"_2-fetch-it-with-a-cache","2. Fetch It, With a Cache",[12,527,528],{},"The server does not bundle the data. It fetches the deployed file, so it is never stale against the published docs:",[133,530,534],{"className":531,"code":532,"language":533,"meta":138,"style":138},"language-ts shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","const CACHE_TTL = 5 * 60 * 1000;\nlet registryCache: Registry | null = null;\nlet registryCacheTime = 0;\n\nasync function getRegistry(): Promise\u003CRegistry | null> {\n  if (registryCache && Date.now() - registryCacheTime \u003C CACHE_TTL) {\n    return registryCache;\n  }\n  try {\n    const response = await fetch(mcpConfig.registryUrl);\n    if (!response.ok) throw new Error(`Failed to fetch registry: ${response.statusText}`);\n    registryCache = await response.json();\n    registryCacheTime = Date.now();\n    return registryCache;\n  } catch (error) {\n    console.error('Error fetching remote registry:', error);\n    return null;\n  }\n}\n","ts",[21,535,536,563,588,602,608,642,687,696,701,708,740,794,814,831,839,856,884,890,894],{"__ignoreMap":138},[142,537,538,541,544,547,550,553,555,557,560],{"class":144,"line":145},[142,539,540],{"class":158},"const",[142,542,543],{"class":462}," CACHE_TTL ",[142,545,546],{"class":148},"=",[142,548,549],{"class":213}," 5",[142,551,552],{"class":148}," *",[142,554,214],{"class":213},[142,556,552],{"class":148},[142,558,559],{"class":213}," 1000",[142,561,562],{"class":148},";\n",[142,564,565,568,571,573,576,579,582,585],{"class":144,"line":152},[142,566,567],{"class":158},"let",[142,569,570],{"class":462}," registryCache",[142,572,165],{"class":148},[142,574,575],{"class":246}," Registry",[142,577,578],{"class":148}," |",[142,580,581],{"class":246}," null",[142,583,584],{"class":148}," =",[142,586,587],{"class":148}," null;\n",[142,589,590,592,595,597,600],{"class":144,"line":180},[142,591,567],{"class":158},[142,593,594],{"class":462}," registryCacheTime ",[142,596,546],{"class":148},[142,598,599],{"class":213}," 0",[142,601,562],{"class":148},[142,603,604],{"class":144,"line":201},[142,605,607],{"emptyLinePlaceholder":606},true,"\n",[142,609,610,613,616,620,623,626,629,632,634,636,639],{"class":144,"line":219},[142,611,612],{"class":158},"async",[142,614,615],{"class":158}," function",[142,617,619],{"class":618},"s2Zo4"," getRegistry",[142,621,622],{"class":148},"():",[142,624,625],{"class":246}," Promise",[142,627,628],{"class":148},"\u003C",[142,630,631],{"class":246},"Registry",[142,633,578],{"class":148},[142,635,581],{"class":246},[142,637,638],{"class":148},">",[142,640,641],{"class":148}," {\n",[142,643,644,648,652,655,658,661,664,667,670,673,676,679,682,685],{"class":144,"line":234},[142,645,647],{"class":646},"s7zQu","  if",[142,649,651],{"class":650},"swJcz"," (",[142,653,654],{"class":462},"registryCache",[142,656,657],{"class":148}," &&",[142,659,660],{"class":462}," Date",[142,662,663],{"class":148},".",[142,665,666],{"class":618},"now",[142,668,669],{"class":650},"() ",[142,671,672],{"class":148},"-",[142,674,675],{"class":462}," registryCacheTime",[142,677,678],{"class":148}," \u003C",[142,680,681],{"class":462}," CACHE_TTL",[142,683,684],{"class":650},") ",[142,686,149],{"class":148},[142,688,689,692,694],{"class":144,"line":240},[142,690,691],{"class":646},"    return",[142,693,570],{"class":462},[142,695,562],{"class":148},[142,697,698],{"class":144,"line":263},[142,699,700],{"class":148},"  }\n",[142,702,703,706],{"class":144,"line":284},[142,704,705],{"class":646},"  try",[142,707,641],{"class":148},[142,709,710,713,716,718,721,724,727,730,732,735,738],{"class":144,"line":305},[142,711,712],{"class":158},"    const",[142,714,715],{"class":462}," response",[142,717,584],{"class":148},[142,719,720],{"class":646}," await",[142,722,723],{"class":618}," fetch",[142,725,726],{"class":650},"(",[142,728,729],{"class":462},"mcpConfig",[142,731,663],{"class":148},[142,733,734],{"class":462},"registryUrl",[142,736,737],{"class":650},")",[142,739,562],{"class":148},[142,741,742,745,747,750,753,755,758,760,763,766,769,771,774,777,780,782,784,787,790,792],{"class":144,"line":319},[142,743,744],{"class":646},"    if",[142,746,651],{"class":650},[142,748,749],{"class":148},"!",[142,751,752],{"class":462},"response",[142,754,663],{"class":148},[142,756,757],{"class":462},"ok",[142,759,684],{"class":650},[142,761,762],{"class":646},"throw",[142,764,765],{"class":148}," new",[142,767,768],{"class":618}," Error",[142,770,726],{"class":650},[142,772,773],{"class":148},"`",[142,775,776],{"class":171},"Failed to fetch registry: ",[142,778,779],{"class":148},"${",[142,781,752],{"class":462},[142,783,663],{"class":148},[142,785,786],{"class":462},"statusText",[142,788,789],{"class":148},"}`",[142,791,737],{"class":650},[142,793,562],{"class":148},[142,795,796,799,801,803,805,807,809,812],{"class":144,"line":379},[142,797,798],{"class":462},"    registryCache",[142,800,584],{"class":148},[142,802,720],{"class":646},[142,804,715],{"class":462},[142,806,663],{"class":148},[142,808,137],{"class":618},[142,810,811],{"class":650},"()",[142,813,562],{"class":148},[142,815,816,819,821,823,825,827,829],{"class":144,"line":436},[142,817,818],{"class":462},"    registryCacheTime",[142,820,584],{"class":148},[142,822,660],{"class":462},[142,824,663],{"class":148},[142,826,666],{"class":618},[142,828,811],{"class":650},[142,830,562],{"class":148},[142,832,833,835,837],{"class":144,"line":442},[142,834,691],{"class":646},[142,836,570],{"class":462},[142,838,562],{"class":148},[142,840,841,844,847,849,852,854],{"class":144,"line":479},[142,842,843],{"class":148},"  }",[142,845,846],{"class":646}," catch",[142,848,651],{"class":650},[142,850,851],{"class":462},"error",[142,853,684],{"class":650},[142,855,149],{"class":148},[142,857,858,861,863,865,867,870,873,875,877,880,882],{"class":144,"line":499},[142,859,860],{"class":462},"    console",[142,862,663],{"class":148},[142,864,851],{"class":618},[142,866,726],{"class":650},[142,868,869],{"class":148},"'",[142,871,872],{"class":171},"Error fetching remote registry:",[142,874,869],{"class":148},[142,876,340],{"class":148},[142,878,879],{"class":462}," error",[142,881,737],{"class":650},[142,883,562],{"class":148},[142,885,886,888],{"class":144,"line":505},[142,887,691],{"class":646},[142,889,587],{"class":148},[142,891,892],{"class":144,"line":511},[142,893,700],{"class":148},[142,895,897],{"class":144,"line":896},19,[142,898,514],{"class":148},[12,900,901,902,905,906,909,910,912,913,916,917,920],{},"Log to ",[21,903,904],{},"stderr",", never ",[21,907,908],{},"stdout",". On a stdio transport ",[21,911,908],{}," ",[59,914,915],{},"is"," the protocol channel, so one stray ",[21,918,919],{},"console.log"," corrupts the stream and your client drops the server with a useless error. This is the most common way to break an MCP server.",[125,922,924],{"id":923},"_3-define-the-tools","3. Define the Tools",[12,926,927,928,931,932,663],{},"Two dependencies: ",[21,929,930],{},"@modelcontextprotocol\u002Fsdk"," and ",[21,933,934],{},"zod",[133,936,938],{"className":531,"code":937,"language":533,"meta":138,"style":138},"import { McpServer } from '@modelcontextprotocol\u002Fsdk\u002Fserver\u002Fmcp.js';\nimport { StdioServerTransport } from '@modelcontextprotocol\u002Fsdk\u002Fserver\u002Fstdio.js';\nimport { z } from 'zod';\n\nconst server = new McpServer({ name: 'empathy-ds', version: '0.0.1' });\n",[21,939,940,967,989,1010,1014],{"__ignoreMap":138},[142,941,942,945,948,951,954,957,960,963,965],{"class":144,"line":145},[142,943,944],{"class":646},"import",[142,946,947],{"class":148}," {",[142,949,950],{"class":462}," McpServer",[142,952,953],{"class":148}," }",[142,955,956],{"class":646}," from",[142,958,959],{"class":148}," '",[142,961,962],{"class":171},"@modelcontextprotocol\u002Fsdk\u002Fserver\u002Fmcp.js",[142,964,869],{"class":148},[142,966,562],{"class":148},[142,968,969,971,973,976,978,980,982,985,987],{"class":144,"line":152},[142,970,944],{"class":646},[142,972,947],{"class":148},[142,974,975],{"class":462}," StdioServerTransport",[142,977,953],{"class":148},[142,979,956],{"class":646},[142,981,959],{"class":148},[142,983,984],{"class":171},"@modelcontextprotocol\u002Fsdk\u002Fserver\u002Fstdio.js",[142,986,869],{"class":148},[142,988,562],{"class":148},[142,990,991,993,995,998,1000,1002,1004,1006,1008],{"class":144,"line":180},[142,992,944],{"class":646},[142,994,947],{"class":148},[142,996,997],{"class":462}," z",[142,999,953],{"class":148},[142,1001,956],{"class":646},[142,1003,959],{"class":148},[142,1005,934],{"class":171},[142,1007,869],{"class":148},[142,1009,562],{"class":148},[142,1011,1012],{"class":144,"line":201},[142,1013,607],{"emptyLinePlaceholder":606},[142,1015,1016,1018,1021,1023,1025,1027,1029,1032,1035,1037,1039,1042,1044,1046,1049,1051,1053,1056,1058,1060,1062],{"class":144,"line":219},[142,1017,540],{"class":158},[142,1019,1020],{"class":462}," server ",[142,1022,546],{"class":148},[142,1024,765],{"class":148},[142,1026,950],{"class":618},[142,1028,726],{"class":462},[142,1030,1031],{"class":148},"{",[142,1033,1034],{"class":650}," name",[142,1036,165],{"class":148},[142,1038,959],{"class":148},[142,1040,1041],{"class":171},"empathy-ds",[142,1043,869],{"class":148},[142,1045,340],{"class":148},[142,1047,1048],{"class":650}," version",[142,1050,165],{"class":148},[142,1052,959],{"class":148},[142,1054,1055],{"class":171},"0.0.1",[142,1057,869],{"class":148},[142,1059,953],{"class":148},[142,1061,737],{"class":462},[142,1063,562],{"class":148},[12,1065,1066],{},"A tool with no arguments:",[133,1068,1070],{"className":531,"code":1069,"language":533,"meta":138,"style":138},"server.tool(\n  'getAllComponents',\n  'Lists all 60+ Empathy DS Vue components with their names, descriptions, and categories. Use this to discover available components.',\n  {},\n  async () => {\n    const components = await listComponents();\n    return {\n      content: [{\n        type: 'text',\n        text: JSON.stringify({\n          totalComponents: components.length,\n          packageName: mcpConfig.packageName,\n          components,\n        }, null, 2),\n      }],\n    };\n  },\n);\n",[21,1071,1072,1085,1097,1108,1113,1126,1144,1150,1161,1177,1196,1212,1228,1235,1250,1260,1265,1270],{"__ignoreMap":138},[142,1073,1074,1077,1079,1082],{"class":144,"line":145},[142,1075,1076],{"class":462},"server",[142,1078,663],{"class":148},[142,1080,1081],{"class":618},"tool",[142,1083,1084],{"class":462},"(\n",[142,1086,1087,1090,1093,1095],{"class":144,"line":152},[142,1088,1089],{"class":148},"  '",[142,1091,1092],{"class":171},"getAllComponents",[142,1094,869],{"class":148},[142,1096,177],{"class":148},[142,1098,1099,1101,1104,1106],{"class":144,"line":180},[142,1100,1089],{"class":148},[142,1102,1103],{"class":171},"Lists all 60+ Empathy DS Vue components with their names, descriptions, and categories. Use this to discover available components.",[142,1105,869],{"class":148},[142,1107,177],{"class":148},[142,1109,1110],{"class":144,"line":201},[142,1111,1112],{"class":148},"  {},\n",[142,1114,1115,1118,1121,1124],{"class":144,"line":219},[142,1116,1117],{"class":158},"  async",[142,1119,1120],{"class":148}," ()",[142,1122,1123],{"class":158}," =>",[142,1125,641],{"class":148},[142,1127,1128,1130,1133,1135,1137,1140,1142],{"class":144,"line":234},[142,1129,712],{"class":158},[142,1131,1132],{"class":462}," components",[142,1134,584],{"class":148},[142,1136,720],{"class":646},[142,1138,1139],{"class":618}," listComponents",[142,1141,811],{"class":650},[142,1143,562],{"class":148},[142,1145,1146,1148],{"class":144,"line":240},[142,1147,691],{"class":646},[142,1149,641],{"class":148},[142,1151,1152,1155,1157,1159],{"class":144,"line":263},[142,1153,1154],{"class":650},"      content",[142,1156,165],{"class":148},[142,1158,454],{"class":650},[142,1160,149],{"class":148},[142,1162,1163,1166,1168,1170,1173,1175],{"class":144,"line":284},[142,1164,1165],{"class":650},"        type",[142,1167,165],{"class":148},[142,1169,959],{"class":148},[142,1171,1172],{"class":171},"text",[142,1174,869],{"class":148},[142,1176,177],{"class":148},[142,1178,1179,1182,1184,1187,1189,1192,1194],{"class":144,"line":305},[142,1180,1181],{"class":650},"        text",[142,1183,165],{"class":148},[142,1185,1186],{"class":462}," JSON",[142,1188,663],{"class":148},[142,1190,1191],{"class":618},"stringify",[142,1193,726],{"class":650},[142,1195,149],{"class":148},[142,1197,1198,1201,1203,1205,1207,1210],{"class":144,"line":319},[142,1199,1200],{"class":650},"          totalComponents",[142,1202,165],{"class":148},[142,1204,1132],{"class":462},[142,1206,663],{"class":148},[142,1208,1209],{"class":462},"length",[142,1211,177],{"class":148},[142,1213,1214,1217,1219,1222,1224,1226],{"class":144,"line":379},[142,1215,1216],{"class":650},"          packageName",[142,1218,165],{"class":148},[142,1220,1221],{"class":462}," mcpConfig",[142,1223,663],{"class":148},[142,1225,185],{"class":462},[142,1227,177],{"class":148},[142,1229,1230,1233],{"class":144,"line":436},[142,1231,1232],{"class":462},"          components",[142,1234,177],{"class":148},[142,1236,1237,1240,1243,1246,1248],{"class":144,"line":442},[142,1238,1239],{"class":148},"        },",[142,1241,1242],{"class":148}," null,",[142,1244,1245],{"class":213}," 2",[142,1247,737],{"class":650},[142,1249,177],{"class":148},[142,1251,1252,1255,1258],{"class":144,"line":479},[142,1253,1254],{"class":148},"      }",[142,1256,1257],{"class":650},"]",[142,1259,177],{"class":148},[142,1261,1262],{"class":144,"line":499},[142,1263,1264],{"class":148},"    };\n",[142,1266,1267],{"class":144,"line":505},[142,1268,1269],{"class":148},"  },\n",[142,1271,1272,1274],{"class":144,"line":511},[142,1273,737],{"class":462},[142,1275,562],{"class":148},[12,1277,1278],{},"And one that takes an argument:",[133,1280,1282],{"className":531,"code":1281,"language":533,"meta":138,"style":138},"server.tool(\n  'getComponent',\n  'Gets detailed information about a specific component including props, variants, and usage examples. Use this when you need implementation details.',\n  {\n    componentName: z.string().describe(\n      \"The kebab-case name of the component (e.g., 'button', 'alert-dialog', 'dropdown-menu')\",\n    ),\n  },\n  async ({ componentName }) => {\n    const component = await getComponentDetail(componentName);\n    if (!component) {\n      return {\n        content: [{\n          type: 'text',\n          text: `Component \"${componentName}\" not found. Use getAllComponents to see available components.`,\n        }],\n        isError: true,\n      };\n    }\n    return { content: [{ type: 'text', text: JSON.stringify(component, null, 2) }] };\n  },\n);\n",[21,1283,1284,1294,1305,1316,1321,1344,1355,1362,1366,1384,1407,1422,1429,1440,1455,1482,1491,1504,1509,1513,1573,1578],{"__ignoreMap":138},[142,1285,1286,1288,1290,1292],{"class":144,"line":145},[142,1287,1076],{"class":462},[142,1289,663],{"class":148},[142,1291,1081],{"class":618},[142,1293,1084],{"class":462},[142,1295,1296,1298,1301,1303],{"class":144,"line":152},[142,1297,1089],{"class":148},[142,1299,1300],{"class":171},"getComponent",[142,1302,869],{"class":148},[142,1304,177],{"class":148},[142,1306,1307,1309,1312,1314],{"class":144,"line":180},[142,1308,1089],{"class":148},[142,1310,1311],{"class":171},"Gets detailed information about a specific component including props, variants, and usage examples. Use this when you need implementation details.",[142,1313,869],{"class":148},[142,1315,177],{"class":148},[142,1317,1318],{"class":144,"line":201},[142,1319,1320],{"class":148},"  {\n",[142,1322,1323,1326,1328,1330,1332,1335,1337,1339,1342],{"class":144,"line":219},[142,1324,1325],{"class":650},"    componentName",[142,1327,165],{"class":148},[142,1329,997],{"class":462},[142,1331,663],{"class":148},[142,1333,1334],{"class":618},"string",[142,1336,811],{"class":462},[142,1338,663],{"class":148},[142,1340,1341],{"class":618},"describe",[142,1343,1084],{"class":462},[142,1345,1346,1348,1351,1353],{"class":144,"line":234},[142,1347,243],{"class":148},[142,1349,1350],{"class":171},"The kebab-case name of the component (e.g., 'button', 'alert-dialog', 'dropdown-menu')",[142,1352,162],{"class":148},[142,1354,177],{"class":148},[142,1356,1357,1360],{"class":144,"line":240},[142,1358,1359],{"class":462},"    )",[142,1361,177],{"class":148},[142,1363,1364],{"class":144,"line":263},[142,1365,1269],{"class":148},[142,1367,1368,1370,1373,1377,1380,1382],{"class":144,"line":284},[142,1369,1117],{"class":158},[142,1371,1372],{"class":148}," ({",[142,1374,1376],{"class":1375},"sHdIc"," componentName",[142,1378,1379],{"class":148}," })",[142,1381,1123],{"class":158},[142,1383,641],{"class":148},[142,1385,1386,1388,1391,1393,1395,1398,1400,1403,1405],{"class":144,"line":305},[142,1387,712],{"class":158},[142,1389,1390],{"class":462}," component",[142,1392,584],{"class":148},[142,1394,720],{"class":646},[142,1396,1397],{"class":618}," getComponentDetail",[142,1399,726],{"class":650},[142,1401,1402],{"class":462},"componentName",[142,1404,737],{"class":650},[142,1406,562],{"class":148},[142,1408,1409,1411,1413,1415,1418,1420],{"class":144,"line":319},[142,1410,744],{"class":646},[142,1412,651],{"class":650},[142,1414,749],{"class":148},[142,1416,1417],{"class":462},"component",[142,1419,684],{"class":650},[142,1421,149],{"class":148},[142,1423,1424,1427],{"class":144,"line":379},[142,1425,1426],{"class":646},"      return",[142,1428,641],{"class":148},[142,1430,1431,1434,1436,1438],{"class":144,"line":436},[142,1432,1433],{"class":650},"        content",[142,1435,165],{"class":148},[142,1437,454],{"class":650},[142,1439,149],{"class":148},[142,1441,1442,1445,1447,1449,1451,1453],{"class":144,"line":442},[142,1443,1444],{"class":650},"          type",[142,1446,165],{"class":148},[142,1448,959],{"class":148},[142,1450,1172],{"class":171},[142,1452,869],{"class":148},[142,1454,177],{"class":148},[142,1456,1457,1460,1462,1465,1468,1470,1472,1475,1478,1480],{"class":144,"line":479},[142,1458,1459],{"class":650},"          text",[142,1461,165],{"class":148},[142,1463,1464],{"class":148}," `",[142,1466,1467],{"class":171},"Component \"",[142,1469,779],{"class":148},[142,1471,1402],{"class":462},[142,1473,1474],{"class":148},"}",[142,1476,1477],{"class":171},"\" not found. Use getAllComponents to see available components.",[142,1479,773],{"class":148},[142,1481,177],{"class":148},[142,1483,1484,1487,1489],{"class":144,"line":499},[142,1485,1486],{"class":148},"        }",[142,1488,1257],{"class":650},[142,1490,177],{"class":148},[142,1492,1493,1496,1498,1502],{"class":144,"line":505},[142,1494,1495],{"class":650},"        isError",[142,1497,165],{"class":148},[142,1499,1501],{"class":1500},"sfNiH"," true",[142,1503,177],{"class":148},[142,1505,1506],{"class":144,"line":511},[142,1507,1508],{"class":148},"      };\n",[142,1510,1511],{"class":144,"line":896},[142,1512,502],{"class":148},[142,1514,1516,1518,1520,1523,1525,1527,1529,1532,1534,1536,1538,1540,1542,1545,1547,1549,1551,1553,1555,1557,1559,1561,1563,1565,1567,1570],{"class":144,"line":1515},20,[142,1517,691],{"class":646},[142,1519,947],{"class":148},[142,1521,1522],{"class":650}," content",[142,1524,165],{"class":148},[142,1526,454],{"class":650},[142,1528,1031],{"class":148},[142,1530,1531],{"class":650}," type",[142,1533,165],{"class":148},[142,1535,959],{"class":148},[142,1537,1172],{"class":171},[142,1539,869],{"class":148},[142,1541,340],{"class":148},[142,1543,1544],{"class":650}," text",[142,1546,165],{"class":148},[142,1548,1186],{"class":462},[142,1550,663],{"class":148},[142,1552,1191],{"class":618},[142,1554,726],{"class":650},[142,1556,1417],{"class":462},[142,1558,340],{"class":148},[142,1560,1242],{"class":148},[142,1562,1245],{"class":213},[142,1564,684],{"class":650},[142,1566,1474],{"class":148},[142,1568,1569],{"class":650},"] ",[142,1571,1572],{"class":148},"};\n",[142,1574,1576],{"class":144,"line":1575},21,[142,1577,1269],{"class":148},[142,1579,1581,1583],{"class":144,"line":1580},22,[142,1582,737],{"class":462},[142,1584,562],{"class":148},[12,1586,1587],{},"Three things in there do more work than they look like they do.",[12,1589,1590,1593],{},[59,1591,1592],{},"The tool description is a prompt."," The model reads it to decide whether to call the tool. \"Use this when you need implementation details\" is an instruction, not documentation. Write it for someone who will act on it.",[12,1595,1596,1602,1603,1606,1607,1610],{},[59,1597,1598,1601],{},[21,1599,1600],{},".describe()"," teaches the argument shape."," I had to spell out kebab-case ",[79,1604,1605],{},"with examples",". Without that, models passed ",[21,1608,1609],{},"AlertDialog"," and got nothing back.",[12,1612,1613,1616],{},[59,1614,1615],{},"The not-found branch returns a next step."," \"Use getAllComponents to see available components\" means a wrong guess fixes itself in one turn instead of the model inventing something.",[125,1618,1620],{"id":1619},"_4-start-it-on-stdio","4. Start It on stdio",[133,1622,1624],{"className":531,"code":1623,"language":533,"meta":138,"style":138},"async function startServer() {\n  try {\n    const transport = new StdioServerTransport();\n    await server.connect(transport);\n    console.error('Empathy DS MCP server started');\n  } catch (error) {\n    console.error('Error starting MCP server:', error);\n    process.exit(1);\n  }\n}\nstartServer();\n",[21,1625,1626,1639,1645,1662,1684,1705,1719,1744,1763,1767,1771],{"__ignoreMap":138},[142,1627,1628,1630,1632,1635,1637],{"class":144,"line":145},[142,1629,612],{"class":158},[142,1631,615],{"class":158},[142,1633,1634],{"class":618}," startServer",[142,1636,811],{"class":148},[142,1638,641],{"class":148},[142,1640,1641,1643],{"class":144,"line":152},[142,1642,705],{"class":646},[142,1644,641],{"class":148},[142,1646,1647,1649,1652,1654,1656,1658,1660],{"class":144,"line":180},[142,1648,712],{"class":158},[142,1650,1651],{"class":462}," transport",[142,1653,584],{"class":148},[142,1655,765],{"class":148},[142,1657,975],{"class":618},[142,1659,811],{"class":650},[142,1661,562],{"class":148},[142,1663,1664,1667,1670,1672,1675,1677,1680,1682],{"class":144,"line":201},[142,1665,1666],{"class":646},"    await",[142,1668,1669],{"class":462}," server",[142,1671,663],{"class":148},[142,1673,1674],{"class":618},"connect",[142,1676,726],{"class":650},[142,1678,1679],{"class":462},"transport",[142,1681,737],{"class":650},[142,1683,562],{"class":148},[142,1685,1686,1688,1690,1692,1694,1696,1699,1701,1703],{"class":144,"line":219},[142,1687,860],{"class":462},[142,1689,663],{"class":148},[142,1691,851],{"class":618},[142,1693,726],{"class":650},[142,1695,869],{"class":148},[142,1697,1698],{"class":171},"Empathy DS MCP server started",[142,1700,869],{"class":148},[142,1702,737],{"class":650},[142,1704,562],{"class":148},[142,1706,1707,1709,1711,1713,1715,1717],{"class":144,"line":234},[142,1708,843],{"class":148},[142,1710,846],{"class":646},[142,1712,651],{"class":650},[142,1714,851],{"class":462},[142,1716,684],{"class":650},[142,1718,149],{"class":148},[142,1720,1721,1723,1725,1727,1729,1731,1734,1736,1738,1740,1742],{"class":144,"line":240},[142,1722,860],{"class":462},[142,1724,663],{"class":148},[142,1726,851],{"class":618},[142,1728,726],{"class":650},[142,1730,869],{"class":148},[142,1732,1733],{"class":171},"Error starting MCP server:",[142,1735,869],{"class":148},[142,1737,340],{"class":148},[142,1739,879],{"class":462},[142,1741,737],{"class":650},[142,1743,562],{"class":148},[142,1745,1746,1749,1751,1754,1756,1759,1761],{"class":144,"line":263},[142,1747,1748],{"class":462},"    process",[142,1750,663],{"class":148},[142,1752,1753],{"class":618},"exit",[142,1755,726],{"class":650},[142,1757,1758],{"class":213},"1",[142,1760,737],{"class":650},[142,1762,562],{"class":148},[142,1764,1765],{"class":144,"line":284},[142,1766,700],{"class":148},[142,1768,1769],{"class":144,"line":305},[142,1770,514],{"class":148},[142,1772,1773,1776,1778],{"class":144,"line":319},[142,1774,1775],{"class":618},"startServer",[142,1777,811],{"class":462},[142,1779,562],{"class":148},[125,1781,1783],{"id":1782},"_5-make-it-runnable-with-npx","5. Make It Runnable With npx",[133,1785,1787],{"className":135,"code":1786,"language":137,"meta":138,"style":138},"{\n  \"name\": \"@empathyds\u002Fmcp-server\",\n  \"type\": \"module\",\n  \"bin\": { \"empathy-ds-mcp\": \"dist\u002Fserver.js\" },\n  \"dependencies\": {\n    \"@modelcontextprotocol\u002Fsdk\": \"^1.0.0\",\n    \"zod\": \"^3.23.0\"\n  }\n}\n",[21,1788,1789,1793,1812,1831,1862,1875,1895,1912,1916],{"__ignoreMap":138},[142,1790,1791],{"class":144,"line":145},[142,1792,149],{"class":148},[142,1794,1795,1797,1799,1801,1803,1805,1808,1810],{"class":144,"line":152},[142,1796,155],{"class":148},[142,1798,247],{"class":158},[142,1800,162],{"class":148},[142,1802,165],{"class":148},[142,1804,168],{"class":148},[142,1806,1807],{"class":171},"@empathyds\u002Fmcp-server",[142,1809,162],{"class":148},[142,1811,177],{"class":148},[142,1813,1814,1816,1818,1820,1822,1824,1827,1829],{"class":144,"line":180},[142,1815,155],{"class":148},[142,1817,345],{"class":158},[142,1819,162],{"class":148},[142,1821,165],{"class":148},[142,1823,168],{"class":148},[142,1825,1826],{"class":171},"module",[142,1828,162],{"class":148},[142,1830,177],{"class":148},[142,1832,1833,1835,1838,1840,1842,1844,1846,1849,1851,1853,1855,1858,1860],{"class":144,"line":201},[142,1834,155],{"class":148},[142,1836,1837],{"class":158},"bin",[142,1839,162],{"class":148},[142,1841,165],{"class":148},[142,1843,947],{"class":148},[142,1845,168],{"class":148},[142,1847,1848],{"class":246},"empathy-ds-mcp",[142,1850,162],{"class":148},[142,1852,165],{"class":148},[142,1854,168],{"class":148},[142,1856,1857],{"class":171},"dist\u002Fserver.js",[142,1859,162],{"class":148},[142,1861,376],{"class":148},[142,1863,1864,1866,1869,1871,1873],{"class":144,"line":219},[142,1865,155],{"class":148},[142,1867,1868],{"class":158},"dependencies",[142,1870,162],{"class":148},[142,1872,165],{"class":148},[142,1874,641],{"class":148},[142,1876,1877,1880,1882,1884,1886,1888,1891,1893],{"class":144,"line":234},[142,1878,1879],{"class":148},"    \"",[142,1881,930],{"class":246},[142,1883,162],{"class":148},[142,1885,165],{"class":148},[142,1887,168],{"class":148},[142,1889,1890],{"class":171},"^1.0.0",[142,1892,162],{"class":148},[142,1894,177],{"class":148},[142,1896,1897,1899,1901,1903,1905,1907,1910],{"class":144,"line":240},[142,1898,1879],{"class":148},[142,1900,934],{"class":246},[142,1902,162],{"class":148},[142,1904,165],{"class":148},[142,1906,168],{"class":148},[142,1908,1909],{"class":171},"^3.23.0",[142,1911,496],{"class":148},[142,1913,1914],{"class":144,"line":263},[142,1915,700],{"class":148},[142,1917,1918],{"class":144,"line":284},[142,1919,514],{"class":148},[12,1921,1922,1923,1926],{},"Put ",[21,1924,1925],{},"#!\u002Fusr\u002Fbin\u002Fenv node"," at the top of the built file. Now anyone can run it without cloning anything:",[133,1928,1930],{"className":135,"code":1929,"language":137,"meta":138,"style":138},"{\n  \"mcpServers\": {\n    \"empathy-ds\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@empathyds\u002Fmcp-server\"]\n    }\n  }\n}\n",[21,1931,1932,1936,1949,1961,1981,2012,2016,2020],{"__ignoreMap":138},[142,1933,1934],{"class":144,"line":145},[142,1935,149],{"class":148},[142,1937,1938,1940,1943,1945,1947],{"class":144,"line":152},[142,1939,155],{"class":148},[142,1941,1942],{"class":158},"mcpServers",[142,1944,162],{"class":148},[142,1946,165],{"class":148},[142,1948,641],{"class":148},[142,1950,1951,1953,1955,1957,1959],{"class":144,"line":180},[142,1952,1879],{"class":148},[142,1954,1041],{"class":246},[142,1956,162],{"class":148},[142,1958,165],{"class":148},[142,1960,641],{"class":148},[142,1962,1963,1965,1968,1970,1972,1974,1977,1979],{"class":144,"line":201},[142,1964,243],{"class":148},[142,1966,1967],{"class":213},"command",[142,1969,162],{"class":148},[142,1971,165],{"class":148},[142,1973,168],{"class":148},[142,1975,1976],{"class":171},"npx",[142,1978,162],{"class":148},[142,1980,177],{"class":148},[142,1982,1983,1985,1988,1990,1992,1994,1996,1999,2001,2003,2005,2007,2009],{"class":144,"line":219},[142,1984,243],{"class":148},[142,1986,1987],{"class":213},"args",[142,1989,162],{"class":148},[142,1991,165],{"class":148},[142,1993,454],{"class":148},[142,1995,162],{"class":148},[142,1997,1998],{"class":171},"-y",[142,2000,162],{"class":148},[142,2002,340],{"class":148},[142,2004,168],{"class":148},[142,2006,1807],{"class":171},[142,2008,162],{"class":148},[142,2010,2011],{"class":148},"]\n",[142,2013,2014],{"class":144,"line":234},[142,2015,502],{"class":148},[142,2017,2018],{"class":144,"line":240},[142,2019,700],{"class":148},[142,2021,2022],{"class":144,"line":263},[142,2023,514],{"class":148},[125,2025,2027],{"id":2026},"the-full-tool-list","The Full Tool List",[12,2029,2030],{},"Eight tools, all deliberately boring:",[2032,2033,2034,2047],"table",{},[2035,2036,2037],"thead",{},[2038,2039,2040,2044],"tr",{},[2041,2042,2043],"th",{},"Tool",[2041,2045,2046],{},"What it answers",[2048,2049,2050,2060,2069,2079,2089,2099,2109,2119],"tbody",{},[2038,2051,2052,2057],{},[2053,2054,2055],"td",{},[21,2056,1092],{},[2053,2058,2059],{},"What exists?",[2038,2061,2062,2066],{},[2053,2063,2064],{},[21,2065,1300],{},[2053,2067,2068],{},"What props and examples does this one have?",[2038,2070,2071,2076],{},[2053,2072,2073],{},[21,2074,2075],{},"getComponentsByCategory",[2053,2077,2078],{},"What's available for forms, layout, feedback?",[2038,2080,2081,2086],{},[2053,2082,2083],{},[21,2084,2085],{},"searchComponents",[2053,2087,2088],{},"Is there something for this?",[2038,2090,2091,2096],{},[2053,2092,2093],{},[21,2094,2095],{},"getCategories",[2053,2097,2098],{},"How is this organised?",[2038,2100,2101,2106],{},[2053,2102,2103],{},[21,2104,2105],{},"getBlocks",[2053,2107,2108],{},"Are there prebuilt patterns?",[2038,2110,2111,2116],{},[2053,2112,2113],{},[21,2114,2115],{},"getBlock",[2053,2117,2118],{},"How does this pattern work?",[2038,2120,2121,2126],{},[2053,2122,2123],{},[21,2124,2125],{},"getUsageGuide",[2053,2127,2128],{},"What are the conventions?",[12,2130,2131],{},"There is no cleverness in any of them. Every one is a question the assistant used to answer by guessing.",[12,2133,2134,2135,2138],{},"The hallucinated props mostly stopped. Not because the model got smarter, and not because I wrote a better prompt — because ",[21,2136,2137],{},"getComponent(\"input\")"," returns six real props and there is nothing left to invent.",[49,2140,2142],{"id":2141},"what-about-a-skill","What About a Skill?",[12,2144,2145,2146,2149,2150,2155],{},"Fair question, and the short answer is that I built one of those too — ",[21,2147,2148],{},"@empathyds\u002Fskills",", a month after this server — and kept both. A skill carries judgement; a server carries facts that change. I wrote up ",[2151,2152,2154],"a",{"href":2153},"\u002Fblog\u002Fwhen-to-build-a-skill-and-when-to-build-an-mcp-server","which one to build"," separately, because the answer is longer than a paragraph.",[49,2157,2159],{"id":2158},"the-general-shape","The General Shape",[12,2161,2162],{},"The lesson is not really about design systems.",[12,2164,2165],{},[59,2166,2167],{},"When an agent is confidently wrong, ask what it was forced to guess at, and whether you can turn that guess into a call.",[12,2169,2170,2171,2174],{},"Most of the effort in this space goes into prompting — describing your domain in words and hoping description substitutes for knowledge. Sometimes it does. But when a model is wrong in a ",[79,2172,2173],{},"confident, plausible, pattern-completing"," way, that is usually a gap, not a misread instruction. And a gap you can close with a lookup.",[12,2176,2177],{},"It is a retrieval problem wearing a prompting problem's clothes.",[12,2179,2180],{},"Once you start looking for that shape it is everywhere. An agent inventing API endpoints needs your OpenAPI spec, not a better description of your API. An agent misremembering your schema needs to be able to query it. An agent guessing at your component props needs your registry.",[12,2182,2183],{},"The fix is almost always smaller than the prompt you were about to write.",[2185,2186,2187],"style",{},"html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .sfNiH, html code.shiki .sfNiH{--shiki-light:#FF5370;--shiki-default:#FF9CAC;--shiki-dark:#FF9CAC}",{"title":138,"searchDepth":152,"depth":152,"links":2189},[2190,2191,2192,2200,2201],{"id":51,"depth":152,"text":52},{"id":85,"depth":152,"text":86},{"id":119,"depth":152,"text":120,"children":2193},[2194,2195,2196,2197,2198,2199],{"id":127,"depth":180,"text":128},{"id":524,"depth":180,"text":525},{"id":923,"depth":180,"text":924},{"id":1619,"depth":180,"text":1620},{"id":1782,"depth":180,"text":1783},{"id":2026,"depth":180,"text":2027},{"id":2141,"depth":152,"text":2142},{"id":2158,"depth":152,"text":2159},"2026-01-25","My AI assistant kept inventing props that did not exist on my components. Better prompts did not fix it. Publishing the component registry as an MCP server did, because it was never a prompting problem.","md","\u002Fimg\u002Fmcp-design-system.jpg",{},"\u002Fblog\u002Fbuilding-an-mcp-server-for-a-vue-design-system",{"title":5,"description":2203},{"loc":2207},"blog\u002Fbuilding-an-mcp-server-for-a-vue-design-system",[2212,2213,2214],"AI","MCP","Design Systems","reiTdjbLDM25ri4eViKb__hbgLFlyF4oIP_67uWZoys",[2217,2222],{"title":2218,"path":2219,"stem":2220,"description":2221,"children":-1},"Build an app with Ionic Framework & Laravel5","\u002Fblog\u002Fbuild-an-app-with-ionic-framework-and-laravel-602","blog\u002Fbuild-an-app-with-ionic-framework-and-laravel-602","In this article we will Build an app with Ionic Framework 3 & Laravel5",{"title":2223,"path":2224,"stem":2225,"description":2226,"children":-1},"Building Highlight Reels in the Browser with WebCodecs","\u002Fblog\u002Fbuilding-highlight-reels-in-the-browser-with-webcodecs","blog\u002Fbuilding-highlight-reels-in-the-browser-with-webcodecs","A highlight reel needs to know which moments mattered. The scoreboard already knew, so the clips come from replaying the scoring engine over the event log — and the render happens client-side with WebCodecs, no server and no upload.",1790075470905]