golf-mcp 0.2.7__tar.gz → 0.2.10__tar.gz

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.

Files changed (65) hide show
  1. {golf_mcp-0.2.7 → golf_mcp-0.2.10}/PKG-INFO +1 -1
  2. {golf_mcp-0.2.7 → golf_mcp-0.2.10}/pyproject.toml +2 -2
  3. {golf_mcp-0.2.7 → golf_mcp-0.2.10}/src/golf/__init__.py +1 -1
  4. {golf_mcp-0.2.7 → golf_mcp-0.2.10}/src/golf/auth/__init__.py +6 -1
  5. {golf_mcp-0.2.7 → golf_mcp-0.2.10}/src/golf/auth/providers.py +5 -29
  6. {golf_mcp-0.2.7 → golf_mcp-0.2.10}/src/golf/core/builder.py +76 -1
  7. {golf_mcp-0.2.7 → golf_mcp-0.2.10}/src/golf_mcp.egg-info/PKG-INFO +1 -1
  8. {golf_mcp-0.2.7 → golf_mcp-0.2.10}/.docs/docs.md +0 -0
  9. {golf_mcp-0.2.7 → golf_mcp-0.2.10}/.docs/fastmcp-diff.md +0 -0
  10. {golf_mcp-0.2.7 → golf_mcp-0.2.10}/.docs/mcp.md +0 -0
  11. {golf_mcp-0.2.7 → golf_mcp-0.2.10}/LICENSE +0 -0
  12. {golf_mcp-0.2.7 → golf_mcp-0.2.10}/MANIFEST.in +0 -0
  13. {golf_mcp-0.2.7 → golf_mcp-0.2.10}/README.md +0 -0
  14. {golf_mcp-0.2.7 → golf_mcp-0.2.10}/setup.cfg +0 -0
  15. {golf_mcp-0.2.7 → golf_mcp-0.2.10}/setup.py +0 -0
  16. {golf_mcp-0.2.7 → golf_mcp-0.2.10}/src/golf/_endpoints.py.in +0 -0
  17. {golf_mcp-0.2.7 → golf_mcp-0.2.10}/src/golf/_endpoints_fallback.py +0 -0
  18. {golf_mcp-0.2.7 → golf_mcp-0.2.10}/src/golf/auth/api_key.py +0 -0
  19. {golf_mcp-0.2.7 → golf_mcp-0.2.10}/src/golf/auth/factory.py +0 -0
  20. {golf_mcp-0.2.7 → golf_mcp-0.2.10}/src/golf/auth/helpers.py +0 -0
  21. {golf_mcp-0.2.7 → golf_mcp-0.2.10}/src/golf/auth/registry.py +0 -0
  22. {golf_mcp-0.2.7 → golf_mcp-0.2.10}/src/golf/cli/__init__.py +0 -0
  23. {golf_mcp-0.2.7 → golf_mcp-0.2.10}/src/golf/cli/branding.py +0 -0
  24. {golf_mcp-0.2.7 → golf_mcp-0.2.10}/src/golf/cli/main.py +0 -0
  25. {golf_mcp-0.2.7 → golf_mcp-0.2.10}/src/golf/commands/__init__.py +0 -0
  26. {golf_mcp-0.2.7 → golf_mcp-0.2.10}/src/golf/commands/build.py +0 -0
  27. {golf_mcp-0.2.7 → golf_mcp-0.2.10}/src/golf/commands/init.py +0 -0
  28. {golf_mcp-0.2.7 → golf_mcp-0.2.10}/src/golf/commands/run.py +0 -0
  29. {golf_mcp-0.2.7 → golf_mcp-0.2.10}/src/golf/core/__init__.py +0 -0
  30. {golf_mcp-0.2.7 → golf_mcp-0.2.10}/src/golf/core/builder_auth.py +0 -0
  31. {golf_mcp-0.2.7 → golf_mcp-0.2.10}/src/golf/core/builder_metrics.py +0 -0
  32. {golf_mcp-0.2.7 → golf_mcp-0.2.10}/src/golf/core/builder_telemetry.py +0 -0
  33. {golf_mcp-0.2.7 → golf_mcp-0.2.10}/src/golf/core/config.py +0 -0
  34. {golf_mcp-0.2.7 → golf_mcp-0.2.10}/src/golf/core/parser.py +0 -0
  35. {golf_mcp-0.2.7 → golf_mcp-0.2.10}/src/golf/core/platform.py +0 -0
  36. {golf_mcp-0.2.7 → golf_mcp-0.2.10}/src/golf/core/telemetry.py +0 -0
  37. {golf_mcp-0.2.7 → golf_mcp-0.2.10}/src/golf/core/transformer.py +0 -0
  38. {golf_mcp-0.2.7 → golf_mcp-0.2.10}/src/golf/examples/__init__.py +0 -0
  39. {golf_mcp-0.2.7 → golf_mcp-0.2.10}/src/golf/examples/basic/.env.example +0 -0
  40. {golf_mcp-0.2.7 → golf_mcp-0.2.10}/src/golf/examples/basic/README.md +0 -0
  41. {golf_mcp-0.2.7 → golf_mcp-0.2.10}/src/golf/examples/basic/auth.py +0 -0
  42. {golf_mcp-0.2.7 → golf_mcp-0.2.10}/src/golf/examples/basic/golf.json +0 -0
  43. {golf_mcp-0.2.7 → golf_mcp-0.2.10}/src/golf/examples/basic/prompts/welcome.py +0 -0
  44. {golf_mcp-0.2.7 → golf_mcp-0.2.10}/src/golf/examples/basic/resources/current_time.py +0 -0
  45. {golf_mcp-0.2.7 → golf_mcp-0.2.10}/src/golf/examples/basic/resources/info.py +0 -0
  46. {golf_mcp-0.2.7 → golf_mcp-0.2.10}/src/golf/examples/basic/resources/weather/city.py +0 -0
  47. {golf_mcp-0.2.7 → golf_mcp-0.2.10}/src/golf/examples/basic/resources/weather/client.py +0 -0
  48. {golf_mcp-0.2.7 → golf_mcp-0.2.10}/src/golf/examples/basic/resources/weather/current.py +0 -0
  49. {golf_mcp-0.2.7 → golf_mcp-0.2.10}/src/golf/examples/basic/resources/weather/forecast.py +0 -0
  50. {golf_mcp-0.2.7 → golf_mcp-0.2.10}/src/golf/examples/basic/tools/calculator.py +0 -0
  51. {golf_mcp-0.2.7 → golf_mcp-0.2.10}/src/golf/examples/basic/tools/say/hello.py +0 -0
  52. {golf_mcp-0.2.7 → golf_mcp-0.2.10}/src/golf/metrics/__init__.py +0 -0
  53. {golf_mcp-0.2.7 → golf_mcp-0.2.10}/src/golf/metrics/collector.py +0 -0
  54. {golf_mcp-0.2.7 → golf_mcp-0.2.10}/src/golf/metrics/registry.py +0 -0
  55. {golf_mcp-0.2.7 → golf_mcp-0.2.10}/src/golf/telemetry/__init__.py +0 -0
  56. {golf_mcp-0.2.7 → golf_mcp-0.2.10}/src/golf/telemetry/instrumentation.py +0 -0
  57. {golf_mcp-0.2.7 → golf_mcp-0.2.10}/src/golf/utilities/__init__.py +0 -0
  58. {golf_mcp-0.2.7 → golf_mcp-0.2.10}/src/golf/utilities/context.py +0 -0
  59. {golf_mcp-0.2.7 → golf_mcp-0.2.10}/src/golf/utilities/elicitation.py +0 -0
  60. {golf_mcp-0.2.7 → golf_mcp-0.2.10}/src/golf/utilities/sampling.py +0 -0
  61. {golf_mcp-0.2.7 → golf_mcp-0.2.10}/src/golf_mcp.egg-info/SOURCES.txt +0 -0
  62. {golf_mcp-0.2.7 → golf_mcp-0.2.10}/src/golf_mcp.egg-info/dependency_links.txt +0 -0
  63. {golf_mcp-0.2.7 → golf_mcp-0.2.10}/src/golf_mcp.egg-info/entry_points.txt +0 -0
  64. {golf_mcp-0.2.7 → golf_mcp-0.2.10}/src/golf_mcp.egg-info/requires.txt +0 -0
  65. {golf_mcp-0.2.7 → golf_mcp-0.2.10}/src/golf_mcp.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: golf-mcp
3
- Version: 0.2.7
3
+ Version: 0.2.10
4
4
  Summary: Framework for building MCP servers
5
5
  Author-email: Antoni Gmitruk <antoni@golf.dev>
6
6
  License-Expression: Apache-2.0
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "golf-mcp"
7
- version = "0.2.7"
7
+ version = "0.2.10"
8
8
  description = "Framework for building MCP servers"
9
9
  authors = [
10
10
  {name = "Antoni Gmitruk", email = "antoni@golf.dev"}
@@ -66,7 +66,7 @@ golf = ["examples/**/*"]
66
66
 
67
67
  [tool.poetry]
68
68
  name = "golf-mcp"
69
- version = "0.2.7"
69
+ version = "0.2.10"
70
70
  description = "Framework for building MCP servers with zero boilerplate"
71
71
  authors = ["Antoni Gmitruk <antoni@golf.dev>"]
72
72
  license = "Apache-2.0"
@@ -1,4 +1,4 @@
1
- __version__ = "0.2.7"
1
+ __version__ = "0.2.10"
2
2
 
3
3
  # Import endpoints with fallback for dev mode
4
4
  try:
@@ -206,6 +206,7 @@ def configure_oauth_proxy(
206
206
  scopes_supported: list[str] | None = None,
207
207
  revocation_endpoint: str | None = None,
208
208
  redirect_path: str = "/oauth/callback",
209
+ **env_vars: str,
209
210
  ) -> None:
210
211
  """Configure OAuth proxy authentication for non-DCR providers.
211
212
 
@@ -223,6 +224,9 @@ def configure_oauth_proxy(
223
224
  scopes_supported: Scopes to advertise to MCP clients
224
225
  revocation_endpoint: Optional token revocation endpoint
225
226
  redirect_path: OAuth callback path (default: /oauth/callback)
227
+ **env_vars: Environment variable names (authorization_endpoint_env_var,
228
+ token_endpoint_env_var, client_id_env_var, client_secret_env_var,
229
+ base_url_env_var, revocation_endpoint_env_var)
226
230
 
227
231
  Note:
228
232
  Requires golf-mcp-enterprise package for implementation.
@@ -235,8 +239,9 @@ def configure_oauth_proxy(
235
239
  revocation_endpoint=revocation_endpoint,
236
240
  base_url=base_url,
237
241
  redirect_path=redirect_path,
238
- scopes_supported=scopes_supported or [],
242
+ scopes_supported=scopes_supported,
239
243
  token_verifier_config=token_verifier_config,
244
+ **env_vars,
240
245
  )
241
246
  configure_auth(config)
242
247
 
@@ -470,7 +470,9 @@ class OAuthProxyConfig(BaseModel):
470
470
  redirect_path: str = Field("/oauth/callback", description="OAuth callback path (must match provider registration)")
471
471
 
472
472
  # Scopes and token verification
473
- scopes_supported: list[str] = Field(default_factory=list, description="Scopes supported by this proxy")
473
+ scopes_supported: list[str] | None = Field(
474
+ None, description="Scopes supported by this proxy (optional, can be empty for intelligent fallback)"
475
+ )
474
476
  token_verifier_config: JWTAuthConfig | StaticTokenConfig = Field(
475
477
  ..., description="Token verifier configuration for validating upstream tokens"
476
478
  )
@@ -536,40 +538,14 @@ class OAuthProxyConfig(BaseModel):
536
538
 
537
539
  return url
538
540
 
539
- @field_validator("scopes_supported")
540
- @classmethod
541
- def validate_scopes_supported(cls, v: list[str]) -> list[str]:
542
- """Validate scopes_supported format and security."""
543
- if not v:
544
- return v
545
-
546
- cleaned_scopes = []
547
- for scope in v:
548
- scope = scope.strip()
549
- if not scope:
550
- raise ValueError("Scopes cannot be empty or whitespace-only")
551
-
552
- # OAuth 2.0 scope format validation (RFC 6749)
553
- if not all(32 < ord(c) < 127 and c not in ' "\\' for c in scope):
554
- raise ValueError(
555
- f"Invalid scope format: '{scope}' - must be ASCII printable without spaces, quotes, or backslashes"
556
- )
557
-
558
- # Reasonable length limit to prevent abuse
559
- if len(scope) > 128:
560
- raise ValueError(f"Scope too long: '{scope}' - maximum 128 characters")
561
-
562
- cleaned_scopes.append(scope)
563
-
564
- return cleaned_scopes
565
-
566
541
  @model_validator(mode="after")
567
542
  def validate_oauth_proxy_config(self) -> "OAuthProxyConfig":
568
543
  """Validate OAuth proxy configuration consistency."""
569
544
  # Validate token verifier config is compatible
570
545
  if not isinstance(self.token_verifier_config, JWTAuthConfig | StaticTokenConfig):
571
546
  raise ValueError(
572
- f"token_verifier_config must be JWTAuthConfig or StaticTokenConfig, got {type(self.token_verifier_config).__name__}"
547
+ f"token_verifier_config must be JWTAuthConfig or StaticTokenConfig, "
548
+ f"got {type(self.token_verifier_config).__name__}"
573
549
  )
574
550
 
575
551
  # Warn about HTTPS requirements in production
@@ -581,6 +581,70 @@ class CodeGenerator:
581
581
  # Default to older behavior for safety
582
582
  return False
583
583
 
584
+ def _generate_startup_section(self, project_path: Path) -> list[str]:
585
+ """Generate code section for startup.py execution during server runtime."""
586
+ startup_path = project_path / "startup.py"
587
+
588
+ if not startup_path.exists():
589
+ return []
590
+
591
+ return [
592
+ "",
593
+ "# Execute startup script for loading secrets and initialization",
594
+ "import importlib.util",
595
+ "import sys",
596
+ "import os",
597
+ "from pathlib import Path",
598
+ "",
599
+ "# Look for startup.py in the same directory as this server.py",
600
+ "startup_path = Path(__file__).parent / 'startup.py'",
601
+ "if startup_path.exists():",
602
+ " try:",
603
+ " # Save original environment for restoration",
604
+ " try:",
605
+ " original_dir = os.getcwd()",
606
+ " except (FileNotFoundError, OSError):",
607
+ " # Use server directory as fallback",
608
+ " original_dir = str(Path(__file__).parent)",
609
+ " os.chdir(original_dir)",
610
+ " original_path = sys.path.copy()",
611
+ " ",
612
+ " # Set context for startup script execution",
613
+ " script_dir = str(startup_path.parent)",
614
+ " os.chdir(script_dir)",
615
+ " sys.path.insert(0, script_dir)",
616
+ " ",
617
+ " # Debug output for startup script development",
618
+ " if os.environ.get('GOLF_DEBUG'):",
619
+ " print(f'Executing startup script: {startup_path}')",
620
+ " print(f'Working directory: {os.getcwd()}')",
621
+ " print(f'Python path: {sys.path[:3]}...')", # Show first 3 entries
622
+ " ",
623
+ " # Load and execute startup script",
624
+ " spec = importlib.util.spec_from_file_location('startup', startup_path)",
625
+ " if spec and spec.loader:",
626
+ " startup_module = importlib.util.module_from_spec(spec)",
627
+ " spec.loader.exec_module(startup_module)",
628
+ " else:",
629
+ " print('Warning: Could not load startup.py', file=sys.stderr)",
630
+ " ",
631
+ " except Exception as e:",
632
+ " import traceback",
633
+ " print(f'Warning: Startup script execution failed: {e}', file=sys.stderr)",
634
+ " print(traceback.format_exc(), file=sys.stderr)",
635
+ " # Continue server startup despite script failure",
636
+ " ",
637
+ " finally:",
638
+ " # Always restore original environment",
639
+ " try:",
640
+ " os.chdir(original_dir)",
641
+ " sys.path[:] = original_path",
642
+ " except Exception:",
643
+ " # If directory restoration fails, at least fix the path",
644
+ " sys.path[:] = original_path",
645
+ "",
646
+ ]
647
+
584
648
  def _generate_server(self) -> None:
585
649
  """Generate the main server entry point."""
586
650
  server_file = self.output_dir / "server.py"
@@ -935,6 +999,9 @@ class CodeGenerator:
935
999
  "",
936
1000
  ]
937
1001
 
1002
+ # Generate startup section
1003
+ startup_section = self._generate_startup_section(self.project_path)
1004
+
938
1005
  # OpenTelemetry setup code will be handled through imports and lifespan
939
1006
 
940
1007
  # Add auth setup code if auth is configured
@@ -1145,12 +1212,13 @@ class CodeGenerator:
1145
1212
  ]
1146
1213
 
1147
1214
  # Combine all sections
1148
- # Order: imports, env_section, auth_setup, server_code (mcp init),
1215
+ # Order: imports, env_section, startup_section, auth_setup, server_code (mcp init),
1149
1216
  # early_telemetry_init, early_metrics_init, component_registrations,
1150
1217
  # metrics_route_code, health_check_code, main_code (run block)
1151
1218
  code = "\n".join(
1152
1219
  imports
1153
1220
  + env_section
1221
+ + startup_section
1154
1222
  + auth_setup_code
1155
1223
  + server_code_lines
1156
1224
  + early_telemetry_init
@@ -1352,6 +1420,13 @@ def build_project(
1352
1420
  generator = CodeGenerator(project_path, settings, output_dir, build_env=build_env, copy_env=copy_env)
1353
1421
  generator.generate()
1354
1422
 
1423
+ # Copy startup.py to output directory if it exists (after server generation)
1424
+ startup_path = project_path / "startup.py"
1425
+ if startup_path.exists():
1426
+ dest_path = output_dir / "startup.py"
1427
+ shutil.copy2(startup_path, dest_path)
1428
+ console.print(get_status_text("success", "Startup script copied to build directory"))
1429
+
1355
1430
  # Platform registration (only for prod builds)
1356
1431
  if build_env == "prod":
1357
1432
  console.print()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: golf-mcp
3
- Version: 0.2.7
3
+ Version: 0.2.10
4
4
  Summary: Framework for building MCP servers
5
5
  Author-email: Antoni Gmitruk <antoni@golf.dev>
6
6
  License-Expression: Apache-2.0
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes