golf-mcp 0.2.11__py3-none-any.whl → 0.2.12__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 +1 -9
- golf/auth/__init__.py +0 -4
- golf/auth/helpers.py +0 -82
- golf/cli/branding.py +1 -2
- golf/cli/main.py +3 -5
- golf/commands/run.py +24 -12
- golf/core/builder.py +3 -38
- golf/core/builder_auth.py +1 -1
- golf/core/builder_metrics.py +0 -11
- golf/core/config.py +0 -19
- golf/examples/basic/.env.example +0 -4
- golf/telemetry/instrumentation.py +0 -36
- {golf_mcp-0.2.11.dist-info → golf_mcp-0.2.12.dist-info}/METADATA +7 -6
- {golf_mcp-0.2.11.dist-info → golf_mcp-0.2.12.dist-info}/RECORD +18 -22
- golf/_endpoints.py +0 -6
- golf/_endpoints.py.in +0 -6
- golf/_endpoints_fallback.py +0 -10
- golf/core/platform.py +0 -182
- {golf_mcp-0.2.11.dist-info → golf_mcp-0.2.12.dist-info}/WHEEL +0 -0
- {golf_mcp-0.2.11.dist-info → golf_mcp-0.2.12.dist-info}/entry_points.txt +0 -0
- {golf_mcp-0.2.11.dist-info → golf_mcp-0.2.12.dist-info}/licenses/LICENSE +0 -0
- {golf_mcp-0.2.11.dist-info → golf_mcp-0.2.12.dist-info}/top_level.txt +0 -0
golf/__init__.py
CHANGED
|
@@ -1,9 +1 @@
|
|
|
1
|
-
__version__ = "0.2.
|
|
2
|
-
|
|
3
|
-
# Import endpoints with fallback for dev mode
|
|
4
|
-
try:
|
|
5
|
-
# In built wheels, this exists (generated from _endpoints.py.in)
|
|
6
|
-
from . import _endpoints
|
|
7
|
-
except ImportError:
|
|
8
|
-
# In editable/dev installs, fall back to env-based values
|
|
9
|
-
from . import _endpoints_fallback as _endpoints
|
|
1
|
+
__version__ = "0.2.12"
|
golf/auth/__init__.py
CHANGED
|
@@ -32,11 +32,9 @@ from .registry import (
|
|
|
32
32
|
# Re-export for backward compatibility
|
|
33
33
|
from .api_key import configure_api_key, get_api_key_config, is_api_key_configured
|
|
34
34
|
from .helpers import (
|
|
35
|
-
debug_api_key_context,
|
|
36
35
|
extract_token_from_header,
|
|
37
36
|
get_api_key,
|
|
38
37
|
get_auth_token,
|
|
39
|
-
get_provider_token,
|
|
40
38
|
set_api_key,
|
|
41
39
|
)
|
|
42
40
|
|
|
@@ -70,11 +68,9 @@ __all__ = [
|
|
|
70
68
|
"get_api_key_config",
|
|
71
69
|
"is_api_key_configured",
|
|
72
70
|
# Helper functions
|
|
73
|
-
"debug_api_key_context",
|
|
74
71
|
"extract_token_from_header",
|
|
75
72
|
"get_api_key",
|
|
76
73
|
"get_auth_token",
|
|
77
|
-
"get_provider_token",
|
|
78
74
|
"set_api_key",
|
|
79
75
|
]
|
|
80
76
|
|
golf/auth/helpers.py
CHANGED
|
@@ -1,26 +1,12 @@
|
|
|
1
1
|
"""Helper functions for working with authentication in MCP context."""
|
|
2
2
|
|
|
3
3
|
from contextvars import ContextVar
|
|
4
|
-
from typing import Any
|
|
5
4
|
|
|
6
|
-
from starlette.requests import Request
|
|
7
5
|
|
|
8
6
|
# Context variable to store the current request's API key
|
|
9
7
|
_current_api_key: ContextVar[str | None] = ContextVar("current_api_key", default=None)
|
|
10
8
|
|
|
11
9
|
|
|
12
|
-
def get_provider_token() -> str | None:
|
|
13
|
-
"""
|
|
14
|
-
Get a provider token (legacy function - no longer supported in Golf 0.2.x).
|
|
15
|
-
|
|
16
|
-
In Golf 0.2.x, use FastMCP's built-in auth providers for OAuth flows.
|
|
17
|
-
This function returns None and is kept for backwards compatibility.
|
|
18
|
-
"""
|
|
19
|
-
# Legacy OAuth provider support removed in Golf 0.2.x
|
|
20
|
-
# Use FastMCP 2.11+ auth providers instead
|
|
21
|
-
return None
|
|
22
|
-
|
|
23
|
-
|
|
24
10
|
def extract_token_from_header(auth_header: str) -> str | None:
|
|
25
11
|
"""Extract bearer token from Authorization header.
|
|
26
12
|
|
|
@@ -123,25 +109,6 @@ def get_api_key() -> str | None:
|
|
|
123
109
|
return None
|
|
124
110
|
|
|
125
111
|
|
|
126
|
-
def get_api_key_from_request(request: Request) -> str | None:
|
|
127
|
-
"""Get the API key from a specific request object.
|
|
128
|
-
|
|
129
|
-
This is useful when you have direct access to the request object.
|
|
130
|
-
|
|
131
|
-
Args:
|
|
132
|
-
request: The Starlette Request object
|
|
133
|
-
|
|
134
|
-
Returns:
|
|
135
|
-
The API key if available, None otherwise
|
|
136
|
-
"""
|
|
137
|
-
# Check request state first (set by our middleware)
|
|
138
|
-
if hasattr(request, "state") and hasattr(request.state, "api_key"):
|
|
139
|
-
return request.state.api_key
|
|
140
|
-
|
|
141
|
-
# Fall back to context variable
|
|
142
|
-
return _current_api_key.get()
|
|
143
|
-
|
|
144
|
-
|
|
145
112
|
def get_auth_token() -> str | None:
|
|
146
113
|
"""Get the authorization token from the current request context.
|
|
147
114
|
|
|
@@ -206,52 +173,3 @@ def get_auth_token() -> str | None:
|
|
|
206
173
|
pass
|
|
207
174
|
|
|
208
175
|
return None
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
def debug_api_key_context() -> dict[str, Any]:
|
|
212
|
-
"""Debug function to inspect API key context.
|
|
213
|
-
|
|
214
|
-
Returns a dictionary with debugging information about the current
|
|
215
|
-
API key context. Useful for troubleshooting authentication issues.
|
|
216
|
-
|
|
217
|
-
Returns:
|
|
218
|
-
Dictionary with debug information
|
|
219
|
-
"""
|
|
220
|
-
import asyncio
|
|
221
|
-
import os
|
|
222
|
-
import sys
|
|
223
|
-
|
|
224
|
-
debug_info = {
|
|
225
|
-
"context_var_value": _current_api_key.get(),
|
|
226
|
-
"has_async_task": False,
|
|
227
|
-
"task_id": None,
|
|
228
|
-
"main_module_has_storage": False,
|
|
229
|
-
"main_module_has_context": False,
|
|
230
|
-
"request_id_from_context": None,
|
|
231
|
-
"env_vars": {
|
|
232
|
-
"API_KEY": bool(os.environ.get("API_KEY")),
|
|
233
|
-
"GOLF_API_KEY_DEBUG": os.environ.get("GOLF_API_KEY_DEBUG", "false"),
|
|
234
|
-
},
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
try:
|
|
238
|
-
task = asyncio.current_task()
|
|
239
|
-
if task:
|
|
240
|
-
debug_info["has_async_task"] = True
|
|
241
|
-
debug_info["task_id"] = id(task)
|
|
242
|
-
except Exception:
|
|
243
|
-
pass
|
|
244
|
-
|
|
245
|
-
try:
|
|
246
|
-
main_module = sys.modules.get("__main__")
|
|
247
|
-
if main_module:
|
|
248
|
-
debug_info["main_module_has_storage"] = hasattr(main_module, "api_key_storage")
|
|
249
|
-
debug_info["main_module_has_context"] = hasattr(main_module, "request_id_context")
|
|
250
|
-
|
|
251
|
-
if hasattr(main_module, "request_id_context"):
|
|
252
|
-
request_id_context = main_module.request_id_context
|
|
253
|
-
debug_info["request_id_from_context"] = request_id_context.get()
|
|
254
|
-
except Exception:
|
|
255
|
-
pass
|
|
256
|
-
|
|
257
|
-
return debug_info
|
golf/cli/branding.py
CHANGED
|
@@ -33,7 +33,6 @@ STATUS_ICONS = {
|
|
|
33
33
|
"building": "🔨",
|
|
34
34
|
"generating": "⚙️",
|
|
35
35
|
"packaging": "📦",
|
|
36
|
-
"platform": "⛳",
|
|
37
36
|
"server": "🚀",
|
|
38
37
|
"loading": "⭕",
|
|
39
38
|
}
|
|
@@ -163,7 +162,7 @@ def get_status_text(status: str, message: str, style: str = "") -> Text:
|
|
|
163
162
|
elif status == "warning":
|
|
164
163
|
text.append("⚡ ", style=f"bold {GOLF_ORANGE}")
|
|
165
164
|
text.append(f"{icon} {message}", style=f"bold {GOLF_ORANGE}")
|
|
166
|
-
elif status in ["building", "generating", "packaging"
|
|
165
|
+
elif status in ["building", "generating", "packaging"]:
|
|
167
166
|
text.append("🔥 ", style=f"bold {GOLF_ORANGE}")
|
|
168
167
|
text.append(f"{icon} {message}", style=f"bold {GOLF_BLUE}")
|
|
169
168
|
else:
|
golf/cli/main.py
CHANGED
|
@@ -167,11 +167,9 @@ def build_prod(
|
|
|
167
167
|
) -> None:
|
|
168
168
|
"""Build a production version for deployment.
|
|
169
169
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
Your production deployment must include GOLF_* vars for runtime telemetry.
|
|
170
|
+
Environment variables from .env are loaded for build operations.
|
|
171
|
+
App environment variables are NOT copied for security - provide them
|
|
172
|
+
in your deployment environment.
|
|
175
173
|
"""
|
|
176
174
|
# Find project root directory
|
|
177
175
|
project_root, config_path = find_project_root()
|
golf/commands/run.py
CHANGED
|
@@ -5,7 +5,7 @@ import subprocess
|
|
|
5
5
|
import sys
|
|
6
6
|
from pathlib import Path
|
|
7
7
|
|
|
8
|
-
from rich.console import Console
|
|
8
|
+
from rich.console import Console, Group
|
|
9
9
|
from rich.panel import Panel
|
|
10
10
|
from rich.align import Align
|
|
11
11
|
from rich.text import Text
|
|
@@ -53,23 +53,35 @@ def run_server(
|
|
|
53
53
|
server_host = host or settings.host or "localhost"
|
|
54
54
|
server_port = port or settings.port or 3000
|
|
55
55
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
56
|
+
# Create server URL line
|
|
57
|
+
server_line = Text()
|
|
58
|
+
server_line.append("🚀 ", style=f"bold {GOLF_ORANGE}")
|
|
59
|
+
server_line.append(f"{STATUS_ICONS['server']} Server starting on ", style=f"bold {GOLF_BLUE}")
|
|
60
|
+
server_line.append(f"http://{server_host}:{server_port}", style=f"bold {GOLF_GREEN}")
|
|
61
|
+
|
|
62
|
+
# Create content with proper alignment
|
|
63
|
+
content_lines = [
|
|
64
|
+
"", # Empty line at top
|
|
65
|
+
Align.center(server_line),
|
|
66
|
+
]
|
|
62
67
|
|
|
63
68
|
# Add telemetry status indicator
|
|
64
69
|
if settings.opentelemetry_enabled:
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
70
|
+
telemetry_line = Text("📊 OpenTelemetry enabled", style=f"dim {GOLF_BLUE}")
|
|
71
|
+
content_lines.append(Align.center(telemetry_line))
|
|
72
|
+
|
|
73
|
+
# Add empty line and stop instruction
|
|
74
|
+
content_lines.extend(
|
|
75
|
+
[
|
|
76
|
+
"", # Empty line before stop instruction
|
|
77
|
+
Align.center(Text("⚡ Press Ctrl+C to stop ⚡", style=f"dim {GOLF_ORANGE}")),
|
|
78
|
+
"", # Empty line at bottom
|
|
79
|
+
]
|
|
80
|
+
)
|
|
69
81
|
|
|
70
82
|
console.print(
|
|
71
83
|
Panel(
|
|
72
|
-
|
|
84
|
+
Group(*content_lines),
|
|
73
85
|
border_style=GOLF_BLUE,
|
|
74
86
|
padding=(1, 2),
|
|
75
87
|
title="[bold]🌐 SERVER READY 🌐[/bold]",
|
golf/core/builder.py
CHANGED
|
@@ -16,7 +16,7 @@ from golf.core.builder_auth import generate_auth_code, generate_auth_routes
|
|
|
16
16
|
from golf.core.builder_telemetry import (
|
|
17
17
|
generate_telemetry_imports,
|
|
18
18
|
)
|
|
19
|
-
from golf.cli.branding import create_build_header, get_status_text
|
|
19
|
+
from golf.cli.branding import create_build_header, get_status_text
|
|
20
20
|
from golf.core.config import Settings
|
|
21
21
|
from golf.core.parser import (
|
|
22
22
|
ComponentType,
|
|
@@ -1401,21 +1401,13 @@ def build_project(
|
|
|
1401
1401
|
build_env: Build environment ('dev' or 'prod')
|
|
1402
1402
|
copy_env: Whether to copy environment variables to the built app
|
|
1403
1403
|
"""
|
|
1404
|
-
# Load
|
|
1405
|
-
# This happens regardless of copy_env setting to ensure build process works
|
|
1404
|
+
# Load environment variables from .env for build operations
|
|
1406
1405
|
from dotenv import load_dotenv
|
|
1407
1406
|
|
|
1408
1407
|
project_env_file = project_path / ".env"
|
|
1409
1408
|
if project_env_file.exists():
|
|
1410
|
-
# Load GOLF_* variables for build process
|
|
1411
1409
|
load_dotenv(project_env_file, override=False)
|
|
1412
1410
|
|
|
1413
|
-
# Only log if we actually found the specific Golf platform credentials
|
|
1414
|
-
has_api_key = "GOLF_API_KEY" in os.environ
|
|
1415
|
-
has_server_id = "GOLF_SERVER_ID" in os.environ
|
|
1416
|
-
if has_api_key and has_server_id:
|
|
1417
|
-
console.print("[dim]Loaded Golf credentials for build operations[/dim]")
|
|
1418
|
-
|
|
1419
1411
|
# Execute auth.py if it exists (for authentication configuration)
|
|
1420
1412
|
# Also support legacy pre_build.py for backward compatibility
|
|
1421
1413
|
auth_path = project_path / "auth.py"
|
|
@@ -1583,33 +1575,6 @@ def build_project(
|
|
|
1583
1575
|
shutil.copy2(health_path, output_dir)
|
|
1584
1576
|
console.print(get_status_text("success", "Health script copied to build directory"))
|
|
1585
1577
|
|
|
1586
|
-
# Platform registration (only for prod builds)
|
|
1587
|
-
if build_env == "prod":
|
|
1588
|
-
console.print()
|
|
1589
|
-
status_msg = f"[{GOLF_BLUE}]{STATUS_ICONS['platform']} Registering with Golf platform and updating resources...[/{GOLF_BLUE}]"
|
|
1590
|
-
with console.status(status_msg):
|
|
1591
|
-
import asyncio
|
|
1592
|
-
|
|
1593
|
-
try:
|
|
1594
|
-
from golf.core.platform import register_project_with_platform
|
|
1595
|
-
|
|
1596
|
-
success = asyncio.run(
|
|
1597
|
-
register_project_with_platform(
|
|
1598
|
-
project_path=project_path,
|
|
1599
|
-
settings=settings,
|
|
1600
|
-
components=generator.components,
|
|
1601
|
-
)
|
|
1602
|
-
)
|
|
1603
|
-
|
|
1604
|
-
if success:
|
|
1605
|
-
console.print(get_status_text("success", "Platform registration completed"))
|
|
1606
|
-
# If success is False, the platform module already printed appropriate warnings
|
|
1607
|
-
except ImportError:
|
|
1608
|
-
console.print(get_status_text("warning", "Platform registration module not available"))
|
|
1609
|
-
except Exception as e:
|
|
1610
|
-
console.print(get_status_text("warning", f"Platform registration failed: {e}"))
|
|
1611
|
-
console.print("[dim]Tip: Ensure GOLF_API_KEY and GOLF_SERVER_ID are available in your .env file[/dim]")
|
|
1612
|
-
|
|
1613
1578
|
# Create a simple README
|
|
1614
1579
|
readme_content = f"""# {settings.name}
|
|
1615
1580
|
|
|
@@ -1639,7 +1604,7 @@ This is a standalone FastMCP server generated by GolfMCP.
|
|
|
1639
1604
|
|
|
1640
1605
|
# Legacy ProviderConfig removed in Golf 0.2.x - use modern auth configurations
|
|
1641
1606
|
# Legacy OAuth imports removed in Golf 0.2.x - use FastMCP 2.11+ auth providers
|
|
1642
|
-
from golf.auth.helpers import
|
|
1607
|
+
from golf.auth.helpers import extract_token_from_header, get_api_key, set_api_key
|
|
1643
1608
|
from golf.auth.api_key import configure_api_key, get_api_key_config
|
|
1644
1609
|
from golf.auth.factory import create_auth_provider
|
|
1645
1610
|
from golf.auth.providers import RemoteAuthConfig, JWTAuthConfig, StaticTokenConfig, OAuthServerConfig
|
golf/core/builder_auth.py
CHANGED
|
@@ -121,7 +121,7 @@ def generate_api_key_auth_components(
|
|
|
121
121
|
"class ApiKeyMiddleware(BaseHTTPMiddleware):",
|
|
122
122
|
" async def dispatch(self, request: Request, call_next):",
|
|
123
123
|
" # Debug mode from environment",
|
|
124
|
-
" debug = os.environ.get('
|
|
124
|
+
" debug = os.environ.get('API_KEY_DEBUG', '').lower() == 'true'",
|
|
125
125
|
" ",
|
|
126
126
|
" # Skip auth for monitoring endpoints",
|
|
127
127
|
" path = request.url.path",
|
golf/core/builder_metrics.py
CHANGED
|
@@ -59,17 +59,6 @@ def generate_metrics_route(metrics_path: str) -> list[str]:
|
|
|
59
59
|
]
|
|
60
60
|
|
|
61
61
|
|
|
62
|
-
def get_metrics_dependencies() -> list[str]:
|
|
63
|
-
"""Get list of metrics dependencies to add to pyproject.toml.
|
|
64
|
-
|
|
65
|
-
Returns:
|
|
66
|
-
List of package requirements strings
|
|
67
|
-
"""
|
|
68
|
-
return [
|
|
69
|
-
"prometheus-client>=0.19.0",
|
|
70
|
-
]
|
|
71
|
-
|
|
72
|
-
|
|
73
62
|
def generate_metrics_instrumentation() -> list[str]:
|
|
74
63
|
"""Generate metrics instrumentation wrapper functions.
|
|
75
64
|
|
golf/core/config.py
CHANGED
|
@@ -172,24 +172,11 @@ def load_settings(project_path: str | Path) -> Settings:
|
|
|
172
172
|
if env_file.exists():
|
|
173
173
|
settings = Settings(_env_file=env_file)
|
|
174
174
|
|
|
175
|
-
# Auto-enable OpenTelemetry if GOLF_API_KEY is present (from .env file)
|
|
176
|
-
import os
|
|
177
|
-
|
|
178
|
-
if os.environ.get("GOLF_API_KEY"):
|
|
179
|
-
settings.opentelemetry_enabled = True
|
|
180
|
-
|
|
181
175
|
# Try to load JSON config file first
|
|
182
176
|
json_config_path = project_path / "golf.json"
|
|
183
177
|
if json_config_path.exists():
|
|
184
178
|
return _load_json_settings(json_config_path, settings)
|
|
185
179
|
|
|
186
|
-
# No config file found, use defaults
|
|
187
|
-
# Auto-enable OpenTelemetry if GOLF_API_KEY is present
|
|
188
|
-
import os
|
|
189
|
-
|
|
190
|
-
if os.environ.get("GOLF_API_KEY"):
|
|
191
|
-
settings.opentelemetry_enabled = True
|
|
192
|
-
|
|
193
180
|
return settings
|
|
194
181
|
|
|
195
182
|
|
|
@@ -206,12 +193,6 @@ def _load_json_settings(path: Path, settings: Settings) -> Settings:
|
|
|
206
193
|
if hasattr(settings, key):
|
|
207
194
|
setattr(settings, key, value)
|
|
208
195
|
|
|
209
|
-
# Auto-enable OpenTelemetry if GOLF_API_KEY is present and telemetry wasn't explicitly configured
|
|
210
|
-
import os
|
|
211
|
-
|
|
212
|
-
if os.environ.get("GOLF_API_KEY") and "opentelemetry_enabled" not in config_data:
|
|
213
|
-
settings.opentelemetry_enabled = True
|
|
214
|
-
|
|
215
196
|
return settings
|
|
216
197
|
except Exception as e:
|
|
217
198
|
console.print(f"[bold red]Error loading JSON config from {path}: {e}[/bold red]")
|
golf/examples/basic/.env.example
CHANGED
|
@@ -1,8 +1,4 @@
|
|
|
1
1
|
# Golf MCP Server Environment Variables
|
|
2
2
|
|
|
3
|
-
# Golf platform integration
|
|
4
|
-
GOLF_API_KEY="your-golf-api-key"
|
|
5
|
-
GOLF_SERVER_ID="your-server-id"
|
|
6
|
-
|
|
7
3
|
# Development tokens are configured in auth.py for this example
|
|
8
4
|
# Additional environment variables can be added as needed
|
|
@@ -14,13 +14,6 @@ from collections import OrderedDict
|
|
|
14
14
|
|
|
15
15
|
from opentelemetry import baggage, trace
|
|
16
16
|
|
|
17
|
-
# Import endpoints with fallback for dev mode
|
|
18
|
-
try:
|
|
19
|
-
# In built wheels, this exists (generated from _endpoints.py.in)
|
|
20
|
-
from golf import _endpoints # type: ignore
|
|
21
|
-
except ImportError:
|
|
22
|
-
# In editable/dev installs, fall back to env-based values
|
|
23
|
-
from golf import _endpoints_fallback as _endpoints # type: ignore
|
|
24
17
|
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
|
|
25
18
|
from opentelemetry.sdk.resources import Resource
|
|
26
19
|
from opentelemetry.sdk.trace import TracerProvider
|
|
@@ -69,28 +62,6 @@ def init_telemetry(service_name: str = "golf-mcp-server") -> TracerProvider | No
|
|
|
69
62
|
"""
|
|
70
63
|
global _provider
|
|
71
64
|
|
|
72
|
-
# Check for Golf platform integration first
|
|
73
|
-
golf_api_key = os.environ.get("GOLF_API_KEY")
|
|
74
|
-
if golf_api_key:
|
|
75
|
-
# Auto-configure for Golf platform - always use OTLP when Golf API
|
|
76
|
-
# key is present
|
|
77
|
-
os.environ["OTEL_TRACES_EXPORTER"] = "otlp_http"
|
|
78
|
-
|
|
79
|
-
# Only set endpoint if not already configured (allow user override)
|
|
80
|
-
if not os.environ.get("OTEL_EXPORTER_OTLP_ENDPOINT"):
|
|
81
|
-
os.environ["OTEL_EXPORTER_OTLP_ENDPOINT"] = _endpoints.OTEL_ENDPOINT
|
|
82
|
-
|
|
83
|
-
# Set Golf platform headers (append to existing if present)
|
|
84
|
-
existing_headers = os.environ.get("OTEL_EXPORTER_OTLP_HEADERS", "")
|
|
85
|
-
golf_header = f"X-Golf-Key={golf_api_key}"
|
|
86
|
-
|
|
87
|
-
if existing_headers:
|
|
88
|
-
# Check if Golf key is already in headers
|
|
89
|
-
if "X-Golf-Key=" not in existing_headers:
|
|
90
|
-
os.environ["OTEL_EXPORTER_OTLP_HEADERS"] = f"{existing_headers},{golf_header}"
|
|
91
|
-
else:
|
|
92
|
-
os.environ["OTEL_EXPORTER_OTLP_HEADERS"] = golf_header
|
|
93
|
-
|
|
94
65
|
# Check for required environment variables based on exporter type
|
|
95
66
|
exporter_type = os.environ.get("OTEL_TRACES_EXPORTER", "console").lower()
|
|
96
67
|
|
|
@@ -111,13 +82,6 @@ def init_telemetry(service_name: str = "golf-mcp-server") -> TracerProvider | No
|
|
|
111
82
|
"service.instance.id": os.environ.get("SERVICE_INSTANCE_ID", "default"),
|
|
112
83
|
}
|
|
113
84
|
|
|
114
|
-
# Add Golf-specific attributes if available
|
|
115
|
-
if golf_api_key:
|
|
116
|
-
golf_server_id = os.environ.get("GOLF_SERVER_ID")
|
|
117
|
-
if golf_server_id:
|
|
118
|
-
resource_attributes["golf.server.id"] = golf_server_id
|
|
119
|
-
resource_attributes["golf.platform.enabled"] = "true"
|
|
120
|
-
|
|
121
85
|
resource = Resource.create(resource_attributes)
|
|
122
86
|
|
|
123
87
|
# Create provider
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: golf-mcp
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.12
|
|
4
4
|
Summary: Framework for building MCP servers
|
|
5
5
|
Author-email: Antoni Gmitruk <antoni@golf.dev>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -21,7 +21,7 @@ Description-Content-Type: text/markdown
|
|
|
21
21
|
License-File: LICENSE
|
|
22
22
|
Requires-Dist: typer>=0.15.4
|
|
23
23
|
Requires-Dist: rich>=14.0.0
|
|
24
|
-
Requires-Dist: fastmcp
|
|
24
|
+
Requires-Dist: fastmcp==2.12.5
|
|
25
25
|
Requires-Dist: pydantic>=2.11.0
|
|
26
26
|
Requires-Dist: pydantic-settings>=2.0.0
|
|
27
27
|
Requires-Dist: python-dotenv>=1.1.0
|
|
@@ -197,9 +197,10 @@ from golf.utils import elicit, sample, get_context
|
|
|
197
197
|
```
|
|
198
198
|
|
|
199
199
|
```bash
|
|
200
|
-
#
|
|
201
|
-
export
|
|
202
|
-
|
|
200
|
+
# Enable OpenTelemetry tracing
|
|
201
|
+
export OTEL_TRACES_EXPORTER="otlp_http"
|
|
202
|
+
export OTEL_EXPORTER_OTLP_ENDPOINT="http://localhost:4318/v1/traces"
|
|
203
|
+
golf run # ✅ Telemetry enabled
|
|
203
204
|
```
|
|
204
205
|
|
|
205
206
|
**[📚 Complete Documentation →](https://docs.golf.dev)**
|
|
@@ -220,7 +221,7 @@ Basic configuration in `golf.json`:
|
|
|
220
221
|
```
|
|
221
222
|
|
|
222
223
|
- **`transport`**: Choose `"sse"`, `"streamable-http"`, or `"stdio"`
|
|
223
|
-
- **`opentelemetry_enabled`**:
|
|
224
|
+
- **`opentelemetry_enabled`**: Enable OpenTelemetry tracing
|
|
224
225
|
- **`detailed_tracing`**: Capture input/output (use carefully with sensitive data)
|
|
225
226
|
|
|
226
227
|
|
|
@@ -1,32 +1,28 @@
|
|
|
1
|
-
golf/__init__.py,sha256=
|
|
2
|
-
golf/
|
|
3
|
-
golf/_endpoints.py.in,sha256=MeqcSF6xinnPknpBGF26xA9FYmSYKSWqCFXOSDlXiOA,216
|
|
4
|
-
golf/_endpoints_fallback.py,sha256=CD6m45Ams1A9HVKowY8dCFUDMiFmJ8ZWSwHCENvU5u4,386
|
|
5
|
-
golf/auth/__init__.py,sha256=gx62l8Z72eIldO2LtzKQ2OQVeobrhaSggTzJaZ0hcCo,8279
|
|
1
|
+
golf/__init__.py,sha256=X4KG3FscE5AhbGbcdDDgdDC550CVpxNMwdNLcx6EQ7M,23
|
|
2
|
+
golf/auth/__init__.py,sha256=sYWjWXGR70Ae87znseeBK2YWl8S1-qn_hndKf2xMULk,8173
|
|
6
3
|
golf/auth/api_key.py,sha256=OonqTlG6USJxqK8TlPviJTv7sgYmTVfCxG_JsEjnEM4,2320
|
|
7
4
|
golf/auth/factory.py,sha256=3-il1GbjjZlQfvWUZs-09r61Y_-b5cYEegWF7sY_cUs,13128
|
|
8
|
-
golf/auth/helpers.py,sha256=
|
|
5
|
+
golf/auth/helpers.py,sha256=N5NUGqlBg8rwfYX6zXmsWnjDE2Bh9n1CHeKAqMShToc,5589
|
|
9
6
|
golf/auth/providers.py,sha256=f89WeQUrYopS0GBcTO3yXlqyPQvG7s7GpaiUK2tb2ME,25048
|
|
10
7
|
golf/auth/registry.py,sha256=Rjj7LnWvzEsI1GCnFbFcxpRllrVanD9bumWPaJ1giFQ,7960
|
|
11
8
|
golf/cli/__init__.py,sha256=R8Y8KdD2C8gDo24fXGq-fdWWNeaq3MYjrbaSB8Hb-Hg,45
|
|
12
|
-
golf/cli/branding.py,sha256=
|
|
13
|
-
golf/cli/main.py,sha256=
|
|
9
|
+
golf/cli/branding.py,sha256=OdmCaYVg6g3P8fqSNDlTG8R5CwUTuqSd68BrpPTjKp8,6861
|
|
10
|
+
golf/cli/main.py,sha256=YnppG_I15wfVU-dELgJbGTjESMvXGmBpUds1JkE83Es,13403
|
|
14
11
|
golf/commands/__init__.py,sha256=j2r-0Zg2BSqG7WtZczAtyAsrur7kRQpEN9ZJuoX1XQ8,119
|
|
15
12
|
golf/commands/build.py,sha256=sLq9lSW4naq2vIlBreKI5SGnviQrhBWw13zfOZOKhuM,2293
|
|
16
13
|
golf/commands/init.py,sha256=KkAg_3-KxBDFOcZqUHqcPAkDipykFVaLWpQ2tydnVPk,9617
|
|
17
|
-
golf/commands/run.py,sha256=
|
|
14
|
+
golf/commands/run.py,sha256=2fdjqTfzQL-dFOqptkl-K2jel8VWpevAx0somcjNsPI,4576
|
|
18
15
|
golf/core/__init__.py,sha256=4bKeskJ2fPaZqkz2xQScSa3phRLLrmrczwSL632jv-o,52
|
|
19
|
-
golf/core/builder.py,sha256=
|
|
20
|
-
golf/core/builder_auth.py,sha256=
|
|
21
|
-
golf/core/builder_metrics.py,sha256=
|
|
16
|
+
golf/core/builder.py,sha256=ynmzTF1IsF5OTZl0dr-1Mzd8iEVNB-Oxa6RBWBu3DRs,76372
|
|
17
|
+
golf/core/builder_auth.py,sha256=f0w9TmxvNjxglcWY8NGULZJ8mwLqtUFFb2QHzgC0xAk,8219
|
|
18
|
+
golf/core/builder_metrics.py,sha256=wrXdE4_XWx7fUXnp61WU7rCBO-aG-4YzCMV6yO0z9Dg,8594
|
|
22
19
|
golf/core/builder_telemetry.py,sha256=86bp7UlMUN6JyQRrZ5EizovP6AJ_q65OANJTeJXDIKc,3421
|
|
23
|
-
golf/core/config.py,sha256=
|
|
20
|
+
golf/core/config.py,sha256=kL440b8i1dF8jdKeYwZZ04HdotX5CAlTyxR1ZyML-Iw,6850
|
|
24
21
|
golf/core/parser.py,sha256=f9WqmLWlFuXQCObl2Qmna9bp_Bo0p0eIlukzwFaBSzo,43373
|
|
25
|
-
golf/core/platform.py,sha256=0TxLfVPBhBR82aJAQWEJcnkGuQv65C9gYYy7P2foUVk,6662
|
|
26
22
|
golf/core/telemetry.py,sha256=dXoWrgrQpj_HGrl_8TBZmRnuLxFKEn0GSDWQ9qq3ZQM,15686
|
|
27
23
|
golf/core/transformer.py,sha256=iTDNFqdVeOjzl-acdjp8ZaTXss8Eptqu5cs4qLWt9SU,6914
|
|
28
24
|
golf/examples/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
29
|
-
golf/examples/basic/.env.example,sha256=
|
|
25
|
+
golf/examples/basic/.env.example,sha256=Ktdc2Qta05smPItYHnEHhVxYPkq5JJ7i2aI5pOyyQx4,162
|
|
30
26
|
golf/examples/basic/README.md,sha256=p8KMyaNXGZtrbgckW-Thu_5RKXViGiyZ5hHEiJ6Zc-U,3283
|
|
31
27
|
golf/examples/basic/auth.py,sha256=cdPWFU__i8Jw8xI1hgGSobhaC4YIBKsh5LsQY2GS2dw,2789
|
|
32
28
|
golf/examples/basic/golf.json,sha256=327fO4XmvksmZdlYtYPmRcB6TgEVkD1nSvHAuGyWsYA,98
|
|
@@ -43,14 +39,14 @@ golf/metrics/__init__.py,sha256=O91y-hj_E9R06gqV8pDZrzHxOIl-1T415Hj9RvFAp3o,283
|
|
|
43
39
|
golf/metrics/collector.py,sha256=ScKeOyDNawZRMIRYBFqNqmaYAIVJQ2riMu_qOE9ugvU,10967
|
|
44
40
|
golf/metrics/registry.py,sha256=mXQE4Pwf3PopGYjcUu4eGgPDAe085YWcsvcvWk0ny8Q,310
|
|
45
41
|
golf/telemetry/__init__.py,sha256=txSXDBhug5uVMD1KjZszcILMrVTjvTCWlxo7TWwbul8,506
|
|
46
|
-
golf/telemetry/instrumentation.py,sha256=
|
|
42
|
+
golf/telemetry/instrumentation.py,sha256=qBgSw8KqK_nroOjaeI1HMxaBUPsrIERyzp0ig842nu8,56159
|
|
47
43
|
golf/utilities/__init__.py,sha256=X9iY9yi3agz1GVcn8-qWeOCt8CSSsruHxqPNtiF63TY,530
|
|
48
44
|
golf/utilities/context.py,sha256=DGGvhVe---QMhy0wtdWhNp-_WVk1NvAcOFn0uBKBpYo,1579
|
|
49
45
|
golf/utilities/elicitation.py,sha256=MParZZZsY45s70-KXduHa6IvpWXnLW2FCPfrGijMaHs,5223
|
|
50
46
|
golf/utilities/sampling.py,sha256=88nDv-trBE4gZQbcnMjXl3LW6TiIhv5zR_cuEIGjaIM,7233
|
|
51
|
-
golf_mcp-0.2.
|
|
52
|
-
golf_mcp-0.2.
|
|
53
|
-
golf_mcp-0.2.
|
|
54
|
-
golf_mcp-0.2.
|
|
55
|
-
golf_mcp-0.2.
|
|
56
|
-
golf_mcp-0.2.
|
|
47
|
+
golf_mcp-0.2.12.dist-info/licenses/LICENSE,sha256=5_j2f6fTJmvfmUewzElhkpAaXg2grVoxKouOA8ihV6E,11348
|
|
48
|
+
golf_mcp-0.2.12.dist-info/METADATA,sha256=RksLyay82K3poGEAup26_dMaRw06Z9ZnOwC3iFWHel8,9414
|
|
49
|
+
golf_mcp-0.2.12.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
50
|
+
golf_mcp-0.2.12.dist-info/entry_points.txt,sha256=5y7rHYM8jGpU-nfwdknCm5XsApLulqsnA37MO6BUTYg,43
|
|
51
|
+
golf_mcp-0.2.12.dist-info/top_level.txt,sha256=BQToHcBUufdyhp9ONGMIvPE40jMEtmI20lYaKb4hxOg,5
|
|
52
|
+
golf_mcp-0.2.12.dist-info/RECORD,,
|
golf/_endpoints.py
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
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 = "https://golf-backend.golf-auth-1.authed-qukc4.ryvn.run/api/resources"
|
|
6
|
-
OTEL_ENDPOINT = "https://golf-backend.golf-auth-1.authed-qukc4.ryvn.run/api/v1/otel"
|
golf/_endpoints.py.in
DELETED
golf/_endpoints_fallback.py
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
"""Fallback endpoints for development/editable installs."""
|
|
2
|
-
|
|
3
|
-
import os
|
|
4
|
-
|
|
5
|
-
# These are used when the generated _endpoints.py doesn't exist (dev mode)
|
|
6
|
-
# or when environment variables override the built-in values
|
|
7
|
-
|
|
8
|
-
PLATFORM_API_URL = os.getenv("GOLF_PLATFORM_API_URL", "http://localhost:8000/api/resources")
|
|
9
|
-
|
|
10
|
-
OTEL_ENDPOINT = os.getenv("GOLF_OTEL_ENDPOINT", "http://localhost:4318/v1/traces")
|
golf/core/platform.py
DELETED
|
@@ -1,182 +0,0 @@
|
|
|
1
|
-
"""Platform registration for Golf MCP projects."""
|
|
2
|
-
|
|
3
|
-
import os
|
|
4
|
-
from datetime import datetime
|
|
5
|
-
from pathlib import Path
|
|
6
|
-
from typing import Any
|
|
7
|
-
|
|
8
|
-
import httpx
|
|
9
|
-
from rich.console import Console
|
|
10
|
-
|
|
11
|
-
from golf import __version__
|
|
12
|
-
from golf.core.config import Settings
|
|
13
|
-
from golf.core.parser import ComponentType, ParsedComponent
|
|
14
|
-
|
|
15
|
-
# Import endpoints with fallback for dev mode
|
|
16
|
-
try:
|
|
17
|
-
# In built wheels, this exists (generated from _endpoints.py.in)
|
|
18
|
-
from golf import _endpoints # type: ignore
|
|
19
|
-
except ImportError:
|
|
20
|
-
# In editable/dev installs, fall back to env-based values
|
|
21
|
-
from golf import _endpoints_fallback as _endpoints # type: ignore
|
|
22
|
-
|
|
23
|
-
console = Console()
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
async def register_project_with_platform(
|
|
27
|
-
project_path: Path,
|
|
28
|
-
settings: Settings,
|
|
29
|
-
components: dict[ComponentType, list[ParsedComponent]],
|
|
30
|
-
) -> bool:
|
|
31
|
-
"""Register project with Golf platform during prod build.
|
|
32
|
-
|
|
33
|
-
Args:
|
|
34
|
-
project_path: Path to the project root
|
|
35
|
-
settings: Project settings
|
|
36
|
-
components: Parsed components dictionary
|
|
37
|
-
|
|
38
|
-
Returns:
|
|
39
|
-
True if registration succeeded or was skipped, False if failed
|
|
40
|
-
"""
|
|
41
|
-
# Check if platform integration is enabled
|
|
42
|
-
api_key = os.getenv("GOLF_API_KEY")
|
|
43
|
-
if not api_key:
|
|
44
|
-
return True # Skip silently if no API key
|
|
45
|
-
|
|
46
|
-
# Require explicit server ID
|
|
47
|
-
server_id = os.getenv("GOLF_SERVER_ID")
|
|
48
|
-
if not server_id:
|
|
49
|
-
console.print(
|
|
50
|
-
"[yellow]Warning: Platform registration skipped - GOLF_SERVER_ID environment variable required[/yellow]"
|
|
51
|
-
)
|
|
52
|
-
return True # Skip registration but don't fail build
|
|
53
|
-
|
|
54
|
-
# Build metadata payload
|
|
55
|
-
metadata = {
|
|
56
|
-
"project_name": settings.name,
|
|
57
|
-
"description": settings.description,
|
|
58
|
-
"server_id": server_id,
|
|
59
|
-
"components": _build_component_list(components, project_path),
|
|
60
|
-
"build_timestamp": datetime.utcnow().isoformat(),
|
|
61
|
-
"golf_version": __version__,
|
|
62
|
-
"component_counts": _get_component_counts(components),
|
|
63
|
-
"server_config": {
|
|
64
|
-
"host": settings.host,
|
|
65
|
-
"port": settings.port,
|
|
66
|
-
"transport": settings.transport,
|
|
67
|
-
"auth_enabled": bool(settings.auth),
|
|
68
|
-
"telemetry_enabled": settings.opentelemetry_enabled,
|
|
69
|
-
"health_check_enabled": settings.health_check_enabled,
|
|
70
|
-
},
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
try:
|
|
74
|
-
async with httpx.AsyncClient(timeout=10.0) as client:
|
|
75
|
-
response = await client.post(
|
|
76
|
-
_endpoints.PLATFORM_API_URL,
|
|
77
|
-
json=metadata,
|
|
78
|
-
headers={
|
|
79
|
-
"X-Golf-Key": api_key,
|
|
80
|
-
"Content-Type": "application/json",
|
|
81
|
-
"User-Agent": f"Golf-MCP/{__version__}",
|
|
82
|
-
},
|
|
83
|
-
)
|
|
84
|
-
response.raise_for_status()
|
|
85
|
-
|
|
86
|
-
console.print("[green]✓[/green] Registered with Golf platform")
|
|
87
|
-
return True
|
|
88
|
-
|
|
89
|
-
except httpx.TimeoutException:
|
|
90
|
-
console.print("[yellow]Warning: Platform registration timed out[/yellow]")
|
|
91
|
-
return False
|
|
92
|
-
except httpx.HTTPStatusError as e:
|
|
93
|
-
if e.response.status_code == 401:
|
|
94
|
-
console.print("[yellow]Warning: Platform registration failed - invalid API key[/yellow]")
|
|
95
|
-
elif e.response.status_code == 403:
|
|
96
|
-
console.print("[yellow]Warning: Platform registration failed - access denied[/yellow]")
|
|
97
|
-
else:
|
|
98
|
-
console.print(f"[yellow]Warning: Platform registration failed - HTTP {e.response.status_code}[/yellow]")
|
|
99
|
-
return False
|
|
100
|
-
except Exception as e:
|
|
101
|
-
console.print(f"[yellow]Warning: Platform registration failed: {e}[/yellow]")
|
|
102
|
-
return False # Don't fail the build
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
def _build_component_list(
|
|
106
|
-
components: dict[ComponentType, list[ParsedComponent]],
|
|
107
|
-
project_path: Path,
|
|
108
|
-
) -> list[dict[str, Any]]:
|
|
109
|
-
"""Convert parsed components to platform format.
|
|
110
|
-
|
|
111
|
-
Args:
|
|
112
|
-
components: Dictionary of parsed components by type
|
|
113
|
-
project_path: Path to the project root
|
|
114
|
-
|
|
115
|
-
Returns:
|
|
116
|
-
List of component metadata dictionaries
|
|
117
|
-
"""
|
|
118
|
-
result = []
|
|
119
|
-
|
|
120
|
-
for comp_type, comp_list in components.items():
|
|
121
|
-
for comp in comp_list:
|
|
122
|
-
# Start with basic component data
|
|
123
|
-
component_data = {
|
|
124
|
-
"name": comp.name,
|
|
125
|
-
"type": comp_type.value,
|
|
126
|
-
"description": comp.docstring,
|
|
127
|
-
"entry_function": comp.entry_function,
|
|
128
|
-
"parent_module": comp.parent_module,
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
# Add file path relative to project root if available
|
|
132
|
-
if comp.file_path:
|
|
133
|
-
try:
|
|
134
|
-
file_path = Path(comp.file_path)
|
|
135
|
-
# Use the provided project_path for relative calculation
|
|
136
|
-
rel_path = file_path.relative_to(project_path)
|
|
137
|
-
component_data["file_path"] = str(rel_path)
|
|
138
|
-
except ValueError:
|
|
139
|
-
# If relative_to fails, try to find a common path or use filename
|
|
140
|
-
component_data["file_path"] = Path(comp.file_path).name
|
|
141
|
-
|
|
142
|
-
# Add schema information only if available and not None
|
|
143
|
-
if hasattr(comp, "input_schema") and comp.input_schema:
|
|
144
|
-
component_data["input_schema"] = comp.input_schema
|
|
145
|
-
if hasattr(comp, "output_schema") and comp.output_schema:
|
|
146
|
-
component_data["output_schema"] = comp.output_schema
|
|
147
|
-
|
|
148
|
-
# Add component-specific fields only if they have values
|
|
149
|
-
if comp_type == ComponentType.RESOURCE:
|
|
150
|
-
if hasattr(comp, "uri_template") and comp.uri_template:
|
|
151
|
-
component_data["uri_template"] = comp.uri_template
|
|
152
|
-
|
|
153
|
-
elif comp_type == ComponentType.TOOL:
|
|
154
|
-
if hasattr(comp, "annotations") and comp.annotations:
|
|
155
|
-
component_data["annotations"] = comp.annotations
|
|
156
|
-
|
|
157
|
-
# Add parameters only if they exist and are not empty
|
|
158
|
-
if hasattr(comp, "parameters") and comp.parameters:
|
|
159
|
-
component_data["parameters"] = comp.parameters
|
|
160
|
-
|
|
161
|
-
result.append(component_data)
|
|
162
|
-
|
|
163
|
-
return result
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
def _get_component_counts(
|
|
167
|
-
components: dict[ComponentType, list[ParsedComponent]],
|
|
168
|
-
) -> dict[str, int]:
|
|
169
|
-
"""Get component counts by type.
|
|
170
|
-
|
|
171
|
-
Args:
|
|
172
|
-
components: Dictionary of parsed components by type
|
|
173
|
-
|
|
174
|
-
Returns:
|
|
175
|
-
Dictionary with counts for each component type
|
|
176
|
-
"""
|
|
177
|
-
return {
|
|
178
|
-
"tools": len(components.get(ComponentType.TOOL, [])),
|
|
179
|
-
"resources": len(components.get(ComponentType.RESOURCE, [])),
|
|
180
|
-
"prompts": len(components.get(ComponentType.PROMPT, [])),
|
|
181
|
-
"total": sum(len(comp_list) for comp_list in components.values()),
|
|
182
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|