fix(gitea-mcp): address MCP tool issues from Sprint 6

Fixes #281 - Multiple MCP tool issues discovered during sprint execution

## Changes

1. **list_issues Token Overflow** (Issue 1)
   - Added `milestone` parameter to filter issues server-side
   - Reduces response size by filtering at API level instead of client-side

2. **Type Coercion for MCP Serialization** (Issues 2 & 4)
   - Added `_coerce_types()` helper function in server.py
   - Handles integers passed as strings (milestone_id, issue_number, etc.)
   - Handles arrays passed as JSON strings (labels, tags, etc.)
   - Applied to all tool calls automatically

3. **Sprint Approval Check Clarification** (Issue 3)
   - Updated sprint-start.md to clarify approval is RECOMMENDED, not enforced
   - Changed STOP/block language to WARN/suggest language
   - Added note explaining this is workflow guidance, not code-enforced

## Files Changed
- mcp-servers/gitea/mcp_server/gitea_client.py: Added milestone param
- mcp-servers/gitea/mcp_server/tools/issues.py: Pass milestone param
- mcp-servers/gitea/mcp_server/server.py: Type coercion + milestone schema
- plugins/projman/commands/sprint-start.md: Clarified approval check

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-28 15:57:42 -05:00
parent 5638891d01
commit e56d685a68
4 changed files with 70 additions and 16 deletions

View File

@@ -26,6 +26,44 @@ logging.getLogger("mcp").setLevel(logging.ERROR)
logger = logging.getLogger(__name__)
def _coerce_types(arguments: dict) -> dict:
"""
Coerce argument types to handle MCP serialization quirks.
MCP sometimes passes integers as strings and arrays as JSON strings.
This function normalizes them to the expected Python types.
"""
coerced = {}
for key, value in arguments.items():
if value is None:
coerced[key] = value
continue
# Coerce integer fields
int_fields = {'issue_number', 'milestone_id', 'pr_number', 'depends_on', 'milestone', 'limit'}
if key in int_fields and isinstance(value, str):
try:
coerced[key] = int(value)
continue
except ValueError:
pass
# Coerce array fields that might be JSON strings
array_fields = {'labels', 'tags', 'issue_numbers', 'comments'}
if key in array_fields and isinstance(value, str):
try:
parsed = json.loads(value)
if isinstance(parsed, list):
coerced[key] = parsed
continue
except json.JSONDecodeError:
pass
coerced[key] = value
return coerced
class GiteaMCPServer:
"""MCP Server for Gitea integration"""
@@ -88,6 +126,10 @@ class GiteaMCPServer:
"items": {"type": "string"},
"description": "Filter by labels"
},
"milestone": {
"type": "string",
"description": "Filter by milestone title (exact match)"
},
"repo": {
"type": "string",
"description": "Repository name (for PMO mode)"
@@ -899,6 +941,9 @@ class GiteaMCPServer:
List of TextContent with results
"""
try:
# Coerce types to handle MCP serialization quirks
arguments = _coerce_types(arguments)
# Route to appropriate tool handler
if name == "list_issues":
result = await self.issue_tools.list_issues(**arguments)