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 CHANGED
@@ -1 +1 @@
1
- __version__ = "0.2.12"
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
- transform_component(tool, output_file, self.project_path, self.import_map)
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
- transform_component(resource, output_file, self.project_path, self.import_map)
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
- transform_component(prompt, output_file, self.project_path, self.import_map)
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,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: golf-mcp
3
- Version: 0.2.12
3
+ Version: 0.2.14
4
4
  Summary: Framework for building MCP servers
5
5
  Author-email: Antoni Gmitruk <antoni@golf.dev>
6
6
  License-Expression: Apache-2.0
@@ -1,4 +1,4 @@
1
- golf/__init__.py,sha256=X4KG3FscE5AhbGbcdDDgdDC550CVpxNMwdNLcx6EQ7M,23
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=ynmzTF1IsF5OTZl0dr-1Mzd8iEVNB-Oxa6RBWBu3DRs,76372
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=iTDNFqdVeOjzl-acdjp8ZaTXss8Eptqu5cs4qLWt9SU,6914
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.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,,
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,,