refactor(plugins): decouple plugin framework from gateway observability service#3140
Merged
refactor(plugins): decouple plugin framework from gateway observability service#3140
Conversation
3 tasks
…ion for observability service Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com>
Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com>
Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com>
Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com>
- Eliminate double plugin execution on failure by restructuring _execute_with_timeout to separate observability from plugin execution - Close orphaned spans with status="error" when plugin hooks raise - Fix docstring typo in ObservabilityMiddleware - Move ObservabilityServiceAdapter import inside conditional block - Document ContextVar bridge requirement on both definitions Signed-off-by: Jonathan Springer <jps@s390x.com>
Cover error and edge-case paths in plugin executor observability spans and get_plugin_manager initialization with plugins enabled. Signed-off-by: Jonathan Springer <jps@s390x.com>
7c64397 to
dde843a
Compare
jonpspri
approved these changes
Feb 24, 2026
Collaborator
jonpspri
left a comment
There was a problem hiding this comment.
Clean refactor — protocol-based DI correctly decouples plugin framework from gateway observability internals, and fixes the latent double-execution bug in the old catch-all fallback. Session lifecycle, Borg singleton interaction, and ContextVar bridge are all sound. Test coverage is thorough.
Minor suggestions (non-blocking):
- Consider exporting or removing
NullObservability(currently dead code in production). - A defensive
if self.observability:guard beforeend_spanin the error/success paths of_execute_with_timeoutwould make the null-safety explicit rather than relying on the surroundingexcept. - The duplicated try/except/finally session boilerplate in the adapter could be collapsed into a helper.
vishu-bh
pushed a commit
that referenced
this pull request
Feb 25, 2026
…ty service (#3140) * refactor(plugins/framework): introduce protocol and dependency injection for observability service Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com> * chore: fix lint issues Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com> * feat: add observability adapter for plugins Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com> * tests: coverage gaps Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com> * fix: address review findings in observability refactor - Eliminate double plugin execution on failure by restructuring _execute_with_timeout to separate observability from plugin execution - Close orphaned spans with status="error" when plugin hooks raise - Fix docstring typo in ObservabilityMiddleware - Move ObservabilityServiceAdapter import inside conditional block - Document ContextVar bridge requirement on both definitions Signed-off-by: Jonathan Springer <jps@s390x.com> * tests: achieve 100% diff coverage for observability refactor Cover error and edge-case paths in plugin executor observability spans and get_plugin_manager initialization with plugins enabled. Signed-off-by: Jonathan Springer <jps@s390x.com> --------- Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com> Signed-off-by: Jonathan Springer <jps@s390x.com> Co-authored-by: Frederico Araujo <frederico.araujo@ibm.com> Co-authored-by: Jonathan Springer <jps@s390x.com>
vishu-bh
pushed a commit
that referenced
this pull request
Feb 25, 2026
…ty service (#3140) * refactor(plugins/framework): introduce protocol and dependency injection for observability service Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com> * chore: fix lint issues Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com> * feat: add observability adapter for plugins Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com> * tests: coverage gaps Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com> * fix: address review findings in observability refactor - Eliminate double plugin execution on failure by restructuring _execute_with_timeout to separate observability from plugin execution - Close orphaned spans with status="error" when plugin hooks raise - Fix docstring typo in ObservabilityMiddleware - Move ObservabilityServiceAdapter import inside conditional block - Document ContextVar bridge requirement on both definitions Signed-off-by: Jonathan Springer <jps@s390x.com> * tests: achieve 100% diff coverage for observability refactor Cover error and edge-case paths in plugin executor observability spans and get_plugin_manager initialization with plugins enabled. Signed-off-by: Jonathan Springer <jps@s390x.com> --------- Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com> Signed-off-by: Jonathan Springer <jps@s390x.com> Co-authored-by: Frederico Araujo <frederico.araujo@ibm.com> Co-authored-by: Jonathan Springer <jps@s390x.com>
MohanLaksh
pushed a commit
that referenced
this pull request
Mar 12, 2026
…ty service (#3140) * refactor(plugins/framework): introduce protocol and dependency injection for observability service Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com> * chore: fix lint issues Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com> * feat: add observability adapter for plugins Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com> * tests: coverage gaps Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com> * fix: address review findings in observability refactor - Eliminate double plugin execution on failure by restructuring _execute_with_timeout to separate observability from plugin execution - Close orphaned spans with status="error" when plugin hooks raise - Fix docstring typo in ObservabilityMiddleware - Move ObservabilityServiceAdapter import inside conditional block - Document ContextVar bridge requirement on both definitions Signed-off-by: Jonathan Springer <jps@s390x.com> * tests: achieve 100% diff coverage for observability refactor Cover error and edge-case paths in plugin executor observability spans and get_plugin_manager initialization with plugins enabled. Signed-off-by: Jonathan Springer <jps@s390x.com> --------- Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com> Signed-off-by: Jonathan Springer <jps@s390x.com> Co-authored-by: Frederico Araujo <frederico.araujo@ibm.com> Co-authored-by: Jonathan Springer <jps@s390x.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Removes the plugin framework's direct dependency on
mcpgateway.db.SessionLocalandmcpgateway.services.observability_serviceby introducing a protocol-based observability abstraction with dependency injection.Closes: #2828
Problem
The plugin framework's
_execute_with_timeoutmethod importedSessionLocalandObservabilityServicedirectly from the gateway, creating a tight coupling that prevented the framework from operating standalone. This also required the plugin framework to manage database sessions for tracing — a concern that belongs to the host application.Solution
ObservabilityProviderprotocol andNullObservabilityno-op default in a newobservability.pymodulecurrent_trace_idContextVar owned by the plugin framework (replacing the one imported from the gateway's observability service)PluginExecutorandPluginManagernow accept an optionalobservabilityparameter via constructor injectionget_plugin_manager()forwards the observability provider to the managerDependency direction (before → after)
Changes
mcpgateway/plugins/framework/observability.pyObservabilityProviderprotocol,NullObservabilitydefault,current_trace_idContextVarmcpgateway/plugins/framework/manager.pyPluginExecutorandPluginManageracceptobservabilityparam;_execute_with_timeoutuses injected provider instead of direct gateway importsmcpgateway/plugins/framework/__init__.pyget_plugin_manager()acceptsobservabilityparam;ObservabilityProvideradded to__all__tests/unit/.../test_observability.pytests/unit/.../test_manager_coverage.pyTestExecuteWithTimeoutto test against injected provider instead of mockingmcpgateway.db/mcpgateway.servicesAdditional Changes
A few tests in
tests/unit/../test_http_auth_integration.pywere failing on dev environment when running the coverage target. Solution: Reset Starlette's cached middleware_stack after injecting the mock plugin manager so the middleware chain is rebuilt with the mock, and restore it afterward to avoid side effects on other tests.Test plan