golf-mcp 0.1.10__py3-none-any.whl → 0.1.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 -1
- golf/auth/__init__.py +38 -26
- golf/auth/api_key.py +16 -23
- golf/auth/helpers.py +68 -54
- golf/auth/oauth.py +340 -277
- golf/auth/provider.py +58 -53
- golf/cli/__init__.py +1 -1
- golf/cli/main.py +202 -82
- golf/commands/__init__.py +1 -1
- golf/commands/build.py +31 -25
- golf/commands/init.py +119 -80
- golf/commands/run.py +14 -13
- golf/core/__init__.py +1 -1
- golf/core/builder.py +478 -353
- golf/core/builder_auth.py +115 -107
- golf/core/builder_telemetry.py +12 -9
- golf/core/config.py +62 -46
- golf/core/parser.py +174 -136
- golf/core/telemetry.py +169 -69
- golf/core/transformer.py +53 -55
- golf/examples/__init__.py +0 -1
- golf/examples/api_key/pre_build.py +2 -2
- golf/examples/api_key/tools/issues/create.py +35 -36
- golf/examples/api_key/tools/issues/list.py +42 -37
- golf/examples/api_key/tools/repos/list.py +50 -29
- golf/examples/api_key/tools/search/code.py +50 -37
- golf/examples/api_key/tools/users/get.py +21 -20
- golf/examples/basic/pre_build.py +4 -4
- golf/examples/basic/prompts/welcome.py +6 -7
- golf/examples/basic/resources/current_time.py +10 -9
- golf/examples/basic/resources/info.py +6 -5
- golf/examples/basic/resources/weather/common.py +16 -10
- golf/examples/basic/resources/weather/current.py +15 -11
- golf/examples/basic/resources/weather/forecast.py +15 -11
- golf/examples/basic/tools/github_user.py +19 -21
- golf/examples/basic/tools/hello.py +10 -6
- golf/examples/basic/tools/payments/charge.py +34 -25
- golf/examples/basic/tools/payments/common.py +8 -6
- golf/examples/basic/tools/payments/refund.py +29 -25
- golf/telemetry/__init__.py +6 -6
- golf/telemetry/instrumentation.py +781 -276
- {golf_mcp-0.1.10.dist-info → golf_mcp-0.1.12.dist-info}/METADATA +1 -1
- golf_mcp-0.1.12.dist-info/RECORD +55 -0
- {golf_mcp-0.1.10.dist-info → golf_mcp-0.1.12.dist-info}/WHEEL +1 -1
- golf_mcp-0.1.10.dist-info/RECORD +0 -55
- {golf_mcp-0.1.10.dist-info → golf_mcp-0.1.12.dist-info}/entry_points.txt +0 -0
- {golf_mcp-0.1.10.dist-info → golf_mcp-0.1.12.dist-info}/licenses/LICENSE +0 -0
- {golf_mcp-0.1.10.dist-info → golf_mcp-0.1.12.dist-info}/top_level.txt +0 -0
golf/commands/build.py
CHANGED
|
@@ -4,26 +4,26 @@ This module implements the `golf build` command which generates a standalone
|
|
|
4
4
|
FastMCP application from a GolfMCP project.
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
-
from pathlib import Path
|
|
8
7
|
import argparse
|
|
8
|
+
from pathlib import Path
|
|
9
9
|
|
|
10
10
|
from rich.console import Console
|
|
11
11
|
|
|
12
|
-
from golf.core.config import Settings, load_settings
|
|
13
12
|
from golf.core.builder import build_project as core_build_project
|
|
13
|
+
from golf.core.config import Settings, load_settings
|
|
14
14
|
|
|
15
15
|
console = Console()
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
def build_project(
|
|
19
|
-
project_path: Path,
|
|
20
|
-
settings: Settings,
|
|
19
|
+
project_path: Path,
|
|
20
|
+
settings: Settings,
|
|
21
21
|
output_dir: Path,
|
|
22
22
|
build_env: str = "prod",
|
|
23
|
-
copy_env: bool = False
|
|
23
|
+
copy_env: bool = False,
|
|
24
24
|
) -> None:
|
|
25
25
|
"""Build a standalone FastMCP application from a GolfMCP project.
|
|
26
|
-
|
|
26
|
+
|
|
27
27
|
Args:
|
|
28
28
|
project_path: Path to the project root
|
|
29
29
|
settings: Project settings
|
|
@@ -32,47 +32,53 @@ def build_project(
|
|
|
32
32
|
copy_env: Whether to copy environment variables to the built app
|
|
33
33
|
"""
|
|
34
34
|
# Call the centralized build function from core.builder
|
|
35
|
-
core_build_project(
|
|
35
|
+
core_build_project(
|
|
36
|
+
project_path, settings, output_dir, build_env=build_env, copy_env=copy_env
|
|
37
|
+
)
|
|
36
38
|
|
|
37
39
|
|
|
38
40
|
# Add a main section to run the build_project function when this module is executed directly
|
|
39
41
|
if __name__ == "__main__":
|
|
40
|
-
parser = argparse.ArgumentParser(
|
|
42
|
+
parser = argparse.ArgumentParser(
|
|
43
|
+
description="Build a standalone FastMCP application"
|
|
44
|
+
)
|
|
41
45
|
parser.add_argument(
|
|
42
|
-
"--project-path",
|
|
43
|
-
|
|
46
|
+
"--project-path",
|
|
47
|
+
"-p",
|
|
48
|
+
type=Path,
|
|
44
49
|
default=Path.cwd(),
|
|
45
|
-
help="Path to the project root (default: current directory)"
|
|
50
|
+
help="Path to the project root (default: current directory)",
|
|
46
51
|
)
|
|
47
52
|
parser.add_argument(
|
|
48
|
-
"--output-dir",
|
|
49
|
-
|
|
53
|
+
"--output-dir",
|
|
54
|
+
"-o",
|
|
55
|
+
type=Path,
|
|
50
56
|
default=Path.cwd() / "dist",
|
|
51
|
-
help="Directory to output the built project (default: ./dist)"
|
|
57
|
+
help="Directory to output the built project (default: ./dist)",
|
|
52
58
|
)
|
|
53
59
|
parser.add_argument(
|
|
54
60
|
"--build-env",
|
|
55
61
|
type=str,
|
|
56
62
|
default="prod",
|
|
57
63
|
choices=["dev", "prod"],
|
|
58
|
-
help="Build environment to use (default: prod)"
|
|
64
|
+
help="Build environment to use (default: prod)",
|
|
59
65
|
)
|
|
60
66
|
parser.add_argument(
|
|
61
67
|
"--copy-env",
|
|
62
68
|
action="store_true",
|
|
63
|
-
help="Copy environment variables to the built application"
|
|
69
|
+
help="Copy environment variables to the built application",
|
|
64
70
|
)
|
|
65
|
-
|
|
71
|
+
|
|
66
72
|
args = parser.parse_args()
|
|
67
|
-
|
|
73
|
+
|
|
68
74
|
# Load settings from the project path
|
|
69
75
|
settings = load_settings(args.project_path)
|
|
70
|
-
|
|
76
|
+
|
|
71
77
|
# Execute the build
|
|
72
78
|
build_project(
|
|
73
|
-
args.project_path,
|
|
74
|
-
settings,
|
|
75
|
-
args.output_dir,
|
|
76
|
-
build_env=args.build_env,
|
|
77
|
-
copy_env=args.copy_env
|
|
78
|
-
)
|
|
79
|
+
args.project_path,
|
|
80
|
+
settings,
|
|
81
|
+
args.output_dir,
|
|
82
|
+
build_env=args.build_env,
|
|
83
|
+
copy_env=args.copy_env,
|
|
84
|
+
)
|
golf/commands/init.py
CHANGED
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
"""Project initialization command implementation."""
|
|
2
2
|
|
|
3
|
-
import os
|
|
4
3
|
import shutil
|
|
5
4
|
from pathlib import Path
|
|
6
|
-
from typing import Optional
|
|
7
5
|
|
|
8
6
|
from rich.console import Console
|
|
9
7
|
from rich.progress import Progress, SpinnerColumn, TextColumn
|
|
10
8
|
from rich.prompt import Confirm
|
|
11
9
|
|
|
12
|
-
from golf.core.telemetry import track_event
|
|
10
|
+
from golf.core.telemetry import track_command, track_event
|
|
13
11
|
|
|
14
12
|
console = Console()
|
|
15
13
|
|
|
@@ -20,83 +18,110 @@ def initialize_project(
|
|
|
20
18
|
template: str = "basic",
|
|
21
19
|
) -> None:
|
|
22
20
|
"""Initialize a new GolfMCP project with the specified template.
|
|
23
|
-
|
|
21
|
+
|
|
24
22
|
Args:
|
|
25
23
|
project_name: Name of the project
|
|
26
24
|
output_dir: Directory where the project will be created
|
|
27
25
|
template: Template to use (basic or api_key)
|
|
28
26
|
"""
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
console.print(
|
|
41
|
-
f"[bold red]Error:[/bold red] '{output_dir}' exists but is not a directory."
|
|
27
|
+
try:
|
|
28
|
+
# Validate template
|
|
29
|
+
valid_templates = ("basic", "api_key")
|
|
30
|
+
if template not in valid_templates:
|
|
31
|
+
console.print(f"[bold red]Error:[/bold red] Unknown template '{template}'")
|
|
32
|
+
console.print(f"Available templates: {', '.join(valid_templates)}")
|
|
33
|
+
track_command(
|
|
34
|
+
"init",
|
|
35
|
+
success=False,
|
|
36
|
+
error_type="InvalidTemplate",
|
|
37
|
+
error_message=f"Unknown template: {template}",
|
|
42
38
|
)
|
|
43
|
-
track_event("cli_init_failed", {"success": False})
|
|
44
39
|
return
|
|
45
|
-
|
|
46
|
-
# Check if directory
|
|
47
|
-
if
|
|
48
|
-
if not
|
|
40
|
+
|
|
41
|
+
# Check if directory exists
|
|
42
|
+
if output_dir.exists():
|
|
43
|
+
if not output_dir.is_dir():
|
|
44
|
+
console.print(
|
|
45
|
+
f"[bold red]Error:[/bold red] '{output_dir}' exists but is not a directory."
|
|
46
|
+
)
|
|
47
|
+
track_command(
|
|
48
|
+
"init",
|
|
49
|
+
success=False,
|
|
50
|
+
error_type="NotADirectory",
|
|
51
|
+
error_message="Target exists but is not a directory",
|
|
52
|
+
)
|
|
53
|
+
return
|
|
54
|
+
|
|
55
|
+
# Check if directory is empty
|
|
56
|
+
if any(output_dir.iterdir()) and not Confirm.ask(
|
|
49
57
|
f"Directory '{output_dir}' is not empty. Continue anyway?",
|
|
50
58
|
default=False,
|
|
51
59
|
):
|
|
52
60
|
console.print("Initialization cancelled.")
|
|
53
61
|
track_event("cli_init_cancelled", {"success": False})
|
|
54
62
|
return
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
63
|
+
else:
|
|
64
|
+
# Create the directory
|
|
65
|
+
output_dir.mkdir(parents=True)
|
|
66
|
+
|
|
67
|
+
# Find template directory within the installed package
|
|
68
|
+
import golf
|
|
69
|
+
|
|
70
|
+
package_init_file = Path(golf.__file__)
|
|
71
|
+
# The 'examples' directory is now inside the 'golf' package directory
|
|
72
|
+
# e.g. golf/examples/basic, so go up one from __init__.py to get to 'golf'
|
|
73
|
+
template_dir = package_init_file.parent / "examples" / template
|
|
74
|
+
|
|
75
|
+
if not template_dir.exists():
|
|
76
|
+
console.print(
|
|
77
|
+
f"[bold red]Error:[/bold red] Could not find template '{template}'"
|
|
78
|
+
)
|
|
79
|
+
track_command(
|
|
80
|
+
"init",
|
|
81
|
+
success=False,
|
|
82
|
+
error_type="TemplateNotFound",
|
|
83
|
+
error_message=f"Template directory not found: {template}",
|
|
84
|
+
)
|
|
85
|
+
return
|
|
86
|
+
|
|
87
|
+
# Copy template files
|
|
88
|
+
with Progress(
|
|
89
|
+
SpinnerColumn(),
|
|
90
|
+
TextColumn("[bold green]Creating project structure...[/bold green]"),
|
|
91
|
+
transient=True,
|
|
92
|
+
) as progress:
|
|
93
|
+
progress.add_task("copying", total=None)
|
|
94
|
+
|
|
95
|
+
# Copy directory structure
|
|
96
|
+
_copy_template(template_dir, output_dir, project_name)
|
|
97
|
+
|
|
98
|
+
# Create virtual environment
|
|
99
|
+
console.print("[bold green]Project initialized successfully![/bold green]")
|
|
100
|
+
console.print("\nTo get started, run:")
|
|
101
|
+
console.print(f" cd {output_dir.name}")
|
|
102
|
+
console.print(" golf build dev")
|
|
103
|
+
|
|
104
|
+
# Track successful initialization
|
|
105
|
+
track_event("cli_init_success", {"success": True, "template": template})
|
|
106
|
+
except Exception as e:
|
|
107
|
+
# Capture error details for telemetry
|
|
108
|
+
error_type = type(e).__name__
|
|
109
|
+
error_message = str(e)
|
|
110
|
+
|
|
67
111
|
console.print(
|
|
68
|
-
f"[bold red]Error:[/bold red]
|
|
112
|
+
f"[bold red]Error during initialization:[/bold red] {error_message}"
|
|
113
|
+
)
|
|
114
|
+
track_command(
|
|
115
|
+
"init", success=False, error_type=error_type, error_message=error_message
|
|
69
116
|
)
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
# Copy template files
|
|
74
|
-
with Progress(
|
|
75
|
-
SpinnerColumn(),
|
|
76
|
-
TextColumn("[bold green]Creating project structure...[/bold green]"),
|
|
77
|
-
transient=True,
|
|
78
|
-
) as progress:
|
|
79
|
-
progress.add_task("copying", total=None)
|
|
80
|
-
|
|
81
|
-
# Copy directory structure
|
|
82
|
-
_copy_template(template_dir, output_dir, project_name)
|
|
83
|
-
|
|
84
|
-
# Create virtual environment
|
|
85
|
-
console.print("[bold green]Project initialized successfully![/bold green]")
|
|
86
|
-
console.print(f"\nTo get started, run:")
|
|
87
|
-
console.print(f" cd {output_dir.name}")
|
|
88
|
-
console.print(f" golf build dev")
|
|
89
|
-
|
|
90
|
-
# Track successful initialization
|
|
91
|
-
track_event("cli_init_success", {
|
|
92
|
-
"success": True,
|
|
93
|
-
"template": template
|
|
94
|
-
})
|
|
117
|
+
|
|
118
|
+
# Re-raise to maintain existing behavior
|
|
119
|
+
raise
|
|
95
120
|
|
|
96
121
|
|
|
97
122
|
def _copy_template(source_dir: Path, target_dir: Path, project_name: str) -> None:
|
|
98
123
|
"""Copy template files to the target directory, with variable substitution.
|
|
99
|
-
|
|
124
|
+
|
|
100
125
|
Args:
|
|
101
126
|
source_dir: Source template directory
|
|
102
127
|
target_dir: Target project directory
|
|
@@ -106,42 +131,44 @@ def _copy_template(source_dir: Path, target_dir: Path, project_name: str) -> Non
|
|
|
106
131
|
(target_dir / "tools").mkdir(exist_ok=True)
|
|
107
132
|
(target_dir / "resources").mkdir(exist_ok=True)
|
|
108
133
|
(target_dir / "prompts").mkdir(exist_ok=True)
|
|
109
|
-
|
|
134
|
+
|
|
110
135
|
# Copy all files from the template
|
|
111
136
|
for source_path in source_dir.glob("**/*"):
|
|
112
137
|
# Skip if directory (we'll create directories as needed)
|
|
113
138
|
if source_path.is_dir():
|
|
114
139
|
continue
|
|
115
|
-
|
|
140
|
+
|
|
116
141
|
# Compute relative path
|
|
117
142
|
rel_path = source_path.relative_to(source_dir)
|
|
118
143
|
target_path = target_dir / rel_path
|
|
119
|
-
|
|
144
|
+
|
|
120
145
|
# Create parent directories if needed
|
|
121
146
|
target_path.parent.mkdir(parents=True, exist_ok=True)
|
|
122
|
-
|
|
147
|
+
|
|
123
148
|
# Copy and substitute content for text files
|
|
124
149
|
if _is_text_file(source_path):
|
|
125
|
-
with open(source_path,
|
|
150
|
+
with open(source_path, encoding="utf-8") as f:
|
|
126
151
|
content = f.read()
|
|
127
|
-
|
|
152
|
+
|
|
128
153
|
# Replace template variables
|
|
129
154
|
content = content.replace("{{project_name}}", project_name)
|
|
130
|
-
content = content.replace(
|
|
131
|
-
|
|
155
|
+
content = content.replace(
|
|
156
|
+
"{{project_name_lowercase}}", project_name.lower()
|
|
157
|
+
)
|
|
158
|
+
|
|
132
159
|
with open(target_path, "w", encoding="utf-8") as f:
|
|
133
160
|
f.write(content)
|
|
134
161
|
else:
|
|
135
162
|
# Binary file, just copy
|
|
136
163
|
shutil.copy2(source_path, target_path)
|
|
137
|
-
|
|
164
|
+
|
|
138
165
|
# Create .env file
|
|
139
166
|
env_file = target_dir / ".env"
|
|
140
167
|
with open(env_file, "w", encoding="utf-8") as f:
|
|
141
168
|
f.write(f"GOLF_NAME={project_name}\n")
|
|
142
169
|
f.write("GOLF_HOST=127.0.0.1\n")
|
|
143
170
|
f.write("GOLF_PORT=3000\n")
|
|
144
|
-
|
|
171
|
+
|
|
145
172
|
# Create a .gitignore if it doesn't exist
|
|
146
173
|
gitignore_file = target_dir / ".gitignore"
|
|
147
174
|
if not gitignore_file.exists():
|
|
@@ -182,31 +209,43 @@ def _copy_template(source_dir: Path, target_dir: Path, project_name: str) -> Non
|
|
|
182
209
|
|
|
183
210
|
def _is_text_file(path: Path) -> bool:
|
|
184
211
|
"""Check if a file is a text file that needs variable substitution.
|
|
185
|
-
|
|
212
|
+
|
|
186
213
|
Args:
|
|
187
214
|
path: Path to check
|
|
188
|
-
|
|
215
|
+
|
|
189
216
|
Returns:
|
|
190
217
|
True if the file is a text file
|
|
191
218
|
"""
|
|
192
219
|
# List of known text file extensions
|
|
193
220
|
text_extensions = {
|
|
194
|
-
".py",
|
|
195
|
-
".
|
|
221
|
+
".py",
|
|
222
|
+
".md",
|
|
223
|
+
".txt",
|
|
224
|
+
".html",
|
|
225
|
+
".css",
|
|
226
|
+
".js",
|
|
227
|
+
".json",
|
|
228
|
+
".yml",
|
|
229
|
+
".yaml",
|
|
230
|
+
".toml",
|
|
231
|
+
".ini",
|
|
232
|
+
".cfg",
|
|
233
|
+
".env",
|
|
234
|
+
".example",
|
|
196
235
|
}
|
|
197
|
-
|
|
236
|
+
|
|
198
237
|
# Check if the file has a text extension
|
|
199
238
|
if path.suffix in text_extensions:
|
|
200
239
|
return True
|
|
201
|
-
|
|
240
|
+
|
|
202
241
|
# Check specific filenames without extensions
|
|
203
242
|
if path.name in {".gitignore", "README", "LICENSE"}:
|
|
204
243
|
return True
|
|
205
|
-
|
|
244
|
+
|
|
206
245
|
# Try to detect if it's a text file by reading a bit of it
|
|
207
246
|
try:
|
|
208
|
-
with open(path,
|
|
247
|
+
with open(path, encoding="utf-8") as f:
|
|
209
248
|
f.read(1024)
|
|
210
249
|
return True
|
|
211
250
|
except UnicodeDecodeError:
|
|
212
|
-
return False
|
|
251
|
+
return False
|
golf/commands/run.py
CHANGED
|
@@ -4,7 +4,6 @@ import os
|
|
|
4
4
|
import subprocess
|
|
5
5
|
import sys
|
|
6
6
|
from pathlib import Path
|
|
7
|
-
from typing import Optional
|
|
8
7
|
|
|
9
8
|
from rich.console import Console
|
|
10
9
|
|
|
@@ -16,44 +15,46 @@ console = Console()
|
|
|
16
15
|
def run_server(
|
|
17
16
|
project_path: Path,
|
|
18
17
|
settings: Settings,
|
|
19
|
-
dist_dir:
|
|
20
|
-
host:
|
|
21
|
-
port:
|
|
18
|
+
dist_dir: Path | None = None,
|
|
19
|
+
host: str | None = None,
|
|
20
|
+
port: int | None = None,
|
|
22
21
|
) -> int:
|
|
23
22
|
"""Run the built FastMCP server.
|
|
24
|
-
|
|
23
|
+
|
|
25
24
|
Args:
|
|
26
25
|
project_path: Path to the project root
|
|
27
26
|
settings: Project settings
|
|
28
27
|
dist_dir: Path to the directory containing the built server (defaults to project_path/dist)
|
|
29
28
|
host: Host to bind the server to (overrides settings)
|
|
30
29
|
port: Port to bind the server to (overrides settings)
|
|
31
|
-
|
|
30
|
+
|
|
32
31
|
Returns:
|
|
33
32
|
Process return code
|
|
34
33
|
"""
|
|
35
34
|
# Set default dist directory if not specified
|
|
36
35
|
if dist_dir is None:
|
|
37
36
|
dist_dir = project_path / "dist"
|
|
38
|
-
|
|
37
|
+
|
|
39
38
|
# Check if server file exists
|
|
40
39
|
server_path = dist_dir / "server.py"
|
|
41
40
|
if not server_path.exists():
|
|
42
|
-
console.print(
|
|
41
|
+
console.print(
|
|
42
|
+
f"[bold red]Error: Server file {server_path} not found.[/bold red]"
|
|
43
|
+
)
|
|
43
44
|
return 1
|
|
44
|
-
|
|
45
|
+
|
|
45
46
|
# Prepare environment variables
|
|
46
47
|
env = os.environ.copy()
|
|
47
48
|
if host is not None:
|
|
48
49
|
env["HOST"] = host
|
|
49
50
|
elif settings.host:
|
|
50
51
|
env["HOST"] = settings.host
|
|
51
|
-
|
|
52
|
+
|
|
52
53
|
if port is not None:
|
|
53
54
|
env["PORT"] = str(port)
|
|
54
55
|
elif settings.port:
|
|
55
56
|
env["PORT"] = str(settings.port)
|
|
56
|
-
|
|
57
|
+
|
|
57
58
|
# Run the server
|
|
58
59
|
try:
|
|
59
60
|
# Using subprocess to properly handle signals (Ctrl+C)
|
|
@@ -62,11 +63,11 @@ def run_server(
|
|
|
62
63
|
cwd=dist_dir,
|
|
63
64
|
env=env,
|
|
64
65
|
)
|
|
65
|
-
|
|
66
|
+
|
|
66
67
|
return process.returncode
|
|
67
68
|
except KeyboardInterrupt:
|
|
68
69
|
console.print("\n[yellow]Server stopped by user[/yellow]")
|
|
69
70
|
return 0
|
|
70
71
|
except Exception as e:
|
|
71
72
|
console.print(f"\n[bold red]Error running server:[/bold red] {e}")
|
|
72
|
-
return 1
|
|
73
|
+
return 1
|
golf/core/__init__.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"""Core functionality for the GolfMCP framework."""
|
|
1
|
+
"""Core functionality for the GolfMCP framework."""
|