weeek-mcp 0.2.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.
weeek_mcp/__init__.py ADDED
@@ -0,0 +1,3 @@
1
+ """Weeek MCP server: task management (public API) and knowledge base (Playwright)."""
2
+
3
+ __version__ = "0.2.0"
weeek_mcp/config.py ADDED
@@ -0,0 +1,87 @@
1
+ """Runtime configuration, read from environment variables (and an optional .env file)."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import os
6
+ from dataclasses import dataclass
7
+ from pathlib import Path
8
+
9
+ from dotenv import load_dotenv
10
+
11
+ # Load .env if present; real environment variables always win.
12
+ load_dotenv()
13
+
14
+ DEFAULT_API_BASE = "https://api.weeek.net/public/v1"
15
+ DEFAULT_APP_BASE = "https://app.weeek.net"
16
+ # Internal (non-public) API the web app uses for the knowledge base.
17
+ DEFAULT_INTERNAL_API_BASE = "https://api.weeek.net"
18
+ # Hocuspocus server the editors sync document bodies through.
19
+ DEFAULT_COLLAB_BASE = "wss://collabws.weeek.net"
20
+
21
+
22
+ def _state_dir() -> Path:
23
+ base = os.environ.get("XDG_STATE_HOME") or (Path.home() / ".local" / "state")
24
+ return Path(base) / "weeek-mcp"
25
+
26
+
27
+ def _default_state_path() -> Path:
28
+ """Where the Playwright login session (storageState) is cached."""
29
+ return _state_dir() / "storage_state.json"
30
+
31
+
32
+ def _default_log_path() -> Path | None:
33
+ """Where diagnostic timing/step logs are written, if enabled.
34
+
35
+ Opt-in via WEEEK_DEBUG_LOG=1: MCP hosts commonly discard a locally-run
36
+ extension's stderr (observed with Claude Desktop: the subprocess's fd 2 is
37
+ wired to /dev/null), so debug output has to go to a file we control to
38
+ survive at all — but that shouldn't happen by default for every user.
39
+ """
40
+ if os.environ.get("WEEEK_DEBUG_LOG", "").lower() not in ("1", "true"):
41
+ return None
42
+ return _state_dir() / "debug.log"
43
+
44
+
45
+ @dataclass(frozen=True)
46
+ class Config:
47
+ # --- Task management (public REST API) ---
48
+ api_token: str | None
49
+ api_base: str
50
+
51
+ # --- Knowledge base (internal API + Playwright for login) ---
52
+ app_base: str
53
+ internal_api_base: str
54
+ collab_base: str
55
+ workspace_id: str | None # auto-detected via /ws when not set
56
+ email: str | None
57
+ password: str | None
58
+ storage_state_path: Path
59
+ log_path: Path | None
60
+ headless: bool
61
+ kb_cache_ttl: int # seconds to cache the KB document tree for resources/list
62
+
63
+ @property
64
+ def has_api(self) -> bool:
65
+ return bool(self.api_token)
66
+
67
+ @property
68
+ def has_kb_credentials(self) -> bool:
69
+ return bool(self.email and self.password)
70
+
71
+ @classmethod
72
+ def from_env(cls) -> "Config":
73
+ state = os.environ.get("WEEEK_STORAGE_STATE")
74
+ return cls(
75
+ api_token=os.environ.get("WEEEK_API_TOKEN"),
76
+ api_base=os.environ.get("WEEEK_API_BASE", DEFAULT_API_BASE).rstrip("/"),
77
+ app_base=os.environ.get("WEEEK_APP_BASE", DEFAULT_APP_BASE).rstrip("/"),
78
+ internal_api_base=os.environ.get("WEEEK_INTERNAL_API_BASE", DEFAULT_INTERNAL_API_BASE).rstrip("/"),
79
+ collab_base=os.environ.get("WEEEK_COLLAB_BASE", DEFAULT_COLLAB_BASE).rstrip("/"),
80
+ workspace_id=os.environ.get("WEEEK_WORKSPACE_ID"),
81
+ email=os.environ.get("WEEEK_EMAIL"),
82
+ password=os.environ.get("WEEEK_PASSWORD"),
83
+ storage_state_path=Path(state) if state else _default_state_path(),
84
+ log_path=_default_log_path(),
85
+ headless=os.environ.get("WEEEK_HEADLESS", "true").lower() != "false",
86
+ kb_cache_ttl=int(os.environ.get("WEEEK_KB_CACHE_TTL", "300")),
87
+ )
@@ -0,0 +1,6 @@
1
+ """Knowledge base access for Weeek via Playwright.
2
+
3
+ Weeek has no public API for the knowledge base, so this package drives the web app.
4
+ All DOM-specific details live in ``selectors.py`` and are marked as requiring
5
+ validation against the live UI (they cannot be verified without a real login).
6
+ """