golf-mcp 0.2.12__py3-none-any.whl → 0.2.14__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/core/builder.py +121 -3
- golf/core/transformer.py +29 -1
- {golf_mcp-0.2.12.dist-info → golf_mcp-0.2.14.dist-info}/METADATA +1 -1
- {golf_mcp-0.2.12.dist-info → golf_mcp-0.2.14.dist-info}/RECORD +9 -9
- {golf_mcp-0.2.12.dist-info → golf_mcp-0.2.14.dist-info}/WHEEL +0 -0
- {golf_mcp-0.2.12.dist-info → golf_mcp-0.2.14.dist-info}/entry_points.txt +0 -0
- {golf_mcp-0.2.12.dist-info → golf_mcp-0.2.14.dist-info}/licenses/LICENSE +0 -0
- {golf_mcp-0.2.12.dist-info → golf_mcp-0.2.14.dist-info}/top_level.txt +0 -0
golf/__init__.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "0.2.
|
|
1
|
+
__version__ = "0.2.14"
|
golf/core/builder.py
CHANGED
|
@@ -383,6 +383,27 @@ 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
|
+
|
|
402
|
+
def _get_root_file_modules(self) -> set[str]:
|
|
403
|
+
"""Get set of root file module names for import transformation."""
|
|
404
|
+
discovered_files = discover_root_files(self.project_path)
|
|
405
|
+
return {Path(filename).stem for filename in discovered_files.keys()}
|
|
406
|
+
|
|
386
407
|
def _create_directory_structure(self) -> None:
|
|
387
408
|
"""Create the output directory structure"""
|
|
388
409
|
# Create main directories
|
|
@@ -428,12 +449,14 @@ class CodeGenerator:
|
|
|
428
449
|
target_file = target_dir / shared_file.name
|
|
429
450
|
|
|
430
451
|
# Use transformer to process the file
|
|
452
|
+
root_file_modules = self._get_root_file_modules()
|
|
431
453
|
transform_component(
|
|
432
454
|
component=None,
|
|
433
455
|
output_file=target_file,
|
|
434
456
|
project_path=self.project_path,
|
|
435
457
|
import_map=self.import_map,
|
|
436
458
|
source_file=shared_file,
|
|
459
|
+
root_file_modules=root_file_modules,
|
|
437
460
|
)
|
|
438
461
|
|
|
439
462
|
def _generate_tools(self) -> None:
|
|
@@ -458,7 +481,10 @@ class CodeGenerator:
|
|
|
458
481
|
|
|
459
482
|
# Create the tool file
|
|
460
483
|
output_file = tool_dir / rel_path.name
|
|
461
|
-
|
|
484
|
+
root_file_modules = self._get_root_file_modules()
|
|
485
|
+
transform_component(
|
|
486
|
+
tool, output_file, self.project_path, self.import_map, root_file_modules=root_file_modules
|
|
487
|
+
)
|
|
462
488
|
|
|
463
489
|
def _generate_resources(self) -> None:
|
|
464
490
|
"""Generate code for all resources."""
|
|
@@ -482,7 +508,10 @@ class CodeGenerator:
|
|
|
482
508
|
|
|
483
509
|
# Create the resource file
|
|
484
510
|
output_file = resource_dir / rel_path.name
|
|
485
|
-
|
|
511
|
+
root_file_modules = self._get_root_file_modules()
|
|
512
|
+
transform_component(
|
|
513
|
+
resource, output_file, self.project_path, self.import_map, root_file_modules=root_file_modules
|
|
514
|
+
)
|
|
486
515
|
|
|
487
516
|
def _generate_prompts(self) -> None:
|
|
488
517
|
"""Generate code for all prompts."""
|
|
@@ -506,7 +535,10 @@ class CodeGenerator:
|
|
|
506
535
|
|
|
507
536
|
# Create the prompt file
|
|
508
537
|
output_file = prompt_dir / rel_path.name
|
|
509
|
-
|
|
538
|
+
root_file_modules = self._get_root_file_modules()
|
|
539
|
+
transform_component(
|
|
540
|
+
prompt, output_file, self.project_path, self.import_map, root_file_modules=root_file_modules
|
|
541
|
+
)
|
|
510
542
|
|
|
511
543
|
def _get_transport_config(self, transport_type: str) -> dict:
|
|
512
544
|
"""Get transport-specific configuration (primarily for endpoint path display).
|
|
@@ -810,6 +842,11 @@ class CodeGenerator:
|
|
|
810
842
|
"",
|
|
811
843
|
]
|
|
812
844
|
|
|
845
|
+
# Add imports for root files
|
|
846
|
+
root_file_imports = self._generate_root_file_imports()
|
|
847
|
+
if root_file_imports:
|
|
848
|
+
imports.extend(root_file_imports)
|
|
849
|
+
|
|
813
850
|
# Add auth imports if auth is configured
|
|
814
851
|
if auth_components.get("has_auth"):
|
|
815
852
|
imports.extend(auth_components["imports"])
|
|
@@ -1575,6 +1612,17 @@ def build_project(
|
|
|
1575
1612
|
shutil.copy2(health_path, output_dir)
|
|
1576
1613
|
console.print(get_status_text("success", "Health script copied to build directory"))
|
|
1577
1614
|
|
|
1615
|
+
# Copy any additional Python files from project root
|
|
1616
|
+
discovered_root_files = discover_root_files(project_path)
|
|
1617
|
+
|
|
1618
|
+
for filename, file_path in discovered_root_files.items():
|
|
1619
|
+
dest_path = output_dir / filename
|
|
1620
|
+
try:
|
|
1621
|
+
shutil.copy2(file_path, dest_path)
|
|
1622
|
+
console.print(get_status_text("success", f"Root file {filename} copied to build directory"))
|
|
1623
|
+
except (OSError, shutil.Error) as e:
|
|
1624
|
+
console.print(f"[red]Error copying {filename}: {e}[/red]")
|
|
1625
|
+
|
|
1578
1626
|
# Create a simple README
|
|
1579
1627
|
readme_content = f"""# {settings.name}
|
|
1580
1628
|
|
|
@@ -1674,6 +1722,76 @@ from golf.auth.providers import RemoteAuthConfig, JWTAuthConfig, StaticTokenConf
|
|
|
1674
1722
|
)
|
|
1675
1723
|
|
|
1676
1724
|
|
|
1725
|
+
def discover_root_files(project_path: Path) -> dict[str, Path]:
|
|
1726
|
+
"""Automatically discover all Python files in the project root directory.
|
|
1727
|
+
|
|
1728
|
+
This function finds all .py files in the project root, excluding:
|
|
1729
|
+
- Special Golf files (startup.py, health.py, readiness.py, auth.py, server.py)
|
|
1730
|
+
- Component directories (tools/, resources/, prompts/)
|
|
1731
|
+
- Hidden files and common exclusions (__pycache__, .git, etc.)
|
|
1732
|
+
|
|
1733
|
+
Args:
|
|
1734
|
+
project_path: Path to the project root directory
|
|
1735
|
+
|
|
1736
|
+
Returns:
|
|
1737
|
+
Dictionary mapping filenames to their full paths
|
|
1738
|
+
"""
|
|
1739
|
+
discovered_files = {}
|
|
1740
|
+
|
|
1741
|
+
# Files that are handled specially by Golf and should not be auto-copied
|
|
1742
|
+
reserved_files = {
|
|
1743
|
+
"startup.py",
|
|
1744
|
+
"health.py",
|
|
1745
|
+
"readiness.py",
|
|
1746
|
+
"auth.py",
|
|
1747
|
+
"server.py",
|
|
1748
|
+
"pre_build.py", # Legacy auth file
|
|
1749
|
+
"golf.json",
|
|
1750
|
+
"golf.toml", # Config files
|
|
1751
|
+
"__init__.py", # Package files
|
|
1752
|
+
}
|
|
1753
|
+
|
|
1754
|
+
# Find all .py files in the project root (not in subdirectories)
|
|
1755
|
+
try:
|
|
1756
|
+
for file_path in project_path.iterdir():
|
|
1757
|
+
if not file_path.is_file():
|
|
1758
|
+
continue
|
|
1759
|
+
|
|
1760
|
+
filename = file_path.name
|
|
1761
|
+
|
|
1762
|
+
# Skip non-Python files
|
|
1763
|
+
if not filename.endswith(".py"):
|
|
1764
|
+
continue
|
|
1765
|
+
|
|
1766
|
+
# Skip reserved/special files
|
|
1767
|
+
if filename in reserved_files:
|
|
1768
|
+
continue
|
|
1769
|
+
|
|
1770
|
+
# Skip hidden files and temporary files
|
|
1771
|
+
if filename.startswith(".") or filename.startswith("_") or filename.endswith("~"):
|
|
1772
|
+
continue
|
|
1773
|
+
|
|
1774
|
+
# Just verify it's a readable file
|
|
1775
|
+
try:
|
|
1776
|
+
with open(file_path, encoding="utf-8") as f:
|
|
1777
|
+
# Just check if file is readable - don't validate syntax
|
|
1778
|
+
f.read(1) # Read one character to verify readability
|
|
1779
|
+
except (OSError, UnicodeDecodeError) as e:
|
|
1780
|
+
console.print(f"[yellow]Warning: Cannot read {filename}, skipping: {e}[/yellow]")
|
|
1781
|
+
continue
|
|
1782
|
+
|
|
1783
|
+
discovered_files[filename] = file_path
|
|
1784
|
+
|
|
1785
|
+
except OSError as e:
|
|
1786
|
+
console.print(f"[yellow]Warning: Error scanning project directory: {e}[/yellow]")
|
|
1787
|
+
|
|
1788
|
+
if discovered_files:
|
|
1789
|
+
file_list = ", ".join(sorted(discovered_files.keys()))
|
|
1790
|
+
console.print(f"[dim]Found root Python files: {file_list}[/dim]")
|
|
1791
|
+
|
|
1792
|
+
return discovered_files
|
|
1793
|
+
|
|
1794
|
+
|
|
1677
1795
|
# Legacy function removed - replaced by parse_shared_files in parser module
|
|
1678
1796
|
|
|
1679
1797
|
|
golf/core/transformer.py
CHANGED
|
@@ -20,6 +20,7 @@ class ImportTransformer(ast.NodeTransformer):
|
|
|
20
20
|
target_path: Path,
|
|
21
21
|
import_map: dict[str, str],
|
|
22
22
|
project_root: Path,
|
|
23
|
+
root_file_modules: set[str] | None = None,
|
|
23
24
|
) -> None:
|
|
24
25
|
"""Initialize the import transformer.
|
|
25
26
|
|
|
@@ -28,14 +29,34 @@ class ImportTransformer(ast.NodeTransformer):
|
|
|
28
29
|
target_path: Path to the target file
|
|
29
30
|
import_map: Mapping of original module paths to generated paths
|
|
30
31
|
project_root: Root path of the project
|
|
32
|
+
root_file_modules: Set of root file module names (without .py extension)
|
|
31
33
|
"""
|
|
32
34
|
self.original_path = original_path
|
|
33
35
|
self.target_path = target_path
|
|
34
36
|
self.import_map = import_map
|
|
35
37
|
self.project_root = project_root
|
|
38
|
+
self.root_file_modules = root_file_modules or set()
|
|
36
39
|
|
|
37
40
|
def visit_Import(self, node: ast.Import) -> Any:
|
|
38
41
|
"""Transform import statements."""
|
|
42
|
+
# Check if any of the imported names are root file modules
|
|
43
|
+
new_names = []
|
|
44
|
+
for alias in node.names:
|
|
45
|
+
module_name = alias.name
|
|
46
|
+
|
|
47
|
+
# If this is a root file module, we need to adjust the import path
|
|
48
|
+
if module_name in self.root_file_modules:
|
|
49
|
+
# Components are in components/tools/, components/resources/, etc.
|
|
50
|
+
# Root files are in the build root, so we need to go up directories
|
|
51
|
+
# to reach them: ../../module_name
|
|
52
|
+
new_names.append(ast.alias(name=f"...{module_name}", asname=alias.asname))
|
|
53
|
+
else:
|
|
54
|
+
new_names.append(alias)
|
|
55
|
+
|
|
56
|
+
# If we made any changes, return a new node
|
|
57
|
+
if any(alias.name != orig_alias.name for alias, orig_alias in zip(new_names, node.names, strict=False)):
|
|
58
|
+
return ast.Import(names=new_names)
|
|
59
|
+
|
|
39
60
|
return node
|
|
40
61
|
|
|
41
62
|
def visit_ImportFrom(self, node: ast.ImportFrom) -> Any:
|
|
@@ -43,6 +64,11 @@ class ImportTransformer(ast.NodeTransformer):
|
|
|
43
64
|
if node.module is None:
|
|
44
65
|
return node
|
|
45
66
|
|
|
67
|
+
# Check if this is importing from a root file module
|
|
68
|
+
if node.level == 0 and node.module in self.root_file_modules:
|
|
69
|
+
# Convert to relative import: from env import API_KEY -> from ...env import API_KEY
|
|
70
|
+
return ast.ImportFrom(module=node.module, names=node.names, level=3)
|
|
71
|
+
|
|
46
72
|
# Handle relative imports
|
|
47
73
|
if node.level > 0:
|
|
48
74
|
# Calculate the source module path
|
|
@@ -98,6 +124,7 @@ def transform_component(
|
|
|
98
124
|
project_path: Path,
|
|
99
125
|
import_map: dict[str, str],
|
|
100
126
|
source_file: Path | None = None,
|
|
127
|
+
root_file_modules: set[str] | None = None,
|
|
101
128
|
) -> str:
|
|
102
129
|
"""Transform a GolfMCP component into a standalone FastMCP component.
|
|
103
130
|
|
|
@@ -107,6 +134,7 @@ def transform_component(
|
|
|
107
134
|
project_path: Path to the project root
|
|
108
135
|
import_map: Mapping of original module paths to generated paths
|
|
109
136
|
source_file: Optional path to source file (for shared files)
|
|
137
|
+
root_file_modules: Set of root file module names (without .py extension)
|
|
110
138
|
|
|
111
139
|
Returns:
|
|
112
140
|
Generated component code
|
|
@@ -126,7 +154,7 @@ def transform_component(
|
|
|
126
154
|
tree = ast.parse(source_code)
|
|
127
155
|
|
|
128
156
|
# Transform imports
|
|
129
|
-
transformer = ImportTransformer(file_path, output_file, import_map, project_path)
|
|
157
|
+
transformer = ImportTransformer(file_path, output_file, import_map, project_path, root_file_modules)
|
|
130
158
|
tree = transformer.visit(tree)
|
|
131
159
|
|
|
132
160
|
# Get all imports and docstring
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
golf/__init__.py,sha256=
|
|
1
|
+
golf/__init__.py,sha256=3fSLgeJpZq4cUgzAH_CdFzXwJEO3NH_VVDv2pQnmwN0,23
|
|
2
2
|
golf/auth/__init__.py,sha256=sYWjWXGR70Ae87znseeBK2YWl8S1-qn_hndKf2xMULk,8173
|
|
3
3
|
golf/auth/api_key.py,sha256=OonqTlG6USJxqK8TlPviJTv7sgYmTVfCxG_JsEjnEM4,2320
|
|
4
4
|
golf/auth/factory.py,sha256=3-il1GbjjZlQfvWUZs-09r61Y_-b5cYEegWF7sY_cUs,13128
|
|
@@ -13,14 +13,14 @@ golf/commands/build.py,sha256=sLq9lSW4naq2vIlBreKI5SGnviQrhBWw13zfOZOKhuM,2293
|
|
|
13
13
|
golf/commands/init.py,sha256=KkAg_3-KxBDFOcZqUHqcPAkDipykFVaLWpQ2tydnVPk,9617
|
|
14
14
|
golf/commands/run.py,sha256=2fdjqTfzQL-dFOqptkl-K2jel8VWpevAx0somcjNsPI,4576
|
|
15
15
|
golf/core/__init__.py,sha256=4bKeskJ2fPaZqkz2xQScSa3phRLLrmrczwSL632jv-o,52
|
|
16
|
-
golf/core/builder.py,sha256=
|
|
16
|
+
golf/core/builder.py,sha256=gbPOPgwUCtwDLok6czcwfPR3Ph8OEOXr2k7W-dk-vfc,80841
|
|
17
17
|
golf/core/builder_auth.py,sha256=f0w9TmxvNjxglcWY8NGULZJ8mwLqtUFFb2QHzgC0xAk,8219
|
|
18
18
|
golf/core/builder_metrics.py,sha256=wrXdE4_XWx7fUXnp61WU7rCBO-aG-4YzCMV6yO0z9Dg,8594
|
|
19
19
|
golf/core/builder_telemetry.py,sha256=86bp7UlMUN6JyQRrZ5EizovP6AJ_q65OANJTeJXDIKc,3421
|
|
20
20
|
golf/core/config.py,sha256=kL440b8i1dF8jdKeYwZZ04HdotX5CAlTyxR1ZyML-Iw,6850
|
|
21
21
|
golf/core/parser.py,sha256=f9WqmLWlFuXQCObl2Qmna9bp_Bo0p0eIlukzwFaBSzo,43373
|
|
22
22
|
golf/core/telemetry.py,sha256=dXoWrgrQpj_HGrl_8TBZmRnuLxFKEn0GSDWQ9qq3ZQM,15686
|
|
23
|
-
golf/core/transformer.py,sha256=
|
|
23
|
+
golf/core/transformer.py,sha256=rcl1X4zo7FGFIcIrcialC57Rs_HzPvf9JApLLuN8xjY,8441
|
|
24
24
|
golf/examples/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
25
25
|
golf/examples/basic/.env.example,sha256=Ktdc2Qta05smPItYHnEHhVxYPkq5JJ7i2aI5pOyyQx4,162
|
|
26
26
|
golf/examples/basic/README.md,sha256=p8KMyaNXGZtrbgckW-Thu_5RKXViGiyZ5hHEiJ6Zc-U,3283
|
|
@@ -44,9 +44,9 @@ golf/utilities/__init__.py,sha256=X9iY9yi3agz1GVcn8-qWeOCt8CSSsruHxqPNtiF63TY,53
|
|
|
44
44
|
golf/utilities/context.py,sha256=DGGvhVe---QMhy0wtdWhNp-_WVk1NvAcOFn0uBKBpYo,1579
|
|
45
45
|
golf/utilities/elicitation.py,sha256=MParZZZsY45s70-KXduHa6IvpWXnLW2FCPfrGijMaHs,5223
|
|
46
46
|
golf/utilities/sampling.py,sha256=88nDv-trBE4gZQbcnMjXl3LW6TiIhv5zR_cuEIGjaIM,7233
|
|
47
|
-
golf_mcp-0.2.
|
|
48
|
-
golf_mcp-0.2.
|
|
49
|
-
golf_mcp-0.2.
|
|
50
|
-
golf_mcp-0.2.
|
|
51
|
-
golf_mcp-0.2.
|
|
52
|
-
golf_mcp-0.2.
|
|
47
|
+
golf_mcp-0.2.14.dist-info/licenses/LICENSE,sha256=5_j2f6fTJmvfmUewzElhkpAaXg2grVoxKouOA8ihV6E,11348
|
|
48
|
+
golf_mcp-0.2.14.dist-info/METADATA,sha256=Tz_qKVbNxMorhTH5GIq_G6i2QNuVlDMiN28O1g01VZI,9414
|
|
49
|
+
golf_mcp-0.2.14.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
50
|
+
golf_mcp-0.2.14.dist-info/entry_points.txt,sha256=5y7rHYM8jGpU-nfwdknCm5XsApLulqsnA37MO6BUTYg,43
|
|
51
|
+
golf_mcp-0.2.14.dist-info/top_level.txt,sha256=BQToHcBUufdyhp9ONGMIvPE40jMEtmI20lYaKb4hxOg,5
|
|
52
|
+
golf_mcp-0.2.14.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|