Power With a Brake: Agents, Tools, and Approval

Corsair gives an agent access to the same application-owned integration boundary used by dashboards and backend code. The key question is not whether a model can call a GitHub or Slack operation, but how it discovers that operation, which tenant it reaches, and what happens when the action carries real authority. Understanding the discovery loop and the permission lifecycle lets a builder expose useful flexibility without treating a prompt as a security control.

Discovery is a projection of the runtime

An application knows the operation for a conventional button. A “Create issue” form can call a known GitHub endpoint with arguments selected by the application. An agent faces a different problem: a user may ask it to find an issue, comment on it, close it, and notify a channel. The exact resources and sequence are not known when the application’s UI was built. Corsair’s agent surface addresses that uncertainty by exposing a small, stable discovery layer over the configured runtime.

The common MCP pattern has three tools. list_operations reports the API operations available from the configured plugins. get_schema describes the parameters, output, and metadata for a selected operation. run_script executes a JavaScript snippet with the existing Corsair instance in scope. The model can therefore discover a provider operation, inspect what it expects, and compose calls instead of relying on a tool definition written by hand for every endpoint.

This is a deliberate separation between discovery and execution. Listing an operation does not call the provider. Inspecting its schema does not grant a new credential. Execution is the point at which the existing Corsair binding resolves the account, builds the key, applies hooks and policy, and can update local state. Adding a configured plugin changes what discovery returns, but it does not create a second execution architecture for the agent.

The core inspection layer walks the endpoint trees supplied by plugins and turns their Zod input schemas into structured descriptions or tool schemas. When a framework adapter needs a callable tool, it can retain a raw input schema where available or build a Zod fallback from the structured form. Operation names can be sanitized for model APIs that reject dotted names, while the original path still determines which Corsair namespace is invoked. The adapter is translating the interface for the AI framework, not translating the provider’s meaning into a generic blob.

That distinction matters for typing. A model may need to know that a GitHub issue update expects a repository and issue identifier, while a Slack message post expects a channel and text. The tool adapter can expose those shapes to a LangChain, LlamaIndex, Mastra, Claude, or another supported runtime. The returned value is serialized for model consumption, but the underlying call remains a provider-specific Corsair operation. A schema helps the model form a valid request; it does not guarantee that the model chose the right issue or understood the business consequence.

The same instance is the important architectural choice. If the agent uses the Corsair instance already serving the application, an API action can update the synchronized entity that a dashboard reads. A chat command that closes a GitHub issue is not writing to an agent-only cache. The application can observe the same entity and apply its own business records around it.