Skip to content

🎨 feat: ClickHouse MCP Tool Call UI with Click UI#12663

Draft
dustinhealy wants to merge 33 commits intodevfrom
feat/click-ui-tool-calls
Draft

🎨 feat: ClickHouse MCP Tool Call UI with Click UI#12663
dustinhealy wants to merge 33 commits intodevfrom
feat/click-ui-tool-calls

Conversation

@dustinhealy
Copy link
Copy Markdown
Collaborator

Summary

Adds @clickhouse/click-ui to the client and renders ClickHouse MCP tool calls with rich, structured UI instead of raw JSON. When a tool call's domain matches clickhouse, it delegates to a custom ClickHouseToolCall component.

  • SQL queries: syntax-highlighted CodeBlock with line numbers, wrap toggle
  • Query results: virtualized Grid (Click UI) with pagination, resizable columns, column filter (CheckboxMultiSelect)
  • Service list: collapsible rows with endpoint pills, ipAccessList pills, expand/collapse all
  • Service details: static key-value layout with endpoint and ipAccessList rendering
  • Table list: collapsible rows with column type display, SQL CodeBlocks for CREATE TABLE
  • Cost data: By Entity / By Date toggle, Daily / Weekly grouping, metric breakdowns, grand total
  • Metrics bar: elapsed time, rows read, bytes read in footer
  • Tabs: Query, Result, Details (right-aligned) with auto-tab switching when output arrives
  • Theming: ClickUIProvider synced with LibreChat dark/light mode, Click UI design tokens for backgrounds
  • Error display: parsed error messages with status codes

Also bumps react/react-dom to ^18.3.1 and adds styled-components (Click UI peer dep).

Change Type

  • New feature (non-breaking change which adds functionality)

Testing

  1. Add a ClickHouse MCP server (e.g. clickhouse-cloud or clickhouse-dev)
  2. Run various tools and verify rendering:
    • run_select_query — SQL in Query tab, virtualized table in Result
    • get_organizations / get_organization_details — flat table / single-row table
    • get_services_list — collapsible service cards with endpoints
    • get_service_details — static key-value with endpoints and ipAccessList pills
    • list_tables — collapsible rows with column definitions and SQL CodeBlocks
    • get_organization_cost — cost view with By Entity/Date toggle, Daily/Weekly
    • list_service_backups / get_service_backup_details — flat table / single row
  3. Toggle dark/light mode — all Click UI components follow theme
  4. Non-ClickHouse tool calls render unchanged (no regression)

Checklist

  • My code adheres to this project's style guidelines
  • I have performed a self-review of my own code
  • My changes do not introduce new warnings
  • Local unit tests pass with my changes

- Add @clickhouse/click-ui and styled-components dependencies
- Bump react/react-dom to ^18.3.1 to satisfy click-ui peer deps
- Add lazy-loaded ClickHouseToolCall component with SQL syntax
  highlighting via CodeBlock, tabbed Input/Query/Result views,
  and status Badge — wrapped in its own ClickUIProvider
- Delegate ClickHouse MCP tool calls from ToolCallInfo when domain
  matches /clickhouse/i
- Add styled-components Vite chunk for code splitting
…d output

- Tabbed layout: Query (SQL), Result (table/key-value), Details (raw JSON)
- Details tab right-aligned, separated from Query/Result
- Metrics bar (elapsed, rows read, bytes) in bottom right with status badge
- Sticky table headers for scrollable query results
- Key-value display for service details, backup config, etc.
- Max height with scroll on Details input/output CodeBlocks
- SQL CodeBlock with wrapLines and showWrapButton for long queries
- New ClickHouseCostView for get_organization_cost with By Entity /
  By Date toggle, Daily / Weekly grouping, metric breakdowns,
  grand total display, and entity type pills
- Collapsible service rows for get_services_list with expand/collapse
  all, endpoint pills, ipAccessList pills, and full-width separators
- Pass functionName through ToolCall → ToolCallInfo → ClickHouseToolCall
  for per-tool rendering decisions
- Use ClickHouse design tokens for container backgrounds
Copilot AI review requested due to automatic review settings April 14, 2026 17:29
@github-actions
Copy link
Copy Markdown
Contributor

🚨 Unused NPM Packages Detected

The following unused dependencies were found:

📂 Client client/package.json

  • styled-components

⚠️ Please remove these unused dependencies to keep your project clean.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a ClickHouse-specific rich UI renderer for MCP tool calls in the chat UI by delegating ClickHouse-domain tool calls to a new ClickHouseToolCall component backed by @clickhouse/click-ui, along with dependency upgrades required to support it.

Changes:

  • Add @clickhouse/click-ui (+ styled-components) and bump react/react-dom to ^18.3.1.
  • Delegate ClickHouse-domain tool calls to a lazily loaded ClickHouseToolCall renderer (tabs, SQL, results grid, details, metrics, cost views).
  • Add a Vite manual chunk rule intended to isolate Click UI-related code.

Reviewed changes

Copilot reviewed 7 out of 8 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
packages/client/package.json Bumps React/ReactDOM versions used by the client package workspace.
client/package.json Adds Click UI + styled-components and bumps React/ReactDOM to support new UI.
package-lock.json Locks the new dependency graph (Click UI + transitive deps) and React bumps.
client/vite.config.ts Adds a manualChunks rule to group styled-components into a click-ui chunk.
client/src/components/Chat/Messages/Content/ToolCallInfo.tsx Adds ClickHouse-domain delegation via React.lazy + Suspense.
client/src/components/Chat/Messages/Content/ToolCall.tsx Passes domain and function_name through to ToolCallInfo.
client/src/components/Chat/Messages/Content/ClickHouseToolCall.tsx New rich renderer for ClickHouse tool calls (query/result/details/cost/metrics).
client/src/components/Chat/Messages/Content/ClickHouseCostView.tsx New cost breakdown UI (by entity/date with day/week grouping).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread client/package.json
"homepage": "https://librechat.ai",
"dependencies": {
"@ariakit/react": "^0.4.15",
"@clickhouse/click-ui": "0.2.0-rc.4",
Comment on lines +250 to +254
{metrics.totalRows !== undefined && !metrics.rowsRead && (
<Text color="muted" size="xs">
{metrics.totalRows.toLocaleString()} {metrics.totalRows === 1 ? 'row' : 'rows'}
</Text>
)}
Comment on lines +36 to +41
function getDateRange(costs: CostEntry[]): { days: number; start: Date; end: Date } {
const dates = costs.map((c) => new Date(c.date)).sort((a, b) => a.getTime() - b.getTime());
const start = dates[0];
const end = dates[dates.length - 1];
const days = Math.round((end.getTime() - start.getTime()) / (1000 * 60 * 60 * 24)) + 1;
return { days, start, end };
Comment on lines +46 to +52
function getTimeLevels(days: number): TimeLevel[] {
if (days <= 7) {
return ['day'];
}
return ['week', 'day'];
}

Comment on lines +137 to +143
if (domain && /clickhouse/i.test(domain)) {
return (
<Suspense fallback={<div className="p-3 text-xs text-text-secondary">Loading...</div>}>
<ClickHouseToolCall input={input} output={output} functionName={functionName} />
</Suspense>
);
}
functionName?: string;
}

interface ParsedInput {
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

create a clickhouse folder, types in one module, helpers in another, custom hooks in another (if any), leaving the main modules with as little boilerplate as possible. add tests for your helpers.

Comment thread client/package.json Outdated
"remark-math": "^6.0.0",
"remark-supersub": "^1.0.0",
"sse.js": "^2.5.0",
"styled-components": "^6.1.11",
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if absolutely required when using click-ui, make an exception in .github/workflows/unused-packages.yml

- Move ClickHouse components into ClickHouse/ folder per review
- Extract types into types.ts, helpers into helpers.ts
- Add 42 unit tests for all helper functions
- Fix rowsRead falsy check (use === undefined)
- Guard getDateRange against empty costs array
- Remove unused getTimeLevels function
- Add styled-components exception to unused-packages workflow
- Reuse existing keys: com_ui_result, com_ui_details, com_ui_input, com_endpoint_output
- Add new keys for ClickHouse-specific strings: com_ch_tab_query,
  com_ch_label_elapsed, com_ch_label_read, com_ch_expand_all, etc.
- Fix useMemo deps warning in CostView DateView
- Remove autoFocus prop (jsx-a11y/no-autofocus)
- Run prettier on all files
@github-actions
Copy link
Copy Markdown
Contributor

🚨 Unused i18next Keys Detected

The following translation keys are defined in translation.json but are not used in the codebase:

  • com_ch_label_rows_other

⚠️ Please remove these unused keys to keep the translation files clean.

click-ui's transitive deps (styled-components etc.) in the vendor chunk
disrupt Rollup's CJS interop wrapping for React, causing forwardRef and
useSyncExternalStore to be undefined at runtime. Giving click-ui its own
manual chunk keeps vendor identical to the dev branch.

Also replace CodeBlock with a lightweight CodeDisplay component since
CodeBlock pulls in react-syntax-highlighter (CJS lowlight@1.x) which
conflicts with rehype-highlight's ESM lowlight@2.x.
Use lowlight (already loaded by rehype-highlight) for SQL/JSON
highlighting, with Click UI's exact color palette scoped via .ch-code
class. Supports dark/light mode.
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you need this in the repo?

Comment thread client/src/locales/en/translation.json Outdated
"com_ui_zoom_level": "Zoom level",
"com_ui_zoom_out": "Zoom out",
"com_user_message": "You"
"com_user_message": "You",
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make sure these are in alphabetical order along with the other i18n keys

Comment thread client/vite.config.ts Outdated
],
globIgnores: ['images/**/*', '**/*.map', 'index.html'],
maximumFileSizeToCacheInBytes: 4 * 1024 * 1024,
maximumFileSizeToCacheInBytes: 5 * 1024 * 1024,
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the current byte size of the build? Can you avoid making this change?

@danny-avila
Copy link
Copy Markdown
Owner

@codex review

@danny-avila
Copy link
Copy Markdown
Owner

/gitnexus index

);
}

function groupEntriesByWeek(
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove helpers from the module, do not group into generic single module helpers.ts

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 82a4273553

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

const groups = new Map<string, CostEntry[]>();

for (const cost of costs) {
const key = getGroupKey(new Date(cost.date), currentLevel);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Group cost dates using UTC-safe calendar parsing

This groups entries with new Date(cost.date) and then derives day/week buckets from local-date methods, which misclassifies date-only strings (YYYY-MM-DD) in non-UTC timezones. For example, in US timezones 2026-01-01 is interpreted as the prior local day, so "By Date" and weekly rollups can be shown under the wrong date/week and produce incorrect financial breakdowns for users.

Useful? React with 👍 / 👎.

Comment on lines +176 to +179
const rawColumns = Object.keys(rows[0]).filter((col) => {
const sample = rows[0][col];
return sample === null || typeof sample !== 'object';
});
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Build table columns from all rows, not just first row

The table schema is inferred only from rows[0], so any scalar field that is absent in the first row but present in later rows is never rendered as a column. This silently hides valid result data for sparse/heterogeneous responses, which makes the tool output incomplete and hard to trust.

Useful? React with 👍 / 👎.

@github-actions
Copy link
Copy Markdown
Contributor

GitNexus: ✅ indexed

PR #12663 was indexed with embeddings.
Index run

⏳ Waiting for deploy to serve the fresh index…

Repository owner deleted a comment from github-actions bot Apr 15, 2026
Repository owner deleted a comment from github-actions bot Apr 15, 2026
Sort com_ch_* i18n keys alphabetically in translation.json.
Revert PWA precache limit to 4MB (vendor is 3.4MB with chunk isolation).
Move formatCHC into CostView to keep cost helpers colocated.
Fix UTC date parsing in CostView with parseLocalDate helper.
Build FlatTable columns from all rows, not just first row.
Fix grid bottom padding gap.
Fix UTC timezone bug in CostView getGroupKey (toISOString → localISODate).
Fix parseOutput false positive on {error: false} responses.
Fix formatCHC handling of negative values.
Remove broad regex fallback in parseOutput catch block.
Eliminate double JSON.parse in parseOutput.
Memoize FlatTable column discovery and sync selectedColumns on row changes.
Stabilize Grid Cell with useCallback.
Add try/catch to clipboard copy with timeout cleanup on unmount.
Inject CodeDisplay styles once via singleton instead of per-instance.
Localize Badge text and Suspense fallback.
Type CostData.costs as CostEntry[] directly.
Add parseLocalDate input validation.
Extract grid height magic numbers to named constants.
Fix i18n key ordering (com_ch before com_citation).
Fix HMR style leak by reusing existing DOM element.
Fix parseLocalDate to return null for invalid dates, filter in callers.
Remove groupEntriesByWeek, use buildTimeHierarchy instead.
Memoize getDateRange in DateView and EntityView.
Fix allOpen check for empty rows.
Remove redundant dark dep from style injection useEffect.
Repository owner deleted a comment from github-actions bot Apr 15, 2026
Repository owner deleted a comment from github-actions bot Apr 15, 2026
Repository owner deleted a comment from github-actions bot Apr 15, 2026
Repository owner deleted a comment from github-actions bot Apr 15, 2026
Repository owner deleted a comment from github-actions bot Apr 15, 2026
Repository owner deleted a comment from github-actions bot Apr 15, 2026
Repository owner deleted a comment from github-actions bot Apr 15, 2026
Use Inconsolata 14px/1.7 (weight 500), theme background/text colors,
1rem padding, and 0.25rem border-radius to match Click UI's codeblock
design tokens exactly.
Show idle/waking services with clock badge and console link.
Add serviceId/database context pills for list_tables and list_databases.
Route get_organizations to collapsible rows, get_organization_details to static rows.
Detect "Failed to" prefixed output as errors with friendly message.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants