siyuan-note/siyuan · warning

capability is disabled or no longer available: %s

Error message

capability is disabled or no longer available: %s

What it means

validateCapabilityCall checks capabilityStillExecutable (kernel/agent/capability.go:351-369): the capability's owner must still be available (connected MCP server, enabled plugin, matching browser-capability generation) and the Agent CapabilityPolicy must still allow the ID, and for non-browser tools the current registry entry must be identical to the registered one. If any check fails, the call is rejected with 'capability is disabled or no longer available: <capabilityID>' and never reaches the handler.

Source

Thrown at kernel/agent/tools.go:61

	}
	if t.ContextHandler == nil && t.Handler == nil {
		return nil, nil, fmt.Errorf("tool handler unavailable: %s", toolName)
	}
	if ctx.Err() != nil {
		return nil, nil, fmt.Errorf("tool execution was cancelled before it started")
	}
	if err := validator.ValidateInputContext(ctx, args); err != nil {
		return nil, nil, fmt.Errorf("invalid tool arguments: %w", err)
	}
	return t, validator, nil
}

func validateCapabilityCall(ctx context.Context, registration *capabilityRegistration, args map[string]any) error {
	if registration == nil {
		return fmt.Errorf("capability was not exposed in this model round")
	}
	if !capabilityStillExecutable(registration, args) {
		return fmt.Errorf("capability is disabled or no longer available: %s", registration.ID)
	}
	if ctx.Err() != nil {
		return fmt.Errorf("capability execution was cancelled before it started")
	}
	if registration.Validator == nil {
		return fmt.Errorf("capability validator unavailable: %s", registration.ID)
	}
	if err := registration.Validator.ValidateInputContext(ctx, args); err != nil {
		return fmt.Errorf("invalid capability arguments: %w", err)
	}
	if !registration.isBrowser() &&
		(registration.Tool == nil || registration.Tool.ContextHandler == nil && registration.Tool.Handler == nil) {
		return fmt.Errorf("capability handler unavailable: %s", registration.ID)
	}
	return nil
}

// executeTool 执行单次工具调用。

View on GitHub (pinned to afa823b6b4)

Solutions

  1. Re-enable the plugin / reconnect the MCP server (or reload the frontend that owns the capability), then start a new round so capabilities are re-exposed
  2. Check Settings - AI and confirm the capability is not denied by the Agent capability policy
  3. Do not blind-retry inside the same round — the capability set is fixed per round; a new turn re-registers it
  4. If the tool must survive disconnects, prefer kernel-native tools over per-connection MCP/browser ones
Defensive patterns

Strategy: fallback

Validate before calling

// Before executing, verify the owner is still connected / policy still allows
// kernel-side: capabilityStillExecutable(registration, args)
// client-side: check MCP server status + plugin enabled state for that capability

Type guard

null

Try / catch

null

Prevention

When it happens

Trigger: Tool call executed after its owner disappeared mid-session: MCP server disconnected between exposure and execution, plugin disabled/uninstalled, browser window that declared a frontend capability closed or reloaded (generation mismatch), or the admin changed the Agent capability policy (Settings - AI - Agent capability restrictions) to deny that tool. Also fires when the tool registry was rebuilt with a different Tool pointer.

Common situations: User revokes a plugin or disconnects an MCP server while the agent is mid-turn; capability policy tightened between rounds; frontend reload during a browser-capability turn; stale sessions resumed after a config change.

Related errors


AI-assisted analysis of siyuan-note/siyuan@afa823b6b4 (2026-08-18). Data as JSON: /api/errors/19f304909958a169. Report an issue: GitHub.