Commit graph inspector/client/src/lib
Author SHA1 Message Date
Cliff Hall
7ef0971c81
Add Tasks support (#1013)
* ### 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.
2026-01-22 21:40:59 -07:00
Cliff Hall
94ba4c3b56
* In useConnection.ts (#924)
- in connect()
    - Pass authProvider in transport options
2026-01-18 19:08:43 -07:00
Ahmet Soormally
2bf0dd1a03
fix: omit scope field in OAuth DCR when undefined and improve error handling (#1003)
fix: OAuth DCR scope field compliance

Omits the scope field entirely when undefined, per RFC 7591. This allows OAuth servers to assign default scopes instead of registering clients with no scopes.

Tested with Keycloak DCR.
2026-01-18 14:22:21 -07:00
Cliff Hall
8cb845798e
Merge branch 'main' into inspector/error-popup 2026-01-09 15:52:22 -05:00
cliffhall
f7bf100a65 Fix is401Error 2026-01-07 14:23:46 -05:00
Cliff Hall
04898cb5ce
Update client/src/lib/hooks/useConnection.ts 2026-01-07 14:16:22 -05:00
Cliff Hall
36a7244f86
Update client/src/lib/hooks/useConnection.ts
Adding fix for Via Proxy mode
2026-01-07 14:07:17 -05:00
thinhtpt-dev
e1886a8229 fix: detect 401 errors from StreamableHTTP transport in client 2026-01-06 14:00:13 +07:00
Cliff Hall
7b644f9f99
Merge branch 'main' into jesselumarie/test-SEP-974 2025-12-01 14:13:47 -05:00
evalstate
635a9a18f0 zod4 compatibility fixed for CI 2025-11-27 19:41:40 +00:00
Cliff Hall
35286a24c6
Merge branch 'main' into jesselumarie/test-SEP-974 2025-11-19 16:21:26 -05:00
lorenzo.neumann
c0b3b952f5 Merge branch 'main' of https://github.com/modelcontextprotocol/inspector into meta_properies_in_tools 2025-11-18 15:07:12 +01:00
Konstantin Konstantinov
a5d5593c97
Merge branch 'main' into meta_properies_in_tools 2025-11-15 01:34:22 +02:00
Vincent
6106b1b562 fix: Remove incorrect nested test 2025-11-13 14:30:28 -08:00
V
adb897f05b
Merge branch 'main' into fix/resolve-ref-pre-validation 2025-11-08 10:47:05 -08:00
Vincent
c1f18a8edd fix: add ref resolves def test 2025-11-08 10:46:28 -08:00
Vincent
12332932b0 fix: Modify test mock data 2025-11-08 09:57:48 -08:00
Vincent
8ad6253cd9 fix: Extract function to utils 2025-11-04 09:31:31 -08:00
Vincent
b000fc25bb fix: Remove redundant type 2025-11-04 09:24:54 -08:00
Vincent
2ab7d625e4 Resolve ref before validation 2025-11-04 07:44:06 -08:00
lorenzo.neumann
8f28ea791b Aligned naming 2025-10-27 12:22:49 +01:00
Cliff Hall
99120937e2
Merge branch 'main' into fix/set-scope-dcr 2025-10-24 17:25:13 -04:00
lorenzo.neumann
caa1a2e1f5 Merge remote-tracking branch 'origin2/main' into meta_properies_in_tools 2025-10-24 15:04:38 +02:00
lorenzo.neumann
809436d65c Added metadata cli tests, renaming 2025-10-24 14:37:22 +02:00
Stanislav Deviatykh
3b247ea21f mock clearScopeFromSessionStorage 2025-10-22 00:11:58 +03:00
Stanislav Deviatykh
eb76696d97 correctly clear scope 2025-10-22 00:09:57 +03:00
Jesse Lumarie
9dc3b748a8 mcp: add icons 2025-10-18 20:42:46 -06:00
Cliff Hall
68788fcdae
Merge branch 'main' into inspector/error-popup 2025-10-18 14:49:40 -04:00
Basil Hosmer
d6b179e6a8
Increase default request timeout to 5 minutes
- Changed MCP_SERVER_REQUEST_TIMEOUT from 10s to 5m (300000ms)
- Supports elicitation tools and other long-running operations
- Updated documentation to clarify client-side vs server-side timeouts
- Users can still customize via UI config or URL parameters
2025-10-16 17:13:14 -04:00
Stanislav Deviatykh
40fa6cb27d refactor test 2025-10-16 00:57:06 +03:00
Stanislav Deviatykh
c2dbff738e fix: set user specified scope in DCR 2025-10-16 00:50:42 +03:00
John Howard
0b569f2fff Move under else 2025-10-13 08:22:15 -07:00
John Howard
2bfbdca485 Add a toast on connection error
When failing to connect to an MCP server, its very hard to understand
why. There is only an opaque "Connection Error" message with no
additional info. This also doesn't change at all on repeated attempts,
so there is no indication we attempted again and failed.

This change introduces a `toast` to visualize the error, and adds the
`cause` into the error message for further debugging
2025-10-13 08:22:15 -07:00
cliffhall
eda547ee7b Fix duplicate OAuth redirect URIs
* In auth.ts
  - add getter for redirect_uris which returns redirectUrl and debugRedirectUrl but de-duped
  - included comments that explains the problem and link to issue
  - in clientMetadata getter,
    - replace hardcoded array value with this..redirect_uris, so it will never contain duplicate uris

Fixes #825
2025-10-11 14:35:47 -04:00
Ola Hungerford
f013291f34
Merge pull request #858 from cliffhall/fix-lint
Fix linter complaints
2025-10-10 19:08:26 -07:00
crondinini-ant
bc1ca95aea
add client secret option 2025-10-10 18:21:34 +01:00
cliffhall
4e90143071 Fix linter complaints
* In JsonView.tsx
  - add setCopied to dependencies of handleCopy useCallback
* In useCopy.ts
  - add timeout to useEffect inside useCopy hook
2025-10-10 11:45:18 -04:00
lorenzo.neumann
842aa3c8ca Added general meta data section to add pairs for all requests 2025-10-02 11:23:29 +02:00
Cliff Hall
5b4edefbc7
Update client/src/lib/hooks/useConnection.ts 2025-09-30 19:06:19 -04:00
Kent C. Dodds
34534ed062 fix: update default authorization header to include empty Bearer token and improve validation logic 2025-09-30 15:17:13 -06:00
Kent C. Dodds
0da5bc2a2e refactor: streamline authorization header validation in useConnection hook 2025-09-26 13:26:46 -06:00
Kent C. Dodds
30f9855fd5 fix: update authorization header handling to prevent empty values and show validation error 2025-09-26 13:24:28 -06:00
Kent C. Dodds
17ace55bbf fix: enhance OAuth token handling in useConnection hook to prevent infinite auth loops 2025-09-25 15:29:26 -06:00
Paul Carleton
b72e3c1233
Revert "fix: filter out client_secret when storing OAuth client information"
This reverts commit 36b9acc97e.
2025-09-24 15:12:52 +01:00
Ola Hungerford
32ea112051
Merge branch 'main' into accurate-cli-version 2025-09-22 20:46:14 -07:00
Cliff Hall
05534ca430
Merge branch 'main' into no-proxy-for-http-transports 2025-09-18 16:36:37 -04:00
Ola Hungerford
81889e680d
Merge pull request #801 from modelcontextprotocol/basil/fix-oauth-redirect-uri-mismatch
Fix OAuth redirect URI mismatch in debug flow
2025-09-16 17:56:14 -07:00
cliffhall
5ef78470de * In App.tsx
- Add state for connectionType
  - Fetch connectionType from localstorage if present

* In Sidebar.tsx
  - Add dropdown for connectionType, only visible if transport type is not stdio

* In Sidebar.test.tsx
  - set connectionType to "proxy"

* In useConnection.ts
  - add connectionType param, defaulting to "proxy"
  - add state for mcpSessionId
  - Only check proxy health if the connection type is proxy
  - create a serverUrl variable which will either be the proxy url OR the server url depending upon the connection type
  - added captureResponseHeaders function to extract the protocol-related headers from a response.
  - when creating transport options and connectionType is "direct" and transportType is not "stdio",
    - add the appropriate `Accept` and `Content-Type` headers
    - capture the protocol related response headers and store them in the custom fetch handler
    - set serverUrl to be the server url, not the proxy url
  - if connection type is proxy set serverUrl to the mcpProxyUrl
  - use serverUrl instead of mcpProxyUrl for the  transport instantiation
* In useConnection.test.tsx
  - replaced test "sends X-MCP-Proxy-Auth header when proxy auth token is configured" with two tests:
    - "sends X-MCP-Proxy-Auth header when proxy auth token is configured for 'proxy' connectionType"
    - "does NOT send X-MCP-Proxy-Auth header when proxy auth token is configured for 'direct' connectionType"
   - added Connection URL Verification section with 2 tests
     - uses server URL directly when connectionType is 'direct'"
     - "uses proxy server URL when connectionType is 'proxy'"
2025-09-16 17:26:29 -04:00
jeetul.samaiya
e08ce8cee9 feat: add default Authorization Bearer header and clean up legacy auth
- Provide "Authorization: Bearer " as default starting header
- Remove legacy auth props from components
- Centralize migration logic and fix localStorage cleanup
- Update tests for new auth architecture
2025-09-15 20:19:56 +05:30
Jeetul Samaiya
f36c649bb9
Merge branch 'main' into main 2025-09-15 19:30:18 +05:30