Skip to content

fix(tools): guard Registry.tools with RWMutex against concurrent MCP registration#709

Merged
edenreich merged 1 commit into
mainfrom
fix/708-registry-tools-data-race
Jul 1, 2026
Merged

fix(tools): guard Registry.tools with RWMutex against concurrent MCP registration#709
edenreich merged 1 commit into
mainfrom
fix/708-registry-tools-data-race

Conversation

@edenreich

Copy link
Copy Markdown
Contributor

Summary

Fixes the data race on the tool Registry.tools map reported in #708: the MCP liveness-probe goroutine registers/unregisters MCP_* tools (RegisterMCPServerTools / UnregisterMCPServerTools) while the main loop reads the same map (GetTool / ListAvailableTools / GetToolDefinitions / IsToolEnabled) with no synchronization — flagged by -race, and a potential fatal error: concurrent map read and map write panic.

Changes

  • internal/agent/tools/registry.go: add toolsMu sync.RWMutex guarding tools. The four read accessors take RLock; every post-construction writer takes Lock — the MCP probe paths plus SetMemoryBackend, SetScreenshotProvider, and SetScreenshotServer. registerTools deliberately stays lock-free (documented): it runs inside NewRegistry before the registry is shared, and no tool constructor calls back into a locking accessor, so there is no re-entrancy hazard.
  • internal/agent/tools/registry_test.go: TestRegistry_ConcurrentMCPToolAccess regression test — churns MCP register/unregister from a goroutine (minimal stubMCPManager + counterfeiter FakeMCPClient) while the test goroutine hammers all four read accessors.

Verification

  • With the fix reverted, the new test fails under -race with multiple DATA RACE reports — it locks in the regression.
  • With the fix: go test -race ./internal/agent/tools/ passes, golangci-lint run ./internal/agent/tools/... reports 0 issues, go build ./... compiles clean.

Closes #708

…registration

The tool registry's tools map was written by the MCP liveness-probe
goroutine (RegisterMCPServerTools/UnregisterMCPServerTools) while the
main loop read it (GetTool/ListAvailableTools/GetToolDefinitions/
IsToolEnabled) with no synchronization - a data race flagged by -race
and a potential concurrent map read/write panic.

Guard the map with a sync.RWMutex: RLock in the read accessors, Lock in
all post-construction writers (MCP register/unregister, SetMemoryBackend,
SetScreenshotProvider, SetScreenshotServer). registerTools stays
lock-free since it runs before the registry escapes the constructor.

Add a -race regression test that churns MCP tool registration from a
goroutine while the read accessors run concurrently.

Closes #708
@edenreich edenreich requested a review from a team as a code owner July 1, 2026 21:55
@edenreich edenreich merged commit 8a70871 into main Jul 1, 2026
1 check passed
@edenreich edenreich deleted the fix/708-registry-tools-data-race branch July 1, 2026 22:07
inference-gateway-releaser Bot added a commit that referenced this pull request Jul 2, 2026
## [0.127.0](v0.126.0...v0.127.0) (2026-07-02)

### 🚀 Features

* **plan:** compact context and start a fresh session when a plan is approved ([#705](#705)) ([28ddba7](28ddba7))
* **memory:** configurable git sync backend ([#707](#707)) ([6a68c3d](6a68c3d)), closes [#670](#670) [#670](#670)
* **history:** each subagent gets its own history file ([#711](#711)) ([16c8fa1](16c8fa1)), closes [#699](#699)

### 🐛 Bug Fixes

* **plan:** accepting a plan switches to auto-accept mode by default ([#714](#714)) ([7b0befc](7b0befc)), closes [#710](#710)
* **tools:** guard concurrent gitignore and screenshot caches ([#713](#713)) ([0ff4276](0ff4276)), closes [#712](#712)
* **tools:** guard Registry.tools with RWMutex against concurrent MCP registration ([#709](#709)) ([8a70871](8a70871)), closes [#708](#708)
* **ui:** update dim color from [#565f89](https://github.com/inference-gateway/cli/issues/565f89) to [#7a7f9a](https://github.com/inference-gateway/cli/issues/7a7f9a) for improved contrast ([#706](#706)) ([b2ee67e](b2ee67e))

### 🔧 Build System

* **deps:** bump github.com/go-telegram/bot from 1.21.0 to 1.22.0 in the gomod group ([#703](#703)) ([3de5136](3de5136))
* **deps:** bump the github-actions group with 5 updates ([#704](#704)) ([80221f7](80221f7))
@inference-gateway-releaser

Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 0.127.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] Data race on tool Registry.tools map between async MCP registration and tool lookups

1 participant