Skip to content

Gateway: HTTP MCP backend, hardening (circuit breaker/audit/redaction), parallel reconnect - #108

Merged
getappz merged 13 commits into
masterfrom
gateway-parallel-reconnect
Jul 9, 2026
Merged

Gateway: HTTP MCP backend, hardening (circuit breaker/audit/redaction), parallel reconnect#108
getappz merged 13 commits into
masterfrom
gateway-parallel-reconnect

Conversation

@getappz

@getappz getappz commented Jul 8, 2026

Copy link
Copy Markdown
Owner

Summary

  • Add a real HTTP/Streamable-HTTP MCP backend (McpHttpBackend, kind = "mcp_http" in gateway.toml) alongside the existing stdio one, using rmcp's Streamable-HTTP client transport. Delete the old unimplemented http_api REST-bridge stub outright — the gateway only ever speaks real MCP.
  • Extract a shared CircuitBreaker used by both backends (was duplicated-in-waiting between stdio and the new HTTP backend).
  • Fix a latent TOCTOU double-lock bug in McpStdioBackend: ensure_connected now returns the still-locked guard instead of releasing and re-acquiring it, closing a window where a concurrent caller could invalidate the "connected" assumption between the two lock acquisitions. The new HTTP backend was built on this corrected pattern from the start.
  • Validate gateway_execute call args before attempting to connect (in both backends), not after — a malformed call now fails instantly instead of first paying for a connect attempt that was never going to succeed.
  • Discover across backends in parallel and reconnect automatically on a service-level error, instead of serially and requiring a manual reconnect.
  • Open a per-backend circuit breaker after repeated consecutive spawn/connection failures, short-circuiting further calls and allowing one probe attempt after a recovery window.
  • Append-only audit log for gateway_execute calls (server, tool, args hash, outcome) written alongside the registry db — raw args are never logged, only a hash.
  • Redact connection details, file paths, and credential-shaped text from downstream error messages before they reach the LLM.
  • Sanitize discovered tool names/descriptions (charset + length bounds) before they're indexed and surfaced via gateway_search, since a downstream (or compromised) server fully controls that data.

Test plan

  • cargo build --workspace
  • cargo test --workspace (all green — 207+ tests across the workspace, including new HTTP backend, circuit-breaker, TOCTOU-fix, audit-log, and reconnect integration tests)

Summary by CodeRabbit

  • New Features
    • Added optional audit logging for each tool execution (success and failure) while keeping sensitive arguments hidden via hashing.
    • Added MCP-over-HTTP backend support, including configurable authentication header handling.
    • Improved LLM-facing safety by sanitizing tool metadata and redacting sensitive details from downstream errors.
  • Bug Fixes
    • Improved resiliency with circuit breaking to stop repeated failing calls and automatic reconnect after upstream/service-level errors.
    • Malformed tool inputs are rejected earlier with clearer error behavior.

getappz added 2 commits July 9, 2026 02:54
…ay-registry

Ported two patterns from forgemax's more mature gateway architecture:

- ensure_fresh() discovered each backend's tools sequentially; with N
  configured servers a single slow one serialized every other one behind
  it. Now runs concurrently via futures_util::future::join_all (already a
  transitive dep at 0.3.32, added explicitly).
- McpStdioBackend::call/discover only cleared the cached connection on a
  timeout. A service-level error (Ok(Err(_)) from rmcp's call_tool/
  list_all_tools) can equally mean the transport died underneath us
  (broken pipe, crashed child) since rmcp doesn't distinguish the two at
  that call site — now drops the cache there too so the next call
  respawns instead of repeatedly hitting a dead pipe.
…tool sanitization

- open a per-backend circuit after repeated consecutive spawn/connection
  failures, short-circuiting further calls and allowing one probe attempt
  after a recovery window
- append-only audit log for gateway_execute calls (server, tool, args hash,
  outcome) written alongside the registry db; never logs raw args
- redact connection details, file paths, and credential-shaped text from
  downstream error messages before they reach the LLM
- sanitize discovered tool names/descriptions (charset + length bounds)
  before they're indexed and surfaced via gateway_search
@coderabbitai

coderabbitai Bot commented Jul 8, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds MCP HTTP backend support, shared circuit breaking, audit logging, tool metadata sanitization, and downstream error redaction across gateway-registry and the MCP server.

Changes

Gateway registry reliability and safety features

Layer / File(s) Summary
Dependencies and module wiring
crates/gateway-registry/Cargo.toml, crates/gateway-registry/src/lib.rs
Adds the new crate dependencies and declares/re-exports the new gateway-registry modules.
Circuit breaker core and stdio wiring
crates/gateway-registry/src/error.rs, crates/gateway-registry/src/circuit.rs, crates/gateway-registry/src/mcp_stdio.rs
Adds CircuitOpen, defines the shared breaker, and wires circuit checks plus cached-connection clearing into the stdio backend.
MCP HTTP backend and config
crates/gateway-registry/src/config.rs, crates/gateway-registry/src/backend.rs, crates/gateway-registry/src/mcp_http.rs
Replaces the old HTTP placeholder shape with mcp_http config and a real Streamable-HTTP backend with optional auth and circuit handling.
Registry execution, discovery, and audit logging
crates/gateway-registry/src/registry.rs, crates/gateway-registry/src/audit.rs, crates/gateway-registry/src/sanitize.rs
Adds audit-log path handling, concurrent discovery, sanitized tool entries, discovery fallback, audit writes on execute, and tool metadata sanitization helpers.
Error redaction
crates/gateway-registry/src/redact.rs, src/mcp_server.rs
Adds downstream error redaction utilities and uses them before returning internal MCP server errors.
Integration fixtures and backend tests
crates/gateway-registry/tests/...
Adds HTTP fixture support plus integration tests for MCP HTTP discovery/call/circuit behavior, stdio reconnect behavior, registry routing, and audit logging.

Estimated code review effort: 5 (Critical) | ~90 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant Registry
  participant Backend
  participant AuditLog

  Client->>Registry: execute(server, tool, args)
  Registry->>Backend: call(args.clone())
  Backend-->>Registry: Ok/Err result
  Registry->>AuditLog: record(server, tool, hashed args, outcome)
  Registry-->>Client: result
Loading

Possibly related PRs

  • getappz/agentflare#104: Evolves the same gateway-registry backend, registry, and MCP server paths with MCP HTTP support, circuit breaking, audit logging, and error redaction.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
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.
Title check ✅ Passed The title clearly matches the main changes: MCP HTTP backend hardening, circuit breaking, audit logging, redaction, and reconnect behavior.
Description check ✅ Passed The PR description has a detailed Summary and Test plan and is mostly aligned with the template, though Notes for reviewers is missing.
✨ 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 gateway-parallel-reconnect

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (2)
crates/gateway-registry/src/audit.rs (1)

35-42: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Write each audit entry with a single append writeln!(f, "{line}") can split a JSONL record across multiple writes, and Registry::execute is &self, so concurrent calls can splice entries together. Format the line once, add \n, and call write_all.

🤖 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 `@crates/gateway-registry/src/audit.rs` around lines 35 - 42, The audit write
path in the `audit` module currently uses `writeln!` on the opened file handle,
which can issue multiple writes and allow concurrent `Registry::execute` calls
to interleave JSONL entries. Update the write logic in the `OpenOptions::open`
success branch to format the entry once, append a newline, and use a single
`write_all` call on `f`, keeping the existing open/error handling in place.
crates/gateway-registry/src/mcp_stdio.rs (1)

159-167: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Duplicated check-then-record wrapper between discover() and call().

Both methods repeat the identical check_circuit() → inner call → record_success/record_failure pattern. Could be extracted into a small private helper (e.g. with_circuit_breaker<T>(&self, fut: impl Future<Output = Result<T, GatewayError>>) -> Result<T, GatewayError>) to avoid the two copies drifting apart if the breaker logic changes again.

Also applies to: 212-220

🤖 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 `@crates/gateway-registry/src/mcp_stdio.rs` around lines 159 - 167, Both
`discover()` and `call()` in `McpStdioClient` duplicate the same circuit-breaker
wrapper logic, so extract that shared pattern into a small private helper (for
example a generic `with_circuit_breaker` method) and have both methods delegate
to it. Keep the helper responsible for `check_circuit()`, awaiting the inner
operation, and calling `record_success()` or `record_failure()` based on the
result so the behavior stays identical. This will keep the `discover_inner()`
and `call_inner()` paths aligned and prevent the breaker logic from drifting
between the two methods.
🤖 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 `@crates/gateway-registry/src/mcp_stdio.rs`:
- Around line 91-120: The circuit breaker in check_circuit(), record_success(),
and record_failure() currently releases the mutex before the actual
discover_inner/call_inner probe, so once opened_until expires multiple
concurrent callers can all pass through at once. Update check_circuit() to
re-arm the circuit while still holding the circuit lock as soon as the recovery
window has elapsed, so only the first caller proceeds and the others still see
the circuit as open. Keep the behavior aligned with the existing circuit state
in record_success() and record_failure(), and use the existing symbols
check_circuit, record_success, record_failure, and opened_until to make the fix
local to the current circuit logic.
- Around line 175-187: Treat the `Ok(Err(e))` branch in `mcp_stdio.rs` as a
protocol error rather than an automatic transport failure when `rmcp` can
distinguish them. Update the `Registry::execute`/stdio call path so only real
transport-level failures clear the cached connection and contribute to
circuit-breaker accounting, while clean RPC errors are returned without dropping
`guard` or forcing a reconnect. Use the existing `Ok(Err(e))` handling and
`GatewayError::Upstream` conversion point to preserve protocol errors while
avoiding breaker budget impact.

---

Nitpick comments:
In `@crates/gateway-registry/src/audit.rs`:
- Around line 35-42: The audit write path in the `audit` module currently uses
`writeln!` on the opened file handle, which can issue multiple writes and allow
concurrent `Registry::execute` calls to interleave JSONL entries. Update the
write logic in the `OpenOptions::open` success branch to format the entry once,
append a newline, and use a single `write_all` call on `f`, keeping the existing
open/error handling in place.

In `@crates/gateway-registry/src/mcp_stdio.rs`:
- Around line 159-167: Both `discover()` and `call()` in `McpStdioClient`
duplicate the same circuit-breaker wrapper logic, so extract that shared pattern
into a small private helper (for example a generic `with_circuit_breaker`
method) and have both methods delegate to it. Keep the helper responsible for
`check_circuit()`, awaiting the inner operation, and calling `record_success()`
or `record_failure()` based on the result so the behavior stays identical. This
will keep the `discover_inner()` and `call_inner()` paths aligned and prevent
the breaker logic from drifting between the two methods.
🪄 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 Plus

Run ID: 1dcc5e58-ec84-490b-9904-1de60c0633f0

📥 Commits

Reviewing files that changed from the base of the PR and between fe770fb and a90052b.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (13)
  • crates/gateway-registry/Cargo.toml
  • crates/gateway-registry/src/audit.rs
  • crates/gateway-registry/src/error.rs
  • crates/gateway-registry/src/lib.rs
  • crates/gateway-registry/src/mcp_stdio.rs
  • crates/gateway-registry/src/redact.rs
  • crates/gateway-registry/src/registry.rs
  • crates/gateway-registry/src/sanitize.rs
  • crates/gateway-registry/tests/fixtures/fixture_server.rs
  • crates/gateway-registry/tests/gateway_audit_log.rs
  • crates/gateway-registry/tests/mcp_stdio_circuit_breaker.rs
  • crates/gateway-registry/tests/mcp_stdio_reconnect.rs
  • src/mcp_server.rs

Comment thread crates/gateway-registry/src/mcp_stdio.rs Outdated
Comment thread crates/gateway-registry/src/mcp_stdio.rs
@getappz getappz changed the title Harden gateway-registry: parallel reconnect, circuit breaker, audit log, redaction Gateway: HTTP MCP backend, hardening (circuit breaker/audit/redaction), parallel reconnect Jul 9, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (3)
crates/gateway-registry/tests/mcp_stdio_reconnect.rs (1)

55-60: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Strengthen assertion to verify per-call correctness, not just success.

The test only checks is_ok(); it doesn't confirm each response's text matches its corresponding input index, so a bug that returns another request's response would not be caught.

♻️ Suggested strengthening
     let calls = (0..20).map(|i| {
         let backend = backend.clone();
-        async move { backend.call("echo", serde_json::json!({"text": i.to_string()})).await }
+        async move { (i, backend.call("echo", serde_json::json!({"text": i.to_string()})).await) }
     });
     let results = futures_util::future::join_all(calls).await;
-    assert!(results.iter().all(|r| r.is_ok()), "expected all concurrent calls to succeed: {results:?}");
+    for (i, result) in results {
+        let result = result.unwrap_or_else(|e| panic!("call {i} failed: {e:?}"));
+        let text = result.get(0).and_then(|c| c.get("text")).and_then(|t| t.as_str());
+        assert_eq!(text, Some(format!("echo: {i}").as_str()));
+    }
🤖 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 `@crates/gateway-registry/tests/mcp_stdio_reconnect.rs` around lines 55 - 60,
The test in mcp_stdio_reconnect.rs only verifies that backend.call("echo", ...)
succeeds, but it does not confirm each response matches the input for that
specific request. Strengthen the join_all assertion by checking each result from
the echo calls against its corresponding index string so request/response mixing
is caught, using the backend.call("echo", ...) and results values to verify
per-call correctness rather than only is_ok().
crates/gateway-registry/src/mcp_http.rs (1)

35-183: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚖️ Poor tradeoff

Significant structural duplication with mcp_stdio.rs.

ensure_connected/discover/discover_inner/call/call_inner here are nearly line-for-line identical in control flow to McpStdioBackend (circuit wrap, timeout handling, guard invalidation on error, args validation, result mapping) — only the transport construction and error message differ. Consider extracting the shared circuit-wrap-and-timeout skeleton (e.g. a small generic helper taking an async connect/call closure) to avoid maintaining two copies of this error-handling logic in lockstep.

Given this doubles the surface for the two backends to drift (e.g. one gets a bugfix the other doesn't), it's a worthwhile — though not urgent — cleanup.

🤖 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 `@crates/gateway-registry/src/mcp_http.rs` around lines 35 - 183, Extract the
shared circuit-breaker, timeout, guard-invalidation, and result-mapping flow
from McpHttpBackend methods like ensure_connected, discover_inner, and
call_inner into a reusable helper, so it mirrors the logic already in
McpStdioBackend without duplicating the same control flow. Keep the
backend-specific parts limited to transport creation and message formatting, and
have discover/call use the shared skeleton with closures or a small generic
wrapper to prevent the two backends from drifting.
crates/gateway-registry/src/config.rs (1)

25-40: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

auth_header isn't validated against auth_ref/auth_env.

parse()'s pairing check only inspects auth_ref/auth_env (Line 62-64); auth_header is discarded via ... So a config that sets auth_header alone (no auth_ref/auth_env) parses successfully, but per registry.rs::resolve_mcp_http_auth_header, the header is silently dropped since resolution only proceeds when both auth_ref and auth_env are Some. A user intending to authenticate would get no error at parse time and no header sent at runtime — a silent, hard-to-debug misconfiguration.

Consider rejecting (or at least the doc comment on Lines 31-38) auth_header set without auth_ref/auth_env, mirroring the existing IncompleteAuthConfig pattern.

Proposed validation addition
         let (auth_ref, auth_env) = match server {
             ServerConfig::McpStdio { auth_ref, auth_env, .. } => (auth_ref, auth_env),
-            ServerConfig::McpHttp { auth_ref, auth_env, .. } => (auth_ref, auth_env),
+            ServerConfig::McpHttp { auth_ref, auth_env, auth_header, .. } => {
+                if auth_header.is_some() && auth_ref.is_none() {
+                    return Err(ConfigError::IncompleteAuthConfig {
+                        server: name.clone(),
+                        auth_ref: auth_ref.clone(),
+                        auth_env: auth_env.clone(),
+                    });
+                }
+                (auth_ref, auth_env)
+            }
         };

Also applies to: 61-71

🤖 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 `@crates/gateway-registry/src/config.rs` around lines 25 - 40, `auth_header` is
currently accepted even when `auth_ref`/`auth_env` are missing, so the config
can parse but never produce an auth header. Update `parse()` in `config.rs` to
validate `auth_header` alongside the existing `IncompleteAuthConfig` pairing
check, and reject any `McpHttp` entry that sets `auth_header` without both
`auth_ref` and `auth_env`. Use the existing `McpHttp`, `IncompleteAuthConfig`,
and `resolve_mcp_http_auth_header` flow as the reference points, and align the
doc comment on `auth_header` with the new validation behavior.
🤖 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 `@crates/gateway-registry/src/mcp_stdio.rs`:
- Around line 167-175: The circuit-breaker accounting in call currently treats
all Err results as backend failures, but GatewayError::InvalidArgument should be
excluded because it is a local validation error. Update the match on result in
call to skip record_failure() when the error is InvalidArgument, and only count
real backend/service failures; apply the same fix in mcp_http::call so both
transport paths behave consistently.

---

Nitpick comments:
In `@crates/gateway-registry/src/config.rs`:
- Around line 25-40: `auth_header` is currently accepted even when
`auth_ref`/`auth_env` are missing, so the config can parse but never produce an
auth header. Update `parse()` in `config.rs` to validate `auth_header` alongside
the existing `IncompleteAuthConfig` pairing check, and reject any `McpHttp`
entry that sets `auth_header` without both `auth_ref` and `auth_env`. Use the
existing `McpHttp`, `IncompleteAuthConfig`, and `resolve_mcp_http_auth_header`
flow as the reference points, and align the doc comment on `auth_header` with
the new validation behavior.

In `@crates/gateway-registry/src/mcp_http.rs`:
- Around line 35-183: Extract the shared circuit-breaker, timeout,
guard-invalidation, and result-mapping flow from McpHttpBackend methods like
ensure_connected, discover_inner, and call_inner into a reusable helper, so it
mirrors the logic already in McpStdioBackend without duplicating the same
control flow. Keep the backend-specific parts limited to transport creation and
message formatting, and have discover/call use the shared skeleton with closures
or a small generic wrapper to prevent the two backends from drifting.

In `@crates/gateway-registry/tests/mcp_stdio_reconnect.rs`:
- Around line 55-60: The test in mcp_stdio_reconnect.rs only verifies that
backend.call("echo", ...) succeeds, but it does not confirm each response
matches the input for that specific request. Strengthen the join_all assertion
by checking each result from the echo calls against its corresponding index
string so request/response mixing is caught, using the backend.call("echo", ...)
and results values to verify per-call correctness rather than only is_ok().
🪄 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 Plus

Run ID: a8cff46c-9de7-4a68-969c-6bc69bc5c042

📥 Commits

Reviewing files that changed from the base of the PR and between a90052b and 678c7a4.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (14)
  • crates/gateway-registry/Cargo.toml
  • crates/gateway-registry/src/backend.rs
  • crates/gateway-registry/src/circuit.rs
  • crates/gateway-registry/src/config.rs
  • crates/gateway-registry/src/lib.rs
  • crates/gateway-registry/src/mcp_http.rs
  • crates/gateway-registry/src/mcp_stdio.rs
  • crates/gateway-registry/src/registry.rs
  • crates/gateway-registry/tests/mcp_http_call.rs
  • crates/gateway-registry/tests/mcp_http_circuit_breaker.rs
  • crates/gateway-registry/tests/mcp_http_discover.rs
  • crates/gateway-registry/tests/mcp_stdio_reconnect.rs
  • crates/gateway-registry/tests/registry.rs
  • crates/gateway-registry/tests/support/mod.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • crates/gateway-registry/src/registry.rs

Comment on lines 167 to +175
pub async fn call(&self, tool: &str, args: Value) -> Result<Value, GatewayError> {
self.ensure_connected().await?;
let mut guard = self.running.lock().await;
let running = guard.as_ref().expect("connected above");
self.circuit.check(&self.command).await?;
let result = self.call_inner(tool, args).await;
match &result {
Ok(_) => self.circuit.record_success().await,
Err(_) => self.circuit.record_failure().await,
}
result
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Map the relevant file and surrounding symbols first.
ast-grep outline crates/gateway-registry/src/mcp_stdio.rs --view expanded || true
printf '\n---\n'
ast-grep outline crates/gateway-registry/src/mcp_http.rs --view expanded || true
printf '\n---\n'
ast-grep outline crates/gateway-registry/src/error.rs --view expanded || true
printf '\n---\n'

# Show the relevant sections with line numbers.
sed -n '1,260p' crates/gateway-registry/src/mcp_stdio.rs | nl -ba | sed -n '1,260p'
printf '\n=== mcp_http.rs ===\n'
sed -n '1,280p' crates/gateway-registry/src/mcp_http.rs | nl -ba | sed -n '1,280p'
printf '\n=== error.rs ===\n'
sed -n '1,220p' crates/gateway-registry/src/error.rs | nl -ba | sed -n '1,220p'

# Search for InvalidArgument and circuit accounting elsewhere.
printf '\n=== InvalidArgument references ===\n'
rg -n "InvalidArgument|record_failure\(|record_success\(" crates/gateway-registry/src

Repository: getappz/agentflare

Length of output: 2468


🏁 Script executed:

#!/bin/bash
set -euo pipefail

ast-grep outline crates/gateway-registry/src/mcp_stdio.rs --view expanded || true
printf '\n---\n'
ast-grep outline crates/gateway-registry/src/mcp_http.rs --view expanded || true
printf '\n---\n'
ast-grep outline crates/gateway-registry/src/error.rs --view expanded || true
printf '\n---\n'

sed -n '1,260p' crates/gateway-registry/src/mcp_stdio.rs | nl -ba | sed -n '1,260p'
printf '\n=== mcp_http.rs ===\n'
sed -n '1,280p' crates/gateway-registry/src/mcp_http.rs | nl -ba | sed -n '1,280p'
printf '\n=== error.rs ===\n'
sed -n '1,220p' crates/gateway-registry/src/error.rs | nl -ba | sed -n '1,220p'

printf '\n=== InvalidArgument references ===\n'
rg -n "InvalidArgument|record_failure\(|record_success\(" crates/gateway-registry/src

Repository: getappz/agentflare

Length of output: 2468


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Show the relevant function bodies with line numbers.
awk 'NR>=150 && NR<=220 {printf "%4d  %s\n", NR, $0}' crates/gateway-registry/src/mcp_stdio.rs
printf '\n=== mcp_http.rs ===\n'
awk 'NR>=120 && NR<=190 {printf "%4d  %s\n", NR, $0}' crates/gateway-registry/src/mcp_http.rs
printf '\n=== error.rs ===\n'
awk 'NR>=1 && NR<=80 {printf "%4d  %s\n", NR, $0}' crates/gateway-registry/src/error.rs

printf '\n=== InvalidArgument usage ===\n'
rg -n "InvalidArgument" crates/gateway-registry/src

printf '\n=== CircuitBreaker usage/definition ===\n'
rg -n "struct CircuitBreaker|impl CircuitBreaker|record_failure|record_success|check\(" crates/gateway-registry/src crates -g '!target'

Repository: getappz/agentflare

Length of output: 17143


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Show the relevant function bodies with line numbers.
awk 'NR>=150 && NR<=220 {printf "%4d  %s\n", NR, $0}' crates/gateway-registry/src/mcp_stdio.rs
printf '\n=== mcp_http.rs ===\n'
awk 'NR>=120 && NR<=190 {printf "%4d  %s\n", NR, $0}' crates/gateway-registry/src/mcp_http.rs
printf '\n=== error.rs ===\n'
awk 'NR>=1 && NR<=80 {printf "%4d  %s\n", NR, $0}' crates/gateway-registry/src/error.rs

printf '\n=== InvalidArgument usage ===\n'
rg -n "InvalidArgument" crates/gateway-registry/src

printf '\n=== CircuitBreaker usage/definition ===\n'
rg -n "struct CircuitBreaker|impl CircuitBreaker|record_failure|record_success|check\\(" crates/gateway-registry/src crates -g '!target'

Repository: getappz/agentflare

Length of output: 17143


🏁 Script executed:

#!/bin/bash
set -euo pipefail

awk 'NR>=1 && NR<=160 {printf "%4d  %s\n", NR, $0}' crates/gateway-registry/src/circuit.rs

Repository: getappz/agentflare

Length of output: 4694


Skip circuit-breaker failure accounting for InvalidArgument
GatewayError::InvalidArgument is a local, pre-flight validation error, not a backend failure. Counting it in record_failure() lets a few malformed calls open the breaker against a healthy backend. Apply the same guard in mcp_http.rs::call.

🤖 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 `@crates/gateway-registry/src/mcp_stdio.rs` around lines 167 - 175, The
circuit-breaker accounting in call currently treats all Err results as backend
failures, but GatewayError::InvalidArgument should be excluded because it is a
local validation error. Update the match on result in call to skip
record_failure() when the error is InvalidArgument, and only count real
backend/service failures; apply the same fix in mcp_http::call so both transport
paths behave consistently.

@getappz
getappz merged commit 2889d6d into master Jul 9, 2026
10 checks passed
@getappz
getappz deleted the gateway-parallel-reconnect branch July 9, 2026 05:21
getappz added a commit that referenced this pull request Aug 14, 2026
…t win (#488)

self_repair_or_gate only checked the local job queue for an in-flight
dispatch, not the item-level claim ledger. A finished job's claim
outliving its (#108-capped) in_review TTL looked like "nothing in
flight", so the sweep dispatched anyway -- the job died instantly at
its own claim-acquire step, still counting the attempt against the
3-try cap. Now it checks claim liveness before dispatching and defers
(retrying next sweep) instead of burning a cap slot on an attempt that
never had a chance.

Agentflare-Agent: claude-code
Agentflare-Branch: task/114-ci-self-repair-burns-its-3-attempt-cap-d
Agentflare-Item: 114

Co-authored-by: shiva <shiva@gosysinfo.tech>
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.

1 participant