golf-mcp 0.1.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 (41) hide show
  1. golf/__init__.py +1 -0
  2. golf/auth/__init__.py +109 -0
  3. golf/auth/helpers.py +56 -0
  4. golf/auth/oauth.py +798 -0
  5. golf/auth/provider.py +110 -0
  6. golf/cli/__init__.py +1 -0
  7. golf/cli/main.py +223 -0
  8. golf/commands/__init__.py +3 -0
  9. golf/commands/build.py +78 -0
  10. golf/commands/init.py +197 -0
  11. golf/commands/run.py +68 -0
  12. golf/core/__init__.py +1 -0
  13. golf/core/builder.py +1169 -0
  14. golf/core/builder_auth.py +157 -0
  15. golf/core/builder_telemetry.py +208 -0
  16. golf/core/config.py +205 -0
  17. golf/core/parser.py +509 -0
  18. golf/core/transformer.py +168 -0
  19. golf/examples/__init__.py +1 -0
  20. golf/examples/basic/.env +3 -0
  21. golf/examples/basic/.env.example +3 -0
  22. golf/examples/basic/README.md +117 -0
  23. golf/examples/basic/golf.json +9 -0
  24. golf/examples/basic/pre_build.py +28 -0
  25. golf/examples/basic/prompts/welcome.py +30 -0
  26. golf/examples/basic/resources/current_time.py +41 -0
  27. golf/examples/basic/resources/info.py +27 -0
  28. golf/examples/basic/resources/weather/common.py +48 -0
  29. golf/examples/basic/resources/weather/current.py +32 -0
  30. golf/examples/basic/resources/weather/forecast.py +32 -0
  31. golf/examples/basic/tools/github_user.py +67 -0
  32. golf/examples/basic/tools/hello.py +29 -0
  33. golf/examples/basic/tools/payments/charge.py +50 -0
  34. golf/examples/basic/tools/payments/common.py +34 -0
  35. golf/examples/basic/tools/payments/refund.py +50 -0
  36. golf_mcp-0.1.0.dist-info/METADATA +78 -0
  37. golf_mcp-0.1.0.dist-info/RECORD +41 -0
  38. golf_mcp-0.1.0.dist-info/WHEEL +5 -0
  39. golf_mcp-0.1.0.dist-info/entry_points.txt +2 -0
  40. golf_mcp-0.1.0.dist-info/licenses/LICENSE +201 -0
  41. golf_mcp-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,117 @@
1
+ # {{project_name}}
2
+
3
+ A GolfMCP project that provides MCP-compatible tools, resources, and prompts.
4
+
5
+ ## Getting Started
6
+
7
+ This project is built with [GolfMCP](https://github.com/yourusername/golfmcp), a Python framework for building MCP servers with zero boilerplate.
8
+
9
+ To start the development server with hot reload:
10
+
11
+ ```bash
12
+ golf dev
13
+ ```
14
+
15
+ This will watch for file changes and automatically reload the server.
16
+
17
+ ## Project Structure
18
+
19
+ - `tools/` - Tool implementations (functions an LLM can call)
20
+ - `resources/` - Resource implementations (data an LLM can read)
21
+ - `prompts/` - Prompt templates (conversations an LLM can use)
22
+ - `golf.json` - Configuration file with settings like telemetry and transport
23
+
24
+ ## Adding New Components
25
+
26
+ ### Tools
27
+
28
+ To add a new tool, create a Python file in the `tools/` directory:
29
+
30
+ ```python
31
+ # tools/my_tool.py
32
+ from pydantic import BaseModel
33
+ from fastmcp import Context
34
+
35
+ class Input(BaseModel):
36
+ param1: str
37
+ param2: int = 42
38
+
39
+ class Output(BaseModel):
40
+ result: str
41
+
42
+ async def run(input: Input, ctx: Context) -> Output:
43
+ """Description of what my tool does."""
44
+ await ctx.info(f"Processing {input.param1}...")
45
+ return MyOutput(result=f"Processed {input.param1} with {input.param2}")
46
+ ```
47
+
48
+ ### Resources
49
+
50
+ To add a new resource, create a Python file in the `resources/` directory:
51
+
52
+ ```python
53
+ # resources/my_data.py
54
+ resource_uri = "data://my-data"
55
+
56
+ async def run() -> dict:
57
+ """Description of the resource."""
58
+ return {
59
+ "title": "My Data",
60
+ "content": "Some valuable information"
61
+ }
62
+ ```
63
+
64
+ ### Sharing Functionality with common.py
65
+
66
+ For directories with multiple related components (like `tools/payments/` or `resources/weather/`),
67
+ use a `common.py` file to share functionality:
68
+
69
+ ```python
70
+ # tools/payments/common.py
71
+ class PaymentClient:
72
+ """Shared payment client implementation."""
73
+ # Implementation details...
74
+
75
+ # Create a shared client instance
76
+ payment_client = PaymentClient()
77
+ ```
78
+
79
+ Then import and use the shared functionality in your components:
80
+
81
+ ```python
82
+ # tools/payments/charge.py
83
+ from .common import payment_client
84
+
85
+ async def run(input):
86
+ result = await payment_client.create_charge(...)
87
+ # Rest of implementation...
88
+ ```
89
+
90
+ This pattern helps organize shared code and makes it easier to build and maintain your project.
91
+
92
+ ## Telemetry
93
+
94
+ This project includes OpenTelemetry integration for tracing server requests:
95
+
96
+ ```json
97
+ // golf.json
98
+ {
99
+ "telemetry": true,
100
+ "telemetry_exporter": "console" // or "otlp_http"
101
+ }
102
+ ```
103
+
104
+ You can configure it with environment variables:
105
+ - `OTEL_SERVICE_NAME`: Set service name (defaults to app name)
106
+ - `OTEL_TRACES_EXPORTER`: Exporter type ("console" or "otlp_http")
107
+ - `OTEL_EXPORTER_OTLP_ENDPOINT`: OTLP exporter endpoint URL
108
+
109
+ ## Deployment
110
+
111
+ To build the project for deployment:
112
+
113
+ ```bash
114
+ golf build
115
+ ```
116
+
117
+ This creates a standalone FastMCP application in the `dist/` directory.
@@ -0,0 +1,9 @@
1
+ {
2
+ "name": "{{project_name}}",
3
+ "description": "A GolfMCP project",
4
+ "host": "127.0.0.1",
5
+ "port": 3000,
6
+ "transport": "sse",
7
+ "opentelemetry_enabled": false,
8
+ "opentelemetry_default_exporter": "console"
9
+ }
@@ -0,0 +1,28 @@
1
+ """Pre-build configuration for the basic example.
2
+
3
+ This file is executed before the build process starts.
4
+ It configures GitHub OAuth authentication for the example.
5
+ """
6
+
7
+ from golf.auth import ProviderConfig, configure_auth
8
+
9
+ # Create GitHub OAuth provider configuration
10
+ github_provider = ProviderConfig(
11
+ provider="github",
12
+ client_id_env_var="GITHUB_CLIENT_ID",
13
+ client_secret_env_var="GITHUB_CLIENT_SECRET",
14
+ jwt_secret_env_var="JWT_SECRET",
15
+ authorize_url="https://github.com/login/oauth/authorize",
16
+ token_url="https://github.com/login/oauth/access_token",
17
+ userinfo_url="https://api.github.com/user",
18
+ scopes=["read:user", "user:email"],
19
+ issuer_url="http://127.0.0.1:3000", # This should be your Golf server's accessible URL
20
+ callback_path="/auth/callback", # Golf's callback path
21
+ token_expiration=3600 # 1 hour
22
+ )
23
+
24
+ # Configure authentication with the provider
25
+ configure_auth(
26
+ provider=github_provider,
27
+ required_scopes=["read:user"], # Require read:user scope for protected endpoints
28
+ )
@@ -0,0 +1,30 @@
1
+ """Welcome prompt for new users."""
2
+
3
+ from typing import List, Dict
4
+
5
+
6
+ async def welcome() -> List[Dict]:
7
+ """Provide a welcome prompt for new users.
8
+
9
+ This is a simple example prompt that demonstrates how to define
10
+ a prompt template in GolfMCP.
11
+ """
12
+ return [
13
+ {
14
+ "role": "system",
15
+ "content": (
16
+ "You are an assistant for the {{project_name}} application. "
17
+ "You help users understand how to interact with this system and its capabilities."
18
+ )
19
+ },
20
+ {
21
+ "role": "user",
22
+ "content": (
23
+ "Welcome to {{project_name}}! This is a project built with GolfMCP. "
24
+ "How can I get started?"
25
+ )
26
+ },
27
+ ]
28
+
29
+ # Designate the entry point function
30
+ export = welcome
@@ -0,0 +1,41 @@
1
+ """Current time resource example."""
2
+
3
+ from datetime import datetime
4
+ from typing import Dict, Any
5
+
6
+ # The URI that clients will use to access this resource
7
+ resource_uri = "system://time/{format}"
8
+
9
+
10
+ async def current_time(format: str = "full") -> Dict[str, Any]:
11
+ """Provide the current time in various formats.
12
+
13
+ This is a simple resource example that accepts a format parameter.
14
+
15
+ Args:
16
+ format: The format to return ('full', 'iso', 'unix' or 'rfc')
17
+ """
18
+ now = datetime.now()
19
+
20
+ # Prepare all possible formats
21
+ all_formats = {
22
+ "iso": now.isoformat(),
23
+ "rfc": now.strftime("%a, %d %b %Y %H:%M:%S %z"),
24
+ "unix": int(now.timestamp()),
25
+ "formatted": {
26
+ "date": now.strftime("%Y-%m-%d"),
27
+ "time": now.strftime("%H:%M:%S"),
28
+ "timezone": now.astimezone().tzname()
29
+ }
30
+ }
31
+
32
+ # Return specific format or all formats
33
+ if format == "full":
34
+ return all_formats
35
+ elif format in all_formats:
36
+ return {format: all_formats[format]}
37
+ else:
38
+ return {"error": f"Unknown format: {format}"}
39
+
40
+ # Designate the entry point function
41
+ export = current_time
@@ -0,0 +1,27 @@
1
+ """Example resource that provides information about the project."""
2
+
3
+ import platform
4
+ from datetime import datetime
5
+ from typing import Dict, Any
6
+
7
+ resource_uri = "info://system"
8
+
9
+
10
+ async def info() -> Dict[str, Any]:
11
+ """Provide system information as a resource.
12
+
13
+ This is a simple example resource that demonstrates how to expose
14
+ data to an LLM client through the MCP protocol.
15
+ """
16
+ return {
17
+ "project": "{{project_name}}",
18
+ "timestamp": datetime.now().isoformat(),
19
+ "platform": {
20
+ "system": platform.system(),
21
+ "python_version": platform.python_version(),
22
+ "architecture": platform.machine(),
23
+ }
24
+ }
25
+
26
+ # Designate the entry point function
27
+ export = info
@@ -0,0 +1,48 @@
1
+ """Weather shared functionality.
2
+
3
+ This common.py file demonstrates the recommended pattern for
4
+ sharing functionality across multiple resources in a directory.
5
+ """
6
+
7
+ import os
8
+
9
+ # Read configuration from environment variables
10
+ WEATHER_API_KEY = os.environ.get("WEATHER_API_KEY", "mock_key")
11
+ WEATHER_API_URL = os.environ.get("WEATHER_API_URL", "https://api.example.com/weather")
12
+ TEMPERATURE_UNIT = os.environ.get("WEATHER_TEMP_UNIT", "fahrenheit")
13
+
14
+
15
+ class WeatherApiClient:
16
+ """Mock weather API client."""
17
+
18
+ def __init__(self, api_key: str = WEATHER_API_KEY, api_url: str = WEATHER_API_URL):
19
+ self.api_key = api_key
20
+ self.api_url = api_url
21
+ self.unit = TEMPERATURE_UNIT
22
+
23
+ async def get_forecast(self, city: str, days: int = 3):
24
+ """Get weather forecast for a city (mock implementation)."""
25
+ # This would make an API call in a real implementation
26
+ print(f"Would call {self.api_url}/forecast/{city} with API key {self.api_key[:4]}...")
27
+ return {
28
+ "city": city,
29
+ "unit": self.unit,
30
+ "forecast": [{"day": i, "temp": 70 + i} for i in range(days)]
31
+ }
32
+
33
+ async def get_current(self, city: str):
34
+ """Get current weather for a city (mock implementation)."""
35
+ print(f"Would call {self.api_url}/current/{city} with API key {self.api_key[:4]}...")
36
+ return {
37
+ "city": city,
38
+ "unit": self.unit,
39
+ "temperature": 72,
40
+ "conditions": "Sunny"
41
+ }
42
+
43
+
44
+ # Create a shared weather client that can be imported by all resources in this directory
45
+ weather_client = WeatherApiClient()
46
+
47
+ # This could also define shared models or other utilities
48
+ # that would be common across weather-related resources
@@ -0,0 +1,32 @@
1
+ """Current weather resource example."""
2
+
3
+ from datetime import datetime
4
+ from typing import Dict, Any
5
+ from .common import weather_client
6
+
7
+ # The URI that clients will use to access this resource
8
+ resource_uri = "weather://current/{city}"
9
+
10
+
11
+ async def current_weather(city: str) -> Dict[str, Any]:
12
+ """Provide current weather for the specified city.
13
+
14
+ This example demonstrates:
15
+ 1. Nested resource organization (resources/weather/current.py)
16
+ 2. Dynamic URI parameters (city in this case)
17
+ 3. Using shared client from the common.py file
18
+ """
19
+ # Use the shared weather client from common.py
20
+ weather_data = await weather_client.get_current(city)
21
+
22
+ # Add some additional data
23
+ weather_data.update({
24
+ "time": datetime.now().isoformat(),
25
+ "source": "GolfMCP Weather API",
26
+ "unit": "fahrenheit"
27
+ })
28
+
29
+ return weather_data
30
+
31
+ # Designate the entry point function
32
+ export = current_weather
@@ -0,0 +1,32 @@
1
+ """Weather forecast resource example demonstrating nested resources."""
2
+
3
+ from datetime import datetime
4
+ from typing import Dict, Any
5
+ from .common import weather_client
6
+
7
+ # The URI that clients will use to access this resource
8
+ resource_uri = "weather://forecast/{city}"
9
+
10
+
11
+ async def forecast_weather(city: str) -> Dict[str, Any]:
12
+ """Provide a weather forecast for the specified city.
13
+
14
+ This example demonstrates:
15
+ 1. Nested resource organization (resources/weather/forecast.py)
16
+ 2. Dynamic URI parameters (city in this case)
17
+ 3. Using shared client from the common.py file
18
+ """
19
+ # Use the shared weather client from common.py
20
+ forecast_data = await weather_client.get_forecast(city, days=5)
21
+
22
+ # Add some additional data
23
+ forecast_data.update({
24
+ "updated_at": datetime.now().isoformat(),
25
+ "source": "GolfMCP Weather API",
26
+ "unit": "fahrenheit"
27
+ })
28
+
29
+ return forecast_data
30
+
31
+ # Designate the entry point function
32
+ export = forecast_weather
@@ -0,0 +1,67 @@
1
+ """Tool for fetching GitHub user information."""
2
+
3
+ from typing import Optional
4
+ from pydantic import BaseModel
5
+ import httpx
6
+ from golf.auth import get_provider_token
7
+
8
+
9
+ class GitHubUserResponse(BaseModel):
10
+ """Response model for GitHub user information."""
11
+
12
+ login: str
13
+ id: int
14
+ name: Optional[str] = None
15
+ email: Optional[str] = None
16
+ avatar_url: Optional[str] = None
17
+ location: Optional[str] = None
18
+ bio: Optional[str] = None
19
+ public_repos: int = 0
20
+ followers: int = 0
21
+ following: int = 0
22
+ message: Optional[str] = None
23
+
24
+
25
+ async def get_github_user() -> GitHubUserResponse:
26
+ """Fetch authenticated user's GitHub profile information."""
27
+ try:
28
+ # Get GitHub token using our abstraction
29
+ github_token = get_provider_token()
30
+
31
+ if not github_token:
32
+ return GitHubUserResponse(
33
+ login="anonymous",
34
+ id=0,
35
+ message="Not authenticated. Please login first."
36
+ )
37
+
38
+ # Call GitHub API to get user info
39
+ async with httpx.AsyncClient() as client:
40
+ response = await client.get(
41
+ "https://api.github.com/user",
42
+ headers={
43
+ "Authorization": f"Bearer {github_token}",
44
+ "Accept": "application/vnd.github.v3+json"
45
+ }
46
+ )
47
+
48
+ if response.status_code == 200:
49
+ data = response.json()
50
+ return GitHubUserResponse(**data)
51
+ else:
52
+ return GitHubUserResponse(
53
+ login="error",
54
+ id=0,
55
+ message=f"GitHub API error: {response.status_code} - {response.text[:100]}"
56
+ )
57
+
58
+ except Exception as e:
59
+ return GitHubUserResponse(
60
+ login="error",
61
+ id=0,
62
+ message=f"Error fetching GitHub data: {str(e)}"
63
+ )
64
+
65
+
66
+ # Export the tool
67
+ export = get_github_user
@@ -0,0 +1,29 @@
1
+ """Hello World tool {{project_name}}."""
2
+
3
+ from pydantic import BaseModel
4
+
5
+
6
+ class Output(BaseModel):
7
+ """Response from the hello tool."""
8
+
9
+ message: str
10
+
11
+
12
+ async def hello(
13
+ name: str = "World",
14
+ greeting: str = "Hello"
15
+ ) -> Output:
16
+ """Say hello to the given name.
17
+
18
+ This is a simple example tool that demonstrates the basic structure
19
+ of a tool implementation in GolfMCP.
20
+ """
21
+ # The framework will add a context object automatically
22
+ # You can log using regular print during development
23
+ print(f"{greeting} {name}...")
24
+
25
+ # Create and return the response
26
+ return Output(message=f"{greeting}, {name}!")
27
+
28
+ # Designate the entry point function
29
+ export = hello
@@ -0,0 +1,50 @@
1
+ """Charge payment tool"""
2
+
3
+ from pydantic import BaseModel
4
+ from .common import payment_client
5
+
6
+
7
+ class Output(BaseModel):
8
+ """Response from the charge payment tool."""
9
+
10
+ success: bool
11
+ charge_id: str
12
+ message: str
13
+
14
+
15
+ async def charge(
16
+ amount: float,
17
+ card_token: str,
18
+ description: str = ""
19
+ ) -> Output:
20
+ """Process a payment charge.
21
+
22
+ This example demonstrates nested directory organization where related tools
23
+ are grouped in subdirectories (tools/payments/charge.py).
24
+
25
+ The resulting tool ID will be: charge-payments
26
+
27
+ Args:
28
+ amount: Amount to charge in USD
29
+ card_token: Tokenized payment card
30
+ description: Optional payment description
31
+ """
32
+ # The framework will add a context object automatically
33
+ # You can log using regular print during development
34
+ print(f"Processing charge for ${amount:.2f}...")
35
+
36
+ # Use the shared payment client from common.py
37
+ charge_result = await payment_client.create_charge(
38
+ amount=amount,
39
+ token=card_token,
40
+ description=description
41
+ )
42
+
43
+ # Create and return the response
44
+ return Output(
45
+ success=True,
46
+ charge_id=charge_result["id"],
47
+ message=f"Successfully charged ${amount:.2f}"
48
+ )
49
+
50
+ export = charge
@@ -0,0 +1,34 @@
1
+ """Payments shared functionality.
2
+
3
+ This common.py file demonstrates the recommended pattern for
4
+ sharing functionality across multiple tools in a directory.
5
+ """
6
+
7
+ import os
8
+
9
+ # Read configuration from environment variables
10
+ PAYMENT_API_KEY = os.environ.get("PAYMENT_API_KEY", "mock_key")
11
+ PAYMENT_API_URL = os.environ.get("PAYMENT_API_URL", "https://api.example.com/payments")
12
+
13
+
14
+ class PaymentClient:
15
+ """Mock payment provider client."""
16
+
17
+ def __init__(self, api_key: str = PAYMENT_API_KEY, api_url: str = PAYMENT_API_URL):
18
+ self.api_key = api_key
19
+ self.api_url = api_url
20
+
21
+ async def create_charge(self, amount: float, token: str, **kwargs):
22
+ """Create a charge (mock implementation)."""
23
+ # In a real implementation, this would make an API request
24
+ # using the configured API key and URL
25
+ return {"id": f"ch_{int(amount * 100)}_{hash(token) % 10000:04d}"}
26
+
27
+ async def create_refund(self, charge_id: str, amount: float, **kwargs):
28
+ """Create a refund (mock implementation)."""
29
+ # In a real implementation, this would make an API request
30
+ return {"id": f"ref_{charge_id}_{int(amount * 100)}"}
31
+
32
+
33
+ # Create a shared payment client that can be imported by all tools in this directory
34
+ payment_client = PaymentClient()
@@ -0,0 +1,50 @@
1
+ """Refund payment tool"""
2
+
3
+ from pydantic import BaseModel
4
+ from .common import payment_client
5
+
6
+
7
+ class Output(BaseModel):
8
+ """Response from the refund payment tool."""
9
+
10
+ success: bool
11
+ refund_id: str
12
+ message: str
13
+
14
+
15
+ async def refund(
16
+ charge_id: str,
17
+ amount: float,
18
+ reason: str = "customer_request"
19
+ ) -> Output:
20
+ """Process a payment refund.
21
+
22
+ This example demonstrates nested directory organization where related tools
23
+ are grouped in subdirectories (tools/payments/refund.py).
24
+
25
+ The resulting tool ID will be: refund-payments
26
+
27
+ Args:
28
+ charge_id: Original charge ID to refund
29
+ amount: Amount to refund in USD
30
+ reason: Reason for refund
31
+ """
32
+ # The framework will add a context object automatically
33
+ # You can log using regular print during development
34
+ print(f"Processing refund of ${amount:.2f} for charge {charge_id}...")
35
+
36
+ # Use the shared payment client from common.py
37
+ refund_result = await payment_client.create_refund(
38
+ charge_id=charge_id,
39
+ amount=amount,
40
+ reason=reason
41
+ )
42
+
43
+ # Create and return the response
44
+ return Output(
45
+ success=True,
46
+ refund_id=refund_result["id"],
47
+ message=f"Successfully refunded ${amount:.2f}"
48
+ )
49
+
50
+ export = refund
@@ -0,0 +1,78 @@
1
+ Metadata-Version: 2.4
2
+ Name: golf-mcp
3
+ Version: 0.1.0
4
+ Summary: Framework for building MCP servers
5
+ Author-email: Antoni Gmitruk <antoni@golf.dev>
6
+ License-Expression: Apache-2.0
7
+ Project-URL: Homepage, https://golf.dev
8
+ Project-URL: Repository, https://github.com/golf-mcp/golf
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: Operating System :: OS Independent
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
14
+ Classifier: Programming Language :: Python :: 3.8
15
+ Classifier: Programming Language :: Python :: 3.9
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Requires-Python: >=3.8
20
+ Description-Content-Type: text/markdown
21
+ License-File: LICENSE
22
+ Requires-Dist: typer[all]>=0.15.4
23
+ Requires-Dist: rich>=14.0.0
24
+ Requires-Dist: fastmcp>=2.0.0
25
+ Requires-Dist: pydantic>=2.11.0
26
+ Requires-Dist: python-dotenv>=1.1.0
27
+ Requires-Dist: black>=24.10.0
28
+ Requires-Dist: pyjwt>=2.0.0
29
+ Requires-Dist: httpx>=0.28.1
30
+ Provides-Extra: telemetry
31
+ Requires-Dist: opentelemetry-api>=1.33.1; extra == "telemetry"
32
+ Requires-Dist: opentelemetry-sdk>=1.33.1; extra == "telemetry"
33
+ Requires-Dist: opentelemetry-instrumentation-asgi>=0.40b0; extra == "telemetry"
34
+ Requires-Dist: opentelemetry-exporter-otlp-proto-http>=0.40b0; extra == "telemetry"
35
+ Requires-Dist: wrapt>=1.17.0; extra == "telemetry"
36
+ Dynamic: license-file
37
+
38
+ # GolfMCP
39
+
40
+ A Pythonic framework for building Model Context Protocol (MCP) servers with zero boilerplate.
41
+
42
+ ## Features
43
+
44
+ * 🚀 **Zero-to-live in under 90 seconds**: Quick setup and deployment
45
+ * 💡 **Convention over configuration**: Minimal boilerplate
46
+ * 🔄 **Fast feedback**: Hot-reload during development (≤ 500 ms)
47
+ * 📂 **Nested folder support**: Organize your tools, resources, and prompts
48
+ * 🔌 **Pluggable auth & deploy**: Built-in providers for OAuth, Vercel, Fly.io, etc.
49
+ * 🛠️ **Delegates protocol compliance to FastMCP**: Focus on your logic, not the wire format
50
+
51
+ ## Installation
52
+
53
+ ```bash
54
+ pip install golfmcp
55
+ ```
56
+
57
+ ## Quick Start
58
+
59
+ Initialize a new project:
60
+
61
+ ```bash
62
+ golf init my-mcp-project
63
+ cd my-mcp-project
64
+ ```
65
+
66
+ Start the development server with hot-reload:
67
+
68
+ ```bash
69
+ golf dev
70
+ ```
71
+
72
+ ## Documentation
73
+
74
+ For detailed documentation, visit [docs](https://golfmcp.docs.example.com/).
75
+
76
+ ## License
77
+
78
+ MIT License