mcpforunityserver 9.3.0b20260129121506__py3-none-any.whl → 9.3.0b20260131003150__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.
Files changed (29) hide show
  1. cli/utils/connection.py +28 -32
  2. core/config.py +15 -0
  3. core/constants.py +4 -0
  4. main.py +306 -174
  5. {mcpforunityserver-9.3.0b20260129121506.dist-info → mcpforunityserver-9.3.0b20260131003150.dist-info}/METADATA +117 -5
  6. {mcpforunityserver-9.3.0b20260129121506.dist-info → mcpforunityserver-9.3.0b20260131003150.dist-info}/RECORD +29 -27
  7. models/__init__.py +2 -2
  8. models/unity_response.py +24 -1
  9. services/api_key_service.py +235 -0
  10. services/resources/active_tool.py +2 -1
  11. services/resources/editor_state.py +7 -7
  12. services/resources/layers.py +2 -1
  13. services/resources/menu_items.py +2 -1
  14. services/resources/prefab_stage.py +2 -1
  15. services/resources/project_info.py +2 -1
  16. services/resources/selection.py +2 -1
  17. services/resources/tags.py +2 -1
  18. services/resources/tests.py +3 -2
  19. services/resources/unity_instances.py +6 -3
  20. services/resources/windows.py +2 -1
  21. services/tools/set_active_instance.py +6 -3
  22. transport/plugin_hub.py +124 -24
  23. transport/plugin_registry.py +75 -19
  24. transport/unity_instance_middleware.py +38 -9
  25. transport/unity_transport.py +41 -10
  26. {mcpforunityserver-9.3.0b20260129121506.dist-info → mcpforunityserver-9.3.0b20260131003150.dist-info}/WHEEL +0 -0
  27. {mcpforunityserver-9.3.0b20260129121506.dist-info → mcpforunityserver-9.3.0b20260131003150.dist-info}/entry_points.txt +0 -0
  28. {mcpforunityserver-9.3.0b20260129121506.dist-info → mcpforunityserver-9.3.0b20260131003150.dist-info}/licenses/LICENSE +0 -0
  29. {mcpforunityserver-9.3.0b20260129121506.dist-info → mcpforunityserver-9.3.0b20260131003150.dist-info}/top_level.txt +0 -0
@@ -1,34 +1,49 @@
1
1
  """Transport helpers for routing commands to Unity."""
2
2
  from __future__ import annotations
3
3
 
4
- import asyncio
5
- import inspect
6
- import os
4
+ import logging
7
5
  from typing import Awaitable, Callable, TypeVar
8
6
 
9
- from fastmcp import Context
10
-
11
7
  from transport.plugin_hub import PluginHub
8
+ from core.config import config
9
+ from core.constants import API_KEY_HEADER
10
+ from services.api_key_service import ApiKeyService
12
11
  from models.models import MCPResponse
13
12
  from models.unity_response import normalize_unity_response
14
- from services.tools import get_unity_instance_from_context
15
13
 
16
14
  T = TypeVar("T")
15
+ logger = logging.getLogger("mcp-for-unity-server")
17
16
 
18
17
 
19
18
  def _is_http_transport() -> bool:
20
- return os.environ.get("UNITY_MCP_TRANSPORT", "stdio").lower() == "http"
19
+ return config.transport_mode.lower() == "http"
21
20
 
22
21
 
23
- def _current_transport() -> str:
24
- """Expose the active transport mode as a simple string identifier."""
25
- return "http" if _is_http_transport() else "stdio"
22
+ async def _resolve_user_id_from_request() -> str | None:
23
+ """Extract user_id from the current HTTP request's API key header."""
24
+ if not config.http_remote_hosted:
25
+ return None
26
+ if not ApiKeyService.is_initialized():
27
+ return None
28
+ try:
29
+ from fastmcp.server.dependencies import get_http_headers
30
+ headers = get_http_headers(include_all=True)
31
+ api_key = headers.get(API_KEY_HEADER.lower())
32
+ if not api_key:
33
+ return None
34
+ service = ApiKeyService.get_instance()
35
+ result = await service.validate(api_key)
36
+ return result.user_id if result.valid else None
37
+ except Exception as e:
38
+ logger.debug("Failed to resolve user_id from HTTP request: %s", e)
39
+ return None
26
40
 
27
41
 
28
42
  async def send_with_unity_instance(
29
43
  send_fn: Callable[..., Awaitable[T]],
30
44
  unity_instance: str | None,
31
45
  *args,
46
+ user_id: str | None = None,
32
47
  **kwargs,
33
48
  ) -> T:
34
49
  if _is_http_transport():
@@ -41,11 +56,27 @@ async def send_with_unity_instance(
41
56
  if not isinstance(params, dict):
42
57
  raise TypeError(
43
58
  "Command parameters must be a dict for HTTP transport")
59
+
60
+ # Auto-resolve user_id from HTTP request API key (remote-hosted mode)
61
+ if user_id is None:
62
+ user_id = await _resolve_user_id_from_request()
63
+
64
+ # Auth check
65
+ if config.http_remote_hosted and not user_id:
66
+ return normalize_unity_response(
67
+ MCPResponse(
68
+ success=False,
69
+ error="auth_required",
70
+ message="API key required",
71
+ ).model_dump()
72
+ )
73
+
44
74
  try:
45
75
  raw = await PluginHub.send_command_for_instance(
46
76
  unity_instance,
47
77
  command_type,
48
78
  params,
79
+ user_id=user_id,
49
80
  )
50
81
  return normalize_unity_response(raw)
51
82
  except Exception as exc: