Skip to content

feat: add ICA metering exporter as first pure-Python plugin - #170

Merged
jonpspri merged 11 commits into
mainfrom
feat/ica-metering-exporter-plugin
Aug 26, 2026
Merged

feat: add ICA metering exporter as first pure-Python plugin#170
jonpspri merged 11 commits into
mainfrom
feat/ica-metering-exporter-plugin

Conversation

@jonpspri

Copy link
Copy Markdown
Collaborator

Summary

Ports the ICA Metering Exporter from IBM/mcp-context-forge PR #5696 at head commit be937dd5743d0abbdc0ce8886b6be93f95c9d3dc into cpex-plugins as the repository's first pure-Python plugin.

Notable deviations from the source PR

  • Replaces gateway-internal request_headers_var access with the CPEX boundary extensions.http.headers.
  • Replaces mcpgateway logging with Python standard-library logging so the plugin remains standalone.
  • Fixes the source PR's undefined-headers NameError in the persona-header loop. This correction is worth feeding back upstream to IBM/mcp-context-forge.

Design decisions

  • Extends the plugin catalog to discover and validate both Rust and pure-Python packages while preserving aggregate compatibility fields.
  • Splits CI selection by implementation language so Python and Rust plugins run only their appropriate toolchains.
  • Adds wrong-language release guards so Python tags cannot enter Rust packaging and Rust tags cannot enter Python packaging.
  • Emits only trace-gated, non-sensitive OpenTelemetry operational metadata. The trace ID is an input gate and is never returned; tokens, headers, payloads, caller attribution, arguments, and output are excluded.

Test evidence

The complete local validation sequence is recorded in .omo/evidence/task-*.txt summaries (local execution evidence, intentionally not committed):

  • Catalog and wheel-helper suites: 146 passed, 3 skipped.
  • ICA Metering Exporter: 77 unit tests passed and 12 plugin-framework integration tests passed; Ruff, mypy, wheel, and sdist checks also passed.
  • Rate limiter regression: 84 Rust tests passed and 101 integration tests passed, 17 skipped; format, Clippy, build, benchmark compile, and wheel-install checks passed.
  • detect-secrets scan/audit gates: green.
  • DCO gates: green for all seven branch commits.

Gateway capability and registration

Gateway registration must grant the plugin the read_headers capability for caller attribution through extensions.http.headers; without it, the gateway strips inbound headers.

Gateway-side registration in mcp-context-forge/plugins/config.yaml is intentionally out of scope for this cpex-plugins pull request.

…CI selection, and release info

Signed-off-by: Jonathan Springer <jps@s390x.com>
…ugin

Signed-off-by: Jonathan Springer <jps@s390x.com>
…ts shim in integration conftest

Signed-off-by: Jonathan Springer <jps@s390x.com>
Signed-off-by: Jonathan Springer <jps@s390x.com>
…re routing

Keep ci-install-built-wheel.yaml unchanged because it remains the Rust wheel-helper workflow.

Signed-off-by: Jonathan Springer <jps@s390x.com>
…rkflows

Signed-off-by: Jonathan Springer <jps@s390x.com>
Signed-off-by: Jonathan Springer <jps@s390x.com>
Signed-off-by: Jonathan Springer <jps@s390x.com>

@lucarlig lucarlig left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

A few non-blocking follow-ups:

  • Parse the gateway’s actual ToolResult shape (_meta and content) so token counts and error messages aren’t dropped.
  • Reject duplicate plugin slugs across the Rust and Python roots.
  • Add capabilities: [read_headers] to the README configuration example.

Signed-off-by: Jonathan Springer <jps@s390x.com>
Signed-off-by: Jonathan Springer <jps@s390x.com>
Signed-off-by: Jonathan Springer <jps@s390x.com>
@jonpspri

Copy link
Copy Markdown
Collaborator Author

Thanks for the review, Luca. I've pushed three DCO-signed commits addressing each of the three summary items (there were no resolvable inline threads to mark):

  1. Parse gateway ToolResult payloads8c50a82
    metering.py now reads the error text from result.content[...].text and token metadata from both _meta and meta. Covered by two new unit tests.

  2. Reject duplicate plugin slugs across managed roots9e93c9a
    tools/plugin_catalog.py raises CatalogError when the same slug exists in both plugins/rust/python-package/ and plugins/python/. Covered by a new unit test.

  3. README capability example967e0b7
    Added capabilities: [read_headers] to the sample plugin config in README.md.

Verification:

  • ICA metering exporter make ci: Ruff, strict mypy, 79 unit tests, build, 12 integration tests passed.
  • Catalog suite: 133 passed, 3 skipped.
  • Real catalog validation and language-split selection passed.
  • Direct ToolResult hands-on QA passed.
  • README fenced YAML parsed and capability placement verified.
  • git diff --check passed.

Branch feat/ica-metering-exporter-plugin pushed normally; local, remote, and PR head all now at 967e0b7.

@jonpspri
jonpspri merged commit e48dc20 into main Aug 26, 2026
43 checks passed
@jonpspri
jonpspri deleted the feat/ica-metering-exporter-plugin branch August 26, 2026 18:26
prakhar-singh1928 added a commit that referenced this pull request Aug 27, 2026
…hon plugins

After rebasing onto main (which added ica_metering_exporter as the first
pure-Python plugin via PR #170), the combined repository now has 9 plugins:
8 Rust (including output_length_guard) + 1 Python (ica_metering_exporter).

Update three assertions that were left with stale values after the rebase:
- plugin_count field test: 8 -> 9
- rust_plugin_count split field: "7" -> "8"
- test_ci_selection_reports_language_splits_and_counts: comment + assertion 7 -> 8

Signed-off-by: prakhar-singh1928 <prakhar.singh1928@ibm.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants