Operation plugins¶
Plugins add trusted Python operations to the SDK, MCP server, CLI, and chat panel through one registration.
Use a plugin when an operation should appear everywhere. Use
FunctionToolSource for one agent application, or a workflow
for read-only validation and queries.
Trust boundary¶
Plugins run inside the ifc-console process and can access anything that process can. Install only reviewed packages.
Discovery reads metadata without importing code. Plugins are disabled by default and load only when their exact entry-point name is in the user allowlist. Project settings cannot enable them.
Package contract¶
Declare one entry point:
[project.entry-points."ifc_console.plugins"]
company_checks = "company_ifc_checks:CompanyChecks"
Provide a versioned manifest and register(api):
from pydantic import BaseModel, ConfigDict
from ifc_console import Capability, Envelope, PluginAPI, PluginManifest
class CompanyStatus(BaseModel):
model_config = ConfigDict(extra="forbid", frozen=True)
model: str
ready: bool
class CompanyChecks:
manifest = PluginManifest(
api_version="1",
name="company_checks",
version="1.0.0",
description="Company submission checks.",
)
def register(self, api: PluginAPI) -> None:
@api.registry.tool(
name="company_checks_status",
description="Return the company submission status.",
data_model=CompanyStatus,
required_capabilities=[Capability.MODEL_READ],
)
async def company_checks_status() -> Envelope:
session = api.core.session
session.require_loaded()
return api.success({
"model": session.name,
"ready": not session.dirty,
})
Rules:
- declare exact capabilities for every operation;
- prefix names to avoid collisions;
- keep structured output enabled;
- return
Envelope,api.success(...), orapi.failure(...); - use a Pydantic
data_modelwhen callers need a checked output contract.
Registration is atomic. Duplicate names, invalid manifests, malformed output, and uncaught exceptions fail safely. The host owns session metadata, correlation IDs, output limits, and untrusted-text warnings.
Install and enable¶
Install the plugin into the same environment as ifc-console, then allow it in user settings:
ifc-console plugins list
ifc-console settings set plugins.enabled true
ifc-console settings set plugins.allow '["company_checks"]'
ifc-console plugins doctor
plugins listreads metadata without importing plugin code.plugins doctorimports only allowed plugins and validates their contract.--jsonmakes either command suitable for automation.
The repository includes a complete example at
examples/plugins/company_checks.
Call an operation¶
from ifc_console import Workbench
with Workbench.open("tower.ifc") as wb:
result = wb.call("company_checks_status")
The operation also appears through MCP and chat when its required capabilities
are allowed. Use tools(permitted_only=True) when an agent should see only
currently permitted operations.
Cleanup and compatibility¶
A plugin that owns resources may define synchronous cleanup:
def shutdown(self, api: PluginAPI) -> None:
self.client.close()
The host calls cleanup once in reverse load order. Cleanup failures are audited and do not stop other services from closing.
manifest.api_version="1" defines the current public plugin contract. A future
incompatible contract will use a new version rather than silently changing
version 1. OperationPlugin is exported for static checking, and the package
includes PEP 561 type information.