golf-mcp 0.2.10__py3-none-any.whl → 0.2.11__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.
Potentially problematic release.
This version of golf-mcp might be problematic. Click here for more details.
- golf/__init__.py +1 -1
- golf/core/builder.py +177 -21
- golf/core/config.py +2 -2
- {golf_mcp-0.2.10.dist-info → golf_mcp-0.2.11.dist-info}/METADATA +1 -1
- {golf_mcp-0.2.10.dist-info → golf_mcp-0.2.11.dist-info}/RECORD +9 -9
- {golf_mcp-0.2.10.dist-info → golf_mcp-0.2.11.dist-info}/WHEEL +0 -0
- {golf_mcp-0.2.10.dist-info → golf_mcp-0.2.11.dist-info}/entry_points.txt +0 -0
- {golf_mcp-0.2.10.dist-info → golf_mcp-0.2.11.dist-info}/licenses/LICENSE +0 -0
- {golf_mcp-0.2.10.dist-info → golf_mcp-0.2.11.dist-info}/top_level.txt +0 -0
golf/__init__.py
CHANGED
golf/core/builder.py
CHANGED
|
@@ -645,6 +645,137 @@ class CodeGenerator:
|
|
|
645
645
|
"",
|
|
646
646
|
]
|
|
647
647
|
|
|
648
|
+
def _generate_readiness_section(self, project_path: Path) -> list[str]:
|
|
649
|
+
"""Generate code section for readiness.py execution during server runtime."""
|
|
650
|
+
readiness_path = project_path / "readiness.py"
|
|
651
|
+
|
|
652
|
+
if not readiness_path.exists():
|
|
653
|
+
# Only generate default readiness if health checks are explicitly enabled
|
|
654
|
+
if not self.settings.health_check_enabled:
|
|
655
|
+
return []
|
|
656
|
+
return [
|
|
657
|
+
"# Default readiness check - no custom readiness.py found",
|
|
658
|
+
"@mcp.custom_route('/ready', methods=[\"GET\"])",
|
|
659
|
+
"async def readiness_check(request: Request) -> JSONResponse:",
|
|
660
|
+
' """Readiness check endpoint for Kubernetes and load balancers."""',
|
|
661
|
+
' return JSONResponse({"status": "pass"}, status_code=200)',
|
|
662
|
+
"",
|
|
663
|
+
]
|
|
664
|
+
|
|
665
|
+
return [
|
|
666
|
+
"# Custom readiness check from readiness.py",
|
|
667
|
+
"from readiness import check as readiness_check_func",
|
|
668
|
+
"@mcp.custom_route('/ready', methods=[\"GET\"])",
|
|
669
|
+
"async def readiness_check(request: Request):",
|
|
670
|
+
' """Readiness check endpoint for Kubernetes and load balancers."""',
|
|
671
|
+
" result = readiness_check_func()",
|
|
672
|
+
" if isinstance(result, dict):",
|
|
673
|
+
" return JSONResponse(result)",
|
|
674
|
+
" return result",
|
|
675
|
+
"",
|
|
676
|
+
]
|
|
677
|
+
|
|
678
|
+
def _generate_health_section(self, project_path: Path) -> list[str]:
|
|
679
|
+
"""Generate code section for health.py execution during server runtime."""
|
|
680
|
+
health_path = project_path / "health.py"
|
|
681
|
+
|
|
682
|
+
if not health_path.exists():
|
|
683
|
+
# Check if legacy health configuration is used
|
|
684
|
+
if self.settings.health_check_enabled:
|
|
685
|
+
return [
|
|
686
|
+
"# Legacy health check configuration (deprecated)",
|
|
687
|
+
"@mcp.custom_route('" + self.settings.health_check_path + '\', methods=["GET"])',
|
|
688
|
+
"async def health_check(request: Request) -> PlainTextResponse:",
|
|
689
|
+
' """Health check endpoint for Kubernetes and load balancers."""',
|
|
690
|
+
f' return PlainTextResponse("{self.settings.health_check_response}")',
|
|
691
|
+
"",
|
|
692
|
+
]
|
|
693
|
+
else:
|
|
694
|
+
# If health checks are disabled, return empty (no default health check)
|
|
695
|
+
return []
|
|
696
|
+
|
|
697
|
+
return [
|
|
698
|
+
"# Custom health check from health.py",
|
|
699
|
+
"from health import check as health_check_func",
|
|
700
|
+
"@mcp.custom_route('/health', methods=[\"GET\"])",
|
|
701
|
+
"async def health_check(request: Request):",
|
|
702
|
+
' """Health check endpoint for Kubernetes and load balancers."""',
|
|
703
|
+
" result = health_check_func()",
|
|
704
|
+
" if isinstance(result, dict):",
|
|
705
|
+
" return JSONResponse(result)",
|
|
706
|
+
" return result",
|
|
707
|
+
"",
|
|
708
|
+
]
|
|
709
|
+
|
|
710
|
+
def _generate_check_function_helper(self) -> list[str]:
|
|
711
|
+
"""Generate helper function to call custom check functions."""
|
|
712
|
+
return [
|
|
713
|
+
"# Helper function to call custom check functions",
|
|
714
|
+
"async def _call_check_function(check_type: str) -> JSONResponse:",
|
|
715
|
+
' """Call custom check function and handle errors gracefully."""',
|
|
716
|
+
" import importlib.util",
|
|
717
|
+
" import traceback",
|
|
718
|
+
" from pathlib import Path",
|
|
719
|
+
" from datetime import datetime",
|
|
720
|
+
" ",
|
|
721
|
+
" try:",
|
|
722
|
+
" # Load the custom check module",
|
|
723
|
+
" module_path = Path(__file__).parent / f'{check_type}.py'",
|
|
724
|
+
" if not module_path.exists():",
|
|
725
|
+
' return JSONResponse({"status": "pass"}, status_code=200)',
|
|
726
|
+
" ",
|
|
727
|
+
" spec = importlib.util.spec_from_file_location(f'{check_type}_check', module_path)",
|
|
728
|
+
" if spec and spec.loader:",
|
|
729
|
+
" module = importlib.util.module_from_spec(spec)",
|
|
730
|
+
" spec.loader.exec_module(module)",
|
|
731
|
+
" ",
|
|
732
|
+
" # Call the check function if it exists",
|
|
733
|
+
" if hasattr(module, 'check'):",
|
|
734
|
+
" result = module.check()",
|
|
735
|
+
" ",
|
|
736
|
+
" # Handle different return types",
|
|
737
|
+
" if isinstance(result, dict):",
|
|
738
|
+
" # User returned structured response",
|
|
739
|
+
" status_code = result.get('status_code', 200)",
|
|
740
|
+
" response_data = {k: v for k, v in result.items() if k != 'status_code'}",
|
|
741
|
+
" elif isinstance(result, bool):",
|
|
742
|
+
" # User returned simple boolean",
|
|
743
|
+
" status_code = 200 if result else 503",
|
|
744
|
+
" response_data = {",
|
|
745
|
+
' "status": "pass" if result else "fail",',
|
|
746
|
+
' "timestamp": datetime.utcnow().isoformat()',
|
|
747
|
+
" }",
|
|
748
|
+
" elif result is None:",
|
|
749
|
+
" # User returned nothing - assume success",
|
|
750
|
+
" status_code = 200",
|
|
751
|
+
' response_data = {"status": "pass"}',
|
|
752
|
+
" else:",
|
|
753
|
+
" # User returned something else - treat as success message",
|
|
754
|
+
" status_code = 200",
|
|
755
|
+
" response_data = {",
|
|
756
|
+
' "status": "pass",',
|
|
757
|
+
' "message": str(result)',
|
|
758
|
+
" }",
|
|
759
|
+
" ",
|
|
760
|
+
" return JSONResponse(response_data, status_code=status_code)",
|
|
761
|
+
" else:",
|
|
762
|
+
" return JSONResponse(",
|
|
763
|
+
' {"status": "fail", "error": f"No check() function found in {check_type}.py"},',
|
|
764
|
+
" status_code=503",
|
|
765
|
+
" )",
|
|
766
|
+
" ",
|
|
767
|
+
" except Exception as e:",
|
|
768
|
+
" # Log error and return failure response",
|
|
769
|
+
" import sys",
|
|
770
|
+
' print(f"Error calling {check_type} check function: {e}", file=sys.stderr)',
|
|
771
|
+
" print(traceback.format_exc(), file=sys.stderr)",
|
|
772
|
+
" return JSONResponse({",
|
|
773
|
+
' "status": "fail",',
|
|
774
|
+
' "error": f"Error calling {check_type} check function: {str(e)}"',
|
|
775
|
+
" }, status_code=503)",
|
|
776
|
+
"",
|
|
777
|
+
]
|
|
778
|
+
|
|
648
779
|
def _generate_server(self) -> None:
|
|
649
780
|
"""Generate the main server entry point."""
|
|
650
781
|
server_file = self.output_dir / "server.py"
|
|
@@ -700,14 +831,31 @@ class CodeGenerator:
|
|
|
700
831
|
imports.extend(generate_metrics_instrumentation())
|
|
701
832
|
imports.extend(generate_session_tracking())
|
|
702
833
|
|
|
703
|
-
# Add health check imports
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
834
|
+
# Add health check imports only when we generate default endpoints
|
|
835
|
+
readiness_exists = (self.project_path / "readiness.py").exists()
|
|
836
|
+
health_exists = (self.project_path / "health.py").exists()
|
|
837
|
+
|
|
838
|
+
# Only import starlette when we generate default endpoints (not when custom files exist)
|
|
839
|
+
will_generate_default_readiness = not readiness_exists and self.settings.health_check_enabled
|
|
840
|
+
will_generate_default_health = not health_exists and self.settings.health_check_enabled
|
|
841
|
+
|
|
842
|
+
if will_generate_default_readiness or will_generate_default_health:
|
|
843
|
+
imports.append("from starlette.requests import Request")
|
|
844
|
+
|
|
845
|
+
# Determine response types needed for default endpoints
|
|
846
|
+
response_types = []
|
|
847
|
+
if will_generate_default_readiness:
|
|
848
|
+
response_types.append("JSONResponse")
|
|
849
|
+
if will_generate_default_health:
|
|
850
|
+
response_types.append("PlainTextResponse")
|
|
851
|
+
|
|
852
|
+
if response_types:
|
|
853
|
+
imports.append(f"from starlette.responses import {', '.join(response_types)}")
|
|
854
|
+
|
|
855
|
+
# Import Request and JSONResponse for custom check routes (they need both)
|
|
856
|
+
elif readiness_exists or health_exists:
|
|
857
|
+
imports.append("from starlette.requests import Request")
|
|
858
|
+
imports.append("from starlette.responses import JSONResponse")
|
|
711
859
|
|
|
712
860
|
# Get transport-specific configuration
|
|
713
861
|
transport_config = self._get_transport_config(self.settings.transport)
|
|
@@ -1199,22 +1347,17 @@ class CodeGenerator:
|
|
|
1199
1347
|
|
|
1200
1348
|
metrics_route_code = generate_metrics_route(self.settings.metrics_path)
|
|
1201
1349
|
|
|
1202
|
-
#
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
"async def health_check(request: Request) -> PlainTextResponse:",
|
|
1209
|
-
' """Health check endpoint for Kubernetes and load balancers."""',
|
|
1210
|
-
(f' return PlainTextResponse("{self.settings.health_check_response}")'),
|
|
1211
|
-
"",
|
|
1212
|
-
]
|
|
1350
|
+
# Generate readiness and health check sections
|
|
1351
|
+
readiness_section = self._generate_readiness_section(self.project_path)
|
|
1352
|
+
health_section = self._generate_health_section(self.project_path)
|
|
1353
|
+
|
|
1354
|
+
# No longer need the check helper function since we use direct imports
|
|
1355
|
+
check_helper_section = []
|
|
1213
1356
|
|
|
1214
1357
|
# Combine all sections
|
|
1215
1358
|
# Order: imports, env_section, startup_section, auth_setup, server_code (mcp init),
|
|
1216
1359
|
# early_telemetry_init, early_metrics_init, component_registrations,
|
|
1217
|
-
# metrics_route_code,
|
|
1360
|
+
# metrics_route_code, check_helper_section, readiness_section, health_section, main_code (run block)
|
|
1218
1361
|
code = "\n".join(
|
|
1219
1362
|
imports
|
|
1220
1363
|
+ env_section
|
|
@@ -1225,7 +1368,9 @@ class CodeGenerator:
|
|
|
1225
1368
|
+ early_metrics_init
|
|
1226
1369
|
+ component_registrations
|
|
1227
1370
|
+ metrics_route_code
|
|
1228
|
-
+
|
|
1371
|
+
+ check_helper_section
|
|
1372
|
+
+ readiness_section
|
|
1373
|
+
+ health_section
|
|
1229
1374
|
+ main_code
|
|
1230
1375
|
)
|
|
1231
1376
|
|
|
@@ -1427,6 +1572,17 @@ def build_project(
|
|
|
1427
1572
|
shutil.copy2(startup_path, dest_path)
|
|
1428
1573
|
console.print(get_status_text("success", "Startup script copied to build directory"))
|
|
1429
1574
|
|
|
1575
|
+
# Copy optional check files to build directory
|
|
1576
|
+
readiness_path = project_path / "readiness.py"
|
|
1577
|
+
if readiness_path.exists():
|
|
1578
|
+
shutil.copy2(readiness_path, output_dir)
|
|
1579
|
+
console.print(get_status_text("success", "Readiness script copied to build directory"))
|
|
1580
|
+
|
|
1581
|
+
health_path = project_path / "health.py"
|
|
1582
|
+
if health_path.exists():
|
|
1583
|
+
shutil.copy2(health_path, output_dir)
|
|
1584
|
+
console.print(get_status_text("success", "Health script copied to build directory"))
|
|
1585
|
+
|
|
1430
1586
|
# Platform registration (only for prod builds)
|
|
1431
1587
|
if build_env == "prod":
|
|
1432
1588
|
console.print()
|
golf/core/config.py
CHANGED
|
@@ -83,9 +83,9 @@ class Settings(BaseSettings):
|
|
|
83
83
|
)
|
|
84
84
|
|
|
85
85
|
# Health check configuration
|
|
86
|
-
health_check_enabled: bool = Field(False, description="Enable health check endpoint")
|
|
86
|
+
health_check_enabled: bool = Field(False, description="Enable health check endpoint (deprecated - use health.py)")
|
|
87
87
|
health_check_path: str = Field("/health", description="Health check endpoint path")
|
|
88
|
-
health_check_response: str = Field("OK", description="Health check response text")
|
|
88
|
+
health_check_response: str = Field("OK", description="Health check response text (deprecated - use health.py)")
|
|
89
89
|
|
|
90
90
|
# HTTP session behaviour
|
|
91
91
|
stateless_http: bool = Field(
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
golf/__init__.py,sha256=
|
|
1
|
+
golf/__init__.py,sha256=OpQ-bTTwRbO4KTjcnQgvU8ccnCWbcM-xPCnqQkEJNz0,307
|
|
2
2
|
golf/_endpoints.py,sha256=-mvAmjx3YtqfAdajO13Kv7LKVBMdqsKqX0_3aCmCK4I,317
|
|
3
3
|
golf/_endpoints.py.in,sha256=MeqcSF6xinnPknpBGF26xA9FYmSYKSWqCFXOSDlXiOA,216
|
|
4
4
|
golf/_endpoints_fallback.py,sha256=CD6m45Ams1A9HVKowY8dCFUDMiFmJ8ZWSwHCENvU5u4,386
|
|
@@ -16,11 +16,11 @@ golf/commands/build.py,sha256=sLq9lSW4naq2vIlBreKI5SGnviQrhBWw13zfOZOKhuM,2293
|
|
|
16
16
|
golf/commands/init.py,sha256=KkAg_3-KxBDFOcZqUHqcPAkDipykFVaLWpQ2tydnVPk,9617
|
|
17
17
|
golf/commands/run.py,sha256=a8GSwLt6E2cUJespv-u3jbD-rNUMHqF3VArD1uXV-Vk,4299
|
|
18
18
|
golf/core/__init__.py,sha256=4bKeskJ2fPaZqkz2xQScSa3phRLLrmrczwSL632jv-o,52
|
|
19
|
-
golf/core/builder.py,sha256
|
|
19
|
+
golf/core/builder.py,sha256=c0Phx77jkEJnks-FGN7ONuBmC5tQsVIHbwJxQkDAjKE,78180
|
|
20
20
|
golf/core/builder_auth.py,sha256=SXPCpc5ipntoNqIAIA2ZCeGmEua6QVs7yC3MDtGKAro,8224
|
|
21
21
|
golf/core/builder_metrics.py,sha256=j6Gtgd867o46JbDfSNGNsHt1QtV1XHKUJs1z8r4siQM,8830
|
|
22
22
|
golf/core/builder_telemetry.py,sha256=86bp7UlMUN6JyQRrZ5EizovP6AJ_q65OANJTeJXDIKc,3421
|
|
23
|
-
golf/core/config.py,sha256=
|
|
23
|
+
golf/core/config.py,sha256=BD4bfyzIv1TZYDmBQTuzSXNF6aHfzWXY65LemAxdjNo,7510
|
|
24
24
|
golf/core/parser.py,sha256=f9WqmLWlFuXQCObl2Qmna9bp_Bo0p0eIlukzwFaBSzo,43373
|
|
25
25
|
golf/core/platform.py,sha256=0TxLfVPBhBR82aJAQWEJcnkGuQv65C9gYYy7P2foUVk,6662
|
|
26
26
|
golf/core/telemetry.py,sha256=dXoWrgrQpj_HGrl_8TBZmRnuLxFKEn0GSDWQ9qq3ZQM,15686
|
|
@@ -48,9 +48,9 @@ golf/utilities/__init__.py,sha256=X9iY9yi3agz1GVcn8-qWeOCt8CSSsruHxqPNtiF63TY,53
|
|
|
48
48
|
golf/utilities/context.py,sha256=DGGvhVe---QMhy0wtdWhNp-_WVk1NvAcOFn0uBKBpYo,1579
|
|
49
49
|
golf/utilities/elicitation.py,sha256=MParZZZsY45s70-KXduHa6IvpWXnLW2FCPfrGijMaHs,5223
|
|
50
50
|
golf/utilities/sampling.py,sha256=88nDv-trBE4gZQbcnMjXl3LW6TiIhv5zR_cuEIGjaIM,7233
|
|
51
|
-
golf_mcp-0.2.
|
|
52
|
-
golf_mcp-0.2.
|
|
53
|
-
golf_mcp-0.2.
|
|
54
|
-
golf_mcp-0.2.
|
|
55
|
-
golf_mcp-0.2.
|
|
56
|
-
golf_mcp-0.2.
|
|
51
|
+
golf_mcp-0.2.11.dist-info/licenses/LICENSE,sha256=5_j2f6fTJmvfmUewzElhkpAaXg2grVoxKouOA8ihV6E,11348
|
|
52
|
+
golf_mcp-0.2.11.dist-info/METADATA,sha256=DDudTuflPauNfgHynFhldQLFI7MlJ-leZBZBhAdZpuY,9371
|
|
53
|
+
golf_mcp-0.2.11.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
54
|
+
golf_mcp-0.2.11.dist-info/entry_points.txt,sha256=5y7rHYM8jGpU-nfwdknCm5XsApLulqsnA37MO6BUTYg,43
|
|
55
|
+
golf_mcp-0.2.11.dist-info/top_level.txt,sha256=BQToHcBUufdyhp9ONGMIvPE40jMEtmI20lYaKb4hxOg,5
|
|
56
|
+
golf_mcp-0.2.11.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|