fenix-mcp 0.5.0__py3-none-any.whl → 0.5.5__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
@@ -3,18 +3,9 @@
3
3
 
4
4
  """
5
5
  Fênix Cloud MCP Server (Python edition).
6
-
7
- This package follows a Clean Architecture layout inside the MCP ecosystem:
8
-
9
- - interface: transports and MCP protocol glue code
10
- - application: tools, registries, presenters and use-case orchestrators
11
- - domain: pure business models and services
12
- - infrastructure: API clients, config, logging and shared context
13
-
14
- Version 0.1.0 - Initial release with basic MCP functionality.
15
- Updated with improved error handling and better documentation.
16
6
  """
17
7
 
18
8
  __all__ = ["__version__"]
19
9
 
20
- __version__ = "0.5.0"
10
+
11
+ __version__ = "0.5.5"
@@ -155,6 +155,7 @@ class IntelligenceTool(Tool):
155
155
  async def _handle_smart_create(self, payload: IntelligenceRequest):
156
156
  if not payload.title or not payload.content:
157
157
  return text("❌ Informe título e conteúdo para criar uma memória.")
158
+ normalized_tags = _ensure_tag_sequence(payload.tags)
158
159
  memory = await self._service.smart_create_memory(
159
160
  title=payload.title,
160
161
  content=payload.content,
@@ -162,7 +163,7 @@ class IntelligenceTool(Tool):
162
163
  context=payload.context,
163
164
  source=payload.source,
164
165
  importance=payload.importance,
165
- tags=payload.tags,
166
+ tags=normalized_tags,
166
167
  )
167
168
  lines = [
168
169
  "🧠 **Memória criada com sucesso!**",
@@ -259,17 +260,18 @@ class IntelligenceTool(Tool):
259
260
  existing = await self._service.get_memory(
260
261
  payload.id, include_content=False, include_metadata=True
261
262
  )
263
+ normalized_tags = _ensure_tag_sequence(payload.tags)
262
264
  metadata = build_metadata(
263
265
  payload.metadata,
264
266
  importance=payload.importance,
265
- tags=payload.tags,
267
+ tags=normalized_tags,
266
268
  existing=existing.get("metadata") if isinstance(existing, dict) else None,
267
269
  )
268
270
  update_fields: Dict[str, Any] = {
269
271
  "title": payload.title,
270
272
  "content": payload.content,
271
273
  "metadata": metadata,
272
- "tags": payload.tags,
274
+ "tags": normalized_tags,
273
275
  "documentation_item_id": payload.documentation_item_id,
274
276
  "mode_id": payload.mode_id,
275
277
  "rule_id": payload.rule_id,
@@ -313,3 +315,15 @@ def format_percentage(value: Optional[float]) -> str:
313
315
  if value is None:
314
316
  return "N/A"
315
317
  return f"{value * 100:.1f}%"
318
+
319
+
320
+ def _ensure_tag_sequence(raw: Optional[Any]) -> Optional[List[str]]:
321
+ if raw is None or raw == "":
322
+ return None
323
+ if isinstance(raw, (list, tuple, set)):
324
+ result = [str(item).strip() for item in raw if str(item).strip()]
325
+ return result or None
326
+ if isinstance(raw, str):
327
+ items = [part.strip() for part in raw.split(",") if part.strip()]
328
+ return items or None
329
+ return [str(raw).strip()]
@@ -5,7 +5,7 @@ from __future__ import annotations
5
5
 
6
6
  import asyncio
7
7
  from dataclasses import dataclass
8
- from typing import Any, Dict, Iterable, List, Optional
8
+ from typing import Any, Dict, Iterable, List, Optional, Union
9
9
 
10
10
  from fenix_mcp.infrastructure.fenix_api.client import FenixApiClient
11
11
 
@@ -24,13 +24,14 @@ class IntelligenceService:
24
24
  context: Optional[str],
25
25
  source: Optional[str],
26
26
  importance: str,
27
- tags: Optional[Iterable[str]] = None,
27
+ tags: Optional[Union[Iterable[str], str]] = None,
28
28
  ) -> Dict[str, Any]:
29
29
  importance_value = importance or "medium"
30
+ normalized_tags = normalize_tags(tags)
30
31
  metadata_str = build_metadata(
31
32
  metadata,
32
33
  importance=importance_value,
33
- tags=tags,
34
+ tags=normalized_tags,
34
35
  context=context,
35
36
  source=source,
36
37
  )
@@ -39,7 +40,7 @@ class IntelligenceService:
39
40
  "content": content,
40
41
  "metadata": metadata_str,
41
42
  "priority_score": _importance_to_priority(importance_value),
42
- "tags": list(tags) if tags else None,
43
+ "tags": normalized_tags,
43
44
  }
44
45
  return await self._call(self.api.smart_create_memory, _strip_none(payload))
45
46
 
@@ -199,7 +200,7 @@ def build_metadata(
199
200
  explicit: Optional[str],
200
201
  *,
201
202
  importance: Optional[str],
202
- tags: Optional[Iterable[str]],
203
+ tags: Optional[Union[Iterable[str], str]],
203
204
  context: Optional[str] = None,
204
205
  source: Optional[str] = None,
205
206
  existing: Optional[str] = None,
@@ -258,12 +259,31 @@ def _slugify(value: Optional[str]) -> str:
258
259
  return "-".join(part for part in sanitized.split() if part).lower()
259
260
 
260
261
 
261
- def _format_tags(tags: Optional[Iterable[str]]) -> str:
262
- if not tags:
262
+ def _format_tags(tags: Optional[Union[Iterable[str], str]]) -> str:
263
+ if tags is None or tags == "":
263
264
  return ""
265
+ if isinstance(tags, str):
266
+ iterable: Iterable[str] = [part.strip() for part in tags.split(",")]
267
+ else:
268
+ iterable = tags
264
269
  normalized = {
265
- _slugify(tag) for tag in tags if isinstance(tag, str) and _slugify(tag)
270
+ _slugify(tag) for tag in iterable if isinstance(tag, str) and _slugify(tag)
266
271
  }
267
272
  if not normalized:
268
273
  return ""
269
274
  return ",".join(sorted(normalized))
275
+
276
+
277
+ def normalize_tags(tags: Optional[Union[Iterable[str], str]]) -> Optional[List[str]]:
278
+ if tags is None or tags == "":
279
+ return None
280
+ if isinstance(tags, str):
281
+ parts = [part.strip() for part in tags.split(",") if part.strip()]
282
+ else:
283
+ parts = [str(part).strip() for part in tags if str(part).strip()]
284
+ if not parts:
285
+ return None
286
+ slugged = [_slugify(part) for part in parts if _slugify(part)]
287
+ if not slugged:
288
+ return None
289
+ return sorted(set(slugged))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fenix-mcp
3
- Version: 0.5.0
3
+ Version: 0.5.5
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=TUKG6aTaYq_EQ3TiKSaS-m7s_p9d5sURwutx4MxHVvQ,615
1
+ fenix_mcp/__init__.py,sha256=VFicXGJqjH3YsCek0bZj1kzpDzhvnsitNiJLU_W3pe0,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=qUcb46qx9gHQfrSHgj4RD4NCHW-OIvKQdR5G9uxZ5l4,1316
@@ -6,12 +6,12 @@ fenix_mcp/application/tool_registry.py,sha256=bPT5g8GfxG_qu28R1WaDOZHvtmG6TPDvZi
6
6
  fenix_mcp/application/tools/__init__.py,sha256=Gi1YvYh-KdL9HD8gLVrknHrxiKKEOhHBEZ02KBXJaKQ,796
7
7
  fenix_mcp/application/tools/health.py,sha256=m5DxhoRbdwl6INzd6PISxv1NAv-ljCrezsr773VB0wE,834
8
8
  fenix_mcp/application/tools/initialize.py,sha256=f33DNDn9u8IYwpqiBj6bjJ-wHgaUP1zEuAvUM1rMYPc,4674
9
- fenix_mcp/application/tools/intelligence.py,sha256=dyHjEdEW4PksDARcdPoYhy4fcu3gneWMnI_SjNzPBNo,13380
9
+ fenix_mcp/application/tools/intelligence.py,sha256=DNWGu6NhPYZXahnHDVHIgYYdWn_jCP-Nw9FwS_Tat34,13945
10
10
  fenix_mcp/application/tools/knowledge.py,sha256=4ClGoFRqyFIPuzzg2DAg-w2eMvTP37mH0THXDGftinw,44634
11
11
  fenix_mcp/application/tools/productivity.py,sha256=2IMkNdZ-Kd1CFAO7geruAVjtf_BWoDdbnwkl76vhtC8,9973
12
12
  fenix_mcp/application/tools/user_config.py,sha256=8mPOZuwszO0TapxgrA7Foe15VQE874_mvfQYlGzyv4Y,6230
13
13
  fenix_mcp/domain/initialization.py,sha256=AZhdSNITQ7O3clELBuqGvjJc-c8pFKc7zQz-XR2xXPc,6933
14
- fenix_mcp/domain/intelligence.py,sha256=Z2k7mrfNlUgIV_rw6suukS3TU3kfAQjv5-ZSvcRZXi4,8246
14
+ fenix_mcp/domain/intelligence.py,sha256=IyZUA_fbCHDgHaWCgxkahXAaAT5qQlaz5AT7Cw2Gwko,9006
15
15
  fenix_mcp/domain/knowledge.py,sha256=fKQOTt20u5aa5Yo7gPeQ1Qxa_K5pBxn1yn8FEfOFltM,20241
16
16
  fenix_mcp/domain/productivity.py,sha256=nmHRuVJGRRu1s4eMoAv8vXHKsSauCPl-FvFx3I_yCTE,6661
17
17
  fenix_mcp/domain/user_config.py,sha256=LzBDCk31gLMtKHTbBmYb9VoFPHDW6OydpmDXeHHd0Mw,1642
@@ -22,8 +22,8 @@ fenix_mcp/infrastructure/logging.py,sha256=bHrWlSi_0HshRe3--BK_5nzUszW-gh37q6jsd
22
22
  fenix_mcp/infrastructure/fenix_api/client.py,sha256=Navi7cGAOradghcbYkFIQQINpjFrdINlNhdfZ4iSSYQ,28338
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-0.5.0.dist-info/METADATA,sha256=CJDz4x6SYkyBzpIPXhk3WEjT1vamMXFp2yY5jqAhpRE,7260
26
- fenix_mcp-0.5.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
27
- fenix_mcp-0.5.0.dist-info/entry_points.txt,sha256=o52x_YHBupEd-1Z1GSfUjv3gJrx5_I-EkHhCgt1WBaE,49
28
- fenix_mcp-0.5.0.dist-info/top_level.txt,sha256=2G1UtKpwjaIGQyE7sRoHecxaGLeuexfjrOUjv9DDKh4,10
29
- fenix_mcp-0.5.0.dist-info/RECORD,,
25
+ fenix_mcp-0.5.5.dist-info/METADATA,sha256=-ACRPvLopTfiqAs3pPeAf-A--tiDnBl6LocFtRkSHwU,7260
26
+ fenix_mcp-0.5.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
27
+ fenix_mcp-0.5.5.dist-info/entry_points.txt,sha256=o52x_YHBupEd-1Z1GSfUjv3gJrx5_I-EkHhCgt1WBaE,49
28
+ fenix_mcp-0.5.5.dist-info/top_level.txt,sha256=2G1UtKpwjaIGQyE7sRoHecxaGLeuexfjrOUjv9DDKh4,10
29
+ fenix_mcp-0.5.5.dist-info/RECORD,,