Skip to content

Commit 629ae6d

Browse files
Peterclaude
andcommitted
fix: resolve MCP manifest validation errors for use_cases and examples fields
- Increase use_cases maxItems constraint from 3 to 5 to match actual usage - Add field_validator for string array length validation (max 200 chars per item) - Implement smart truncation at word boundaries with ellipsis - Fix imports to include ValidationInfo from pydantic - Reduce start_pre_ingestion examples from 4 to 3 to comply with constraints - Handle various input types (string/list) for MCP client compatibility Fixes validation error: "['Understanding API evolution...'] is too long" 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 61f0163 commit 629ae6d

File tree

2 files changed

+52
-4
lines changed

2 files changed

+52
-4
lines changed

src/docsrs_mcp/app.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -652,8 +652,7 @@ async def get_mcp_manifest(request: Request):
652652
),
653653
examples=[
654654
"start_pre_ingestion()",
655-
"start_pre_ingestion(force=true)",
656-
"start_pre_ingestion(concurrency=5)",
655+
"start_pre_ingestion(force=true, concurrency=5)",
657656
"start_pre_ingestion(count=200, concurrency=5)",
658657
],
659658
use_cases=[

src/docsrs_mcp/models.py

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,14 @@
1010
from enum import Enum
1111
from typing import Any, Literal
1212

13-
from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator
13+
from pydantic import (
14+
BaseModel,
15+
ConfigDict,
16+
Field,
17+
ValidationInfo,
18+
field_validator,
19+
model_validator,
20+
)
1421

1522
from . import config as app_config
1623
from .validation import validate_crate_name, validate_rust_path, validate_version_string
@@ -56,11 +63,53 @@ class MCPTool(BaseModel):
5663
use_cases: list[str] | None = Field(
5764
None,
5865
description="Common use cases for this tool",
59-
json_schema_extra={"maxItems": 3},
66+
json_schema_extra={"maxItems": 5}, # Increased to match actual usage
6067
)
6168

6269
model_config = ConfigDict(extra="forbid")
6370

71+
@field_validator("use_cases", "examples", mode="before")
72+
@classmethod
73+
def validate_string_arrays(
74+
cls, v: Any, info: ValidationInfo
75+
) -> list[str] | None:
76+
"""Validate string arrays with length constraints."""
77+
if v is None:
78+
return None
79+
80+
# Handle string input (split by newlines or commas)
81+
if isinstance(v, str):
82+
v = [
83+
item.strip() for item in v.replace("\n", ",").split(",") if item.strip()
84+
]
85+
86+
# Ensure list type
87+
if not isinstance(v, list):
88+
v = [v]
89+
90+
# Validate constraints
91+
field_name = info.field_name
92+
max_items = 5 if field_name == "use_cases" else 3
93+
max_length = 200 # Reasonable limit for individual strings
94+
95+
if len(v) > max_items:
96+
raise ValueError(
97+
f"{field_name} cannot exceed {max_items} items (got {len(v)})"
98+
)
99+
100+
# Validate and truncate individual strings
101+
validated = []
102+
for i, item in enumerate(v):
103+
item_str = str(item).strip()
104+
if len(item_str) > max_length:
105+
# Truncate at word boundary with ellipsis
106+
truncated = item_str[: max_length - 3].rsplit(" ", 1)[0] + "..."
107+
validated.append(truncated)
108+
else:
109+
validated.append(item_str)
110+
111+
return validated if validated else None
112+
64113

65114
class MCPResource(BaseModel):
66115
"""

0 commit comments

Comments
 (0)