@seed-ship/mcp-ui-solid 6.24.0 → 6.25.1

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 (124) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/README.md +47 -0
  3. package/dist/components/ActionGroupRenderer.cjs +6 -6
  4. package/dist/components/ActionGroupRenderer.cjs.map +1 -1
  5. package/dist/components/ActionGroupRenderer.js +6 -6
  6. package/dist/components/ActionGroupRenderer.js.map +1 -1
  7. package/dist/components/AutocompleteDropdown.cjs +6 -6
  8. package/dist/components/AutocompleteDropdown.cjs.map +1 -1
  9. package/dist/components/AutocompleteDropdown.js +6 -6
  10. package/dist/components/AutocompleteDropdown.js.map +1 -1
  11. package/dist/components/AutocompleteFormField.cjs +6 -5
  12. package/dist/components/AutocompleteFormField.cjs.map +1 -1
  13. package/dist/components/AutocompleteFormField.d.ts.map +1 -1
  14. package/dist/components/AutocompleteFormField.js +6 -5
  15. package/dist/components/AutocompleteFormField.js.map +1 -1
  16. package/dist/components/ChartJSRenderer.cjs +216 -6
  17. package/dist/components/ChartJSRenderer.cjs.map +1 -1
  18. package/dist/components/ChartJSRenderer.d.ts.map +1 -1
  19. package/dist/components/ChartJSRenderer.js +217 -7
  20. package/dist/components/ChartJSRenderer.js.map +1 -1
  21. package/dist/components/ChatPrompt.cjs +5 -5
  22. package/dist/components/ChatPrompt.cjs.map +1 -1
  23. package/dist/components/ChatPrompt.js +5 -5
  24. package/dist/components/ChatPrompt.js.map +1 -1
  25. package/dist/components/ComponentToolbar.cjs +5 -5
  26. package/dist/components/ComponentToolbar.cjs.map +1 -1
  27. package/dist/components/ComponentToolbar.js +5 -5
  28. package/dist/components/ComponentToolbar.js.map +1 -1
  29. package/dist/components/DegradedFallback.cjs +1 -1
  30. package/dist/components/DegradedFallback.cjs.map +1 -1
  31. package/dist/components/DegradedFallback.js +1 -1
  32. package/dist/components/DegradedFallback.js.map +1 -1
  33. package/dist/components/ExpandableWrapper.cjs +10 -7
  34. package/dist/components/ExpandableWrapper.cjs.map +1 -1
  35. package/dist/components/ExpandableWrapper.d.ts.map +1 -1
  36. package/dist/components/ExpandableWrapper.js +10 -7
  37. package/dist/components/ExpandableWrapper.js.map +1 -1
  38. package/dist/components/FormFieldRenderer.cjs +13 -12
  39. package/dist/components/FormFieldRenderer.cjs.map +1 -1
  40. package/dist/components/FormFieldRenderer.d.ts.map +1 -1
  41. package/dist/components/FormFieldRenderer.js +13 -12
  42. package/dist/components/FormFieldRenderer.js.map +1 -1
  43. package/dist/components/FormRenderer.cjs +1 -1
  44. package/dist/components/FormRenderer.cjs.map +1 -1
  45. package/dist/components/FormRenderer.js +1 -1
  46. package/dist/components/FormRenderer.js.map +1 -1
  47. package/dist/components/GenerativeUIErrorBoundary.cjs +1 -1
  48. package/dist/components/GenerativeUIErrorBoundary.cjs.map +1 -1
  49. package/dist/components/GenerativeUIErrorBoundary.js +1 -1
  50. package/dist/components/GenerativeUIErrorBoundary.js.map +1 -1
  51. package/dist/components/GhostText.cjs +2 -2
  52. package/dist/components/GhostText.cjs.map +1 -1
  53. package/dist/components/GhostText.js +2 -2
  54. package/dist/components/GhostText.js.map +1 -1
  55. package/dist/components/GraphRenderer.cjs +100 -29
  56. package/dist/components/GraphRenderer.cjs.map +1 -1
  57. package/dist/components/GraphRenderer.d.ts +1 -1
  58. package/dist/components/GraphRenderer.d.ts.map +1 -1
  59. package/dist/components/GraphRenderer.js +100 -29
  60. package/dist/components/GraphRenderer.js.map +1 -1
  61. package/dist/components/MissingValue.cjs +2 -2
  62. package/dist/components/MissingValue.cjs.map +1 -1
  63. package/dist/components/MissingValue.js +2 -2
  64. package/dist/components/MissingValue.js.map +1 -1
  65. package/dist/components/ModalRenderer.cjs +39 -31
  66. package/dist/components/ModalRenderer.cjs.map +1 -1
  67. package/dist/components/ModalRenderer.d.ts.map +1 -1
  68. package/dist/components/ModalRenderer.js +40 -32
  69. package/dist/components/ModalRenderer.js.map +1 -1
  70. package/dist/components/PortalDropdownMenu.cjs +6 -3
  71. package/dist/components/PortalDropdownMenu.cjs.map +1 -1
  72. package/dist/components/PortalDropdownMenu.d.ts.map +1 -1
  73. package/dist/components/PortalDropdownMenu.js +7 -4
  74. package/dist/components/PortalDropdownMenu.js.map +1 -1
  75. package/dist/components/ScratchpadPanel.cjs +38 -44
  76. package/dist/components/ScratchpadPanel.cjs.map +1 -1
  77. package/dist/components/ScratchpadPanel.d.ts.map +1 -1
  78. package/dist/components/ScratchpadPanel.js +38 -44
  79. package/dist/components/ScratchpadPanel.js.map +1 -1
  80. package/dist/components/UIResourceRenderer.cjs +20 -20
  81. package/dist/components/UIResourceRenderer.cjs.map +1 -1
  82. package/dist/components/UIResourceRenderer.js +20 -20
  83. package/dist/components/UIResourceRenderer.js.map +1 -1
  84. package/dist/components/chart-missing-plugin.cjs +4 -4
  85. package/dist/components/chart-missing-plugin.cjs.map +1 -1
  86. package/dist/components/chart-missing-plugin.d.ts +3 -1
  87. package/dist/components/chart-missing-plugin.d.ts.map +1 -1
  88. package/dist/components/chart-missing-plugin.js +4 -4
  89. package/dist/components/chart-missing-plugin.js.map +1 -1
  90. package/dist/utils/math-markdown.cjs +1 -1
  91. package/dist/utils/math-markdown.cjs.map +1 -1
  92. package/dist/utils/math-markdown.js +1 -1
  93. package/dist/utils/math-markdown.js.map +1 -1
  94. package/dist/utils/theme.cjs +91 -0
  95. package/dist/utils/theme.cjs.map +1 -0
  96. package/dist/utils/theme.d.ts +11 -0
  97. package/dist/utils/theme.d.ts.map +1 -0
  98. package/dist/utils/theme.js +91 -0
  99. package/dist/utils/theme.js.map +1 -0
  100. package/docs/SECURITY-DEPENDENCIES.md +81 -0
  101. package/docs/THEMING.md +205 -0
  102. package/package.json +5 -3
  103. package/src/components/ActionGroupRenderer.tsx +6 -6
  104. package/src/components/AutocompleteDropdown.tsx +17 -17
  105. package/src/components/AutocompleteFormField.tsx +10 -9
  106. package/src/components/ChartJSRenderer.tsx +483 -239
  107. package/src/components/ChatPrompt.tsx +16 -16
  108. package/src/components/ComponentToolbar.tsx +5 -5
  109. package/src/components/DegradedFallback.tsx +9 -9
  110. package/src/components/ExpandableWrapper.tsx +15 -11
  111. package/src/components/FormFieldRenderer.tsx +52 -51
  112. package/src/components/FormRenderer.tsx +12 -12
  113. package/src/components/GenerativeUIErrorBoundary.tsx +6 -6
  114. package/src/components/GhostText.tsx +7 -7
  115. package/src/components/GraphRenderer.tsx +83 -67
  116. package/src/components/MissingValue.tsx +2 -2
  117. package/src/components/ModalRenderer.tsx +11 -5
  118. package/src/components/PortalDropdownMenu.tsx +6 -2
  119. package/src/components/ScratchpadPanel.tsx +144 -141
  120. package/src/components/UIResourceRenderer.tsx +101 -101
  121. package/src/components/chart-missing-plugin.ts +5 -3
  122. package/src/styles/autocomplete.css +53 -53
  123. package/src/utils/math-markdown.ts +1 -1
  124. package/src/utils/theme.ts +101 -0
@@ -98,7 +98,7 @@ function CopyButton(props: { getText: () => string; title?: string; position?: '
98
98
  return (
99
99
  <button
100
100
  onClick={handleCopy}
101
- class={`${positionClasses()} opacity-60 hover:opacity-100 px-2 py-1 bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-600 rounded-full hover:bg-gray-100 dark:hover:bg-gray-700 transition-all shadow-sm z-10`}
101
+ class={`${positionClasses()} opacity-60 hover:opacity-100 px-2 py-1 bg-[color:var(--mcp-ui-surface,var(--color-white,#fff))] dark:bg-[color:var(--mcp-ui-surface,var(--color-gray-800,#1f2937))] border border-[color:var(--mcp-ui-border,var(--color-gray-200,#e5e7eb))] dark:border-[color:var(--mcp-ui-border,var(--color-gray-600,#4b5563))] rounded-full hover:bg-[color:var(--mcp-ui-surface-hover,var(--color-gray-100,#f3f4f6))] dark:hover:bg-[color:var(--mcp-ui-surface-hover,var(--color-gray-700,#374151))] transition-all shadow-[var(--mcp-ui-shadow,var(--shadow-sm))] z-10`}
102
102
  title={props.title || strings.copy}
103
103
  aria-label={props.title || strings.copy}
104
104
  data-mcp-ui-action="copy"
@@ -107,12 +107,12 @@ function CopyButton(props: { getText: () => string; title?: string; position?: '
107
107
  <Show
108
108
  when={!copied()}
109
109
  fallback={
110
- <svg class="w-3 h-3 text-green-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
110
+ <svg class="w-3 h-3 text-[color:var(--mcp-ui-success,var(--color-green-500))]" fill="none" viewBox="0 0 24 24" stroke="currentColor">
111
111
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" />
112
112
  </svg>
113
113
  }
114
114
  >
115
- <svg class="w-3 h-3 text-gray-500 dark:text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
115
+ <svg class="w-3 h-3 text-[color:var(--mcp-ui-fg-muted,var(--color-gray-500,#6b7280))] dark:text-[color:var(--mcp-ui-fg-subtle,var(--color-gray-400,#9ca3af))]" fill="none" viewBox="0 0 24 24" stroke="currentColor">
116
116
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" />
117
117
  </svg>
118
118
  </Show>
@@ -259,8 +259,8 @@ function ChartRenderer(props: {
259
259
  // Guard: if data or datasets missing, show error instead of crashing Chart.js
260
260
  if (!params()?.data?.datasets) {
261
261
  return (
262
- <div class="p-4 bg-white dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-gray-700">
263
- <p class="text-red-500 dark:text-red-400 text-sm">{strings.chartInvalidData}</p>
262
+ <div class="p-4 bg-[color:var(--mcp-ui-surface,var(--color-white,#fff))] dark:bg-[color:var(--mcp-ui-surface,var(--color-gray-800,#1f2937))] rounded-lg border border-[color:var(--mcp-ui-border,var(--color-gray-200,#e5e7eb))] dark:border-[color:var(--mcp-ui-border,var(--color-gray-700,#374151))]">
263
+ <p class="text-[color:var(--mcp-ui-danger,var(--color-red-500))] dark:text-[color:var(--mcp-ui-danger,var(--color-red-400))] text-sm">{strings.chartInvalidData}</p>
264
264
  </div>
265
265
  )
266
266
  }
@@ -338,7 +338,7 @@ function ChartRenderer(props: {
338
338
  <Show
339
339
  when={useNative()}
340
340
  fallback={
341
- <div class="relative w-full h-full min-h-[300px] bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 overflow-hidden">
341
+ <div class="relative w-full h-full min-h-[300px] bg-[color:var(--mcp-ui-surface,var(--color-white,#fff))] dark:bg-[color:var(--mcp-ui-surface,var(--color-gray-800,#1f2937))] rounded-lg shadow-[var(--mcp-ui-shadow,var(--shadow-sm))] border border-[color:var(--mcp-ui-border,var(--color-gray-200,#e5e7eb))] dark:border-[color:var(--mcp-ui-border,var(--color-gray-700,#374151))] overflow-hidden">
342
342
  {/* P1.7 — Chart.js missing and quickchart fallback not allowed:
343
343
  show the chart data as a local table instead of an implicit
344
344
  call to quickchart.io. */}
@@ -357,15 +357,15 @@ function ChartRenderer(props: {
357
357
 
358
358
  <Show when={isLoading()}>
359
359
  <div class="absolute inset-0 flex items-center justify-center">
360
- <div class="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600" />
360
+ <div class="animate-spin rounded-full h-8 w-8 border-b-2 border-[color:var(--mcp-ui-accent-border,var(--color-blue-600))]" />
361
361
  </div>
362
362
  </Show>
363
363
 
364
364
  <Show when={error()}>
365
365
  <div class="absolute inset-0 flex items-center justify-center p-4">
366
366
  <div class="text-center">
367
- <p class="text-red-600 dark:text-red-400 text-sm font-medium">{strings.chartError}</p>
368
- <p class="text-gray-600 dark:text-gray-400 text-xs mt-1">{error()}</p>
367
+ <p class="text-[color:var(--mcp-ui-danger,var(--color-red-600))] dark:text-[color:var(--mcp-ui-danger,var(--color-red-400))] text-sm font-medium">{strings.chartError}</p>
368
+ <p class="text-[color:var(--mcp-ui-fg-muted,var(--color-gray-600,#4b5563))] dark:text-[color:var(--mcp-ui-fg-subtle,var(--color-gray-400,#9ca3af))] text-xs mt-1">{error()}</p>
369
369
  </div>
370
370
  </div>
371
371
  </Show>
@@ -373,7 +373,7 @@ function ChartRenderer(props: {
373
373
  <Show when={iframeUrl() && !error()}>
374
374
  <div class="w-full h-full p-4">
375
375
  <Show when={params()?.title}>
376
- <h3 class="text-sm font-semibold text-gray-900 dark:text-white mb-3">
376
+ <h3 class="text-sm font-semibold text-[color:var(--mcp-ui-fg,var(--color-gray-900,#111827))] dark:text-[color:var(--mcp-ui-fg,var(--color-white,#fff))] mb-3">
377
377
  {params()?.title}
378
378
  </h3>
379
379
  </Show>
@@ -414,7 +414,7 @@ function ChartRenderer(props: {
414
414
  * Smart cell value renderer that handles markdown links and other formats
415
415
  */
416
416
  /** Class list carried by every `<mark>` that `highlightQuery` injects. */
417
- const HIGHLIGHT_MARK_CLASS = 'bg-yellow-200 dark:bg-[#222F49] text-inherit rounded px-0.5'
417
+ const HIGHLIGHT_MARK_CLASS = 'bg-[color:var(--mcp-ui-highlight,var(--color-yellow-200))] dark:bg-[color:var(--mcp-ui-highlight,#222F49)] text-inherit rounded px-0.5'
418
418
 
419
419
  /**
420
420
  * Wrap matches of `query` in `<mark>` tags within an HTML string.
@@ -553,12 +553,12 @@ function defaultCitationChip(
553
553
  const safeDocName = encodeURIComponent(fileName || '')
554
554
  const label = fileName ? `${fileName} - ${pageNum}` : `${pageNum}`
555
555
  if (!verified) {
556
- return `<span class="citation-ref inline-flex items-center gap-0.5 align-middle opacity-60"><span class="text-gray-500 line-through">[${label}]</span></span>`
556
+ return `<span class="citation-ref inline-flex items-center gap-0.5 align-middle opacity-60"><span class="text-[color:var(--mcp-ui-fg-muted,var(--color-gray-500,#6b7280))] line-through">[${label}]</span></span>`
557
557
  }
558
558
  return [
559
559
  '<span class="citation-ref inline-flex items-center gap-0.5 align-middle">',
560
- `<span class="text-gray-500">[${label}]</span>`,
561
- '<button class="inline-flex items-center ml-0.5 px-1 py-0.5 text-xs bg-gray-800 hover:bg-gray-700 border border-gray-600 hover:border-teal-500 rounded cursor-pointer transition-colors align-middle"',
560
+ `<span class="text-[color:var(--mcp-ui-fg-muted,var(--color-gray-500,#6b7280))]">[${label}]</span>`,
561
+ '<button class="inline-flex items-center ml-0.5 px-1 py-0.5 text-xs bg-[color:var(--mcp-ui-surface,var(--color-gray-800,#1f2937))] hover:bg-[color:var(--mcp-ui-surface-hover,var(--color-gray-700,#374151))] border border-[color:var(--mcp-ui-border,var(--color-gray-600,#4b5563))] hover:border-[color:var(--mcp-ui-info-border,var(--color-teal-500))] rounded cursor-pointer transition-colors align-middle"',
562
562
  ` data-citation-page="${pageNum}"`,
563
563
  ` data-citation-doc="${safeDocName}"`,
564
564
  ' data-citation-verified="true"',
@@ -616,7 +616,7 @@ export function renderCellValue(value: any, citationCtx?: CitationCtx, mathRende
616
616
  const label = value.name || value.label || value.title || value.url
617
617
  const sanitizedLabel = sanitizeHtml(String(label))
618
618
  const sanitizedUrl = sanitizeHtml(String(value.url))
619
- const anchor = `<a href="${sanitizedUrl}" target="_blank" rel="noopener noreferrer" class="text-blue-600 dark:text-blue-400 hover:underline">${sanitizedLabel}</a>`
619
+ const anchor = `<a href="${sanitizedUrl}" target="_blank" rel="noopener noreferrer" class="text-[color:var(--mcp-ui-accent,var(--color-blue-600))] dark:text-[color:var(--mcp-ui-accent,var(--color-blue-400))] hover:underline">${sanitizedLabel}</a>`
620
620
  // Re-sanitize the composed anchor: sanitizing the bare `url` string
621
621
  // leaves quotes and `javascript:` untouched, so a crafted value could
622
622
  // otherwise break out of the attribute or smuggle a scriptable href.
@@ -675,7 +675,7 @@ export function renderCellValue(value: any, citationCtx?: CitationCtx, mathRende
675
675
  // Replace all markdown links with HTML links
676
676
  const htmlValue = strValue.replace(
677
677
  /\[([^\]]+)\]\(([^)]+)\)/g,
678
- '<a href="$2" target="_blank" rel="noopener noreferrer" class="text-blue-600 dark:text-blue-400 hover:underline">$1</a>'
678
+ '<a href="$2" target="_blank" rel="noopener noreferrer" class="text-[color:var(--mcp-ui-accent,var(--color-blue-600))] dark:text-[color:var(--mcp-ui-accent,var(--color-blue-400))] hover:underline">$1</a>'
679
679
  )
680
680
  return sanitizeHtml(htmlValue, SANITIZE_PROFILES.cellLink)
681
681
  }
@@ -1035,13 +1035,13 @@ function TableRenderer(props: {
1035
1035
 
1036
1036
  // Standard table body (non-virtualized) — uses client pagination when active
1037
1037
  const StandardTableBody = () => (
1038
- <tbody class="bg-white dark:bg-gray-800 divide-y divide-gray-200 dark:divide-gray-700">
1038
+ <tbody class="bg-[color:var(--mcp-ui-surface,var(--color-white,#fff))] dark:bg-[color:var(--mcp-ui-surface,var(--color-gray-800,#1f2937))] divide-y divide-[color:var(--mcp-ui-border,var(--color-gray-200,#e5e7eb))] dark:divide-[color:var(--mcp-ui-border,var(--color-gray-700,#374151))]">
1039
1039
  <For each={clientVisibleRows().slice(0, DEFAULT_RESOURCE_LIMITS.maxTableRows)}>
1040
1040
  {(row: any, i) => (
1041
- <tr class={`hover:bg-gray-50 dark:hover:bg-gray-700/50 transition-colors ${i() % 2 === 0 ? 'bg-white dark:bg-gray-800' : 'bg-gray-50/30 dark:bg-gray-800/50'}`}>
1041
+ <tr class={`hover:bg-[color:var(--mcp-ui-surface-hover,var(--color-gray-50,#f9fafb))] dark:hover:bg-[color:var(--mcp-ui-surface-hover,color-mix(in_oklab,var(--color-gray-700,#374151)_50%,transparent))] transition-colors ${i() % 2 === 0 ? 'bg-[color:var(--mcp-ui-surface,var(--color-white,#fff))] dark:bg-[color:var(--mcp-ui-surface,var(--color-gray-800,#1f2937))]' : 'bg-[color:var(--mcp-ui-surface-muted,color-mix(in_oklab,var(--color-gray-50,#f9fafb)_30%,transparent))] dark:bg-[color:var(--mcp-ui-surface,color-mix(in_oklab,var(--color-gray-800,#1f2937)_50%,transparent))]'}`}>
1042
1042
  <For each={tableParams.columns}>
1043
1043
  {(column: any) => (
1044
- <td class="px-6 py-4 text-sm text-gray-700 dark:text-gray-200 whitespace-normal break-words leading-relaxed first:pl-6 last:pr-6">
1044
+ <td class="px-6 py-4 text-sm text-[color:var(--mcp-ui-fg,var(--color-gray-700,#374151))] dark:text-[color:var(--mcp-ui-fg,var(--color-gray-200,#e5e7eb))] whitespace-normal break-words leading-relaxed first:pl-6 last:pr-6">
1045
1045
  <Show
1046
1046
  when={!isMissingCellValue(row[column.key])}
1047
1047
  fallback={<MissingValueMark />}
@@ -1069,7 +1069,7 @@ function TableRenderer(props: {
1069
1069
 
1070
1070
  return (
1071
1071
  <tbody
1072
- class="bg-white dark:bg-gray-800 relative"
1072
+ class="bg-[color:var(--mcp-ui-surface,var(--color-white,#fff))] dark:bg-[color:var(--mcp-ui-surface,var(--color-gray-800,#1f2937))] relative"
1073
1073
  style={{ height: `${totalSize}px` }}
1074
1074
  >
1075
1075
  <For each={items}>
@@ -1077,7 +1077,7 @@ function TableRenderer(props: {
1077
1077
  const row = tableParams.rows[virtualRow.index]
1078
1078
  return (
1079
1079
  <tr
1080
- class={`hover:bg-gray-50 dark:hover:bg-gray-700/50 transition-colors absolute left-0 right-0 ${virtualRow.index % 2 === 0 ? 'bg-white dark:bg-gray-800' : 'bg-gray-50/30 dark:bg-gray-800/50'}`}
1080
+ class={`hover:bg-[color:var(--mcp-ui-surface-hover,var(--color-gray-50,#f9fafb))] dark:hover:bg-[color:var(--mcp-ui-surface-hover,color-mix(in_oklab,var(--color-gray-700,#374151)_50%,transparent))] transition-colors absolute left-0 right-0 ${virtualRow.index % 2 === 0 ? 'bg-[color:var(--mcp-ui-surface,var(--color-white,#fff))] dark:bg-[color:var(--mcp-ui-surface,var(--color-gray-800,#1f2937))]' : 'bg-[color:var(--mcp-ui-surface-muted,color-mix(in_oklab,var(--color-gray-50,#f9fafb)_30%,transparent))] dark:bg-[color:var(--mcp-ui-surface,color-mix(in_oklab,var(--color-gray-800,#1f2937)_50%,transparent))]'}`}
1081
1081
  style={{
1082
1082
  height: `${rowHeight}px`,
1083
1083
  transform: `translateY(${virtualRow.start}px)`
@@ -1085,7 +1085,7 @@ function TableRenderer(props: {
1085
1085
  >
1086
1086
  <For each={tableParams.columns}>
1087
1087
  {(column: any) => (
1088
- <td class="px-6 py-4 text-sm text-gray-700 dark:text-gray-200 whitespace-normal break-words leading-relaxed first:pl-6 last:pr-6">
1088
+ <td class="px-6 py-4 text-sm text-[color:var(--mcp-ui-fg,var(--color-gray-700,#374151))] dark:text-[color:var(--mcp-ui-fg,var(--color-gray-200,#e5e7eb))] whitespace-normal break-words leading-relaxed first:pl-6 last:pr-6">
1089
1089
  <Show
1090
1090
  when={!isMissingCellValue(row[column.key])}
1091
1091
  fallback={<MissingValueMark />}
@@ -1105,7 +1105,7 @@ function TableRenderer(props: {
1105
1105
 
1106
1106
  return (
1107
1107
  <ExpandableWrapper title={tableParams.title || strings.tableTitle} copyData={getTableCSV()} copyLabel={strings.tableCopyCsv} toolbarVariant={props.toolbarVariant} onExpandedChange={setSelfExpanded}>
1108
- <div class={`relative w-full bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 overflow-hidden group ${
1108
+ <div class={`relative w-full bg-[color:var(--mcp-ui-surface,var(--color-white,#fff))] dark:bg-[color:var(--mcp-ui-surface,var(--color-gray-800,#1f2937))] rounded-lg shadow-[var(--mcp-ui-shadow,var(--shadow-sm))] border border-[color:var(--mcp-ui-border,var(--color-gray-200,#e5e7eb))] dark:border-[color:var(--mcp-ui-border,var(--color-gray-700,#374151))] overflow-hidden group ${
1109
1109
  isExpanded() ? 'flex-1 min-h-0 flex flex-col' : 'h-full'
1110
1110
  } ${tableParams.className || ''}`}>
1111
1111
  <Show when={exportable} fallback={<CopyButton getText={getTableCSV} title={strings.tableCopyCsv} position="top-right" />}>
@@ -1113,13 +1113,13 @@ function TableRenderer(props: {
1113
1113
  <button
1114
1114
  ref={exportTriggerRef}
1115
1115
  onClick={() => setShowExportMenu(!showExportMenu())}
1116
- class="opacity-60 hover:opacity-100 px-2 py-1 bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-600 rounded-full hover:bg-gray-100 dark:hover:bg-gray-700 transition-all shadow-sm"
1116
+ class="opacity-60 hover:opacity-100 px-2 py-1 bg-[color:var(--mcp-ui-surface,var(--color-white,#fff))] dark:bg-[color:var(--mcp-ui-surface,var(--color-gray-800,#1f2937))] border border-[color:var(--mcp-ui-border,var(--color-gray-200,#e5e7eb))] dark:border-[color:var(--mcp-ui-border,var(--color-gray-600,#4b5563))] rounded-full hover:bg-[color:var(--mcp-ui-surface-hover,var(--color-gray-100,#f3f4f6))] dark:hover:bg-[color:var(--mcp-ui-surface-hover,var(--color-gray-700,#374151))] transition-all shadow-[var(--mcp-ui-shadow,var(--shadow-sm))]"
1117
1117
  title={strings.tableExport}
1118
1118
  aria-label={strings.tableExport}
1119
1119
  aria-haspopup="menu"
1120
1120
  aria-expanded={showExportMenu()}
1121
1121
  >
1122
- <svg class="w-3 h-3 text-gray-500 dark:text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
1122
+ <svg class="w-3 h-3 text-[color:var(--mcp-ui-fg-muted,var(--color-gray-500,#6b7280))] dark:text-[color:var(--mcp-ui-fg-subtle,var(--color-gray-400,#9ca3af))]" fill="none" viewBox="0 0 24 24" stroke="currentColor">
1123
1123
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
1124
1124
  </svg>
1125
1125
  </button>
@@ -1130,23 +1130,23 @@ function TableRenderer(props: {
1130
1130
  width={144}
1131
1131
  >
1132
1132
  <Show when={(exportFormats as string[]).includes('tsv')}>
1133
- <button onClick={() => handleExport('tsv')} class="w-full text-left px-3 py-1.5 hover:bg-gray-100 dark:hover:bg-gray-700 text-gray-700 dark:text-gray-300">{strings.tableCopyTsv}</button>
1133
+ <button onClick={() => handleExport('tsv')} class="w-full text-left px-3 py-1.5 hover:bg-[color:var(--mcp-ui-surface-hover,var(--color-gray-100,#f3f4f6))] dark:hover:bg-[color:var(--mcp-ui-surface-hover,var(--color-gray-700,#374151))] text-[color:var(--mcp-ui-fg,var(--color-gray-700,#374151))] dark:text-[color:var(--mcp-ui-fg,var(--color-gray-300,#d1d5db))]">{strings.tableCopyTsv}</button>
1134
1134
  </Show>
1135
1135
  <Show when={(exportFormats as string[]).includes('csv')}>
1136
- <button onClick={() => handleExport('csv')} class="w-full text-left px-3 py-1.5 hover:bg-gray-100 dark:hover:bg-gray-700 text-gray-700 dark:text-gray-300">{strings.tableDownloadCsv}</button>
1136
+ <button onClick={() => handleExport('csv')} class="w-full text-left px-3 py-1.5 hover:bg-[color:var(--mcp-ui-surface-hover,var(--color-gray-100,#f3f4f6))] dark:hover:bg-[color:var(--mcp-ui-surface-hover,var(--color-gray-700,#374151))] text-[color:var(--mcp-ui-fg,var(--color-gray-700,#374151))] dark:text-[color:var(--mcp-ui-fg,var(--color-gray-300,#d1d5db))]">{strings.tableDownloadCsv}</button>
1137
1137
  </Show>
1138
1138
  <Show when={(exportFormats as string[]).includes('json')}>
1139
- <button onClick={() => handleExport('json')} class="w-full text-left px-3 py-1.5 hover:bg-gray-100 dark:hover:bg-gray-700 text-gray-700 dark:text-gray-300">{strings.tableDownloadJson}</button>
1139
+ <button onClick={() => handleExport('json')} class="w-full text-left px-3 py-1.5 hover:bg-[color:var(--mcp-ui-surface-hover,var(--color-gray-100,#f3f4f6))] dark:hover:bg-[color:var(--mcp-ui-surface-hover,var(--color-gray-700,#374151))] text-[color:var(--mcp-ui-fg,var(--color-gray-700,#374151))] dark:text-[color:var(--mcp-ui-fg,var(--color-gray-300,#d1d5db))]">{strings.tableDownloadJson}</button>
1140
1140
  </Show>
1141
1141
  </PortalDropdownMenu>
1142
1142
  </div>
1143
1143
  </Show>
1144
1144
  <div class={`p-4 ${isExpanded() ? 'flex-1 min-h-0 flex flex-col' : ''}`}>
1145
1145
  <Show when={tableParams.title}>
1146
- <h3 id={`${tableId}-title`} class="text-sm font-semibold text-gray-900 dark:text-white mb-3 flex-shrink-0">
1146
+ <h3 id={`${tableId}-title`} class="text-sm font-semibold text-[color:var(--mcp-ui-fg,var(--color-gray-900,#111827))] dark:text-[color:var(--mcp-ui-fg,var(--color-white,#fff))] mb-3 flex-shrink-0">
1147
1147
  {tableParams.title}
1148
1148
  <Show when={isVirtualizing()}>
1149
- <span class="ml-2 text-xs font-normal text-gray-400">
1149
+ <span class="ml-2 text-xs font-normal text-[color:var(--mcp-ui-fg-subtle,var(--color-gray-400,#9ca3af))]">
1150
1150
  {formatMCPUIString(strings.tableVirtualizedRows, { count: tableParams.rows?.length ?? 0 })}
1151
1151
  </span>
1152
1152
  </Show>
@@ -1156,25 +1156,25 @@ function TableRenderer(props: {
1156
1156
  {/* Search input (v4.3.3) */}
1157
1157
  <Show when={isSearchable()}>
1158
1158
  <div class="relative mb-3">
1159
- <span class="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 pointer-events-none text-sm">{'\uD83D\uDD0D'}</span>
1159
+ <span class="absolute left-3 top-1/2 -translate-y-1/2 text-[color:var(--mcp-ui-fg-subtle,var(--color-gray-400,#9ca3af))] pointer-events-none text-sm">{'\uD83D\uDD0D'}</span>
1160
1160
  <input
1161
1161
  type="text"
1162
1162
  value={searchQuery()}
1163
1163
  onInput={(e) => handleSearch(e.currentTarget.value)}
1164
1164
  placeholder={searchPlaceholder()}
1165
- class="w-full max-w-xs min-w-[200px] pl-8 pr-8 py-1.5 text-sm border border-gray-200 dark:border-gray-600 rounded-md bg-white dark:bg-gray-700 text-gray-900 dark:text-white placeholder-gray-400 focus:border-blue-400 focus:ring-1 focus:ring-blue-400 outline-none"
1165
+ class="w-full max-w-xs min-w-[200px] pl-8 pr-8 py-1.5 text-sm border border-[color:var(--mcp-ui-border,var(--color-gray-200,#e5e7eb))] dark:border-[color:var(--mcp-ui-border,var(--color-gray-600,#4b5563))] rounded-md bg-[color:var(--mcp-ui-surface,var(--color-white,#fff))] dark:bg-[color:var(--mcp-ui-surface-muted,var(--color-gray-700,#374151))] text-[color:var(--mcp-ui-fg,var(--color-gray-900,#111827))] dark:text-[color:var(--mcp-ui-fg,var(--color-white,#fff))] placeholder-[color:var(--mcp-ui-fg-subtle,var(--color-gray-400,#9ca3af))] focus:border-[color:var(--mcp-ui-focus,var(--color-blue-400))] focus:ring-1 focus:ring-[color:var(--mcp-ui-focus,var(--color-blue-400))] outline-none"
1166
1166
  />
1167
1167
  <Show when={searchQuery()}>
1168
1168
  <button
1169
1169
  type="button"
1170
1170
  onClick={() => { handleSearch(''); setSearchQuery(''); setDebouncedQuery('') }}
1171
- class="absolute right-2 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 text-sm"
1171
+ class="absolute right-2 top-1/2 -translate-y-1/2 text-[color:var(--mcp-ui-fg-subtle,var(--color-gray-400,#9ca3af))] hover:text-[color:var(--mcp-ui-fg-muted,var(--color-gray-600,#4b5563))] dark:hover:text-[color:var(--mcp-ui-fg,var(--color-gray-300,#d1d5db))] text-sm"
1172
1172
  aria-label={strings.tableClearSearch}
1173
1173
  >&times;</button>
1174
1174
  </Show>
1175
1175
  </div>
1176
1176
  <Show when={debouncedQuery() && filteredRows().length !== sortedRows().length}>
1177
- <p class="text-xs text-gray-500 dark:text-gray-400 mb-2">
1177
+ <p class="text-xs text-[color:var(--mcp-ui-fg-muted,var(--color-gray-500,#6b7280))] dark:text-[color:var(--mcp-ui-fg-subtle,var(--color-gray-400,#9ca3af))] mb-2">
1178
1178
  {formatMCPUIString(
1179
1179
  filteredRows().length === 1 ? strings.tableSearchResultsOne : strings.tableSearchResultsMany,
1180
1180
  { count: filteredRows().length, total: sortedRows().length }
@@ -1213,16 +1213,16 @@ function TableRenderer(props: {
1213
1213
  tabindex="0"
1214
1214
  >
1215
1215
  <table
1216
- class="min-w-full divide-y divide-gray-200 dark:divide-gray-700 border-separate border-spacing-0"
1216
+ class="min-w-full divide-y divide-[color:var(--mcp-ui-border,var(--color-gray-200,#e5e7eb))] dark:divide-[color:var(--mcp-ui-border,var(--color-gray-700,#374151))] border-separate border-spacing-0"
1217
1217
  aria-labelledby={tableParams.title ? `${tableId}-title` : undefined}
1218
1218
  >
1219
- <thead class="bg-gray-100 dark:bg-gray-900 sticky top-0 z-10">
1219
+ <thead class="bg-[color:var(--mcp-ui-surface-muted,var(--color-gray-100,#f3f4f6))] dark:bg-[color:var(--mcp-ui-surface,var(--color-gray-900,#111827))] sticky top-0 z-10">
1220
1220
  <tr>
1221
1221
  <For each={tableParams.columns}>
1222
1222
  {(column: any) => (
1223
1223
  <th
1224
1224
  scope="col"
1225
- class="px-6 py-3 text-left text-xs font-semibold text-gray-500 dark:text-gray-400 uppercase tracking-wider border-b border-gray-200 dark:border-gray-700 first:pl-6 last:pr-6 bg-gray-100 dark:bg-gray-900 cursor-pointer select-none hover:bg-gray-200 dark:hover:bg-gray-800 transition-colors"
1225
+ class="px-6 py-3 text-left text-xs font-semibold text-[color:var(--mcp-ui-fg-muted,var(--color-gray-500,#6b7280))] dark:text-[color:var(--mcp-ui-fg-subtle,var(--color-gray-400,#9ca3af))] uppercase tracking-wider border-b border-[color:var(--mcp-ui-border,var(--color-gray-200,#e5e7eb))] dark:border-[color:var(--mcp-ui-border,var(--color-gray-700,#374151))] first:pl-6 last:pr-6 bg-[color:var(--mcp-ui-surface-muted,var(--color-gray-100,#f3f4f6))] dark:bg-[color:var(--mcp-ui-surface,var(--color-gray-900,#111827))] cursor-pointer select-none hover:bg-[color:var(--mcp-ui-surface-hover,var(--color-gray-200,#e5e7eb))] dark:hover:bg-[color:var(--mcp-ui-surface-hover,var(--color-gray-800,#1f2937))] transition-colors"
1226
1226
  style={column.width ? { width: column.width } : {}}
1227
1227
  on:click={() => handleSort(column.key)}
1228
1228
  title={formatMCPUIString(strings.sortBy, { column: column.label })}
@@ -1233,7 +1233,7 @@ function TableRenderer(props: {
1233
1233
  class="text-[10px] leading-none"
1234
1234
  classList={{
1235
1235
  'opacity-30': sortKey() !== column.key,
1236
- 'opacity-100 text-blue-600 dark:text-blue-400': sortKey() === column.key,
1236
+ 'opacity-100 text-[color:var(--mcp-ui-accent,var(--color-blue-600))] dark:text-[color:var(--mcp-ui-accent,var(--color-blue-400))]': sortKey() === column.key,
1237
1237
  }}
1238
1238
  >
1239
1239
  {sortIndicator(column.key)}
@@ -1257,7 +1257,7 @@ function TableRenderer(props: {
1257
1257
 
1258
1258
  {/* Server-side pagination (legacy) */}
1259
1259
  <Show when={tableParams.pagination}>
1260
- <div class="mt-3 flex items-center justify-between text-xs text-gray-500 dark:text-gray-400">
1260
+ <div class="mt-3 flex items-center justify-between text-xs text-[color:var(--mcp-ui-fg-muted,var(--color-gray-500,#6b7280))] dark:text-[color:var(--mcp-ui-fg-subtle,var(--color-gray-400,#9ca3af))]">
1261
1261
  <span>
1262
1262
  {formatMCPUIString(strings.tableServerPageRange, {
1263
1263
  start: tableParams.pagination.currentPage * tableParams.pagination.pageSize + 1,
@@ -1273,14 +1273,14 @@ function TableRenderer(props: {
1273
1273
 
1274
1274
  {/* Client-side pagination (v4.3.7) */}
1275
1275
  <Show when={needsClientPagination()}>
1276
- <div class="mt-3 flex items-center justify-between text-xs text-gray-500 dark:text-gray-400">
1276
+ <div class="mt-3 flex items-center justify-between text-xs text-[color:var(--mcp-ui-fg-muted,var(--color-gray-500,#6b7280))] dark:text-[color:var(--mcp-ui-fg-subtle,var(--color-gray-400,#9ca3af))]">
1277
1277
  <span>
1278
1278
  {clientRangeStart()}&ndash;{clientRangeEnd()} / {filteredRows().length.toLocaleString(strings.locale)}
1279
1279
  </span>
1280
1280
  <div class="flex items-center gap-2">
1281
1281
  <button
1282
1282
  type="button"
1283
- class="px-2 py-1 rounded hover:bg-gray-100 dark:hover:bg-gray-700 disabled:opacity-40 disabled:cursor-not-allowed transition-colors"
1283
+ class="px-2 py-1 rounded hover:bg-[color:var(--mcp-ui-surface-hover,var(--color-gray-100,#f3f4f6))] dark:hover:bg-[color:var(--mcp-ui-surface-hover,var(--color-gray-700,#374151))] disabled:opacity-40 disabled:cursor-not-allowed transition-colors"
1284
1284
  disabled={clientPage() === 0}
1285
1285
  onClick={() => setClientPage(p => p - 1)}
1286
1286
  aria-label={strings.paginationPrevious}
@@ -1291,7 +1291,7 @@ function TableRenderer(props: {
1291
1291
  <span aria-live="polite">{clientPage() + 1} / {clientTotalPages()}</span>
1292
1292
  <button
1293
1293
  type="button"
1294
- class="px-2 py-1 rounded hover:bg-gray-100 dark:hover:bg-gray-700 disabled:opacity-40 disabled:cursor-not-allowed transition-colors"
1294
+ class="px-2 py-1 rounded hover:bg-[color:var(--mcp-ui-surface-hover,var(--color-gray-100,#f3f4f6))] dark:hover:bg-[color:var(--mcp-ui-surface-hover,var(--color-gray-700,#374151))] disabled:opacity-40 disabled:cursor-not-allowed transition-colors"
1295
1295
  disabled={clientPage() >= clientTotalPages() - 1}
1296
1296
  onClick={() => setClientPage(p => p + 1)}
1297
1297
  aria-label={strings.paginationNext}
@@ -1302,7 +1302,7 @@ function TableRenderer(props: {
1302
1302
  {/* Page size selector — fullscreen only */}
1303
1303
  <Show when={isExpanded() && filteredRows().length > 10}>
1304
1304
  <select
1305
- class="ml-2 px-1 py-0.5 text-xs border border-gray-200 dark:border-gray-600 rounded bg-white dark:bg-gray-700 text-gray-700 dark:text-gray-300"
1305
+ class="ml-2 px-1 py-0.5 text-xs border border-[color:var(--mcp-ui-border,var(--color-gray-200,#e5e7eb))] dark:border-[color:var(--mcp-ui-border,var(--color-gray-600,#4b5563))] rounded bg-[color:var(--mcp-ui-surface,var(--color-white,#fff))] dark:bg-[color:var(--mcp-ui-surface-muted,var(--color-gray-700,#374151))] text-[color:var(--mcp-ui-fg,var(--color-gray-700,#374151))] dark:text-[color:var(--mcp-ui-fg,var(--color-gray-300,#d1d5db))]"
1306
1306
  value={clientPageSize()}
1307
1307
  onChange={(e) => handlePageSizeChange(Number(e.currentTarget.value))}
1308
1308
  aria-label={strings.paginationPageSize}
@@ -1312,7 +1312,7 @@ function TableRenderer(props: {
1312
1312
  {(opt) => <option value={opt.value}>{opt.label}</option>}
1313
1313
  </For>
1314
1314
  </select>
1315
- <span class="text-gray-400">{strings.perPageSuffix}</span>
1315
+ <span class="text-[color:var(--mcp-ui-fg-subtle,var(--color-gray-400,#9ca3af))]">{strings.perPageSuffix}</span>
1316
1316
  </Show>
1317
1317
  </div>
1318
1318
  </div>
@@ -1339,17 +1339,17 @@ function MetricRenderer(props: { component: UIComponent }) {
1339
1339
  }
1340
1340
 
1341
1341
  return (
1342
- <div class="relative w-full h-full bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 p-4 group">
1342
+ <div class="relative w-full h-full bg-[color:var(--mcp-ui-surface,var(--color-white,#fff))] dark:bg-[color:var(--mcp-ui-surface,var(--color-gray-800,#1f2937))] rounded-lg shadow-[var(--mcp-ui-shadow,var(--shadow-sm))] border border-[color:var(--mcp-ui-border,var(--color-gray-200,#e5e7eb))] dark:border-[color:var(--mcp-ui-border,var(--color-gray-700,#374151))] p-4 group">
1343
1343
  <CopyButton getText={getMetricText} title={strings.copyMetric} position="top-right" />
1344
1344
  <div class="flex flex-col h-full justify-between">
1345
1345
  <div>
1346
- <p class="text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wide">
1346
+ <p class="text-xs font-medium text-[color:var(--mcp-ui-fg-muted,var(--color-gray-500,#6b7280))] dark:text-[color:var(--mcp-ui-fg-subtle,var(--color-gray-400,#9ca3af))] uppercase tracking-wide">
1347
1347
  {metricParams.title}
1348
1348
  </p>
1349
1349
  <div class="mt-2 flex items-baseline">
1350
- <p class="text-2xl font-semibold text-gray-900 dark:text-white">{metricParams.value}</p>
1350
+ <p class="text-2xl font-semibold text-[color:var(--mcp-ui-fg,var(--color-gray-900,#111827))] dark:text-[color:var(--mcp-ui-fg,var(--color-white,#fff))]">{metricParams.value}</p>
1351
1351
  <Show when={metricParams.unit}>
1352
- <span class="ml-2 text-sm font-medium text-gray-500 dark:text-gray-400">
1352
+ <span class="ml-2 text-sm font-medium text-[color:var(--mcp-ui-fg-muted,var(--color-gray-500,#6b7280))] dark:text-[color:var(--mcp-ui-fg-subtle,var(--color-gray-400,#9ca3af))]">
1353
1353
  {metricParams.unit}
1354
1354
  </span>
1355
1355
  </Show>
@@ -1360,10 +1360,10 @@ function MetricRenderer(props: { component: UIComponent }) {
1360
1360
  <div class="mt-3 flex items-center">
1361
1361
  <span
1362
1362
  class={`text-sm font-medium ${metricParams.trend.direction === 'up'
1363
- ? 'text-green-600 dark:text-green-400'
1363
+ ? 'text-[color:var(--mcp-ui-success,var(--color-green-600))] dark:text-[color:var(--mcp-ui-success,var(--color-green-400))]'
1364
1364
  : metricParams.trend.direction === 'down'
1365
- ? 'text-red-600 dark:text-red-400'
1366
- : 'text-gray-600 dark:text-gray-400'
1365
+ ? 'text-[color:var(--mcp-ui-danger,var(--color-red-600))] dark:text-[color:var(--mcp-ui-danger,var(--color-red-400))]'
1366
+ : 'text-[color:var(--mcp-ui-fg-muted,var(--color-gray-600,#4b5563))] dark:text-[color:var(--mcp-ui-fg-subtle,var(--color-gray-400,#9ca3af))]'
1367
1367
  }`}
1368
1368
  >
1369
1369
  {metricParams.trend.direction === 'up'
@@ -1377,7 +1377,7 @@ function MetricRenderer(props: { component: UIComponent }) {
1377
1377
  </Show>
1378
1378
 
1379
1379
  <Show when={metricParams.subtitle}>
1380
- <p class="mt-2 text-xs text-gray-500 dark:text-gray-400">{metricParams.subtitle}</p>
1380
+ <p class="mt-2 text-xs text-[color:var(--mcp-ui-fg-muted,var(--color-gray-500,#6b7280))] dark:text-[color:var(--mcp-ui-fg-subtle,var(--color-gray-400,#9ca3af))]">{metricParams.subtitle}</p>
1381
1381
  </Show>
1382
1382
  </div>
1383
1383
  </div>
@@ -1468,7 +1468,7 @@ function TextRenderer(props: { component: UIComponent }) {
1468
1468
  <Show
1469
1469
  when={imageData()}
1470
1470
  fallback={
1471
- <div class="relative w-full h-full bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 p-4 group">
1471
+ <div class="relative w-full h-full bg-[color:var(--mcp-ui-surface,var(--color-white,#fff))] dark:bg-[color:var(--mcp-ui-surface,var(--color-gray-800,#1f2937))] rounded-lg shadow-[var(--mcp-ui-shadow,var(--shadow-sm))] border border-[color:var(--mcp-ui-border,var(--color-gray-200,#e5e7eb))] dark:border-[color:var(--mcp-ui-border,var(--color-gray-700,#374151))] p-4 group">
1472
1472
  <CopyButton getText={getTextContent} title={strings.copyText} position="top-right" />
1473
1473
  <SafeHtml
1474
1474
  class={`prose prose-sm dark:prose-invert max-w-none ${textParams.className || ''}`}
@@ -1483,13 +1483,13 @@ function TextRenderer(props: { component: UIComponent }) {
1483
1483
  <img
1484
1484
  src={data().imageUrl}
1485
1485
  alt={data().alt}
1486
- class="max-w-full max-h-[400px] object-contain rounded shadow-sm hover:opacity-90 transition-opacity"
1486
+ class="max-w-full max-h-[400px] object-contain rounded shadow-[var(--mcp-ui-shadow,var(--shadow-sm))] hover:opacity-90 transition-opacity"
1487
1487
  loading="lazy"
1488
1488
  />
1489
1489
  )
1490
1490
  return (
1491
- <div class="w-full h-full bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 overflow-hidden flex flex-col">
1492
- <div class="flex-1 flex items-center justify-center p-4 bg-gray-50 dark:bg-gray-900 min-h-[200px]">
1491
+ <div class="w-full h-full bg-[color:var(--mcp-ui-surface,var(--color-white,#fff))] dark:bg-[color:var(--mcp-ui-surface,var(--color-gray-800,#1f2937))] rounded-lg shadow-[var(--mcp-ui-shadow,var(--shadow-sm))] border border-[color:var(--mcp-ui-border,var(--color-gray-200,#e5e7eb))] dark:border-[color:var(--mcp-ui-border,var(--color-gray-700,#374151))] overflow-hidden flex flex-col">
1492
+ <div class="flex-1 flex items-center justify-center p-4 bg-[color:var(--mcp-ui-surface-muted,var(--color-gray-50,#f9fafb))] dark:bg-[color:var(--mcp-ui-surface,var(--color-gray-900,#111827))] min-h-[200px]">
1493
1493
  {/* The anchor only exists when the link URL passed `safeUrl` — a
1494
1494
  `javascript:` link degrades to a plain, unlinked image. */}
1495
1495
  <Show when={data().linkUrl} fallback={image()}>
@@ -1500,8 +1500,8 @@ function TextRenderer(props: { component: UIComponent }) {
1500
1500
  )}
1501
1501
  </Show>
1502
1502
  </div>
1503
- <div class="p-3 border-t border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800">
1504
- <p class="text-sm text-gray-600 dark:text-gray-400 text-center italic">{data().credit}</p>
1503
+ <div class="p-3 border-t border-[color:var(--mcp-ui-border,var(--color-gray-200,#e5e7eb))] dark:border-[color:var(--mcp-ui-border,var(--color-gray-700,#374151))] bg-[color:var(--mcp-ui-surface,var(--color-white,#fff))] dark:bg-[color:var(--mcp-ui-surface,var(--color-gray-800,#1f2937))]">
1504
+ <p class="text-sm text-[color:var(--mcp-ui-fg-muted,var(--color-gray-600,#4b5563))] dark:text-[color:var(--mcp-ui-fg-subtle,var(--color-gray-400,#9ca3af))] text-center italic">{data().credit}</p>
1505
1505
  </div>
1506
1506
  </div>
1507
1507
  )
@@ -1522,10 +1522,10 @@ function IframeRenderer(props: { component: UIComponent }) {
1522
1522
  // the `credentialless` decision.
1523
1523
  const trustOptions = () => ({ customTrustedDomains: config.customTrustedIframeDomains })
1524
1524
  return (
1525
- <div class="w-full h-full bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 overflow-hidden flex flex-col">
1525
+ <div class="w-full h-full bg-[color:var(--mcp-ui-surface,var(--color-white,#fff))] dark:bg-[color:var(--mcp-ui-surface,var(--color-gray-800,#1f2937))] rounded-lg shadow-[var(--mcp-ui-shadow,var(--shadow-sm))] border border-[color:var(--mcp-ui-border,var(--color-gray-200,#e5e7eb))] dark:border-[color:var(--mcp-ui-border,var(--color-gray-700,#374151))] overflow-hidden flex flex-col">
1526
1526
  <Show when={params.title}>
1527
- <div class="px-4 py-2 border-b border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-900">
1528
- <h3 class="text-sm font-semibold text-gray-900 dark:text-white">{params.title}</h3>
1527
+ <div class="px-4 py-2 border-b border-[color:var(--mcp-ui-border,var(--color-gray-200,#e5e7eb))] dark:border-[color:var(--mcp-ui-border,var(--color-gray-700,#374151))] bg-[color:var(--mcp-ui-surface-muted,var(--color-gray-50,#f9fafb))] dark:bg-[color:var(--mcp-ui-surface,var(--color-gray-900,#111827))]">
1528
+ <h3 class="text-sm font-semibold text-[color:var(--mcp-ui-fg,var(--color-gray-900,#111827))] dark:text-[color:var(--mcp-ui-fg,var(--color-white,#fff))]">{params.title}</h3>
1529
1529
  </div>
1530
1530
  </Show>
1531
1531
  <iframe
@@ -1548,7 +1548,7 @@ function IframeRenderer(props: { component: UIComponent }) {
1548
1548
  }
1549
1549
  loading="lazy"
1550
1550
  />
1551
- <IframeFallbackLink url={params.url} class="border-t border-gray-200 dark:border-gray-700" />
1551
+ <IframeFallbackLink url={params.url} class="border-t border-[color:var(--mcp-ui-border,var(--color-gray-200,#e5e7eb))] dark:border-[color:var(--mcp-ui-border,var(--color-gray-700,#374151))]" />
1552
1552
  </div>
1553
1553
  )
1554
1554
  }
@@ -1561,13 +1561,13 @@ function ImageRenderer(props: { component: UIComponent }) {
1561
1561
  const params = props.component.params as any
1562
1562
 
1563
1563
  return (
1564
- <figure class={`w-full h-full bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 overflow-hidden flex flex-col ${params.className || ''}`}>
1565
- <div class="flex-1 flex items-center justify-center p-4 bg-gray-50 dark:bg-gray-900 min-h-[200px]">
1564
+ <figure class={`w-full h-full bg-[color:var(--mcp-ui-surface,var(--color-white,#fff))] dark:bg-[color:var(--mcp-ui-surface,var(--color-gray-800,#1f2937))] rounded-lg shadow-[var(--mcp-ui-shadow,var(--shadow-sm))] border border-[color:var(--mcp-ui-border,var(--color-gray-200,#e5e7eb))] dark:border-[color:var(--mcp-ui-border,var(--color-gray-700,#374151))] overflow-hidden flex flex-col ${params.className || ''}`}>
1565
+ <div class="flex-1 flex items-center justify-center p-4 bg-[color:var(--mcp-ui-surface-muted,var(--color-gray-50,#f9fafb))] dark:bg-[color:var(--mcp-ui-surface,var(--color-gray-900,#111827))] min-h-[200px]">
1566
1566
  <a
1567
1567
  href={safeUrl(params.url)}
1568
1568
  target="_blank"
1569
1569
  rel="noopener noreferrer"
1570
- class="cursor-zoom-in focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 rounded"
1570
+ class="cursor-zoom-in focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-[color:var(--mcp-ui-focus,var(--color-blue-500))] rounded"
1571
1571
  aria-label={formatMCPUIString(strings.imageViewFullSize, {
1572
1572
  alt: params.alt || strings.imageAltFallback,
1573
1573
  })}
@@ -1575,14 +1575,14 @@ function ImageRenderer(props: { component: UIComponent }) {
1575
1575
  <img
1576
1576
  src={safeUrl(params.url, { allowDataImage: true })}
1577
1577
  alt={params.alt || strings.imageAlt}
1578
- class="max-w-full max-h-[500px] object-contain rounded shadow-sm hover:opacity-95 transition-opacity"
1578
+ class="max-w-full max-h-[500px] object-contain rounded shadow-[var(--mcp-ui-shadow,var(--shadow-sm))] hover:opacity-95 transition-opacity"
1579
1579
  loading="lazy"
1580
1580
  />
1581
1581
  </a>
1582
1582
  </div>
1583
1583
  <Show when={params.caption}>
1584
- <figcaption class="p-3 border-t border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800">
1585
- <p class="text-sm text-gray-600 dark:text-gray-400 text-center">{params.caption}</p>
1584
+ <figcaption class="p-3 border-t border-[color:var(--mcp-ui-border,var(--color-gray-200,#e5e7eb))] dark:border-[color:var(--mcp-ui-border,var(--color-gray-700,#374151))] bg-[color:var(--mcp-ui-surface,var(--color-white,#fff))] dark:bg-[color:var(--mcp-ui-surface,var(--color-gray-800,#1f2937))]">
1585
+ <p class="text-sm text-[color:var(--mcp-ui-fg-muted,var(--color-gray-600,#4b5563))] dark:text-[color:var(--mcp-ui-fg-subtle,var(--color-gray-400,#9ca3af))] text-center">{params.caption}</p>
1586
1586
  </figcaption>
1587
1587
  </Show>
1588
1588
  </figure>
@@ -1605,10 +1605,10 @@ function LinkRenderer(props: { component: UIComponent }) {
1605
1605
  label: params.label || strings.linkLabel,
1606
1606
  description: params.description || params.url,
1607
1607
  })}
1608
- class={`flex items-center gap-3 p-4 bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors group h-full focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 ${params.className || ''}`}
1608
+ class={`flex items-center gap-3 p-4 bg-[color:var(--mcp-ui-surface,var(--color-white,#fff))] dark:bg-[color:var(--mcp-ui-surface,var(--color-gray-800,#1f2937))] rounded-lg shadow-[var(--mcp-ui-shadow,var(--shadow-sm))] border border-[color:var(--mcp-ui-border,var(--color-gray-200,#e5e7eb))] dark:border-[color:var(--mcp-ui-border,var(--color-gray-700,#374151))] hover:bg-[color:var(--mcp-ui-surface-hover,var(--color-gray-50,#f9fafb))] dark:hover:bg-[color:var(--mcp-ui-surface-hover,var(--color-gray-700,#374151))] transition-colors group h-full focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-[color:var(--mcp-ui-focus,var(--color-blue-500))] ${params.className || ''}`}
1609
1609
  onClick={(e) => e.stopPropagation()}
1610
1610
  >
1611
- <div class="p-2 bg-blue-50 dark:bg-blue-900/30 rounded-full text-blue-600 dark:text-blue-400 group-hover:bg-blue-100 dark:group-hover:bg-blue-900/50 shrink-0 transition-colors" aria-hidden="true">
1611
+ <div class="p-2 bg-[color:var(--mcp-ui-accent-soft,var(--color-blue-50))] dark:bg-[color:var(--mcp-ui-accent-soft,color-mix(in_oklab,var(--color-blue-900)_30%,transparent))] rounded-full text-[color:var(--mcp-ui-accent,var(--color-blue-600))] dark:text-[color:var(--mcp-ui-accent,var(--color-blue-400))] group-hover:bg-[color:var(--mcp-ui-accent-soft,var(--color-blue-100))] dark:group-hover:bg-[color:var(--mcp-ui-accent-soft,color-mix(in_oklab,var(--color-blue-900)_50%,transparent))] shrink-0 transition-colors" aria-hidden="true">
1612
1612
  <svg
1613
1613
  xmlns="http://www.w3.org/2000/svg"
1614
1614
  class="w-5 h-5"
@@ -1624,16 +1624,16 @@ function LinkRenderer(props: { component: UIComponent }) {
1624
1624
  </svg>
1625
1625
  </div>
1626
1626
  <div class="flex-1 min-w-0">
1627
- <h4 class="text-sm font-medium text-gray-900 dark:text-white truncate group-hover:text-blue-600 dark:group-hover:text-blue-400 transition-colors">
1627
+ <h4 class="text-sm font-medium text-[color:var(--mcp-ui-fg,var(--color-gray-900,#111827))] dark:text-[color:var(--mcp-ui-fg,var(--color-white,#fff))] truncate group-hover:text-[color:var(--mcp-ui-accent,var(--color-blue-600))] dark:group-hover:text-[color:var(--mcp-ui-accent,var(--color-blue-400))] transition-colors">
1628
1628
  {params.label || params.url}
1629
1629
  </h4>
1630
1630
  <Show when={params.description}>
1631
- <p class="text-xs text-gray-500 dark:text-gray-400 truncate">{params.description}</p>
1631
+ <p class="text-xs text-[color:var(--mcp-ui-fg-muted,var(--color-gray-500,#6b7280))] dark:text-[color:var(--mcp-ui-fg-subtle,var(--color-gray-400,#9ca3af))] truncate">{params.description}</p>
1632
1632
  </Show>
1633
1633
  </div>
1634
1634
  <svg
1635
1635
  xmlns="http://www.w3.org/2000/svg"
1636
- class="w-4 h-4 text-gray-400 group-hover:text-gray-600 dark:group-hover:text-gray-300 shrink-0 transition-colors"
1636
+ class="w-4 h-4 text-[color:var(--mcp-ui-fg-subtle,var(--color-gray-400,#9ca3af))] group-hover:text-[color:var(--mcp-ui-fg-muted,var(--color-gray-600,#4b5563))] dark:group-hover:text-[color:var(--mcp-ui-fg,var(--color-gray-300,#d1d5db))] shrink-0 transition-colors"
1637
1637
  viewBox="0 0 24 24"
1638
1638
  fill="none"
1639
1639
  stroke="currentColor"
@@ -1758,7 +1758,7 @@ function ComponentRenderer(props: {
1758
1758
  if (mode === 'inline-warn') {
1759
1759
  return (
1760
1760
  <div
1761
- class="inline-flex items-center gap-1.5 px-2 py-1 rounded-md bg-yellow-50 dark:bg-yellow-900/20 border border-yellow-200 dark:border-yellow-800 text-xs text-yellow-800 dark:text-yellow-200"
1761
+ class="inline-flex items-center gap-1.5 px-2 py-1 rounded-md bg-[color:var(--mcp-ui-warning-soft,var(--color-yellow-50))] dark:bg-[color:var(--mcp-ui-warning-soft,color-mix(in_oklab,var(--color-yellow-900)_20%,transparent))] border border-[color:var(--mcp-ui-warning-border,var(--color-yellow-200))] dark:border-[color:var(--mcp-ui-warning-border,var(--color-yellow-800))] text-xs text-[color:var(--mcp-ui-warning,var(--color-yellow-800))] dark:text-[color:var(--mcp-ui-warning,var(--color-yellow-200))]"
1762
1762
  role="alert"
1763
1763
  aria-label={strings.validationWarning}
1764
1764
  title={firstError}
@@ -1785,9 +1785,9 @@ function ComponentRenderer(props: {
1785
1785
 
1786
1786
  // mode === 'block' (default, pre-v5.4.0 behavior)
1787
1787
  return (
1788
- <div class="w-full h-full bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-lg p-4">
1789
- <p class="text-sm font-medium text-red-900 dark:text-red-100">{strings.validationError}</p>
1790
- <p class="text-xs text-red-700 dark:text-red-300 mt-1">
1788
+ <div class="w-full h-full bg-[color:var(--mcp-ui-danger-soft,var(--color-red-50))] dark:bg-[color:var(--mcp-ui-danger-soft,color-mix(in_oklab,var(--color-red-900)_20%,transparent))] border border-[color:var(--mcp-ui-danger-border,var(--color-red-200))] dark:border-[color:var(--mcp-ui-danger-border,var(--color-red-800))] rounded-lg p-4">
1789
+ <p class="text-sm font-medium text-[color:var(--mcp-ui-danger,var(--color-red-900))] dark:text-[color:var(--mcp-ui-danger,var(--color-red-100))]">{strings.validationError}</p>
1790
+ <p class="text-xs text-[color:var(--mcp-ui-danger,var(--color-red-700))] dark:text-[color:var(--mcp-ui-danger,var(--color-red-300))] mt-1">
1791
1791
  {firstError}
1792
1792
  </p>
1793
1793
  </div>
@@ -1892,7 +1892,7 @@ function UnsupportedComponentFallback(props: { component: UIComponent }) {
1892
1892
  return (
1893
1893
  <div
1894
1894
  role="alert"
1895
- class="w-full rounded-lg border border-amber-300 bg-amber-50 px-3 py-2 text-sm text-amber-800 dark:border-amber-700/50 dark:bg-amber-900/20 dark:text-amber-200"
1895
+ class="w-full rounded-lg border border-[color:var(--mcp-ui-warning-border,var(--color-amber-300))] bg-[color:var(--mcp-ui-warning-soft,var(--color-amber-50))] px-3 py-2 text-sm text-[color:var(--mcp-ui-warning,var(--color-amber-800))] dark:border-[color:var(--mcp-ui-warning-border,color-mix(in_oklab,var(--color-amber-700)_50%,transparent))] dark:bg-[color:var(--mcp-ui-warning-soft,color-mix(in_oklab,var(--color-amber-900)_20%,transparent))] dark:text-[color:var(--mcp-ui-warning,var(--color-amber-200))]"
1896
1896
  >
1897
1897
  {strings.unsupportedComponentType} <code class="font-mono">{props.component.type}</code>
1898
1898
  </div>
@@ -1956,10 +1956,10 @@ function ActionRenderer(props: { component: UIComponent }) {
1956
1956
  target={safeUrl(params.url) ? '_blank' : undefined}
1957
1957
  rel="noopener noreferrer"
1958
1958
  aria-label={params.ariaLabel || params.label}
1959
- class={`inline-flex items-center gap-2 px-4 py-2 rounded-md text-sm font-medium transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500
1960
- ${params.variant === 'primary' ? 'bg-blue-600 text-white hover:bg-blue-700' :
1961
- params.variant === 'outline' ? 'border border-gray-300 text-gray-700 hover:bg-gray-50 dark:border-gray-600 dark:text-gray-300 dark:hover:bg-gray-800' :
1962
- 'text-blue-600 hover:text-blue-800 dark:text-blue-400 dark:hover:text-blue-300'}
1959
+ class={`inline-flex items-center gap-2 px-4 py-2 rounded-md text-sm font-medium transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-[color:var(--mcp-ui-focus,var(--color-blue-500))]
1960
+ ${params.variant === 'primary' ? 'bg-[color:var(--mcp-ui-accent,var(--color-blue-600))] text-[color:var(--mcp-ui-accent-fg,var(--color-white,#fff))] hover:bg-[color:var(--mcp-ui-accent-hover,var(--color-blue-700))]' :
1961
+ params.variant === 'outline' ? 'border border-[color:var(--mcp-ui-border,var(--color-gray-300,#d1d5db))] text-[color:var(--mcp-ui-fg,var(--color-gray-700,#374151))] hover:bg-[color:var(--mcp-ui-surface-hover,var(--color-gray-50,#f9fafb))] dark:border-[color:var(--mcp-ui-border,var(--color-gray-600,#4b5563))] dark:text-[color:var(--mcp-ui-fg,var(--color-gray-300,#d1d5db))] dark:hover:bg-[color:var(--mcp-ui-surface-hover,var(--color-gray-800,#1f2937))]' :
1962
+ 'text-[color:var(--mcp-ui-accent,var(--color-blue-600))] hover:text-[color:var(--mcp-ui-accent,var(--color-blue-800))] dark:text-[color:var(--mcp-ui-accent,var(--color-blue-400))] dark:hover:text-[color:var(--mcp-ui-accent,var(--color-blue-300))]'}
1963
1963
  ${params.className || ''}`}
1964
1964
  onClick={handleClick}
1965
1965
  >
@@ -1977,12 +1977,12 @@ function ActionRenderer(props: { component: UIComponent }) {
1977
1977
  disabled={isDisabled()}
1978
1978
  aria-busy={isExecuting() && isExecutable()}
1979
1979
  aria-label={params.ariaLabel || params.label}
1980
- class={`inline-flex items-center gap-2 px-4 py-2 rounded-md text-sm font-medium transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500
1981
- ${params.variant === 'primary' ? 'bg-blue-600 text-white hover:bg-blue-700 shadow-sm' :
1982
- params.variant === 'secondary' ? 'bg-gray-100 text-gray-900 hover:bg-gray-200 dark:bg-gray-700 dark:text-white dark:hover:bg-gray-600' :
1983
- params.variant === 'outline' ? 'border border-gray-300 text-gray-700 hover:bg-gray-50 dark:border-gray-600 dark:text-gray-300 dark:hover:bg-gray-800' :
1984
- params.variant === 'danger' ? 'bg-red-600 text-white hover:bg-red-700' :
1985
- 'bg-transparent text-gray-700 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-800'}
1980
+ class={`inline-flex items-center gap-2 px-4 py-2 rounded-md text-sm font-medium transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-[color:var(--mcp-ui-focus,var(--color-blue-500))]
1981
+ ${params.variant === 'primary' ? 'bg-[color:var(--mcp-ui-accent,var(--color-blue-600))] text-[color:var(--mcp-ui-accent-fg,var(--color-white,#fff))] hover:bg-[color:var(--mcp-ui-accent-hover,var(--color-blue-700))] shadow-[var(--mcp-ui-shadow,var(--shadow-sm))]' :
1982
+ params.variant === 'secondary' ? 'bg-[color:var(--mcp-ui-surface-muted,var(--color-gray-100,#f3f4f6))] text-[color:var(--mcp-ui-fg,var(--color-gray-900,#111827))] hover:bg-[color:var(--mcp-ui-surface-hover,var(--color-gray-200,#e5e7eb))] dark:bg-[color:var(--mcp-ui-surface-muted,var(--color-gray-700,#374151))] dark:text-[color:var(--mcp-ui-fg,var(--color-white,#fff))] dark:hover:bg-[color:var(--mcp-ui-surface-hover,var(--color-gray-600,#4b5563))]' :
1983
+ params.variant === 'outline' ? 'border border-[color:var(--mcp-ui-border,var(--color-gray-300,#d1d5db))] text-[color:var(--mcp-ui-fg,var(--color-gray-700,#374151))] hover:bg-[color:var(--mcp-ui-surface-hover,var(--color-gray-50,#f9fafb))] dark:border-[color:var(--mcp-ui-border,var(--color-gray-600,#4b5563))] dark:text-[color:var(--mcp-ui-fg,var(--color-gray-300,#d1d5db))] dark:hover:bg-[color:var(--mcp-ui-surface-hover,var(--color-gray-800,#1f2937))]' :
1984
+ params.variant === 'danger' ? 'bg-[color:var(--mcp-ui-danger,var(--color-red-600))] text-[color:var(--mcp-ui-accent-fg,var(--color-white,#fff))] hover:bg-[color:var(--mcp-ui-danger-hover,var(--color-red-700))]' :
1985
+ 'bg-transparent text-[color:var(--mcp-ui-fg,var(--color-gray-700,#374151))] hover:bg-[color:var(--mcp-ui-surface-hover,var(--color-gray-100,#f3f4f6))] dark:text-[color:var(--mcp-ui-fg,var(--color-gray-300,#d1d5db))] dark:hover:bg-[color:var(--mcp-ui-surface-hover,var(--color-gray-800,#1f2937))]'}
1986
1986
  ${isDisabled() ? 'opacity-50 cursor-not-allowed' : ''}
1987
1987
  ${params.size === 'sm' ? 'px-3 py-1.5 text-xs' : params.size === 'lg' ? 'px-6 py-3 text-base' : ''}
1988
1988
  ${params.className || ''}`}
@@ -2017,32 +2017,32 @@ function ErrorCardRenderer(props: { error: any }) {
2017
2017
  }
2018
2018
 
2019
2019
  return (
2020
- <div class="relative w-full bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-lg p-4 group">
2020
+ <div class="relative w-full bg-[color:var(--mcp-ui-danger-soft,var(--color-red-50))] dark:bg-[color:var(--mcp-ui-danger-soft,color-mix(in_oklab,var(--color-red-900)_20%,transparent))] border border-[color:var(--mcp-ui-danger-border,var(--color-red-200))] dark:border-[color:var(--mcp-ui-danger-border,var(--color-red-800))] rounded-lg p-4 group">
2021
2021
  <CopyButton getText={getErrorText} title={strings.copyErrorDetails} position="top-right" />
2022
2022
  <div class="flex items-start gap-3">
2023
- <div class="p-2 bg-red-100 dark:bg-red-900/40 rounded-full shrink-0">
2024
- <svg class="w-5 h-5 text-red-600 dark:text-red-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
2023
+ <div class="p-2 bg-[color:var(--mcp-ui-danger-soft,var(--color-red-100))] dark:bg-[color:var(--mcp-ui-danger-soft,color-mix(in_oklab,var(--color-red-900)_40%,transparent))] rounded-full shrink-0">
2024
+ <svg class="w-5 h-5 text-[color:var(--mcp-ui-danger,var(--color-red-600))] dark:text-[color:var(--mcp-ui-danger,var(--color-red-400))]" fill="none" viewBox="0 0 24 24" stroke="currentColor">
2025
2025
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
2026
2026
  </svg>
2027
2027
  </div>
2028
2028
  <div class="flex-1 min-w-0">
2029
- <h4 class="text-sm font-semibold text-red-800 dark:text-red-200">
2029
+ <h4 class="text-sm font-semibold text-[color:var(--mcp-ui-danger,var(--color-red-800))] dark:text-[color:var(--mcp-ui-danger,var(--color-red-200))]">
2030
2030
  {formatMCPUIString(strings.toolErrorTitle, {
2031
2031
  tool: props.error.tool || strings.errorUnknownToolName,
2032
2032
  })}
2033
2033
  </h4>
2034
- <p class="text-sm text-red-700 dark:text-red-300 mt-1">
2034
+ <p class="text-sm text-[color:var(--mcp-ui-danger,var(--color-red-700))] dark:text-[color:var(--mcp-ui-danger,var(--color-red-300))] mt-1">
2035
2035
  {props.error.message || strings.errorToolExecution}
2036
2036
  </p>
2037
2037
  <Show when={props.error.type}>
2038
- <p class="text-xs text-red-600 dark:text-red-400 mt-1">
2038
+ <p class="text-xs text-[color:var(--mcp-ui-danger,var(--color-red-600))] dark:text-[color:var(--mcp-ui-danger,var(--color-red-400))] mt-1">
2039
2039
  {formatMCPUIString(strings.errorTypeLabel, { type: props.error.type })}
2040
2040
  </p>
2041
2041
  </Show>
2042
2042
  <Show when={props.error.suggestions?.length}>
2043
2043
  <div class="mt-3">
2044
- <p class="text-xs font-medium text-red-700 dark:text-red-300">{strings.errorSuggestions}</p>
2045
- <ul class="mt-1 text-xs text-red-600 dark:text-red-400 list-disc list-inside">
2044
+ <p class="text-xs font-medium text-[color:var(--mcp-ui-danger,var(--color-red-700))] dark:text-[color:var(--mcp-ui-danger,var(--color-red-300))]">{strings.errorSuggestions}</p>
2045
+ <ul class="mt-1 text-xs text-[color:var(--mcp-ui-danger,var(--color-red-600))] dark:text-[color:var(--mcp-ui-danger,var(--color-red-400))] list-disc list-inside">
2046
2046
  <For each={props.error.suggestions}>
2047
2047
  {(suggestion: string) => <li>{suggestion}</li>}
2048
2048
  </For>
@@ -2050,7 +2050,7 @@ function ErrorCardRenderer(props: { error: any }) {
2050
2050
  </div>
2051
2051
  </Show>
2052
2052
  <Show when={mounted() && props.error.timestamp}>
2053
- <p class="text-xs text-red-500 dark:text-red-500 mt-2">
2053
+ <p class="text-xs text-[color:var(--mcp-ui-danger,var(--color-red-500))] dark:text-[color:var(--mcp-ui-danger,var(--color-red-500))] mt-2">
2054
2054
  {new Date(props.error.timestamp).toLocaleString(strings.locale)}
2055
2055
  </p>
2056
2056
  </Show>
@@ -2097,10 +2097,10 @@ function UIResourceHtmlRenderer(props: { resource: any }) {
2097
2097
  }
2098
2098
 
2099
2099
  return (
2100
- <div class="w-full bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 overflow-hidden">
2100
+ <div class="w-full bg-[color:var(--mcp-ui-surface,var(--color-white,#fff))] dark:bg-[color:var(--mcp-ui-surface,var(--color-gray-800,#1f2937))] rounded-lg shadow-[var(--mcp-ui-shadow,var(--shadow-sm))] border border-[color:var(--mcp-ui-border,var(--color-gray-200,#e5e7eb))] dark:border-[color:var(--mcp-ui-border,var(--color-gray-700,#374151))] overflow-hidden">
2101
2101
  <Show when={props.resource.metadata?.title || props.resource.uri}>
2102
- <div class="px-4 py-2 border-b border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-900">
2103
- <h3 class="text-sm font-semibold text-gray-900 dark:text-white capitalize">
2102
+ <div class="px-4 py-2 border-b border-[color:var(--mcp-ui-border,var(--color-gray-200,#e5e7eb))] dark:border-[color:var(--mcp-ui-border,var(--color-gray-700,#374151))] bg-[color:var(--mcp-ui-surface-muted,var(--color-gray-50,#f9fafb))] dark:bg-[color:var(--mcp-ui-surface,var(--color-gray-900,#111827))]">
2103
+ <h3 class="text-sm font-semibold text-[color:var(--mcp-ui-fg,var(--color-gray-900,#111827))] dark:text-[color:var(--mcp-ui-fg,var(--color-white,#fff))] capitalize">
2104
2104
  {resourceTitle()}
2105
2105
  </h3>
2106
2106
  </div>
@@ -2231,7 +2231,7 @@ export const UIResourceRenderer: Component<UIResourceRendererProps> = (props) =>
2231
2231
  return (
2232
2232
  <RenderProvider renderComponent={renderComponent}>
2233
2233
  <div
2234
- class={`w-full ${props.class || ''}`}
2234
+ class={`mcp-ui-root [background-color:var(--mcp-ui-bg)] w-full ${props.class || ''}`}
2235
2235
  {...(isLayoutContent
2236
2236
  ? { 'data-mcp-ui-layout-id': outerKey() }
2237
2237
  : { 'data-mcp-ui-component-id': outerKey() })}