Skip to content

feat(mcp): read takes uri for one file and uris for several - #6860

Merged
ZaynJarvis merged 4 commits into
volcengine:mainfrom
wongzw:feat/mcp-read-uri-alias
Nov 2, 2026
Merged

ZaynJarvis merged 4 commits into
volcengine:mainfrom
wongzw:feat/mcp-read-uri-alias

Conversation

@wongzw

@wongzw wongzw commented Nov 1, 2026

Copy link
Copy Markdown
Contributor

Description

read was the only MCP tool whose path parameter was plural. ls, tree, download, write, edit, grep, glob, forget, the ACL tools and REST /api/v1/content/read?uri= all use uri, so agents guess uri and the call fails. In one user's Claude Code history, 25 of 394 read calls (about 6%) sent uri. Several came right after auto-compaction removed the earlier correct calls from context.

This follows the 2026-10-06 decision (智恒, 郑啸): read takes uri for one file and uris for several, matching the other tools. The decision lists three places to change: the 火山-hosted Go MCP, the MCP docs and the Claude Code plugin. This PR covers the open-source Python MCP, the docs, the plugins and the gateway. The hosted Go MCP needs the same change separately.

Human Involvement

  • A human participated in the implementation or review loop
  • This PR was generated entirely by AI agents without human participation in the loop

Related Issue

None.

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Refactoring (no functional changes)
  • Performance improvement
  • Test update

Changes Made

  • MCP read (openviking/server/mcp_endpoint.py): new uri parameter for one file, while uris still reads several in one call. At runtime both accept a string or a list. Passing both, or no URI, returns INVALID_ARGUMENT with both forms in the message.
  • Exported schema: _portable_schema collapses unions to their most general branch, which turned uri into an array. Clients that validate against the schema (the pi plugin's Ajv, Gemini function calling) would then reject read(uri="…"). A per-tool override now pins read.uri to {"type": "string"}, and uris stays an array.
  • Gateway (openviking_gateway/tool_catalog.py): the read notice uses uri first, then uris, so a uri call still shows its target.
  • Docs: the EN/ZH 06-mcp-integration.md read row lists uri for one file and uris for several.
  • Plugins:
    • The uri-guard deny message now suggests read(uri="…"). Edited in examples/memory-plugin-shared/lib/uri-guard.mjs and regenerated with sync.mjs.
    • The openviking-skills/SKILL.md check (9 copies, still identical) and agent-plugins/skills/ov-resources/SKILL.md now show read(uri).
    • The opencode and pi wrappers (openviking_read) are unchanged.
    • Patch bumps so check-plugin-version-bumps.sh passes: Claude Code 0.7.21, Codex 0.11.19, agent-hook 0.5.30 (with host manifests), OpenCode 0.5.24, DSH 0.5.32, pi 0.4.27.

Existing callers that send uris keep working unchanged.

Testing

  • I have added tests that prove my fix is effective or that my feature works

  • New and existing unit tests pass locally with my changes

  • I have tested this on the following platforms:

    • Linux
    • macOS
    • Windows
  • tests/server/test_mcp_endpoint.py:

    • Accepted: uri and uris, each as a string and as a list, through mcp.call_tool.
    • Rejected: both set, neither set, empty list and empty string. These also go through mcp.call_tool and assert isError with INVALID_ARGUMENT.
    • Schema: uri is string, uris is an array of strings, and neither is required.
    • The failures that remain in this file also fail on main.
  • tests/gateway/test_tools.py: a uri call shows its target in the notice.

  • Plugins: uri-guard, codebuddy and marketplace suites pass, and check-plugin-version-bumps.sh passes.

Checklist

  • My code follows the project's coding style
  • I have performed a self-review of my code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • Any dependent changes have been merged and published

Additional Notes

Release order: the plugins also run against the hosted Go MCP. Release these plugin versions only after the hosted Go MCP accepts uri. Before then, an agent on the hosted service that copies read(uri="…") from the hint would fail.

🤖 Generated with Claude Code

zw-bd and others added 4 commits November 1, 2026 01:40
read was the only MCP tool whose path parameter was plural, so agents
guessed uri and failed. uri now takes one URI or a list; uris still works.
Passing both, or no URI, returns INVALID_ARGUMENT naming the parameter.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Describe uri as the single-file parameter and uris as the batch one, so
agents still see that read can take several files in one call. Both
names keep accepting a string or a list.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The MCP read tool now takes uri for one file and uris for several.
The uri-guard deny message and the openviking-skills SKILL.md read a
single file, so they show read(uri=...).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
_portable_schema collapsed uri's union to an array, so clients that
validate against the schema rejected read(uri=...). Pin it to a string;
uris stays an array. The gateway notice shows uri targets, the
ov-resources skill shows read(uri), and the rejection tests go through
mcp.call_tool.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ZaynJarvis
ZaynJarvis merged commit 88c72b9 into volcengine:main Nov 2, 2026
15 checks passed
@github-project-automation github-project-automation Bot moved this from Backlog to Done in OpenViking project Nov 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

3 participants