Multi-agent code review MCP server with consensus voting. N agents analyze code, synthesize findings, vote on suggestions, and return ranked improvements.
Council Review exposes 4 tools via FastMCP with partial schema documentation. Tool names are reasonably clear (council, council_test, council_health, council_history) but descriptions vary in quality. The primary 'council' tool has a detailed description (187 chars) and complete input schema with enums and type constraints. However, 'council_test' and 'council_health' have minimal descriptions (47 and 56 chars respectively, below the 50-200 char baseline for LLM optimization). No output schemas are documented for any tool, LLMs cannot plan downstream operations or structure parsing without knowing what fields to expect. Error handling is present (input validation, rate limiting, error messages) but generic and non-actionable in most cases. Tool composition is reasonable, each tool has a single responsibility, but the lack of documented output structure and interdependencies weakens chainability. Security is addressed via denylist injection and sanitization, but the codebase shows the server operates as STDIO-only, which is a hard architectural limitation.
Multi-agent expert council: N agents analyze -> synthesize -> vote -> ranked improvements. Args: request (Review question or task), file_paths (File or folder paths, comma-separated), output_format ("markdown" or "json"), mode ("full" or "quick").
Health check: validate config, verify LLM endpoints, check API keys. Returns diagnostic report.
Query persistent session history. Lists recent reviews or retrieves full report for a session ID.
Test council pipeline on sample code. Returns analysis and suggestions without full voting.
Output schemas not documented for any tool. LLMs cannot plan multi-step operations or extract required fields without knowing what the response contains. For example, 'council' returns a report string but does not document whether it includes session_id, timestamp, or other fields needed for downstream calls to council_history.
council_test and council_health have minimal descriptions (47 and 56 characters, below the 50-200 char baseline). Descriptions lack context for when to use them vs alternatives. 'Test council pipeline on sample code' does not explain what sample code is used, what 'analysis and suggestions' means structurally, or when an LLM should call this vs the main 'council' tool.
council_test input schema is empty ({}) but the description says it returns 'analysis and suggestions without full voting.' This mismatch is confusing: does it accept no parameters, or are they optional? The empty schema violates the principle that every tool with output should declare what inputs shape that output.
Inferred effective spec: <=2025-11-25.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-22 | F | 40 | <=2025-11-25 | v2 |
| 2026-03-09 | F | 17 | - | v1 |
council_health input schema is empty ({}) but should document what kind of 'diagnostic report' is returned. Without knowing the output structure (config validity, endpoint status, API key validation results), LLMs cannot parse or act on the report.
Error messages are present but generic. 'Rate limit exceeded. Please wait before retrying.' does not tell the LLM how long to wait, whether to retry immediately, or what the actual rate limit is. 'Empty request. Please provide a review question.' is somewhat better but lacks guidance on what constitutes a valid request length or complexity.
council tool accepts 'file_paths' as a comma-separated string but does not document allowed path formats (relative vs absolute), maximum total path length, or behavior when a path does not exist. The validation error 'Too many file paths' is helpful but other edge cases (invalid paths, permission denied, unsupported file types) are not documented.
council tool supports 'quick' mode which silently slices the council.members list. This behavior is not obvious from the mode parameter description. 'quick (first N agents, faster)' suggests N is a magic number the LLM does not control. The code shows quick_size comes from config.settings but the parameter description does not explain this dependency.
council_history accepts optional session_id or lists recent sessions if omitted, but the parameter description does not clarify the mutual exclusivity or behavior. Does passing session_id=0 list recent? Does passing session_id and limit have interaction? The description should state: 'If session_id is provided, retrieve that specific report and ignore limit. If omitted, list the most recent sessions up to limit.'