golf-mcp 0.1.12__tar.gz → 0.1.14__tar.gz

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 (69) hide show
  1. {golf_mcp-0.1.12/src/golf_mcp.egg-info → golf_mcp-0.1.14}/PKG-INFO +1 -1
  2. {golf_mcp-0.1.12 → golf_mcp-0.1.14}/pyproject.toml +2 -2
  3. golf_mcp-0.1.14/src/golf/__init__.py +1 -0
  4. {golf_mcp-0.1.12 → golf_mcp-0.1.14}/src/golf/cli/main.py +50 -38
  5. {golf_mcp-0.1.12 → golf_mcp-0.1.14}/src/golf/commands/run.py +16 -2
  6. {golf_mcp-0.1.12 → golf_mcp-0.1.14}/src/golf/core/builder.py +17 -0
  7. {golf_mcp-0.1.12 → golf_mcp-0.1.14}/src/golf/core/telemetry.py +91 -17
  8. {golf_mcp-0.1.12 → golf_mcp-0.1.14/src/golf_mcp.egg-info}/PKG-INFO +1 -1
  9. golf_mcp-0.1.12/src/golf/__init__.py +0 -1
  10. {golf_mcp-0.1.12 → golf_mcp-0.1.14}/.docs/docs.md +0 -0
  11. {golf_mcp-0.1.12 → golf_mcp-0.1.14}/.docs/fast-mcp.md +0 -0
  12. {golf_mcp-0.1.12 → golf_mcp-0.1.14}/.docs/fastmcp-example-1.py +0 -0
  13. {golf_mcp-0.1.12 → golf_mcp-0.1.14}/.docs/fastmcp-example-2.py +0 -0
  14. {golf_mcp-0.1.12 → golf_mcp-0.1.14}/.docs/mcp.md +0 -0
  15. {golf_mcp-0.1.12 → golf_mcp-0.1.14}/.docs/oauth-implementation.md +0 -0
  16. {golf_mcp-0.1.12 → golf_mcp-0.1.14}/.docs/oauth.md +0 -0
  17. {golf_mcp-0.1.12 → golf_mcp-0.1.14}/LICENSE +0 -0
  18. {golf_mcp-0.1.12 → golf_mcp-0.1.14}/MANIFEST.in +0 -0
  19. {golf_mcp-0.1.12 → golf_mcp-0.1.14}/README.md +0 -0
  20. {golf_mcp-0.1.12 → golf_mcp-0.1.14}/setup.cfg +0 -0
  21. {golf_mcp-0.1.12 → golf_mcp-0.1.14}/src/golf/auth/__init__.py +0 -0
  22. {golf_mcp-0.1.12 → golf_mcp-0.1.14}/src/golf/auth/api_key.py +0 -0
  23. {golf_mcp-0.1.12 → golf_mcp-0.1.14}/src/golf/auth/helpers.py +0 -0
  24. {golf_mcp-0.1.12 → golf_mcp-0.1.14}/src/golf/auth/oauth.py +0 -0
  25. {golf_mcp-0.1.12 → golf_mcp-0.1.14}/src/golf/auth/provider.py +0 -0
  26. {golf_mcp-0.1.12 → golf_mcp-0.1.14}/src/golf/cli/__init__.py +0 -0
  27. {golf_mcp-0.1.12 → golf_mcp-0.1.14}/src/golf/commands/__init__.py +0 -0
  28. {golf_mcp-0.1.12 → golf_mcp-0.1.14}/src/golf/commands/build.py +0 -0
  29. {golf_mcp-0.1.12 → golf_mcp-0.1.14}/src/golf/commands/init.py +0 -0
  30. {golf_mcp-0.1.12 → golf_mcp-0.1.14}/src/golf/core/__init__.py +0 -0
  31. {golf_mcp-0.1.12 → golf_mcp-0.1.14}/src/golf/core/builder_auth.py +0 -0
  32. {golf_mcp-0.1.12 → golf_mcp-0.1.14}/src/golf/core/builder_telemetry.py +0 -0
  33. {golf_mcp-0.1.12 → golf_mcp-0.1.14}/src/golf/core/config.py +0 -0
  34. {golf_mcp-0.1.12 → golf_mcp-0.1.14}/src/golf/core/parser.py +0 -0
  35. {golf_mcp-0.1.12 → golf_mcp-0.1.14}/src/golf/core/transformer.py +0 -0
  36. {golf_mcp-0.1.12 → golf_mcp-0.1.14}/src/golf/examples/__init__.py +0 -0
  37. {golf_mcp-0.1.12 → golf_mcp-0.1.14}/src/golf/examples/api_key/.env +0 -0
  38. {golf_mcp-0.1.12 → golf_mcp-0.1.14}/src/golf/examples/api_key/.env.example +0 -0
  39. {golf_mcp-0.1.12 → golf_mcp-0.1.14}/src/golf/examples/api_key/README.md +0 -0
  40. {golf_mcp-0.1.12 → golf_mcp-0.1.14}/src/golf/examples/api_key/golf.json +0 -0
  41. {golf_mcp-0.1.12 → golf_mcp-0.1.14}/src/golf/examples/api_key/pre_build.py +0 -0
  42. {golf_mcp-0.1.12 → golf_mcp-0.1.14}/src/golf/examples/api_key/tools/issues/create.py +0 -0
  43. {golf_mcp-0.1.12 → golf_mcp-0.1.14}/src/golf/examples/api_key/tools/issues/list.py +0 -0
  44. {golf_mcp-0.1.12 → golf_mcp-0.1.14}/src/golf/examples/api_key/tools/repos/list.py +0 -0
  45. {golf_mcp-0.1.12 → golf_mcp-0.1.14}/src/golf/examples/api_key/tools/search/code.py +0 -0
  46. {golf_mcp-0.1.12 → golf_mcp-0.1.14}/src/golf/examples/api_key/tools/users/get.py +0 -0
  47. {golf_mcp-0.1.12 → golf_mcp-0.1.14}/src/golf/examples/basic/.env +0 -0
  48. {golf_mcp-0.1.12 → golf_mcp-0.1.14}/src/golf/examples/basic/.env.example +0 -0
  49. {golf_mcp-0.1.12 → golf_mcp-0.1.14}/src/golf/examples/basic/README.md +0 -0
  50. {golf_mcp-0.1.12 → golf_mcp-0.1.14}/src/golf/examples/basic/golf.json +0 -0
  51. {golf_mcp-0.1.12 → golf_mcp-0.1.14}/src/golf/examples/basic/pre_build.py +0 -0
  52. {golf_mcp-0.1.12 → golf_mcp-0.1.14}/src/golf/examples/basic/prompts/welcome.py +0 -0
  53. {golf_mcp-0.1.12 → golf_mcp-0.1.14}/src/golf/examples/basic/resources/current_time.py +0 -0
  54. {golf_mcp-0.1.12 → golf_mcp-0.1.14}/src/golf/examples/basic/resources/info.py +0 -0
  55. {golf_mcp-0.1.12 → golf_mcp-0.1.14}/src/golf/examples/basic/resources/weather/common.py +0 -0
  56. {golf_mcp-0.1.12 → golf_mcp-0.1.14}/src/golf/examples/basic/resources/weather/current.py +0 -0
  57. {golf_mcp-0.1.12 → golf_mcp-0.1.14}/src/golf/examples/basic/resources/weather/forecast.py +0 -0
  58. {golf_mcp-0.1.12 → golf_mcp-0.1.14}/src/golf/examples/basic/tools/github_user.py +0 -0
  59. {golf_mcp-0.1.12 → golf_mcp-0.1.14}/src/golf/examples/basic/tools/hello.py +0 -0
  60. {golf_mcp-0.1.12 → golf_mcp-0.1.14}/src/golf/examples/basic/tools/payments/charge.py +0 -0
  61. {golf_mcp-0.1.12 → golf_mcp-0.1.14}/src/golf/examples/basic/tools/payments/common.py +0 -0
  62. {golf_mcp-0.1.12 → golf_mcp-0.1.14}/src/golf/examples/basic/tools/payments/refund.py +0 -0
  63. {golf_mcp-0.1.12 → golf_mcp-0.1.14}/src/golf/telemetry/__init__.py +0 -0
  64. {golf_mcp-0.1.12 → golf_mcp-0.1.14}/src/golf/telemetry/instrumentation.py +0 -0
  65. {golf_mcp-0.1.12 → golf_mcp-0.1.14}/src/golf_mcp.egg-info/SOURCES.txt +0 -0
  66. {golf_mcp-0.1.12 → golf_mcp-0.1.14}/src/golf_mcp.egg-info/dependency_links.txt +0 -0
  67. {golf_mcp-0.1.12 → golf_mcp-0.1.14}/src/golf_mcp.egg-info/entry_points.txt +0 -0
  68. {golf_mcp-0.1.12 → golf_mcp-0.1.14}/src/golf_mcp.egg-info/requires.txt +0 -0
  69. {golf_mcp-0.1.12 → golf_mcp-0.1.14}/src/golf_mcp.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: golf-mcp
3
- Version: 0.1.12
3
+ Version: 0.1.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
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "golf-mcp"
7
- version = "0.1.12"
7
+ version = "0.1.14"
8
8
  description = "Framework for building MCP servers"
9
9
  authors = [
10
10
  {name = "Antoni Gmitruk", email = "antoni@golf.dev"}
@@ -64,7 +64,7 @@ golf = ["examples/**/*"]
64
64
 
65
65
  [tool.poetry]
66
66
  name = "golf-mcp"
67
- version = "0.1.12"
67
+ version = "0.1.14"
68
68
  description = "Framework for building MCP servers with zero boilerplate"
69
69
  authors = ["Antoni Gmitruk <antoni@golf.dev>"]
70
70
  license = "Apache-2.0"
@@ -0,0 +1 @@
1
+ __version__ = "0.1.14"
@@ -15,6 +15,7 @@ from golf.core.telemetry import (
15
15
  set_telemetry_enabled,
16
16
  shutdown,
17
17
  track_event,
18
+ track_detailed_error,
18
19
  )
19
20
 
20
21
  # Create console for rich output
@@ -156,16 +157,12 @@ def build_dev(
156
157
  # Track successful build with environment
157
158
  track_event("cli_build_success", {"success": True, "environment": "dev"})
158
159
  except Exception as e:
159
- error_type = type(e).__name__
160
- error_message = str(e)
161
- track_event(
160
+ track_detailed_error(
162
161
  "cli_build_failed",
163
- {
164
- "success": False,
165
- "environment": "dev",
166
- "error_type": error_type,
167
- "error_message": error_message,
168
- },
162
+ e,
163
+ context="Development build with environment variables",
164
+ operation="build_dev",
165
+ additional_props={"environment": "dev", "copy_env": True}
169
166
  )
170
167
  raise
171
168
 
@@ -212,16 +209,12 @@ def build_prod(
212
209
  # Track successful build with environment
213
210
  track_event("cli_build_success", {"success": True, "environment": "prod"})
214
211
  except Exception as e:
215
- error_type = type(e).__name__
216
- error_message = str(e)
217
- track_event(
212
+ track_detailed_error(
218
213
  "cli_build_failed",
219
- {
220
- "success": False,
221
- "environment": "prod",
222
- "error_type": error_type,
223
- "error_message": error_message,
224
- },
214
+ e,
215
+ context="Production build without environment variables",
216
+ operation="build_prod",
217
+ additional_props={"environment": "prod", "copy_env": False}
225
218
  )
226
219
  raise
227
220
 
@@ -282,18 +275,15 @@ def run(
282
275
 
283
276
  build_project(project_root, settings, dist_dir)
284
277
  except Exception as e:
285
- error_type = type(e).__name__
286
- error_message = str(e)
287
278
  console.print(
288
- f"[bold red]Error building project:[/bold red] {error_message}"
279
+ f"[bold red]Error building project:[/bold red] {str(e)}"
289
280
  )
290
- track_event(
281
+ track_detailed_error(
291
282
  "cli_run_failed",
292
- {
293
- "success": False,
294
- "error_type": f"BuildError.{error_type}",
295
- "error_message": error_message,
296
- },
283
+ e,
284
+ context="Auto-build before running server",
285
+ operation="auto_build_before_run",
286
+ additional_props={"auto_build": True}
297
287
  )
298
288
  raise
299
289
  else:
@@ -325,16 +315,41 @@ def run(
325
315
  port=port,
326
316
  )
327
317
 
328
- # Track based on return code
318
+ # Track based on return code with better categorization
329
319
  if return_code == 0:
330
320
  track_event("cli_run_success", {"success": True})
321
+ elif return_code in [130, 143, 137, 2]:
322
+ # Intentional shutdowns (not errors):
323
+ # 130: Ctrl+C (SIGINT)
324
+ # 143: SIGTERM (graceful shutdown, e.g., Kubernetes, Docker)
325
+ # 137: SIGKILL (forced shutdown)
326
+ # 2: General interrupt/graceful shutdown
327
+ shutdown_type = {
328
+ 130: "UserInterrupt",
329
+ 143: "GracefulShutdown",
330
+ 137: "ForcedShutdown",
331
+ 2: "Interrupt"
332
+ }.get(return_code, "GracefulShutdown")
333
+
334
+ track_event(
335
+ "cli_run_shutdown",
336
+ {
337
+ "success": True, # Not an error
338
+ "shutdown_type": shutdown_type,
339
+ "exit_code": return_code,
340
+ },
341
+ )
331
342
  else:
343
+ # Actual errors (unexpected exit codes)
332
344
  track_event(
333
345
  "cli_run_failed",
334
346
  {
335
347
  "success": False,
336
- "error_type": "NonZeroExit",
337
- "error_message": f"Server exited with code {return_code}",
348
+ "error_type": "UnexpectedExit",
349
+ "error_message": f"Server process exited unexpectedly with code {return_code}",
350
+ "exit_code": return_code,
351
+ "operation": "server_process_execution",
352
+ "context": "Server process terminated with unexpected exit code",
338
353
  },
339
354
  )
340
355
 
@@ -342,15 +357,12 @@ def run(
342
357
  if return_code != 0:
343
358
  raise typer.Exit(code=return_code)
344
359
  except Exception as e:
345
- error_type = type(e).__name__
346
- error_message = str(e)
347
- track_event(
360
+ track_detailed_error(
348
361
  "cli_run_failed",
349
- {
350
- "success": False,
351
- "error_type": error_type,
352
- "error_message": error_message,
353
- },
362
+ e,
363
+ context="Server execution or startup failure",
364
+ operation="run_server_execution",
365
+ additional_props={"has_dist_dir": dist_dir.exists() if dist_dir else False}
354
366
  )
355
367
  raise
356
368
 
@@ -64,10 +64,24 @@ def run_server(
64
64
  env=env,
65
65
  )
66
66
 
67
+ # Provide more context about the exit
68
+ if process.returncode == 0:
69
+ console.print("[green]Server stopped successfully[/green]")
70
+ elif process.returncode == 130:
71
+ console.print("[yellow]Server stopped by user interrupt (Ctrl+C)[/yellow]")
72
+ elif process.returncode == 143:
73
+ console.print("[yellow]Server stopped by SIGTERM (graceful shutdown)[/yellow]")
74
+ elif process.returncode == 137:
75
+ console.print("[yellow]Server stopped by SIGKILL (forced shutdown)[/yellow]")
76
+ elif process.returncode in [1, 2]:
77
+ console.print(f"[red]Server exited with error code {process.returncode}[/red]")
78
+ else:
79
+ console.print(f"[orange]Server exited with code {process.returncode}[/orange]")
80
+
67
81
  return process.returncode
68
82
  except KeyboardInterrupt:
69
- console.print("\n[yellow]Server stopped by user[/yellow]")
70
- return 0
83
+ console.print("\n[yellow]Server stopped by user (Ctrl+C)[/yellow]")
84
+ return 130 # Standard exit code for SIGINT
71
85
  except Exception as e:
72
86
  console.print(f"\n[bold red]Error running server:[/bold red] {e}")
73
87
  return 1
@@ -950,6 +950,23 @@ def build_project(
950
950
  import traceback
951
951
 
952
952
  console.print(f"[red]{traceback.format_exc()}[/red]")
953
+
954
+ # Track detailed error for pre_build.py execution failures
955
+ try:
956
+ from golf.core.telemetry import track_detailed_error
957
+ track_detailed_error(
958
+ "build_pre_build_failed",
959
+ e,
960
+ context="Executing pre_build.py configuration script",
961
+ operation="pre_build_execution",
962
+ additional_props={
963
+ "file_path": str(pre_build_path.relative_to(project_path)),
964
+ "build_env": build_env,
965
+ }
966
+ )
967
+ except Exception:
968
+ # Don't let telemetry errors break the build
969
+ pass
953
970
 
954
971
  # Clear the output directory if it exists
955
972
  if output_dir.exists():
@@ -189,11 +189,11 @@ def initialize_telemetry() -> None:
189
189
  """Initialize PostHog telemetry if enabled."""
190
190
  # Ensure PostHog is disabled in test mode
191
191
  _ensure_posthog_disabled_in_test_mode()
192
-
192
+
193
193
  # Don't initialize if PostHog is disabled (test mode)
194
194
  if posthog.disabled:
195
195
  return
196
-
196
+
197
197
  if not is_telemetry_enabled():
198
198
  return
199
199
 
@@ -281,6 +281,8 @@ def track_event(event_name: str, properties: dict[str, Any] | None = None) -> No
281
281
  "command_type",
282
282
  "error_type",
283
283
  "error_message",
284
+ "shutdown_type",
285
+ "exit_code",
284
286
  }
285
287
  for key in safe_keys:
286
288
  if key in properties:
@@ -326,26 +328,98 @@ def track_command(
326
328
  track_event(f"cli_{command}", properties)
327
329
 
328
330
 
329
- def _sanitize_error_message(message: str) -> str:
330
- """Sanitize error message to remove sensitive information.
331
+ def track_detailed_error(
332
+ event_name: str,
333
+ error: Exception,
334
+ context: str | None = None,
335
+ operation: str | None = None,
336
+ additional_props: dict[str, Any] | None = None,
337
+ ) -> None:
338
+ """Track a detailed error with enhanced debugging information.
331
339
 
332
340
  Args:
333
- message: Raw error message
334
-
335
- Returns:
336
- Sanitized error message
341
+ event_name: Name of the error event (e.g., "cli_run_failed", "cli_build_failed")
342
+ error: The exception that occurred
343
+ context: Additional context about where the error occurred
344
+ operation: The specific operation that failed
345
+ additional_props: Additional properties to include
337
346
  """
347
+ import traceback
348
+ import time
349
+
350
+ properties = {
351
+ "success": False,
352
+ "error_type": type(error).__name__,
353
+ "error_message": _sanitize_error_message(str(error)),
354
+ "timestamp": int(time.time()),
355
+ }
356
+
357
+ # Add operation context
358
+ if operation:
359
+ properties["operation"] = operation
360
+ if context:
361
+ properties["context"] = context
362
+
363
+ # Add sanitized stack trace for debugging
364
+ try:
365
+ tb_lines = traceback.format_exception(type(error), error, error.__traceback__)
366
+ # Get the last few frames (most relevant) and sanitize them
367
+ relevant_frames = tb_lines[-3:] if len(tb_lines) > 3 else tb_lines
368
+ sanitized_trace = []
369
+
370
+ for frame in relevant_frames:
371
+ # Sanitize file paths in stack trace
372
+ sanitized_frame = _sanitize_error_message(frame.strip())
373
+ # Further sanitize common traceback patterns
374
+ sanitized_frame = sanitized_frame.replace('File "[PATH]', 'File "[PATH]')
375
+ sanitized_trace.append(sanitized_frame)
376
+
377
+ properties["stack_trace"] = " | ".join(sanitized_trace)
378
+
379
+ # Add the specific line that caused the error if available
380
+ if hasattr(error, '__traceback__') and error.__traceback__:
381
+ tb = error.__traceback__
382
+ while tb.tb_next:
383
+ tb = tb.tb_next
384
+ properties["error_line"] = tb.tb_lineno
385
+
386
+ except Exception:
387
+ # Don't fail if we can't capture stack trace
388
+ pass
389
+
390
+ # Add system context for debugging
391
+ try:
392
+ properties["python_executable"] = _sanitize_error_message(platform.python_implementation())
393
+ properties["platform_detail"] = platform.platform()[:50] # Limit length
394
+ except Exception:
395
+ pass
396
+
397
+ # Merge additional properties
398
+ if additional_props:
399
+ # Only include safe additional properties
400
+ safe_additional_keys = {
401
+ "exit_code", "shutdown_type", "environment", "template",
402
+ "build_env", "transport", "component_count", "file_path",
403
+ "component_type", "validation_error", "config_error"
404
+ }
405
+ for key, value in additional_props.items():
406
+ if key in safe_additional_keys:
407
+ properties[key] = value
408
+
409
+ track_event(event_name, properties)
410
+
411
+ def _sanitize_error_message(message: str) -> str:
412
+ """Sanitize error messages to remove sensitive information."""
338
413
  import re
339
414
 
340
- # Remove absolute file paths but keep the filename
341
- # Unix-style paths
342
- message = re.sub(
343
- r'/(?:Users|home|var|tmp|opt|usr|etc)/[^\s"\']+/([^/\s"\']+)', r"\1", message
344
- )
345
- # Windows-style paths
346
- message = re.sub(r'[A-Za-z]:\\[^\s"\']+\\([^\\s"\']+)', r"\1", message)
347
- # Generic path pattern (catches remaining paths)
348
- message = re.sub(r'(?:^|[\s"])(/[^\s"\']+/)+([^/\s"\']+)', r"\2", message)
415
+ # Remove file paths but preserve filenames
416
+ # Match paths with directories and capture the filename
417
+ # Unix style: /path/to/file.py -> file.py
418
+ message = re.sub(r"(/[^/\s]+)+/([^/\s]+)", r"\2", message)
419
+ # Windows style: C:\path\to\file.py -> file.py
420
+ message = re.sub(r"([A-Za-z]:\\[^\\]+\\)+([^\\]+)", r"\2", message)
421
+ # Remaining absolute paths without filename
422
+ message = re.sub(r"[/\\][^\s]*[/\\]", "[PATH]/", message)
349
423
 
350
424
  # Remove potential API keys or tokens (common patterns)
351
425
  # Generic API keys (20+ alphanumeric with underscores/hyphens)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: golf-mcp
3
- Version: 0.1.12
3
+ Version: 0.1.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 +0,0 @@
1
- __version__ = "0.1.12"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes