Static source inference · medium confidence · detected: Logging
Deprecated protocol patterns detected
Summary
Lex API exposes 14 tools for UK legislative and caselaw research. Critical issues: (1) Tool definitions are inferred from route files and package.json rather than explicitly visible in source code, no MCP tool registration schema found. (2) Input schemas are severely underspecified, tools reference abstract query objects (AmendmentSearch, CaselawSearch, etc.) without revealing their internal structure, parameter names, or constraints. (3) Parameter descriptions are absent for nested objects. (4) Tool descriptions are generic and lack domain context, LLM guidance, or when-to-use hints. (5) No output schemas documented. (6) No error handling guidance. This server appears to be primarily a FastAPI/Next.js application with MCP wrapper functionality, but the MCP tool definitions themselves are not fully visible in the provided source snippets. Scoring is conservative because tool registration code, actual schema definitions, and complete parameter metadata cannot be verified.
Input schemas are not visible or verifiable. All 14 tools declare nested object parameters (AmendmentSearch, CaselawSearch, etc.) but their internal structure, required fields, allowed enums, and constraints are not revealed in the provided source. Per the rubric, if a tool has NO visible input schema, its schema score MUST be 0.
Tool definitions appear to be inferred from route file references and package.json dependencies rather than explicitly visible MCP tool registration code. The source provided does not show actual MCP tool definition objects, tool registration calls, or handler implementations.
Recommendations
Publish complete MCP tool registration code. Show the actual fastmcp @tool decorators or MCP server handlers with full schema definitions, not inferred route mappings.
Expand all nested object parameters into explicit flattened parameters with enums and constraints. E.g., for search_amendments, replace 'search: AmendmentSearch' with discrete parameters: amendment_type (enum: act|si|statutory_instrument), search_text (string, max 500), year_from (int, min 1800), year_to (int, max current year), etc.
Rewrite descriptions as LLM-optimized prompts. Example: 'search_amendments: Find amendments to UK Acts and Statutory Instruments by keyword, title, or affected legislation ID. Use this before search_for_legislation_acts to understand how a law has changed. Returns amendment ID, title, year, affected legislation ID, and summary. Limit 50 results; use page/offset for more.'
Document output schemas for every tool using JSON Schema. Example for search_amendments: '{"type": "object", "properties": {"amendments": {"type": "array", "items": {"type": "object", "properties": {"amendment_id": {"type": "string"}, "title": {"type": "string"}, "year": {"type": "integer"}, "affected_legislation_id": {"type": "string"}, "summary": {"type": "string"}}}}, "total_count": {"type": "integer"}, "page": {"type": "integer"}, "limit": {"type": "integer"}}'.
Remove duplicate tools. Alias search_caselaw_by_reference to search_for_caselaw_by_reference and delete the duplicate entry.
Standardize tool naming: use either search_* or search_for_* consistently. Recommend search_* for brevity (13 chars vs 16 chars average name length from production baselines).
Spec posture evidence
Inferred effective spec: 2026-07-28+.
Relies on Logging (deprecated) - log to stderr or use OpenTelemetry
Find cases by AI-generated summaries. Returns concise results suitable for AI agents. Summaries include material facts, legal issues, ratio decidendi, reasoning, and obiter dicta.
Descriptions are generic and lack domain context. E.g., 'Find amendments to Acts and SIs by content, title, or affected legislation' does not explain when an LLM should call this vs. search_for_legislation_acts or other tools. No LLM-optimized guidance on what the tool returns or how to use results downstream. Average description length is ~40 chars; baseline for A+ tools is 50-200 chars.
No output schemas documented. LLMs cannot plan downstream tool calls or extract expected fields if they don't know what a tool returns. search_for_caselaw returns 'cases with match scores and metadata' but field names, types, and structure are undocumented.
Duplicate or near-duplicate tools. search_for_caselaw_by_reference and search_caselaw_by_reference have identical descriptions and appear to do the same thing. This violates the single-responsibility principle and forces LLMs to reason about which to use.
Parameter descriptions missing for nested objects. All tools accept complex query objects (e.g., AmendmentSearch, CaselawSearch) but the internal parameter structure is not documented. LLMs have no way to know what fields these objects expect.
No error handling guidance. Tools do not document what errors are possible, whether they are retryable, or what recovery steps the LLM should take. A failed search returns no actionable error message.
Tool names are inconsistent. Some use search_for_* (search_for_caselaw) and others use search_* (search_amendments). This forces LLMs to learn multiple naming conventions for semantically similar operations.
No pagination guidance. Search tools do not document how many results they return, whether results are paginated, or how to request additional pages. This risks context explosion or incomplete result sets.
Add pagination parameters to all search tools. Include limit (1-100, default 20), offset (int, min 0), and sort_by (enum: relevance|date|title). Return total_count and next_offset in responses.
Add error handling documentation. Example: 'Returns 400 if search_text is empty or > 500 chars. Returns 404 if amendment_id not found with suggestion: "Did you mean: [similar_amendment_ids]?". Returns 503 if backend service unavailable, retry after 30s.'
Add tool annotations for MCP spec compliance. Mark read-only tools with readOnlyHint: true. Consider idempotentHint for lookup tools.
Document API rate limits and timeout behavior. E.g., 'Each search call counts as 1 quota unit. Max 100 requests/minute per client. Timeout: 30s.'
Separate query complexity. Create a discovery tool like list_amendment_types() or describe_caselaw_filters() to help LLMs understand available search parameters without needing to know the schema.
Return chaining IDs. If a user calls search_for_caselaw and later wants to fetch metadata via proxy_caselaw_data, ensure case_id is always returned in search results.
Add examples to descriptions (as separate field, not embedded text). E.g., 'examples': [{'search_text': 'employment rights', 'year_from': 2020}]. LLMs will consult examples only if explicitly provided, reducing hallucination of example values in real calls.