fenix-mcp 1.6.0__py3-none-any.whl → 1.8.0__py3-none-any.whl

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/__init__.py CHANGED
@@ -8,4 +8,4 @@ Fênix Cloud MCP Server (Python edition).
8
8
  __all__ = ["__version__"]
9
9
 
10
10
 
11
- __version__ = "1.6.0"
11
+ __version__ = "1.8.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 in the same batch, or parent_key to reference an existing work item (e.g., TEMA-0056). Cannot use both parent_temp_id and parent_key on the same item. 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'}] or [{temp_id:'task-1', parent_key:'TEMA-0056', 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,19 @@ 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 from same batch (e.g., parent_temp_id:'epic-1'), "
273
+ "OR parent_key to set parent from existing work item (e.g., parent_key:'TEMA-0056'). "
274
+ "Cannot use both parent_temp_id and parent_key on the same item. "
275
+ "Optional: description, priority (low/medium/high/critical), story_points, tags, due_date. "
276
+ 'Example: [{"temp_id":"e1", "title":"Epic", "item_type":"epic", "work_category":"backend"}, '
277
+ '{"temp_id":"t1", "parent_temp_id":"e1", "title":"Task", "item_type":"task", "work_category":"backend"}]'
278
+ ),
279
+ )
263
280
 
264
281
  # Mode fields
265
282
  mode_id: Optional[UUIDStr] = Field(
@@ -579,6 +596,52 @@ class KnowledgeTool(Tool):
579
596
  count = len(payload.work_item_ids)
580
597
  return text(f"✅ {count} work item(s) assigned to sprint.")
581
598
 
599
+ if action is KnowledgeAction.WORK_BULK_CREATE:
600
+ if not payload.work_items:
601
+ return text(
602
+ "❌ Provide work_items array. Each item requires: temp_id, title, item_type, work_category. "
603
+ "Optional: parent_temp_id OR parent_key (not both), description, priority, story_points, tags, due_date."
604
+ )
605
+ if len(payload.work_items) > 50:
606
+ return text("❌ Maximum 50 items per bulk create.")
607
+
608
+ # Validate required fields
609
+ for i, item in enumerate(payload.work_items):
610
+ if not item.get("temp_id"):
611
+ return text(f"❌ Item {i}: missing temp_id.")
612
+ if not item.get("title"):
613
+ return text(f"❌ Item {i}: missing title.")
614
+ if not item.get("item_type"):
615
+ return text(f"❌ Item {i}: missing item_type.")
616
+ if not item.get("work_category"):
617
+ return text(f"❌ Item {i}: missing work_category.")
618
+ if item.get("parent_temp_id") and item.get("parent_key"):
619
+ return text(
620
+ f"❌ Item {i}: cannot have both parent_temp_id and parent_key. Use one or the other."
621
+ )
622
+
623
+ items = await self._service.work_bulk_create({"items": payload.work_items})
624
+
625
+ # Format response with summary
626
+ type_counts: Dict[str, int] = {}
627
+ for item in items:
628
+ item_type = item.get("item_type", "unknown")
629
+ type_counts[item_type] = type_counts.get(item_type, 0) + 1
630
+
631
+ lines = [f"✅ **{len(items)} work items created**", ""]
632
+ for item in items:
633
+ key = item.get("key", "")
634
+ title = item.get("title", "Untitled")
635
+ item_type = item.get("item_type", "unknown")
636
+ lines.append(f"- [{key}] {title} ({item_type})")
637
+
638
+ lines.append("")
639
+ lines.append("**Summary by type:**")
640
+ for item_type, count in sorted(type_counts.items()):
641
+ lines.append(f"- {item_type}: {count}")
642
+
643
+ return text("\n".join(lines))
644
+
582
645
  return text(
583
646
  "❌ Unsupported work item action.\n\nChoose one of the values:\n"
584
647
  + "\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
  # ------------------------------------------------------------------
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fenix-mcp
3
- Version: 1.6.0
3
+ Version: 1.8.0
4
4
  Summary: Fênix Cloud MCP server implemented in Python
5
5
  Author: Fenix Inc
6
6
  Requires-Python: >=3.10
@@ -1,4 +1,4 @@
1
- fenix_mcp/__init__.py,sha256=0hD_tbK6SIxOmfllb0TMUOmfIeKzQvRt5FZWd9Uhcgw,180
1
+ fenix_mcp/__init__.py,sha256=1rPPMWBN4_kt19tylpYO9VURpib6wyxuNU5d3n6gYfk,180
2
2
  fenix_mcp/main.py,sha256=iJV-9btNMDJMObvcn7wBQdbLLKjkYCQ1ANGEwHGHlMU,2857
3
3
  fenix_mcp/application/presenters.py,sha256=fGME54PdCDhTBhXO-JUB9yLdBHiE1aeXLTC2fCuxnxM,689
4
4
  fenix_mcp/application/tool_base.py,sha256=YJk7aSVGjXEvAkXrOHOuUjCFhYni9NPKFyPKiZqkrCc,4235
@@ -7,23 +7,23 @@ fenix_mcp/application/tools/__init__.py,sha256=Gi1YvYh-KdL9HD8gLVrknHrxiKKEOhHBE
7
7
  fenix_mcp/application/tools/health.py,sha256=m5DxhoRbdwl6INzd6PISxv1NAv-ljCrezsr773VB0wE,834
8
8
  fenix_mcp/application/tools/initialize.py,sha256=YfsE3fVYiqGEwvaI_jg5-0K7pGURXxpB3WNwETmGBPc,5499
9
9
  fenix_mcp/application/tools/intelligence.py,sha256=fXfjBwAQmZCn3Zc8BqFnQFAJkpd9JsfOPa_uXJj-bMU,15778
10
- fenix_mcp/application/tools/knowledge.py,sha256=mQL3PmXCQIBpSMhpxCaWmF7silj__s1pc5dMJSciXUw,54650
10
+ fenix_mcp/application/tools/knowledge.py,sha256=TOXyiXzEzeq_IiLTJ9kR_o8Kgc2oDmnQOQVvDPimAAA,58408
11
11
  fenix_mcp/application/tools/productivity.py,sha256=wyJ7-2VqgI2cdrliBD_ejwNvQhN1DecpXSQVrCxcUpQ,11231
12
12
  fenix_mcp/application/tools/user_config.py,sha256=O5AVg7IUKL9uIoUoBSFovBDHl9jofhKWzhFK7CnKi4s,6470
13
13
  fenix_mcp/domain/initialization.py,sha256=AZhdSNITQ7O3clELBuqGvjJc-c8pFKc7zQz-XR2xXPc,6933
14
14
  fenix_mcp/domain/intelligence.py,sha256=j1kkxT-pjuzLQeAGDd2H8gd3O1aeUIRgHFnMGvNwQYg,8636
15
- fenix_mcp/domain/knowledge.py,sha256=X2terO-05fMzCpDTEmdIoAAzooEqx2odF90zIOXyf6I,20726
15
+ fenix_mcp/domain/knowledge.py,sha256=4zCEpfzQxXiMDIphWfKiKnqvsVQ-B8yoUk1Zog3lJnE,20928
16
16
  fenix_mcp/domain/productivity.py,sha256=PzY664eRPuBCfZGUY_Uv1GNeyMWsw6xqC54C-nobQns,6799
17
17
  fenix_mcp/domain/user_config.py,sha256=8rzhJCNqIArfaCoKxxQXFoemCU7qww3hq0RDanIf_2Y,2028
18
18
  fenix_mcp/infrastructure/config.py,sha256=zhJ3hhsP-bRfICcdq8rIDh5NGDe_u7AGpcgjcc2U1nY,1908
19
19
  fenix_mcp/infrastructure/context.py,sha256=kiDiamiPbHZpTGyZMylcQwtLhfaDXrxAkWSst_DWQNw,470
20
20
  fenix_mcp/infrastructure/http_client.py,sha256=QLIPhGYR_cBQGsbIO4RTR6ksyvkQt-OKHQU1JhPyap8,2470
21
21
  fenix_mcp/infrastructure/logging.py,sha256=bHrWlSi_0HshRe3--BK_5nzUszW-gh37q6jsd0ShS2Y,1371
22
- fenix_mcp/infrastructure/fenix_api/client.py,sha256=5ewLAdZcNO59zgCkFLke0sTLU8dalo1W0nXKATt3F4Q,28301
22
+ fenix_mcp/infrastructure/fenix_api/client.py,sha256=GZrrWiUGxMaFM7kT7M8YYeWN1X5EetaJg6Co1-RBI0o,28457
23
23
  fenix_mcp/interface/mcp_server.py,sha256=5UM2NJuNbwHkmCEprIFataJ5nFZiO8efTtP_oW3_iX0,2331
24
24
  fenix_mcp/interface/transports.py,sha256=PxdhfjH8UMl03f7nuCLc-M6tMx6-Y-btVz_mSqXKrSI,8138
25
- fenix_mcp-1.6.0.dist-info/METADATA,sha256=ZIVb_fHfqXzT-S6-vxJqVplXjwGxNTIYYpPAH4AHirE,7260
26
- fenix_mcp-1.6.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
27
- fenix_mcp-1.6.0.dist-info/entry_points.txt,sha256=o52x_YHBupEd-1Z1GSfUjv3gJrx5_I-EkHhCgt1WBaE,49
28
- fenix_mcp-1.6.0.dist-info/top_level.txt,sha256=2G1UtKpwjaIGQyE7sRoHecxaGLeuexfjrOUjv9DDKh4,10
29
- fenix_mcp-1.6.0.dist-info/RECORD,,
25
+ fenix_mcp-1.8.0.dist-info/METADATA,sha256=I9_mtSYu17C0GPL2tEyygd3L3giTE8wo-rq88IQP0Os,7260
26
+ fenix_mcp-1.8.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
27
+ fenix_mcp-1.8.0.dist-info/entry_points.txt,sha256=o52x_YHBupEd-1Z1GSfUjv3gJrx5_I-EkHhCgt1WBaE,49
28
+ fenix_mcp-1.8.0.dist-info/top_level.txt,sha256=2G1UtKpwjaIGQyE7sRoHecxaGLeuexfjrOUjv9DDKh4,10
29
+ fenix_mcp-1.8.0.dist-info/RECORD,,