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

Merged
lmiranda merged 1 commits from fix/281-mcp-tool-issues into development 2026-01-28 21:48:07 +00:00
4 changed files with 70 additions and 16 deletions

View File

@@ -53,6 +53,7 @@ class GiteaClient:
self,
state: str = 'open',
labels: Optional[List[str]] = None,
milestone: Optional[str] = None,
repo: Optional[str] = None
) -> List[Dict]:
"""
@@ -61,6 +62,7 @@ class GiteaClient:
Args:
state: Issue state (open, closed, all)
labels: Filter by labels
milestone: Filter by milestone title (exact match)
repo: Repository in 'owner/repo' format
Returns:
@@ -71,6 +73,8 @@ class GiteaClient:
params = {'state': state}
if labels:
params['labels'] = ','.join(labels)
if milestone:
params['milestones'] = milestone
logger.info(f"Listing issues from {owner}/{target_repo} with state={state}")
response = self.session.get(url, params=params)
response.raise_for_status()

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)

View File

@@ -98,6 +98,7 @@ class IssueTools:
self,
state: str = 'open',
labels: Optional[List[str]] = None,
milestone: Optional[str] = None,
repo: Optional[str] = None
) -> List[Dict]:
"""
@@ -106,6 +107,7 @@ class IssueTools:
Args:
state: Issue state (open, closed, all)
labels: Filter by labels
milestone: Filter by milestone title (exact match)
repo: Override configured repo (for PMO multi-repo)
Returns:
@@ -124,7 +126,7 @@ class IssueTools:
loop = asyncio.get_event_loop()
return await loop.run_in_executor(
None,
lambda: self.gitea.list_issues(state, labels, repo)
lambda: self.gitea.list_issues(state, labels, milestone, repo)
)
async def get_issue(

View File

@@ -6,9 +6,13 @@ description: Begin sprint execution with relevant lessons learned from previous
You are initiating sprint execution. The orchestrator agent will coordinate the work, analyze dependencies for parallel execution, search for relevant lessons learned, and guide you through the implementation process.
## Sprint Approval Verification
## Sprint Approval Verification (Recommended)
**CRITICAL: Sprint must be approved before execution.**
**RECOMMENDED: Sprint should be approved before execution.**
> **Note:** This is a recommended workflow practice, not code-enforced. The orchestrator
> SHOULD check for approval, but execution will proceed if approval is missing. For
> critical projects, consider making approval mandatory in your workflow.
The orchestrator checks for approval in the milestone description:
@@ -19,16 +23,15 @@ get_milestone(milestone_id=17)
**If Approval Missing:**
```
⚠️ SPRINT NOT APPROVED
⚠️ SPRINT APPROVAL NOT FOUND (Warning)
Sprint 17 has not been approved for execution.
The milestone description does not contain an approval record.
Sprint 17 milestone does not contain an approval record.
Please run /sprint-plan to:
Recommended: Run /sprint-plan first to:
1. Review the sprint scope
2. Approve the execution plan
2. Document the approved execution plan
Then run /sprint-start again.
Proceeding anyway - consider adding approval for audit trail.
```
**If Approval Found:**
@@ -42,10 +45,10 @@ Then run /sprint-start again.
Proceeding with execution within approved scope...
```
**Scope Enforcement:**
- Agents can ONLY create branches matching approved patterns
- Agents can ONLY modify files within approved paths
- Operations outside scope require re-approval via `/sprint-plan`
**Scope Enforcement (when approval exists):**
- Agents SHOULD only create branches matching approved patterns
- Agents SHOULD only modify files within approved paths
- Operations outside scope should trigger re-approval via `/sprint-plan`
## Branch Detection
@@ -66,11 +69,11 @@ If you are on a production or staging branch, you MUST stop and ask the user to
The orchestrator agent will:
1. **Verify Sprint Approval**
1. **Verify Sprint Approval** (Recommended)
- Check milestone description for `## Sprint Approval` section
- If no approval found, STOP and direct user to `/sprint-plan`
- If no approval found, WARN user and suggest `/sprint-plan` first
- If approval found, extract scope (branches, files)
- Agents operate ONLY within approved scope
- Agents SHOULD operate within approved scope when available
2. **Detect Checkpoints (Resume Support)**
- Check each open issue for `## Checkpoint` comments