ADR-0039: Adopt Fully Independent Plugin Crates ArchitectureΒΆ
ContextΒΆ
The current pii_filter plugin is not a separate crate and embeds PyO3 dependencies and macros directly. This couples plugin logic to Python bindings, making it difficult to add new plugins and increasing long-term maintenance costs as we expand support for both Rust and Python implementations.
DecisionΒΆ
Adopt ** Fully Independent Plugin Crates** as the plugin architecture.
- Each plugin lives in its own crate with its own versioning and types.
- Plugins expose their own
#[pyfunction]/#[pymodule]/#[pyclass]for in-process usage (via maturin/pip packaging). - Plugin authors may choose in-process (PyO3) or out-of-process (gRPC/HTTP) execution.
- Shared utilities, error conversions, or common adapters live in a separate shared crate if needed.
- Strong isolation and self-containment for plugins.
ConsequencesΒΆ
PositiveΒΆ
- Clear ownership and strong isolation per plugin
- Straightforward pip distribution for Python integration
- Flexibility: in-process or remote execution per plugin
- Reduced coupling between core and plugin code
- Easier to add/maintain plugins independently
NegativeΒΆ
- Minor boilerplate per plugin for bindings/API surface
Risks / MitigationsΒΆ
- Repetition in bindings β mitigate with shared helper crate when patterns emerge
- Workspace uniformity β optional shared crate
Alternatives ConsideredΒΆ
- Option 1: Rust API on top of Python API β Rejected (creates duplicative public Rust contract, tight coupling)
- Option 3: Hybrid workspace with dedicated adapter crate β Deferred (viable future evolution if many plugins justify shared adapters; little practical difference from Option 2 initially)
- Option 4: Only gRPC/HTTP β Rejected (adds latency/complexity for local dev; not required for all use cases)
RelatedΒΆ
- Testing: Use shared Python-based integration tests across Rust and Python implementations
- Issue: IBM/mcp-context-forge#2730