mirror of
https://github.com/shadoll/redmine-mcp.git
synced 2026-08-28 11:33:28 +00:00
Enhance issue management tools: add relations and watchers functionality, update README
This commit is contained in:
+68
-16
@@ -1,6 +1,17 @@
|
||||
import json
|
||||
from ..mcp import mcp
|
||||
from ..client import _get, _put, _post
|
||||
from ..client import _get, _put, _post, _delete
|
||||
|
||||
|
||||
def _apply_relations(issue_id: int, relations: list[dict]) -> None:
|
||||
"""Create issue relations. Each item: {"issue_id": int, "relation_type": str}."""
|
||||
for rel in relations:
|
||||
_post(f"/issues/{issue_id}/relations.json", {
|
||||
"relation": {
|
||||
"issue_to_id": rel["issue_id"],
|
||||
"relation_type": rel.get("relation_type", "relates"),
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@mcp.tool()
|
||||
@@ -11,17 +22,26 @@ def create_issue(
|
||||
assigned_to_id: int = 0,
|
||||
priority_id: int = 0,
|
||||
due_date: str = "",
|
||||
parent_issue_id: int = 0,
|
||||
watcher_user_ids: list[int] | None = None,
|
||||
relations: list[dict] | None = None,
|
||||
) -> str:
|
||||
"""
|
||||
Create a new Redmine issue.
|
||||
|
||||
Args:
|
||||
project_id: Project ID or slug
|
||||
subject: Issue title
|
||||
description: Issue description
|
||||
assigned_to_id: User ID to assign (use get_project_members to find IDs)
|
||||
priority_id: Priority ID (leave 0 for default)
|
||||
due_date: Due date in YYYY-MM-DD format
|
||||
project_id: Project ID or slug
|
||||
subject: Issue title
|
||||
description: Issue description
|
||||
assigned_to_id: User ID to assign (use get_project_members to find IDs)
|
||||
priority_id: Priority ID (leave 0 for default)
|
||||
due_date: Due date in YYYY-MM-DD format
|
||||
parent_issue_id: Parent issue ID (makes this a subtask)
|
||||
watcher_user_ids: List of user IDs to add as watchers
|
||||
relations: List of related issues, e.g.
|
||||
[{"issue_id": 42, "relation_type": "relates"}]
|
||||
Types: relates, duplicates, duplicated,
|
||||
blocks, blocked, precedes, follows
|
||||
"""
|
||||
payload: dict = {"project_id": project_id, "subject": subject}
|
||||
if description:
|
||||
@@ -32,9 +52,17 @@ def create_issue(
|
||||
payload["priority_id"] = priority_id
|
||||
if due_date:
|
||||
payload["due_date"] = due_date
|
||||
if parent_issue_id:
|
||||
payload["parent_issue_id"] = parent_issue_id
|
||||
if watcher_user_ids:
|
||||
payload["watcher_user_ids"] = watcher_user_ids
|
||||
|
||||
data = _post("/issues.json", {"issue": payload})
|
||||
issue = data["issue"]
|
||||
|
||||
if relations:
|
||||
_apply_relations(issue["id"], relations)
|
||||
|
||||
return json.dumps({"id": issue["id"], "subject": issue["subject"]}, ensure_ascii=False, indent=2)
|
||||
|
||||
|
||||
@@ -102,17 +130,26 @@ def update_issue(
|
||||
priority_id: int = 0,
|
||||
due_date: str = "",
|
||||
comment: str = "",
|
||||
parent_issue_id: int = 0,
|
||||
watcher_user_ids: list[int] | None = None,
|
||||
relations: list[dict] | None = None,
|
||||
) -> str:
|
||||
"""
|
||||
Update general fields of a Redmine issue.
|
||||
|
||||
Args:
|
||||
issue_id: Redmine issue ID
|
||||
subject: New title (leave empty to keep current)
|
||||
description: New description (leave empty to keep current)
|
||||
priority_id: Priority ID (leave 0 to keep current)
|
||||
due_date: Due date in YYYY-MM-DD format (leave empty to keep current)
|
||||
comment: Optional journal note
|
||||
issue_id: Redmine issue ID
|
||||
subject: New title (leave empty to keep current)
|
||||
description: New description (leave empty to keep current)
|
||||
priority_id: Priority ID (leave 0 to keep current)
|
||||
due_date: Due date in YYYY-MM-DD format (leave empty to keep current)
|
||||
comment: Optional journal note
|
||||
parent_issue_id: Parent issue ID (makes this a subtask; 0 = no change)
|
||||
watcher_user_ids: List of user IDs to add as watchers
|
||||
relations: List of relations to add, e.g.
|
||||
[{"issue_id": 42, "relation_type": "blocks"}]
|
||||
Types: relates, duplicates, duplicated,
|
||||
blocks, blocked, precedes, follows
|
||||
"""
|
||||
payload: dict = {}
|
||||
if subject:
|
||||
@@ -125,12 +162,27 @@ def update_issue(
|
||||
payload["due_date"] = due_date
|
||||
if comment:
|
||||
payload["notes"] = comment
|
||||
if parent_issue_id:
|
||||
payload["parent_issue_id"] = parent_issue_id
|
||||
|
||||
if not payload:
|
||||
if not payload and not watcher_user_ids and not relations:
|
||||
return "Nothing to update — all fields are empty."
|
||||
|
||||
_put(f"/issues/{issue_id}.json", {"issue": payload})
|
||||
return f"Issue #{issue_id} updated: {list(payload.keys())}."
|
||||
if payload:
|
||||
_put(f"/issues/{issue_id}.json", {"issue": payload})
|
||||
|
||||
for user_id in (watcher_user_ids or []):
|
||||
_post(f"/issues/{issue_id}/watchers.json", {"user_id": user_id})
|
||||
|
||||
if relations:
|
||||
_apply_relations(issue_id, relations)
|
||||
|
||||
updated = list(payload.keys())
|
||||
if watcher_user_ids:
|
||||
updated.append("watchers")
|
||||
if relations:
|
||||
updated.append("relations")
|
||||
return f"Issue #{issue_id} updated: {updated}."
|
||||
|
||||
|
||||
@mcp.tool()
|
||||
|
||||
Reference in New Issue
Block a user