golf-mcp 0.1.19__py3-none-any.whl → 0.2.0__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.

Files changed (123) hide show
  1. golf/__init__.py +9 -1
  2. golf/_endpoints.py +6 -0
  3. golf/_endpoints_fallback.py +10 -0
  4. golf/auth/__init__.py +188 -84
  5. golf/auth/api_key.py +6 -14
  6. golf/auth/factory.py +333 -0
  7. golf/auth/helpers.py +12 -42
  8. golf/auth/providers.py +396 -0
  9. golf/auth/registry.py +256 -0
  10. golf/cli/branding.py +192 -0
  11. golf/cli/main.py +28 -69
  12. golf/commands/__init__.py +2 -0
  13. golf/commands/build.py +4 -7
  14. golf/commands/init.py +30 -53
  15. golf/commands/run.py +50 -20
  16. golf/core/builder.py +356 -412
  17. golf/core/builder_auth.py +63 -144
  18. golf/core/builder_telemetry.py +26 -3
  19. golf/core/config.py +38 -59
  20. golf/core/parser.py +132 -139
  21. golf/core/platform.py +12 -10
  22. golf/core/telemetry.py +11 -19
  23. golf/core/transformer.py +38 -15
  24. golf/examples/__pycache__/__init__.cpython-311.pyc +0 -0
  25. golf/examples/basic/.coverage +0 -0
  26. golf/examples/basic/.env.example +8 -4
  27. golf/examples/basic/README.md +117 -45
  28. golf/examples/basic/__pycache__/auth.cpython-311.pyc +0 -0
  29. golf/examples/basic/auth.py +76 -0
  30. golf/examples/basic/golf.json +2 -5
  31. golf/examples/basic/htmlcov/.gitignore +2 -0
  32. golf/examples/basic/htmlcov/class_index.html +547 -0
  33. golf/examples/basic/htmlcov/coverage_html_cb_6fb7b396.js +733 -0
  34. golf/examples/basic/htmlcov/favicon_32_cb_58284776.png +0 -0
  35. golf/examples/basic/htmlcov/function_index.html +2091 -0
  36. golf/examples/basic/htmlcov/index.html +349 -0
  37. golf/examples/basic/htmlcov/keybd_closed_cb_ce680311.png +0 -0
  38. golf/examples/basic/htmlcov/status.json +1 -0
  39. golf/examples/basic/htmlcov/style_cb_8e611ae1.css +337 -0
  40. golf/examples/basic/htmlcov/z_1c9a91c0e91c8496___init___py.html +323 -0
  41. golf/examples/basic/htmlcov/z_1c9a91c0e91c8496_api_key_py.html +170 -0
  42. golf/examples/basic/htmlcov/z_1c9a91c0e91c8496_factory_py.html +430 -0
  43. golf/examples/basic/htmlcov/z_1c9a91c0e91c8496_helpers_py.html +288 -0
  44. golf/examples/basic/htmlcov/z_1c9a91c0e91c8496_providers_py.html +493 -0
  45. golf/examples/basic/htmlcov/z_1c9a91c0e91c8496_registry_py.html +353 -0
  46. golf/examples/basic/htmlcov/z_3ec3b3f490dc0950___init___py.html +120 -0
  47. golf/examples/basic/htmlcov/z_3ec3b3f490dc0950_instrumentation_py.html +1535 -0
  48. golf/examples/basic/htmlcov/z_4b8b9dd4ccccc5db___init___py.html +98 -0
  49. golf/examples/basic/htmlcov/z_4b8b9dd4ccccc5db_branding_py.html +289 -0
  50. golf/examples/basic/htmlcov/z_4b8b9dd4ccccc5db_main_py.html +476 -0
  51. golf/examples/basic/htmlcov/z_5a6c4e6bcc86fb2f___init___py.html +97 -0
  52. golf/examples/basic/htmlcov/z_6cadab9ec0df475d___init___py.html +102 -0
  53. golf/examples/basic/htmlcov/z_6cadab9ec0df475d_build_py.html +178 -0
  54. golf/examples/basic/htmlcov/z_6cadab9ec0df475d_init_py.html +387 -0
  55. golf/examples/basic/htmlcov/z_6cadab9ec0df475d_run_py.html +222 -0
  56. golf/examples/basic/htmlcov/z_6fcdee0582ba84e4___init___py.html +106 -0
  57. golf/examples/basic/htmlcov/z_6fcdee0582ba84e4__endpoints_fallback_py.html +107 -0
  58. golf/examples/basic/htmlcov/z_7ba499ed22986217___init___py.html +98 -0
  59. golf/examples/basic/htmlcov/z_7ba499ed22986217_builder_auth_py.html +306 -0
  60. golf/examples/basic/htmlcov/z_7ba499ed22986217_builder_metrics_py.html +329 -0
  61. golf/examples/basic/htmlcov/z_7ba499ed22986217_builder_py.html +1471 -0
  62. golf/examples/basic/htmlcov/z_7ba499ed22986217_builder_telemetry_py.html +186 -0
  63. golf/examples/basic/htmlcov/z_7ba499ed22986217_config_py.html +315 -0
  64. golf/examples/basic/htmlcov/z_7ba499ed22986217_parser_py.html +1149 -0
  65. golf/examples/basic/htmlcov/z_7ba499ed22986217_platform_py.html +279 -0
  66. golf/examples/basic/htmlcov/z_7ba499ed22986217_telemetry_py.html +589 -0
  67. golf/examples/basic/htmlcov/z_7ba499ed22986217_transformer_py.html +286 -0
  68. golf/examples/basic/htmlcov/z_7d7da37693a43688___init___py.html +107 -0
  69. golf/examples/basic/htmlcov/z_7d7da37693a43688_collector_py.html +417 -0
  70. golf/examples/basic/htmlcov/z_7d7da37693a43688_registry_py.html +109 -0
  71. golf/examples/basic/htmlcov/z_abe733142b40ad4e___init___py.html +109 -0
  72. golf/examples/basic/htmlcov/z_abe733142b40ad4e_context_py.html +150 -0
  73. golf/examples/basic/htmlcov/z_abe733142b40ad4e_elicitation_py.html +267 -0
  74. golf/examples/basic/htmlcov/z_abe733142b40ad4e_sampling_py.html +318 -0
  75. golf/examples/basic/prompts/__pycache__/welcome.cpython-311.pyc +0 -0
  76. golf/examples/basic/prompts/welcome.py +3 -5
  77. golf/examples/basic/resources/__pycache__/current_time.cpython-311.pyc +0 -0
  78. golf/examples/basic/resources/__pycache__/info.cpython-311.pyc +0 -0
  79. golf/examples/basic/resources/current_time.py +5 -13
  80. golf/examples/basic/resources/weather/__pycache__/common.cpython-311.pyc +0 -0
  81. golf/examples/basic/resources/weather/__pycache__/current.cpython-311.pyc +0 -0
  82. golf/examples/basic/resources/weather/__pycache__/forecast.cpython-311.pyc +0 -0
  83. golf/examples/basic/resources/weather/city.py +46 -0
  84. golf/examples/basic/resources/weather/common.py +4 -11
  85. golf/examples/basic/resources/weather/current.py +5 -5
  86. golf/examples/basic/resources/weather/forecast.py +5 -5
  87. golf/examples/basic/tools/__pycache__/calculator.cpython-311.pyc +0 -0
  88. golf/examples/basic/tools/calculator.py +94 -0
  89. golf/examples/basic/tools/say/__pycache__/hello.cpython-311.pyc +0 -0
  90. golf/examples/basic/tools/say/hello.py +65 -0
  91. golf/metrics/collector.py +100 -19
  92. golf/telemetry/__init__.py +4 -0
  93. golf/telemetry/instrumentation.py +496 -174
  94. golf/utilities/__init__.py +12 -0
  95. golf/utilities/context.py +53 -0
  96. golf/utilities/elicitation.py +170 -0
  97. golf/utilities/sampling.py +221 -0
  98. {golf_mcp-0.1.19.dist-info → golf_mcp-0.2.0.dist-info}/METADATA +56 -110
  99. golf_mcp-0.2.0.dist-info/RECORD +110 -0
  100. golf/auth/oauth.py +0 -861
  101. golf/auth/provider.py +0 -115
  102. golf/examples/api_key/.env +0 -2
  103. golf/examples/api_key/.env.example +0 -1
  104. golf/examples/api_key/README.md +0 -84
  105. golf/examples/api_key/golf.json +0 -8
  106. golf/examples/api_key/pre_build.py +0 -11
  107. golf/examples/api_key/tools/issues/create.py +0 -93
  108. golf/examples/api_key/tools/issues/list.py +0 -92
  109. golf/examples/api_key/tools/repos/list.py +0 -111
  110. golf/examples/api_key/tools/search/code.py +0 -106
  111. golf/examples/api_key/tools/users/get.py +0 -82
  112. golf/examples/basic/.env +0 -5
  113. golf/examples/basic/pre_build.py +0 -28
  114. golf/examples/basic/tools/github_user.py +0 -65
  115. golf/examples/basic/tools/hello.py +0 -34
  116. golf/examples/basic/tools/payments/charge.py +0 -70
  117. golf/examples/basic/tools/payments/common.py +0 -36
  118. golf/examples/basic/tools/payments/refund.py +0 -61
  119. golf_mcp-0.1.19.dist-info/RECORD +0 -60
  120. {golf_mcp-0.1.19.dist-info → golf_mcp-0.2.0.dist-info}/WHEEL +0 -0
  121. {golf_mcp-0.1.19.dist-info → golf_mcp-0.2.0.dist-info}/entry_points.txt +0 -0
  122. {golf_mcp-0.1.19.dist-info → golf_mcp-0.2.0.dist-info}/licenses/LICENSE +0 -0
  123. {golf_mcp-0.1.19.dist-info → golf_mcp-0.2.0.dist-info}/top_level.txt +0 -0
golf/core/transformer.py CHANGED
@@ -51,35 +51,62 @@ class ImportTransformer(ast.NodeTransformer):
51
51
  source_dir = source_dir.parent
52
52
 
53
53
  if node.module:
54
+ # Handle imports like `from .helpers import utils`
54
55
  source_module = source_dir / node.module.replace(".", "/")
55
56
  else:
57
+ # Handle imports like `from . import something`
56
58
  source_module = source_dir
57
59
 
58
- # Check if this is a common module import
59
- source_str = str(source_module.relative_to(self.project_root))
60
- if source_str in self.import_map:
61
- # Replace with absolute import
62
- new_module = self.import_map[source_str]
63
- return ast.ImportFrom(module=new_module, names=node.names, level=0)
60
+ try:
61
+ # Check if this is a shared module import
62
+ source_str = str(source_module.relative_to(self.project_root))
63
+
64
+ # First, try direct module path match (e.g., "tools/weather/helpers")
65
+ if source_str in self.import_map:
66
+ new_module = self.import_map[source_str]
67
+ return ast.ImportFrom(module=new_module, names=node.names, level=0)
68
+
69
+ # If direct match fails, try directory-based matching
70
+ # This handles cases like `from . import common` where the import_map
71
+ # has "tools/weather/common" but we're looking for "tools/weather"
72
+ source_dir_str = str(source_dir.relative_to(self.project_root))
73
+ if source_dir_str in self.import_map:
74
+ new_module = self.import_map[source_dir_str]
75
+ if node.module:
76
+ new_module = f"{new_module}.{node.module}"
77
+ return ast.ImportFrom(module=new_module, names=node.names, level=0)
78
+
79
+ # Check for specific module imports within the directory
80
+ for import_path, mapped_path in self.import_map.items():
81
+ # Handle cases where we import a specific module from a directory
82
+ # e.g., `from .common import something` should match "tools/weather/common"
83
+ if import_path.startswith(source_dir_str + "/") and node.module:
84
+ module_name = import_path.replace(source_dir_str + "/", "")
85
+ if module_name == node.module:
86
+ return ast.ImportFrom(module=mapped_path, names=node.names, level=0)
87
+
88
+ except ValueError:
89
+ # source_module is not relative to project_root, leave import unchanged
90
+ pass
64
91
 
65
92
  return node
66
93
 
67
94
 
68
95
  def transform_component(
69
- component: ParsedComponent,
96
+ component: ParsedComponent | None,
70
97
  output_file: Path,
71
98
  project_path: Path,
72
99
  import_map: dict[str, str],
73
- source_file: Path = None,
100
+ source_file: Path | None = None,
74
101
  ) -> str:
75
102
  """Transform a GolfMCP component into a standalone FastMCP component.
76
103
 
77
104
  Args:
78
- component: Parsed component to transform
105
+ component: Parsed component to transform (optional if source_file provided)
79
106
  output_file: Path to write the transformed component to
80
107
  project_path: Path to the project root
81
108
  import_map: Mapping of original module paths to generated paths
82
- source_file: Optional path to source file (for common.py files)
109
+ source_file: Optional path to source file (for shared files)
83
110
 
84
111
  Returns:
85
112
  Generated component code
@@ -144,11 +171,7 @@ def transform_component(
144
171
  continue
145
172
 
146
173
  # Skip the original docstring
147
- if (
148
- isinstance(node, ast.Expr)
149
- and isinstance(node.value, ast.Constant)
150
- and isinstance(node.value.value, str)
151
- ):
174
+ if isinstance(node, ast.Expr) and isinstance(node.value, ast.Constant) and isinstance(node.value.value, str):
152
175
  continue
153
176
 
154
177
  remaining_nodes.append(node)
Binary file
@@ -1,4 +1,8 @@
1
- GITHUB_CLIENT_ID="default-client-id"
2
- GITHUB_CLIENT_SECRET="default-secret"
3
- JWT_SECRET="example-jwt-secret-for-development-only"
4
- #GOLF_API_KEY=<your-api-key>
1
+ # Golf MCP Server Environment Variables
2
+
3
+ # Golf platform integration
4
+ GOLF_API_KEY="your-golf-api-key"
5
+ GOLF_SERVER_ID="your-server-id"
6
+
7
+ # Development tokens are configured in auth.py for this example
8
+ # Additional environment variables can be added as needed
@@ -1,61 +1,133 @@
1
- # GolfMCP Project Boilerplate
1
+ # Golf MCP Project Template (Basic)
2
2
 
3
- This directory serves as a starting template for new GolfMCP projects. Initialize a project using the `golf init <your-project-name>` command.
4
- ## About GolfMCP
3
+ This is a basic template for creating MCP servers with Golf. It includes development authentication for easy testing. Use `golf init <project-name>` to bootstrap new projects from this template.
5
4
 
6
- GolfMCP is a Python framework designed to build MCP servers with minimal boilerplate. It allows you to define tools, resources, and prompts as simple Python files. These components are then automatically discovered and compiled into a runnable [FastMCP](https://github.com/fastmcp/fastmcp) server.
5
+ ## About Golf
7
6
 
8
- ## Getting Started (After `golf init`)
7
+ Golf is a Python framework for building MCP (Model Context Protocol) servers with minimal boilerplate. Define your server's capabilities as simple Python files, and Golf automatically discovers and compiles them into a runnable FastMCP server.
9
8
 
10
- Once you've initialized your new project from this boilerplate:
9
+ ## Getting Started
11
10
 
12
- 1. **Navigate to your project directory:**
13
- ```bash
14
- cd your-project-name
15
- ```
11
+ After initializing your project:
16
12
 
17
- 2. **Start the development server:**
18
- ```bash
19
- golf build dev # For a development build
20
- # or
21
- golf build prod # For a production build
22
-
23
- golf run
24
- ```
13
+ 1. **Navigate to your project directory:**
14
+ ```bash
15
+ cd your-project-name
16
+ ```
25
17
 
26
- ## Project Structure
27
-
28
- Your initialized GolfMCP project will typically have the following structure:
29
-
30
- - `tools/`: Directory for your tool implementations (Python files defining functions an LLM can call).
31
- - `resources/`: Directory for your resource implementations (Python files defining data an LLM can read).
32
- - `prompts/`: Directory for your prompt templates (Python files defining reusable conversation structures).
33
- - `golf.json`: The main configuration file for your project, including settings like the server name, port, and transport.
34
- - `pre_build.py`: (Optional) A Python script that can be used to run custom logic before the build process begins, such as configuring authentication.
35
- - `.env`: File to store environment-specific variables (e.g., API keys). This is created during `golf init`.
36
-
37
- ## Adding New Components
18
+ 2. **Configure authentication (optional):**
19
+ This template includes development authentication in `auth.py` with sample tokens. Edit the file to set up JWT, OAuth, or API key authentication for production use.
38
20
 
39
- To add new functionalities:
21
+ 3. **Build and run your server:**
22
+ ```bash
23
+ golf build dev # Development build
24
+ golf run # Start the server
25
+ ```
40
26
 
41
- - **Tools**: Create a new `.py` file in the `tools/` directory.
42
- - **Resources**: Create a new `.py` file in the `resources/` directory.
43
- - **Prompts**: Create a new `.py` file in the `prompts/` directory.
44
-
45
- Each Python file should generally define a single component. A module-level docstring in the file will be used as the description for the component. See the example files (e.g., `tools/hello.py`, `resources/info.py`) provided in this boilerplate for reference.
27
+ ## Project Structure
46
28
 
47
- For shared functionality within a component subdirectory (e.g., `tools/payments/common.py`), you can use a `common.py` file.
29
+ ```
30
+ your-project/
31
+ ├── tools/ # Tool implementations (functions LLMs can call)
32
+ ├── resources/ # Resource implementations (data LLMs can read)
33
+ ├── prompts/ # Prompt templates (conversation structures)
34
+ ├── golf.json # Server configuration
35
+ └── auth.py # Authentication setup
36
+ ```
37
+
38
+ ## Adding Components
39
+
40
+ ### Tools
41
+ Create `.py` files in `tools/` directory. Each file should export a single async function:
42
+
43
+ ```python
44
+ # tools/calculator.py
45
+ async def add(a: int, b: int) -> int:
46
+ """Add two numbers together."""
47
+ return a + b
48
+
49
+ export = add
50
+ ```
51
+
52
+ ### Resources
53
+ Create `.py` files in `resources/` directory with a `resource_uri` and export function:
54
+
55
+ ```python
56
+ # resources/status.py
57
+ resource_uri = "status://server"
58
+
59
+ async def status() -> dict:
60
+ """Get server status information."""
61
+ return {"status": "running", "timestamp": "2024-01-01T00:00:00Z"}
62
+
63
+ export = status
64
+ ```
65
+
66
+ ### Prompts
67
+ Create `.py` files in `prompts/` directory that return message lists:
68
+
69
+ ```python
70
+ # prompts/assistant.py
71
+ async def assistant() -> list[dict]:
72
+ """System prompt for a helpful assistant."""
73
+ return [
74
+ {
75
+ "role": "system",
76
+ "content": "You are a helpful assistant for {{project_name}}."
77
+ }
78
+ ]
79
+
80
+ export = assistant
81
+ ```
82
+
83
+ ## Authentication Examples
84
+
85
+ ### No Authentication (Default)
86
+ Leave `auth.py` empty or remove it entirely.
87
+
88
+ ### API Key Authentication
89
+ ```python
90
+ # auth.py
91
+ from golf.auth import configure_api_key
92
+
93
+ configure_api_key(
94
+ header_name="Authorization",
95
+ header_prefix="Bearer ",
96
+ required=True
97
+ )
98
+ ```
99
+
100
+ ### JWT Authentication
101
+ ```python
102
+ # auth.py
103
+ from golf.auth import configure_jwt_auth
104
+
105
+ configure_jwt_auth(
106
+ jwks_uri="https://your-domain.auth0.com/.well-known/jwks.json",
107
+ issuer="https://your-domain.auth0.com/",
108
+ audience="https://your-api.example.com"
109
+ )
110
+ ```
111
+
112
+ ### Development Tokens
113
+ ```python
114
+ # auth.py
115
+ from golf.auth import configure_dev_auth
116
+
117
+ configure_dev_auth(
118
+ tokens={
119
+ "dev-token-123": {
120
+ "client_id": "dev-client",
121
+ "scopes": ["read", "write"]
122
+ }
123
+ }
124
+ )
125
+ ```
48
126
 
49
127
  ## Documentation
50
128
 
51
- For comprehensive details on the GolfMCP framework, including component specifications, advanced configurations, CLI commands, and more, please refer to the official documentation:
52
-
53
- [https://docs.golf.dev](https://docs.golf.dev)
129
+ For comprehensive documentation, visit: [https://docs.golf.dev](https://docs.golf.dev)
54
130
 
55
131
  ---
56
132
 
57
- Happy Building!
58
-
59
- <div align="center">
60
- Made with ❤️ in San Francisco
61
- </div>
133
+ Happy building! 🏌️‍♂️
@@ -0,0 +1,76 @@
1
+ """Authentication configuration for the basic Golf MCP server example.
2
+
3
+ This example shows different authentication options available in Golf 0.2.x:
4
+ - JWT authentication with static keys or JWKS endpoints (production)
5
+ - Static token authentication (development/testing)
6
+ - OAuth Server mode (full OAuth 2.0 server)
7
+ - Remote Authorization Server integration
8
+ """
9
+
10
+ # Example 1: JWT authentication with a static public key
11
+ # from golf.auth import configure_auth, JWTAuthConfig
12
+ #
13
+ # configure_auth(
14
+ # JWTAuthConfig(
15
+ # public_key_env_var="JWT_PUBLIC_KEY", # PEM-encoded public key
16
+ # issuer="https://your-auth-server.com",
17
+ # audience="https://your-golf-server.com",
18
+ # required_scopes=["read:data"],
19
+ # )
20
+ # )
21
+
22
+ # Example 2: JWT authentication with JWKS (recommended for production)
23
+ # from golf.auth import configure_auth, JWTAuthConfig
24
+ #
25
+ # configure_auth(
26
+ # JWTAuthConfig(
27
+ # jwks_uri_env_var="JWKS_URI", # e.g., "https://your-domain.auth0.com/.well-known/jwks.json"
28
+ # issuer_env_var="JWT_ISSUER", # e.g., "https://your-domain.auth0.com/"
29
+ # audience_env_var="JWT_AUDIENCE", # e.g., "https://your-api.example.com"
30
+ # required_scopes=["read:user"],
31
+ # )
32
+ # )
33
+
34
+ # Example 3: OAuth Server mode - Golf acts as full OAuth 2.0 authorization server
35
+ # from golf.auth import configure_auth, OAuthServerConfig
36
+ #
37
+ # configure_auth(
38
+ # OAuthServerConfig(
39
+ # base_url_env_var="OAUTH_BASE_URL", # e.g., "https://auth.example.com"
40
+ # valid_scopes=["read", "write", "admin"], # Scopes clients can request
41
+ # default_scopes=["read"], # Default scopes for new clients
42
+ # required_scopes=["read"], # Scopes required for all requests
43
+ # )
44
+ # )
45
+
46
+ # Example 4: Remote Authorization Server integration
47
+ # from golf.auth import configure_auth, RemoteAuthConfig, JWTAuthConfig
48
+ #
49
+ # configure_auth(
50
+ # RemoteAuthConfig(
51
+ # authorization_servers_env_var="AUTH_SERVERS", # Comma-separated: "https://auth1.com,https://auth2.com"
52
+ # resource_server_url_env_var="RESOURCE_URL", # This server's URL
53
+ # token_verifier_config=JWTAuthConfig(
54
+ # jwks_uri_env_var="JWKS_URI"
55
+ # ),
56
+ # )
57
+ # )
58
+
59
+ # Example 5: Static token authentication for development (NOT for production)
60
+ from golf.auth import configure_auth, StaticTokenConfig
61
+
62
+ configure_auth(
63
+ StaticTokenConfig(
64
+ tokens={
65
+ "dev-token-123": {
66
+ "client_id": "dev-client",
67
+ "scopes": ["read", "write"],
68
+ },
69
+ "admin-token-456": {
70
+ "client_id": "admin-client",
71
+ "scopes": ["read", "write", "admin"],
72
+ },
73
+ },
74
+ required_scopes=["read"],
75
+ )
76
+ )
@@ -1,8 +1,5 @@
1
1
  {
2
- "name": "{{project_name}}",
2
+ "name": "basic-server-example",
3
3
  "description": "A GolfMCP project",
4
- "host": "127.0.0.1",
5
- "port": 3000,
6
- "transport": "sse",
7
- "opentelemetry_enabled": false
4
+ "transport": "http"
8
5
  }
@@ -0,0 +1,2 @@
1
+ # Created by coverage.py
2
+ *