feat(mcp): cap MCP batch tool at MAX_BATCH_OPERATIONS (PRJ-22)

- enforce the same 100-operation cap the HTTP /batch endpoint enforces;
  over-cap \x60calls\x60 reject with a structured INVALID_INPUT (retryable:
  false, matching CallError::invalid_input) before any dispatch
- hoist MAX_BATCH_OPERATIONS to gateway/mod.rs and reuse it in routes,
  to_openapi (removing a pre-existing duplicate literal), and to_mcp
- state the limit in the batch tool description and add maxItems to the
  input schema (doc previously advertised no limit)
- GatewayDispatch gains a per-instance invoke_count spy accessor so the
  over-cap test proves zero dispatches (process-global counters raced
  under the parallel test runner)
- tests: over-cap -> INVALID_INPUT + invoke_count()==0; at-cap -> 100
  results + invoke_count()==100

verification: scripts/verify.sh (352 passed) and scripts/verify.sh
--all-features (468 passed); cargo clippy --all-targets -D warnings and
cargo fmt --check clean
This commit is contained in:
2026-08-30 22:51:06 +00:00
parent 8261fefd8f
commit 4f644a4c2c
5 changed files with 101 additions and 6 deletions
+1 -2
View File
@@ -60,6 +60,7 @@ use alkcall::registry::registration::OperationRegistry;
use alkcall::registry::spec::ErrorDefinition;
use super::openapi_spec::OpenAPISpec;
use crate::gateway::MAX_BATCH_OPERATIONS;
const GATEWAY_VERSION: &str = "1.2.0";
const GATEWAY_TITLE: &str = "alk gateway";
@@ -93,8 +94,6 @@ const SCHEME_BEARER: &str = "bearerAuth";
const RESPONSE_REF: &str = "#/components/schemas/";
const MAX_BATCH_OPERATIONS: usize = 100;
/// Project the registry into the fixed 6-endpoint gateway doc (ADR-042).
///
/// Returns [`AdapterError::SchemaParse`] if the generated doc does not