golf-mcp 0.1.18__py3-none-any.whl → 0.1.19__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/telemetry/instrumentation.py +234 -196
- {golf_mcp-0.1.18.dist-info → golf_mcp-0.1.19.dist-info}/METADATA +1 -1
- {golf_mcp-0.1.18.dist-info → golf_mcp-0.1.19.dist-info}/RECORD +8 -8
- {golf_mcp-0.1.18.dist-info → golf_mcp-0.1.19.dist-info}/WHEEL +0 -0
- {golf_mcp-0.1.18.dist-info → golf_mcp-0.1.19.dist-info}/entry_points.txt +0 -0
- {golf_mcp-0.1.18.dist-info → golf_mcp-0.1.19.dist-info}/licenses/LICENSE +0 -0
- {golf_mcp-0.1.18.dist-info → golf_mcp-0.1.19.dist-info}/top_level.txt +0 -0
golf/__init__.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "0.1.
|
|
1
|
+
__version__ = "0.1.19"
|
|
@@ -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
|
|
@@ -821,221 +826,254 @@ def instrument_prompt(func: Callable[..., T], prompt_name: str) -> Callable[...,
|
|
|
821
826
|
return sync_wrapper
|
|
822
827
|
|
|
823
828
|
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
"""
|
|
827
|
-
|
|
829
|
+
# Add the BoundedSessionTracker class before SessionTracingMiddleware
|
|
830
|
+
class BoundedSessionTracker:
|
|
831
|
+
"""Memory-safe session tracker with automatic expiration."""
|
|
832
|
+
|
|
833
|
+
def __init__(self, max_sessions: int = 1000, session_ttl: int = 3600):
|
|
834
|
+
self.max_sessions = max_sessions
|
|
835
|
+
self.session_ttl = session_ttl
|
|
836
|
+
self.sessions: OrderedDict[str, float] = OrderedDict()
|
|
837
|
+
self.last_cleanup = time.time()
|
|
838
|
+
|
|
839
|
+
def track_session(self, session_id: str) -> bool:
|
|
840
|
+
"""Track a session, returns True if it's new."""
|
|
841
|
+
current_time = time.time()
|
|
842
|
+
|
|
843
|
+
# Periodic cleanup (every 5 minutes)
|
|
844
|
+
if current_time - self.last_cleanup > 300:
|
|
845
|
+
self._cleanup_expired(current_time)
|
|
846
|
+
self.last_cleanup = current_time
|
|
847
|
+
|
|
848
|
+
# Check if session exists and is still valid
|
|
849
|
+
if session_id in self.sessions:
|
|
850
|
+
# Move to end (mark as recently used)
|
|
851
|
+
self.sessions.move_to_end(session_id)
|
|
852
|
+
return False
|
|
853
|
+
|
|
854
|
+
# New session
|
|
855
|
+
self.sessions[session_id] = current_time
|
|
856
|
+
|
|
857
|
+
# Enforce max size
|
|
858
|
+
while len(self.sessions) > self.max_sessions:
|
|
859
|
+
self.sessions.popitem(last=False) # Remove oldest
|
|
860
|
+
|
|
861
|
+
return True
|
|
862
|
+
|
|
863
|
+
def _cleanup_expired(self, current_time: float):
|
|
864
|
+
"""Remove expired sessions."""
|
|
865
|
+
expired = [
|
|
866
|
+
sid
|
|
867
|
+
for sid, timestamp in self.sessions.items()
|
|
868
|
+
if current_time - timestamp > self.session_ttl
|
|
869
|
+
]
|
|
870
|
+
for sid in expired:
|
|
871
|
+
del self.sessions[sid]
|
|
872
|
+
|
|
873
|
+
def get_active_session_count(self) -> int:
|
|
874
|
+
return len(self.sessions)
|
|
875
|
+
|
|
876
|
+
|
|
877
|
+
class SessionTracingMiddleware(BaseHTTPMiddleware):
|
|
878
|
+
def __init__(self, app):
|
|
879
|
+
super().__init__(app)
|
|
880
|
+
# Use memory-safe session tracker instead of unbounded collections
|
|
881
|
+
self.session_tracker = BoundedSessionTracker(
|
|
882
|
+
max_sessions=1000, session_ttl=3600
|
|
883
|
+
)
|
|
828
884
|
|
|
829
|
-
|
|
830
|
-
|
|
885
|
+
async def dispatch(self, request: Request, call_next):
|
|
886
|
+
# Record HTTP request timing
|
|
887
|
+
import time
|
|
831
888
|
|
|
832
|
-
|
|
833
|
-
if provider is None:
|
|
834
|
-
# Just yield without any telemetry setup
|
|
835
|
-
yield
|
|
836
|
-
return
|
|
889
|
+
start_time = time.time()
|
|
837
890
|
|
|
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()}"
|
|
891
|
+
# Extract session ID from query params or headers
|
|
892
|
+
session_id = request.query_params.get("session_id")
|
|
893
|
+
if not session_id:
|
|
894
|
+
# Check headers as fallback
|
|
895
|
+
session_id = request.headers.get("x-session-id")
|
|
916
896
|
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
span.set_attribute("http.method", method)
|
|
921
|
-
span.set_attribute("http.url", str(request.url))
|
|
922
|
-
span.set_attribute("http.scheme", request.url.scheme)
|
|
923
|
-
span.set_attribute("http.host", request.url.hostname or "unknown")
|
|
924
|
-
span.set_attribute("http.target", path)
|
|
925
|
-
span.set_attribute(
|
|
926
|
-
"http.user_agent", request.headers.get("user-agent", "unknown")
|
|
927
|
-
)
|
|
897
|
+
# Track session metrics using memory-safe tracker
|
|
898
|
+
if session_id:
|
|
899
|
+
is_new_session = self.session_tracker.track_session(session_id)
|
|
928
900
|
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
#
|
|
946
|
-
|
|
947
|
-
|
|
901
|
+
if is_new_session:
|
|
902
|
+
try:
|
|
903
|
+
from golf.metrics import get_metrics_collector
|
|
904
|
+
|
|
905
|
+
metrics_collector = get_metrics_collector()
|
|
906
|
+
metrics_collector.increment_session()
|
|
907
|
+
except ImportError:
|
|
908
|
+
pass
|
|
909
|
+
else:
|
|
910
|
+
# Record session duration for existing sessions
|
|
911
|
+
try:
|
|
912
|
+
from golf.metrics import get_metrics_collector
|
|
913
|
+
|
|
914
|
+
metrics_collector = get_metrics_collector()
|
|
915
|
+
# Use a default duration since we don't track exact start times anymore
|
|
916
|
+
# This is less precise but memory-safe
|
|
917
|
+
metrics_collector.record_session_duration(300.0) # 5 min default
|
|
918
|
+
except ImportError:
|
|
919
|
+
pass
|
|
920
|
+
|
|
921
|
+
# Create a descriptive span name based on the request
|
|
922
|
+
method = request.method
|
|
923
|
+
path = request.url.path
|
|
924
|
+
|
|
925
|
+
# Determine the operation type from the path
|
|
926
|
+
operation_type = "unknown"
|
|
927
|
+
if "/mcp" in path:
|
|
928
|
+
operation_type = "mcp.request"
|
|
929
|
+
elif "/sse" in path:
|
|
930
|
+
operation_type = "sse.stream"
|
|
931
|
+
elif "/auth" in path:
|
|
932
|
+
operation_type = "auth"
|
|
933
|
+
|
|
934
|
+
span_name = f"{operation_type}.{method.lower()}"
|
|
935
|
+
|
|
936
|
+
tracer = get_tracer()
|
|
937
|
+
with tracer.start_as_current_span(span_name) as span:
|
|
938
|
+
# Add comprehensive HTTP attributes
|
|
939
|
+
span.set_attribute("http.method", method)
|
|
940
|
+
span.set_attribute("http.url", str(request.url))
|
|
941
|
+
span.set_attribute("http.scheme", request.url.scheme)
|
|
942
|
+
span.set_attribute("http.host", request.url.hostname or "unknown")
|
|
943
|
+
span.set_attribute("http.target", path)
|
|
944
|
+
span.set_attribute(
|
|
945
|
+
"http.user_agent", request.headers.get("user-agent", "unknown")
|
|
946
|
+
)
|
|
947
|
+
|
|
948
|
+
# Add session tracking
|
|
949
|
+
if session_id:
|
|
950
|
+
span.set_attribute("mcp.session.id", session_id)
|
|
951
|
+
span.set_attribute(
|
|
952
|
+
"mcp.session.active_count",
|
|
953
|
+
self.session_tracker.get_active_session_count(),
|
|
954
|
+
)
|
|
955
|
+
# Add to baggage for propagation
|
|
956
|
+
ctx = baggage.set_baggage("mcp.session.id", session_id)
|
|
957
|
+
from opentelemetry import context
|
|
958
|
+
|
|
959
|
+
token = context.attach(ctx)
|
|
960
|
+
else:
|
|
961
|
+
token = None
|
|
962
|
+
|
|
963
|
+
# Add request size if available
|
|
964
|
+
content_length = request.headers.get("content-length")
|
|
965
|
+
if content_length:
|
|
966
|
+
span.set_attribute("http.request.size", int(content_length))
|
|
967
|
+
|
|
968
|
+
# Add event for request start
|
|
969
|
+
span.add_event("http.request.started", {"method": method, "path": path})
|
|
970
|
+
|
|
971
|
+
try:
|
|
972
|
+
response = await call_next(request)
|
|
973
|
+
|
|
974
|
+
# Add response attributes
|
|
975
|
+
span.set_attribute("http.status_code", response.status_code)
|
|
976
|
+
span.set_attribute(
|
|
977
|
+
"http.status_class", f"{response.status_code // 100}xx"
|
|
978
|
+
)
|
|
979
|
+
|
|
980
|
+
# Set span status based on HTTP status
|
|
981
|
+
if response.status_code >= 400:
|
|
982
|
+
span.set_status(
|
|
983
|
+
Status(StatusCode.ERROR, f"HTTP {response.status_code}")
|
|
948
984
|
)
|
|
985
|
+
else:
|
|
986
|
+
span.set_status(Status(StatusCode.OK))
|
|
987
|
+
|
|
988
|
+
# Add event for request completion
|
|
989
|
+
span.add_event(
|
|
990
|
+
"http.request.completed",
|
|
991
|
+
{
|
|
992
|
+
"method": method,
|
|
993
|
+
"path": path,
|
|
994
|
+
"status_code": response.status_code,
|
|
995
|
+
},
|
|
996
|
+
)
|
|
949
997
|
|
|
950
|
-
|
|
951
|
-
|
|
998
|
+
# Record HTTP request metrics
|
|
999
|
+
try:
|
|
1000
|
+
from golf.metrics import get_metrics_collector
|
|
952
1001
|
|
|
953
|
-
|
|
954
|
-
span.set_attribute("http.status_code", response.status_code)
|
|
955
|
-
span.set_attribute(
|
|
956
|
-
"http.status_class", f"{response.status_code // 100}xx"
|
|
957
|
-
)
|
|
1002
|
+
metrics_collector = get_metrics_collector()
|
|
958
1003
|
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
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
|
-
)
|
|
1004
|
+
# Clean up path for metrics (remove query params, normalize)
|
|
1005
|
+
clean_path = path.split("?")[0] # Remove query parameters
|
|
1006
|
+
if clean_path.startswith("/"):
|
|
1007
|
+
clean_path = (
|
|
1008
|
+
clean_path[1:] or "root"
|
|
1009
|
+
) # Remove leading slash, handle root
|
|
976
1010
|
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
1011
|
+
metrics_collector.increment_http_request(
|
|
1012
|
+
method, response.status_code, clean_path
|
|
1013
|
+
)
|
|
1014
|
+
metrics_collector.record_http_duration(
|
|
1015
|
+
method, clean_path, time.time() - start_time
|
|
1016
|
+
)
|
|
1017
|
+
except ImportError:
|
|
1018
|
+
# Metrics not available, continue without metrics
|
|
1019
|
+
pass
|
|
980
1020
|
|
|
981
|
-
|
|
1021
|
+
return response
|
|
1022
|
+
except Exception as e:
|
|
1023
|
+
span.record_exception(e)
|
|
1024
|
+
span.set_status(Status(StatusCode.ERROR, str(e)))
|
|
982
1025
|
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
1026
|
+
# Add event for error
|
|
1027
|
+
span.add_event(
|
|
1028
|
+
"http.request.error",
|
|
1029
|
+
{
|
|
1030
|
+
"method": method,
|
|
1031
|
+
"path": path,
|
|
1032
|
+
"error.type": type(e).__name__,
|
|
1033
|
+
"error.message": str(e),
|
|
1034
|
+
},
|
|
1035
|
+
)
|
|
989
1036
|
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
metrics_collector.record_http_duration(
|
|
994
|
-
method, clean_path, time.time() - start_time
|
|
995
|
-
)
|
|
996
|
-
except ImportError:
|
|
997
|
-
# Metrics not available, continue without metrics
|
|
998
|
-
pass
|
|
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
|
-
)
|
|
1037
|
+
# Record HTTP error metrics
|
|
1038
|
+
try:
|
|
1039
|
+
from golf.metrics import get_metrics_collector
|
|
1015
1040
|
|
|
1016
|
-
|
|
1017
|
-
try:
|
|
1018
|
-
from golf.metrics import get_metrics_collector
|
|
1041
|
+
metrics_collector = get_metrics_collector()
|
|
1019
1042
|
|
|
1020
|
-
|
|
1043
|
+
# Clean up path for metrics
|
|
1044
|
+
clean_path = path.split("?")[0]
|
|
1045
|
+
if clean_path.startswith("/"):
|
|
1046
|
+
clean_path = clean_path[1:] or "root"
|
|
1021
1047
|
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1048
|
+
metrics_collector.increment_http_request(
|
|
1049
|
+
method, 500, clean_path
|
|
1050
|
+
) # Assume 500 for exceptions
|
|
1051
|
+
metrics_collector.increment_error("http", type(e).__name__)
|
|
1052
|
+
except ImportError:
|
|
1053
|
+
pass
|
|
1026
1054
|
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
except ImportError:
|
|
1032
|
-
pass
|
|
1055
|
+
raise
|
|
1056
|
+
finally:
|
|
1057
|
+
if token:
|
|
1058
|
+
context.detach(token)
|
|
1033
1059
|
|
|
1034
|
-
raise
|
|
1035
|
-
finally:
|
|
1036
|
-
if token:
|
|
1037
|
-
context.detach(token)
|
|
1038
1060
|
|
|
1061
|
+
@asynccontextmanager
|
|
1062
|
+
async def telemetry_lifespan(mcp_instance):
|
|
1063
|
+
"""Simplified lifespan for telemetry initialization and cleanup."""
|
|
1064
|
+
global _provider
|
|
1065
|
+
|
|
1066
|
+
# Initialize telemetry with the server name
|
|
1067
|
+
provider = init_telemetry(service_name=mcp_instance.name)
|
|
1068
|
+
|
|
1069
|
+
# If provider is None, telemetry is disabled
|
|
1070
|
+
if provider is None:
|
|
1071
|
+
# Just yield without any telemetry setup
|
|
1072
|
+
yield
|
|
1073
|
+
return
|
|
1074
|
+
|
|
1075
|
+
# Try to add session tracking middleware if possible
|
|
1076
|
+
try:
|
|
1039
1077
|
# Try to add middleware to FastMCP app if it has Starlette app
|
|
1040
1078
|
if hasattr(mcp_instance, "app") or hasattr(mcp_instance, "_app"):
|
|
1041
1079
|
app = getattr(mcp_instance, "app", getattr(mcp_instance, "_app", None))
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
golf/__init__.py,sha256=
|
|
1
|
+
golf/__init__.py,sha256=cAJAbAh288a9AL-3yxwFzEM1L26izSJ6wma5aiml_9Y,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
|
|
@@ -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=8n69nYUzsLCvItyYVe7TbxiyfYjgJHqC4sV7GgwL7QI,44652
|
|
55
|
+
golf_mcp-0.1.19.dist-info/licenses/LICENSE,sha256=5_j2f6fTJmvfmUewzElhkpAaXg2grVoxKouOA8ihV6E,11348
|
|
56
|
+
golf_mcp-0.1.19.dist-info/METADATA,sha256=VWwqQwy6gSijjJcjA2A2euWf53gHpZ3KhFRwK8yrE4U,12956
|
|
57
|
+
golf_mcp-0.1.19.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
58
|
+
golf_mcp-0.1.19.dist-info/entry_points.txt,sha256=5y7rHYM8jGpU-nfwdknCm5XsApLulqsnA37MO6BUTYg,43
|
|
59
|
+
golf_mcp-0.1.19.dist-info/top_level.txt,sha256=BQToHcBUufdyhp9ONGMIvPE40jMEtmI20lYaKb4hxOg,5
|
|
60
|
+
golf_mcp-0.1.19.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|