Skip to content

Add filtering by host, port, and path for MCP tool's getExchanges#2936

Merged
predic8 merged 6 commits intomasterfrom
mcp-exchange-config
May 6, 2026
Merged

Add filtering by host, port, and path for MCP tool's getExchanges#2936
predic8 merged 6 commits intomasterfrom
mcp-exchange-config

Conversation

@christiangoerdes
Copy link
Copy Markdown
Collaborator

@christiangoerdes christiangoerdes commented May 5, 2026

Summary by CodeRabbit

  • New Features

    • getExchanges tool now supports optional filters: host, port, and pathPattern alongside limit and includeBodies for targeted retrieval.
  • Bug Fixes

    • Invalid pathPattern values are handled safely (won’t break queries).
    • Tool argument validation tightened to reject unexpected arguments.
  • Documentation

    • getExchanges schema and description updated to document the new filter parameters and behavior.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 5, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 0f28c6c0-7056-43ed-b0ef-5adc78d6e4a7

📥 Commits

Reviewing files that changed from the base of the PR and between b5076b7 and 70adf9d.

📒 Files selected for processing (1)
  • core/src/main/java/com/predic8/membrane/core/interceptor/mcp/MembraneMCPServer.java
🚧 Files skipped from review as they are similar to previous changes (1)
  • core/src/main/java/com/predic8/membrane/core/interceptor/mcp/MembraneMCPServer.java

📝 Walkthrough

Walkthrough

Adds server-side request filtering to the MCP getExchanges tool: new package-private ExchangeUtils evaluates host, port, and path-pattern filters; MCPUtil gains an optional-string argument helper; MembraneMCPServer accepts, validates, and applies the new filters and updates the tool schema/description. (50 words)

Changes

MCP Exchange Filtering Feature

Layer / File(s) Summary
Filtering Utilities
core/src/main/java/com/predic8/membrane/core/interceptor/mcp/ExchangeUtils.java
New package-private ExchangeUtils with matchesExchangeFilter(...) and helpers: host matching (case-insensitive, null = any), port matching (null = any, authority → proxy-key fallback), path matching (null = any, prefix or regex). Protects against URI parsing and regex errors.
Argument Extraction
core/src/main/java/com/predic8/membrane/core/interceptor/mcp/MCPUtil.java
Added public static @nullable String getOptionalStringArgument(MCPToolsCall, String) that returns null when absent, enforces String type, trims input, and rejects blank values via InvalidToolArgumentsException.
Tool Implementation & Schema
core/src/main/java/com/predic8/membrane/core/interceptor/mcp/MembraneMCPServer.java
getExchanges now permits optional host, port, and pathPattern arguments (validated via rejectUnexpectedArguments), reads limit/includeBodies, filters stored exchanges using ExchangeUtils.matchesExchangeFilter(...), takes the last limit entries of the filtered list, and updates tool description and JSON schema. Also adds static imports for utility methods.
Auxiliary
pom.xml, build.gradle
Build manifests updated (lines changed noted in diff metadata).

Estimated Code Review Effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 I hopped through code to build a sieve,
Hosts and ports and paths that start or jive,
Trimmed the args, kept parsing safe and neat,
Filters applied, exchanges trimmed to meet,
A small soft hop — the server hums complete.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: adding filtering by host, port, and path to the MCP tool's getExchanges functionality, which aligns with the primary objective and all file changes.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch mcp-exchange-config

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@christiangoerdes
Copy link
Copy Markdown
Collaborator Author

/ok-to-test

@christiangoerdes christiangoerdes requested a review from predic8 May 5, 2026 10:24
@membrane-ci-server
Copy link
Copy Markdown

This pull request needs "/ok-to-test" from an authorized committer.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@core/src/main/java/com/predic8/membrane/core/interceptor/mcp/MembraneMCPServer.java`:
- Around line 240-246: The handler currently accepts a "path" argument but
ignores it in filtering—only "pathPattern" is used—so update the filtering and
schema so "path" is treated as an alias of "pathPattern": modify the stream
filter call that invokes ExchangeUtils.matchesExchangeFilter to pass
getOptionalStringArgument(call, "path") when present (or otherwise
getOptionalStringArgument(call, "pathPattern")), and update the
schema/properties declaration in MembraneMCPServer to document/accept "path" the
same way as "pathPattern" (i.e., add the "path" property and/or map it to
"pathPattern" in validation). Ensure rejectUnexpectedArguments still allows
"path" and that getOptionalStringArgument usage is consistent with existing
getOptionalPort/getOptionalStringArgument calls.
- Around line 242-253: Pre-validate and evaluate the optional arguments before
streaming so invalid inputs are rejected even when there are zero exchanges:
call getOptionalStringArgument(call, "host"), getOptionalPort(call),
getOptionalStringArgument(call, "pathPattern"), getOptionalIntArgument(call,
"limit", maxExchanges, 1, maxExchanges) and
MCPUtil.getOptionalBooleanArgument(call, "includeBodies", false) into local
variables first, use those locals in the ExchangeUtils.matchesExchangeFilter
call and when computing the subList for exchanges, and pass the pre-evaluated
includeBodies local into MCPUtil.describeExchange; this ensures argument
parsing/validation happens up-front rather than inside the stream or when
exchanges are empty.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 6b99bcbd-4452-4c05-a125-22d11d254ad0

📥 Commits

Reviewing files that changed from the base of the PR and between 549e827 and 871b9dc.

📒 Files selected for processing (3)
  • core/src/main/java/com/predic8/membrane/core/interceptor/mcp/ExchangeUtils.java
  • core/src/main/java/com/predic8/membrane/core/interceptor/mcp/MCPUtil.java
  • core/src/main/java/com/predic8/membrane/core/interceptor/mcp/MembraneMCPServer.java

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
core/src/main/java/com/predic8/membrane/core/interceptor/mcp/MembraneMCPServer.java (1)

242-256: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Pre-parse all arguments before the stream.

All filter and response arguments — host, port, pathPattern, and includeBodies — are resolved inside the stream lambdas. This has two consequences:

  1. Correctness gap: when the exchange store is empty, none of the lambda bodies execute, so invalid/malformed argument values are silently accepted.
  2. Performance: getOptionalStringArgument/getOptionalPort are invoked once per exchange instead of once per call.
🐛 Proposed fix: hoist argument parsing out of the stream
     private MCPToolsCallResponse getExchanges(MCPToolsCall call, Exchange exc) {
         rejectUnexpectedArguments(call, Set.of("limit", "includeBodies", "host", "port", "pathPattern"));
 
+        String host = getOptionalStringArgument(call, "host");
+        Integer port = getOptionalPort(call);
+        String pathPattern = getOptionalStringArgument(call, "pathPattern");
+        boolean includeBodies = getOptionalBooleanArgument(call, "includeBodies", false);
+        int limit = getOptionalIntArgument(call, "limit", maxExchanges, 1, maxExchanges);
+
         List<AbstractExchange> filteredExchanges = Optional.ofNullable(getRouter().getExchangeStore().getAllExchangesAsList())
                 .orElse(List.of())
                 .stream()
-                .filter(exchange -> ExchangeUtils.matchesExchangeFilter(exchange, getOptionalStringArgument(call, "host"), getOptionalPort(call), getOptionalStringArgument(call, "pathPattern")))
+                .filter(exchange -> ExchangeUtils.matchesExchangeFilter(exchange, host, port, pathPattern))
                 .toList();
-        List<AbstractExchange> exchanges = filteredExchanges.subList(Math.max(0, filteredExchanges.size() - getOptionalIntArgument(call, "limit", maxExchanges, 1, maxExchanges)), filteredExchanges.size());
+        List<AbstractExchange> exchanges = filteredExchanges.subList(Math.max(0, filteredExchanges.size() - limit), filteredExchanges.size());
 
         return MCPToolsCallResponse.from(call)
                 .withJson(Map.of(
                         "exchanges",
                         exchanges.stream()
-                                .map(exchange -> MCPUtil.describeExchange(exchange, MCPUtil.getOptionalBooleanArgument(call, "includeBodies", false), payloadSanitizer))
+                                .map(exchange -> describeExchange(exchange, includeBodies, payloadSanitizer))
                                 .filter(Objects::nonNull)
                                 .toList()
                 ));
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@core/src/main/java/com/predic8/membrane/core/interceptor/mcp/MembraneMCPServer.java`
around lines 242 - 256, Pre-parse all call arguments before creating the stream:
call getOptionalStringArgument for "host" and "pathPattern", getOptionalPort for
port, getOptionalIntArgument for "limit" (apply the same bounds logic to compute
the start index), and MCPUtil.getOptionalBooleanArgument for "includeBodies";
then use these local variables inside the filter lambda (instead of calling
getOptional... inside ExchangeUtils.matchesExchangeFilter) and inside the map
that calls MCPUtil.describeExchange so argument parsing happens once and errors
surface even when the exchange store is empty.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Duplicate comments:
In
`@core/src/main/java/com/predic8/membrane/core/interceptor/mcp/MembraneMCPServer.java`:
- Around line 242-256: Pre-parse all call arguments before creating the stream:
call getOptionalStringArgument for "host" and "pathPattern", getOptionalPort for
port, getOptionalIntArgument for "limit" (apply the same bounds logic to compute
the start index), and MCPUtil.getOptionalBooleanArgument for "includeBodies";
then use these local variables inside the filter lambda (instead of calling
getOptional... inside ExchangeUtils.matchesExchangeFilter) and inside the map
that calls MCPUtil.describeExchange so argument parsing happens once and errors
surface even when the exchange store is empty.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: a8e42053-573f-4710-8b02-eda3eef0955c

📥 Commits

Reviewing files that changed from the base of the PR and between 871b9dc and b5076b7.

📒 Files selected for processing (1)
  • core/src/main/java/com/predic8/membrane/core/interceptor/mcp/MembraneMCPServer.java

@predic8 predic8 merged commit 1af0001 into master May 6, 2026
5 checks passed
@predic8 predic8 deleted the mcp-exchange-config branch May 6, 2026 08:17
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