Skip to content

Merge branch 'master' into TT-16566-mcp-policy-filter-tools-resource-…

47582c7
Select commit
Loading
Failed to load commit list.
Merged

[TT-16566] mcp policy filter tools resource prompt lists #7868

Merge branch 'master' into TT-16566-mcp-policy-filter-tools-resource-…
47582c7
Select commit
Loading
Failed to load commit list.
probelabs / Visor: performance failed Apr 16, 2026 in 1m 15s

🚨 Check Failed

performance check failed because fail_if condition was met.

Details

📊 Summary

  • Total Issues: 4
  • Error Issues: 2
  • Warning Issues: 2

🔍 Failure Condition Results

Failed Conditions

  • global_fail_if: output.issues && output.issues.some(i => i.severity === 'critical' || i.severity === 'error')
    • Severity: ❌ error

Issues by Category

Performance (3)

  • internal/mcp/list_filter.go:83 - The FilterItems function exhibits an N+1 JSON parsing anti-pattern. It iterates over a slice of json.RawMessage and calls ExtractStringField for each item. ExtractStringField in turn calls json.Unmarshal on each item's raw JSON just to extract a single field. For a list of N items, this results in at least N separate unmarshaling operations within a loop, which is highly inefficient and leads to excessive allocations and CPU usage, especially for large lists.
  • ⚠️ internal/mcp/list_filter.go:205 - The matchPattern function calls regexp.Compile on every invocation. This function is called within a loop in CheckAccessControlRules for each access control pattern against each item in the list. While the tyk/regexp package provides caching, this still results in repeated cache lookup overhead (map access, mutex locks) in a hot path. For a list of 1000 items and 10 rules, this can be called 10,000 times per request.
  • ⚠️ gateway/res_handler_mcp_list_filter.go:65 - The HandleResponse function reads the entire response body into memory via readAndCloseBody (io.ReadAll) before filtering. For very large list responses, this can cause significant memory allocations and put pressure on the garbage collector. While the author's performance analysis notes this is acceptable for the current expected scale, it presents a potential scalability risk if list sizes grow significantly.

Logic (1)

  • system:0 - Global failure condition met: output.issues && output.issues.some(i => i.severity === 'critical' || i.severity === 'error')

Powered by Visor from Probelabs

💡 TIP: You can chat with Visor using /visor ask <your question>

Annotations

Check failure on line 83 in internal/mcp/list_filter.go

See this annotation in the file changed.

@probelabs probelabs / Visor: performance

performance Issue

The `FilterItems` function exhibits an N+1 JSON parsing anti-pattern. It iterates over a slice of `json.RawMessage` and calls `ExtractStringField` for each item. `ExtractStringField` in turn calls `json.Unmarshal` on each item's raw JSON just to extract a single field. For a list of N items, this results in at least N separate unmarshaling operations within a loop, which is highly inefficient and leads to excessive allocations and CPU usage, especially for large lists.
Raw output
Refactor the filtering logic to avoid unmarshaling each item individually inside the loop. Instead, unmarshal the entire list into a structured Go type (e.g., `[]map[string]any`) once. Then, iterate over this slice, perform the filtering by accessing the fields via map lookups, and finally, re-marshal the filtered slice back to JSON. This changes the complexity from O(N * M) where M is item parsing cost, to O(N) for filtering after a single initial parse.

Check warning on line 205 in internal/mcp/list_filter.go

See this annotation in the file changed.

@probelabs probelabs / Visor: performance

performance Issue

The `matchPattern` function calls `regexp.Compile` on every invocation. This function is called within a loop in `CheckAccessControlRules` for each access control pattern against each item in the list. While the `tyk/regexp` package provides caching, this still results in repeated cache lookup overhead (map access, mutex locks) in a hot path. For a list of 1000 items and 10 rules, this can be called 10,000 times per request.
Raw output
Pre-compile all regex patterns from the `user.AccessControlRules` once per request, before starting the item filtering loop. The resulting `*regexp.Regexp` objects can be stored in a temporary struct or slice and reused for all items in that request. This avoids the overhead of repeated compilation or cache lookups inside the main filtering loop.

Check warning on line 65 in gateway/res_handler_mcp_list_filter.go

See this annotation in the file changed.

@probelabs probelabs / Visor: performance

performance Issue

The `HandleResponse` function reads the entire response body into memory via `readAndCloseBody` (`io.ReadAll`) before filtering. For very large list responses, this can cause significant memory allocations and put pressure on the garbage collector. While the author's performance analysis notes this is acceptable for the current expected scale, it presents a potential scalability risk if list sizes grow significantly.
Raw output
For future optimization, consider replacing the full-body read with a streaming JSON parser. This would allow filtering the list without holding the entire response in memory, albeit at the cost of increased implementation complexity. No immediate action is required, but this should be monitored.