golf-mcp 0.2.11__py3-none-any.whl → 0.2.13__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 +113 -36
- 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.13.dist-info}/METADATA +7 -6
- {golf_mcp-0.2.11.dist-info → golf_mcp-0.2.13.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.13.dist-info}/WHEEL +0 -0
- {golf_mcp-0.2.11.dist-info → golf_mcp-0.2.13.dist-info}/entry_points.txt +0 -0
- {golf_mcp-0.2.11.dist-info → golf_mcp-0.2.13.dist-info}/licenses/LICENSE +0 -0
- {golf_mcp-0.2.11.dist-info → golf_mcp-0.2.13.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.13"
|
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,
|
|
@@ -383,6 +383,22 @@ class CodeGenerator:
|
|
|
383
383
|
console.print()
|
|
384
384
|
console.print(get_status_text("success", f"Build completed successfully in {output_dir_display}"))
|
|
385
385
|
|
|
386
|
+
def _generate_root_file_imports(self) -> list[str]:
|
|
387
|
+
"""Generate import statements for automatically discovered root files."""
|
|
388
|
+
root_file_imports = []
|
|
389
|
+
discovered_files = discover_root_files(self.project_path)
|
|
390
|
+
|
|
391
|
+
if discovered_files:
|
|
392
|
+
root_file_imports.append("# Import root-level Python files")
|
|
393
|
+
|
|
394
|
+
for filename in sorted(discovered_files.keys()):
|
|
395
|
+
module_name = Path(filename).stem # env.py -> env
|
|
396
|
+
root_file_imports.append(f"import {module_name}")
|
|
397
|
+
|
|
398
|
+
root_file_imports.append("") # Blank line
|
|
399
|
+
|
|
400
|
+
return root_file_imports
|
|
401
|
+
|
|
386
402
|
def _create_directory_structure(self) -> None:
|
|
387
403
|
"""Create the output directory structure"""
|
|
388
404
|
# Create main directories
|
|
@@ -810,6 +826,11 @@ class CodeGenerator:
|
|
|
810
826
|
"",
|
|
811
827
|
]
|
|
812
828
|
|
|
829
|
+
# Add imports for root files
|
|
830
|
+
root_file_imports = self._generate_root_file_imports()
|
|
831
|
+
if root_file_imports:
|
|
832
|
+
imports.extend(root_file_imports)
|
|
833
|
+
|
|
813
834
|
# Add auth imports if auth is configured
|
|
814
835
|
if auth_components.get("has_auth"):
|
|
815
836
|
imports.extend(auth_components["imports"])
|
|
@@ -1401,21 +1422,13 @@ def build_project(
|
|
|
1401
1422
|
build_env: Build environment ('dev' or 'prod')
|
|
1402
1423
|
copy_env: Whether to copy environment variables to the built app
|
|
1403
1424
|
"""
|
|
1404
|
-
# Load
|
|
1405
|
-
# This happens regardless of copy_env setting to ensure build process works
|
|
1425
|
+
# Load environment variables from .env for build operations
|
|
1406
1426
|
from dotenv import load_dotenv
|
|
1407
1427
|
|
|
1408
1428
|
project_env_file = project_path / ".env"
|
|
1409
1429
|
if project_env_file.exists():
|
|
1410
|
-
# Load GOLF_* variables for build process
|
|
1411
1430
|
load_dotenv(project_env_file, override=False)
|
|
1412
1431
|
|
|
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
1432
|
# Execute auth.py if it exists (for authentication configuration)
|
|
1420
1433
|
# Also support legacy pre_build.py for backward compatibility
|
|
1421
1434
|
auth_path = project_path / "auth.py"
|
|
@@ -1583,32 +1596,16 @@ def build_project(
|
|
|
1583
1596
|
shutil.copy2(health_path, output_dir)
|
|
1584
1597
|
console.print(get_status_text("success", "Health script copied to build directory"))
|
|
1585
1598
|
|
|
1586
|
-
#
|
|
1587
|
-
|
|
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
|
-
)
|
|
1599
|
+
# Copy any additional Python files from project root
|
|
1600
|
+
discovered_root_files = discover_root_files(project_path)
|
|
1603
1601
|
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
console.print("[dim]Tip: Ensure GOLF_API_KEY and GOLF_SERVER_ID are available in your .env file[/dim]")
|
|
1602
|
+
for filename, file_path in discovered_root_files.items():
|
|
1603
|
+
dest_path = output_dir / filename
|
|
1604
|
+
try:
|
|
1605
|
+
shutil.copy2(file_path, dest_path)
|
|
1606
|
+
console.print(get_status_text("success", f"Root file {filename} copied to build directory"))
|
|
1607
|
+
except (OSError, shutil.Error) as e:
|
|
1608
|
+
console.print(f"[red]Error copying {filename}: {e}[/red]")
|
|
1612
1609
|
|
|
1613
1610
|
# Create a simple README
|
|
1614
1611
|
readme_content = f"""# {settings.name}
|
|
@@ -1639,7 +1636,7 @@ This is a standalone FastMCP server generated by GolfMCP.
|
|
|
1639
1636
|
|
|
1640
1637
|
# Legacy ProviderConfig removed in Golf 0.2.x - use modern auth configurations
|
|
1641
1638
|
# Legacy OAuth imports removed in Golf 0.2.x - use FastMCP 2.11+ auth providers
|
|
1642
|
-
from golf.auth.helpers import
|
|
1639
|
+
from golf.auth.helpers import extract_token_from_header, get_api_key, set_api_key
|
|
1643
1640
|
from golf.auth.api_key import configure_api_key, get_api_key_config
|
|
1644
1641
|
from golf.auth.factory import create_auth_provider
|
|
1645
1642
|
from golf.auth.providers import RemoteAuthConfig, JWTAuthConfig, StaticTokenConfig, OAuthServerConfig
|
|
@@ -1709,6 +1706,86 @@ from golf.auth.providers import RemoteAuthConfig, JWTAuthConfig, StaticTokenConf
|
|
|
1709
1706
|
)
|
|
1710
1707
|
|
|
1711
1708
|
|
|
1709
|
+
def discover_root_files(project_path: Path) -> dict[str, Path]:
|
|
1710
|
+
"""Automatically discover all Python files in the project root directory.
|
|
1711
|
+
|
|
1712
|
+
This function finds all .py files in the project root, excluding:
|
|
1713
|
+
- Special Golf files (startup.py, health.py, readiness.py, auth.py, server.py)
|
|
1714
|
+
- Component directories (tools/, resources/, prompts/)
|
|
1715
|
+
- Hidden files and common exclusions (__pycache__, .git, etc.)
|
|
1716
|
+
|
|
1717
|
+
Args:
|
|
1718
|
+
project_path: Path to the project root directory
|
|
1719
|
+
|
|
1720
|
+
Returns:
|
|
1721
|
+
Dictionary mapping filenames to their full paths
|
|
1722
|
+
"""
|
|
1723
|
+
import ast
|
|
1724
|
+
|
|
1725
|
+
discovered_files = {}
|
|
1726
|
+
|
|
1727
|
+
# Files that are handled specially by Golf and should not be auto-copied
|
|
1728
|
+
reserved_files = {
|
|
1729
|
+
"startup.py",
|
|
1730
|
+
"health.py",
|
|
1731
|
+
"readiness.py",
|
|
1732
|
+
"auth.py",
|
|
1733
|
+
"server.py",
|
|
1734
|
+
"pre_build.py", # Legacy auth file
|
|
1735
|
+
"golf.json",
|
|
1736
|
+
"golf.toml", # Config files
|
|
1737
|
+
"__init__.py", # Package files
|
|
1738
|
+
}
|
|
1739
|
+
|
|
1740
|
+
# Find all .py files in the project root (not in subdirectories)
|
|
1741
|
+
try:
|
|
1742
|
+
for file_path in project_path.iterdir():
|
|
1743
|
+
if not file_path.is_file():
|
|
1744
|
+
continue
|
|
1745
|
+
|
|
1746
|
+
filename = file_path.name
|
|
1747
|
+
|
|
1748
|
+
# Skip non-Python files
|
|
1749
|
+
if not filename.endswith(".py"):
|
|
1750
|
+
continue
|
|
1751
|
+
|
|
1752
|
+
# Skip reserved/special files
|
|
1753
|
+
if filename in reserved_files:
|
|
1754
|
+
continue
|
|
1755
|
+
|
|
1756
|
+
# Skip hidden files and temporary files
|
|
1757
|
+
if filename.startswith(".") or filename.startswith("_") or filename.endswith("~"):
|
|
1758
|
+
continue
|
|
1759
|
+
|
|
1760
|
+
# Validate it's a readable Python file
|
|
1761
|
+
try:
|
|
1762
|
+
with open(file_path, encoding="utf-8") as f:
|
|
1763
|
+
# Read first 200 chars to validate it's a proper Python file
|
|
1764
|
+
content = f.read(200)
|
|
1765
|
+
|
|
1766
|
+
# Basic Python syntax validation
|
|
1767
|
+
try:
|
|
1768
|
+
ast.parse(content + "\n# truncated for validation")
|
|
1769
|
+
except SyntaxError:
|
|
1770
|
+
# Still include files with syntax errors, but warn
|
|
1771
|
+
console.print(f"[yellow]Warning: {filename} has syntax issues but will be included[/yellow]")
|
|
1772
|
+
|
|
1773
|
+
except (OSError, UnicodeDecodeError) as e:
|
|
1774
|
+
console.print(f"[yellow]Warning: Cannot read {filename}, skipping: {e}[/yellow]")
|
|
1775
|
+
continue
|
|
1776
|
+
|
|
1777
|
+
discovered_files[filename] = file_path
|
|
1778
|
+
|
|
1779
|
+
except OSError as e:
|
|
1780
|
+
console.print(f"[yellow]Warning: Error scanning project directory: {e}[/yellow]")
|
|
1781
|
+
|
|
1782
|
+
if discovered_files:
|
|
1783
|
+
file_list = ", ".join(sorted(discovered_files.keys()))
|
|
1784
|
+
console.print(f"[dim]Found root Python files: {file_list}[/dim]")
|
|
1785
|
+
|
|
1786
|
+
return discovered_files
|
|
1787
|
+
|
|
1788
|
+
|
|
1712
1789
|
# Legacy function removed - replaced by parse_shared_files in parser module
|
|
1713
1790
|
|
|
1714
1791
|
|
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.13
|
|
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=C0atO05M0rfDTTHt02NxNa4jt0eSqXM4AxShEhb2epA,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=7NuRoIGpmqT0vg2ZF5vMA-T6kBfcJOEi1oPwVUKJBes,80427
|
|
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.13.dist-info/licenses/LICENSE,sha256=5_j2f6fTJmvfmUewzElhkpAaXg2grVoxKouOA8ihV6E,11348
|
|
48
|
+
golf_mcp-0.2.13.dist-info/METADATA,sha256=P-2vXyg5M1YIAvvgMr7NBeViHlPSTs7wGpc0RUyUQys,9414
|
|
49
|
+
golf_mcp-0.2.13.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
50
|
+
golf_mcp-0.2.13.dist-info/entry_points.txt,sha256=5y7rHYM8jGpU-nfwdknCm5XsApLulqsnA37MO6BUTYg,43
|
|
51
|
+
golf_mcp-0.2.13.dist-info/top_level.txt,sha256=BQToHcBUufdyhp9ONGMIvPE40jMEtmI20lYaKb4hxOg,5
|
|
52
|
+
golf_mcp-0.2.13.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
|