golf-mcp 0.1.18__py3-none-any.whl → 0.1.20__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 +5 -2
- golf/core/platform.py +1 -1
- golf/telemetry/instrumentation.py +254 -200
- {golf_mcp-0.1.18.dist-info → golf_mcp-0.1.20.dist-info}/METADATA +6 -7
- {golf_mcp-0.1.18.dist-info → golf_mcp-0.1.20.dist-info}/RECORD +10 -10
- {golf_mcp-0.1.18.dist-info → golf_mcp-0.1.20.dist-info}/WHEEL +0 -0
- {golf_mcp-0.1.18.dist-info → golf_mcp-0.1.20.dist-info}/entry_points.txt +0 -0
- {golf_mcp-0.1.18.dist-info → golf_mcp-0.1.20.dist-info}/licenses/LICENSE +0 -0
- {golf_mcp-0.1.18.dist-info → golf_mcp-0.1.20.dist-info}/top_level.txt +0 -0
golf/__init__.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "0.1.
|
|
1
|
+
__version__ = "0.1.20"
|
golf/core/builder.py
CHANGED
|
@@ -1251,14 +1251,17 @@ def build_project(
|
|
|
1251
1251
|
try:
|
|
1252
1252
|
from golf.core.platform import register_project_with_platform
|
|
1253
1253
|
|
|
1254
|
-
asyncio.run(
|
|
1254
|
+
success = asyncio.run(
|
|
1255
1255
|
register_project_with_platform(
|
|
1256
1256
|
project_path=project_path,
|
|
1257
1257
|
settings=settings,
|
|
1258
1258
|
components=generator.components,
|
|
1259
1259
|
)
|
|
1260
1260
|
)
|
|
1261
|
-
|
|
1261
|
+
|
|
1262
|
+
if success:
|
|
1263
|
+
console.print("[green]✓ Platform registration completed[/green]")
|
|
1264
|
+
# If success is False, the platform module already printed appropriate warnings
|
|
1262
1265
|
except ImportError:
|
|
1263
1266
|
console.print(
|
|
1264
1267
|
"[yellow]Warning: Platform registration module not available[/yellow]"
|
golf/core/platform.py
CHANGED
|
@@ -65,7 +65,7 @@ async def register_project_with_platform(
|
|
|
65
65
|
try:
|
|
66
66
|
async with httpx.AsyncClient(timeout=10.0) as client:
|
|
67
67
|
response = await client.post(
|
|
68
|
-
"
|
|
68
|
+
"https://golf-backend.golf-auth-1.authed-qukc4.ryvn.run/api/resources",
|
|
69
69
|
json=metadata,
|
|
70
70
|
headers={
|
|
71
71
|
"X-Golf-Key": api_key,
|
|
@@ -4,9 +4,11 @@ import asyncio
|
|
|
4
4
|
import functools
|
|
5
5
|
import os
|
|
6
6
|
import sys
|
|
7
|
+
import time
|
|
7
8
|
from collections.abc import Callable
|
|
8
9
|
from contextlib import asynccontextmanager
|
|
9
10
|
from typing import TypeVar
|
|
11
|
+
from collections import OrderedDict
|
|
10
12
|
|
|
11
13
|
from opentelemetry import baggage, trace
|
|
12
14
|
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
|
|
@@ -15,6 +17,9 @@ from opentelemetry.sdk.trace import TracerProvider
|
|
|
15
17
|
from opentelemetry.sdk.trace.export import BatchSpanProcessor, ConsoleSpanExporter
|
|
16
18
|
from opentelemetry.trace import Status, StatusCode
|
|
17
19
|
|
|
20
|
+
from starlette.middleware.base import BaseHTTPMiddleware
|
|
21
|
+
from starlette.requests import Request
|
|
22
|
+
|
|
18
23
|
T = TypeVar("T")
|
|
19
24
|
|
|
20
25
|
# Global tracer instance
|
|
@@ -31,11 +36,27 @@ def init_telemetry(service_name: str = "golf-mcp-server") -> TracerProvider | No
|
|
|
31
36
|
|
|
32
37
|
# Check for Golf platform integration first
|
|
33
38
|
golf_api_key = os.environ.get("GOLF_API_KEY")
|
|
34
|
-
if golf_api_key
|
|
35
|
-
# Auto-configure for Golf platform
|
|
39
|
+
if golf_api_key:
|
|
40
|
+
# Auto-configure for Golf platform - always use OTLP when Golf API key is present
|
|
36
41
|
os.environ["OTEL_TRACES_EXPORTER"] = "otlp_http"
|
|
37
|
-
|
|
38
|
-
|
|
42
|
+
|
|
43
|
+
# Only set endpoint if not already configured (allow user override)
|
|
44
|
+
if not os.environ.get("OTEL_EXPORTER_OTLP_ENDPOINT"):
|
|
45
|
+
os.environ["OTEL_EXPORTER_OTLP_ENDPOINT"] = (
|
|
46
|
+
"https://golf-backend.golf-auth-1.authed-qukc4.ryvn.run/api/v1/otel"
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
# Set Golf platform headers (append to existing if present)
|
|
50
|
+
existing_headers = os.environ.get("OTEL_EXPORTER_OTLP_HEADERS", "")
|
|
51
|
+
golf_header = f"X-Golf-Key={golf_api_key}"
|
|
52
|
+
|
|
53
|
+
if existing_headers:
|
|
54
|
+
# Check if Golf key is already in headers
|
|
55
|
+
if "X-Golf-Key=" not in existing_headers:
|
|
56
|
+
os.environ["OTEL_EXPORTER_OTLP_HEADERS"] = f"{existing_headers},{golf_header}"
|
|
57
|
+
else:
|
|
58
|
+
os.environ["OTEL_EXPORTER_OTLP_HEADERS"] = golf_header
|
|
59
|
+
|
|
39
60
|
print("[INFO] Auto-configured OpenTelemetry for Golf platform ingestion")
|
|
40
61
|
|
|
41
62
|
# Check for required environment variables based on exporter type
|
|
@@ -821,221 +842,254 @@ def instrument_prompt(func: Callable[..., T], prompt_name: str) -> Callable[...,
|
|
|
821
842
|
return sync_wrapper
|
|
822
843
|
|
|
823
844
|
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
"""
|
|
827
|
-
|
|
845
|
+
# Add the BoundedSessionTracker class before SessionTracingMiddleware
|
|
846
|
+
class BoundedSessionTracker:
|
|
847
|
+
"""Memory-safe session tracker with automatic expiration."""
|
|
848
|
+
|
|
849
|
+
def __init__(self, max_sessions: int = 1000, session_ttl: int = 3600):
|
|
850
|
+
self.max_sessions = max_sessions
|
|
851
|
+
self.session_ttl = session_ttl
|
|
852
|
+
self.sessions: OrderedDict[str, float] = OrderedDict()
|
|
853
|
+
self.last_cleanup = time.time()
|
|
854
|
+
|
|
855
|
+
def track_session(self, session_id: str) -> bool:
|
|
856
|
+
"""Track a session, returns True if it's new."""
|
|
857
|
+
current_time = time.time()
|
|
858
|
+
|
|
859
|
+
# Periodic cleanup (every 5 minutes)
|
|
860
|
+
if current_time - self.last_cleanup > 300:
|
|
861
|
+
self._cleanup_expired(current_time)
|
|
862
|
+
self.last_cleanup = current_time
|
|
863
|
+
|
|
864
|
+
# Check if session exists and is still valid
|
|
865
|
+
if session_id in self.sessions:
|
|
866
|
+
# Move to end (mark as recently used)
|
|
867
|
+
self.sessions.move_to_end(session_id)
|
|
868
|
+
return False
|
|
869
|
+
|
|
870
|
+
# New session
|
|
871
|
+
self.sessions[session_id] = current_time
|
|
872
|
+
|
|
873
|
+
# Enforce max size
|
|
874
|
+
while len(self.sessions) > self.max_sessions:
|
|
875
|
+
self.sessions.popitem(last=False) # Remove oldest
|
|
876
|
+
|
|
877
|
+
return True
|
|
878
|
+
|
|
879
|
+
def _cleanup_expired(self, current_time: float):
|
|
880
|
+
"""Remove expired sessions."""
|
|
881
|
+
expired = [
|
|
882
|
+
sid
|
|
883
|
+
for sid, timestamp in self.sessions.items()
|
|
884
|
+
if current_time - timestamp > self.session_ttl
|
|
885
|
+
]
|
|
886
|
+
for sid in expired:
|
|
887
|
+
del self.sessions[sid]
|
|
888
|
+
|
|
889
|
+
def get_active_session_count(self) -> int:
|
|
890
|
+
return len(self.sessions)
|
|
891
|
+
|
|
892
|
+
|
|
893
|
+
class SessionTracingMiddleware(BaseHTTPMiddleware):
|
|
894
|
+
def __init__(self, app):
|
|
895
|
+
super().__init__(app)
|
|
896
|
+
# Use memory-safe session tracker instead of unbounded collections
|
|
897
|
+
self.session_tracker = BoundedSessionTracker(
|
|
898
|
+
max_sessions=1000, session_ttl=3600
|
|
899
|
+
)
|
|
828
900
|
|
|
829
|
-
|
|
830
|
-
|
|
901
|
+
async def dispatch(self, request: Request, call_next):
|
|
902
|
+
# Record HTTP request timing
|
|
903
|
+
import time
|
|
831
904
|
|
|
832
|
-
|
|
833
|
-
if provider is None:
|
|
834
|
-
# Just yield without any telemetry setup
|
|
835
|
-
yield
|
|
836
|
-
return
|
|
905
|
+
start_time = time.time()
|
|
837
906
|
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
class SessionTracingMiddleware(BaseHTTPMiddleware):
|
|
844
|
-
def __init__(self, app):
|
|
845
|
-
super().__init__(app)
|
|
846
|
-
# Track seen sessions to count unique sessions
|
|
847
|
-
self.seen_sessions = set()
|
|
848
|
-
# Track session start times for duration calculation
|
|
849
|
-
self.session_start_times = {}
|
|
850
|
-
|
|
851
|
-
async def dispatch(self, request: Request, call_next):
|
|
852
|
-
# Record HTTP request timing
|
|
853
|
-
import time
|
|
854
|
-
|
|
855
|
-
start_time = time.time()
|
|
856
|
-
|
|
857
|
-
# Extract session ID from query params or headers
|
|
858
|
-
session_id = request.query_params.get("session_id")
|
|
859
|
-
if not session_id:
|
|
860
|
-
# Check headers as fallback
|
|
861
|
-
session_id = request.headers.get("x-session-id")
|
|
862
|
-
|
|
863
|
-
# Track session metrics
|
|
864
|
-
if session_id:
|
|
865
|
-
current_time = time.time()
|
|
866
|
-
|
|
867
|
-
# Record new session if we haven't seen this session ID before
|
|
868
|
-
if session_id not in self.seen_sessions:
|
|
869
|
-
self.seen_sessions.add(session_id)
|
|
870
|
-
self.session_start_times[session_id] = current_time
|
|
871
|
-
try:
|
|
872
|
-
from golf.metrics import get_metrics_collector
|
|
873
|
-
|
|
874
|
-
metrics_collector = get_metrics_collector()
|
|
875
|
-
metrics_collector.increment_session()
|
|
876
|
-
except ImportError:
|
|
877
|
-
pass
|
|
878
|
-
else:
|
|
879
|
-
# Update session duration (time since first request)
|
|
880
|
-
if session_id in self.session_start_times:
|
|
881
|
-
duration = (
|
|
882
|
-
current_time - self.session_start_times[session_id]
|
|
883
|
-
)
|
|
884
|
-
try:
|
|
885
|
-
from golf.metrics import get_metrics_collector
|
|
886
|
-
|
|
887
|
-
metrics_collector = get_metrics_collector()
|
|
888
|
-
metrics_collector.record_session_duration(duration)
|
|
889
|
-
except ImportError:
|
|
890
|
-
pass
|
|
891
|
-
|
|
892
|
-
# Clean up old session data periodically
|
|
893
|
-
if len(self.seen_sessions) > 10000:
|
|
894
|
-
# Keep only the most recent 5000 sessions
|
|
895
|
-
recent_sessions = list(self.seen_sessions)[-5000:]
|
|
896
|
-
self.seen_sessions = set(recent_sessions)
|
|
897
|
-
# Clean up start times for removed sessions
|
|
898
|
-
for old_session in list(self.session_start_times.keys()):
|
|
899
|
-
if old_session not in self.seen_sessions:
|
|
900
|
-
self.session_start_times.pop(old_session, None)
|
|
901
|
-
|
|
902
|
-
# Create a descriptive span name based on the request
|
|
903
|
-
method = request.method
|
|
904
|
-
path = request.url.path
|
|
905
|
-
|
|
906
|
-
# Determine the operation type from the path
|
|
907
|
-
operation_type = "unknown"
|
|
908
|
-
if "/mcp" in path:
|
|
909
|
-
operation_type = "mcp.request"
|
|
910
|
-
elif "/sse" in path:
|
|
911
|
-
operation_type = "sse.stream"
|
|
912
|
-
elif "/auth" in path:
|
|
913
|
-
operation_type = "auth"
|
|
914
|
-
|
|
915
|
-
span_name = f"{operation_type}.{method.lower()}"
|
|
907
|
+
# Extract session ID from query params or headers
|
|
908
|
+
session_id = request.query_params.get("session_id")
|
|
909
|
+
if not session_id:
|
|
910
|
+
# Check headers as fallback
|
|
911
|
+
session_id = request.headers.get("x-session-id")
|
|
916
912
|
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
span.set_attribute("http.target", path)
|
|
925
|
-
span.set_attribute(
|
|
926
|
-
"http.user_agent", request.headers.get("user-agent", "unknown")
|
|
927
|
-
)
|
|
913
|
+
# Track session metrics using memory-safe tracker
|
|
914
|
+
if session_id:
|
|
915
|
+
is_new_session = self.session_tracker.track_session(session_id)
|
|
916
|
+
|
|
917
|
+
if is_new_session:
|
|
918
|
+
try:
|
|
919
|
+
from golf.metrics import get_metrics_collector
|
|
928
920
|
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
#
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
921
|
+
metrics_collector = get_metrics_collector()
|
|
922
|
+
metrics_collector.increment_session()
|
|
923
|
+
except ImportError:
|
|
924
|
+
pass
|
|
925
|
+
else:
|
|
926
|
+
# Record session duration for existing sessions
|
|
927
|
+
try:
|
|
928
|
+
from golf.metrics import get_metrics_collector
|
|
929
|
+
|
|
930
|
+
metrics_collector = get_metrics_collector()
|
|
931
|
+
# Use a default duration since we don't track exact start times anymore
|
|
932
|
+
# This is less precise but memory-safe
|
|
933
|
+
metrics_collector.record_session_duration(300.0) # 5 min default
|
|
934
|
+
except ImportError:
|
|
935
|
+
pass
|
|
936
|
+
|
|
937
|
+
# Create a descriptive span name based on the request
|
|
938
|
+
method = request.method
|
|
939
|
+
path = request.url.path
|
|
940
|
+
|
|
941
|
+
# Determine the operation type from the path
|
|
942
|
+
operation_type = "unknown"
|
|
943
|
+
if "/mcp" in path:
|
|
944
|
+
operation_type = "mcp.request"
|
|
945
|
+
elif "/sse" in path:
|
|
946
|
+
operation_type = "sse.stream"
|
|
947
|
+
elif "/auth" in path:
|
|
948
|
+
operation_type = "auth"
|
|
949
|
+
|
|
950
|
+
span_name = f"{operation_type}.{method.lower()}"
|
|
951
|
+
|
|
952
|
+
tracer = get_tracer()
|
|
953
|
+
with tracer.start_as_current_span(span_name) as span:
|
|
954
|
+
# Add comprehensive HTTP attributes
|
|
955
|
+
span.set_attribute("http.method", method)
|
|
956
|
+
span.set_attribute("http.url", str(request.url))
|
|
957
|
+
span.set_attribute("http.scheme", request.url.scheme)
|
|
958
|
+
span.set_attribute("http.host", request.url.hostname or "unknown")
|
|
959
|
+
span.set_attribute("http.target", path)
|
|
960
|
+
span.set_attribute(
|
|
961
|
+
"http.user_agent", request.headers.get("user-agent", "unknown")
|
|
962
|
+
)
|
|
963
|
+
|
|
964
|
+
# Add session tracking
|
|
965
|
+
if session_id:
|
|
966
|
+
span.set_attribute("mcp.session.id", session_id)
|
|
967
|
+
span.set_attribute(
|
|
968
|
+
"mcp.session.active_count",
|
|
969
|
+
self.session_tracker.get_active_session_count(),
|
|
970
|
+
)
|
|
971
|
+
# Add to baggage for propagation
|
|
972
|
+
ctx = baggage.set_baggage("mcp.session.id", session_id)
|
|
973
|
+
from opentelemetry import context
|
|
974
|
+
|
|
975
|
+
token = context.attach(ctx)
|
|
976
|
+
else:
|
|
977
|
+
token = None
|
|
978
|
+
|
|
979
|
+
# Add request size if available
|
|
980
|
+
content_length = request.headers.get("content-length")
|
|
981
|
+
if content_length:
|
|
982
|
+
span.set_attribute("http.request.size", int(content_length))
|
|
983
|
+
|
|
984
|
+
# Add event for request start
|
|
985
|
+
span.add_event("http.request.started", {"method": method, "path": path})
|
|
986
|
+
|
|
987
|
+
try:
|
|
988
|
+
response = await call_next(request)
|
|
989
|
+
|
|
990
|
+
# Add response attributes
|
|
991
|
+
span.set_attribute("http.status_code", response.status_code)
|
|
992
|
+
span.set_attribute(
|
|
993
|
+
"http.status_class", f"{response.status_code // 100}xx"
|
|
994
|
+
)
|
|
995
|
+
|
|
996
|
+
# Set span status based on HTTP status
|
|
997
|
+
if response.status_code >= 400:
|
|
998
|
+
span.set_status(
|
|
999
|
+
Status(StatusCode.ERROR, f"HTTP {response.status_code}")
|
|
948
1000
|
)
|
|
1001
|
+
else:
|
|
1002
|
+
span.set_status(Status(StatusCode.OK))
|
|
949
1003
|
|
|
950
|
-
|
|
951
|
-
|
|
1004
|
+
# Add event for request completion
|
|
1005
|
+
span.add_event(
|
|
1006
|
+
"http.request.completed",
|
|
1007
|
+
{
|
|
1008
|
+
"method": method,
|
|
1009
|
+
"path": path,
|
|
1010
|
+
"status_code": response.status_code,
|
|
1011
|
+
},
|
|
1012
|
+
)
|
|
952
1013
|
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
"http.status_class", f"{response.status_code // 100}xx"
|
|
957
|
-
)
|
|
1014
|
+
# Record HTTP request metrics
|
|
1015
|
+
try:
|
|
1016
|
+
from golf.metrics import get_metrics_collector
|
|
958
1017
|
|
|
959
|
-
|
|
960
|
-
if response.status_code >= 400:
|
|
961
|
-
span.set_status(
|
|
962
|
-
Status(StatusCode.ERROR, f"HTTP {response.status_code}")
|
|
963
|
-
)
|
|
964
|
-
else:
|
|
965
|
-
span.set_status(Status(StatusCode.OK))
|
|
966
|
-
|
|
967
|
-
# Add event for request completion
|
|
968
|
-
span.add_event(
|
|
969
|
-
"http.request.completed",
|
|
970
|
-
{
|
|
971
|
-
"method": method,
|
|
972
|
-
"path": path,
|
|
973
|
-
"status_code": response.status_code,
|
|
974
|
-
},
|
|
975
|
-
)
|
|
1018
|
+
metrics_collector = get_metrics_collector()
|
|
976
1019
|
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
1020
|
+
# Clean up path for metrics (remove query params, normalize)
|
|
1021
|
+
clean_path = path.split("?")[0] # Remove query parameters
|
|
1022
|
+
if clean_path.startswith("/"):
|
|
1023
|
+
clean_path = (
|
|
1024
|
+
clean_path[1:] or "root"
|
|
1025
|
+
) # Remove leading slash, handle root
|
|
980
1026
|
|
|
981
|
-
|
|
1027
|
+
metrics_collector.increment_http_request(
|
|
1028
|
+
method, response.status_code, clean_path
|
|
1029
|
+
)
|
|
1030
|
+
metrics_collector.record_http_duration(
|
|
1031
|
+
method, clean_path, time.time() - start_time
|
|
1032
|
+
)
|
|
1033
|
+
except ImportError:
|
|
1034
|
+
# Metrics not available, continue without metrics
|
|
1035
|
+
pass
|
|
982
1036
|
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
clean_path[1:] or "root"
|
|
988
|
-
) # Remove leading slash, handle root
|
|
1037
|
+
return response
|
|
1038
|
+
except Exception as e:
|
|
1039
|
+
span.record_exception(e)
|
|
1040
|
+
span.set_status(Status(StatusCode.ERROR, str(e)))
|
|
989
1041
|
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
return response
|
|
1001
|
-
except Exception as e:
|
|
1002
|
-
span.record_exception(e)
|
|
1003
|
-
span.set_status(Status(StatusCode.ERROR, str(e)))
|
|
1004
|
-
|
|
1005
|
-
# Add event for error
|
|
1006
|
-
span.add_event(
|
|
1007
|
-
"http.request.error",
|
|
1008
|
-
{
|
|
1009
|
-
"method": method,
|
|
1010
|
-
"path": path,
|
|
1011
|
-
"error.type": type(e).__name__,
|
|
1012
|
-
"error.message": str(e),
|
|
1013
|
-
},
|
|
1014
|
-
)
|
|
1042
|
+
# Add event for error
|
|
1043
|
+
span.add_event(
|
|
1044
|
+
"http.request.error",
|
|
1045
|
+
{
|
|
1046
|
+
"method": method,
|
|
1047
|
+
"path": path,
|
|
1048
|
+
"error.type": type(e).__name__,
|
|
1049
|
+
"error.message": str(e),
|
|
1050
|
+
},
|
|
1051
|
+
)
|
|
1015
1052
|
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1053
|
+
# Record HTTP error metrics
|
|
1054
|
+
try:
|
|
1055
|
+
from golf.metrics import get_metrics_collector
|
|
1056
|
+
|
|
1057
|
+
metrics_collector = get_metrics_collector()
|
|
1058
|
+
|
|
1059
|
+
# Clean up path for metrics
|
|
1060
|
+
clean_path = path.split("?")[0]
|
|
1061
|
+
if clean_path.startswith("/"):
|
|
1062
|
+
clean_path = clean_path[1:] or "root"
|
|
1063
|
+
|
|
1064
|
+
metrics_collector.increment_http_request(
|
|
1065
|
+
method, 500, clean_path
|
|
1066
|
+
) # Assume 500 for exceptions
|
|
1067
|
+
metrics_collector.increment_error("http", type(e).__name__)
|
|
1068
|
+
except ImportError:
|
|
1069
|
+
pass
|
|
1070
|
+
|
|
1071
|
+
raise
|
|
1072
|
+
finally:
|
|
1073
|
+
if token:
|
|
1074
|
+
context.detach(token)
|
|
1019
1075
|
|
|
1020
|
-
metrics_collector = get_metrics_collector()
|
|
1021
1076
|
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1077
|
+
@asynccontextmanager
|
|
1078
|
+
async def telemetry_lifespan(mcp_instance):
|
|
1079
|
+
"""Simplified lifespan for telemetry initialization and cleanup."""
|
|
1080
|
+
global _provider
|
|
1026
1081
|
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
) # Assume 500 for exceptions
|
|
1030
|
-
metrics_collector.increment_error("http", type(e).__name__)
|
|
1031
|
-
except ImportError:
|
|
1032
|
-
pass
|
|
1082
|
+
# Initialize telemetry with the server name
|
|
1083
|
+
provider = init_telemetry(service_name=mcp_instance.name)
|
|
1033
1084
|
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1085
|
+
# If provider is None, telemetry is disabled
|
|
1086
|
+
if provider is None:
|
|
1087
|
+
# Just yield without any telemetry setup
|
|
1088
|
+
yield
|
|
1089
|
+
return
|
|
1038
1090
|
|
|
1091
|
+
# Try to add session tracking middleware if possible
|
|
1092
|
+
try:
|
|
1039
1093
|
# Try to add middleware to FastMCP app if it has Starlette app
|
|
1040
1094
|
if hasattr(mcp_instance, "app") or hasattr(mcp_instance, "_app"):
|
|
1041
1095
|
app = getattr(mcp_instance, "app", getattr(mcp_instance, "_app", None))
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: golf-mcp
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.20
|
|
4
4
|
Summary: Framework for building MCP servers
|
|
5
5
|
Author-email: Antoni Gmitruk <antoni@golf.dev>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -28,12 +28,11 @@ Requires-Dist: black>=24.10.0
|
|
|
28
28
|
Requires-Dist: pyjwt>=2.0.0
|
|
29
29
|
Requires-Dist: httpx>=0.28.1
|
|
30
30
|
Requires-Dist: posthog>=4.1.0
|
|
31
|
-
|
|
32
|
-
Requires-Dist: opentelemetry-
|
|
33
|
-
Requires-Dist: opentelemetry-
|
|
34
|
-
Requires-Dist: opentelemetry-
|
|
35
|
-
Requires-Dist:
|
|
36
|
-
Requires-Dist: wrapt>=1.17.0; extra == "telemetry"
|
|
31
|
+
Requires-Dist: opentelemetry-api>=1.33.1
|
|
32
|
+
Requires-Dist: opentelemetry-sdk>=1.33.1
|
|
33
|
+
Requires-Dist: opentelemetry-instrumentation-asgi>=0.40b0
|
|
34
|
+
Requires-Dist: opentelemetry-exporter-otlp-proto-http>=0.40b0
|
|
35
|
+
Requires-Dist: wrapt>=1.17.0
|
|
37
36
|
Provides-Extra: metrics
|
|
38
37
|
Requires-Dist: prometheus-client>=0.22.1; extra == "metrics"
|
|
39
38
|
Dynamic: license-file
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
golf/__init__.py,sha256=
|
|
1
|
+
golf/__init__.py,sha256=8XalsVoLEfXslFvdtUEmkNOuYShzOzYOcFbgmOz1oSk,23
|
|
2
2
|
golf/auth/__init__.py,sha256=Rj4yUngJklk6xrDCrxqLTtoDAMzF1HcTvy_l8wREeao,4103
|
|
3
3
|
golf/auth/api_key.py,sha256=LiIraLiH2v7s3yavidaI6BDlAEfK8XnWF15QmaJn9G4,2378
|
|
4
4
|
golf/auth/helpers.py,sha256=ZogdcHM7J2PN6cL6F6OLZ3gyoUR3dwAFDxOJQ2DW_bc,6526
|
|
@@ -11,13 +11,13 @@ golf/commands/build.py,sha256=jhdxB5EwwCC_8PgqdXLUKuBpnycjh0gft3_7EuTo6ro,2319
|
|
|
11
11
|
golf/commands/init.py,sha256=DUAvGqOUapWdF2cgWPscqHRvyOZDiajR0F0Wkn_jm-k,10355
|
|
12
12
|
golf/commands/run.py,sha256=xsiG5LZw4qVt3cRTTfIoWP4Bf4AxNBBJKx0NNfoua40,2884
|
|
13
13
|
golf/core/__init__.py,sha256=4bKeskJ2fPaZqkz2xQScSa3phRLLrmrczwSL632jv-o,52
|
|
14
|
-
golf/core/builder.py,sha256=
|
|
14
|
+
golf/core/builder.py,sha256=06BccMHR6BFMsdyL-3YJJFqLHVLE-NYSQriVyPFzL6s,59657
|
|
15
15
|
golf/core/builder_auth.py,sha256=nGgyMTiRAqaNfh1FSvoFe6oTVq9RgfMf9JoFGAv2_do,14050
|
|
16
16
|
golf/core/builder_metrics.py,sha256=j6Gtgd867o46JbDfSNGNsHt1QtV1XHKUJs1z8r4siQM,8830
|
|
17
17
|
golf/core/builder_telemetry.py,sha256=jobFgRSspLQLuitL4ytk6asSUdTqYcDxGY3sTjkrZd4,2654
|
|
18
18
|
golf/core/config.py,sha256=6yPtwzVTJauufEnrfUbxsz69H8jC0Ra427oDaRM0-xE,7397
|
|
19
19
|
golf/core/parser.py,sha256=BQRus1O9zmzSmyavwLVfN8BpYFkbrWUDrgQ7yrYfAKw,42457
|
|
20
|
-
golf/core/platform.py,sha256=
|
|
20
|
+
golf/core/platform.py,sha256=y8-yhRPfvm-Eu44p_kN9wg74n1kB2HweRgRYy-Gu1c4,6473
|
|
21
21
|
golf/core/telemetry.py,sha256=CjZ7urbizaRjyFiVBjfGW8V4PmNCG1_quk3FvbVTcjw,15772
|
|
22
22
|
golf/core/transformer.py,sha256=_0nM42M41oM9zw_XxPVVS6MErdBSw2B5lULC7_UFLfU,5287
|
|
23
23
|
golf/examples/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -51,10 +51,10 @@ golf/metrics/__init__.py,sha256=O91y-hj_E9R06gqV8pDZrzHxOIl-1T415Hj9RvFAp3o,283
|
|
|
51
51
|
golf/metrics/collector.py,sha256=iyRszP8TAAigyOsUFTGdKN8Xeob36LhUvXW9tntJrbA,7617
|
|
52
52
|
golf/metrics/registry.py,sha256=mXQE4Pwf3PopGYjcUu4eGgPDAe085YWcsvcvWk0ny8Q,310
|
|
53
53
|
golf/telemetry/__init__.py,sha256=ESGCg5HKwTCIfID1e_K7EE0bOWkSzMidlLtdqQgBd0w,396
|
|
54
|
-
golf/telemetry/instrumentation.py,sha256=
|
|
55
|
-
golf_mcp-0.1.
|
|
56
|
-
golf_mcp-0.1.
|
|
57
|
-
golf_mcp-0.1.
|
|
58
|
-
golf_mcp-0.1.
|
|
59
|
-
golf_mcp-0.1.
|
|
60
|
-
golf_mcp-0.1.
|
|
54
|
+
golf/telemetry/instrumentation.py,sha256=t0iuoIuY3mmtcdNAlUvbUgUfpRkH0mZoYg2C6qm8g2s,45320
|
|
55
|
+
golf_mcp-0.1.20.dist-info/licenses/LICENSE,sha256=5_j2f6fTJmvfmUewzElhkpAaXg2grVoxKouOA8ihV6E,11348
|
|
56
|
+
golf_mcp-0.1.20.dist-info/METADATA,sha256=erjB5udWAGp_OQa3MiPhwbpi0R7zZAJeTMpSqnl67Rg,12820
|
|
57
|
+
golf_mcp-0.1.20.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
58
|
+
golf_mcp-0.1.20.dist-info/entry_points.txt,sha256=5y7rHYM8jGpU-nfwdknCm5XsApLulqsnA37MO6BUTYg,43
|
|
59
|
+
golf_mcp-0.1.20.dist-info/top_level.txt,sha256=BQToHcBUufdyhp9ONGMIvPE40jMEtmI20lYaKb4hxOg,5
|
|
60
|
+
golf_mcp-0.1.20.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|