feat(mcp): read a working-directory .mcp.json, honor enabled:false, name unmodelled keys; bump v1.1.29 - #79
Merged
Merged
Conversation
…ame unmodelled keys
Sources are now, lowest precedence first: <workdir>/.mcp.json (Claude Code
project file), ~/.tact/mcp.json, <workdir>/.tact/mcp.json, installed plugins.
A repository's shared configuration works out of the box without being able to
silently take over a server the user declared; a displaced declaration is still
reported. That file belongs to the project rather than to the user, so an
unparseable one is a warning and a skip instead of the hard error a native
mcp.json gets.
McpProjectConfig gains `enabled` (default true) and a flattened `extra` map:
- "enabled": false (the Codex convention, used by OpenAI's bundled
unified-computer-use) is resolved -- it can shadow and be shadowed -- but
never connected; `mcp list` reports it as `disabled (enabled: false)` and
`mcp get` describes it without dialing.
- Keys Tact does not model (enabled_tools, omit_tools_from,
startup_timeout_sec, tools.<name>.output_token_limit) are named one by one in
`mcp list`, with a matching warning in the log. The listing is the channel
that matters: tact-ui installs a tracing subscriber only when RUST_LOG or
tokio_console is set, so a warning alone would be invisible.
Also fixes a plugin-bundle parse: a plugin-root .mcp.json using the standard
{"mcpServers": {...}} wrapper was read as a flat name->config map, producing a
bogus server that was then skipped. parse_plugin_mcp_document accepts the
wrapper (which wins when present) and falls back to the flat form.
Docs: Ch 8 source table and entry semantics, Ch 21, and a Ch 26 entry (en/zh).
Tact's two native config files were named `mcp.json` (`~/.tact/mcp.json`, `<workdir>/.tact/mcp.json`) while the same concept is `.mcp.json` everywhere else: Claude Code's project file, the file a plugin bundle's `mcpServers` points at, VS Code's `.vscode/mcp.json`. One concept with two names only breeds doubt about which to write. Both scopes are now `.mcp.json`, with the path kept in the single `MCP_CONFIG_FILE` constant. The old name is not read and nothing is done for compatibility: a leftover `mcp.json` is an unrelated file, neither a source nor reported. Source order is unchanged (`<workdir>/.mcp.json` → `~/.tact/.mcp.json` → `<workdir>/.tact/.mcp.json` → installed plugins); `mcp add`/`remove` write the new paths. `scope_hint` now matches the Claude Code project file by full path rather than by `.mcp.json` suffix, which would also have caught Tact's own `.tact/.mcp.json`. Docs (Ch 8, 21, 26, README) and tests follow the rename.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Three commits on top of
v1.1.28(#78), all in the MCP configuration area, plus the v1.1.29 bump.1. Read
<workdir>/.mcp.json— the Claude Code project fileSources are now, lowest precedence first:
<workdir>/.mcp.json→~/.tact/.mcp.json→
<workdir>/.tact/.mcp.json→ installed plugins. A repository's shared configurationworks out of the box, but cannot silently take over a server the user declared — a
displaced declaration is still reported.
a skip, not the hard error a native config gets.
McpProjectConfiggainsenabled(defaulttrue) and a flattenedextramap:"enabled": false(the Codex convention) is resolved — it can shadow and be shadowed —but never connected;
mcp listreportsdisabled (enabled: false),mcp getdescribesit without dialing.
enabled_tools,omit_tools_from,startup_timeout_sec,tools.<name>.output_token_limit) are named one by one inmcp listplus a warning inthe log. The listing is the channel that matters:
tact-uiinstalls a tracing subscriberonly when
RUST_LOG/tokio_consoleis set, so a warning alone would be invisible.2. Fix plugin-bundle MCP parsing
A plugin-root
.mcp.jsonusing the standard{"mcpServers": {...}}wrapper was read as aflat name→config map, producing a bogus server that was then skipped.
parse_plugin_mcp_documentaccepts the wrapper (which wins when present) and falls back to the flat form.
3. Rename the native MCP config to
.mcp.jsonTact's two native config files were
mcp.json(~/.tact/mcp.json,<workdir>/.tact/mcp.json)while the same concept is
.mcp.jsoneverywhere else: Claude Code's project file, the file aplugin bundle's
mcpServerspoints at, VS Code's.vscode/mcp.json. Both scopes are now.mcp.json, kept in the singleMCP_CONFIG_FILEconstant. Nothing is done for compatibility:a leftover
mcp.jsonis an unrelated file, neither a source nor reported.Docs: Ch 8 source table and entry semantics, Ch 21, Ch 26 entry (en/zh), README.
Verification
scripts/check-rust.shgreen on the pushed tree:cargo fmt --check,clippy --all-targets -D warnings, and the four-crate test suite.no_proxy=127.0.0.1,localhostrequired for the loopback tests in this environment.