Files
mcp-use__mcp-use/.github/workflows/inspector-e2e.yml
Enrico Toniato b76df332f6 Canary (#1218)
* ci: enhance CI workflow with tunnel testing for dev and start commands

- Added new jobs to test the development and start commands with the `--tunnel` flag in the CI workflow.
- Implemented logic to start the dev server and poll for the tunnel URL, ensuring it is generated successfully.
- Included cleanup steps to terminate the server processes after testing.
- Enhanced error handling to report if the tunnel URL is not found in the output logs.

* docs: fix changelog order (newest first)

* chore: move tunnel testing from create-mcp-use-app CI to inspector E2E

- Remove tunnel steps from create-mcp-use-app-tests (dev --tunnel, start --tunnel)
- Add run-tunnel-test.mjs (test_tunnel) in inspector E2E scripts
- Add test:e2e:tunnel script and inspector-e2e-tunnel job

* chore: enter canary prerelease mode

* fix: prettier format run-tunnel-test.mjs

* feat: add reconnection options to conformance client (#1212)

* feat: add reconnection options to conformance client

- Introduced `reconnectionOptions` with a `maxRetries` setting to enhance the conformance client’s ability to handle connection issues.

* fix(tests): update prompt server path in test configuration

- Modified the test configuration to use the correct path for the prompt server, ensuring that the tests can locate and execute the server script properly.

* chore(typescript): version packages (canary)

* chore: update dependencies to Vite 8.0.0 and @vitejs/plugin-react 6.0.0 (#1209)

* chore: update dependencies to Vite 8.0.0 and @vitejs/plugin-react 6.0.0

- Bumped Vite version from ^7.3.0 to ^8.0.0 across multiple package.json files.
- Updated @vitejs/plugin-react from ^5.1.4 to ^6.0.0 in various templates and packages.
- Adjusted pnpm-lock.yaml to reflect these changes.
- Modified build configurations to use 'rolldownOptions' instead of 'rollupOptions' for consistency.

* fix: ensure consistent handling of TypeScript file paths across platforms

- Updated path handling in TypeScript-related functions to ensure compatibility with Windows and other operating systems.
- Refactored code to utilize `path.join` for constructing file paths, addressing issues with path separators.
- Enhanced error handling in CLI tests to prevent failures due to missing build artifacts.

* fix: prettier format run-tunnel-test.mjs

* chore: update dependency versions in pnpm-lock.yaml and package.json

- Changed the version specifier for `ai` from `^6.0.116` to `>=5.0.52`.
- Updated `express-rate-limit` from `^7.5.1` to `>=8.2.2` in both `pnpm-lock.yaml` and `package.json`.
- Adjusted the corresponding version in the lock file to reflect the new version of `express-rate-limit`.

* test: enhance telemetry test stability with increased wait times

- Updated `beforeEach` to include a delay for settling lingering telemetry.
- Increased wait times from 100ms to 500ms in multiple test cases to ensure telemetry events are captured reliably.

* chore(typescript): version packages (canary)

* Feat/use-files (#1213)

* feat(react): add useFiles hook with isSupported detection

Adds useFiles() hook for file upload and download in widgets.

File operations are only supported in the ChatGPT Apps SDK environment.
The MCP Apps spec (SEP-1865) has deferred file handling, meaning MCP Apps
clients (Claude, Goose, VS Code) do not support file operations.

The hook exposes an isSupported flag computed from the presence of
window.openai.uploadFile and window.openai.getFileDownloadUrl, letting
widgets render graceful fallback UI in non-ChatGPT environments rather
than throwing runtime errors.

- isSupported: true only in ChatGPT Apps SDK hosts
- upload(file): delegates to window.openai.uploadFile, returns FileMetadata
- getDownloadUrl(file): delegates to window.openai.getFileDownloadUrl
- Both throw a descriptive error when called with isSupported === false

Also adds:
- FileMetadata type ({ fileId: string }) in widget-types.ts
- Optional uploadFile/getFileDownloadUrl on the API interface
- examples/server/ui/files/ — file manager widget with upload, progress
  state, download URL retrieval, and isSupported-based fallback notice
- docs/typescript/server/widget-components/usefiles.mdx — API reference
  with isSupported usage, FileMetadata type, and error handling guidance

* feat(react): add modelVisible option to useFiles and unit tests

Adds model visibility control to useFiles().upload() and 19 unit tests
verifying the full hook behaviour.

### modelVisible option

By default, uploaded files are tracked in widget state under `imageIds`
so ChatGPT includes them in the model's conversation context (matching
the post-fix behaviour of Skybridge PR #539 which fixed privateContent
not being preserved during setWidgetState).

Pass `{ modelVisible: false }` to upload privately — the file is still
uploaded via window.openai.uploadFile but the fileId is not added to
imageIds, so the model won't see it.

```ts
// Model sees this (default)
const { fileId } = await upload(file);

// Model does not see this
const { fileId } = await upload(file, { modelVisible: false });
```

Existing imageIds and other widgetState fields are preserved when
tracking a new fileId, so uploads never wipe non-file state.

### Tests (19)

- isSupported: false when window/openai undefined or partial
- upload() error when not supported (message includes isSupported)
- upload() delegates to window.openai.uploadFile
- upload() returns FileMetadata
- upload() calls setWidgetState with updated imageIds
- upload() appends to existing imageIds
- upload() preserves other widgetState fields
- upload({ modelVisible: false }) skips setWidgetState entirely
- upload({ modelVisible: false }) still returns FileMetadata
- getDownloadUrl() error when not supported
- getDownloadUrl() delegates to window.openai.getFileDownloadUrl
- getDownloadUrl() passes through fileId

* docs(skill): add files reference to mcp-apps-builder skill

Adds references/widgets/files.md covering:
- useFiles() hook (isSupported, upload, getDownloadUrl)
- isSupported guard pattern — always required, renders fallback in MCP Apps
- Model visibility: modelVisible option (true = tracked in imageIds, false = private)
- Storing fileId in widget state vs caching download URLs
- Error handling patterns

Also adds a navigation entry and decision tree node to SKILL.md.

* chore(typescript): version packages (canary)

* feat(mcp-use): add MCP operation-level middleware support (#1137)

- Introduced a new middleware system for handling MCP operations, allowing for cross-cutting concerns like logging and authentication.
- Updated `MCPServerClass` to register and manage middleware entries dynamically.
- Enhanced documentation to include examples of using `server.use('mcp:...', handler)` for middleware registration.
- Added new types and utility functions to support middleware composition and context management.

This commit enhances the flexibility and functionality of the MCP framework by enabling developers to define custom middleware for various MCP operations.

* chore(typescript): version packages (canary)

* Feat/model-context (#1214)

* feat(react): add ModelContext component and modelContext imperative API

Adds two complementary APIs for annotating widget UI with contextual
descriptions the AI model can see, without requiring explicit tool calls
or storing data in developer-managed state.

- <ModelContext content="..."> — lifecycle-tied React component that
  participates in a parent-child tree via React context (useId +
  ParentIdContext). Supports empty children (leaf nodes) and nesting.
- modelContext.set(key, content) / .remove(key) / .clear() — module-level
  imperative API that works anywhere: event handlers, plain functions,
  outside React. Entries are always root-level nodes.

Both APIs feed into a shared global registry that serializes the node tree
into an indented markdown-like string on every change (batched via
queueMicrotask). The string is pushed to the host via:
- MCP Apps: ui/update-model-context (structuredContent.__model_context)
- ChatGPT Apps SDK: setWidgetState (__model_context merged into state)

useWidget wires up a registerModelContextFlush handler on mount so
annotations always reach the correct protocol channel. __model_context
is filtered from the developer-facing state value returned by useWidget.
setState preserves existing __model_context to prevent annotations from
being wiped on state updates.

Also adds:
- examples/server/ui/model-context/ — interactive product browser example
  demonstrating nesting (<ModelContext>) and imperative (modelContext.set)
  usage with a visual context debug panel
- docs/typescript/server/widget-components/modelcontext.mdx — API reference
  for both APIs, nesting behavior, serialization format, and comparison
  with setState

* test(react): add model-context unit tests; expose test helpers

Adds 25 unit tests covering the full ModelContext system:
- Tree serialization: empty, single, multiple root entries, nesting,
  whitespace trimming, blank content skipped, upsert, remove, clear
- modelContext imperative API: set/remove/clear, no-op on missing key
- registerModelContextFlush: immediate notification on registration,
  deregistration stops calls, deregistering stale handler is safe
- Batched flush: multiple synchronous mutations → single handler call
- Context state passed to model: full integration of set + flush handler,
  update, remove, clear sequences

Also exposes two @internal helpers required for testing module singletons:
- _resetModelContextForTesting() — resets nodes/handler/flushScheduled
- _getDescriptionForTesting() — returns the current serialized string
  without triggering a flush

* docs(skill): add model-context reference to mcp-apps-builder skill

Adds references/widgets/model-context.md covering:
- When to use ModelContext vs setState
- <ModelContext> component: nesting, siblings, leaf nodes, lifecycle
- modelContext imperative API: set/remove/clear, cleanup rules
- How the tree is serialized and sent to the model
- Common patterns: tab-switching, selected item, multi-level dashboard

Also adds a navigation entry and decision tree node to SKILL.md.

* Update title in modelcontext.mdx

Signed-off-by: Enrico Toniato <2827496+tonxxd@users.noreply.github.com>

* chore: add changeset for useFiles and ModelContext minor features

---------

Signed-off-by: Enrico Toniato <2827496+tonxxd@users.noreply.github.com>

* chore(typescript): version packages (canary)

* fix: prefix resource and prompt tool names to avoid collisions (#937)

* fix: prefix resource and prompt tool names to avoid collisions (#910)

When a resource and a prompt share the same name, the LangChain tools
array sent to the API contains duplicate tool names, causing a 400 error.
Prefix resource tools with `resource_` and prompt tools with `prompt_`
to ensure unique names.

* dynamic implementation to avoid prompt resource names collisions

* fix: make reserveName collision-safe and sanitize prompt names

- reserveName now checks the prefixed name for conflicts too, falling
  back to a numeric suffix when both base and prefixed names are taken.
  Previously a tool named resource_foo alongside a resource named foo
  would silently produce a duplicate tool name.
- Prompt names are now sanitized through sanitizeToolName() for
  consistency with resource names.

* chore: add changeset for tool name collision fix

---------

Co-authored-by: Enrico Toniato <2827496+tonxxd@users.noreply.github.com>

* chore(typescript): version packages (canary)

* fix: map elicit result content to data for Zod validation (#1215) (#1216)

* fix: map elicit result content to data for Zod validation

The MCP SDK returns form data in result.content per the elicitation spec,
but createElicitMethod was checking result.data which is always undefined.
This caused Zod validation to never run, leaving result.data as undefined
for tool callbacks that use ctx.elicit() with a Zod schema.

Now checks result.content (SDK spec) with fallback to result.data for
backward compatibility with custom handlers.

Fixes #1215

* fix: also fix inspector and tests for elicit content/data mapping

- Inspector: send `content` instead of `data` per MCP spec
- Server: also map `content` to `data` for non-Zod-schema elicit calls
  (verbose API overload), so conformance server tools work correctly
- Tests: update all integration test mocks to use spec-correct `content`
  field instead of non-standard `data`, and adjust validation error
  assertions to match SDK-level schema validation
- Add changeset

Follows up on the initial fix in b90ea51e.

---------

Co-authored-by: Enrico Toniato <2827496+tonxxd@users.noreply.github.com>

* chore(typescript): version packages (canary)

* feat(inspector): implement tunnel management functionality (#1222)

- Added API endpoints for starting, stopping, and checking the status of a tunnel.
- Integrated tunnel management into the Layout and LayoutHeader components, allowing users to start and stop tunnels directly from the UI.
- Updated context to manage tunnel state, including a loading state for starting the tunnel.
- Enhanced the user experience with visual feedback during tunnel operations and added instructions for using the tunnel URL in ChatGPT.

This feature improves the overall functionality of the inspector by enabling real-time tunnel management.

* chore(typescript): version packages (canary)

* chore(changelog): update changelog for v0.25.0 and v1.22.0 releases

- Added details for v0.25.0: introduced tunnel management for `mcp-use dev`, Vite 8 build stack, and aligned elicit payload with MCP spec.
- Updated v1.22.0: included enhancements for MCP middleware, new React hooks, and fixes for elicit and adapter functionalities.
- Updated dependencies for both releases.

* fix(tests): update server-telemetry test to mock startServer return value

- Modified the mock implementation of startServer to return an object containing close and forceClose functions, ensuring proper handling in tests.
- This change prevents actual server startup during tests while maintaining the expected interface.

---------

Signed-off-by: Enrico Toniato <2827496+tonxxd@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Gab <86735558+gabrielekarra@users.noreply.github.com>
Co-authored-by: guoyangzhen <upgyz@qq.com>
2026-03-23 13:09:28 +01:00

144 lines
4.5 KiB
YAML

name: Inspector E2E Tests
permissions:
contents: read
# ============================================================================
# Inspector E2E Tests
# ============================================================================
#
# Runs Playwright E2E tests for the Inspector package across all test modes:
# - mix: Built server :3002, dev inspector :3000 (most common dev setup)
# - prod: Built server :3002, built inspector :3000 (production simulation)
# - builtin: Dev server with built-in inspector :3000 (HMR tests)
#
# Triggered on:
# - PRs from canary to main (runs all 3 modes for release validation)
# - Manual dispatch (can run all modes or a single mode)
#
on:
pull_request:
branches: [main]
# Only run on PRs coming from canary branch
# This catches release PRs before they merge to main
workflow_dispatch:
inputs:
test_mode:
description: "Test mode (all runs matrix, or pick one)"
required: false
default: "all"
type: choice
options:
- all
- mix
- prod
- builtin
jobs:
inspector-e2e:
name: "Inspector E2E (${{ matrix.mode }})"
runs-on: ubuntu-latest
# Disabled: set to false to skip without deleting the workflow. Re-enable by restoring:
# if: github.event_name == 'workflow_dispatch' || github.head_ref == 'canary'
if: false
strategy:
fail-fast: true
matrix:
# Run all modes for comprehensive testing (or single mode for manual dispatch)
# - mix: Built server :3002, dev inspector :3000 (most common dev setup)
# - prod: Built server :3002, built inspector :3000 (production simulation)
# - builtin: Dev server with built-in inspector :3000 (HMR tests)
mode: ${{ github.event.inputs.test_mode == 'all' || github.event.inputs.test_mode == '' && fromJson('["mix", "prod", "builtin"]') || fromJson(format('["{0}"]', github.event.inputs.test_mode)) }}
defaults:
run:
working-directory: libraries/typescript
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup pnpm
uses: pnpm/action-setup@v3
with:
version: 10.6.1
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 22
cache: "pnpm"
cache-dependency-path: libraries/typescript/pnpm-lock.yaml
- name: Install Dependencies
run: pnpm install --no-frozen-lockfile
- name: Build Packages
run: pnpm build
- name: Link CLI Binaries
# After build, CLI binaries exist - re-run install to create symlinks
run: pnpm install --frozen-lockfile
- name: Install Playwright Browsers
run: pnpm --filter @mcp-use/inspector exec playwright install --with-deps chromium
- name: Run E2E Tests (${{ matrix.mode }} mode)
env:
MCP_USE_ANONYMIZED_TELEMETRY: "false"
NODE_ENV: test
run: |
cd packages/inspector
node tests/e2e/scripts/run-test-matrix.mjs ${{ matrix.mode }}
- name: Upload Playwright Report
uses: actions/upload-artifact@v4
if: always()
with:
name: playwright-report-${{ matrix.mode }}
path: libraries/typescript/packages/inspector/playwright-report/
retention-days: 30
- name: Upload Test Results
uses: actions/upload-artifact@v4
if: always()
with:
name: test-results-${{ matrix.mode }}
path: libraries/typescript/packages/inspector/test-results/
retention-days: 7
inspector-e2e-tunnel:
name: "Inspector E2E (tunnel)"
runs-on: ubuntu-latest
# Disabled: set to false to skip without deleting the workflow. Re-enable by restoring:
# if: github.event_name == 'workflow_dispatch' || github.head_ref == 'canary'
if: false
defaults:
run:
working-directory: libraries/typescript
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup pnpm
uses: pnpm/action-setup@v3
with:
version: 10.6.1
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 22
cache: "pnpm"
cache-dependency-path: libraries/typescript/pnpm-lock.yaml
- name: Install Dependencies
run: pnpm install --no-frozen-lockfile
- name: Build Packages
run: pnpm build
- name: Run tunnel E2E test (test_tunnel)
env:
MCP_USE_ANONYMIZED_TELEMETRY: "false"
run: pnpm --filter @mcp-use/inspector test:e2e:tunnel