golf-mcp 0.2.6__tar.gz → 0.2.9__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.
- {golf_mcp-0.2.6 → golf_mcp-0.2.9}/PKG-INFO +1 -2
- {golf_mcp-0.2.6 → golf_mcp-0.2.9}/README.md +0 -1
- {golf_mcp-0.2.6 → golf_mcp-0.2.9}/pyproject.toml +2 -2
- {golf_mcp-0.2.6 → golf_mcp-0.2.9}/src/golf/__init__.py +1 -1
- {golf_mcp-0.2.6 → golf_mcp-0.2.9}/src/golf/auth/__init__.py +6 -1
- {golf_mcp-0.2.6 → golf_mcp-0.2.9}/src/golf/auth/providers.py +5 -29
- {golf_mcp-0.2.6 → golf_mcp-0.2.9}/src/golf/core/builder.py +137 -32
- {golf_mcp-0.2.6 → golf_mcp-0.2.9}/src/golf_mcp.egg-info/PKG-INFO +1 -2
- {golf_mcp-0.2.6 → golf_mcp-0.2.9}/.docs/docs.md +0 -0
- {golf_mcp-0.2.6 → golf_mcp-0.2.9}/.docs/fastmcp-diff.md +0 -0
- {golf_mcp-0.2.6 → golf_mcp-0.2.9}/.docs/mcp.md +0 -0
- {golf_mcp-0.2.6 → golf_mcp-0.2.9}/LICENSE +0 -0
- {golf_mcp-0.2.6 → golf_mcp-0.2.9}/MANIFEST.in +0 -0
- {golf_mcp-0.2.6 → golf_mcp-0.2.9}/setup.cfg +0 -0
- {golf_mcp-0.2.6 → golf_mcp-0.2.9}/setup.py +0 -0
- {golf_mcp-0.2.6 → golf_mcp-0.2.9}/src/golf/_endpoints.py.in +0 -0
- {golf_mcp-0.2.6 → golf_mcp-0.2.9}/src/golf/_endpoints_fallback.py +0 -0
- {golf_mcp-0.2.6 → golf_mcp-0.2.9}/src/golf/auth/api_key.py +0 -0
- {golf_mcp-0.2.6 → golf_mcp-0.2.9}/src/golf/auth/factory.py +0 -0
- {golf_mcp-0.2.6 → golf_mcp-0.2.9}/src/golf/auth/helpers.py +0 -0
- {golf_mcp-0.2.6 → golf_mcp-0.2.9}/src/golf/auth/registry.py +0 -0
- {golf_mcp-0.2.6 → golf_mcp-0.2.9}/src/golf/cli/__init__.py +0 -0
- {golf_mcp-0.2.6 → golf_mcp-0.2.9}/src/golf/cli/branding.py +0 -0
- {golf_mcp-0.2.6 → golf_mcp-0.2.9}/src/golf/cli/main.py +0 -0
- {golf_mcp-0.2.6 → golf_mcp-0.2.9}/src/golf/commands/__init__.py +0 -0
- {golf_mcp-0.2.6 → golf_mcp-0.2.9}/src/golf/commands/build.py +0 -0
- {golf_mcp-0.2.6 → golf_mcp-0.2.9}/src/golf/commands/init.py +0 -0
- {golf_mcp-0.2.6 → golf_mcp-0.2.9}/src/golf/commands/run.py +0 -0
- {golf_mcp-0.2.6 → golf_mcp-0.2.9}/src/golf/core/__init__.py +0 -0
- {golf_mcp-0.2.6 → golf_mcp-0.2.9}/src/golf/core/builder_auth.py +0 -0
- {golf_mcp-0.2.6 → golf_mcp-0.2.9}/src/golf/core/builder_metrics.py +0 -0
- {golf_mcp-0.2.6 → golf_mcp-0.2.9}/src/golf/core/builder_telemetry.py +0 -0
- {golf_mcp-0.2.6 → golf_mcp-0.2.9}/src/golf/core/config.py +0 -0
- {golf_mcp-0.2.6 → golf_mcp-0.2.9}/src/golf/core/parser.py +0 -0
- {golf_mcp-0.2.6 → golf_mcp-0.2.9}/src/golf/core/platform.py +0 -0
- {golf_mcp-0.2.6 → golf_mcp-0.2.9}/src/golf/core/telemetry.py +0 -0
- {golf_mcp-0.2.6 → golf_mcp-0.2.9}/src/golf/core/transformer.py +0 -0
- {golf_mcp-0.2.6 → golf_mcp-0.2.9}/src/golf/examples/__init__.py +0 -0
- {golf_mcp-0.2.6 → golf_mcp-0.2.9}/src/golf/examples/basic/.env.example +0 -0
- {golf_mcp-0.2.6 → golf_mcp-0.2.9}/src/golf/examples/basic/README.md +0 -0
- {golf_mcp-0.2.6 → golf_mcp-0.2.9}/src/golf/examples/basic/auth.py +0 -0
- {golf_mcp-0.2.6 → golf_mcp-0.2.9}/src/golf/examples/basic/golf.json +0 -0
- {golf_mcp-0.2.6 → golf_mcp-0.2.9}/src/golf/examples/basic/prompts/welcome.py +0 -0
- {golf_mcp-0.2.6 → golf_mcp-0.2.9}/src/golf/examples/basic/resources/current_time.py +0 -0
- {golf_mcp-0.2.6 → golf_mcp-0.2.9}/src/golf/examples/basic/resources/info.py +0 -0
- {golf_mcp-0.2.6 → golf_mcp-0.2.9}/src/golf/examples/basic/resources/weather/city.py +0 -0
- {golf_mcp-0.2.6 → golf_mcp-0.2.9}/src/golf/examples/basic/resources/weather/client.py +0 -0
- {golf_mcp-0.2.6 → golf_mcp-0.2.9}/src/golf/examples/basic/resources/weather/current.py +0 -0
- {golf_mcp-0.2.6 → golf_mcp-0.2.9}/src/golf/examples/basic/resources/weather/forecast.py +0 -0
- {golf_mcp-0.2.6 → golf_mcp-0.2.9}/src/golf/examples/basic/tools/calculator.py +0 -0
- {golf_mcp-0.2.6 → golf_mcp-0.2.9}/src/golf/examples/basic/tools/say/hello.py +0 -0
- {golf_mcp-0.2.6 → golf_mcp-0.2.9}/src/golf/metrics/__init__.py +0 -0
- {golf_mcp-0.2.6 → golf_mcp-0.2.9}/src/golf/metrics/collector.py +0 -0
- {golf_mcp-0.2.6 → golf_mcp-0.2.9}/src/golf/metrics/registry.py +0 -0
- {golf_mcp-0.2.6 → golf_mcp-0.2.9}/src/golf/telemetry/__init__.py +0 -0
- {golf_mcp-0.2.6 → golf_mcp-0.2.9}/src/golf/telemetry/instrumentation.py +0 -0
- {golf_mcp-0.2.6 → golf_mcp-0.2.9}/src/golf/utilities/__init__.py +0 -0
- {golf_mcp-0.2.6 → golf_mcp-0.2.9}/src/golf/utilities/context.py +0 -0
- {golf_mcp-0.2.6 → golf_mcp-0.2.9}/src/golf/utilities/elicitation.py +0 -0
- {golf_mcp-0.2.6 → golf_mcp-0.2.9}/src/golf/utilities/sampling.py +0 -0
- {golf_mcp-0.2.6 → golf_mcp-0.2.9}/src/golf_mcp.egg-info/SOURCES.txt +0 -0
- {golf_mcp-0.2.6 → golf_mcp-0.2.9}/src/golf_mcp.egg-info/dependency_links.txt +0 -0
- {golf_mcp-0.2.6 → golf_mcp-0.2.9}/src/golf_mcp.egg-info/entry_points.txt +0 -0
- {golf_mcp-0.2.6 → golf_mcp-0.2.9}/src/golf_mcp.egg-info/requires.txt +0 -0
- {golf_mcp-0.2.6 → golf_mcp-0.2.9}/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.
|
|
3
|
+
Version: 0.2.9
|
|
4
4
|
Summary: Framework for building MCP servers
|
|
5
5
|
Author-email: Antoni Gmitruk <antoni@golf.dev>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -132,7 +132,6 @@ A Golf project initialized with `golf init` will have a structure similar to thi
|
|
|
132
132
|
- **`auth.py`**: Dedicated authentication configuration file (new in v0.2.0, breaking change from v0.1.x authentication API) for JWT, OAuth Server, API key, or development authentication.
|
|
133
133
|
- **`tools/`**, **`resources/`**, **`prompts/`**: Contain your Python files, each defining a single component. These directories can also contain nested subdirectories to further organize your components (e.g., `tools/payments/charge.py`). The module docstring of each file serves as the component's description.
|
|
134
134
|
- Component IDs are automatically derived from their file path. For example, `tools/hello.py` becomes `hello`, and a nested file like `tools/payments/submit.py` would become `submit_payments` (filename, followed by reversed parent directories under the main category, joined by underscores).
|
|
135
|
-
- **`common.py`** (not shown, but can be placed in subdirectories like `tools/payments/common.py`): Used to share code (clients, models, etc.) among components in the same subdirectory.
|
|
136
135
|
|
|
137
136
|
## Example: Defining a Tool
|
|
138
137
|
|
|
@@ -92,7 +92,6 @@ A Golf project initialized with `golf init` will have a structure similar to thi
|
|
|
92
92
|
- **`auth.py`**: Dedicated authentication configuration file (new in v0.2.0, breaking change from v0.1.x authentication API) for JWT, OAuth Server, API key, or development authentication.
|
|
93
93
|
- **`tools/`**, **`resources/`**, **`prompts/`**: Contain your Python files, each defining a single component. These directories can also contain nested subdirectories to further organize your components (e.g., `tools/payments/charge.py`). The module docstring of each file serves as the component's description.
|
|
94
94
|
- Component IDs are automatically derived from their file path. For example, `tools/hello.py` becomes `hello`, and a nested file like `tools/payments/submit.py` would become `submit_payments` (filename, followed by reversed parent directories under the main category, joined by underscores).
|
|
95
|
-
- **`common.py`** (not shown, but can be placed in subdirectories like `tools/payments/common.py`): Used to share code (clients, models, etc.) among components in the same subdirectory.
|
|
96
95
|
|
|
97
96
|
## Example: Defining a Tool
|
|
98
97
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "golf-mcp"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.9"
|
|
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.
|
|
69
|
+
version = "0.2.9"
|
|
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"
|
|
@@ -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
|
|
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(
|
|
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,
|
|
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
|
|
@@ -170,6 +170,41 @@ class ManifestBuilder:
|
|
|
170
170
|
console.print(f"[green]Manifest saved to {output_path}[/green]")
|
|
171
171
|
return output_path
|
|
172
172
|
|
|
173
|
+
def _get_fastmcp_version(self) -> str | None:
|
|
174
|
+
"""Get the installed FastMCP version.
|
|
175
|
+
|
|
176
|
+
Returns:
|
|
177
|
+
FastMCP version string (e.g., "2.12.0") or None if not available
|
|
178
|
+
"""
|
|
179
|
+
try:
|
|
180
|
+
import fastmcp
|
|
181
|
+
|
|
182
|
+
return fastmcp.__version__
|
|
183
|
+
except (ImportError, AttributeError):
|
|
184
|
+
return None
|
|
185
|
+
|
|
186
|
+
def _is_fastmcp_version_gte(self, target_version: str) -> bool:
|
|
187
|
+
"""Check if installed FastMCP version is >= target version.
|
|
188
|
+
|
|
189
|
+
Args:
|
|
190
|
+
target_version: Version string to compare against (e.g., "2.12.0")
|
|
191
|
+
|
|
192
|
+
Returns:
|
|
193
|
+
True if FastMCP version >= target_version, False otherwise
|
|
194
|
+
"""
|
|
195
|
+
try:
|
|
196
|
+
from packaging import version
|
|
197
|
+
|
|
198
|
+
current_version = self._get_fastmcp_version()
|
|
199
|
+
if current_version is None:
|
|
200
|
+
# Default to older behavior for safety
|
|
201
|
+
return False
|
|
202
|
+
|
|
203
|
+
return version.parse(current_version) >= version.parse(target_version)
|
|
204
|
+
except (ImportError, ValueError):
|
|
205
|
+
# Default to older behavior for safety
|
|
206
|
+
return False
|
|
207
|
+
|
|
173
208
|
|
|
174
209
|
def build_manifest(project_path: Path, settings: Settings) -> dict[str, Any]:
|
|
175
210
|
"""Build a FastMCP manifest from parsed components.
|
|
@@ -511,6 +546,41 @@ class CodeGenerator:
|
|
|
511
546
|
and len(component.parameters) > 0
|
|
512
547
|
)
|
|
513
548
|
|
|
549
|
+
def _get_fastmcp_version(self) -> str | None:
|
|
550
|
+
"""Get the installed FastMCP version.
|
|
551
|
+
|
|
552
|
+
Returns:
|
|
553
|
+
FastMCP version string (e.g., "2.12.0") or None if not available
|
|
554
|
+
"""
|
|
555
|
+
try:
|
|
556
|
+
import fastmcp
|
|
557
|
+
|
|
558
|
+
return fastmcp.__version__
|
|
559
|
+
except (ImportError, AttributeError):
|
|
560
|
+
return None
|
|
561
|
+
|
|
562
|
+
def _is_fastmcp_version_gte(self, target_version: str) -> bool:
|
|
563
|
+
"""Check if installed FastMCP version is >= target version.
|
|
564
|
+
|
|
565
|
+
Args:
|
|
566
|
+
target_version: Version string to compare against (e.g., "2.12.0")
|
|
567
|
+
|
|
568
|
+
Returns:
|
|
569
|
+
True if FastMCP version >= target_version, False otherwise
|
|
570
|
+
"""
|
|
571
|
+
try:
|
|
572
|
+
from packaging import version
|
|
573
|
+
|
|
574
|
+
current_version = self._get_fastmcp_version()
|
|
575
|
+
if current_version is None:
|
|
576
|
+
# Default to older behavior for safety
|
|
577
|
+
return False
|
|
578
|
+
|
|
579
|
+
return version.parse(current_version) >= version.parse(target_version)
|
|
580
|
+
except (ImportError, ValueError):
|
|
581
|
+
# Default to older behavior for safety
|
|
582
|
+
return False
|
|
583
|
+
|
|
514
584
|
def _generate_server(self) -> None:
|
|
515
585
|
"""Generate the main server entry point."""
|
|
516
586
|
server_file = self.output_dir / "server.py"
|
|
@@ -956,23 +1026,40 @@ class CodeGenerator:
|
|
|
956
1026
|
main_code.extend(middleware_setup)
|
|
957
1027
|
main_code.append(f" middleware = [{', '.join(middleware_list)}]")
|
|
958
1028
|
main_code.append("")
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
1029
|
+
if self._is_fastmcp_version_gte("2.12.0"):
|
|
1030
|
+
main_code.extend(
|
|
1031
|
+
[
|
|
1032
|
+
" # Run SSE server with middleware using FastMCP's run method",
|
|
1033
|
+
' mcp.run(transport="sse", host=host, port=port, '
|
|
1034
|
+
'log_level="info", middleware=middleware, show_banner=False)',
|
|
1035
|
+
]
|
|
1036
|
+
)
|
|
1037
|
+
else:
|
|
1038
|
+
main_code.extend(
|
|
1039
|
+
[
|
|
1040
|
+
" # Run SSE server with middleware using FastMCP's run method",
|
|
1041
|
+
f' mcp.run(transport="sse", host=host, port=port, '
|
|
1042
|
+
f'path="{endpoint_path}", log_level="info", '
|
|
1043
|
+
f"middleware=middleware, show_banner=False)",
|
|
1044
|
+
]
|
|
1045
|
+
)
|
|
967
1046
|
else:
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
1047
|
+
if self._is_fastmcp_version_gte("2.12.0"):
|
|
1048
|
+
main_code.extend(
|
|
1049
|
+
[
|
|
1050
|
+
" # Run SSE server using FastMCP's run method",
|
|
1051
|
+
' mcp.run(transport="sse", host=host, port=port, log_level="info", show_banner=False)',
|
|
1052
|
+
]
|
|
1053
|
+
)
|
|
1054
|
+
else:
|
|
1055
|
+
main_code.extend(
|
|
1056
|
+
[
|
|
1057
|
+
" # Run SSE server using FastMCP's run method",
|
|
1058
|
+
f' mcp.run(transport="sse", host=host, port=port, '
|
|
1059
|
+
f'path="{endpoint_path}", log_level="info", '
|
|
1060
|
+
f"show_banner=False)",
|
|
1061
|
+
]
|
|
1062
|
+
)
|
|
976
1063
|
|
|
977
1064
|
elif self.settings.transport in ["streamable-http", "http"]:
|
|
978
1065
|
# Check if we need middleware for streamable-http
|
|
@@ -999,23 +1086,41 @@ class CodeGenerator:
|
|
|
999
1086
|
main_code.extend(middleware_setup)
|
|
1000
1087
|
main_code.append(f" middleware = [{', '.join(middleware_list)}]")
|
|
1001
1088
|
main_code.append("")
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1089
|
+
if self._is_fastmcp_version_gte("2.12.0"):
|
|
1090
|
+
main_code.extend(
|
|
1091
|
+
[
|
|
1092
|
+
" # Run HTTP server with middleware using FastMCP's run method",
|
|
1093
|
+
' mcp.run(transport="streamable-http", host=host, '
|
|
1094
|
+
'port=port, log_level="info", middleware=middleware, show_banner=False)',
|
|
1095
|
+
]
|
|
1096
|
+
)
|
|
1097
|
+
else:
|
|
1098
|
+
main_code.extend(
|
|
1099
|
+
[
|
|
1100
|
+
" # Run HTTP server with middleware using FastMCP's run method",
|
|
1101
|
+
f' mcp.run(transport="streamable-http", host=host, '
|
|
1102
|
+
f'port=port, path="{endpoint_path}", log_level="info", '
|
|
1103
|
+
f"middleware=middleware, show_banner=False)",
|
|
1104
|
+
]
|
|
1105
|
+
)
|
|
1010
1106
|
else:
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1107
|
+
if self._is_fastmcp_version_gte("2.12.0"):
|
|
1108
|
+
main_code.extend(
|
|
1109
|
+
[
|
|
1110
|
+
" # Run HTTP server using FastMCP's run method",
|
|
1111
|
+
' mcp.run(transport="streamable-http", host=host, '
|
|
1112
|
+
'port=port, log_level="info", show_banner=False)',
|
|
1113
|
+
]
|
|
1114
|
+
)
|
|
1115
|
+
else:
|
|
1116
|
+
main_code.extend(
|
|
1117
|
+
[
|
|
1118
|
+
" # Run HTTP server using FastMCP's run method",
|
|
1119
|
+
f' mcp.run(transport="streamable-http", host=host, '
|
|
1120
|
+
f'port=port, path="{endpoint_path}", log_level="info", '
|
|
1121
|
+
f"show_banner=False)",
|
|
1122
|
+
]
|
|
1123
|
+
)
|
|
1019
1124
|
else:
|
|
1020
1125
|
# For stdio transport, use mcp.run()
|
|
1021
1126
|
main_code.extend([" # Run with stdio transport", ' mcp.run(transport="stdio", show_banner=False)'])
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: golf-mcp
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.9
|
|
4
4
|
Summary: Framework for building MCP servers
|
|
5
5
|
Author-email: Antoni Gmitruk <antoni@golf.dev>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -132,7 +132,6 @@ A Golf project initialized with `golf init` will have a structure similar to thi
|
|
|
132
132
|
- **`auth.py`**: Dedicated authentication configuration file (new in v0.2.0, breaking change from v0.1.x authentication API) for JWT, OAuth Server, API key, or development authentication.
|
|
133
133
|
- **`tools/`**, **`resources/`**, **`prompts/`**: Contain your Python files, each defining a single component. These directories can also contain nested subdirectories to further organize your components (e.g., `tools/payments/charge.py`). The module docstring of each file serves as the component's description.
|
|
134
134
|
- Component IDs are automatically derived from their file path. For example, `tools/hello.py` becomes `hello`, and a nested file like `tools/payments/submit.py` would become `submit_payments` (filename, followed by reversed parent directories under the main category, joined by underscores).
|
|
135
|
-
- **`common.py`** (not shown, but can be placed in subdirectories like `tools/payments/common.py`): Used to share code (clients, models, etc.) among components in the same subdirectory.
|
|
136
135
|
|
|
137
136
|
## Example: Defining a Tool
|
|
138
137
|
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|