golf-mcp 0.2.0__tar.gz → 0.2.1__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 (109) hide show
  1. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/PKG-INFO +1 -1
  2. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/pyproject.toml +2 -2
  3. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/__init__.py +1 -1
  4. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/auth/__init__.py +48 -0
  5. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/auth/factory.py +25 -0
  6. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/auth/providers.py +50 -0
  7. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/core/builder_auth.py +1 -1
  8. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf_mcp.egg-info/PKG-INFO +1 -1
  9. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/.docs/docs.md +0 -0
  10. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/.docs/fastmcp-diff.md +0 -0
  11. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/.docs/mcp.md +0 -0
  12. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/LICENSE +0 -0
  13. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/MANIFEST.in +0 -0
  14. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/README.md +0 -0
  15. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/setup.cfg +0 -0
  16. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/setup.py +0 -0
  17. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/_endpoints_fallback.py +0 -0
  18. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/auth/api_key.py +0 -0
  19. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/auth/helpers.py +0 -0
  20. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/auth/registry.py +0 -0
  21. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/cli/__init__.py +0 -0
  22. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/cli/branding.py +0 -0
  23. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/cli/main.py +0 -0
  24. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/commands/__init__.py +0 -0
  25. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/commands/build.py +0 -0
  26. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/commands/init.py +0 -0
  27. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/commands/run.py +0 -0
  28. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/core/__init__.py +0 -0
  29. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/core/builder.py +0 -0
  30. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/core/builder_metrics.py +0 -0
  31. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/core/builder_telemetry.py +0 -0
  32. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/core/config.py +0 -0
  33. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/core/parser.py +0 -0
  34. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/core/platform.py +0 -0
  35. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/core/telemetry.py +0 -0
  36. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/core/transformer.py +0 -0
  37. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/examples/__init__.py +0 -0
  38. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/examples/basic/.coverage +0 -0
  39. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/examples/basic/.env.example +0 -0
  40. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/examples/basic/README.md +0 -0
  41. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/examples/basic/auth.py +0 -0
  42. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/examples/basic/golf.json +0 -0
  43. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/examples/basic/htmlcov/.gitignore +0 -0
  44. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/examples/basic/htmlcov/class_index.html +0 -0
  45. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/examples/basic/htmlcov/coverage_html_cb_6fb7b396.js +0 -0
  46. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/examples/basic/htmlcov/favicon_32_cb_58284776.png +0 -0
  47. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/examples/basic/htmlcov/function_index.html +0 -0
  48. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/examples/basic/htmlcov/index.html +0 -0
  49. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/examples/basic/htmlcov/keybd_closed_cb_ce680311.png +0 -0
  50. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/examples/basic/htmlcov/status.json +0 -0
  51. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/examples/basic/htmlcov/style_cb_8e611ae1.css +0 -0
  52. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/examples/basic/htmlcov/z_1c9a91c0e91c8496___init___py.html +0 -0
  53. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/examples/basic/htmlcov/z_1c9a91c0e91c8496_api_key_py.html +0 -0
  54. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/examples/basic/htmlcov/z_1c9a91c0e91c8496_factory_py.html +0 -0
  55. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/examples/basic/htmlcov/z_1c9a91c0e91c8496_helpers_py.html +0 -0
  56. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/examples/basic/htmlcov/z_1c9a91c0e91c8496_providers_py.html +0 -0
  57. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/examples/basic/htmlcov/z_1c9a91c0e91c8496_registry_py.html +0 -0
  58. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/examples/basic/htmlcov/z_3ec3b3f490dc0950___init___py.html +0 -0
  59. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/examples/basic/htmlcov/z_3ec3b3f490dc0950_instrumentation_py.html +0 -0
  60. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/examples/basic/htmlcov/z_4b8b9dd4ccccc5db___init___py.html +0 -0
  61. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/examples/basic/htmlcov/z_4b8b9dd4ccccc5db_branding_py.html +0 -0
  62. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/examples/basic/htmlcov/z_4b8b9dd4ccccc5db_main_py.html +0 -0
  63. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/examples/basic/htmlcov/z_5a6c4e6bcc86fb2f___init___py.html +0 -0
  64. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/examples/basic/htmlcov/z_6cadab9ec0df475d___init___py.html +0 -0
  65. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/examples/basic/htmlcov/z_6cadab9ec0df475d_build_py.html +0 -0
  66. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/examples/basic/htmlcov/z_6cadab9ec0df475d_init_py.html +0 -0
  67. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/examples/basic/htmlcov/z_6cadab9ec0df475d_run_py.html +0 -0
  68. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/examples/basic/htmlcov/z_6fcdee0582ba84e4___init___py.html +0 -0
  69. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/examples/basic/htmlcov/z_6fcdee0582ba84e4__endpoints_fallback_py.html +0 -0
  70. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/examples/basic/htmlcov/z_7ba499ed22986217___init___py.html +0 -0
  71. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/examples/basic/htmlcov/z_7ba499ed22986217_builder_auth_py.html +0 -0
  72. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/examples/basic/htmlcov/z_7ba499ed22986217_builder_metrics_py.html +0 -0
  73. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/examples/basic/htmlcov/z_7ba499ed22986217_builder_py.html +0 -0
  74. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/examples/basic/htmlcov/z_7ba499ed22986217_builder_telemetry_py.html +0 -0
  75. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/examples/basic/htmlcov/z_7ba499ed22986217_config_py.html +0 -0
  76. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/examples/basic/htmlcov/z_7ba499ed22986217_parser_py.html +0 -0
  77. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/examples/basic/htmlcov/z_7ba499ed22986217_platform_py.html +0 -0
  78. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/examples/basic/htmlcov/z_7ba499ed22986217_telemetry_py.html +0 -0
  79. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/examples/basic/htmlcov/z_7ba499ed22986217_transformer_py.html +0 -0
  80. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/examples/basic/htmlcov/z_7d7da37693a43688___init___py.html +0 -0
  81. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/examples/basic/htmlcov/z_7d7da37693a43688_collector_py.html +0 -0
  82. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/examples/basic/htmlcov/z_7d7da37693a43688_registry_py.html +0 -0
  83. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/examples/basic/htmlcov/z_abe733142b40ad4e___init___py.html +0 -0
  84. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/examples/basic/htmlcov/z_abe733142b40ad4e_context_py.html +0 -0
  85. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/examples/basic/htmlcov/z_abe733142b40ad4e_elicitation_py.html +0 -0
  86. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/examples/basic/htmlcov/z_abe733142b40ad4e_sampling_py.html +0 -0
  87. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/examples/basic/prompts/welcome.py +0 -0
  88. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/examples/basic/resources/current_time.py +0 -0
  89. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/examples/basic/resources/info.py +0 -0
  90. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/examples/basic/resources/weather/city.py +0 -0
  91. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/examples/basic/resources/weather/common.py +0 -0
  92. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/examples/basic/resources/weather/current.py +0 -0
  93. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/examples/basic/resources/weather/forecast.py +0 -0
  94. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/examples/basic/tools/calculator.py +0 -0
  95. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/examples/basic/tools/say/hello.py +0 -0
  96. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/metrics/__init__.py +0 -0
  97. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/metrics/collector.py +0 -0
  98. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/metrics/registry.py +0 -0
  99. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/telemetry/__init__.py +0 -0
  100. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/telemetry/instrumentation.py +0 -0
  101. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/utilities/__init__.py +0 -0
  102. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/utilities/context.py +0 -0
  103. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/utilities/elicitation.py +0 -0
  104. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf/utilities/sampling.py +0 -0
  105. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf_mcp.egg-info/SOURCES.txt +0 -0
  106. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf_mcp.egg-info/dependency_links.txt +0 -0
  107. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf_mcp.egg-info/entry_points.txt +0 -0
  108. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/src/golf_mcp.egg-info/requires.txt +0 -0
  109. {golf_mcp-0.2.0 → golf_mcp-0.2.1}/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.0
3
+ Version: 0.2.1
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.0"
7
+ version = "0.2.1"
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.1.20"
69
+ version = "0.2.1"
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.0"
1
+ __version__ = "0.2.1"
2
2
 
3
3
  # Import endpoints with fallback for dev mode
4
4
  try:
@@ -14,6 +14,7 @@ from .providers import (
14
14
  StaticTokenConfig,
15
15
  OAuthServerConfig,
16
16
  RemoteAuthConfig,
17
+ OAuthProxyConfig,
17
18
  )
18
19
  from .factory import (
19
20
  create_auth_provider,
@@ -44,6 +45,7 @@ __all__ = [
44
45
  "configure_auth",
45
46
  "configure_jwt_auth",
46
47
  "configure_dev_auth",
48
+ "configure_oauth_proxy",
47
49
  "get_auth_config",
48
50
  # Provider configurations
49
51
  "AuthConfig",
@@ -51,6 +53,7 @@ __all__ = [
51
53
  "StaticTokenConfig",
52
54
  "OAuthServerConfig",
53
55
  "RemoteAuthConfig",
56
+ "OAuthProxyConfig",
54
57
  # Factory functions
55
58
  "create_auth_provider",
56
59
  "create_simple_jwt_provider",
@@ -191,6 +194,51 @@ def configure_dev_auth(
191
194
  configure_auth(config)
192
195
 
193
196
 
197
+ def configure_oauth_proxy(
198
+ upstream_authorization_endpoint: str,
199
+ upstream_token_endpoint: str,
200
+ upstream_client_id: str,
201
+ upstream_client_secret: str,
202
+ base_url: str,
203
+ token_verifier_config: JWTAuthConfig | StaticTokenConfig,
204
+ scopes_supported: list[str] | None = None,
205
+ upstream_revocation_endpoint: str | None = None,
206
+ redirect_path: str = "/oauth/callback",
207
+ ) -> None:
208
+ """Configure OAuth proxy authentication for non-DCR providers.
209
+
210
+ This sets up an OAuth proxy that bridges MCP clients (expecting DCR) with
211
+ traditional OAuth providers like GitHub, Google, Okta Web Apps that use
212
+ fixed client credentials.
213
+
214
+ Args:
215
+ upstream_authorization_endpoint: Provider's authorization URL
216
+ upstream_token_endpoint: Provider's token endpoint URL
217
+ upstream_client_id: Your client ID registered with the provider
218
+ upstream_client_secret: Your client secret from the provider
219
+ base_url: This proxy server's public URL
220
+ token_verifier_config: JWT or static token config for token verification
221
+ scopes_supported: Scopes to advertise to MCP clients
222
+ upstream_revocation_endpoint: Optional token revocation endpoint
223
+ redirect_path: OAuth callback path (default: /oauth/callback)
224
+
225
+ Note:
226
+ Requires golf-mcp-enterprise package for implementation.
227
+ """
228
+ config = OAuthProxyConfig(
229
+ upstream_authorization_endpoint=upstream_authorization_endpoint,
230
+ upstream_token_endpoint=upstream_token_endpoint,
231
+ upstream_client_id=upstream_client_id,
232
+ upstream_client_secret=upstream_client_secret,
233
+ upstream_revocation_endpoint=upstream_revocation_endpoint,
234
+ base_url=base_url,
235
+ redirect_path=redirect_path,
236
+ scopes_supported=scopes_supported or [],
237
+ token_verifier_config=token_verifier_config,
238
+ )
239
+ configure_auth(config)
240
+
241
+
194
242
  def get_auth_config() -> AuthConfig | None:
195
243
  """Get the current auth configuration.
196
244
 
@@ -17,6 +17,7 @@ from .providers import (
17
17
  StaticTokenConfig,
18
18
  OAuthServerConfig,
19
19
  RemoteAuthConfig,
20
+ OAuthProxyConfig,
20
21
  )
21
22
  from .registry import (
22
23
  get_provider_registry,
@@ -55,6 +56,8 @@ def create_auth_provider(config: AuthConfig) -> "AuthProvider":
55
56
  return _create_oauth_server_provider(config)
56
57
  elif config.provider_type == "remote":
57
58
  return _create_remote_provider(config)
59
+ elif config.provider_type == "oauth_proxy":
60
+ return _create_oauth_proxy_provider(config)
58
61
  else:
59
62
  raise ValueError(f"Unknown provider type: {config.provider_type}") from None
60
63
 
@@ -238,6 +241,11 @@ def _create_remote_provider(config: RemoteAuthConfig) -> "AuthProvider":
238
241
  if not hasattr(token_verifier, "verify_token"):
239
242
  raise ValueError(f"Remote auth provider requires a TokenVerifier, got {type(token_verifier).__name__}")
240
243
 
244
+ # Update token verifier's required_scopes to match our scopes_supported for PRM
245
+ # RemoteAuthProvider uses token_verifier.required_scopes for scopes_supported in PRM
246
+ if config.scopes_supported and hasattr(token_verifier, "required_scopes"):
247
+ token_verifier.required_scopes = list(config.scopes_supported)
248
+
241
249
  return RemoteAuthProvider(
242
250
  token_verifier=token_verifier,
243
251
  authorization_servers=authorization_servers,
@@ -245,6 +253,21 @@ def _create_remote_provider(config: RemoteAuthConfig) -> "AuthProvider":
245
253
  )
246
254
 
247
255
 
256
+ def _create_oauth_proxy_provider(config: OAuthProxyConfig) -> "AuthProvider":
257
+ """Create OAuth proxy provider - requires enterprise package."""
258
+ try:
259
+ # Try to import from enterprise package
260
+ from golf_enterprise import create_oauth_proxy_provider
261
+ return create_oauth_proxy_provider(config)
262
+ except ImportError as e:
263
+ raise ImportError(
264
+ "OAuth Proxy requires golf-mcp-enterprise package. "
265
+ "This feature provides OAuth proxy functionality for non-DCR providers "
266
+ "(GitHub, Google, Okta Web Apps, etc.). "
267
+ "Contact sales@golf.dev for enterprise licensing."
268
+ ) from e
269
+
270
+
248
271
  def create_simple_jwt_provider(
249
272
  *,
250
273
  jwks_uri: str | None = None,
@@ -319,6 +342,7 @@ def register_builtin_providers() -> None:
319
342
  - static: Static token verification (development)
320
343
  - oauth_server: Full OAuth authorization server
321
344
  - remote: Remote authorization server integration
345
+ - oauth_proxy: OAuth proxy for non-DCR providers (requires golf-mcp-enterprise)
322
346
  """
323
347
  registry = get_provider_registry()
324
348
 
@@ -327,6 +351,7 @@ def register_builtin_providers() -> None:
327
351
  registry.register_factory("static", _create_static_provider)
328
352
  registry.register_factory("oauth_server", _create_oauth_server_provider)
329
353
  registry.register_factory("remote", _create_remote_provider)
354
+ registry.register_factory("oauth_proxy", _create_oauth_proxy_provider)
330
355
 
331
356
 
332
357
  # Register built-in providers when module is imported
@@ -299,6 +299,12 @@ class RemoteAuthConfig(BaseModel):
299
299
  # This server's URL
300
300
  resource_server_url: str = Field(..., description="URL of this resource server")
301
301
 
302
+ # Scopes this resource supports (advertised via /.well-known/oauth-protected-resource)
303
+ scopes_supported: list[str] = Field(
304
+ default_factory=list,
305
+ description="Scopes this resource supports (advertised via /.well-known/oauth-protected-resource)",
306
+ )
307
+
302
308
  # Token verification (delegate to another config)
303
309
  token_verifier_config: JWTAuthConfig | StaticTokenConfig = Field(
304
310
  ..., description="Configuration for the underlying token verifier"
@@ -362,6 +368,45 @@ class RemoteAuthConfig(BaseModel):
362
368
 
363
369
  return url
364
370
 
371
+ @field_validator("scopes_supported")
372
+ @classmethod
373
+ def validate_scopes_supported(cls, v: list[str]) -> list[str]:
374
+ """Validate scopes_supported format and security."""
375
+ if not v:
376
+ return v
377
+
378
+ cleaned_scopes = []
379
+ for scope in v:
380
+ scope = scope.strip()
381
+ if not scope:
382
+ raise ValueError("Scopes cannot be empty or whitespace-only")
383
+
384
+ # OAuth 2.0 scope format validation (RFC 6749)
385
+ if not all(32 < ord(c) < 127 and c not in ' "\\' for c in scope):
386
+ raise ValueError(
387
+ f"Invalid scope format: '{scope}' - must be ASCII printable without spaces, quotes, or backslashes"
388
+ )
389
+
390
+ # Reasonable length limit to prevent abuse
391
+ if len(scope) > 128:
392
+ raise ValueError(f"Scope too long: '{scope}' - maximum 128 characters")
393
+
394
+ # Warn about potentially dangerous scope names
395
+ dangerous_scopes = {"admin", "root", "superuser", "system", "*", "all"}
396
+ if scope.lower() in dangerous_scopes:
397
+ import warnings
398
+
399
+ warnings.warn(
400
+ f"Potentially dangerous scope detected: '{scope}'. "
401
+ "Consider using more specific, principle-of-least-privilege scopes.",
402
+ UserWarning,
403
+ stacklevel=2,
404
+ )
405
+
406
+ cleaned_scopes.append(scope)
407
+
408
+ return cleaned_scopes
409
+
365
410
  @model_validator(mode="after")
366
411
  def validate_token_verifier_compatibility(self) -> "RemoteAuthConfig":
367
412
  """Validate that the token verifier config is compatible with token verification."""
@@ -389,6 +434,11 @@ class RemoteAuthConfig(BaseModel):
389
434
  if isinstance(config, StaticTokenConfig) and not config.tokens:
390
435
  raise ValueError("Static token verifier config must provide at least one token")
391
436
 
437
+ # Convenience: if user didn't set scopes_supported, default to verifier.required_scopes
438
+ if not self.scopes_supported:
439
+ if hasattr(config, "required_scopes") and config.required_scopes:
440
+ self.scopes_supported = list(config.required_scopes)
441
+
392
442
  return self
393
443
 
394
444
 
@@ -52,7 +52,7 @@ def generate_auth_code(
52
52
  "import os",
53
53
  "import sys",
54
54
  "from golf.auth.factory import create_auth_provider",
55
- "from golf.auth.providers import RemoteAuthConfig, JWTAuthConfig, StaticTokenConfig, OAuthServerConfig",
55
+ "from golf.auth.providers import RemoteAuthConfig, JWTAuthConfig, StaticTokenConfig, OAuthServerConfig, OAuthProxyConfig",
56
56
  ]
57
57
 
58
58
  # Embed the auth configuration directly in the generated code
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: golf-mcp
3
- Version: 0.2.0
3
+ Version: 0.2.1
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
File without changes