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 CHANGED
@@ -1,4 +1,4 @@
1
- __version__ = "0.2.10"
1
+ __version__ = "0.2.11"
2
2
 
3
3
  # Import endpoints with fallback for dev mode
4
4
  try:
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 if enabled
704
- if self.settings.health_check_enabled:
705
- imports.extend(
706
- [
707
- "from starlette.requests import Request",
708
- "from starlette.responses import PlainTextResponse",
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
- # Add health check route if enabled
1203
- health_check_code = []
1204
- if self.settings.health_check_enabled:
1205
- health_check_code = [
1206
- "# Add health check route",
1207
- "@mcp.custom_route('" + self.settings.health_check_path + '\', methods=["GET"])',
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, health_check_code, main_code (run block)
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
- + health_check_code
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,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: golf-mcp
3
- Version: 0.2.10
3
+ Version: 0.2.11
4
4
  Summary: Framework for building MCP servers
5
5
  Author-email: Antoni Gmitruk <antoni@golf.dev>
6
6
  License-Expression: Apache-2.0
@@ -1,4 +1,4 @@
1
- golf/__init__.py,sha256=KrLUEDZhh_8Gu_JcwZgGUhFN9JR6Sjqt8v46gVPBsmE,307
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=-iUhj1G5SKSE9kG9Y2glxQPp3b45fqXVrYi3gQGmgbs,69963
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=h8LWKdD-5vS8vRGs1qsCI2d8EbtjIKuXM3rUJ0T7EZ8,7452
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.10.dist-info/licenses/LICENSE,sha256=5_j2f6fTJmvfmUewzElhkpAaXg2grVoxKouOA8ihV6E,11348
52
- golf_mcp-0.2.10.dist-info/METADATA,sha256=4YRKbcRjyZfBFPFcnzJ5ZV8hU3enJEVmQy2VumwVlpc,9371
53
- golf_mcp-0.2.10.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
54
- golf_mcp-0.2.10.dist-info/entry_points.txt,sha256=5y7rHYM8jGpU-nfwdknCm5XsApLulqsnA37MO6BUTYg,43
55
- golf_mcp-0.2.10.dist-info/top_level.txt,sha256=BQToHcBUufdyhp9ONGMIvPE40jMEtmI20lYaKb4hxOg,5
56
- golf_mcp-0.2.10.dist-info/RECORD,,
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,,