Releases the pending v1 security and hygiene fixes: the js-yaml
override correction (#2072), the remaining audit advisories (#2074),
and the esbuild/fsevents install-script denials (#2079). Together they
take `npm audit` from 8 advisories to 0.
Version fields only — no functional change.
The lockfile version fields were edited directly rather than via
`npm run update-version`, which finishes with a bare `npm install`
that re-resolves the whole tree; on this branch that churns 164
packages including production deps (@modelcontextprotocol/sdk, hono,
@hono/node-server 1.x -> 2.x major, jose, ws).
Fixes#2080
Claude-Session: https://claude.ai/code/session_01Gq5jMmxRUphrVbfNbYVmQH
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Adds overrides for the five advisories present in the production
dependency tree, plus two dev-only stragglers, bringing `npm audit`
to zero.
Only ip-address is meaningfully reachable: server/src/index.ts builds
sandboxRateLimiter from express-rate-limit, which parses IPs via
Address6 for subnet keying. Impact here is a rate-limit key bypass on
/sandbox rather than the SSRF the advisory titles imply, since req.ip
derives from the socket and the proxy binds localhost.
The other four are installed but unexercised: hono middleware is never
wired up, @hono/node-server's serve-static is never imported (only
getRequestListener), fast-uri is reached only for ajv format checks
whose result is never trusted for a host decision, and brace-expansion
expands serve-handler's config-supplied pattern rather than the
attacker-supplied path. nanoid and postcss are dev-only.
Every patched release exists within the current major line.
@hono/node-server is deliberately held at 1.19.17 rather than 2.x — a
major bump has no place on a deprecated branch.
Lock entries are patched in place rather than re-resolved, keeping the
diff to the affected packages.
Fixes#2074
Claude-Session: https://claude.ai/code/session_01Gq5jMmxRUphrVbfNbYVmQH
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
The root `overrides` block pinned js-yaml to versions inside the
advisory range (3.15.0 and 4.2.0), so `npm audit fix` reported a fix
as available and then changed nothing — overrides take precedence.
Bumps both pins to the patched `v3-legacy` / `v4-legacy` releases,
addressing GHSA-52cp-r559-cp3m and GHSA-5p4m-2wfm-xmqj.
Exposure is development-only: `npm ls js-yaml --omit=dev` is empty and
both copies are reachable only via eslint and ts-jest/istanbul, neither
of which ships in the published package.
Both patched versions have an identical dependency and bin shape, so
the lock entries were patched in place — 6 lines, no transitive churn.
Fixes#2072
Claude-Session: https://claude.ai/code/session_01Gq5jMmxRUphrVbfNbYVmQH
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Addresses the round-1 Copilot review.
- createPinnedAgent: Node's net.connect runs with autoSelectFamily on
(Node >= 20), so it calls the lookup hook with `{ all: true }` and
requires an ARRAY of `{ address, family }`. The scalar-only callback
failed every hostname request with ERR_INVALID_IP_ADDRESS, so /fetch
could only reach literal-IP targets. Both callback shapes are now
supported. Reproduced against Node 22/26 before and after.
- Tests: cover the `{ all: true }` shape for IPv4 and IPv6, and add an
end-to-end request through the agent over the production path
(node-fetch -> http.Agent -> net.connect) using an unresolvable
hostname, so the request can only succeed via the pinned IP. Verified
these three fail without the fix. Replaced the `Function`-typed casts
with a typed pinnedLookup() helper.
- CI: run the new server suite (.github/workflows/main.yml) and add a
root `test-server` script, so this regression coverage is enforced.
- package-lock.json: sync the server workspace manifest mirror with the
added @types/node and vitest devDependencies.
- index.ts: drop the `agent as any` cast and its eslint-disable — the
node-fetch RequestInit already types `agent`, and tsc is clean without
the suppression.
- Formatting: prettier-check now passes (it failed on the two new files).
Signed-off-by: cliffhall <cliff@futurescale.com>
* chore: v1 deprecation notices in all four packages, bump to 1.0.1
Phase 2 of the v2 go-live runbook (#1804 §4). v1 publishes four separately
installable names, so each gets its own notice — a root-README-only change is
invisible to anyone who installed a sub-package. `cli/` and `server/` ship no
README at all, so for those two the runtime banner plus the forthcoming
`npm deprecate` (#1816) are the only notice their users ever get.
Notices, all using identical wording so the runtime banner and the npm warning
agree:
- root `README.md` and `client/README.md`
- `cli/src/cli.ts` — stderr banner in `main()`. Also covers the root
`mcp-inspector` bin, which is `cli/build/cli.js`. Deliberately **stderr**:
`--cli` mode emits JSON on stdout and callers pipe it, so a banner there
would corrupt output. Verified against a real server — stdout stays
parseable JSON while the banner goes to stderr.
- `server/src/index.ts` — alongside the existing proxy listening log
- `client/bin/start.js` — alongside the existing startup URL log
- `client/src/components/DeprecationBanner.tsx` — dismissible in-app banner,
dismissal persisted in localStorage with both read and write guarded so a
storage failure degrades to "banner reappears" rather than breaking the app
AGENTS.md is replaced with a hard stop: v1 takes security fixes only, by issue
only, and agents must never open a PR against v1/main.
Version bumped to 1.0.1 across all four package.json files plus the lockfile
(`npm run update-version`); `check-version` passes. The lockfile diff is
restricted to the version fields — the `libc` churn a newer npm wanted to
introduce was reverted as unrelated.
`publish-all` is deliberately NOT changed here: 1.0.1 must take `latest`, which
is the entire point of shipping this notice to npx users. Adding `--tag v1` is
#1816, immediately after this publishes.
Note for review: `client/src/App.tsx` shows ~836 changed lines but `git diff -w`
shows 8 — wrapping the layout in a flex column added one nesting level and
prettier re-indented the subtree. Review it with `-w`.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Txmv2qqv3yeKgRzoqXytzD
* docs: replace the README screenshot with one showing the deprecation banner
Captured from this branch's build: v1.0.1 in the sidebar heading, the
dismissible deprecation banner across the top, connected to the everything
server with tools listed.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Txmv2qqv3yeKgRzoqXytzD
* docs: pin the README screenshot to v1/main instead of main
The image URL must stay absolute — a relative path breaks on the npm package
page, which renders the README outside any repo context. But it was pinned to
`main`, so the v1 README rendered whatever `main` happened to hold: today the
pre-deprecation screenshot, and after the v2 tree swap (#1817) either the v2
screenshot or a 404 if that path doesn't exist there.
Pinning to `v1/main` keeps it absolute for npm, shows the deprecation banner
once this merges, and survives the swap. Verified all candidate refs resolve
200 — GitHub disambiguates the slash in `v1/main` as the ref without needing a
`refs/heads/` prefix.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Txmv2qqv3yeKgRzoqXytzD
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
npm does not reliably apply these transitive overrides to an existing
lockfile (bare and targeted overrides via install/update leave residual
vulnerable copies). This regenerates the lockfile from scratch with
version-targeted overrides so every copy of the affected packages
resolves to a patched version.
Resolves Dependabot alerts:
- esbuild #121 (-> 0.28.1)
- minimatch #69, #66, #61 (3.x -> 3.1.5)
- @babel/core #132 (-> 7.29.7; completes the partial fix from #1712)
Also pins js-yaml overrides (3.15.0 / 4.2.0) to prevent regression.
Supersedes #1713, #1714, #1715. Part of #1706.
Verified: 0 vulnerable copies across all advisories; build + client (535)
+ cli tests pass; lockfile internally consistent.
Claude-Session: https://claude.ai/code/session_01HiccCEh9mwCfVzE8qYcop1
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Bumps shell-quote from ^1.8.3 to ^1.8.4 in the root and server
packages to resolve a critical security advisory. Adds an npm
override so concurrency's pinned shell-quote@1.8.3 also resolves to
a patched version, leaving no vulnerable copy in the tree.
Claude-Session: https://claude.ai/code/session_01HiccCEh9mwCfVzE8qYcop1
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Bumps the client's vite dev dependency from ^7.1.11 to ^7.3.5 to
resolve Dependabot security alerts.
- #123 (HIGH): vite server.fs.deny bypass, patched in 7.3.5
- #129 (MEDIUM): vulnerability in launch-editor, a transitive dep of
vite; the newer vite no longer pulls in launch-editor, clearing it
Claude-Session: https://claude.ai/code/session_01HiccCEh9mwCfVzE8qYcop1
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Bumps vitest from ^4.0.17 to ^4.1.0 in the cli workspace to resolve
Dependabot alert #119 (CRITICAL). Resolves via vitest@4.1.10.
Claude-Session: https://claude.ai/code/session_01HiccCEh9mwCfVzE8qYcop1
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The "Check formatting" step in main.yml ran `npx prettier --check .`
before `npm install`, so npx fetched the LATEST prettier rather than the
version pinned in package-lock.json. This made the format check
non-deterministic and red on open PRs whenever the latest published
prettier differed from the pinned one.
- Pin prettier to exact 3.9.5 in devDependencies and update the lockfile
- Reformat the repo with the pinned prettier (expected source churn)
- Move the format check after `npm install --no-package-lock` and run it
via `npm run prettier-check` so CI uses the locally-installed pinned
prettier
Claude-Session: https://claude.ai/code/session_01HiccCEh9mwCfVzE8qYcop1
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Resolves 15 of 16 Dependabot alerts via lockfile-only updates (no
breaking major bumps): handlebars (critical), fast-uri, flatted, hono,
path-to-regexp, rollup, vite, express-rate-limit, @hono/node-server,
ajv, brace-expansion, ip-address, picomatch, postcss, qs, ws, yaml,
and @tootallnate/once.
The remaining minimatch@3.1.2 advisory comes from @eslint/config-array
(dev/lint-only, not shipped) and will clear when ESLint bumps it.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Updated all package.json files to version 0.20.0
- Updated workspace dependencies in root package.json
- Updated package-lock.json
- Verified version consistency with check-version-consistency script
Co-authored-by: Ola Hungerford <olaservo@users.noreply.github.com>
* Fix MCP Apps rendering issue and add comprehensive logging
- Fixed AppRenderer useEffect dependency array to include resourceContent
This ensures the component re-evaluates when resource content arrives
- Added detailed console logging throughout the app lifecycle:
* Resource fetch and response tracking in App.tsx
* Setup conditions and AppBridge creation in AppRenderer.tsx
* HTML parsing and iframe rendering steps
* PostMessageTransport and AppBridge connection status
* App tool filtering and selection in AppsTab.tsx
- Refactored AppsTab selectedTool rendering for better tracking
The issue was that resourceContent prop updates weren't triggering
the AppRenderer setup effect. Now the effect properly responds to
both resourceUri and resourceContent changes.
Co-authored-by: Cliff Hall <cliffhall@users.noreply.github.com>
* Fix MCP Apps iframe rendering issue
The app was getting stuck on 'Loading MCP App...' because the iframe was
hidden (display: none) until the oninitialized event fired. However, the
PostMessage handshake requires the iframe to be visible to complete.
This fix:
- Sets loading to false immediately after writing HTML to the iframe
- Makes the iframe visible before establishing PostMessage transport
- Allows the AppBridge initialization handshake to complete successfully
- Removes redundant setLoading(false) from oninitialized callback
The iframe is now visible and ready for PostMessage communication before
the AppBridge connect() call, enabling proper initialization.
Co-authored-by: Cliff Hall <cliffhall@users.noreply.github.com>
* Fix MCP Apps HTML extraction to match spec
The AppRenderer was incorrectly checking for a 'type' field in resource
contents, but TextResourceContents objects only have uri, mimeType, and
text fields according to the MCP specification.
Fixed by checking for the presence of the 'text' field directly instead
of checking a non-existent 'type' field. This allows the HTML content
to be properly extracted and rendered in the iframe.
Co-authored-by: Cliff Hall <cliffhall@users.noreply.github.com>
* Add comprehensive tests for MCP Apps support
- Add tests for AppsTab component (13 tests)
- Add tests for AppRenderer component (17 tests)
- Update jest.config.cjs to handle ES modules from @modelcontextprotocol/ext-apps
- All 478 tests pass successfully
Co-authored-by: Cliff Hall <cliffhall@users.noreply.github.com>
* Add MCP Apps support to Inspector
- Add AppsTab component for detecting and listing MCP apps
- Add AppRenderer component with full AppBridge integration
- Implement UI resource fetching and sandboxed iframe rendering
- Add PostMessage transport for bidirectional JSON-RPC communication
- Include comprehensive test coverage (30 new tests)
- Auto-populate apps when tab becomes active
- Support theme awareness and configurable permissions
Co-authored-by: Cliff Hall <cliffhall@users.noreply.github.com>
* Prefer structuredContent over content field in tool responses
Some MCP servers return different data in structuredContent vs content fields.
This change ensures that when structuredContent is present, it is used
exclusively for display instead of showing both fields.
Changes:
- Modified ToolResults.tsx to only show content when structuredContent is absent
- Removed unused checkContentCompatibility function
- Updated test cases to reflect new behavior
Co-authored-by: Cliff Hall <cliffhall@users.noreply.github.com>
* Revert "Prefer structuredContent over content field in tool responses"
This reverts commit 3b054b4da08517cce53ef23e60c07bb32b0fa8f5.
Claude did not do the right thing.
* feat: integrate @mcp-ui/client for MCP application rendering
This commit implements the integration of `@mcp-ui/client` to handle the
rendering of Model Context Protocol (MCP) applications within the inspector.
It includes refactoring the rendering logic, improving resource fetching
in the main application state, and setting up a secure sandbox environment.
Changes per file:
- client/package.json:
- Added `@mcp-ui/client` as a dependency.
- client/src/components/AppRenderer.tsx:
- Refactored to use `McpUiAppRenderer` from `@mcp-ui/client`.
- Implemented HTML parsing logic for MCP resource responses.
- Configured host context (theme) and sandbox URL for the renderer.
- Replaced iframe-based manual rendering with the official component.
- client/src/App.tsx:
- Added `fetchingResources` state to prevent duplicate concurrent resource requests.
- Enhanced `readResource` with better error handling and state tracking.
- Optimized resource content mapping to better support application state.
- client/src/components/AppsTab.tsx:
- Updated to use `getToolUiResourceUri` utility from `@modelcontextprotocol/ext-apps`
instead of manual metadata property access.
- Simplified tool filtering and selection logic.
- client/public/sandbox_proxy.html:
- Added a sandbox proxy page to facilitate secure communication between
the inspector and the rendered MCP applications.
- client/bin/client.js:
- Added server rewrites to ensure `sandbox_proxy.html` is served correctly.
- Implemented specific `Cache-Control` headers for `sandbox_proxy.html` to
prevent stale cached versions.
- client/vite.config.ts:
- Explicitly configured `publicDir: "public"` to ensure the sandbox proxy
is included in the build output.
- client/src/components/__tests__/AppRenderer.test.tsx:
- Updated tests to mock the new `@mcp-ui/client` component.
- Adjusted assertions to verify correct props are passed to the renderer.
- Enhanced mock MCP client to include required methods like `getServerCapabilities`.
* Potential fix for code scanning alert no. 37: Client-side cross-site scripting
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
* Update package-lock.json
- npm install
- npm audit fix
* Potential fix for code scanning alert no. 38: Client-side cross-site scripting
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
* Potential fix for code scanning alert no. 39: Client-side cross-site scripting
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
* prettier
* Update client/src/components/AppsTab.tsx
Co-authored-by: Ola Hungerford <olahungerford@gmail.com>
* prettier
* In AppsTab.test.tsx, fetch button by aria-label
* relative imports
* Remove sanitization logic from sandbox_proxy.html. It's breaking the app rendering. Will sort out what best practices for this HTML is later
* In sandbox_proxy.html,formatting
In AppsTab.tsx
- Add app window
- when an app is selected,
- show input form for apps that have an input schema
- button shows app
- if app is shown, show maximize button
- if maximized,
- show minimize button
- hide app list
* In AppsTab.test.tsx
- test new layout and controls
* In AppRenderer.tsx
- accept toolInput
- pass to McpUiAppRenderer
* In AppsTab.tsx, if an app has no inputSchema, just show it, otherwise show the form and the "back to form" button when showing the app.
* In AppsTab.test.tsx
- test new behavior
* In ListPane.tsx
- remove the Clear button
* In ListPane.test.tsx
- remove test for clear button
* In AppRenderer.tsx,
- remove onReadResource and resourceContent, not needed since mcpClient is being passed
* In App.tsx and AppsTab.tsx,
- remove the passing of these variables
* In AppRenderer.test.tsx, and AppsTab.test.tsx
- remove tests that fail after having removed onReadResource and resourceContent
* Serving the sandbox_proxy.html from a separate port, using the proxy instead of the webclient server.
* In App.tsx
- pass the path to the sandbox endpoint on the proxy to the AppsTab
* In AppsTab.tsx
- accept the sandboxPath property and pass it to the AppRenderer
* In AppRenderer.tsx
- accept the sandboxPath property and pass it to the McpUiAppRenderer
* In client.js
- remove the rewrite and header config for sandbox_proxy.html
* In server/src/index.ts
- add a /sandbox endpoint that reads and returns the sandbox_proxy.html file with no-cache header
* In server/package.json
- add shx for cross-platform copy function
- in build script, copy static folder to build folder
* Moved sandbox_proxy.html from client/public to server/static
* In client.js
- return to original state
* In vite.config.ts
- return to original state
* Potential fix for code scanning alert no. 41: Missing rate limiting
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
* In AppRenderer.tsx
- add open link handler that handles link requests from the UI. Makes sure that the URL starts with http or https
* In sandbox_proxy.html
- refactor to match [basic-host](https://github.com/modelcontextprotocol/ext-apps/tree/main/examples/basic-host) example
- creates an nested iframe for security.
- in this implementation, for simplicity the sandbox.ts is inlined in sandbox_proxy.html as javascript
* prettier
* In AppRenderer.tsx
- add support for handling McpUiMessageRequest messages from the UI
- show message in a toast
* Add logging message handler to AppRenderer
In App.tsx
- pass an onNotification function to the AppsTab that adds a notification to the notification array
In AppsTab.tsx
- Accept the onNotification function and pass it to the AppRenderer
In AppRenderer.tsx
- Accept the onNotification function
- added an handleLoggingMessage function that takes a LoggingMessageNotificationParams object, wraps it with a method and params prop to make it a ServerNotification shape, and pass it to the onNotification function
- pass handleLoggingMessage to McpUiAppRenderer
* In ResourcesTab.test.tsx
- fix @ import that wasn't resolving
* In AppRenderer.tsx
- remove fetch and evaluation of resourceUri, as the mcpClient handles that (review request)
* In AppRenderer.test.tsx
- remove test for no resourceUri found
* Merge branch 'main' into full-apps-support-final
Resolved Conflicts:
- package-lock.json
* Fixed mismatch with sanboxRateLimiter and the express version
---------
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Cliff Hall <cliffhall@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
Co-authored-by: Ola Hungerford <olahungerford@gmail.com>
* ### client/src/App.tsx
- Imports:
- Added: `Task` and `GetTaskResultSchema` to the same import block.
- UI Icons: Added `ListTodo` from `lucide-react` to the icon imports.
- Components: Added `TasksTab` import beside `ToolsTab`.
- Config utils: Added `getMCPTaskTtl` to the config utils import block.
- State additions:
- `const [tasks, setTasks] = useState<Task[]>([]);`
- Extended `errors` state to include a `tasks` key: `tasks: null,`
- `const [selectedTask, setSelectedTask] = useState<Task | null>(null);`
- `const [isPollingTask, setIsPollingTask] = useState(false);`
- `const [nextTaskCursor, setNextTaskCursor] = useState<string | undefined>();`
- Hook: `useConnection({...})` return value usage extended
- Added destructured functions: `cancelTask: cancelMcpTask` and `listTasks: listMcpTasks` from the custom hook.
- Notification handling:
- In `onNotification`, added:
- If `method === "notifications/tasks/list_changed"`, call `listTasks()` (voided).
- If `method === "notifications/tasks/status"`, treat `notification.params` as a `Task` and update `tasks` state: replace if exists by `taskId`, otherwise prepend. Also update `selectedTask` if it’s the same `taskId`.
- Tab routing:
- When computing valid tabs, added `tasks` when server declares capability: `...(serverCapabilities?.tasks ? ["tasks"] : []),`
- When choosing a default tab, added a branch to fall back to `"tasks"` if neither resources/prompts/tools are present but tasks are.
- Effect for Tasks tab:
- When `mcpClient` is connected and `activeTab === "tasks"`, invoke `listTasks()`.
- Tools → task-augmented calls integration in `callTool`:
- Parameter signature supports `runAsTask?: boolean` (already present in this file), but now:
- If `runAsTask` is true, augment the `tools/call` request’s `params` with a `task` object: `{ task: { ttl: getMCPTaskTtl(config) } }`.
- Use a permissive result schema for tool call: `sendMCPRequest(request, z.any(), "tools")` to avoid version-mismatch schema issues.
- Task reference detection introduced:
- `isTaskResult` helper checks for a nested `task` object with `taskId` (i.e., `response.task.taskId`).
- When task is detected:
- Set `isPollingTask(true)`.
- Immediately set a temporary `toolResult` that includes text content “Task created: … Polling for status…” and `_meta` with `"io.modelcontextprotocol/related-task": { taskId }`.
- Start a polling loop:
- Delay 1s between polls.
- Call `tasks/get` with `GetTaskResultSchema` for status.
- If status is `completed`: call `tasks/result` with `z.any()` to retrieve the final result and set it as `toolResult`; call `listTasks()`.
- If status is `failed` or `cancelled`: set an error `toolResult` content that includes the status + `statusMessage`; call `listTasks()`.
- Else (still running): update `toolResult` content with current `status`/`statusMessage` and preserve `_meta` related-task.
- After loop, set `isPollingTask(false)`.
- When not a task response, set `toolResult` directly from response (cast to `CompatibilityCallToolResult`).
- Tasks list + cancel helpers in App:
- `listTasks`: uses `listMcpTasks(nextTaskCursor)` from the hook, updates `tasks`, `nextTaskCursor`, and clears `errors.tasks`.
- `cancelTask`: calls `cancelMcpTask(taskId)`, updates `tasks` array by `taskId`, updates `selectedTask` if it matches, and clears `errors.tasks`.
- UI integration:
- Added a `TabsTrigger` for “Tasks” with `<ListTodo />` icon, disabled unless server supports tasks.
- Added `<TasksTab />` to the main `TabsContent` block, passing: `tasks`, `listTasks`, `clearTasks`, `cancelTask`, `selectedTask`, `setSelectedTask`, `error={errors.tasks}`, `nextCursor={nextTaskCursor}`.
- Passed `isPollingTask={isPollingTask}` and `toolResult` into `ToolsTab` so the Tools tab can show the live “Polling Task…” state and block reruns while polling.
Note: The raw diff is long; the key hunks align with the above bullet points (imports, state, notifications, tab wiring, request augmentation, polling loop, UI additions).
---
### client/src/components/ToolsTab.tsx
- Props shape changed:
- Added `isPollingTask?: boolean` prop in the destructured props and in the prop types.
- The `callTool` callback signature is now `(name, params, metadata?, runAsTask?) => Promise<void>` (runAsTask added earlier; test updates elsewhere reflect this).
- Local state additions:
- `const [runAsTask, setRunAsTask] = useState(false);`
- Reset behavior:
- When switching tools (`useEffect` on `selectedTool`), reset `runAsTask(false)`.
- When clearing the list in `ListPane.clearItems`, also call `setRunAsTask(false)`.
- UI additions:
- New checkbox control block to toggle “Run as task”:
- Checkbox `id="run-as-task"`, bound to `runAsTask`, with `onCheckedChange` → `setRunAsTask(checked)`.
- Label “Run as task”.
- Run button disabling conditions expanded to include `isPollingTask`.
- Run button text shows spinner with conditional label:
- If `isToolRunning || isPollingTask` → show spinner and text `isPollingTask ? "Polling Task..." : "Running..."`.
- Call invocation change:
- When clicking “Run Tool”, the `callTool` is invoked with `(selectedTool.name, params, metadata?, runAsTask)`.
- ToolResults relay:
- Passes `isPollingTask` to `<ToolResults />`.
---
### client/src/components/ToolResults.tsx
- Props shape changed:
- Added optional prop: `isPollingTask?: boolean`.
- Task-running banner logic:
- Extracts related task from the tool result’s `_meta["io.modelcontextprotocol/related-task"]` if present.
- Computes `isTaskRunning` as `isPollingTask ||` a text-heuristic against `structuredResult.content` entries that contain text like “Polling” or “Task status”.
- Header “Tool Result:” now conditionally shows:
- `Error` (red) if `isError` is true, else
- `Task Running` (yellow) if `isTaskRunning`, else
- `Success` (green).
No other changes to validation or rendering of content blocks.
---
### client/src/components/TasksTab.tsx (new file)
- A brand new tab to list and inspect tasks.
- Key elements:
- Imports `Task` type and multiple status icons.
- `TaskStatusIcon` component maps task `status` to an icon and color.
- Main `TasksTab` props: `tasks`, `listTasks`, `clearTasks`, `cancelTask`, `selectedTask`, `setSelectedTask`, `error`, `nextCursor`.
- Left column (`ListPane`): lists tasks, shows status icon, `taskId`, `status`, and last update time; button text changes to “List More Tasks” if `nextCursor` present; disables button if no cursor and list non-empty.
- Right column:
- Shows error `Alert` if `error` prop provided.
- If a task is selected: header with `Task Details`, a Cancel button when `status === "working"` (shows a spinner while cancelling), and a grid of task fields: Status (with colored label and icon), Last Updated, Created At, TTL (shows “Infinite” if `ttl === null`, otherwise shows numeric with `s` suffix), optional Status Message, and full task JSON via `JsonView`.
- If no task is selected: centered empty state with a “Refresh Tasks” button.
---
### client/src/lib/hooks/useConnection.ts
- Imports added from `@modelcontextprotocol/sdk/types.js`:
- `ListTasksResultSchema`, `CancelTaskResultSchema`, `TaskStatusNotificationSchema`.
- Client capabilities on `connect`:
- Added `tasks: { list: {}, cancel: {} }` into the `clientCapabilities` passed to `new Client(...)`.
- Notification handling setup:
- The hook’s notification schema registration now includes the `TaskStatusNotificationSchema` in the `setNotificationHandler` list so the app receives `notifications/tasks/status`.
- New hook functions:
- `cancelTask(taskId: string)` sends `tasks/cancel` with `CancelTaskResultSchema`.
- `listTasks(cursor?: string)` sends `tasks/list` with `ListTasksResultSchema`.
- Exports:
- Returned object now includes `cancelTask` and `listTasks`.
---
### client/src/utils/configUtils.ts
- Added a new getter:
- `export const getMCPTaskTtl = (config: InspectorConfig): number => { return config.MCP_TASK_TTL.value as number; };`
---
### client/src/lib/configurationTypes.ts
- `InspectorConfig` type extended with a new item:
- `MCP_TASK_TTL: ConfigItem;`
- Includes descriptive JSDoc about default TTL in milliseconds for newly created tasks.
---
### client/src/lib/constants.ts
- `DEFAULT_INSPECTOR_CONFIG` extended with a default for task TTL:
- Key: `MCP_TASK_TTL`
- Label: `"Task TTL"`
- Description: `"Default Time-to-Live (TTL) in milliseconds for newly created tasks"`
- Default `value: 60000`
- `is_session_item: false`
---
### client/src/components/__tests__/ToolsTab.test.tsx
- Expectations updated due to new `callTool` signature (4th arg `runAsTask`). Everywhere the test asserts a `callTool` invocation, an additional trailing `false` argument was added to reflect the default state when the box isn’t checked.
- Examples of added trailing `false` at various assertion points (line offsets from diff): after calls around prior lines 132, 157, 193, 236, 257, 279, 297, 818, 1082 (now passing 4 arguments: name, params, metadata-or-undefined, false).
---
### Additional notes
- The Tasks feature is wired end-to-end:
- Client capability declaration (list/cancel)
- Notification handler for `notifications/tasks/status`
- Tools call augmentation with `task` `{ ttl }`
- Polling loop using `tasks/get` and `tasks/result`
- UI feedback in Tools and dedicated Tasks tab
- Configurable TTL via new config item and getter
* Fix issue where displayed task on task tab was not updated when task completes, leaving the cancel task button available.
* Handle button the same when input_requred or working state
* ### What changed
- Added **receiver-side (client-side) Tasks support** to the Inspector client for task-augmented **server → client** requests.
- When the server sends `sampling/createMessage` or `elicitation/create` with `params.task`, the client now:
- Creates a local task and immediately returns a `CreateTaskResult` (`{ task: ... }`).
- Runs the underlying user-driven flow asynchronously.
- Updates task state to `completed` / `failed` and makes the final payload available via `tasks/result`.
- Implemented server polling handlers backed by the local task store:
- `tasks/get`
- `tasks/result` (blocks until payload is ready)
- `tasks/list`
- `tasks/cancel`
- Advertises task-augmented request capabilities via `capabilities.tasks.requests.sampling.createMessage` and `capabilities.tasks.requests.elicitation.create` when the corresponding callbacks are provided.
- Emits best-effort `notifications/tasks/status` updates as local task status changes.
* Fix review requests.
* In the ToolsTab, when a tool call results in an elicitation request, the app automatically switches to the elicitation tab, and once submitted, switches back to the ToolsTab to view the result of the tool call.
However, when a tool call results in a sampling request, it does not switch automatically to the SamplingTab and when the sampling request form is submitted it does not automatically switch back to the ToolsTab to view the result of the tool call.
These changes make the sampling use case work like the elicitation one. Tests were added.
- Updated version in root package.json
- Updated version in cli/package.json
- Updated version in client/package.json
- Updated version in server/package.json
- Updated workspace dependencies in root package.json
- Updated package-lock.json via npm install
Co-authored-by: Ola Hungerford <olaservo@users.noreply.github.com>
* Pinned server-everything, fixed all tests to work with current pinned version, fixed problem with undetected failures (isError: true payloads).
* First working vitest implementation
* Refactoring some single-use configs fixtures and into the refeencing tests
* No tests refere to server-everything (or any other server from a registry), all tests actually validate what they say they test.
* Removed server-everything dep from CI, minor cleanup
* Addressed Claude PR review comments: Added tsx dev dependency, beefed up process termination (possible leak on Windows), beefed up http server cleanup (close all connections), removed unused hasValidJsonOutput, reduced CLI timeout to give it breathing room with vitest timeout.
* Made both stdio and http test servers fully composable, cleaned up types, terminology, and usage.
Update @modelcontextprotocol/sdk from 1.24.3 to 1.25.2 to fix ReDoS
vulnerability (GHSA-8r9q-7v3j-jr4g) and qs to 6.14.1 to fix DoS
vulnerability (GHSA-6rw7-vpxm-498p).
🦉 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Version 0.17.3 had TypeScript build errors that prevented successful builds. This patch release fixes those errors and bumps the version to 0.17.4.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* In package.json under cli/, client/, server/ and /
- bump @modelcontextprotocol/sdk to ^1.20.1
* In client/package.json
- bump @vitejs/plugin-react to ^5.0.4
- bump vite to ^7.1.11
* In package-lock.json
- bump playwright to 1.56.1
- cascading changes to rollup and other dependencies
* In package.json under cli/, client/, server/ and /
- bump @modelcontextprotocol/sdk to ^1.20.1
* In client/package.json
- bump @vitejs/plugin-react to ^5.0.4
- bump vite to ^7.1.11
* In package-lock.json
- bump playwright to 1.56.1
- cascading changes to rollup and other dependencies
- New feature: Connection Type
- Reverts "fix: filter out client_secret when storing OAuth client information"
- Fixes STDIO "Headers is undefined" message when connecting to an SSE server.
- in createCustomFetch function
- convert finalHeaders to headers object for node-fetch compatibility
- for SSE streams, convert node stream to response body to web ReadableStream since EventSource polyfill expects web-compatible stream
* In package-lock.json and package.json
- add node-fetch as a dependency
This fixes#600