Skip to content

fix(mcp): validate search_graph inputs before Zep API calls#548

Open
vedikatai wants to merge 2 commits into
getzep:mainfrom
vedikatai:fix/input-validation
Open

fix(mcp): validate search_graph inputs before Zep API calls#548
vedikatai wants to merge 2 commits into
getzep:mainfrom
vedikatai:fix/input-validation

Conversation

@vedikatai

Copy link
Copy Markdown

Summary

Adds defensive input validation to the Go MCP server search_graph handler so malformed or abusive tool arguments are rejected before they reach the Zep API.

This closes a validation gap where SearchGraphInput fields were passed through with no bounds checking, empty-string checks, or max-length enforcement.

Security rationale

The MCP server is an untrusted boundary: clients (agents, IDEs, scripts) can send arbitrary tool arguments. Without local validation:

  1. Empty / whitespace-only queries waste API quota and can surface confusing downstream errors.
  2. Oversized queries (>2000 characters) increase request payload size and can stress embedding/search backends.
  3. Out-of-range limit (negative or very large) can cause unintended expensive scans or invalid API calls.
  4. Out-of-range min_fact_rating (the score threshold field on this tool) can send nonsensical filter values to the API.

Failing fast with clear fmt.Errorf messages matches existing handler/transform error patterns and keeps bad inputs out of the network path.

Changes

SearchGraphInput.Validate()mcp/zep-mcp-server/internal/handlers/types.go

New method enforces:

Rule Behavior
Empty / whitespace-only query rejected (query cannot be empty)
query > 2000 runes rejected (query exceeds maximum length of 2000 characters)
Explicit limit outside 1–100 rejected (limit must be between 1 and 100); 0 remains the "use default" sentinel
min_fact_rating outside [0.0, 1.0] rejected (min_fact_rating must be between 0 and 1); 0 still means omitted

Constants: searchQueryMaxLen, searchLimitMin/Max, searchMinScoreMin/Max (lines 10–16 in types.go).

Error style mirrors internal/transform.ValidateRequired (fmt.Errorf("... cannot be empty"), etc.).

Handler wiring — mcp/zep-mcp-server/internal/handlers/search.go

HandleSearchGraph now calls input.Validate() before applying defaults and building zep.GraphSearchQuery (lines 17–19), so explicit out-of-range limits are rejected rather than being overwritten by defaults.

Graph handler (graph.go) check

There is no internal/handlers/graph.go in this package. Graph search is implemented only in:

  • search.goHandleSearchGraph (the tool fixed here)
  • Read-only graph entity handlers (nodes.go, edges.go, episodes.go, node_detail.go, edge_detail.go, episode_detail.go, node_edges.go, episode_mentions.go) which take UUIDs/IDs/limits only and do not accept free-text search queries or score thresholds

So the validation gap was specific to search_graph, not a missing parallel graph.go file.

Tests added

All in existing mcp/zep-mcp-server/internal/handlers/types_test.go via new TestSearchGraphInputValidate (table-driven, same style as TestGetUserInputValidation):

Valid

  • valid minimal query
  • valid query with surrounding whitespace
  • valid query at max length (2000 chars)
  • valid limit omitted (zero uses handler default)
  • valid limit at minimum boundary (1)
  • valid limit at maximum boundary (100)
  • valid min_fact_rating omitted (zero)
  • valid min_fact_rating at minimum boundary (0.0)
  • valid min_fact_rating at maximum boundary (1.0)
  • valid min_fact_rating mid range (0.5)
  • limit zero is default sentinel not error

Invalid

  • empty query
  • whitespace only query
  • query exceeds max length (2001 chars)
  • limit below minimum (-1)
  • limit above maximum (101)
  • min_fact_rating below minimum (-0.01)
  • min_fact_rating above maximum (1.01)

Verification

cd mcp/zep-mcp-server && go test ./...

All packages pass locally.

Test plan

  • go test ./... under mcp/zep-mcp-server passes
  • Empty/whitespace query rejected before API call
  • Query length boundary at 2000 / 2001
  • Limit boundaries: 0 (default ok), 1, 100 ok; -1, 101 rejected
  • min_fact_rating boundaries: 0, 1 ok; -0.01, 1.01 rejected
  • CI green on this PR

Reject empty/whitespace queries, queries over 2000 runes, limit values
outside 1-100 when explicitly set, and min_fact_rating outside [0,1].
Mirrors existing fmt.Errorf validation style used in transform package.
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