Spaces:
Paused
Paused
separate client and server api key for http and weave tracing
Browse files- HUGGINGFACE_DEPLOYMENT.md +1 -9
- auth.example.env +6 -16
- src/wandb_mcp_server/auth.py +10 -21
- src/wandb_mcp_server/mcp_tools/count_traces.py +1 -0
- src/wandb_mcp_server/mcp_tools/create_report.py +1 -0
- src/wandb_mcp_server/mcp_tools/list_wandb_entities_projects.py +1 -0
- src/wandb_mcp_server/mcp_tools/query_wandb_gql.py +2 -1
- src/wandb_mcp_server/weave_api/service.py +14 -5
HUGGINGFACE_DEPLOYMENT.md
CHANGED
|
@@ -39,15 +39,7 @@ The application runs as a FastAPI server on port 7860 (HF Spaces default) with:
|
|
| 39 |
|
| 40 |
No environment variables are required! The server works without any configuration.
|
| 41 |
|
| 42 |
-
|
| 43 |
-
```
|
| 44 |
-
WANDB_API_KEY=your_api_key_here # Only if you want server-side Weave tracing
|
| 45 |
-
WANDB_ENTITY=your_wandb_entity # For server-side Weave tracing
|
| 46 |
-
MCP_LOGS_WANDB_PROJECT=wandb-mcp-logs # Project for server logs
|
| 47 |
-
WEAVE_DISABLED=false # Set to enable Weave tracing
|
| 48 |
-
```
|
| 49 |
-
|
| 50 |
-
**Note**: For normal operation, users provide their own W&B API keys as Bearer tokens. No server configuration needed.
|
| 51 |
|
| 52 |
## Deployment Steps
|
| 53 |
|
|
|
|
| 39 |
|
| 40 |
No environment variables are required! The server works without any configuration.
|
| 41 |
|
| 42 |
+
**Note**: Users provide their own W&B API keys as Bearer tokens. No server configuration needed.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 43 |
|
| 44 |
## Deployment Steps
|
| 45 |
|
auth.example.env
CHANGED
|
@@ -1,30 +1,20 @@
|
|
| 1 |
-
# W&B MCP Server
|
| 2 |
# Copy this file to .env and add your values
|
| 3 |
|
| 4 |
# ================================
|
| 5 |
-
#
|
| 6 |
# ================================
|
| 7 |
|
| 8 |
-
#
|
| 9 |
# Get your key from: https://wandb.ai/authorize
|
| 10 |
WANDB_API_KEY=your_wandb_api_key_here
|
| 11 |
|
| 12 |
-
# For HTTP transport (optional):
|
| 13 |
-
# Users provide their own API keys as Bearer tokens
|
| 14 |
-
# No server configuration needed
|
| 15 |
-
|
| 16 |
# ================================
|
| 17 |
-
#
|
| 18 |
# ================================
|
| 19 |
|
| 20 |
-
#
|
| 21 |
-
#
|
| 22 |
-
|
| 23 |
-
# Project for MCP operation traces (if Weave tracing enabled)
|
| 24 |
-
# MCP_LOGS_WANDB_PROJECT=wandb-mcp-logs
|
| 25 |
-
|
| 26 |
-
# Disable Weave tracing (set to true to disable)
|
| 27 |
-
# WEAVE_DISABLED=true
|
| 28 |
|
| 29 |
# ================================
|
| 30 |
# DEVELOPMENT ONLY
|
|
|
|
| 1 |
+
# W&B MCP Server Configuration Example
|
| 2 |
# Copy this file to .env and add your values
|
| 3 |
|
| 4 |
# ================================
|
| 5 |
+
# FOR STDIO TRANSPORT
|
| 6 |
# ================================
|
| 7 |
|
| 8 |
+
# Required for STDIO transport only
|
| 9 |
# Get your key from: https://wandb.ai/authorize
|
| 10 |
WANDB_API_KEY=your_wandb_api_key_here
|
| 11 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 12 |
# ================================
|
| 13 |
+
# FOR HTTP TRANSPORT
|
| 14 |
# ================================
|
| 15 |
|
| 16 |
+
# No configuration needed!
|
| 17 |
+
# Users provide their own API keys as Bearer tokens
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 18 |
|
| 19 |
# ================================
|
| 20 |
# DEVELOPMENT ONLY
|
src/wandb_mcp_server/auth.py
CHANGED
|
@@ -135,32 +135,21 @@ async def mcp_auth_middleware(request: Request, call_next):
|
|
| 135 |
wandb_api_key = wandb_api_key.strip()
|
| 136 |
|
| 137 |
# Store the API key in request state for W&B operations
|
| 138 |
-
# The MCP tools should access this from the request context
|
| 139 |
request.state.wandb_api_key = wandb_api_key
|
| 140 |
|
| 141 |
-
#
|
| 142 |
-
#
|
| 143 |
-
|
| 144 |
-
|
| 145 |
-
# Set the clean API key
|
| 146 |
os.environ["WANDB_API_KEY"] = wandb_api_key
|
| 147 |
|
| 148 |
-
# Debug logging
|
| 149 |
-
logger.
|
| 150 |
-
|
| 151 |
-
|
| 152 |
-
|
|
|
|
|
|
|
| 153 |
|
| 154 |
-
try:
|
| 155 |
-
# Continue processing
|
| 156 |
-
response = await call_next(request)
|
| 157 |
-
finally:
|
| 158 |
-
# Restore original environment
|
| 159 |
-
if original_api_key:
|
| 160 |
-
os.environ["WANDB_API_KEY"] = original_api_key
|
| 161 |
-
elif "WANDB_API_KEY" in os.environ:
|
| 162 |
-
del os.environ["WANDB_API_KEY"]
|
| 163 |
-
|
| 164 |
return response
|
| 165 |
|
| 166 |
except HTTPException as e:
|
|
|
|
| 135 |
wandb_api_key = wandb_api_key.strip()
|
| 136 |
|
| 137 |
# Store the API key in request state for W&B operations
|
|
|
|
| 138 |
request.state.wandb_api_key = wandb_api_key
|
| 139 |
|
| 140 |
+
# Set the API key for this request
|
| 141 |
+
# Note: We don't restore the original value because with streaming responses,
|
| 142 |
+
# the tool execution happens after call_next returns. Each request sets its own key.
|
|
|
|
|
|
|
| 143 |
os.environ["WANDB_API_KEY"] = wandb_api_key
|
| 144 |
|
| 145 |
+
# Debug logging
|
| 146 |
+
logger.debug(f"Auth middleware: Set WANDB_API_KEY with length={len(wandb_api_key)}, "
|
| 147 |
+
f"is_40_chars={len(wandb_api_key) == 40}")
|
| 148 |
+
|
| 149 |
+
# Continue processing without restoring the env var
|
| 150 |
+
# Each request will set its own API key
|
| 151 |
+
response = await call_next(request)
|
| 152 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 153 |
return response
|
| 154 |
|
| 155 |
except HTTPException as e:
|
src/wandb_mcp_server/mcp_tools/count_traces.py
CHANGED
|
@@ -176,6 +176,7 @@ def count_traces(
|
|
| 176 |
"""
|
| 177 |
project_id = f"{entity_name}/{project_name}"
|
| 178 |
|
|
|
|
| 179 |
api_key = os.environ.get("WANDB_API_KEY")
|
| 180 |
if not api_key:
|
| 181 |
logger.error("WANDB_API_KEY not found in environment variables.")
|
|
|
|
| 176 |
"""
|
| 177 |
project_id = f"{entity_name}/{project_name}"
|
| 178 |
|
| 179 |
+
# Get API key from environment (set by auth middleware for HTTP, or by user for STDIO)
|
| 180 |
api_key = os.environ.get("WANDB_API_KEY")
|
| 181 |
if not api_key:
|
| 182 |
logger.error("WANDB_API_KEY not found in environment variables.")
|
src/wandb_mcp_server/mcp_tools/create_report.py
CHANGED
|
@@ -130,6 +130,7 @@ def create_report(
|
|
| 130 |
processed_plots_html = None
|
| 131 |
|
| 132 |
try:
|
|
|
|
| 133 |
wandb.init(
|
| 134 |
entity=entity_name, project=project_name, job_type="mcp_report_creation"
|
| 135 |
)
|
|
|
|
| 130 |
processed_plots_html = None
|
| 131 |
|
| 132 |
try:
|
| 133 |
+
# W&B will use WANDB_API_KEY from environment
|
| 134 |
wandb.init(
|
| 135 |
entity=entity_name, project=project_name, job_type="mcp_report_creation"
|
| 136 |
)
|
src/wandb_mcp_server/mcp_tools/list_wandb_entities_projects.py
CHANGED
|
@@ -70,6 +70,7 @@ def list_entity_projects(entity: str | None = None) -> dict[str, list[dict[str,
|
|
| 70 |
- tags: List of project tags
|
| 71 |
"""
|
| 72 |
# Initialize wandb API
|
|
|
|
| 73 |
api = wandb.Api()
|
| 74 |
|
| 75 |
# Merge entity and teams into a single list
|
|
|
|
| 70 |
- tags: List of project tags
|
| 71 |
"""
|
| 72 |
# Initialize wandb API
|
| 73 |
+
# Will use WANDB_API_KEY from environment (set by auth middleware or user)
|
| 74 |
api = wandb.Api()
|
| 75 |
|
| 76 |
# Merge entity and teams into a single list
|
src/wandb_mcp_server/mcp_tools/query_wandb_gql.py
CHANGED
|
@@ -591,7 +591,8 @@ def query_paginated_wandb_gql(
|
|
| 591 |
api = None
|
| 592 |
limit_key = None
|
| 593 |
try:
|
| 594 |
-
|
|
|
|
| 595 |
logger.info(
|
| 596 |
"--- Inside query_paginated_wandb_gql: Step 0: Execute Initial Query ---"
|
| 597 |
)
|
|
|
|
| 591 |
api = None
|
| 592 |
limit_key = None
|
| 593 |
try:
|
| 594 |
+
# Use API key from environment (set by auth middleware for HTTP, or by user for STDIO)
|
| 595 |
+
api = wandb.Api() # Will use WANDB_API_KEY from environment
|
| 596 |
logger.info(
|
| 597 |
"--- Inside query_paginated_wandb_gql: Step 0: Execute Initial Query ---"
|
| 598 |
)
|
src/wandb_mcp_server/weave_api/service.py
CHANGED
|
@@ -62,6 +62,7 @@ class TraceService:
|
|
| 62 |
|
| 63 |
def __init__(
|
| 64 |
self,
|
|
|
|
| 65 |
server_url: Optional[str] = None,
|
| 66 |
retries: int = 3,
|
| 67 |
timeout: int = 10,
|
|
@@ -69,18 +70,26 @@ class TraceService:
|
|
| 69 |
"""Initialize the TraceService.
|
| 70 |
|
| 71 |
Args:
|
|
|
|
| 72 |
server_url: Weave API server URL. Defaults to 'https://trace.wandb.ai'.
|
| 73 |
retries: Number of retries for failed requests.
|
| 74 |
timeout: Request timeout in seconds.
|
| 75 |
"""
|
| 76 |
-
#
|
| 77 |
-
|
| 78 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 79 |
|
| 80 |
# Pass the resolved API key to WeaveApiClient.
|
| 81 |
-
# If
|
| 82 |
self.client = WeaveApiClient(
|
| 83 |
-
api_key=
|
| 84 |
server_url=server_url,
|
| 85 |
retries=retries,
|
| 86 |
timeout=timeout,
|
|
|
|
| 62 |
|
| 63 |
def __init__(
|
| 64 |
self,
|
| 65 |
+
api_key: Optional[str] = None,
|
| 66 |
server_url: Optional[str] = None,
|
| 67 |
retries: int = 3,
|
| 68 |
timeout: int = 10,
|
|
|
|
| 70 |
"""Initialize the TraceService.
|
| 71 |
|
| 72 |
Args:
|
| 73 |
+
api_key: W&B API key. If not provided, uses WANDB_API_KEY env var.
|
| 74 |
server_url: Weave API server URL. Defaults to 'https://trace.wandb.ai'.
|
| 75 |
retries: Number of retries for failed requests.
|
| 76 |
timeout: Request timeout in seconds.
|
| 77 |
"""
|
| 78 |
+
# If no API key provided, try to get from environment
|
| 79 |
+
if api_key is None:
|
| 80 |
+
import os
|
| 81 |
+
# Try to get from environment (set by auth middleware for HTTP or user for STDIO)
|
| 82 |
+
api_key = os.environ.get("WANDB_API_KEY")
|
| 83 |
+
|
| 84 |
+
# If still no key, try get_server_args as fallback
|
| 85 |
+
if not api_key:
|
| 86 |
+
server_config = get_server_args()
|
| 87 |
+
api_key = server_config.wandb_api_key
|
| 88 |
|
| 89 |
# Pass the resolved API key to WeaveApiClient.
|
| 90 |
+
# If api_key is None or "", WeaveApiClient will raise its ValueError.
|
| 91 |
self.client = WeaveApiClient(
|
| 92 |
+
api_key=api_key,
|
| 93 |
server_url=server_url,
|
| 94 |
retries=retries,
|
| 95 |
timeout=timeout,
|