Add tauri-mcp-client tool: Tauri app + FastMCP sidecar + HTML UI - #1
Add tauri-mcp-client tool: Tauri app + FastMCP sidecar + HTML UI#1AM1010101 wants to merge 11 commits into
Conversation
A desktop scaffold that drives a FastMCP process to call MCP servers. The Python sidecar plays both MCP roles: a local FastMCP "hub" server with its own tools, plus a config-driven fastmcp.Client that proxies to external MCP servers. A FastAPI localhost bridge exposes it to a simple HTML frontend, and the Tauri (v2) Rust shell spawns the sidecar on start. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011c8J7RdTEPqqi1Q6kdKKLu
- Add sidecar.spec: freeze the FastMCP/FastAPI bridge into one mcp-bridge binary (collects fastmcp/uvicorn trees, bundles example config; excludes mcp.cli which sys.exits at import without its optional extras). - Add scripts/build-sidecar.sh: build in a throwaway venv and stage the binary as src-tauri/binaries/mcp-bridge-<target-triple> for Tauri. - tauri.conf.json: declare bundle.externalBin so Tauri copies the sidecar next to the app executable. - main.rs: prefer the bundled mcp-bridge binary at runtime, fall back to python server.py in dev. - server.py: resolve mcp_config.json across dev and frozen layouts (MCP_CONFIG env, cwd, next-to-exe, bundled example). - mcp_config.example.json: wire to the MCP "everything" demo server. - .gitignore + README updated for the build artifacts and flow. Verified: frozen binary runs under `env -i` (no Python) and serves the hub, config listing, and tool calls. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011c8J7RdTEPqqi1Q6kdKKLu
Introduces src-scripts/, a Node/TS runtime that is both the MCP client (official @modelcontextprotocol/sdk) and the "Script" layer from the dashboarding design. Scripts authored in TypeScript compose MCP tool calls and return chart-ready JSON; the frontend calls named scripts, the sanctioned egress path from the (future) sandbox. - src/mcp.ts: config-driven MCP client manager (stdio + HTTP/SSE), one cached client per server, JSON-friendly results. - src/scripts.ts: script context + loader; scripts re-imported per run so Builder-agent edits take effect without a restart. - src/bridge.ts: localhost HTTP bridge (/health, /servers, /servers/:name/tools, /scripts, /scripts/:name/run). - scripts/demo_timeseries.ts (pure, always runnable) and scripts/everything_sum.ts (calls the everything server's get-sum). - dev.sh, tsconfig, README; single-local-user auth model. Verified: typecheck passes; pure script and MCP-backed script both run end to end (get-sum returned "The sum of 19 and 23 is 42."). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011c8J7RdTEPqqi1Q6kdKKLu
Adds src-web/, a Vite/React app that renders dashboards by running scripts through the Script-layer bridge -- the frontend never calls MCP directly. - Declarative dashboard JSON (panels: script + params + chart spec); <Panel> runs the script via callScript() and renders the chart. - Hand-rolled SVG line/bar charts honoring the dataviz mark specs: single-series blue from the validated reference palette, 2px lines with soft area, rounded bar data-ends, recessive grid, hover crosshair/tooltip, light + dark themes via CSS tokens. - bridge.ts client; theme.css tokens; example sales.json dashboard. - Tauri config points at src-web (dev via Vite, build via vite build); main.rs gains MCP_SIDECAR_DISABLED so the dashboard dev flow can own the bridge without a port clash. - dev-dashboard.sh runs bridge + Vite (+ optional Tauri); READMEs + roadmap. Verified live: bridge + Vite running, React panels rendered demo_timeseries end to end as line + bar in both light and dark (Playwright screenshots). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011c8J7RdTEPqqi1Q6kdKKLu
Three skills teach Claude to author the dashboard artifacts: - inspect-mcps: discover configured servers + tools (config + bridge). - write-script: author a TS script returning chart-ready rows; verify it against the running bridge. - write-dashboard: author dashboard JSON (panels: script + chart spec). Enable the loop and prove it: - src-scripts: add ctx.listTools(server) so scripts can enumerate a server's tools. - scripts/mcp_tool_counts.ts (authored per write-script): tool count per configured MCP server from live data. - dashboards/mcp_overview.json (authored per write-dashboard) renders it. - App.tsx: dashboard picker; theme.css: picker styling. Verified live: mcp_tool_counts returned real MCP data (everything: 13 tools); the MCP Overview dashboard rendered it as a bar chart alongside the demo line, light + dark (screenshots). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011c8J7RdTEPqqi1Q6kdKKLu
Confine the agent-generated frontend so its only egress is the bridge, and the bridge's only egress is configured MCP servers. - Webview CSP (tauri.conf.json): connect-src limited to the loopback bridge; script-src 'self' (Vite build emits only external self-hosted modules); object-src 'none'; frame-ancestors 'none'. - Bridge guards (bridge.ts): DNS-rebinding guard (reject non-loopback Host -> 403); Origin guard (only loopback/tauri origins, reflected not '*'); keeps loopback bind and fixed script/server surface. - SECURITY.md documents the three enforcement layers and trust boundaries. Verified: spoofed Host -> 403, evil Origin -> 403, loopback + localhost origin allowed; scripts still run through the hardened bridge; built HTML is CSP-safe (no inline scripts). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011c8J7RdTEPqqi1Q6kdKKLu
Freezes the TypeScript Script bridge into one `mcp-bridge` executable that embeds the Bun runtime and runs with nothing else installed. - scripts/build-bridge.sh: `bun build --compile` the bridge; precompile authored scripts to .mjs; stage binary + scripts/ + example config into src-tauri/binaries/. Cross-compiles via BUN_TARGET. - src-scripts: resolve scripts dir and mcp_config across dev and packaged layouts ($MCP_SCRIPTS_DIR / next-to-executable), since a packaged binary can't use the tsx loader — scripts load as external .mjs beside the binary. - tauri.conf.json: bundle scripts/ + config as resources; main.rs points the sidecar at the resource dir via MCP_SCRIPTS_DIR. - Drop the Node-SEA/postject approach (this Node build's ELF notes break postject); Bun compiles cleanly and cross-compiles. esbuild kept for compiling scripts; postject removed. Verified: the compiled binary runs under `env -i` (no runtime installed), lists its scripts, and completes real MCP calls that spawn a child stdio server (everything get-sum -> 42; tool counts -> 13). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011c8J7RdTEPqqi1Q6kdKKLu
Dashboards are now served by the bridge and loaded by the frontend at runtime, so a new dashboard is just a JSON file -- no App.tsx registry edit, no Vite rebuild. - src-scripts/src/dashboards.ts + bridge routes GET /dashboards and GET /dashboards/:name; dashboards resolved across dev/packaged layouts ($MCP_DASHBOARDS_DIR / next-to-exe / ../dashboards). - Move dashboard JSON from src-web/src/dashboards/ to src-scripts/dashboards/ (authored content sits with scripts + config). - App.tsx: fetch the dashboard list + selected definition from the bridge; drop the compile-time import map. Picker is populated from the bridge. - Packaging + Tauri: build-bridge.sh stages dashboards/; tauri.conf bundles them as resources; main.rs sets MCP_DASHBOARDS_DIR. - write-dashboard skill + READMEs updated (no wire-up, no rebuild). Verified live: picker populated from the bridge; switching dashboards works; dropping a new dashboards/ops.json while the app ran made it appear in the picker and render on reload with no rebuild (screenshots). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011c8J7RdTEPqqi1Q6kdKKLu
📝 WalkthroughWalkthroughAdds a Tauri MCP dashboard application with Python and TypeScript bridge implementations, configurable MCP servers, dashboard scripts and JSON definitions, a React/Vite frontend with interactive charts, desktop sidecar management, build scripts, security documentation, and authoring workflows. ChangesMCP Dashboard Client
Estimated code review effort: 5 (Critical) | ~120 minutes Sequence Diagram(s)sequenceDiagram
participant Dashboard as React Dashboard
participant Bridge as TypeScript Script Bridge
participant Script as Dashboard Script
participant MCP as Configured MCP Server
Dashboard->>Bridge: GET /dashboards
Bridge-->>Dashboard: Dashboard summaries
Dashboard->>Bridge: POST /scripts/{name}/run
Bridge->>Script: run(ctx, params)
Script->>MCP: listTools or callTool
MCP-->>Script: Tool result
Script-->>Bridge: Chart-ready rows
Bridge-->>Dashboard: Script result
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 16
Note
Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.
🟡 Minor comments (9)
tools/tauri-mcp-client/src-scripts/scripts/demo_timeseries.ts-13-22 (1)
13-22: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winValidate numeric script parameters before using them.
Number()accepts invalid input asNaNor infinity, producing invalid chart data or forwarding unusable arguments to MCP tools.
tools/tauri-mcp-client/src-scripts/scripts/demo_timeseries.ts#L13-L22: fall back or reject unlessseedis finite before calculating revenue.tools/tauri-mcp-client/src-scripts/scripts/everything_sum.ts#L13-L17: validateaandbas finite numbers before callingget-sum.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tools/tauri-mcp-client/src-scripts/scripts/demo_timeseries.ts` around lines 13 - 22, Validate the numeric parameters before use: in tools/tauri-mcp-client/src-scripts/scripts/demo_timeseries.ts lines 13-22, ensure the seed used by run is finite, falling back or rejecting invalid values before revenue calculation; in tools/tauri-mcp-client/src-scripts/scripts/everything_sum.ts lines 13-17, ensure both a and b are finite before invoking get-sum.tools/tauri-mcp-client/src/styles.css-10-10 (1)
10-10: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick winResolve the reported Stylelint errors.
Add the required declaration spacing and replace deprecated
word-break: break-wordwithoverflow-wrap: anywhere(and normal word breaking).Also applies to: 118-118
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tools/tauri-mcp-client/src/styles.css` at line 10, Update the CSS declarations in styles.css to satisfy Stylelint: add the required spacing around declarations, and replace deprecated word-break: break-word occurrences with overflow-wrap: anywhere plus normal word breaking. Apply the same changes to the additional reported location.Source: Linters/SAST tools
tools/tauri-mcp-client/src-web/src/charts/BarChart.tsx-35-42 (1)
35-42: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winHandle empty datasets before computing scales.
data: []makesyMax-Infinityandbandinfinite, yielding invalid SVG output. Render a no-data state before calculating ticks and bar geometry.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tools/tauri-mcp-client/src-web/src/charts/BarChart.tsx` around lines 35 - 42, Handle an empty data array at the start of the BarChart rendering logic before yMax, niceTicks, yScale, band, or bar geometry are computed. Return the component’s no-data state for data.length === 0, while preserving the existing scale and bar rendering path for non-empty datasets.tools/tauri-mcp-client/src/app.js-47-74 (1)
47-74: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winDiscard stale tool-list responses.
Selecting server A and then B before A’s request resolves can render A’s tools while
state.serverremains B, causing calls to target the wrong server. Abort the prior request or verify a selection token afterawait.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tools/tauri-mcp-client/src/app.js` around lines 47 - 74, Update selectServer so each tool-list request is associated with the current server selection and stale responses are discarded. After awaiting api, verify the selection still matches the request (or use an abort mechanism) before mutating the tools list, including success and error rendering; preserve the existing loading and current-server behavior.tools/tauri-mcp-client/SECURITY.md-3-7 (1)
3-7: 🔒 Security & Privacy | 🟡 Minor | ⚡ Quick winCorrect the script-egress claim.
This says scripts can access the outside world only through configured MCP servers, but Lines 55-58 correctly state that scripts run with normal Node process privileges. State that the bridge confines the frontend only; trusted scripts can still use filesystem, process, and network APIs directly.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tools/tauri-mcp-client/SECURITY.md` around lines 3 - 7, Update the security statement in SECURITY.md to limit the bridge-enforcement claim to the dashboard frontend only. Clarify that trusted scripts run with normal Node process privileges and may directly access filesystem, process, and network APIs, while retaining the configured MCP-server restriction only for frontend access through the Script bridge.tools/tauri-mcp-client/SECURITY.md-13-18 (1)
13-18: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick winAdd a language hint to the CSP block.
Use
```textso the documentation passes the reported Markdown fenced-code-language check.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tools/tauri-mcp-client/SECURITY.md` around lines 13 - 18, Update the CSP fenced code block in SECURITY.md to specify the text language by changing its opening fence to ```text, while leaving the CSP directives unchanged.Source: Linters/SAST tools
tools/tauri-mcp-client/src-web/README.md-6-9 (1)
6-9: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick winAdd a language to the fenced diagram block.
Use
text(or another suitable language) after the opening fence so markdownlint passes.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tools/tauri-mcp-client/src-web/README.md` around lines 6 - 9, Update the fenced diagram block in the README by adding a suitable language identifier, preferably text, to its opening fence while preserving the diagram content unchanged.Source: Linters/SAST tools
tools/tauri-mcp-client/skills/write-dashboard/SKILL.md-3-3 (1)
3-3: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick winCorrect the dashboard output path.
The description says to write into
src-web/src/dashboards/, but the bridge discoverssrc-scripts/dashboards/. Following this instruction creates dashboards that are not listed at runtime.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tools/tauri-mcp-client/skills/write-dashboard/SKILL.md` at line 3, Update the SKILL.md description to direct dashboard JSON files into src-scripts/dashboards/ instead of src-web/src/dashboards/, while preserving the existing guidance to verify that the dashboard renders.tools/tauri-mcp-client/src-web/src/charts/LineChart.tsx-41-45 (1)
41-45: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winFix the hover coordinate calculation.
currentTargetis the overlay rect whose left edge is already atM.left, so subtractingM.leftagain shifts the selected point left. Calculate the index frompx / iw.Proposed fix
- const i = Math.round(((px - M.left) / (iw || 1)) * (data.length - 1)); + const i = Math.round((px / (iw || 1)) * (data.length - 1));🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tools/tauri-mcp-client/src-web/src/charts/LineChart.tsx` around lines 41 - 45, Update the hover index calculation in onMove to derive the normalized position from px / (iw || 1), removing the extra M.left subtraction while preserving the existing rounding and clamping behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@tools/tauri-mcp-client/README.md`:
- Around line 178-179: Update the Python bridge CORS configuration in server.py
to replace the wildcard origin, methods, and headers with the explicit
loopback/Tauri origin policy used by the TypeScript bridge. Preserve only the
required local origins and ensure credentialed requests remain restricted to
that allowlist.
- Around line 151-166: Update the documented Tauri packaging flow to avoid
staging the legacy Python bridge as mcp-bridge, since the packaged dashboard
requires /scripts and /dashboards. Use distinct sidecar names, or explicitly
stage the compiled TypeScript dashboard bridge, and align the references in the
build commands, tauri.conf.json, and main.rs runtime selection.
In `@tools/tauri-mcp-client/scripts/build-bridge.sh`:
- Around line 74-78: Use distinct staged binary names for the bridge
implementations so build-bridge.sh and build-sidecar.sh cannot overwrite each
other; update tools/tauri-mcp-client/scripts/build-bridge.sh and
tools/tauri-mcp-client/scripts/build-sidecar.sh accordingly. Align
tools/tauri-mcp-client/src-tauri/src/main.rs, including its mcp-bridge launch
configuration, with the selected staged name, and ensure only the intended
implementation is packaged and launched.
- Around line 30-50: Update the target-resolution logic before the `case
"$TRIPLE"` mapping so explicit `TRIPLE` and `BUN_TARGET` values are honored and
mutually consistent. Derive the Rust triple from `BUN_TARGET` when only the
bundle target is provided, preserve native detection when neither is set, and
fail clearly when the supplied values mismatch; ensure the staged bridge
filename uses the resolved intended triple.
In `@tools/tauri-mcp-client/src-python/server.py`:
- Around line 161-167: Update the CORSMiddleware configuration in the FastAPI
app to replace allow_origins=["*"] with an explicit allowlist of trusted
Tauri/Vite application origins. Preserve the existing methods and headers
settings, and add a per-launch authentication token for MCP endpoints if
required to exclude non-browser local clients.
In `@tools/tauri-mcp-client/src-scripts/mcp_config.example.json`:
- Around line 3-5: Pin the `@modelcontextprotocol/server-everything` package to
the reviewed version in the everything command’s args within
mcp_config.example.json, and apply the same pinned version to the mirrored
README examples. Keep the npx -y invocation and existing configuration structure
unchanged.
In `@tools/tauri-mcp-client/src-scripts/src/dashboards.ts`:
- Around line 54-57: Update getDashboard to validate the parsed dashboard
against the complete panel/chart contract before returning it, including
ensuring panels is an array with valid panel entries and chart data expected by
App.tsx. Throw an error for any invalid definition so the caller’s existing
error state is used, while preserving the current missing-file behavior.
In `@tools/tauri-mcp-client/src-scripts/src/mcp.ts`:
- Around line 68-97: Update the connection management around connect so
concurrent requests for the same server share one in-flight Promise<Client>
instead of creating duplicate clients. Add an in-flight map keyed by name, reuse
its promise after the existing clients check, and clear the entry in finally
while preserving the successful clients cache and existing transport setup.
- Around line 62-97: Update tools/tauri-mcp-client/src-scripts/src/mcp.ts lines
62-97 around serverNames() and connect() to fingerprint each loaded server
configuration, compare fingerprints before returning cached clients, close and
replace clients when configurations change, and evict cached clients for removed
servers. Update tools/tauri-mcp-client/README.md lines 25-28 to narrow the
runtime-reload claim until existing connections are invalidated on configuration
changes.
In `@tools/tauri-mcp-client/src-scripts/src/scripts.ts`:
- Around line 62-68: Dynamic import in importScript does not sandbox authored
scripts; execute them in a separately permission-restricted process or
container, or explicitly classify them as fully trusted code. Update
tools/tauri-mcp-client/README.md lines 17-19 to remove the sandbox-hardening
claim or document the trusted-script boundary.
In `@tools/tauri-mcp-client/src-tauri/Cargo.toml`:
- Line 6: Update the rust-version setting in Cargo.toml from 1.70 to 1.77.2,
then align the repository’s CI configuration and toolchain documentation with
Rust 1.77.2.
In `@tools/tauri-mcp-client/src-web/src/App.tsx`:
- Around line 31-43: Update the dashboard-loading useEffect around
listDashboards so it only runs when status === "ok", and clear the existing
error state after a successful dashboard load. Preserve the current list and
selection updates, ensuring a recovered bridge no longer leaves the stale error
panel visible.
In `@tools/tauri-mcp-client/src-web/src/charts/LineChart.tsx`:
- Around line 23-39: Handle an empty data array at the start of the LineChart
rendering logic before calculating ys, yMin, yMax, ticks, scales, or paths.
Render the chart’s explicit “No data” state for data.length === 0, while
preserving the existing geometry calculations for non-empty data.
In `@tools/tauri-mcp-client/src/app.js`:
- Around line 12-18: Update api() to create an AbortController and enforce a
configurable finite request deadline, passing its signal to fetch and ensuring
the timeout is cleared after completion or failure. Preserve the existing
response validation and error propagation while allowing callers to configure
the deadline through options or the established configuration mechanism.
- Around line 38-42: Update the list-item rendering around selectServer to use
native button controls inside each li instead of making the li itself clickable.
Move the server/tool selection handler onto the button, ensure the control is
keyboard-operable, and preserve the selected state with the appropriate semantic
state attribute.
- Around line 38-41: Replace the innerHTML assignments in the list-item
rendering and the related locations around lines 66-68 and 72-73 with DOM
construction using createElement, textContent, and replaceChildren. Ensure
server names, tool metadata, descriptions, and error messages are rendered
strictly as text while preserving the existing structure and displayed values.
---
Minor comments:
In `@tools/tauri-mcp-client/SECURITY.md`:
- Around line 3-7: Update the security statement in SECURITY.md to limit the
bridge-enforcement claim to the dashboard frontend only. Clarify that trusted
scripts run with normal Node process privileges and may directly access
filesystem, process, and network APIs, while retaining the configured MCP-server
restriction only for frontend access through the Script bridge.
- Around line 13-18: Update the CSP fenced code block in SECURITY.md to specify
the text language by changing its opening fence to ```text, while leaving the
CSP directives unchanged.
In `@tools/tauri-mcp-client/skills/write-dashboard/SKILL.md`:
- Line 3: Update the SKILL.md description to direct dashboard JSON files into
src-scripts/dashboards/ instead of src-web/src/dashboards/, while preserving the
existing guidance to verify that the dashboard renders.
In `@tools/tauri-mcp-client/src-scripts/scripts/demo_timeseries.ts`:
- Around line 13-22: Validate the numeric parameters before use: in
tools/tauri-mcp-client/src-scripts/scripts/demo_timeseries.ts lines 13-22,
ensure the seed used by run is finite, falling back or rejecting invalid values
before revenue calculation; in
tools/tauri-mcp-client/src-scripts/scripts/everything_sum.ts lines 13-17, ensure
both a and b are finite before invoking get-sum.
In `@tools/tauri-mcp-client/src-web/README.md`:
- Around line 6-9: Update the fenced diagram block in the README by adding a
suitable language identifier, preferably text, to its opening fence while
preserving the diagram content unchanged.
In `@tools/tauri-mcp-client/src-web/src/charts/BarChart.tsx`:
- Around line 35-42: Handle an empty data array at the start of the BarChart
rendering logic before yMax, niceTicks, yScale, band, or bar geometry are
computed. Return the component’s no-data state for data.length === 0, while
preserving the existing scale and bar rendering path for non-empty datasets.
In `@tools/tauri-mcp-client/src-web/src/charts/LineChart.tsx`:
- Around line 41-45: Update the hover index calculation in onMove to derive the
normalized position from px / (iw || 1), removing the extra M.left subtraction
while preserving the existing rounding and clamping behavior.
In `@tools/tauri-mcp-client/src/app.js`:
- Around line 47-74: Update selectServer so each tool-list request is associated
with the current server selection and stale responses are discarded. After
awaiting api, verify the selection still matches the request (or use an abort
mechanism) before mutating the tools list, including success and error
rendering; preserve the existing loading and current-server behavior.
In `@tools/tauri-mcp-client/src/styles.css`:
- Line 10: Update the CSS declarations in styles.css to satisfy Stylelint: add
the required spacing around declarations, and replace deprecated word-break:
break-word occurrences with overflow-wrap: anywhere plus normal word breaking.
Apply the same changes to the additional reported location.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: d012acbb-d13f-4db6-93e1-27a65f7bc4bd
⛔ Files ignored due to path filters (2)
tools/tauri-mcp-client/src-scripts/package-lock.jsonis excluded by!**/package-lock.jsontools/tauri-mcp-client/src-web/package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (50)
tools/tauri-mcp-client/README.mdtools/tauri-mcp-client/SECURITY.mdtools/tauri-mcp-client/dev-dashboard.shtools/tauri-mcp-client/dev.shtools/tauri-mcp-client/scripts/build-bridge.shtools/tauri-mcp-client/scripts/build-sidecar.shtools/tauri-mcp-client/skills/inspect-mcps/SKILL.mdtools/tauri-mcp-client/skills/write-dashboard/SKILL.mdtools/tauri-mcp-client/skills/write-script/SKILL.mdtools/tauri-mcp-client/src-python/mcp_config.example.jsontools/tauri-mcp-client/src-python/requirements.txttools/tauri-mcp-client/src-python/server.pytools/tauri-mcp-client/src-python/sidecar.spectools/tauri-mcp-client/src-scripts/README.mdtools/tauri-mcp-client/src-scripts/dashboards/mcp_overview.jsontools/tauri-mcp-client/src-scripts/dashboards/sales.jsontools/tauri-mcp-client/src-scripts/dev.shtools/tauri-mcp-client/src-scripts/mcp_config.example.jsontools/tauri-mcp-client/src-scripts/package.jsontools/tauri-mcp-client/src-scripts/scripts/demo_timeseries.tstools/tauri-mcp-client/src-scripts/scripts/everything_sum.tstools/tauri-mcp-client/src-scripts/scripts/mcp_tool_counts.tstools/tauri-mcp-client/src-scripts/src/bridge.tstools/tauri-mcp-client/src-scripts/src/dashboards.tstools/tauri-mcp-client/src-scripts/src/mcp.tstools/tauri-mcp-client/src-scripts/src/scripts.tstools/tauri-mcp-client/src-scripts/tsconfig.jsontools/tauri-mcp-client/src-tauri/Cargo.tomltools/tauri-mcp-client/src-tauri/build.rstools/tauri-mcp-client/src-tauri/capabilities/default.jsontools/tauri-mcp-client/src-tauri/src/main.rstools/tauri-mcp-client/src-tauri/tauri.conf.jsontools/tauri-mcp-client/src-web/README.mdtools/tauri-mcp-client/src-web/index.htmltools/tauri-mcp-client/src-web/package.jsontools/tauri-mcp-client/src-web/src/App.tsxtools/tauri-mcp-client/src-web/src/bridge.tstools/tauri-mcp-client/src-web/src/charts/BarChart.tsxtools/tauri-mcp-client/src-web/src/charts/LineChart.tsxtools/tauri-mcp-client/src-web/src/charts/Panel.tsxtools/tauri-mcp-client/src-web/src/charts/scale.tstools/tauri-mcp-client/src-web/src/charts/useSize.tstools/tauri-mcp-client/src-web/src/main.tsxtools/tauri-mcp-client/src-web/src/theme.csstools/tauri-mcp-client/src-web/src/types.tstools/tauri-mcp-client/src-web/tsconfig.jsontools/tauri-mcp-client/src-web/vite.config.tstools/tauri-mcp-client/src/app.jstools/tauri-mcp-client/src/index.htmltools/tauri-mcp-client/src/styles.css
| ```bash | ||
| ./scripts/build-sidecar.sh # -> src-tauri/binaries/mcp-bridge-<triple> | ||
| cd src-tauri && cargo tauri build | ||
| ``` | ||
|
|
||
| How it fits together: | ||
|
|
||
| - `src-python/sidecar.spec` — PyInstaller spec; bundles the fastmcp/fastapi/ | ||
| uvicorn trees and `mcp_config.example.json` into one `mcp-bridge` executable. | ||
| - `scripts/build-sidecar.sh` — runs PyInstaller in a throwaway venv, then copies | ||
| the output to `src-tauri/binaries/mcp-bridge-<target-triple>` (the name Tauri | ||
| requires). | ||
| - `tauri.conf.json` → `bundle.externalBin` references `binaries/mcp-bridge`, so | ||
| Tauri copies the matching binary next to the app executable at bundle time. | ||
| - `src-tauri/src/main.rs` prefers that bundled `mcp-bridge` binary at runtime | ||
| and only falls back to `python server.py` when it isn't present (dev mode). |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift
Do not package the legacy Python bridge as the dashboard sidecar.
These instructions stage Python as mcp-bridge, but the packaged Tauri flow expects that binary to serve script/dashboard resources. The Python bridge lacks /scripts and /dashboards, so the React dashboard fails after following this distributable build path. Use distinct sidecar names or make the dashboard build explicitly stage the compiled TypeScript bridge.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@tools/tauri-mcp-client/README.md` around lines 151 - 166, Update the
documented Tauri packaging flow to avoid staging the legacy Python bridge as
mcp-bridge, since the packaged dashboard requires /scripts and /dashboards. Use
distinct sidecar names, or explicitly stage the compiled TypeScript dashboard
bridge, and align the references in the build commands, tauri.conf.json, and
main.rs runtime selection.
| - The bridge binds to `127.0.0.1` only and CORS is open — appropriate for a | ||
| local desktop bridge, not for exposing on a network. |
There was a problem hiding this comment.
🔒 Security & Privacy | 🔴 Critical | ⚡ Quick win
Restrict Python bridge CORS; loopback alone is not sufficient.
src-python/server.py allows every origin, methods, and headers. A remote webpage can therefore read from and invoke this unauthenticated localhost bridge—including configured credentialed MCP tools. Replace allow_origins=["*"] with the same explicit loopback/Tauri origin policy used by the TypeScript bridge.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@tools/tauri-mcp-client/README.md` around lines 178 - 179, Update the Python
bridge CORS configuration in server.py to replace the wildcard origin, methods,
and headers with the explicit loopback/Tauri origin policy used by the
TypeScript bridge. Preserve only the required local origins and ensure
credentialed requests remain restricted to that allowlist.
| if command -v rustc >/dev/null 2>&1; then | ||
| TRIPLE="$(rustc -vV | awk '/^host:/ {print $2}')" | ||
| else | ||
| case "$(uname -s)-$(uname -m)" in | ||
| Linux-x86_64) TRIPLE="x86_64-unknown-linux-gnu" ;; | ||
| Linux-aarch64) TRIPLE="aarch64-unknown-linux-gnu" ;; | ||
| Darwin-arm64) TRIPLE="aarch64-apple-darwin" ;; | ||
| Darwin-x86_64) TRIPLE="x86_64-apple-darwin" ;; | ||
| *) echo "error: unknown platform; set TRIPLE/BUN_TARGET manually" >&2; exit 1 ;; | ||
| esac | ||
| fi | ||
| case "$TRIPLE" in | ||
| x86_64-unknown-linux-gnu) BUN_TARGET="${BUN_TARGET:-bun-linux-x64}" ;; | ||
| aarch64-unknown-linux-gnu) BUN_TARGET="${BUN_TARGET:-bun-linux-arm64}" ;; | ||
| aarch64-apple-darwin) BUN_TARGET="${BUN_TARGET:-bun-darwin-arm64}" ;; | ||
| x86_64-apple-darwin) BUN_TARGET="${BUN_TARGET:-bun-darwin-x64}" ;; | ||
| *-windows-*) BUN_TARGET="${BUN_TARGET:-bun-windows-x64}"; EXE=".exe" ;; | ||
| *) BUN_TARGET="${BUN_TARGET:-bun-$(uname -s | tr A-Z a-z)-x64}" ;; | ||
| esac | ||
| EXE="${EXE:-}" | ||
| echo "==> Target triple: $TRIPLE (bun target: $BUN_TARGET)" |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '\n## build-bridge.sh (around lines 1-120)\n'
sed -n '1,140p' tools/tauri-mcp-client/scripts/build-bridge.sh | cat -n
printf '\n## search for TRIPLE/BUN_TARGET/externalBin references\n'
rg -n "TRIPLE|BUN_TARGET|externalBin|mcp-bridge" tools/tauri-mcp-client -S
printf '\n## related build-sidecar script\n'
sed -n '1,200p' tools/tauri-mcp-client/scripts/build-sidecar.sh | cat -nRepository: AM1010101/agent-skills
Length of output: 12198
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '\n## file list under tools/tauri-mcp-client\n'
git ls-files tools/tauri-mcp-client | sed -n '1,200p'
printf '\n## tauri config files mentioning externalBin or sidecar\n'
rg -n "externalBin|sidecar|mcp-bridge|build-bridge" tools/tauri-mcp-client -SRepository: AM1010101/agent-skills
Length of output: 11102
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '\n## build-bridge.sh (around lines 1-140)\n'
sed -n '1,140p' tools/tauri-mcp-client/scripts/build-bridge.sh | cat -n
printf '\n## search for TRIPLE/BUN_TARGET/externalBin/mcp-bridge references\n'
rg -n "TRIPLE|BUN_TARGET|externalBin|mcp-bridge" tools/tauri-mcp-client -S
printf '\n## related build-sidecar script\n'
sed -n '1,200p' tools/tauri-mcp-client/scripts/build-sidecar.sh | cat -nRepository: AM1010101/agent-skills
Length of output: 12209
Derive the staged triple from the intended bundle target. TRIPLE is always taken from rustc -vV, so an explicit TRIPLE is ignored and BUN_TARGET=bun-darwin-arm64 on Linux still stages mcp-bridge-<linux-triple>. That breaks Tauri’s target-specific externalBin lookup for cross-target builds. Accept a matching TRIPLE/target or map it from BUN_TARGET and fail on mismatches.
🧰 Tools
🪛 Shellcheck (0.11.0)
[info] 47-47: Use '[:upper:]' to support accents and foreign alphabets.
(SC2019)
[info] 47-47: Use '[:lower:]' to support accents and foreign alphabets.
(SC2018)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@tools/tauri-mcp-client/scripts/build-bridge.sh` around lines 30 - 50, Update
the target-resolution logic before the `case "$TRIPLE"` mapping so explicit
`TRIPLE` and `BUN_TARGET` values are honored and mutually consistent. Derive the
Rust triple from `BUN_TARGET` when only the bundle target is provided, preserve
native detection when neither is set, and fail clearly when the supplied values
mismatch; ensure the staged bridge filename uses the resolved intended triple.
| app = FastAPI(title="Tauri MCP Client bridge", lifespan=lifespan) | ||
| app.add_middleware( | ||
| CORSMiddleware, | ||
| allow_origins=["*"], # localhost-only server; fine for a desktop bridge | ||
| allow_methods=["*"], | ||
| allow_headers=["*"], | ||
| ) |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '\n## server.py outline\n'
ast-grep outline tools/tauri-mcp-client/src-python/server.py --view expanded || true
printf '\n## relevant route and middleware context\n'
sed -n '1,260p' tools/tauri-mcp-client/src-python/server.py
printf '\n## search for origin/auth/token checks in the Python client bridge\n'
rg -n "allow_origins|CORSMiddleware|origin|token|auth|middleware|FastAPI|`@app`\." tools/tauri-mcp-client/src-python -SRepository: AM1010101/agent-skills
Length of output: 10220
Restrict CORS to trusted app origins.
allow_origins=["*"] lets any website read from and invoke this localhost bridge’s MCP tool endpoints. Loopback binding is not an origin boundary; use an explicit Tauri/Vite allowlist, and add a per-launch token if non-browser local clients need to be excluded.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@tools/tauri-mcp-client/src-python/server.py` around lines 161 - 167, Update
the CORSMiddleware configuration in the FastAPI app to replace
allow_origins=["*"] with an explicit allowlist of trusted Tauri/Vite application
origins. Preserve the existing methods and headers settings, and add a
per-launch authentication token for MCP endpoints if required to exclude
non-browser local clients.
| useEffect(() => { | ||
| let alive = true; | ||
| listDashboards() | ||
| .then((ds) => { | ||
| if (!alive) return; | ||
| setList(ds); | ||
| setSelected((cur) => cur ?? ds[0]?.name ?? null); | ||
| }) | ||
| .catch((e) => alive && setError((e as Error).message)); | ||
| return () => { | ||
| alive = false; | ||
| }; | ||
| }, [status === "ok"]); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Clear stale dashboard-list errors after bridge recovery.
This effect runs before the bridge is healthy, and a failed initial request sets error. When /health later becomes healthy, a successful retry updates list but never clears error, so the error panel continues to hide the recovered dashboard. Gate on status === "ok" and clear the error before or after a successful load.
Proposed fix
useEffect(() => {
+ if (status !== "ok") return;
let alive = true;
+ setError(null);
listDashboards()
.then((ds) => {
if (!alive) return;
setList(ds);
setSelected((cur) => cur ?? ds[0]?.name ?? null);
})
.catch((e) => alive && setError((e as Error).message));
return () => {
alive = false;
};
- }, [status === "ok"]);
+ }, [status]);📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| useEffect(() => { | |
| let alive = true; | |
| listDashboards() | |
| .then((ds) => { | |
| if (!alive) return; | |
| setList(ds); | |
| setSelected((cur) => cur ?? ds[0]?.name ?? null); | |
| }) | |
| .catch((e) => alive && setError((e as Error).message)); | |
| return () => { | |
| alive = false; | |
| }; | |
| }, [status === "ok"]); | |
| useEffect(() => { | |
| if (status !== "ok") return; | |
| let alive = true; | |
| setError(null); | |
| listDashboards() | |
| .then((ds) => { | |
| if (!alive) return; | |
| setList(ds); | |
| setSelected((cur) => cur ?? ds[0]?.name ?? null); | |
| }) | |
| .catch((e) => alive && setError((e as Error).message)); | |
| return () => { | |
| alive = false; | |
| }; | |
| }, [status]); |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@tools/tauri-mcp-client/src-web/src/App.tsx` around lines 31 - 43, Update the
dashboard-loading useEffect around listDashboards so it only runs when status
=== "ok", and clear the existing error state after a successful dashboard load.
Preserve the current list and selection updates, ensuring a recovered bridge no
longer leaves the stale error panel visible.
| const ys = data.map((d) => Number(d[y])); | ||
| const yMin = Math.min(...ys, 0); | ||
| const yMax = Math.max(...ys); | ||
| const ticks = niceTicks(yMin, yMax, 4); | ||
| const yScale = linear( | ||
| [ticks[0], ticks[ticks.length - 1]], | ||
| [M.top + ih, M.top], | ||
| ); | ||
| const xAt = (i: number) => | ||
| M.left + (data.length <= 1 ? iw / 2 : (i / (data.length - 1)) * iw); | ||
|
|
||
| const path = data | ||
| .map((d, i) => `${i === 0 ? "M" : "L"} ${xAt(i).toFixed(1)} ${yScale(Number(d[y])).toFixed(1)}`) | ||
| .join(" "); | ||
| const area = | ||
| `${path} L ${xAt(data.length - 1).toFixed(1)} ${(M.top + ih).toFixed(1)} ` + | ||
| `L ${xAt(0).toFixed(1)} ${(M.top + ih).toFixed(1)} Z`; |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Handle empty chart data before building scales and paths.
For data = [], Math.max(...ys) becomes -Infinity, niceTicks returns no ticks, and the area path uses data.length - 1. Render an explicit “No data” state (or reject empty rows upstream) before calculating chart geometry.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@tools/tauri-mcp-client/src-web/src/charts/LineChart.tsx` around lines 23 -
39, Handle an empty data array at the start of the LineChart rendering logic
before calculating ys, yMin, yMax, ticks, scales, or paths. Render the chart’s
explicit “No data” state for data.length === 0, while preserving the existing
geometry calculations for non-empty data.
| async function api(path, options) { | ||
| const res = await fetch(BASE + path, options); | ||
| if (!res.ok) { | ||
| const text = await res.text().catch(() => res.statusText); | ||
| throw new Error(`${res.status}: ${text}`); | ||
| } | ||
| return res.json(); |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
Add a finite timeout to bridge requests.
A stalled sidecar or MCP call leaves the UI indefinitely in calling…; the 5-second health poll also accumulates pending requests. Use an AbortController with a configurable deadline in api().
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@tools/tauri-mcp-client/src/app.js` around lines 12 - 18, Update api() to
create an AbortController and enforce a configurable finite request deadline,
passing its signal to fetch and ensuring the timeout is cleared after completion
or failure. Preserve the existing response validation and error propagation
while allowing callers to configure the deadline through options or the
established configuration mechanism.
| const li = document.createElement("li"); | ||
| li.innerHTML = `<span class="kind">${s.kind}</span> | ||
| <div class="name">${s.name}</div> | ||
| <div class="desc">${s.description || ""}</div>`; |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
Do not render bridge data with innerHTML.
Server/tool metadata and error messages can contain externally controlled text. The Python bridge returns configured server names and remote tool metadata, so these assignments permit markup injection. Build nodes with textContent/replaceChildren() instead.
Also applies to: 66-68, 72-73
🧰 Tools
🪛 ast-grep (0.44.1)
[warning] 38-40: Avoid assigning untrusted data to innerHTML/outerHTML or document.write
Context: li.innerHTML = <span class="kind">${s.kind}</span> <div class="name">${s.name}</div> <div class="desc">${s.description || ""}</div>
Note: [CWE-79] Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting').
(inner-outer-html)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@tools/tauri-mcp-client/src/app.js` around lines 38 - 41, Replace the
innerHTML assignments in the list-item rendering and the related locations
around lines 66-68 and 72-73 with DOM construction using createElement,
textContent, and replaceChildren. Ensure server names, tool metadata,
descriptions, and error messages are rendered strictly as text while preserving
the existing structure and displayed values.
Source: Linters/SAST tools
| const li = document.createElement("li"); | ||
| li.innerHTML = `<span class="kind">${s.kind}</span> | ||
| <div class="name">${s.name}</div> | ||
| <div class="desc">${s.description || ""}</div>`; | ||
| li.onclick = () => selectServer(s.name, li); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Make server and tool selection keyboard-operable.
Clickable <li> elements cannot be reached or activated by keyboard users. Use native <button> controls within each list item and retain the selected state semantically.
Also applies to: 66-70
🧰 Tools
🪛 ast-grep (0.44.1)
[warning] 38-40: Avoid assigning untrusted data to innerHTML/outerHTML or document.write
Context: li.innerHTML = <span class="kind">${s.kind}</span> <div class="name">${s.name}</div> <div class="desc">${s.description || ""}</div>
Note: [CWE-79] Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting').
(inner-outer-html)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@tools/tauri-mcp-client/src/app.js` around lines 38 - 42, Update the list-item
rendering around selectServer to use native button controls inside each li
instead of making the li itself clickable. Move the server/tool selection
handler onto the button, ensure the control is keyboard-operable, and preserve
the selected state with the appropriate semantic state attribute.
There was a problem hiding this comment.
Actionable comments posted: 14
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@tools/tauri-mcp-client/SECURITY.md`:
- Around line 18-21: Update the fenced CSP block in SECURITY.md to include the
text language identifier, preserving its contents unchanged.
In `@tools/tauri-mcp-client/src-scripts/src/bridge.ts`:
- Around line 102-105: Update the configuration parser around the returned
ServerConfig to handle config.env explicitly: validate it as a string-to-string
record and preserve it in the returned config so McpManager.connect can pass it
to StdioClientTransport, or reject the field with a clear validation error if
environment variables are unsupported. Do not silently discard a supplied
config.env.
In `@tools/tauri-mcp-client/src-scripts/src/mcp.ts`:
- Around line 145-148: Update connect and disconnect to track a per-server
generation or pending connection. In disconnect, invalidate the generation
before removing and closing the cached client; in connect, verify the generation
remains current before caching the newly connected client, and close and retry
the client when it has been invalidated.
- Around line 145-148: Update disconnect in the MCP client manager so
client.close() cleanup is best-effort and cannot reject after the configuration
has been saved; match the existing close() behavior by handling or suppressing
close failures while still deleting the client entry. Ensure bridge.ts does not
report the configuration update as failed when disconnect cleanup fails.
In `@tools/tauri-mcp-client/src-tauri/binaries/dashboards/sales.json`:
- Around line 17-19: Update the seed in the bar panel’s demo_timeseries params
from 6 to 3 so it uses the same series as the line panel; preserve the existing
chart configuration and subtitle.
In `@tools/tauri-mcp-client/src-tauri/binaries/mcp_config.example.json`:
- Around line 4-5: Update the MCP configuration represented by the command and
args entries to avoid runtime npx resolution: use a bundled, reviewed MCP server
binary or a pinned package with enforced signature/integrity verification,
ensuring release users do not need Node/npm or mutable package downloads.
In `@tools/tauri-mcp-client/src-tauri/binaries/scripts/demo_timeseries.mjs`:
- Around line 5-6: Validate every numeric parameter with a finite-number check
before computation: in
tools/tauri-mcp-client/src-tauri/binaries/scripts/demo_timeseries.mjs lines 5-6,
validate seed before generating revenue values; in
tools/tauri-mcp-client/src-tauri/binaries/scripts/everything_sum.mjs lines 5-7,
validate both a and b before calling ctx.callTool. Reject invalid, NaN, or
infinite inputs rather than allowing them across the bridge or into serialized
data.
In `@tools/tauri-mcp-client/src-tauri/binaries/scripts/everything_sum.mjs`:
- Line 8: Update the get-sum handling around ctx.callTool so the returned text
envelope is parsed to extract and return the numeric sum before the dashboard
consumes it. Preserve the existing a and b inputs, and ensure the result is
numeric rather than the full descriptive string.
In `@tools/tauri-mcp-client/src-tauri/binaries/scripts/mcp_tool_counts.mjs`:
- Around line 10-11: Update the catch block around ctx.listTools to normalize
unknown rejection values before accessing the message: use the Error message
only when e is an Error, otherwise convert e with String(e). Preserve the
existing skip log and fallback-row behavior for null, undefined, and other
non-Error rejections.
- Around line 10-12: Update the listTools failure handling in the catch block to
avoid pushing a server record with tools: 0, since that represents an outage as
a valid empty result. Propagate the failure or store an explicit error status,
and ensure downstream rendering distinguishes unavailable servers from servers
with no tools.
- Line 8: Update the MCP RPC flows around listTools(server), callTool(...), and
the HTTP bridge handler to enforce a bounded timeout for every connect,
client.listTools(), and tool invocation. Use the existing timeout or abort
mechanism where available, otherwise wrap each awaited call with cancellation or
a Promise.race, and ensure timed-out servers fail promptly so subsequent server
queries continue.
In `@tools/tauri-mcp-client/src-web/public/sandbox.js`:
- Around line 41-45: Update the message listener around the existing
dashboard-model validation to require event.source to equal window.parent before
calling render(data.model). Keep the current payload and panels checks
unchanged, and do not add an event.origin restriction because this frame uses an
opaque origin.
In `@tools/tauri-mcp-client/src-web/src/App.tsx`:
- Around line 71-80: Introduce a dedicated serversError state for the
listServers effect and update its catch handler to set that state instead of the
shared error state. Render serversError in the Connected MCPs/connections view,
leaving the dashboard error state and its existing loading flows unchanged.
In `@tools/tauri-mcp-client/src-web/src/DashboardSandbox.tsx`:
- Around line 44-51: The error path in DashboardSandbox.tsx forwards raw script
failure messages to the sandbox frame. Replace the Error.message value in the
Promise.all panel mapping with a generic non-identifying string before assigning
SandboxedPanel.error; re-verify the claim in tools/tauri-mcp-client/SECURITY.md
lines 23-27 after this code fix, with no direct documentation change unless
needed.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 4181e491-a090-4564-9110-0fc3ba0b1273
⛔ Files ignored due to path filters (51)
tools/tauri-mcp-client/src-tauri/Cargo.lockis excluded by!**/*.locktools/tauri-mcp-client/src-tauri/icons/128x128.pngis excluded by!**/*.pngtools/tauri-mcp-client/src-tauri/icons/128x128@2x.pngis excluded by!**/*.pngtools/tauri-mcp-client/src-tauri/icons/32x32.pngis excluded by!**/*.pngtools/tauri-mcp-client/src-tauri/icons/64x64.pngis excluded by!**/*.pngtools/tauri-mcp-client/src-tauri/icons/Square107x107Logo.pngis excluded by!**/*.pngtools/tauri-mcp-client/src-tauri/icons/Square142x142Logo.pngis excluded by!**/*.pngtools/tauri-mcp-client/src-tauri/icons/Square150x150Logo.pngis excluded by!**/*.pngtools/tauri-mcp-client/src-tauri/icons/Square284x284Logo.pngis excluded by!**/*.pngtools/tauri-mcp-client/src-tauri/icons/Square30x30Logo.pngis excluded by!**/*.pngtools/tauri-mcp-client/src-tauri/icons/Square310x310Logo.pngis excluded by!**/*.pngtools/tauri-mcp-client/src-tauri/icons/Square44x44Logo.pngis excluded by!**/*.pngtools/tauri-mcp-client/src-tauri/icons/Square71x71Logo.pngis excluded by!**/*.pngtools/tauri-mcp-client/src-tauri/icons/Square89x89Logo.pngis excluded by!**/*.pngtools/tauri-mcp-client/src-tauri/icons/StoreLogo.pngis excluded by!**/*.pngtools/tauri-mcp-client/src-tauri/icons/android/mipmap-hdpi/ic_launcher.pngis excluded by!**/*.pngtools/tauri-mcp-client/src-tauri/icons/android/mipmap-hdpi/ic_launcher_foreground.pngis excluded by!**/*.pngtools/tauri-mcp-client/src-tauri/icons/android/mipmap-hdpi/ic_launcher_round.pngis excluded by!**/*.pngtools/tauri-mcp-client/src-tauri/icons/android/mipmap-mdpi/ic_launcher.pngis excluded by!**/*.pngtools/tauri-mcp-client/src-tauri/icons/android/mipmap-mdpi/ic_launcher_foreground.pngis excluded by!**/*.pngtools/tauri-mcp-client/src-tauri/icons/android/mipmap-mdpi/ic_launcher_round.pngis excluded by!**/*.pngtools/tauri-mcp-client/src-tauri/icons/android/mipmap-xhdpi/ic_launcher.pngis excluded by!**/*.pngtools/tauri-mcp-client/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_foreground.pngis excluded by!**/*.pngtools/tauri-mcp-client/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_round.pngis excluded by!**/*.pngtools/tauri-mcp-client/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher.pngis excluded by!**/*.pngtools/tauri-mcp-client/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_foreground.pngis excluded by!**/*.pngtools/tauri-mcp-client/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_round.pngis excluded by!**/*.pngtools/tauri-mcp-client/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher.pngis excluded by!**/*.pngtools/tauri-mcp-client/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_foreground.pngis excluded by!**/*.pngtools/tauri-mcp-client/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_round.pngis excluded by!**/*.pngtools/tauri-mcp-client/src-tauri/icons/icon.icois excluded by!**/*.icotools/tauri-mcp-client/src-tauri/icons/icon.pngis excluded by!**/*.pngtools/tauri-mcp-client/src-tauri/icons/icon.svgis excluded by!**/*.svgtools/tauri-mcp-client/src-tauri/icons/ios/AppIcon-20x20@1x.pngis excluded by!**/*.pngtools/tauri-mcp-client/src-tauri/icons/ios/AppIcon-20x20@2x-1.pngis excluded by!**/*.pngtools/tauri-mcp-client/src-tauri/icons/ios/AppIcon-20x20@2x.pngis excluded by!**/*.pngtools/tauri-mcp-client/src-tauri/icons/ios/AppIcon-20x20@3x.pngis excluded by!**/*.pngtools/tauri-mcp-client/src-tauri/icons/ios/AppIcon-29x29@1x.pngis excluded by!**/*.pngtools/tauri-mcp-client/src-tauri/icons/ios/AppIcon-29x29@2x-1.pngis excluded by!**/*.pngtools/tauri-mcp-client/src-tauri/icons/ios/AppIcon-29x29@2x.pngis excluded by!**/*.pngtools/tauri-mcp-client/src-tauri/icons/ios/AppIcon-29x29@3x.pngis excluded by!**/*.pngtools/tauri-mcp-client/src-tauri/icons/ios/AppIcon-40x40@1x.pngis excluded by!**/*.pngtools/tauri-mcp-client/src-tauri/icons/ios/AppIcon-40x40@2x-1.pngis excluded by!**/*.pngtools/tauri-mcp-client/src-tauri/icons/ios/AppIcon-40x40@2x.pngis excluded by!**/*.pngtools/tauri-mcp-client/src-tauri/icons/ios/AppIcon-40x40@3x.pngis excluded by!**/*.pngtools/tauri-mcp-client/src-tauri/icons/ios/AppIcon-512@2x.pngis excluded by!**/*.pngtools/tauri-mcp-client/src-tauri/icons/ios/AppIcon-60x60@2x.pngis excluded by!**/*.pngtools/tauri-mcp-client/src-tauri/icons/ios/AppIcon-60x60@3x.pngis excluded by!**/*.pngtools/tauri-mcp-client/src-tauri/icons/ios/AppIcon-76x76@1x.pngis excluded by!**/*.pngtools/tauri-mcp-client/src-tauri/icons/ios/AppIcon-76x76@2x.pngis excluded by!**/*.pngtools/tauri-mcp-client/src-tauri/icons/ios/AppIcon-83.5x83.5@2x.pngis excluded by!**/*.png
📒 Files selected for processing (25)
.gitignoreskills/mcp-apps/SKILL.mdskills/mcp-apps/agents/openai.yamltools/basic-crm/.gitignoretools/phased-builder/.gitignoretools/tauri-mcp-client/SECURITY.mdtools/tauri-mcp-client/src-scripts/src/bridge.tstools/tauri-mcp-client/src-scripts/src/mcp.tstools/tauri-mcp-client/src-tauri/.gitignoretools/tauri-mcp-client/src-tauri/binaries/dashboards/mcp_overview.jsontools/tauri-mcp-client/src-tauri/binaries/dashboards/sales.jsontools/tauri-mcp-client/src-tauri/binaries/mcp_config.example.jsontools/tauri-mcp-client/src-tauri/binaries/scripts/demo_timeseries.mjstools/tauri-mcp-client/src-tauri/binaries/scripts/everything_sum.mjstools/tauri-mcp-client/src-tauri/binaries/scripts/mcp_tool_counts.mjstools/tauri-mcp-client/src-tauri/icons/icon.icnstools/tauri-mcp-client/src-tauri/src/main.rstools/tauri-mcp-client/src-tauri/tauri.conf.jsontools/tauri-mcp-client/src-web/public/sandbox.csstools/tauri-mcp-client/src-web/public/sandbox.htmltools/tauri-mcp-client/src-web/public/sandbox.jstools/tauri-mcp-client/src-web/src/App.tsxtools/tauri-mcp-client/src-web/src/DashboardSandbox.tsxtools/tauri-mcp-client/src-web/src/bridge.tstools/tauri-mcp-client/src-web/src/theme.css
💤 Files with no reviewable changes (1)
- .gitignore
🚧 Files skipped from review as they are similar to previous changes (2)
- tools/tauri-mcp-client/src-tauri/tauri.conf.json
- tools/tauri-mcp-client/src-tauri/src/main.rs
| ``` | ||
| default-src 'none'; script-src 'self'; style-src 'self'; img-src data:; | ||
| connect-src 'none'; base-uri 'none'; form-action 'none' | ||
| ``` |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Add a language identifier to the fenced CSP block.
markdownlint (MD040) flags this fenced code block for missing a language identifier.
Proposed fix
-```
+```text
default-src 'none'; script-src 'self'; style-src 'self'; img-src data:;
connect-src 'none'; base-uri 'none'; form-action 'none'</details>
<!-- suggestion_start -->
<details>
<summary>📝 Committable suggestion</summary>
> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
```suggestion
🧰 Tools
🪛 markdownlint-cli2 (0.23.1)
[warning] 18-18: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@tools/tauri-mcp-client/SECURITY.md` around lines 18 - 21, Update the fenced
CSP block in SECURITY.md to include the text language identifier, preserving its
contents unchanged.
Source: Linters/SAST tools
| if (typeof config.command !== "string" || !config.command.trim()) throw new Error("A local MCP command is required."); | ||
| const args = config.args === undefined ? [] : config.args; | ||
| if (!Array.isArray(args) || args.some((arg) => typeof arg !== "string")) throw new Error("Arguments must be strings."); | ||
| return { name, config: { command: config.command.trim(), args } }; |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Preserve or reject config.env explicitly.
McpManager.connect passes cfg.env to StdioClientTransport, but this parser silently drops a supplied config.env. The route returns HTTP 201, then the local MCP process starts without its required environment variables.
Validate config.env as a string-to-string record and include it in the returned ServerConfig. If this endpoint must not accept environment variables, reject config.env instead of discarding it.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@tools/tauri-mcp-client/src-scripts/src/bridge.ts` around lines 102 - 105,
Update the configuration parser around the returned ServerConfig to handle
config.env explicitly: validate it as a string-to-string record and preserve it
in the returned config so McpManager.connect can pass it to
StdioClientTransport, or reject the field with a clear validation error if
environment variables are unsupported. Do not silently discard a supplied
config.env.
| async disconnect(name: string) { | ||
| const client = this.clients.get(name); | ||
| this.clients.delete(name); | ||
| if (client) await client.close(); |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift
Make disconnect invalidate an in-progress connection.
A connect(name) call can load the old configuration and await its transport connection before it adds a client to this.clients. During that await, POST /servers saves the new configuration and disconnect(name) finds no cached client. The old connection then completes and is cached after the update.
Track a per-server generation or pending connection. Invalidate that generation before cleanup. Before caching a connected client, verify that its generation is still current. Close and retry the client when the generation changed.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@tools/tauri-mcp-client/src-scripts/src/mcp.ts` around lines 145 - 148, Update
connect and disconnect to track a per-server generation or pending connection.
In disconnect, invalidate the generation before removing and closing the cached
client; in connect, verify the generation remains current before caching the
newly connected client, and close and retry the client when it has been
invalidated.
🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win
Do not report a failed configuration update after saveConfig succeeds.
bridge.ts saves the configuration before it awaits disconnect(name). If client.close() rejects on Line 148, the route returns HTTP 400 although the new configuration is already persisted. Match close() behavior and make disconnection cleanup best-effort, or return a result that distinguishes a saved configuration from a cleanup failure.
Proposed fix
async disconnect(name: string) {
const client = this.clients.get(name);
this.clients.delete(name);
- if (client) await client.close();
+ if (client) {
+ try {
+ await client.close();
+ } catch {
+ /* ignore cleanup failure */
+ }
+ }
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| async disconnect(name: string) { | |
| const client = this.clients.get(name); | |
| this.clients.delete(name); | |
| if (client) await client.close(); | |
| async disconnect(name: string) { | |
| const client = this.clients.get(name); | |
| this.clients.delete(name); | |
| if (client) { | |
| try { | |
| await client.close(); | |
| } catch { | |
| /* ignore cleanup failure */ | |
| } | |
| } |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@tools/tauri-mcp-client/src-scripts/src/mcp.ts` around lines 145 - 148, Update
disconnect in the MCP client manager so client.close() cleanup is best-effort
and cannot reject after the configuration has been saved; match the existing
close() behavior by handling or suppressing close failures while still deleting
the client entry. Ensure bridge.ts does not report the configuration update as
failed when disconnect cleanup fails.
| "script": "demo_timeseries", | ||
| "params": { "seed": 6 }, | ||
| "chart": { "type": "bar", "x": "month", "y": "revenue", "yLabel": "Revenue ($)" } |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Use the same seed for the “same series” comparison.
The line panel uses seed 3, but the bar panel uses seed 6. The panels therefore render different data. Set the bar seed to 3, or change the subtitle.
Proposed fix
- "params": { "seed": 6 },
+ "params": { "seed": 3 },📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| "script": "demo_timeseries", | |
| "params": { "seed": 6 }, | |
| "chart": { "type": "bar", "x": "month", "y": "revenue", "yLabel": "Revenue ($)" } | |
| "script": "demo_timeseries", | |
| "params": { "seed": 3 }, | |
| "chart": { "type": "bar", "x": "month", "y": "revenue", "yLabel": "Revenue ($)" } |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@tools/tauri-mcp-client/src-tauri/binaries/dashboards/sales.json` around lines
17 - 19, Update the seed in the bar panel’s demo_timeseries params from 6 to 3
so it uses the same series as the line panel; preserve the existing chart
configuration and subtitle.
| "command": "npx", | ||
| "args": ["-y", "@modelcontextprotocol/server-everything"] |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
rg -n -C 8 'server-everything|npx|mcp_config' tools/tauri-mcp-client
npm view `@modelcontextprotocol/server-everything` version versions dist.integrity --jsonRepository: AM1010101/agent-skills
Length of output: 50380
Pin and package the MCP server before release.
The bundled example seeds mcp_config.json with "command": "npx" and "args": ["-y", "@model contextprotocol/server-everything"]. That resolves a mutable package at runtime and requires Node/npm on the user host. Pin the server and enforce a signature/integrity boundary, or bundle the reviewed server binary with Node/npm instead of relying around an unpinned package.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@tools/tauri-mcp-client/src-tauri/binaries/mcp_config.example.json` around
lines 4 - 5, Update the MCP configuration represented by the command and args
entries to avoid runtime npx resolution: use a bundled, reviewed MCP server
binary or a pinned package with enforced signature/integrity verification,
ensuring release users do not need Node/npm or mutable package downloads.
| } catch (e) { | ||
| ctx.log(`skip ${server}: ${e.message}`); |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win
Normalize unknown rejection values before reading e.message.
The catch block assumes that e is a non-null Error. If ctx.listTools rejects with null or undefined, the logger throws inside the catch block and the fallback row is not returned.
Use e instanceof Error ? e.message : String(e).
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@tools/tauri-mcp-client/src-tauri/binaries/scripts/mcp_tool_counts.mjs` around
lines 10 - 11, Update the catch block around ctx.listTools to normalize unknown
rejection values before accessing the message: use the Error message only when e
is an Error, otherwise convert e with String(e). Preserve the existing skip log
and fallback-row behavior for null, undefined, and other non-Error rejections.
| } catch (e) { | ||
| ctx.log(`skip ${server}: ${e.message}`); | ||
| rows.push({ server, tools: 0 }); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Do not report an unavailable server as a server with zero tools.
When listTools fails, { tools: 0 } creates false dashboard data. The chart cannot distinguish an outage from a valid empty tool list. Return an explicit error status and render it, or propagate the failure instead of using zero.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@tools/tauri-mcp-client/src-tauri/binaries/scripts/mcp_tool_counts.mjs` around
lines 10 - 12, Update the listTools failure handling in the catch block to avoid
pushing a server record with tools: 0, since that represents an outage as a
valid empty result. Propagate the failure or store an explicit error status, and
ensure downstream rendering distinguishes unavailable servers from servers with
no tools.
| window.addEventListener('message', (event) => { | ||
| const data = event.data; | ||
| if (!data || data.type !== 'dashboard-model' || !data.model || !Array.isArray(data.model.panels)) return; | ||
| render(data.model); | ||
| }); |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
Add a sender check to the message listener.
This listener accepts any dashboard-model message without checking event.source or event.origin. Static analysis flags this as CWE-346 (origin validation error). The frame has an opaque origin, so the parent must target it with "*" (confirmed against MDN's postMessage guidance for opaque-origin targets), but the receiver here should still confirm the message actually came from its own parent frame before rendering it.
Proposed fix
window.addEventListener('message', (event) => {
+ if (event.source !== window.parent) return;
const data = event.data;
if (!data || data.type !== 'dashboard-model' || !data.model || !Array.isArray(data.model.panels)) return;
render(data.model);
});📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| window.addEventListener('message', (event) => { | |
| const data = event.data; | |
| if (!data || data.type !== 'dashboard-model' || !data.model || !Array.isArray(data.model.panels)) return; | |
| render(data.model); | |
| }); | |
| window.addEventListener('message', (event) => { | |
| if (event.source !== window.parent) return; | |
| const data = event.data; | |
| if (!data || data.type !== 'dashboard-model' || !data.model || !Array.isArray(data.model.panels)) return; | |
| render(data.model); | |
| }); |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@tools/tauri-mcp-client/src-web/public/sandbox.js` around lines 41 - 45,
Update the message listener around the existing dashboard-model validation to
require event.source to equal window.parent before calling render(data.model).
Keep the current payload and panels checks unchanged, and do not add an
event.origin restriction because this frame uses an opaque origin.
Source: Linters/SAST tools
| // The connection list belongs to the trusted shell. It never enters a | ||
| // dashboard definition or panel payload. | ||
| useEffect(() => { | ||
| if (status !== "ok") return; | ||
| let alive = true; | ||
| listServers() | ||
| .then((items) => alive && setServers(items)) | ||
| .catch((e) => alive && setError((e as Error).message)); | ||
| return () => { alive = false; }; | ||
| }, [status]); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Servers-loading failure overwrites the dashboard-view error state.
This effect calls setError on failure, the same state variable used by the dashboard-loading effect (line 65) and the dashboard-definition effect (line 104). Only the Dashboard view renders error (line 151). If listing MCP servers fails, the Dashboard tab shows an unrelated error message, even though the actual failure belongs to the Connected MCPs view. Conversely, a later dashboard load does not clear a stale error left by a servers failure.
Introduce a dedicated state for this effect's failures, consistent with how toolsError and saveError are already scoped to their own views.
Proposed fix
+ const [serversError, setServersError] = useState<string | null>(null);
+
useEffect(() => {
if (status !== "ok") return;
let alive = true;
listServers()
.then((items) => alive && setServers(items))
- .catch((e) => alive && setError((e as Error).message));
+ .catch((e) => alive && setServersError((e as Error).message));
return () => { alive = false; };
}, [status]);Render serversError in the connections view instead of reusing error.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@tools/tauri-mcp-client/src-web/src/App.tsx` around lines 71 - 80, Introduce a
dedicated serversError state for the listServers effect and update its catch
handler to set that state instead of the shared error state. Render serversError
in the Connected MCPs/connections view, leaving the dashboard error state and
its existing loading flows unchanged.
A desktop scaffold that drives a FastMCP process to call MCP servers.
The Python sidecar plays both MCP roles: a local FastMCP "hub" server
with its own tools, plus a config-driven fastmcp.Client that proxies to
external MCP servers. A FastAPI localhost bridge exposes it to a simple
HTML frontend, and the Tauri (v2) Rust shell spawns the sidecar on start.
Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com
Claude-Session: https://claude.ai/code/session_011c8J7RdTEPqqi1Q6kdKKLu
Summary by CodeRabbit
New Features
Documentation