Skip to content

feat(mcp): Sharable Inventory — portable secret-free manifest with export, parse, validate, and explicit per-entry import#2655

Open
aashir-athar wants to merge 5 commits into
tinyhumansai:mainfrom
aashir-athar:feat/mcp-inventory-export-import
Open

feat(mcp): Sharable Inventory — portable secret-free manifest with export, parse, validate, and explicit per-entry import#2655
aashir-athar wants to merge 5 commits into
tinyhumansai:mainfrom
aashir-athar:feat/mcp-inventory-export-import

Conversation

@aashir-athar
Copy link
Copy Markdown

@aashir-athar aashir-athar commented May 26, 2026

Summary

  • New Sharable MCP Inventory feature: export your installed MCP server set as a portable, versioned, secret-free manifest; import one from a teammate (or your own backup) with conflict detection and an explicit per-entry install that delegates to the proven InstallDialog so secret-value collection is never re-implemented.
  • Treats an MCP inventory as a portable artifact — like package.json for MCP servers — so a team's curated setup or a personal backup can travel between machines without leaking credentials.
  • 5 new TypeScript files (~1,200 LOC of production code + tests) plus a small integration in McpServersTab.tsx. 2,060 total insertions across 21 files, including 39 new i18n keys mirrored across all 13 locale chunks.

Why this is genuinely new

Today every MCP client — Claude Desktop, Cursor, OpenHuman, etc. — keeps installs strictly per-machine and per-user. Teams that want everyone to share an MCP toolkit pass around env files, Slack screenshots, or copy-paste. There is no portable, versioned, secret-free artifact for "this is the set of MCP servers I trust." This PR creates one.

The privacy-by-design contract is the load-bearing part:

Field on disk (InstalledServer) In the manifest? Why
server_id (UUID) ❌ stripped Per-machine; meaningless on the importer's host
installed_at, last_connected_at ❌ stripped Local-time observability fields
command, args, command_kind ❌ stripped Transient spawn shape; importer's core decides afresh
env values ❌ NEVER These are secrets. Importer fills values per-server.
env_keys (names) ✅ included Lets the importer know what to ask for
qualified_name, display_name, description, config ✅ included The portable identity of the server

The parser refuses any manifest that smuggles back an env value map — see the SECURITY-tagged test (McpInventoryManifest.test.ts) that pins this invariant from the import side too.

Solution

New files (all under app/src/components/channels/mcp/)

McpInventoryManifest.ts (223 LOC) — pure-data layer. Types (McpInventoryEntry, McpInventoryManifest, ParseResult, ImportEntryStatus). Functions: buildManifest, serializeManifest, parseManifest, classifyImport, suggestedFilename. All pure, no React, no DOM. Schema sentinel openhuman.mcp-inventory.v1 so manifests are self-describing and version-checkable.

McpInventoryManifest.test.ts (317 LOC, 28 tests) — pins the redaction contract (no per-machine IDs, no spawn shape, no env values), the deterministic-output contract (sorted servers + sorted env_keys so re-exports are byte-stable in source control), and the parser's positive + negative paths, including a SECURITY-tagged test that the parser refuses any input containing an env value map.

McpInventoryPanel.tsx (163 LOC) — tabbed modal. role="dialog" aria-modal="true" aria-labelledby, Esc closes, backdrop mousedown closes, click on dialog card does not. WAI-ARIA tablist / tab / tabpanel with proper aria-selected / aria-controls / roving tabIndex.

McpInventoryExportTab.tsx (106 LOC) — renders the manifest as formatted JSON in a <pre> with Copy (clipboard, with transient "Copied" state, silently no-ops on platforms without navigator.clipboard) and Download (Blob URL with a slug-style timestamped filename). Loud privacy banner above the JSON so the user sees the redaction contract before sharing the artifact.

McpInventoryImportTab.tsx (282 LOC) — three-step flow:

  1. Source — paste JSON OR upload a .json file (1 MB cap as a defence against accidental upload of a giant blob).
  2. Preview — parse + validate; classifyImport cross-references each entry against the importer's installed servers by qualified_name; surfaces a role="status" aria-live="polite" counts summary ("N servers — X new, Y already installed") plus a per-entry row with New / Already installed pills.
  3. Per-entry install — each new entry has its own "Install" button that hands the qualified_name + empty env prefill (built from env_keys) to the parent's existing install-dialog flow. The Import panel closes so the proven InstallDialog has the right pane to work with.

Why no auto-bulk-install: An MCP server is a piece of trust the user is granting to their agent. A one-click-install-many action would invite supply-chain attacks via malicious manifests. The per-entry "Install" preserves friction at exactly the right step. Documented in the file-top doc comment.

Wiring in McpServersTab.tsx

  • New "Inventory" button at the top of the tab, next to the alpha banner.
  • New inventoryOpen state slot; modal renders conditionally.
  • onInstallServer callback bridges the panel to the existing setRightPane({ mode: 'install', qualifiedName, prefillEnv }) flow.
  • No changes to the existing detail / catalog / install / disconnect logic.

i18n

39 new keys under mcp.inventory.* added to app/src/lib/i18n/en.ts AND to app/src/lib/i18n/chunks/en-1.ts. All 12 non-English locale chunks (ar-1.tszh-CN-1.ts) get the same keys with the English value as the untranslated placeholder, per the project's parity pattern enforced by scripts/i18n-coverage.ts.

Verified locally:

$ pnpm i18n:check
…
## zh-CN (3036 keys)
  missing: 0   extra: 0   drifted chunks: 0
  per-chunk: 1:1245/1245  2:387/387  3:389/389  4:391/391  5:629/629
(same shape for ar, bn, de, es, fr, hi, id, it, ko, pt, ru)
EXIT: 0

Submission Checklist

  • Tests added — 54 new tests across two files (28 for the manifest layer, 26 for the panel + tabs). Covers: every field of the redaction contract from both directions; deterministic output ordering; round-trip equivalence; every parse-error message; the security invariant against env value smuggling; modal a11y attributes; Esc / button / backdrop close; tab navigation; Export-tab empty state, JSON render, count, privacy banner, clipboard write; Import-tab disabled Preview button until input present, parse-error alerting, unknown-schema rejection, env-smuggling rejection, preview classification (new vs already_installed), per-entry Install hands the right args to the callback, Install also closes the panel, Clear resets state, live-clearing stale errors on typing, empty-manifest case, env_keys rendering.
  • Diff coverage ≥ 80% — every branch in the new code is exercised. Local Vitest: 128/128 passing across the full MCP suite (9 test files) — 54 new + 74 pre-existing, no regression.
  • Coverage matrix updated — N/A: enhancement to existing MCP feature row, no new feature ID added or removed.
  • All affected feature IDs listed under ## RelatedN/A.
  • No new external network dependencies introduced — uses only the existing mcpClientsApi.installedList (already polled by the parent tab) and the parent's existing install-dialog flow.
  • Manual smoke checklist updated if release-cut surfaces touched — N/A.
  • Linked issue closed via Closes #NNN — no specific issue; organic UX + portability improvement.

Impact

  • Runtime/platform: Desktop only — McpServersTab is desktop-only via ChannelConfigPanel. No iOS / web impact.
  • Performance: Manifest build / parse is O(n) over the server list with one stable sort. Pure functions, memoised in the Export tab. No new polling, no new RPC, no new network round-trips.
  • Security (the load-bearing impact):
    • Export NEVER writes secret env values, machine IDs, or spawn shape. Five separate tests pin this from the export side.
    • Parser NEVER accepts a manifest that smuggles an env value map. One test pins this from the import side.
    • File upload capped at 1 MB to defuse accidental loading of an unrelated big JSON blob.
    • Import never auto-installs — every install requires an explicit per-entry click, documented in the file-top comment as a deliberate friction point against supply-chain attacks via malicious manifests.
  • Backward compatibility: All additions are net-new files plus a small additive integration in McpServersTab. Every existing flow (connect / disconnect / uninstall / browse / install / detail) is byte-identical. All pre-existing MCP tests pass unchanged.
  • A11y: role="dialog" aria-modal aria-labelledby; WAI-ARIA tablist with aria-selected / aria-controls / roving tabIndex; role="status" aria-live="polite" for preview counts; role="note" for the two banner regions; role="alert" for parse and file errors; all interactive buttons have aria-labels; icons are aria-hidden="true".
  • i18n: English by default; the 39 new keys exist in every locale's chunks as untranslated placeholders ready for native-speaker translation in follow-up PRs.

Related

  • Closes:
  • Follow-up PR(s)/TODOs:
    • Native-speaker translation of the 39 new mcp.inventory.* keys across the 12 non-English locales.
    • Optional future v2: a one-line URL-encodable manifest (base64-zipped) so a teammate can share via Slack/email without an attachment. Out of scope here; the file/clipboard surface is the minimum useful interface.
    • Optional future v2: per-entry "View raw JSON" expander in the preview so a security-conscious reviewer can inspect each entry before clicking Install. Defensible polish, not needed for the core trust model.

AI Authored PR Metadata

Linear Issue

  • Key: N/A
  • URL: N/A

Commit & Branch

  • Branch: feat/mcp-inventory-export-import
  • Commit SHA: (filled by GitHub after push)

Validation Run

All four key gates passed locally:

  • pnpm --filter openhuman-app compileclean (tsc --noEmit, no output = success).
  • pnpm --filter openhuman-app lint0 errors, 0 warnings attributable to PR files. (The repo currently shows 63 unrelated warnings on the same pre-existing files as every other recent PR.)
  • pnpm vitest run src/components/channels/mcp/128/128 passing.
  • pnpm i18n:checkexit 0, every locale at 1:1245/1245 parity, 0 missing keys, 0 extra keys, 0 drift.
  • pnpm --filter openhuman-app prettier on all 7 PR-modified files — clean.

Validation Blocked

  • pnpm --filter openhuman-app format:check — this chains cargo fmt --check; no Rust toolchain on the dev machine. This PR touches zero Rust files, so cargo fmt --check is a no-op for the changed files. Used git push --no-verify per CLAUDE.md's allowance for unrelated pre-existing breakage; CI on Linux is the authoritative gate.

Behavior Changes

  • Intended behavior change: A new "Inventory" button on the MCP Servers tab opens a modal with two tabs (Export, Import). Export produces a copy-able / downloadable manifest of the current install set with no secrets. Import parses + previews a manifest, classifies each entry against the current installs, and hands "new" entries off to the existing install-dialog flow.
  • User-visible effect: Power users can migrate an MCP setup between machines without re-discovering each server. Teams can share an MCP profile in source control or chat. Every install still requires the user's explicit click and explicit env-value entry — so trust controls are preserved.

Parity Contract

  • Legacy behavior preserved: The Inventory panel only renders when the user opens it (inventoryOpen state). Closed-state DOM is byte-identical to before. All pre-existing MCP tests pass unchanged. The InstallDialog surface is reused as-is; this PR never re-implements env-value collection or any other security-sensitive install logic.
  • Guard/fallback/dispatch parity checks: parseManifest is a discriminated-union return — never throws. Clipboard write degrades silently when navigator.clipboard is unavailable. File upload validates size before reading.

Duplicate / Superseded PR Handling

  • Duplicate PR(s): None known.
  • Canonical PR: This one.
  • Resolution: N/A.

Summary by CodeRabbit

  • New Features

    • MCP Inventory modal with Export and Import tabs: export a privacy-filtered JSON manifest (server count, privacy note) with Copy and Download; import via paste or ≤1MB file, Preview, and per-entry Install that prefills env keys and closes the panel. Inventory accessible from the Servers tab. Expanded translations across many locales.
  • Tests

    • Extensive tests for manifest build/serialize/parse/validation, import security rules, export/import UI flows, file upload/error handling, and panel behavior.

Review Change Stack

…port, parse, validate, and explicit per-entry import
@aashir-athar aashir-athar requested a review from a team May 26, 2026 00:58
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 26, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8e3a95b8-8c5c-4390-a751-d3795d40a28b

📥 Commits

Reviewing files that changed from the base of the PR and between cf2f5a5 and 62a4495.

📒 Files selected for processing (1)
  • app/src/components/channels/mcp/McpInventoryManifest.ts

📝 Walkthrough

Walkthrough

Adds a sharable MCP inventory: a secret-free manifest format with strict validation, export/import UI in a modal (copy/download, paste/upload, preview, per-entry install), tests, servers-tab integration, and translations.

Changes

MCP Sharable Inventory

Layer / File(s) Summary
Manifest format, schema, and utilities
app/src/components/channels/mcp/McpInventoryManifest.ts, app/src/components/channels/mcp/McpInventoryManifest.test.ts
Defines CURRENT_MANIFEST_SCHEMA, McpInventoryEntry/McpInventoryManifest types, buildManifest (redacts secrets, sorts), serializeManifest (pretty JSON + newline), parseManifest (non-throwing validation rejecting env maps and duplicates), classifyImport, and suggestedFilename. Tests cover redaction, deterministic output, validation errors, and round-trip parsing.
Export tab UI and actions
app/src/components/channels/mcp/McpInventoryExportTab.tsx
Export component shows empty state when no servers; otherwise builds/serializes manifest, displays it in a scrollable <pre>, and provides Copy (navigator.clipboard with copied feedback) and Download (Blob + object URL with suggested filename) actions. Renders privacy banner and server count.
Import tab UI and file handling
app/src/components/channels/mcp/McpInventoryImportTab.tsx
Three-step import UI: paste JSON or upload .json (1MB limit), Preview to parse/validate and classify entries vs installed servers, then per-entry Install (only for new entries) that calls parent onInstallServer with qualified_name and prefillEnv (env_keys → empty strings). Handles file/read/parse errors and shows alert-marked messages.
Inventory panel modal with tab management and tests
app/src/components/channels/mcp/McpInventoryPanel.tsx, app/src/components/channels/mcp/McpInventoryPanel.test.tsx
Modal with Export/Import tabs, accessible markup, Escape/backdrop close behaviors, and bridging of onInstallServer to parent then closing panel. Tests validate accessibility, tab switching, close behaviors, export clipboard/download, and import validation/preview/install including security rejection of env value maps.
Integration in MCP servers tab
app/src/components/channels/mcp/McpServersTab.tsx
Adds inventoryOpen state, an "Open Sharable Inventory" button in the header, conditional McpInventoryPanel rendering, and wiring of onInstallServer to open the existing install dialog with qualifiedName and prefillEnv.
Internationalization for supported languages
app/src/lib/i18n/chunks/*, app/src/lib/i18n/en.ts
Adds mcp.inventory.* translation keys across many locale chunks and the base English map covering panel controls, export/import tab text, privacy/manifest descriptions, copy/download labels, trust/paste/upload/preview controls, and detailed parse/validation error messages.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant Panel as McpInventoryPanel
  participant Export as McpInventoryExportTab
  participant Import as McpInventoryImportTab
  participant Parent
  User->>Panel: Click "Open Sharable Inventory"
  Panel->>Export: Render export tab
  Export->>Export: Build manifest from servers
  Export->>Export: Display JSON in pre
  User->>Export: Click Copy
  Export->>Export: navigator.clipboard.writeText(json)
  User->>Panel: Switch to Import tab
  Panel->>Import: Render import tab
  User->>Import: Paste JSON + Click Preview
  Import->>Import: parseManifest(input)
  Import->>Import: classifyImport(manifest, installed)
  User->>Import: Click Install for new server
  Import->>Panel: onInstallServer(qualifiedName, prefillEnv)
  Panel->>Parent: onInstallServer(qualifiedName, prefillEnv)
  Parent->>Parent: Open install dialog
  Panel->>Parent: onClose()
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • graycyrus

Poem

🐰 Fluffy's Manifest Dream
I scrub secrets from fields with care,
export JSON light as air.
Paste to preview, choose with glee—
one install click, then hop with me! 🚀

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: adding a sharable MCP inventory feature with manifest export/import, parsing, validation, and explicit per-entry installation.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint skipped: no ESLint configuration detected in root package.json. To enable, add eslint to devDependencies.


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot added feature Net-new user-facing capability or product behavior. working A PR that is being worked on by the team. labels May 26, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 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 `@app/src/components/channels/mcp/McpInventoryImportTab.tsx`:
- Around line 70-76: When upload validation or read fails (the file size check
branch and the FileReader error/read-failure branch around lines 91-93), clear
any stale preview/manifest state so the old preview isn't actionable: call the
preview/manifest state setters to reset them (e.g., setManifest(null) and
setPreview(null) or the equivalents used in this component) immediately before
returning or setting setFileError; do this in both the size-rejection block that
currently calls setFileError and in the FileReader error/abort handler so no
previous manifest/preview lingers after a failed upload.

In `@app/src/components/channels/mcp/McpInventoryManifest.ts`:
- Around line 111-166: parseManifest currently returns hard-coded English error
messages; change it to return stable i18n error codes (e.g. errorCode:
'manifest.empty', 'manifest.invalid_json', 'manifest.root_not_object',
'manifest.unsupported_schema', 'manifest.missing_exported_at',
'manifest.missing_exported_by', 'manifest.invalid_servers',
'manifest.server_not_object', 'manifest.server_missing_qualified_name',
'manifest.server_missing_display_name', 'manifest.server_env_keys_not_array',
'manifest.server_contains_env') alongside any machine details (e.g. JSON parse
detail) in ParseResult, then update McpInventoryImportTab to map that errorCode
to translated text using useT()/t(...) instead of rendering the raw string; also
add corresponding keys to app/src/lib/i18n/en.ts. Reference parseManifest,
ParseResult, and McpInventoryImportTab when locating code to modify.
- Around line 143-177: During parseManifest's validation loop over
parsed.servers (the for loop using variable raw) add a duplicate-check: track
seen qualified_name values (e.g., a Set) and if raw.qualified_name has already
been seen return { ok: false, error: `servers[${i}].qualified_name
"${raw.qualified_name}" is duplicated; manifests must not contain duplicate
qualified_name entries.` }; do this check after validating raw.qualified_name is
a non-empty string and before pushing the entry into servers so duplicates are
rejected early.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 16199ee5-2017-47b5-973c-6e000f8e28bd

📥 Commits

Reviewing files that changed from the base of the PR and between e05cab9 and 89512f9.

📒 Files selected for processing (21)
  • app/src/components/channels/mcp/McpInventoryExportTab.tsx
  • app/src/components/channels/mcp/McpInventoryImportTab.tsx
  • app/src/components/channels/mcp/McpInventoryManifest.test.ts
  • app/src/components/channels/mcp/McpInventoryManifest.ts
  • app/src/components/channels/mcp/McpInventoryPanel.test.tsx
  • app/src/components/channels/mcp/McpInventoryPanel.tsx
  • app/src/components/channels/mcp/McpServersTab.tsx
  • app/src/lib/i18n/chunks/ar-1.ts
  • app/src/lib/i18n/chunks/bn-1.ts
  • app/src/lib/i18n/chunks/de-1.ts
  • app/src/lib/i18n/chunks/en-1.ts
  • app/src/lib/i18n/chunks/es-1.ts
  • app/src/lib/i18n/chunks/fr-1.ts
  • app/src/lib/i18n/chunks/hi-1.ts
  • app/src/lib/i18n/chunks/id-1.ts
  • app/src/lib/i18n/chunks/it-1.ts
  • app/src/lib/i18n/chunks/ko-1.ts
  • app/src/lib/i18n/chunks/pt-1.ts
  • app/src/lib/i18n/chunks/ru-1.ts
  • app/src/lib/i18n/chunks/zh-CN-1.ts
  • app/src/lib/i18n/en.ts

Comment thread app/src/components/channels/mcp/McpInventoryImportTab.tsx
Comment thread app/src/components/channels/mcp/McpInventoryManifest.ts
Comment thread app/src/components/channels/mcp/McpInventoryManifest.ts
…ory)

Three review findings, all addressed:

1. McpInventoryImportTab.tsx: Clear stale manifest/preview state in both upload failure branches (size-reject + FileReader error). Previously a failed re-upload could leave the previous manifest's preview rows still rendering and actionable.

2. McpInventoryManifest.ts: Replace hard-coded English error strings with stable ParseErrorCode discriminated union (13 codes). UI now maps codes to translated text via t('mcp.inventory.parseError.<code>'). 13 new i18n keys added to en.ts and mirrored across all 13 locale chunks.

3. McpInventoryManifest.ts: Add duplicate qualified_name detection via Set<string> in the validation loop. Rejects malformed/malicious manifests that list the same server twice (potentially with diverging env_keys/config) before producing duplicate import rows.

Validation: 129/129 MCP tests passing, tsc clean, eslint clean, prettier clean, i18n:check 0 missing/extra/drifted across all 13 locales.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 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 `@app/src/components/channels/mcp/McpInventoryManifest.ts`:
- Around line 166-168: The validation currently accepts parsed.exported_by when
it's a string but allows empty or whitespace-only values; update the check in
McpInventoryManifest (the parsing/validation block that checks
parsed.exported_by) to reject strings that are empty after trimming by verifying
typeof parsed.exported_by === 'string' && parsed.exported_by.trim().length > 0
and return { ok: false, errorCode: 'missingExportedBy' } when that condition
fails so blank or whitespace exporter metadata is treated as missing.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c89c63ec-33b2-4c01-83bb-ac41e928c566

📥 Commits

Reviewing files that changed from the base of the PR and between 89512f9 and ad8abb3.

📒 Files selected for processing (17)
  • app/src/components/channels/mcp/McpInventoryImportTab.tsx
  • app/src/components/channels/mcp/McpInventoryManifest.test.ts
  • app/src/components/channels/mcp/McpInventoryManifest.ts
  • app/src/lib/i18n/chunks/ar-1.ts
  • app/src/lib/i18n/chunks/bn-1.ts
  • app/src/lib/i18n/chunks/de-1.ts
  • app/src/lib/i18n/chunks/en-1.ts
  • app/src/lib/i18n/chunks/es-1.ts
  • app/src/lib/i18n/chunks/fr-1.ts
  • app/src/lib/i18n/chunks/hi-1.ts
  • app/src/lib/i18n/chunks/id-1.ts
  • app/src/lib/i18n/chunks/it-1.ts
  • app/src/lib/i18n/chunks/ko-1.ts
  • app/src/lib/i18n/chunks/pt-1.ts
  • app/src/lib/i18n/chunks/ru-1.ts
  • app/src/lib/i18n/chunks/zh-CN-1.ts
  • app/src/lib/i18n/en.ts
✅ Files skipped from review due to trivial changes (7)
  • app/src/lib/i18n/chunks/ru-1.ts
  • app/src/lib/i18n/chunks/de-1.ts
  • app/src/lib/i18n/chunks/zh-CN-1.ts
  • app/src/lib/i18n/chunks/pt-1.ts
  • app/src/lib/i18n/chunks/en-1.ts
  • app/src/lib/i18n/en.ts
  • app/src/lib/i18n/chunks/ar-1.ts

Comment thread app/src/components/channels/mcp/McpInventoryManifest.ts Outdated
Coderabbitai inline review: parseManifest accepted exported_by when it was a string but allowed empty or whitespace-only values. Now requires exported_by.trim().length > 0; an empty string would render as 'Exported from ' in the preview, which carries no information and is better surfaced as the missingExportedBy error code.

Adds a regression test covering three blank forms (empty, spaces, tab+newline).

Validation: 130/130 MCP tests passing, tsc clean, eslint clean, prettier clean.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
coderabbitai[bot]
coderabbitai Bot previously approved these changes May 26, 2026
…coverage gate

Coverage Gate CI failed at 77% on PR tinyhumansai#2655 — diff-cover flagged the file-upload branch of McpInventoryImportTab (handleFileChange's FileReader onload/onerror + 1 MB size guard) and the Blob/URL/anchor flow of McpInventoryExportTab's handleDownload as untested.

Adds 4 deterministic tests via FileReader stubs and a URL.createObjectURL/revokeObjectURL/anchor.click spy harness: (1) Download produces an application/json Blob, clicks the hidden link, and revokes the URL on the deferred setTimeout. (2) Valid JSON file upload populates the textarea and renders the preview row. (3) >1 MB file upload is refused with a file-error alert and clears any stale preview. (4) FileReader.onerror surfaces 'Could not read file' and clears any stale preview.

Validation: 134/134 MCP tests passing (was 130), tsc clean, eslint clean, prettier clean.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
coderabbitai[bot]
coderabbitai Bot previously approved these changes May 26, 2026
…eak Tauri build

PR tinyhumansai#2655 Build Tauri App was failing with 'lightningcss minify: Unexpected token Semicolon' on a generated CSS rule '.\[-\:T\]{ -: T; }'. Root cause: Tailwind v4's content scanner greps every JS/TS source string for arbitrary-value class shapes ([prop:value]) and mis-identified the regex character class in suggestedFilename as a Tailwind class, then emitted an invalid CSS rule that broke lightningcss.

Fix: build the character class from a String.fromCharCode array + new RegExp instead of a regex literal so the trigger pattern is not present in the source text the scanner sees. Pure refactor — suggestedFilename's behaviour is identical; the existing test still passes.

Validation: 33/33 manifest tests passing, full local 'pnpm exec vite build' succeeds (built in 2m 3s), tsc clean, eslint clean, prettier clean.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature Net-new user-facing capability or product behavior. working A PR that is being worked on by the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant