MCP server for Raposa Aval: give your agent a request_human_approval tool with a signed audit trail.
Three tools with complete schemas and descriptions, but significant gaps in parameter documentation and output schema clarity. Tool names follow verb_noun convention (create_approval, get_approval, request_human_approval). Descriptions are present (80-180 chars) but lack actionable guidance on when to use each tool vs. alternatives. Parameters have types but most lack descriptions in the schema (only visible in docstrings). Output is JSON-serialized strings rather than structured objects. Error handling converts ToolError to RuntimeError without recovery guidance. No tool annotations (readOnlyHint, destructiveHint, idempotentHint). Missing parameter constraints (enums for 'risk', bounds for 'wait_sec'/'expires_in_sec'). API key injection via environment is correct, but no audit logging visible.
Create an approval request and return its id immediately (no waiting). Use with a webhook_url, or poll with get_approval. risk: low | medium | high.
Read an approval by id. Look at `approved` — it is true only when a human approved.
Ask an authorised human to approve an action and wait for the answer. Returns {approved: bool, status, decided_by, ...}. Proceed ONLY if approved is true — a timeout, an expiry or a rejection means do not proceed. risk: low | medium | high.
Parameter descriptions missing from JSON Schema. 'risk', 'requested_by', 'expires_in_sec', 'webhook_url', 'wait_sec' have no descriptions in the @mcp.tool() decorator schema, only in docstrings. LLMs cannot see docstring text; they parse JSON Schema. This forces LLMs to guess parameter meaning.
'risk' parameter accepts only 'low', 'medium', 'high' but is defined as free-form string. Should be an enum constraint in schema. Current implementation validates at runtime (ToolError), but LLMs cannot see the constraint and may hallucinate invalid values.
Output schema not documented. All three tools return JSON-serialized strings (json.dumps()) rather than structured objects. LLMs cannot parse the response schema from the tool definition, they must infer it from examples. Expected fields: 'id', 'status', 'approved', 'decided_by', 'decided_at', 'comment', 'message' are not declared.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | C | 60 | 2026-07-28+ | v2 |
No tool annotations. 'get_approval' is read-only (should have readOnlyHint=true). 'create_approval' and 'request_human_approval' are destructive/state-modifying (should have destructiveHint=true). 'request_human_approval' is idempotent if called with same approval_id (should have idempotentHint=true). Annotations help LLMs reason about retry safety and side effects.
Error handling converts ToolError to RuntimeError without recovery guidance. When RAPOSA_API_KEY is missing or API returns 400+, the error message is included but LLM receives no actionable next step (e.g., 'Set RAPOSA_API_KEY environment variable' or 'Try again in 60 seconds'). Errors should classify as retryable, user-fixable, or fatal.