Skip to content

fix(server): decouple native Paseo tools from MCP injection - #4434

Closed
thomasvan wants to merge 1 commit into
getpaseo:mainfrom
thomasvan:native-tools-injection-independent
Closed

fix(server): decouple native Paseo tools from MCP injection#4434
thomasvan wants to merge 1 commit into
getpaseo:mainfrom
thomasvan:native-tools-injection-independent

Conversation

@thomasvan

Copy link
Copy Markdown
Contributor

After #4277 landed per-provider control of the Paseo tool catalog, disabling MCP injection also disables the native catalog, even where the provider policy is enabled:

// bootstrap.ts — startup and both live field-change handlers
agentManager.setPaseoToolsEnabled(mcpEnabled && mcp.injectIntoAgents !== false);

Why it matters. Deployments that serve MCP caller-scoped — each seat gets its own caller-scoped server, so daemon-wide injection is off — still need the native catalog for coordinator seats (and, via the per-provider paseoTools policy, none for worker seats). Gating the catalog on injectIntoAgents removes the whole channel for exactly those deployments; the per-provider policy from #4277 is a second gate on top of a switch that is already off.

Fix. Gate native availability on mcp.enabled at startup and on both onFieldChange handlers; injection keeps controlling only the injected MCP server URL (setMcpBaseUrl). The per-provider paseoTools policy remains the seat-level gate. Adds native-tools-gate.ts owning the decision, with its truth table (native-tools-gate.test.ts).

Default behaviour is unchanged where MCP is enabled and injection is on; the change is only for injection-off deployments, whose native tools previously disappeared as a side effect of a flag about something else. Server typecheck and the new tests pass.

After getpaseo#4277, disabling MCP injection also disables the native Paseo tool
catalog, even when the per-provider paseoTools policy is enabled. Deployments
that serve MCP caller-scoped (daemon-wide injection off) lose native tools for
their coordinator seats entirely.

Gate native availability on mcp.enabled at startup and on both live
field-change handlers, and keep injection controlling only the injected MCP
server URL. The per-provider paseoTools policy remains the seat-level gate.
Adds native-tools-gate.ts with the decision and its truth table.
thomasvan added a commit to thomasvan/paseo that referenced this pull request Sep 7, 2026
@greptile-apps

greptile-apps Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR separates native Paseo tool availability from daemon MCP URL injection, using mcp.enabled as the native catalog master switch at startup and during live configuration changes.

  • Adds a small gate function and truth-table unit tests.
  • Keeps MCP URL injection controlled by mcp.injectIntoAgents.
  • Updates both AgentManager and provider-runtime catalog state.
  • The provider-runtime path still exposes a global OpenCode manifest without applying the seat-level policy.

Confidence Score: 4/5

The PR is not ready to merge because injection-off worker seats can be shown native OpenCode tools that their provider policy disables, and the explicit repository test and import requirements also need to be satisfied.

The AgentManager path correctly combines global enablement with provider policy, but the provider runtime receives a daemon-wide catalog and advertises it independently of that policy, producing tools that fail with 403 for disabled sessions.

Files Needing Attention: packages/server/src/server/bootstrap.ts, packages/server/src/server/native-tools-gate.test.ts

Important Files Changed

Filename Overview
packages/server/src/server/bootstrap.ts Decouples native catalogs from MCP injection, but enables the global OpenCode manifest without applying the provider-level policy.
packages/server/src/server/native-tools-gate.ts Defines the intended MCP-enabled truth table as a small pure function.
packages/server/src/server/native-tools-gate.test.ts Covers the helper truth table but not the startup and live bootstrap behavior that caused the regression.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[mcp.enabled] --> B[Native tools master gate]
  C[mcp.injectIntoAgents] --> D[MCP base URL injection]
  B --> E[AgentManager]
  E --> F{Provider paseoTools policy}
  F -->|enabled| G[Session-bound native catalog]
  F -->|disabled| H[No executable session tools]
  B --> I[Global OpenCode manifest]
  I --> J[Tools advertised to all OpenCode sessions]
  H --> K[Advertised invocation returns 403]
Loading

Reviews (1): Last reviewed commit: "fix(server): decouple native Paseo tools..." | Re-trigger Greptile

// injection: caller-scoped deployments keep the catalog while injecting
// nothing (see native-tools-gate.ts).
agentManager.setPaseoToolsEnabled(isNativePaseoToolsEnabled(config.mcpEnabled));
setAgentProviderToolsEnabled(isNativePaseoToolsEnabled(config.mcpEnabled));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 Provider policy is bypassed

When MCP is enabled and an OpenCode worker has its paseoTools policy disabled, this installs the full daemon-wide manifest without applying that provider policy. OpenCode therefore advertises every native tool to the worker, but the session has no executable tools and each invocation returns 403. Apply the provider policy when exposing the manifest, or make catalog discovery session-scoped so disabled seats receive no catalog.

Comment on lines +5 to +15
test("mcp enabled + injection off keeps the native catalog available", () => {
expect(isNativePaseoToolsEnabled(true)).toBe(true);
});

test("absent mcp.enabled defaults to enabled", () => {
expect(isNativePaseoToolsEnabled(undefined)).toBe(true);
});

test("mcp disabled disables the native catalog regardless of injection", () => {
expect(isNativePaseoToolsEnabled(false)).toBe(false);
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Tests miss bootstrap behavior

These tests exercise only the extracted boolean helper, so they still pass if startup or either live configuration handler couples native tools back to MCP injection. The repository requires tests to use the same interface as callers and prove visible behavior. Before merging, add a bootstrap or daemon-level regression test that observes native catalog availability with injection disabled, including the relevant live configuration transition.

Rule Used: # Code Review Pattern Reference: Slop, Tests, Feat... (source)

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

import { CheckoutDiffManager } from "./checkout-diff-manager.js";
import { ScheduleService } from "./schedule/service.js";
import { DaemonConfigStore, type MutableDaemonConfig } from "./daemon-config-store.js";
import { isNativePaseoToolsEnabled } from "./native-tools-gate.js";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Imports violate server convention

This new import uses a relative path, and the corresponding import in packages/server/src/server/native-tools-gate.test.ts:3 does the same. The server package guide requires imports to use the @server/* alias. This repository requirement must be satisfied before merging.

Context Used: packages/server/CLAUDE.md (source)

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@boudra

boudra commented Sep 8, 2026

Copy link
Copy Markdown
Collaborator

Closing for now: this needs a daemon-level regression and real-provider evidence that native tools remain usable with MCP injection off at startup and after live config changes, while disabled provider policies still hide them. Please reopen with that evidence.

@boudra boudra closed this Sep 8, 2026
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.

2 participants