unifi-network-mcp 0.4.0__py3-none-any.whl → 0.4.2__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.
src/_version.py CHANGED
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '0.4.0'
32
- __version_tuple__ = version_tuple = (0, 4, 0)
31
+ __version__ = version = '0.4.2'
32
+ __version_tuple__ = version_tuple = (0, 4, 2)
33
33
 
34
34
  __commit_id__ = commit_id = None
src/config/config.yaml CHANGED
@@ -51,6 +51,7 @@ server:
51
51
 
52
52
  http:
53
53
  enabled: ${oc.env:UNIFI_MCP_HTTP_ENABLED,false}
54
+ force: ${oc.env:UNIFI_MCP_HTTP_FORCE,false}
54
55
  diagnostics:
55
56
  enabled: ${oc.env:UNIFI_MCP_DIAGNOSTICS,false}
56
57
  log_tool_args: ${oc.env:UNIFI_MCP_DIAG_LOG_TOOL_ARGS,true}
src/main.py CHANGED
@@ -10,9 +10,11 @@ Responsibilities:
10
10
  import asyncio
11
11
  import logging
12
12
  import os
13
- import sys # Removed uvicorn import
13
+ import sys
14
14
  import traceback
15
15
 
16
+ import uvicorn.config
17
+
16
18
  from src.bootstrap import (
17
19
  UNIFI_TOOL_REGISTRATION_MODE,
18
20
  logger,
@@ -26,6 +28,7 @@ from src.runtime import (
26
28
  server,
27
29
  )
28
30
  from src.tool_index import register_tool, tool_index_handler
31
+ from src.utils.config_helpers import parse_config_bool
29
32
  from src.utils.diagnostics import diagnostics_enabled, wrap_tool
30
33
  from src.utils.lazy_tool_loader import setup_lazy_loading
31
34
  from src.utils.meta_tools import register_load_tools, register_meta_tools
@@ -310,17 +313,16 @@ async def main_async():
310
313
  host = config.server.get("host", "0.0.0.0")
311
314
  port = int(config.server.get("port", 3000))
312
315
  http_cfg = config.server.get("http", {})
313
- http_enabled_raw = http_cfg.get("enabled", False)
314
- if isinstance(http_enabled_raw, str):
315
- http_enabled = http_enabled_raw.strip().lower() in {"1", "true", "yes", "on"}
316
- else:
317
- http_enabled = bool(http_enabled_raw)
316
+ http_enabled = parse_config_bool(http_cfg.get("enabled", False))
318
317
 
319
- # Only the main container process (PID 1) should bind the HTTP SSE port.
318
+ # Only the main container process (PID 1) should bind the HTTP SSE port,
319
+ # unless http.force=true is set in config (for local development/testing).
320
+ force_http = parse_config_bool(http_cfg.get("force", False))
320
321
  is_main_container_process = os.getpid() == 1
321
- if http_enabled and not is_main_container_process:
322
+ if http_enabled and not is_main_container_process and not force_http:
322
323
  logger.info(
323
- "HTTP SSE enabled in config but skipped in exec session (PID %s != 1)",
324
+ "HTTP SSE enabled in config but skipped in exec session (PID %s != 1). "
325
+ "Set UNIFI_MCP_HTTP_FORCE=true to override.",
324
326
  os.getpid(),
325
327
  )
326
328
  http_enabled = False
@@ -335,9 +337,13 @@ async def main_async():
335
337
  async def run_http():
336
338
  try:
337
339
  logger.info(f"Starting FastMCP HTTP SSE server on {host}:{port} ...")
338
- # MCP SDK >= 1.10 (pinned to 1.13.1): configure host/port via settings
339
340
  server.settings.host = host
340
341
  server.settings.port = port
342
+
343
+ # Redirect uvicorn access logs to stderr to prevent stdout conflicts
344
+ # when running alongside stdio transport (stdout is used for JSON-RPC)
345
+ uvicorn.config.LOGGING_CONFIG["handlers"]["access"]["stream"] = "ext://sys.stderr"
346
+
341
347
  await server.run_sse_async()
342
348
  logger.info("HTTP SSE started via run_sse_async() using server.settings host/port.")
343
349
  except Exception as http_e:
@@ -0,0 +1,38 @@
1
+ """Configuration parsing utilities.
2
+
3
+ This module provides helpers for parsing configuration values that may come
4
+ from OmegaConf-resolved environment variables (which can be strings like
5
+ "true"/"false") or direct boolean values.
6
+ """
7
+
8
+ from typing import Any
9
+
10
+
11
+ def parse_config_bool(value: Any, default: bool = False) -> bool:
12
+ """Parse a config value as boolean, handling string values from env vars.
13
+
14
+ OmegaConf resolves ${oc.env:VAR,default} to strings when the env var is set,
15
+ so "true"/"false" strings need to be parsed explicitly.
16
+
17
+ Args:
18
+ value: The config value to parse (string, bool, or None)
19
+ default: Default value if value is None
20
+
21
+ Returns:
22
+ Boolean interpretation of the value
23
+
24
+ Examples:
25
+ >>> parse_config_bool("true")
26
+ True
27
+ >>> parse_config_bool("false")
28
+ False
29
+ >>> parse_config_bool(True)
30
+ True
31
+ >>> parse_config_bool(None, default=True)
32
+ True
33
+ """
34
+ if value is None:
35
+ return default
36
+ if isinstance(value, str):
37
+ return value.strip().lower() in {"1", "true", "yes", "on"}
38
+ return bool(value)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: unifi-network-mcp
3
- Version: 0.4.0
3
+ Version: 0.4.2
4
4
  Summary: Unifi Network MCP Server
5
5
  License-File: LICENSE
6
6
  Requires-Python: >=3.13
@@ -1,7 +1,7 @@
1
- src/_version.py,sha256=2_0GUP7yBCXRus-qiJKxQD62z172WSs1sQ6DVpPsbmM,704
1
+ src/_version.py,sha256=A45grTqzrHuDn1CT9K5GVUbY4_Q3OSTcXAl3zdHzcEI,704
2
2
  src/bootstrap.py,sha256=mqkDDfn5xKRzun07TS8xPLZm_WnfLt3xTguxxFnfRV0,7572
3
3
  src/jobs.py,sha256=3IUO8ChpeRUjyJTWeFlyIwtkQLv-_KvfzuA5Ra4PmDI,5984
4
- src/main.py,sha256=7ZCXXzSoHFsXuA_FdNwJhcLtjMtTzK4sxah7ahzmEHs,15456
4
+ src/main.py,sha256=l4T0PFMw-7a4lhExOyd-GBk13ZfcDN0ghpFGfxvNSAk,15747
5
5
  src/runtime.py,sha256=7WqGkzXe92fn0JczCv8YVr5LTIc40pIt7nqSX4ji2To,5816
6
6
  src/schemas.py,sha256=Y9fglAAgRGh8zxwO0J5zpj5BsRMLDDwevwXY_6kj5VU,33725
7
7
  src/tool_index.py,sha256=aUPFqES4i_cq9ZsfAoiWuhKwoEEJ8NEAOafQ2h1g1NE,5492
@@ -36,6 +36,7 @@ src/tools/system.py,sha256=_JYzjZ_ZmNY8nBtAZJyZ_p5NlSUp06-cLoaSxWUSA6s,2599
36
36
  src/tools/traffic_routes.py,sha256=cQvqCf5WZOHLuLdvPCLztsjXy-EciAVO3wNG6wlJgPM,9051
37
37
  src/tools/usergroups.py,sha256=S5tIj99YHmStuyQPgD-h1-Do9JvbZpM8bFk8XfuON2k,8459
38
38
  src/tools/vpn.py,sha256=aBvACvdm-xQcEFFK42JzYlG9OSmwqA2QIvsb6d-UG_s,7500
39
+ src/utils/config_helpers.py,sha256=L9UYSTD1BKsy5KsFag8jVyHbsUA_leUAHRXSMA-ZFZs,1131
39
40
  src/utils/confirmation.py,sha256=_GfvEaiyWIC53wmfVHFo8pcjGwmzajnc7EuuqvZ63RI,7045
40
41
  src/utils/diagnostics.py,sha256=kDQlVHm5SLUU7t_X4F4zamHSCUujTLrMIploVBTdTTU,5673
41
42
  src/utils/lazy_tool_loader.py,sha256=0GdfF7z06U_pvx7hmUE1jWEOFMFFo3WS9PWEEwkpXG4,11549
@@ -43,10 +44,10 @@ src/utils/meta_tools.py,sha256=XlLkzFEvrZsDEiXxMq_Lz22ZGZ8mMzbjx6krYJS-JD4,13172
43
44
  src/utils/permissions.py,sha256=GGg81gCPBo18Ra9NWGgHO3pPzX1EFUAt_Xd9gbUfKQo,4060
44
45
  src/utils/tool_loader.py,sha256=QpfHOxyZ_bzPJM0SItB7UM8uW_p7vl2Sm25rfgfwsAY,4147
45
46
  src/tools_manifest.json,sha256=G7j9-pKly9fGvjc7vDwoMqQROvpbhwafWu4UY9dPMjU,37902
46
- src/config/config.yaml,sha256=FPoDva21XrUqgiwXTahVa5tDy_aNTeOL3cT8DTxyICU,3953
47
- unifi_network_mcp-0.4.0.data/data/share/unifi-network-mcp/.well-known/mcp-server.json,sha256=Ru2oF_SdOzkathJVTQ6R0bRB-NTmiXLlNVvsp7GqmPs,1427
48
- unifi_network_mcp-0.4.0.dist-info/METADATA,sha256=3Cro-ITlcHDdw0vug5Q6yJ6Ev2tM2J9E4cWaUmEN_Dk,38696
49
- unifi_network_mcp-0.4.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
50
- unifi_network_mcp-0.4.0.dist-info/entry_points.txt,sha256=iDs5JXOBoUROpkuTXoxr-1WSrz1FLEgI0TO4pFsZ8u0,52
51
- unifi_network_mcp-0.4.0.dist-info/licenses/LICENSE,sha256=1tMHOACX4Nse1DzgSKufrvTGztT8kS71LE8l29IAvto,1068
52
- unifi_network_mcp-0.4.0.dist-info/RECORD,,
47
+ src/config/config.yaml,sha256=pTZgVqh_o4RTm3jL9ch9_jdT6vOXeRaB4_zV3kQHXQs,4001
48
+ unifi_network_mcp-0.4.2.data/data/share/unifi-network-mcp/.well-known/mcp-server.json,sha256=Ru2oF_SdOzkathJVTQ6R0bRB-NTmiXLlNVvsp7GqmPs,1427
49
+ unifi_network_mcp-0.4.2.dist-info/METADATA,sha256=OBgfKQXV3ZuRRs_TfCMKedKo5pc_qnVlSNl6whm_Irs,38696
50
+ unifi_network_mcp-0.4.2.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
51
+ unifi_network_mcp-0.4.2.dist-info/entry_points.txt,sha256=iDs5JXOBoUROpkuTXoxr-1WSrz1FLEgI0TO4pFsZ8u0,52
52
+ unifi_network_mcp-0.4.2.dist-info/licenses/LICENSE,sha256=1tMHOACX4Nse1DzgSKufrvTGztT8kS71LE8l29IAvto,1068
53
+ unifi_network_mcp-0.4.2.dist-info/RECORD,,