Skip to content

feat: add MCP auto tool injection toggle#1933

Open
Pratham-Mishra04 wants to merge 1 commit into02-18-refactor_standardize_empty_array_conventions_in_virtual_keyfrom
03-05-feat_add_option_to_disable_automatic_mcp_tool_injection_per_request
Open

feat: add MCP auto tool injection toggle#1933
Pratham-Mishra04 wants to merge 1 commit into02-18-refactor_standardize_empty_array_conventions_in_virtual_keyfrom
03-05-feat_add_option_to_disable_automatic_mcp_tool_injection_per_request

Conversation

@Pratham-Mishra04
Copy link
Collaborator

Summary

Adds a new configuration option DisableAutoToolInject to the MCP (Model Context Protocol) system that allows disabling automatic tool injection into requests. When enabled, MCP tools are only included when explicitly requested via context headers or filters, providing more granular control over tool availability.

Changes

  • Added DisableAutoToolInject field to MCPToolManagerConfig schema with runtime update support
  • Implemented atomic boolean storage in ToolsManager to safely handle concurrent access
  • Added logic in ParseAndAddToolsToRequest to respect the disable flag and only inject tools when explicit context filters are present
  • Extended configuration management with database migration, UI controls, and API endpoints
  • Added hot-reload capability through UpdateMCPDisableAutoToolInject methods across the stack
  • Updated UI with a toggle switch and clear documentation about the feature's behavior

Type of change

  • Feature
  • Bug fix
  • Refactor
  • Documentation
  • Chore/CI

Affected areas

  • Core (Go)
  • Transports (HTTP)
  • Providers/Integrations
  • Plugins
  • UI (Next.js)
  • Docs

How to test

Validate the new MCP auto tool injection toggle:

# Core/Transports
go version
go test ./...

# UI
cd ui
pnpm i || npm i
pnpm test || npm test
pnpm build || npm run build

Test the feature:

  1. Configure MCP clients and tools
  2. Enable "Disable Auto Tool Injection" in the MCP configuration UI
  3. Make requests without explicit tool headers - tools should not be injected
  4. Make requests with x-bf-mcp-include-tools header - tools should be injected
  5. Verify hot-reload works by toggling the setting without server restart

Screenshots/Recordings

UI changes include a new toggle switch in the MCP configuration view with descriptive text explaining when tools are injected based on explicit headers.

Breaking changes

  • Yes
  • No

This is a backward-compatible addition with a default value of false (auto injection enabled).

Related issues

This addresses the need for more granular control over MCP tool injection behavior in request processing.

Security considerations

The feature provides better control over tool exposure by allowing administrators to require explicit opt-in for tool injection, potentially reducing unintended tool access.

Checklist

  • I read docs/contributing/README.md and followed the guidelines
  • I added/updated tests where appropriate
  • I updated documentation where needed
  • I verified builds succeed (Go and UI)
  • I verified the CI pipeline passes locally if applicable

Copy link
Collaborator Author

Pratham-Mishra04 commented Mar 5, 2026

Warning

This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
Learn more

This stack of pull requests is managed by Graphite. Learn more about stacking.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 5, 2026

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Added configurable setting to disable automatic MCP tool injection for individual requests via new UI toggle in MCP configuration.
  • Bug Fixes

    • Restored preservation of original audio filenames in transcription requests.

Walkthrough

This pull request adds a new DisableAutoToolInject feature to the MCP (Model Context Protocol) system, allowing developers to disable automatic tool injection at runtime. The feature is propagated across core logic, database configuration, HTTP handlers, and the React UI through new methods and configuration fields.

Changes

Cohort / File(s) Summary
Core MCP Configuration & Logic
core/bifrost.go, core/schemas/mcp.go, core/mcp/interface.go, core/mcp/mcp.go, core/mcp/toolmanager.go
Added new public method UpdateMCPDisableAutoToolInject to enable runtime toggling of auto-injection. Introduced atomic bool flag disableAutoToolInject in ToolsManager initialized from config, with logic gating in ParseAndAddToolsToRequest. Updated error messages to use lowercase. New interface method added to MCPManagerInterface.
Database Configuration Layer
framework/configstore/clientconfig.go, framework/configstore/migrations.go, framework/configstore/tables/clientconfig.go, framework/configstore/rdb.go
Added MCPDisableAutoToolInject field to ClientConfig and TableClientConfig structs with JSON/GORM tags. Created new database migration migrationAddMCPDisableAutoToolInjectColumn to add the column. Updated UpdateClientConfig and GetClientConfig to handle the new field. Modified GenerateClientConfigHash to include the field in hash computation.
HTTP Transport & Handlers
transports/bifrost-http/handlers/config.go, transports/bifrost-http/server/server.go
Added new UpdateMCPDisableAutoToolInject methods to ConfigManager and ServerCallbacks interface. Implemented handler to persist changes and synchronize with MCP configuration when the flag is updated.
UI Components & Type Definitions
ui/app/workspace/config/views/mcpView.tsx, ui/lib/types/config.ts, ui/lib/types/schemas.ts
Added new Switch component for "Disable Auto Tool Injection" toggle in MCP settings. Extended CoreConfig interface and DefaultCoreConfig with mcp_disable_auto_tool_inject boolean field. Updated Zod schema with the new configuration property.
Configuration Schema & Tests
transports/config.schema.json, transports/schema_test/config_schema_test.go, transports/bifrost-http/lib/config_test.go
Added mcp_disable_auto_tool_inject property to JSON schema with boolean type and default false. Updated test configuration to include the new field and excluded it from internal field comparison.
Documentation & Cleanup
core/changelog.md, framework/changelog.md, transports/changelog.md, ui/app/workspace/logs/sheets/logDetailsSheet.tsx
Added feature entries to changelogs documenting the new DisableAutoToolInject capability. Removed unused imports (FileText, DollarSign) from logDetailsSheet component.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested reviewers

  • akshaydeo
  • danpiths

Poem

🐰 A toggle hops into the frame,
Auto-inject without the claim!
From config depths to UI light,
DisableAutoToolInject shines bright! ✨
Control flows pure, the tools obey,
When the flag says "nay!" 🔧

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat: add MCP auto tool injection toggle' clearly and concisely describes the main feature being added - a toggle to control automatic MCP tool injection.
Description check ✅ Passed The PR description comprehensively follows the template with all major sections completed: Summary, Changes, Type of change, Affected areas, How to test, Screenshots/Recordings, Breaking changes, Related issues, Security considerations, and Checklist all present and filled out.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch 03-05-feat_add_option_to_disable_automatic_mcp_tool_injection_per_request

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
framework/configstore/migrations.go (1)

4195-4200: Make rollback idempotent with a column-existence guard.

Rollback currently drops the column unconditionally. Guarding with HasColumn improves resilience across partial rollback or branch-skew scenarios.

♻️ Suggested hardening
 		Rollback: func(tx *gorm.DB) error {
 			tx = tx.WithContext(ctx)
 			migratorInstance := tx.Migrator()
-			if err := migratorInstance.DropColumn(&tables.TableClientConfig{}, "mcp_disable_auto_tool_inject"); err != nil {
-				return err
+			if migratorInstance.HasColumn(&tables.TableClientConfig{}, "mcp_disable_auto_tool_inject") {
+				if err := migratorInstance.DropColumn(&tables.TableClientConfig{}, "mcp_disable_auto_tool_inject"); err != nil {
+					return err
+				}
 			}
 			return nil
 		},
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@framework/configstore/migrations.go` around lines 4195 - 4200, The Rollback
closure currently calls migratorInstance.DropColumn(&tables.TableClientConfig{},
"mcp_disable_auto_tool_inject") unconditionally; make it idempotent by first
checking migratorInstance.HasColumn(&tables.TableClientConfig{},
"mcp_disable_auto_tool_inject") and only calling DropColumn when HasColumn
returns true, ensuring you still propagate errors from HasColumn and DropColumn
and preserving the existing tx.WithContext(ctx) and migratorInstance usage.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@core/bifrost.go`:
- Around line 3378-3380: Change the error string returned in the nil check for
bifrost.MCPManager (the block that returns fmt.Errorf when bifrost.MCPManager ==
nil) to follow Go conventions: make the message all lowercase with no trailing
punctuation (e.g., "mcp is not configured in this bifrost instance") so
fmt.Errorf produces a compliant error string.

In `@ui/app/workspace/config/views/mcpView.tsx`:
- Around line 188-193: Add a data-testid to the new Switch control so it follows
the workspace UI selector convention; in the Switch component with id
"mcp-disable-auto-tool-inject" (the one using
checked={localConfig.mcp_disable_auto_tool_inject ?? false},
onCheckedChange={handleDisableAutoToolInjectChange},
disabled={!hasSettingsUpdateAccess}), add a prop data-testid using the pattern
"<entity>-<element>-<qualifier>" (e.g., "mcp-switch-disable-auto-tool-inject" or
"mcp-disable-auto-tool-inject-switch") to make the element targetable by tests.

---

Nitpick comments:
In `@framework/configstore/migrations.go`:
- Around line 4195-4200: The Rollback closure currently calls
migratorInstance.DropColumn(&tables.TableClientConfig{},
"mcp_disable_auto_tool_inject") unconditionally; make it idempotent by first
checking migratorInstance.HasColumn(&tables.TableClientConfig{},
"mcp_disable_auto_tool_inject") and only calling DropColumn when HasColumn
returns true, ensuring you still propagate errors from HasColumn and DropColumn
and preserving the existing tx.WithContext(ctx) and migratorInstance usage.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 4db42427-dfea-4af6-9e93-224a715157fe

📥 Commits

Reviewing files that changed from the base of the PR and between 9ee898b and a26bb7f.

📒 Files selected for processing (20)
  • core/bifrost.go
  • core/changelog.md
  • core/mcp/interface.go
  • core/mcp/mcp.go
  • core/mcp/toolmanager.go
  • core/schemas/mcp.go
  • framework/changelog.md
  • framework/configstore/clientconfig.go
  • framework/configstore/migrations.go
  • framework/configstore/rdb.go
  • framework/configstore/tables/clientconfig.go
  • transports/bifrost-http/handlers/config.go
  • transports/bifrost-http/lib/config_test.go
  • transports/bifrost-http/server/server.go
  • transports/changelog.md
  • transports/config.schema.json
  • transports/schema_test/config_schema_test.go
  • ui/app/workspace/config/views/mcpView.tsx
  • ui/lib/types/config.ts
  • ui/lib/types/schemas.ts

@Pratham-Mishra04 Pratham-Mishra04 force-pushed the 03-05-feat_add_option_to_disable_automatic_mcp_tool_injection_per_request branch from a26bb7f to b515efc Compare March 5, 2026 12:44
@Pratham-Mishra04 Pratham-Mishra04 force-pushed the 02-18-refactor_standardize_empty_array_conventions_in_virtual_key branch from 9ee898b to 8789ae3 Compare March 5, 2026 12:44
@Pratham-Mishra04 Pratham-Mishra04 force-pushed the 03-05-feat_add_option_to_disable_automatic_mcp_tool_injection_per_request branch from b515efc to 1ee6d71 Compare March 5, 2026 12:48
@Pratham-Mishra04 Pratham-Mishra04 force-pushed the 02-18-refactor_standardize_empty_array_conventions_in_virtual_key branch from 8789ae3 to ea84c03 Compare March 5, 2026 13:07
@Pratham-Mishra04 Pratham-Mishra04 force-pushed the 03-05-feat_add_option_to_disable_automatic_mcp_tool_injection_per_request branch from 1ee6d71 to 57671fd Compare March 5, 2026 13:07
@Pratham-Mishra04 Pratham-Mishra04 force-pushed the 02-18-refactor_standardize_empty_array_conventions_in_virtual_key branch from ea84c03 to 2d9d2e9 Compare March 5, 2026 13:11
@Pratham-Mishra04 Pratham-Mishra04 force-pushed the 03-05-feat_add_option_to_disable_automatic_mcp_tool_injection_per_request branch from 57671fd to dae2e01 Compare March 5, 2026 13:11
@Pratham-Mishra04 Pratham-Mishra04 force-pushed the 02-18-refactor_standardize_empty_array_conventions_in_virtual_key branch from 2d9d2e9 to c0dfed9 Compare March 5, 2026 14:42
@Pratham-Mishra04 Pratham-Mishra04 force-pushed the 03-05-feat_add_option_to_disable_automatic_mcp_tool_injection_per_request branch from dae2e01 to fc9336c Compare March 5, 2026 14:42
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@core/mcp/toolmanager.go`:
- Around line 674-675: UpdateConfig is unconditionally calling
m.disableAutoToolInject.Store(config.DisableAutoToolInject), which allows
partial/patch updates to inadvertently flip DisableAutoToolInject; change the
config contract so presence is explicit (make DisableAutoToolInject a *bool or
add a DisableAutoToolInjectSet bool) and then in UpdateConfig only call
m.disableAutoToolInject.Store(...) when that presence flag/pointer is
non-nil/true; adjust callers to supply the new presence marker or pointer as
needed so partial updates won't reset m.disableAutoToolInject inadvertently.
- Around line 301-302: The context key lookups in toolmanager.go are using
undefined bare identifiers MCPContextKeyIncludeTools and
MCPContextKeyIncludeClients; update the read paths to use the same fully
qualified keys used by writers by calling
ctx.Value(schemas.MCPContextKeyIncludeTools) and
ctx.Value(schemas.MCPContextKeyIncludeClients) where the current ctx.Value(...)
calls occur (locate the ctx.Value usages in the function/method that references
includeTools/includeClients) so the keys match the schemas package constants
used by transports, handlers, and tests.

In `@transports/changelog.md`:
- Line 6: The changelog contains a duplicate entry "fix: preserve original audio
filename in transcription requests" — remove the repeated line (the duplicate
changelog item) so the file only contains a single instance of that entry;
search for the exact string "fix: preserve original audio filename in
transcription requests" and delete the redundant occurrence to keep release
notes unique.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b5645c5d-afdd-4cc0-a6ac-24865582ee10

📥 Commits

Reviewing files that changed from the base of the PR and between c0dfed9 and fc9336c.

📒 Files selected for processing (21)
  • core/bifrost.go
  • core/changelog.md
  • core/mcp/interface.go
  • core/mcp/mcp.go
  • core/mcp/toolmanager.go
  • core/schemas/mcp.go
  • framework/changelog.md
  • framework/configstore/clientconfig.go
  • framework/configstore/migrations.go
  • framework/configstore/rdb.go
  • framework/configstore/tables/clientconfig.go
  • transports/bifrost-http/handlers/config.go
  • transports/bifrost-http/lib/config_test.go
  • transports/bifrost-http/server/server.go
  • transports/changelog.md
  • transports/config.schema.json
  • transports/schema_test/config_schema_test.go
  • ui/app/workspace/config/views/mcpView.tsx
  • ui/app/workspace/logs/sheets/logDetailsSheet.tsx
  • ui/lib/types/config.ts
  • ui/lib/types/schemas.ts

Comment on lines +301 to +302
includeTools := ctx.Value(MCPContextKeyIncludeTools)
includeClients := ctx.Value(MCPContextKeyIncludeClients)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Key definitions =="
rg -n 'MCPContextKeyInclude(Tools|Clients)' --type go -B2 -A2

echo
echo "== context.WithValue write sites =="
rg -n 'context\.WithValue.*MCPContextKeyInclude' --type go -B2 -A2

echo
echo "== ctx.Value read sites =="
rg -n '\.Value\(.*MCPContextKeyInclude' --type go -B2 -A2

Repository: maximhq/bifrost

Length of output: 19317


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Check toolmanager.go for key definitions =="
rg -n '^const|^var|MCPContextKey' core/mcp/toolmanager.go | head -30

echo
echo "== Full context around toolmanager.go lines 301-302 =="
sed -n '295,310p' core/mcp/toolmanager.go

Repository: maximhq/bifrost

Length of output: 755


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Check toolmanager.go imports =="
head -50 core/mcp/toolmanager.go | grep -E '^import|^const|^var'

echo
echo "== Search for where these unqualified identifiers should come from =="
rg -n 'const.*MCPContextKey' core/mcp/

echo
echo "== Check if toolmanager.go has any const block at package level =="
sed -n '1,100p' core/mcp/toolmanager.go | grep -A20 'const ('
</parameter>

Repository: maximhq/bifrost

Length of output: 173


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Full imports section in toolmanager.go =="
sed -n '1,30p' core/mcp/toolmanager.go

echo
echo "== Check if schemas is imported =="
rg -n 'import|schemas' core/mcp/toolmanager.go | head -20
</parameter>

Repository: maximhq/bifrost

Length of output: 2528


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Verify the symbols are undefined in toolmanager.go =="
# Check if these unqualified symbols appear anywhere else in toolmanager.go
rg -c 'MCPContextKeyIncludeTools|MCPContextKeyIncludeClients' core/mcp/toolmanager.go

echo
echo "== Confirm key definitions are only in schemas =="
rg -n 'const.*MCPContextKeyIncludeTools|const.*MCPContextKeyIncludeClients' core/schemas/
</parameter>

Repository: maximhq/bifrost

Length of output: 168


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Find exact key definition lines =="
rg -n 'MCPContextKeyInclude' core/schemas/bifrost.go

echo
echo "== Verify no const definition of these unqualified names exist =="
grep -r 'const.*MCPContextKeyInclude' core/mcp/

echo
echo "== Check if there's a package-level const block in toolmanager.go =="
sed -n '30,150p' core/mcp/toolmanager.go | grep -A50 'const'
</parameter>

Repository: maximhq/bifrost

Length of output: 515


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Check if toolmanager.go has build constraints =="
head -5 core/mcp/toolmanager.go

echo
echo "== Verify these unqualified names are truly undefined by checking all occurrences =="
rg -n 'MCPContextKeyInclude(Tools|Clients)' core/mcp/toolmanager.go -B3 -A3

echo
echo "== Search entire codebase for const definitions of unqualified MCPContextKey =="
rg -n '^const.*MCPContextKey' core/
</parameter>

Repository: maximhq/bifrost

Length of output: 735


Fix context key references in toolmanager.go to use fully qualified names matching write paths.

Lines 301-302 use undefined identifiers MCPContextKeyIncludeTools and MCPContextKeyIncludeClients. All write paths (transports, handlers, tests) set these via schemas.MCPContextKeyIncludeTools and schemas.MCPContextKeyIncludeClients, but the read path here uses unqualified names that won't match. This breaks context filter detection when auto-inject is disabled.

Change to:

  • ctx.Value(schemas.MCPContextKeyIncludeTools)
  • ctx.Value(schemas.MCPContextKeyIncludeClients)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@core/mcp/toolmanager.go` around lines 301 - 302, The context key lookups in
toolmanager.go are using undefined bare identifiers MCPContextKeyIncludeTools
and MCPContextKeyIncludeClients; update the read paths to use the same fully
qualified keys used by writers by calling
ctx.Value(schemas.MCPContextKeyIncludeTools) and
ctx.Value(schemas.MCPContextKeyIncludeClients) where the current ctx.Value(...)
calls occur (locate the ctx.Value usages in the function/method that references
includeTools/includeClients) so the keys match the schemas package constants
used by transports, handlers, and tests.

Comment on lines +674 to +675
m.disableAutoToolInject.Store(config.DisableAutoToolInject)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

UpdateConfig can unintentionally reset DisableAutoToolInject.

Line 674 always writes config.DisableAutoToolInject, while the rest of UpdateConfig behaves like a partial/patch update. A partial call that only intends to change timeout/depth can silently flip this flag to false.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@core/mcp/toolmanager.go` around lines 674 - 675, UpdateConfig is
unconditionally calling
m.disableAutoToolInject.Store(config.DisableAutoToolInject), which allows
partial/patch updates to inadvertently flip DisableAutoToolInject; change the
config contract so presence is explicit (make DisableAutoToolInject a *bool or
add a DisableAutoToolInjectSet bool) and then in UpdateConfig only call
m.disableAutoToolInject.Store(...) when that presence flag/pointer is
non-nil/true; adjust callers to supply the new presence marker or pointer as
needed so partial updates won't reset m.disableAutoToolInject inadvertently.

- fix: async jobs stuck in "processing" on marshal failure now correctly transition to "failed"
- feat: adds attachment support in Maxim plugin
- feat: add option to disable automatic MCP tool injection per request
- fix: preserve original audio filename in transcription requests
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Remove duplicate changelog item.

Line 6 repeats an existing changelog entry already present earlier in this file, so it should be removed to avoid duplicate release notes.

✂️ Proposed fix
 - feat: add option to disable automatic MCP tool injection per request
-- fix: preserve original audio filename in transcription requests
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- fix: preserve original audio filename in transcription requests
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@transports/changelog.md` at line 6, The changelog contains a duplicate entry
"fix: preserve original audio filename in transcription requests" — remove the
repeated line (the duplicate changelog item) so the file only contains a single
instance of that entry; search for the exact string "fix: preserve original
audio filename in transcription requests" and delete the redundant occurrence to
keep release notes unique.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant