golf-mcp 0.2.1__tar.gz → 0.2.3__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 (111) hide show
  1. {golf_mcp-0.2.1 → golf_mcp-0.2.3}/MANIFEST.in +1 -0
  2. {golf_mcp-0.2.1 → golf_mcp-0.2.3}/PKG-INFO +1 -1
  3. {golf_mcp-0.2.1 → golf_mcp-0.2.3}/pyproject.toml +2 -2
  4. {golf_mcp-0.2.1 → golf_mcp-0.2.3}/src/golf/__init__.py +1 -1
  5. golf_mcp-0.2.3/src/golf/_endpoints.py.in +6 -0
  6. {golf_mcp-0.2.1 → golf_mcp-0.2.3}/src/golf/auth/__init__.py +4 -4
  7. {golf_mcp-0.2.1 → golf_mcp-0.2.3}/src/golf/auth/factory.py +4 -2
  8. {golf_mcp-0.2.1 → golf_mcp-0.2.3}/src/golf/auth/providers.py +169 -1
  9. {golf_mcp-0.2.1 → golf_mcp-0.2.3}/src/golf/core/builder_auth.py +2 -2
  10. {golf_mcp-0.2.1 → golf_mcp-0.2.3}/src/golf_mcp.egg-info/PKG-INFO +1 -1
  11. golf_mcp-0.2.3/src/golf_mcp.egg-info/SOURCES.txt +63 -0
  12. golf_mcp-0.2.1/src/golf/examples/basic/.coverage +0 -0
  13. golf_mcp-0.2.1/src/golf/examples/basic/htmlcov/.gitignore +0 -2
  14. golf_mcp-0.2.1/src/golf/examples/basic/htmlcov/class_index.html +0 -547
  15. golf_mcp-0.2.1/src/golf/examples/basic/htmlcov/coverage_html_cb_6fb7b396.js +0 -733
  16. golf_mcp-0.2.1/src/golf/examples/basic/htmlcov/favicon_32_cb_58284776.png +0 -0
  17. golf_mcp-0.2.1/src/golf/examples/basic/htmlcov/function_index.html +0 -2091
  18. golf_mcp-0.2.1/src/golf/examples/basic/htmlcov/index.html +0 -349
  19. golf_mcp-0.2.1/src/golf/examples/basic/htmlcov/keybd_closed_cb_ce680311.png +0 -0
  20. golf_mcp-0.2.1/src/golf/examples/basic/htmlcov/status.json +0 -1
  21. golf_mcp-0.2.1/src/golf/examples/basic/htmlcov/style_cb_8e611ae1.css +0 -337
  22. golf_mcp-0.2.1/src/golf/examples/basic/htmlcov/z_1c9a91c0e91c8496___init___py.html +0 -323
  23. golf_mcp-0.2.1/src/golf/examples/basic/htmlcov/z_1c9a91c0e91c8496_api_key_py.html +0 -170
  24. golf_mcp-0.2.1/src/golf/examples/basic/htmlcov/z_1c9a91c0e91c8496_factory_py.html +0 -430
  25. golf_mcp-0.2.1/src/golf/examples/basic/htmlcov/z_1c9a91c0e91c8496_helpers_py.html +0 -288
  26. golf_mcp-0.2.1/src/golf/examples/basic/htmlcov/z_1c9a91c0e91c8496_providers_py.html +0 -493
  27. golf_mcp-0.2.1/src/golf/examples/basic/htmlcov/z_1c9a91c0e91c8496_registry_py.html +0 -353
  28. golf_mcp-0.2.1/src/golf/examples/basic/htmlcov/z_3ec3b3f490dc0950___init___py.html +0 -120
  29. golf_mcp-0.2.1/src/golf/examples/basic/htmlcov/z_3ec3b3f490dc0950_instrumentation_py.html +0 -1535
  30. golf_mcp-0.2.1/src/golf/examples/basic/htmlcov/z_4b8b9dd4ccccc5db___init___py.html +0 -98
  31. golf_mcp-0.2.1/src/golf/examples/basic/htmlcov/z_4b8b9dd4ccccc5db_branding_py.html +0 -289
  32. golf_mcp-0.2.1/src/golf/examples/basic/htmlcov/z_4b8b9dd4ccccc5db_main_py.html +0 -476
  33. golf_mcp-0.2.1/src/golf/examples/basic/htmlcov/z_5a6c4e6bcc86fb2f___init___py.html +0 -97
  34. golf_mcp-0.2.1/src/golf/examples/basic/htmlcov/z_6cadab9ec0df475d___init___py.html +0 -102
  35. golf_mcp-0.2.1/src/golf/examples/basic/htmlcov/z_6cadab9ec0df475d_build_py.html +0 -178
  36. golf_mcp-0.2.1/src/golf/examples/basic/htmlcov/z_6cadab9ec0df475d_init_py.html +0 -387
  37. golf_mcp-0.2.1/src/golf/examples/basic/htmlcov/z_6cadab9ec0df475d_run_py.html +0 -222
  38. golf_mcp-0.2.1/src/golf/examples/basic/htmlcov/z_6fcdee0582ba84e4___init___py.html +0 -106
  39. golf_mcp-0.2.1/src/golf/examples/basic/htmlcov/z_6fcdee0582ba84e4__endpoints_fallback_py.html +0 -107
  40. golf_mcp-0.2.1/src/golf/examples/basic/htmlcov/z_7ba499ed22986217___init___py.html +0 -98
  41. golf_mcp-0.2.1/src/golf/examples/basic/htmlcov/z_7ba499ed22986217_builder_auth_py.html +0 -306
  42. golf_mcp-0.2.1/src/golf/examples/basic/htmlcov/z_7ba499ed22986217_builder_metrics_py.html +0 -329
  43. golf_mcp-0.2.1/src/golf/examples/basic/htmlcov/z_7ba499ed22986217_builder_py.html +0 -1471
  44. golf_mcp-0.2.1/src/golf/examples/basic/htmlcov/z_7ba499ed22986217_builder_telemetry_py.html +0 -186
  45. golf_mcp-0.2.1/src/golf/examples/basic/htmlcov/z_7ba499ed22986217_config_py.html +0 -315
  46. golf_mcp-0.2.1/src/golf/examples/basic/htmlcov/z_7ba499ed22986217_parser_py.html +0 -1149
  47. golf_mcp-0.2.1/src/golf/examples/basic/htmlcov/z_7ba499ed22986217_platform_py.html +0 -279
  48. golf_mcp-0.2.1/src/golf/examples/basic/htmlcov/z_7ba499ed22986217_telemetry_py.html +0 -589
  49. golf_mcp-0.2.1/src/golf/examples/basic/htmlcov/z_7ba499ed22986217_transformer_py.html +0 -286
  50. golf_mcp-0.2.1/src/golf/examples/basic/htmlcov/z_7d7da37693a43688___init___py.html +0 -107
  51. golf_mcp-0.2.1/src/golf/examples/basic/htmlcov/z_7d7da37693a43688_collector_py.html +0 -417
  52. golf_mcp-0.2.1/src/golf/examples/basic/htmlcov/z_7d7da37693a43688_registry_py.html +0 -109
  53. golf_mcp-0.2.1/src/golf/examples/basic/htmlcov/z_abe733142b40ad4e___init___py.html +0 -109
  54. golf_mcp-0.2.1/src/golf/examples/basic/htmlcov/z_abe733142b40ad4e_context_py.html +0 -150
  55. golf_mcp-0.2.1/src/golf/examples/basic/htmlcov/z_abe733142b40ad4e_elicitation_py.html +0 -267
  56. golf_mcp-0.2.1/src/golf/examples/basic/htmlcov/z_abe733142b40ad4e_sampling_py.html +0 -318
  57. golf_mcp-0.2.1/src/golf_mcp.egg-info/SOURCES.txt +0 -107
  58. {golf_mcp-0.2.1 → golf_mcp-0.2.3}/.docs/docs.md +0 -0
  59. {golf_mcp-0.2.1 → golf_mcp-0.2.3}/.docs/fastmcp-diff.md +0 -0
  60. {golf_mcp-0.2.1 → golf_mcp-0.2.3}/.docs/mcp.md +0 -0
  61. {golf_mcp-0.2.1 → golf_mcp-0.2.3}/LICENSE +0 -0
  62. {golf_mcp-0.2.1 → golf_mcp-0.2.3}/README.md +0 -0
  63. {golf_mcp-0.2.1 → golf_mcp-0.2.3}/setup.cfg +0 -0
  64. {golf_mcp-0.2.1 → golf_mcp-0.2.3}/setup.py +0 -0
  65. {golf_mcp-0.2.1 → golf_mcp-0.2.3}/src/golf/_endpoints_fallback.py +0 -0
  66. {golf_mcp-0.2.1 → golf_mcp-0.2.3}/src/golf/auth/api_key.py +0 -0
  67. {golf_mcp-0.2.1 → golf_mcp-0.2.3}/src/golf/auth/helpers.py +0 -0
  68. {golf_mcp-0.2.1 → golf_mcp-0.2.3}/src/golf/auth/registry.py +0 -0
  69. {golf_mcp-0.2.1 → golf_mcp-0.2.3}/src/golf/cli/__init__.py +0 -0
  70. {golf_mcp-0.2.1 → golf_mcp-0.2.3}/src/golf/cli/branding.py +0 -0
  71. {golf_mcp-0.2.1 → golf_mcp-0.2.3}/src/golf/cli/main.py +0 -0
  72. {golf_mcp-0.2.1 → golf_mcp-0.2.3}/src/golf/commands/__init__.py +0 -0
  73. {golf_mcp-0.2.1 → golf_mcp-0.2.3}/src/golf/commands/build.py +0 -0
  74. {golf_mcp-0.2.1 → golf_mcp-0.2.3}/src/golf/commands/init.py +0 -0
  75. {golf_mcp-0.2.1 → golf_mcp-0.2.3}/src/golf/commands/run.py +0 -0
  76. {golf_mcp-0.2.1 → golf_mcp-0.2.3}/src/golf/core/__init__.py +0 -0
  77. {golf_mcp-0.2.1 → golf_mcp-0.2.3}/src/golf/core/builder.py +0 -0
  78. {golf_mcp-0.2.1 → golf_mcp-0.2.3}/src/golf/core/builder_metrics.py +0 -0
  79. {golf_mcp-0.2.1 → golf_mcp-0.2.3}/src/golf/core/builder_telemetry.py +0 -0
  80. {golf_mcp-0.2.1 → golf_mcp-0.2.3}/src/golf/core/config.py +0 -0
  81. {golf_mcp-0.2.1 → golf_mcp-0.2.3}/src/golf/core/parser.py +0 -0
  82. {golf_mcp-0.2.1 → golf_mcp-0.2.3}/src/golf/core/platform.py +0 -0
  83. {golf_mcp-0.2.1 → golf_mcp-0.2.3}/src/golf/core/telemetry.py +0 -0
  84. {golf_mcp-0.2.1 → golf_mcp-0.2.3}/src/golf/core/transformer.py +0 -0
  85. {golf_mcp-0.2.1 → golf_mcp-0.2.3}/src/golf/examples/__init__.py +0 -0
  86. {golf_mcp-0.2.1 → golf_mcp-0.2.3}/src/golf/examples/basic/.env.example +0 -0
  87. {golf_mcp-0.2.1 → golf_mcp-0.2.3}/src/golf/examples/basic/README.md +0 -0
  88. {golf_mcp-0.2.1 → golf_mcp-0.2.3}/src/golf/examples/basic/auth.py +0 -0
  89. {golf_mcp-0.2.1 → golf_mcp-0.2.3}/src/golf/examples/basic/golf.json +0 -0
  90. {golf_mcp-0.2.1 → golf_mcp-0.2.3}/src/golf/examples/basic/prompts/welcome.py +0 -0
  91. {golf_mcp-0.2.1 → golf_mcp-0.2.3}/src/golf/examples/basic/resources/current_time.py +0 -0
  92. {golf_mcp-0.2.1 → golf_mcp-0.2.3}/src/golf/examples/basic/resources/info.py +0 -0
  93. {golf_mcp-0.2.1 → golf_mcp-0.2.3}/src/golf/examples/basic/resources/weather/city.py +0 -0
  94. {golf_mcp-0.2.1 → golf_mcp-0.2.3}/src/golf/examples/basic/resources/weather/common.py +0 -0
  95. {golf_mcp-0.2.1 → golf_mcp-0.2.3}/src/golf/examples/basic/resources/weather/current.py +0 -0
  96. {golf_mcp-0.2.1 → golf_mcp-0.2.3}/src/golf/examples/basic/resources/weather/forecast.py +0 -0
  97. {golf_mcp-0.2.1 → golf_mcp-0.2.3}/src/golf/examples/basic/tools/calculator.py +0 -0
  98. {golf_mcp-0.2.1 → golf_mcp-0.2.3}/src/golf/examples/basic/tools/say/hello.py +0 -0
  99. {golf_mcp-0.2.1 → golf_mcp-0.2.3}/src/golf/metrics/__init__.py +0 -0
  100. {golf_mcp-0.2.1 → golf_mcp-0.2.3}/src/golf/metrics/collector.py +0 -0
  101. {golf_mcp-0.2.1 → golf_mcp-0.2.3}/src/golf/metrics/registry.py +0 -0
  102. {golf_mcp-0.2.1 → golf_mcp-0.2.3}/src/golf/telemetry/__init__.py +0 -0
  103. {golf_mcp-0.2.1 → golf_mcp-0.2.3}/src/golf/telemetry/instrumentation.py +0 -0
  104. {golf_mcp-0.2.1 → golf_mcp-0.2.3}/src/golf/utilities/__init__.py +0 -0
  105. {golf_mcp-0.2.1 → golf_mcp-0.2.3}/src/golf/utilities/context.py +0 -0
  106. {golf_mcp-0.2.1 → golf_mcp-0.2.3}/src/golf/utilities/elicitation.py +0 -0
  107. {golf_mcp-0.2.1 → golf_mcp-0.2.3}/src/golf/utilities/sampling.py +0 -0
  108. {golf_mcp-0.2.1 → golf_mcp-0.2.3}/src/golf_mcp.egg-info/dependency_links.txt +0 -0
  109. {golf_mcp-0.2.1 → golf_mcp-0.2.3}/src/golf_mcp.egg-info/entry_points.txt +0 -0
  110. {golf_mcp-0.2.1 → golf_mcp-0.2.3}/src/golf_mcp.egg-info/requires.txt +0 -0
  111. {golf_mcp-0.2.1 → golf_mcp-0.2.3}/src/golf_mcp.egg-info/top_level.txt +0 -0
@@ -1,6 +1,7 @@
1
1
  include README.md
2
2
  include LICENSE
3
3
  include pyproject.toml
4
+ include src/golf/_endpoints.py.in
4
5
  graft .docs
5
6
  graft src/golf/examples
6
7
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: golf-mcp
3
- Version: 0.2.1
3
+ Version: 0.2.3
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.1"
7
+ version = "0.2.3"
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.1"
69
+ version = "0.2.3"
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.1"
1
+ __version__ = "0.2.3"
2
2
 
3
3
  # Import endpoints with fallback for dev mode
4
4
  try:
@@ -0,0 +1,6 @@
1
+ # Auto-generated at build time by setup.py:build_py
2
+ # This template contains placeholders that are replaced during build
3
+
4
+ # Platform endpoints
5
+ PLATFORM_API_URL = "{PLATFORM_API_URL}"
6
+ OTEL_ENDPOINT = "{OTEL_ENDPOINT}"
@@ -206,14 +206,14 @@ def configure_oauth_proxy(
206
206
  redirect_path: str = "/oauth/callback",
207
207
  ) -> None:
208
208
  """Configure OAuth proxy authentication for non-DCR providers.
209
-
209
+
210
210
  This sets up an OAuth proxy that bridges MCP clients (expecting DCR) with
211
211
  traditional OAuth providers like GitHub, Google, Okta Web Apps that use
212
212
  fixed client credentials.
213
-
213
+
214
214
  Args:
215
215
  upstream_authorization_endpoint: Provider's authorization URL
216
- upstream_token_endpoint: Provider's token endpoint URL
216
+ upstream_token_endpoint: Provider's token endpoint URL
217
217
  upstream_client_id: Your client ID registered with the provider
218
218
  upstream_client_secret: Your client secret from the provider
219
219
  base_url: This proxy server's public URL
@@ -221,7 +221,7 @@ def configure_oauth_proxy(
221
221
  scopes_supported: Scopes to advertise to MCP clients
222
222
  upstream_revocation_endpoint: Optional token revocation endpoint
223
223
  redirect_path: OAuth callback path (default: /oauth/callback)
224
-
224
+
225
225
  Note:
226
226
  Requires golf-mcp-enterprise package for implementation.
227
227
  """
@@ -258,6 +258,7 @@ def _create_oauth_proxy_provider(config: OAuthProxyConfig) -> "AuthProvider":
258
258
  try:
259
259
  # Try to import from enterprise package
260
260
  from golf_enterprise import create_oauth_proxy_provider
261
+
261
262
  return create_oauth_proxy_provider(config)
262
263
  except ImportError as e:
263
264
  raise ImportError(
@@ -342,7 +343,8 @@ def register_builtin_providers() -> None:
342
343
  - static: Static token verification (development)
343
344
  - oauth_server: Full OAuth authorization server
344
345
  - remote: Remote authorization server integration
345
- - oauth_proxy: OAuth proxy for non-DCR providers (requires golf-mcp-enterprise)
346
+
347
+ Note: oauth_proxy provider is registered by the golf-mcp-enterprise package
346
348
  """
347
349
  registry = get_provider_registry()
348
350
 
@@ -351,7 +353,7 @@ def register_builtin_providers() -> None:
351
353
  registry.register_factory("static", _create_static_provider)
352
354
  registry.register_factory("oauth_server", _create_oauth_server_provider)
353
355
  registry.register_factory("remote", _create_remote_provider)
354
- registry.register_factory("oauth_proxy", _create_oauth_proxy_provider)
356
+ # oauth_proxy is registered by golf-mcp-enterprise package when installed
355
357
 
356
358
 
357
359
  # Register built-in providers when module is imported
@@ -442,5 +442,173 @@ class RemoteAuthConfig(BaseModel):
442
442
  return self
443
443
 
444
444
 
445
+ class OAuthProxyConfig(BaseModel):
446
+ """Configuration for OAuth proxy functionality (requires golf-mcp-enterprise).
447
+
448
+ This configuration enables bridging MCP clients (which expect Dynamic Client
449
+ Registration) with OAuth providers that use fixed client credentials like
450
+ GitHub Apps, Google Cloud Console apps, Okta Web Applications, etc.
451
+
452
+ The proxy acts as a DCR-capable authorization server to MCP clients while
453
+ using your fixed upstream client credentials with the actual OAuth provider.
454
+
455
+ Note: This class provides configuration only. The actual implementation
456
+ requires the golf-mcp-enterprise package.
457
+ """
458
+
459
+ provider_type: Literal["oauth_proxy"] = "oauth_proxy"
460
+
461
+ # Upstream OAuth provider configuration
462
+ upstream_authorization_endpoint: str = Field(..., description="Upstream provider's authorization endpoint URL")
463
+ upstream_token_endpoint: str = Field(..., description="Upstream provider's token endpoint URL")
464
+ upstream_client_id: str = Field(..., description="Your registered client ID with the upstream provider")
465
+ upstream_client_secret: str = Field(..., description="Your registered client secret with the upstream provider")
466
+ upstream_revocation_endpoint: str | None = Field(None, description="Optional upstream token revocation endpoint")
467
+
468
+ # This proxy server configuration
469
+ base_url: str = Field(..., description="Public URL of this OAuth proxy server")
470
+ redirect_path: str = Field("/oauth/callback", description="OAuth callback path (must match provider registration)")
471
+
472
+ # Scopes and token verification
473
+ scopes_supported: list[str] = Field(default_factory=list, description="Scopes supported by this proxy")
474
+ token_verifier_config: JWTAuthConfig | StaticTokenConfig = Field(
475
+ ..., description="Token verifier configuration for validating upstream tokens"
476
+ )
477
+
478
+ # Environment variable names for runtime configuration
479
+ upstream_authorization_endpoint_env_var: str | None = Field(
480
+ None, description="Environment variable name for upstream authorization endpoint"
481
+ )
482
+ upstream_token_endpoint_env_var: str | None = Field(
483
+ None, description="Environment variable name for upstream token endpoint"
484
+ )
485
+ upstream_client_id_env_var: str | None = Field(None, description="Environment variable name for upstream client ID")
486
+ upstream_client_secret_env_var: str | None = Field(
487
+ None, description="Environment variable name for upstream client secret"
488
+ )
489
+ upstream_revocation_endpoint_env_var: str | None = Field(
490
+ None, description="Environment variable name for upstream revocation endpoint"
491
+ )
492
+ base_url_env_var: str | None = Field(None, description="Environment variable name for base URL")
493
+
494
+ @field_validator("upstream_authorization_endpoint", "upstream_token_endpoint", "base_url")
495
+ @classmethod
496
+ def validate_required_urls(cls, v: str) -> str:
497
+ """Validate required URLs are properly formatted."""
498
+ if not v or not v.strip():
499
+ raise ValueError("URL cannot be empty")
500
+
501
+ url = v.strip()
502
+ try:
503
+ from urllib.parse import urlparse
504
+
505
+ parsed = urlparse(url)
506
+ if not parsed.scheme or not parsed.netloc:
507
+ raise ValueError(f"Invalid URL format: '{url}' - must include scheme and netloc")
508
+ if parsed.scheme not in ("http", "https"):
509
+ raise ValueError(f"URL must use http or https scheme: '{url}'")
510
+ except Exception as e:
511
+ if isinstance(e, ValueError):
512
+ raise
513
+ raise ValueError(f"Invalid URL '{url}': {e}") from e
514
+
515
+ return url
516
+
517
+ @field_validator("upstream_revocation_endpoint")
518
+ @classmethod
519
+ def validate_optional_url(cls, v: str | None) -> str | None:
520
+ """Validate optional URLs are properly formatted."""
521
+ if not v:
522
+ return v
523
+
524
+ url = v.strip()
525
+ if not url:
526
+ return None
527
+
528
+ try:
529
+ from urllib.parse import urlparse
530
+
531
+ parsed = urlparse(url)
532
+ if not parsed.scheme or not parsed.netloc:
533
+ raise ValueError(f"Invalid URL format: '{url}' - must include scheme and netloc")
534
+ if parsed.scheme not in ("http", "https"):
535
+ raise ValueError(f"URL must use http or https scheme: '{url}'")
536
+ except Exception as e:
537
+ if isinstance(e, ValueError):
538
+ raise
539
+ raise ValueError(f"Invalid URL '{url}': {e}") from e
540
+
541
+ return url
542
+
543
+ @field_validator("scopes_supported")
544
+ @classmethod
545
+ def validate_scopes_supported(cls, v: list[str]) -> list[str]:
546
+ """Validate scopes_supported format and security."""
547
+ if not v:
548
+ return v
549
+
550
+ cleaned_scopes = []
551
+ for scope in v:
552
+ scope = scope.strip()
553
+ if not scope:
554
+ raise ValueError("Scopes cannot be empty or whitespace-only")
555
+
556
+ # OAuth 2.0 scope format validation (RFC 6749)
557
+ if not all(32 < ord(c) < 127 and c not in ' "\\' for c in scope):
558
+ raise ValueError(
559
+ f"Invalid scope format: '{scope}' - must be ASCII printable without spaces, quotes, or backslashes"
560
+ )
561
+
562
+ # Reasonable length limit to prevent abuse
563
+ if len(scope) > 128:
564
+ raise ValueError(f"Scope too long: '{scope}' - maximum 128 characters")
565
+
566
+ cleaned_scopes.append(scope)
567
+
568
+ return cleaned_scopes
569
+
570
+ @model_validator(mode="after")
571
+ def validate_oauth_proxy_config(self) -> "OAuthProxyConfig":
572
+ """Validate OAuth proxy configuration consistency."""
573
+ # Validate token verifier config is compatible
574
+ if not isinstance(self.token_verifier_config, JWTAuthConfig | StaticTokenConfig):
575
+ raise ValueError(
576
+ f"token_verifier_config must be JWTAuthConfig or StaticTokenConfig, got {type(self.token_verifier_config).__name__}"
577
+ )
578
+
579
+ # Warn about HTTPS requirements in production
580
+ is_production = (
581
+ os.environ.get("GOLF_ENV", "").lower() in ("prod", "production")
582
+ or os.environ.get("NODE_ENV", "").lower() == "production"
583
+ or os.environ.get("ENVIRONMENT", "").lower() in ("prod", "production")
584
+ )
585
+
586
+ if is_production:
587
+ from urllib.parse import urlparse
588
+
589
+ urls_to_check = [
590
+ ("base_url", self.base_url),
591
+ ("upstream_authorization_endpoint", self.upstream_authorization_endpoint),
592
+ ("upstream_token_endpoint", self.upstream_token_endpoint),
593
+ ]
594
+
595
+ if self.upstream_revocation_endpoint:
596
+ urls_to_check.append(("upstream_revocation_endpoint", self.upstream_revocation_endpoint))
597
+
598
+ for field_name, url in urls_to_check:
599
+ parsed = urlparse(url)
600
+ if parsed.scheme == "http":
601
+ import warnings
602
+
603
+ warnings.warn(
604
+ f"OAuth proxy {field_name} '{url}' uses HTTP in production environment. "
605
+ "HTTPS is strongly recommended for OAuth endpoints to prevent token interception.",
606
+ UserWarning,
607
+ stacklevel=2,
608
+ )
609
+
610
+ return self
611
+
612
+
445
613
  # Union type for all auth configurations
446
- AuthConfig = JWTAuthConfig | StaticTokenConfig | OAuthServerConfig | RemoteAuthConfig
614
+ AuthConfig = JWTAuthConfig | StaticTokenConfig | OAuthServerConfig | RemoteAuthConfig | OAuthProxyConfig
@@ -64,7 +64,7 @@ def generate_auth_code(
64
64
  f"auth_config = {auth_config_repr}",
65
65
  "try:",
66
66
  " auth_provider = create_auth_provider(auth_config)",
67
- " print(f'Authentication configured with {auth_config.provider_type} provider')",
67
+ " # Authentication configured with {auth_config.provider_type} provider",
68
68
  "except Exception as e:",
69
69
  " print(f'Authentication setup failed: {e}', file=sys.stderr)",
70
70
  " auth_provider = None",
@@ -203,7 +203,7 @@ if auth_provider and hasattr(auth_provider, 'get_routes'):
203
203
  # Add routes to FastMCP's additional HTTP routes list
204
204
  try:
205
205
  mcp._additional_http_routes.extend(auth_routes)
206
- print(f"Added {len(auth_routes)} OAuth metadata routes")
206
+ # Added {len(auth_routes)} OAuth metadata routes
207
207
  except Exception as e:
208
208
  print(f"Warning: Failed to add OAuth routes: {e}")
209
209
  """
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: golf-mcp
3
- Version: 0.2.1
3
+ Version: 0.2.3
4
4
  Summary: Framework for building MCP servers
5
5
  Author-email: Antoni Gmitruk <antoni@golf.dev>
6
6
  License-Expression: Apache-2.0
@@ -0,0 +1,63 @@
1
+ LICENSE
2
+ MANIFEST.in
3
+ README.md
4
+ pyproject.toml
5
+ setup.py
6
+ .docs/docs.md
7
+ .docs/fastmcp-diff.md
8
+ .docs/mcp.md
9
+ src/golf/__init__.py
10
+ src/golf/_endpoints.py.in
11
+ src/golf/_endpoints_fallback.py
12
+ src/golf/auth/__init__.py
13
+ src/golf/auth/api_key.py
14
+ src/golf/auth/factory.py
15
+ src/golf/auth/helpers.py
16
+ src/golf/auth/providers.py
17
+ src/golf/auth/registry.py
18
+ src/golf/cli/__init__.py
19
+ src/golf/cli/branding.py
20
+ src/golf/cli/main.py
21
+ src/golf/commands/__init__.py
22
+ src/golf/commands/build.py
23
+ src/golf/commands/init.py
24
+ src/golf/commands/run.py
25
+ src/golf/core/__init__.py
26
+ src/golf/core/builder.py
27
+ src/golf/core/builder_auth.py
28
+ src/golf/core/builder_metrics.py
29
+ src/golf/core/builder_telemetry.py
30
+ src/golf/core/config.py
31
+ src/golf/core/parser.py
32
+ src/golf/core/platform.py
33
+ src/golf/core/telemetry.py
34
+ src/golf/core/transformer.py
35
+ src/golf/examples/__init__.py
36
+ src/golf/examples/basic/.env.example
37
+ src/golf/examples/basic/README.md
38
+ src/golf/examples/basic/auth.py
39
+ src/golf/examples/basic/golf.json
40
+ src/golf/examples/basic/prompts/welcome.py
41
+ src/golf/examples/basic/resources/current_time.py
42
+ src/golf/examples/basic/resources/info.py
43
+ src/golf/examples/basic/resources/weather/city.py
44
+ src/golf/examples/basic/resources/weather/common.py
45
+ src/golf/examples/basic/resources/weather/current.py
46
+ src/golf/examples/basic/resources/weather/forecast.py
47
+ src/golf/examples/basic/tools/calculator.py
48
+ src/golf/examples/basic/tools/say/hello.py
49
+ src/golf/metrics/__init__.py
50
+ src/golf/metrics/collector.py
51
+ src/golf/metrics/registry.py
52
+ src/golf/telemetry/__init__.py
53
+ src/golf/telemetry/instrumentation.py
54
+ src/golf/utilities/__init__.py
55
+ src/golf/utilities/context.py
56
+ src/golf/utilities/elicitation.py
57
+ src/golf/utilities/sampling.py
58
+ src/golf_mcp.egg-info/PKG-INFO
59
+ src/golf_mcp.egg-info/SOURCES.txt
60
+ src/golf_mcp.egg-info/dependency_links.txt
61
+ src/golf_mcp.egg-info/entry_points.txt
62
+ src/golf_mcp.egg-info/requires.txt
63
+ src/golf_mcp.egg-info/top_level.txt
@@ -1,2 +0,0 @@
1
- # Created by coverage.py
2
- *