fenix-mcp 1.6.0__tar.gz → 1.7.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {fenix_mcp-1.6.0 → fenix_mcp-1.7.0}/PKG-INFO +1 -1
- {fenix_mcp-1.6.0 → fenix_mcp-1.7.0}/fenix_mcp/__init__.py +1 -1
- {fenix_mcp-1.6.0 → fenix_mcp-1.7.0}/fenix_mcp/application/tools/knowledge.py +57 -0
- {fenix_mcp-1.6.0 → fenix_mcp-1.7.0}/fenix_mcp/domain/knowledge.py +5 -0
- {fenix_mcp-1.6.0 → fenix_mcp-1.7.0}/fenix_mcp/infrastructure/fenix_api/client.py +3 -0
- {fenix_mcp-1.6.0 → fenix_mcp-1.7.0}/fenix_mcp.egg-info/PKG-INFO +1 -1
- {fenix_mcp-1.6.0 → fenix_mcp-1.7.0}/README.md +0 -0
- {fenix_mcp-1.6.0 → fenix_mcp-1.7.0}/fenix_mcp/application/presenters.py +0 -0
- {fenix_mcp-1.6.0 → fenix_mcp-1.7.0}/fenix_mcp/application/tool_base.py +0 -0
- {fenix_mcp-1.6.0 → fenix_mcp-1.7.0}/fenix_mcp/application/tool_registry.py +0 -0
- {fenix_mcp-1.6.0 → fenix_mcp-1.7.0}/fenix_mcp/application/tools/__init__.py +0 -0
- {fenix_mcp-1.6.0 → fenix_mcp-1.7.0}/fenix_mcp/application/tools/health.py +0 -0
- {fenix_mcp-1.6.0 → fenix_mcp-1.7.0}/fenix_mcp/application/tools/initialize.py +0 -0
- {fenix_mcp-1.6.0 → fenix_mcp-1.7.0}/fenix_mcp/application/tools/intelligence.py +0 -0
- {fenix_mcp-1.6.0 → fenix_mcp-1.7.0}/fenix_mcp/application/tools/productivity.py +0 -0
- {fenix_mcp-1.6.0 → fenix_mcp-1.7.0}/fenix_mcp/application/tools/user_config.py +0 -0
- {fenix_mcp-1.6.0 → fenix_mcp-1.7.0}/fenix_mcp/domain/initialization.py +0 -0
- {fenix_mcp-1.6.0 → fenix_mcp-1.7.0}/fenix_mcp/domain/intelligence.py +0 -0
- {fenix_mcp-1.6.0 → fenix_mcp-1.7.0}/fenix_mcp/domain/productivity.py +0 -0
- {fenix_mcp-1.6.0 → fenix_mcp-1.7.0}/fenix_mcp/domain/user_config.py +0 -0
- {fenix_mcp-1.6.0 → fenix_mcp-1.7.0}/fenix_mcp/infrastructure/config.py +0 -0
- {fenix_mcp-1.6.0 → fenix_mcp-1.7.0}/fenix_mcp/infrastructure/context.py +0 -0
- {fenix_mcp-1.6.0 → fenix_mcp-1.7.0}/fenix_mcp/infrastructure/http_client.py +0 -0
- {fenix_mcp-1.6.0 → fenix_mcp-1.7.0}/fenix_mcp/infrastructure/logging.py +0 -0
- {fenix_mcp-1.6.0 → fenix_mcp-1.7.0}/fenix_mcp/interface/mcp_server.py +0 -0
- {fenix_mcp-1.6.0 → fenix_mcp-1.7.0}/fenix_mcp/interface/transports.py +0 -0
- {fenix_mcp-1.6.0 → fenix_mcp-1.7.0}/fenix_mcp/main.py +0 -0
- {fenix_mcp-1.6.0 → fenix_mcp-1.7.0}/fenix_mcp.egg-info/SOURCES.txt +0 -0
- {fenix_mcp-1.6.0 → fenix_mcp-1.7.0}/fenix_mcp.egg-info/dependency_links.txt +0 -0
- {fenix_mcp-1.6.0 → fenix_mcp-1.7.0}/fenix_mcp.egg-info/entry_points.txt +0 -0
- {fenix_mcp-1.6.0 → fenix_mcp-1.7.0}/fenix_mcp.egg-info/requires.txt +0 -0
- {fenix_mcp-1.6.0 → fenix_mcp-1.7.0}/fenix_mcp.egg-info/top_level.txt +0 -0
- {fenix_mcp-1.6.0 → fenix_mcp-1.7.0}/pyproject.toml +0 -0
- {fenix_mcp-1.6.0 → fenix_mcp-1.7.0}/setup.cfg +0 -0
|
@@ -78,6 +78,10 @@ class KnowledgeAction(str, Enum):
|
|
|
78
78
|
"work_assign_to_me",
|
|
79
79
|
"Assigns a work item to the current user.",
|
|
80
80
|
)
|
|
81
|
+
WORK_BULK_CREATE = (
|
|
82
|
+
"work_bulk_create",
|
|
83
|
+
"Creates multiple work items atomically with hierarchy. Use temp_id as temporary identifier and parent_temp_id to reference parent. Example: [{temp_id:'epic-1', title:'My Epic', item_type:'epic', work_category:'backend'}, {temp_id:'task-1', parent_temp_id:'epic-1', title:'My Task', item_type:'task', work_category:'backend'}]",
|
|
84
|
+
)
|
|
81
85
|
|
|
82
86
|
# Boards
|
|
83
87
|
BOARD_LIST = ("board_list", "Lists available boards with optional filters.")
|
|
@@ -260,6 +264,17 @@ class KnowledgeRequest(ToolRequest):
|
|
|
260
264
|
default=None,
|
|
261
265
|
description="List of work item IDs for batch operations (UUIDs).",
|
|
262
266
|
)
|
|
267
|
+
work_items: Optional[List[Dict[str, Any]]] = Field(
|
|
268
|
+
default=None,
|
|
269
|
+
description=(
|
|
270
|
+
"List of work items for bulk create (max 50). Each item requires: "
|
|
271
|
+
"temp_id (your temporary ID like 'epic-1', 'task-a'), title, item_type, work_category. "
|
|
272
|
+
"Use parent_temp_id to set parent (e.g., parent_temp_id:'epic-1' makes it child of epic-1). "
|
|
273
|
+
"Optional: description, priority (low/medium/high/critical), story_points, tags, due_date. "
|
|
274
|
+
'Example: [{"temp_id":"e1", "title":"Epic", "item_type":"epic", "work_category":"backend"}, '
|
|
275
|
+
'{"temp_id":"t1", "parent_temp_id":"e1", "title":"Task", "item_type":"task", "work_category":"backend"}]'
|
|
276
|
+
),
|
|
277
|
+
)
|
|
263
278
|
|
|
264
279
|
# Mode fields
|
|
265
280
|
mode_id: Optional[UUIDStr] = Field(
|
|
@@ -579,6 +594,48 @@ class KnowledgeTool(Tool):
|
|
|
579
594
|
count = len(payload.work_item_ids)
|
|
580
595
|
return text(f"✅ {count} work item(s) assigned to sprint.")
|
|
581
596
|
|
|
597
|
+
if action is KnowledgeAction.WORK_BULK_CREATE:
|
|
598
|
+
if not payload.work_items:
|
|
599
|
+
return text(
|
|
600
|
+
"❌ Provide work_items array. Each item requires: temp_id, title, item_type, work_category. "
|
|
601
|
+
"Optional: parent_temp_id, description, priority, story_points, tags, due_date."
|
|
602
|
+
)
|
|
603
|
+
if len(payload.work_items) > 50:
|
|
604
|
+
return text("❌ Maximum 50 items per bulk create.")
|
|
605
|
+
|
|
606
|
+
# Validate required fields
|
|
607
|
+
for i, item in enumerate(payload.work_items):
|
|
608
|
+
if not item.get("temp_id"):
|
|
609
|
+
return text(f"❌ Item {i}: missing temp_id.")
|
|
610
|
+
if not item.get("title"):
|
|
611
|
+
return text(f"❌ Item {i}: missing title.")
|
|
612
|
+
if not item.get("item_type"):
|
|
613
|
+
return text(f"❌ Item {i}: missing item_type.")
|
|
614
|
+
if not item.get("work_category"):
|
|
615
|
+
return text(f"❌ Item {i}: missing work_category.")
|
|
616
|
+
|
|
617
|
+
items = await self._service.work_bulk_create({"items": payload.work_items})
|
|
618
|
+
|
|
619
|
+
# Format response with summary
|
|
620
|
+
type_counts: Dict[str, int] = {}
|
|
621
|
+
for item in items:
|
|
622
|
+
item_type = item.get("item_type", "unknown")
|
|
623
|
+
type_counts[item_type] = type_counts.get(item_type, 0) + 1
|
|
624
|
+
|
|
625
|
+
lines = [f"✅ **{len(items)} work items created**", ""]
|
|
626
|
+
for item in items:
|
|
627
|
+
key = item.get("key", "")
|
|
628
|
+
title = item.get("title", "Untitled")
|
|
629
|
+
item_type = item.get("item_type", "unknown")
|
|
630
|
+
lines.append(f"- [{key}] {title} ({item_type})")
|
|
631
|
+
|
|
632
|
+
lines.append("")
|
|
633
|
+
lines.append("**Summary by type:**")
|
|
634
|
+
for item_type, count in sorted(type_counts.items()):
|
|
635
|
+
lines.append(f"- {item_type}: {count}")
|
|
636
|
+
|
|
637
|
+
return text("\n".join(lines))
|
|
638
|
+
|
|
582
639
|
return text(
|
|
583
640
|
"❌ Unsupported work item action.\n\nChoose one of the values:\n"
|
|
584
641
|
+ "\n".join(
|
|
@@ -181,6 +181,11 @@ class KnowledgeService:
|
|
|
181
181
|
async def work_bulk_update(self, payload: Dict[str, Any]) -> Dict[str, Any]:
|
|
182
182
|
return await self._call(self.api.bulk_update_work_items, _strip_none(payload))
|
|
183
183
|
|
|
184
|
+
async def work_bulk_create(self, payload: Dict[str, Any]) -> List[Dict[str, Any]]:
|
|
185
|
+
return await self._call_list(
|
|
186
|
+
self.api.bulk_create_work_items, _strip_none(payload)
|
|
187
|
+
)
|
|
188
|
+
|
|
184
189
|
# ------------------------------------------------------------------
|
|
185
190
|
# Work boards
|
|
186
191
|
# ------------------------------------------------------------------
|
|
@@ -573,6 +573,9 @@ class FenixApiClient:
|
|
|
573
573
|
def bulk_update_work_items(self, payload: Mapping[str, Any]) -> Any:
|
|
574
574
|
return self._request("PATCH", "/api/work-items/bulk-update", json=payload)
|
|
575
575
|
|
|
576
|
+
def bulk_create_work_items(self, payload: Mapping[str, Any]) -> Any:
|
|
577
|
+
return self._request("POST", "/api/work-items/bulk-create", json=payload)
|
|
578
|
+
|
|
576
579
|
# ------------------------------------------------------------------
|
|
577
580
|
# Knowledge: boards
|
|
578
581
|
# ------------------------------------------------------------------
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|