qwen-code/docs/users/features
Shaojin Wen e5c01aa353
feat(mcp): support MCP resources and reliably surface prompts (#5544)
* feat(mcp): support MCP resources and reliably surface prompts

Prompts were silently hidden for MCP servers that implement `prompts/list`
but under-declare the `prompts` capability in their initialize response.
Drop the capability gate in `listMcpPrompts` (and apply the same leniency to
resources): always attempt the list call and swallow `Method not found`, so
those prompts now appear as `/` slash commands like in other clients.

Add first-class MCP resource support:

- core: `listMcpResources` / `discoverResources`, a `DiscoveredMCPResource`
  type, a `ResourceRegistry`, and `Config.getResourceRegistry()`. Discovery
  is wired into the standalone `McpClient.discover()` path and the
  connection-pool path (snapshot -> `SessionMcpView.applyResources` -> the
  session's registry, with a `resourcesChanged` event on reconnect). A
  resource-only server now counts as a successful discovery.
- cli: the `/mcp` dialog shows per-server Resources (and Prompts) counts.
- cli: `@server:uri` reads an MCP resource and injects its contents into the
  message (text inline, blobs as inlineData); `@server:` autocompletes the
  server's resource URIs. The `server` prefix must match a configured MCP
  server, so existing `@path` file references are unaffected.

Docs updated; unit tests added across core and cli.

* fix(mcp): reload commands on discovery + harden resource ref parsing

Address review feedback and complete the prompt UX:

- Slash commands now rebuild when an MCP server finishes connecting.
  Discovery is progressive (runs after the UI is interactive), so prompts
  a server exposes via prompts/list were registered too late to appear in
  the `/` menu — the `/mcp` dialog showed the count while the slash menu
  stayed empty. A debounced MCP-status listener now reloads the command
  tree on connect. Verified end-to-end in a real TUI against a mock server
  that under-declares the prompts capability: `/greet` now lists.
- `isMethodNotFound` keys off the JSON-RPC `-32601` code rather than the
  server-supplied message text (which may be localized or worded
  differently); applied to both `listMcpPrompts` and `listMcpResources`.
- `useAtCompletion` uses `Object.hasOwn` so `@__proto__:` / `@constructor:`
  and other inherited keys are not mistaken for configured servers.

* fix(mcp): lenient resource read to match discovery + review polish

- `McpClient.readResource` no longer prechecks `getServerCapabilities()
  ?.resources`. This PR is the first caller to make the read path
  reachable, and the strict precheck meant a server that answers
  `resources/read` but under-declares the `resources` capability — exactly
  the servers the lenient `listMcpResources` discovery targets — would get
  its resources discovered, listed in `/mcp`, and autocompleted, yet fail
  every `@server:uri` with a misleading "does not support resources". The
  read now matches discovery; a server that truly lacks resources answers
  `-32601`, surfaced as the existing error card. Added a regression test.
- `@server:uri` success cards now report what was injected ("Injected N
  chars" / "N attachments") or "(no readable content)" when a read yields
  no text/blob parts, so a partially-empty multi-ref read isn't hidden.
- `useAtCompletion` resource filter reduced to a single `includes` match
  (`startsWith` was subsumed; empty partial matches all via `includes('')`);
  the overstated "prefers prefix" comment is corrected.
- Tests: mixed `@file` + `@server:uri` injection (both parts + both cards),
  empty-content card, and the pool restart fan-out now asserts
  `applyResources` alongside `applyTools`.

* perf+security(mcp): parallelize discovery/reads, cap & frame resources

Review round 3 fold-ins:

- Discovery now runs `listMcpPrompts` / `listMcpResources` / `discoverTools`
  concurrently in `discoverAndReturn` (independent reads; the SDK client
  multiplexes by JSON-RPC id), saving per-server round-trips at startup.
- `@server:uri` resource reads run in parallel (`Promise.allSettled`) instead
  of serially, matching how the file path batches via `readManyFiles`; order
  is preserved so cards/labels line up with refs.
- Resource injection is now capped and framed: text is bounded by
  `MAX_MCP_RESOURCE_TEXT_CHARS` (100k) and oversized blobs are skipped, so a
  misbehaving/hostile server can't overflow the context window or OOM; the
  content is fenced with `--- Content from MCP resource <label> ---` /
  `--- End ---` delimiters so the model can separate untrusted server output
  from the user's prompt. The success card reports truncation.
- File-read error path now merges `resourceLabels` into `filesRead` /
  recording, so a resource read that succeeded before a file read failed is
  not dropped from the audit trail.
- `isMethodNotFound` (JSON-RPC -32601) now also covers `discoverTools` and
  `invokeMcpPrompt`, replacing the remaining message-substring checks.
- `PoolEntry.markActive` `initialResources` is now required (no `= []`
  default), removing a footgun where an omitted arg would wipe a server's
  resources via `applyResources([])`.
- `useAtCompletion` resource suggestions rank prefix matches above mid-string
  matches.
- `'Resources:'` added to the remaining 6 locales (ca, de, fr, ja, pt, ru)
  for parity with `'Prompts:'`.

Tests: attribution framing, text truncation, completion prefix ranking.

* test(mcp): cover resource registration in discover() and resource-only discovery

Closes the two coverage gaps flagged in review: assert discover() registers
discovered resources into the Config ResourceRegistry, and that a resource-only
server (no tools/prompts) is a successful discovery rather than throwing.

* fix(mcp): idempotent resource re-discovery + cumulative blob cap

Review round 4 (all Suggestions):
- discover() now clears a server's resources (removeResourcesByServer) before
  re-registering, so reconnect / incremental re-discovery is idempotent and a
  resource the server dropped doesn't linger in the registry (matches the
  pool path's SessionMcpView.applyResources).
- @server:uri injection now caps CUMULATIVE blob size per resource, not just
  each blob, so many sub-limit blobs in one response can't inject unbounded
  data. Added a test for the oversized-blob skip + card.
- Documented that file/resource content parts are grouped by type (model
  correlates by delimiter labels, not position).

* test(mcp): cover the MCP-status command reload (prompts surfacing in /)

Adds the missing coverage for the discovery-driven reload: a CONNECTED status
fires the listener and rebuilds the command tree (so progressively-discovered
MCP prompts appear as / commands), and a non-CONNECTED status does not.

* fix(mcp): don't wipe resources when resources/list transiently fails

- discover() only clears + replaces a server's resources when listMcpResources
  returns a non-empty set. Because that helper swallows all errors (including
  transient network failures) and returns [], an unconditional clear-then-
  register would silently purge a server's resources on a transient list
  failure while tools/prompts succeed. Guarding on length>0 keeps the existing
  set on failure; a real partial drop still re-registers the fresh set.
- Resource success card now shows '(truncated)' for capped/skipped blobs too,
  not just text. Added a cumulative-blob-cap test (two sub-limit blobs whose
  sum exceeds the cap).

* fix(mcp): guard pool applyResources against transient-failure wipe too

The non-pool discover() guard (resources.length > 0) left the pool path
exposed: on a restart, doRestart -> discoverAndReturn swallows a transient
resources/list failure to [], and applyResources([]) then wiped the session's
resources. applyResources is now a no-op on an empty snapshot (mirrors the
discover() guard; applyTools/applyPrompts keep their pre-existing clear-on-empty
behavior, out of scope). Added tests: applyResources([]) does not clear, and
discover() with an empty resource list does not call removeResourcesByServer.

* fix(mcp): preserve pool resource snapshot on transient restart failure

The applyResources([]) no-op only protected already-attached sessions; doRestart
still overwrote the pool entry's resourcesSnapshot with [] when the restart's
resources/list transiently failed, so any session attaching AFTER the restart
got zero resources. doRestart now only updates resourcesSnapshot when the
re-read is non-empty, preserving it for new and existing subscribers alike.
Tests: applyResources([]) preserves a pre-populated set; a restart whose
resources/list comes back empty still serves the prior resource to a new
session.

* fix(mcp): trust-gate resource completion, colon server names, narrower method-not-found

- useAtCompletion no longer surfaces resource URIs in an untrusted folder
  (the read path is already blocked there); avoids leaking resource existence.
- parseMcpResourceRef / getMcpResourceSuggestions match the LONGEST configured
  server name as a '<name>:' prefix instead of splitting on the first colon,
  so a server whose name contains ':' (a valid settings.json key) resolves.
- isMethodNotFound's message fallback is back to the case-sensitive exact
  'Method not found' substring (the -32601 code is the primary check), not a
  broad /method not found/i that would swallow unrelated errors.
Tests: @my:server:uri resolution, untrusted-folder completion.

* refactor(mcp): extract shared longest-prefix server matcher + doc/test fixes

- Extract matchMcpServerPrefix (new mcpResourceRef.ts) and use it from both
  parseMcpResourceRef (injection) and getMcpResourceSuggestions (completion),
  removing the duplicated longest-prefix logic and its drift risk.
- Update parseMcpResourceRef JSDoc to describe longest-prefix matching.
- Tests: shared-helper unit tests; the @my:server colon test now configures
  both 'my' and 'my:server' to exercise disambiguation; a colon completion
  test; isMethodNotFound message-casing tests (exact 'Method not found'
  swallowed, 'method not found handler' not swallowed).
2026-06-21 19:04:52 +08:00
..
channels feat(channel): add QQ Bot (QQ机器人) channel adapter (#5202) 2026-06-19 06:32:52 +08:00
_meta.ts refactor(core): remove GitService, migrate /restore to FileHistoryService (#4871) 2026-06-09 18:34:31 +08:00
approval-mode.md fix(core): require opt-in for plan mode prompt (#5433) 2026-06-20 17:53:57 +08:00
arena.md feat(arena): add comparison summary for agent results (#3394) 2026-04-22 05:31:19 +08:00
auto-mode.md Harden auto mode self-modification checks (#4572) 2026-06-08 10:22:31 +08:00
code-review.md feat(cli): route foreground subagents through pill+dialog while running (#3768) 2026-05-06 14:08:12 +08:00
commands.md docs: fix SSE ring size errors and add /workflows command (#5205) 2026-06-18 09:43:38 +08:00
dual-output.md fix(dual-output): prevent FIFO blocking on startup when no reader connected (#4894) 2026-06-15 06:04:06 +08:00
followup-suggestions.md feat(cli): show follow-up suggestion in input placeholder (#5145) 2026-06-19 13:39:12 +08:00
headless.md feat(cli): headless / non-interactive runaway-protection guardrails (#4103) (#4502) 2026-05-26 00:06:26 +08:00
hooks.md feat(hooks): pass original API call ID (toolCallId) to hook system (#4918) 2026-06-18 08:20:38 +00:00
language.md refactor(cli): revert dynamic slash command LLM translation (#4145) 2026-05-15 16:01:16 +08:00
lsp.md fix(lsp): expose status and startup diagnostics (#3649) 2026-05-17 01:42:28 +08:00
markdown-rendering.md feat(cli): support /copy N to copy Nth-last AI message (#4761) 2026-06-08 10:08:45 +08:00
mcp.md feat(mcp): support MCP resources and reliably surface prompts (#5544) 2026-06-21 19:04:52 +08:00
memory.md feat(memory): load .qwen/QWEN.local.md as project-local context (#4091) (#4394) 2026-05-25 11:22:55 +08:00
sandbox.md feat(cli): support tools.sandboxImage in settings (#3146) 2026-04-13 09:43:34 +08:00
scheduled-tasks.md feat(core): enable loop/cron tools by default (#4950) 2026-06-10 23:21:53 +08:00
skills.md feat(skills): support user-invocable frontmatter (#5037) 2026-06-13 06:09:23 +08:00
status-line.md fix(cli): clarify cumulative statusline token labels (#5400) 2026-06-19 17:39:31 +08:00
structured-output.md docs: user + design docs for --json-schema structured output (#4051) 2026-05-17 23:10:34 +08:00
sub-agents.md fix(agent): stop forking result-bearing work; keep omitted subagent_type awaitable (#5155) 2026-06-16 09:38:10 +08:00
tips.md feat: add contextual tips system with post-response context awareness (#2904) 2026-04-13 17:40:27 +08:00
token-caching.md feat: update docs 2025-12-12 19:37:36 +08:00
tool-use-summaries.md feat(cli,core): LLM-generated summary labels for tool-call batches (#3538) 2026-04-27 16:54:10 +08:00
worktree.md feat(worktree): Phase D — startup --worktree flag + symlinkDirectories + PR refs (#4381) 2026-05-27 17:04:51 +08:00