File size: 13,522 Bytes
108dc63 1e513bd ff320d6 09410e1 1e513bd 606e7e5 108dc63 1e513bd 4c3e379 1e513bd 63ee82a 108dc63 63ee82a e6a445e 108dc63 e6a445e 63ee82a e6a445e 108dc63 1e513bd 4c3e379 1e513bd 63ee82a 4c3e379 63ee82a 4c3e379 63ee82a 1e513bd 63ee82a 1e513bd de8148c 1e513bd 63ee82a 108dc63 1e513bd 4c3e379 1e513bd 4c3e379 1e513bd 4c3e379 1e513bd 108dc63 1e513bd 940235a cd6c13a 1e513bd 4c3e379 1e513bd 4c3e379 1e513bd de8148c 1e513bd 09410e1 ff320d6 606e7e5 09410e1 606e7e5 ff320d6 606e7e5 ff320d6 606e7e5 30fa53f 606e7e5 108dc63 606e7e5 4c3e379 606e7e5 ff320d6 606e7e5 ff320d6 606e7e5 ff320d6 1e513bd 108dc63 de8148c 4c3e379 1e513bd 108dc63 1e513bd 63ee82a 0359cf2 63ee82a 108dc63 63ee82a 1e513bd 0359cf2 63ee82a 108dc63 63ee82a 1e513bd 63ee82a 1e513bd 63ee82a 1e513bd 606e7e5 cc6556b 1e513bd 108dc63 1e513bd de8148c 1e513bd de8148c 1e513bd 4c3e379 1e513bd |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 |
import api_client
import json
from datetime import datetime, timedelta
import hashlib
import psycopg2
import os
from dotenv import load_dotenv
# Load environment variables from .env file
load_dotenv()
def validate_api_configuration(
mcp_api_key,
name,
description,
method,
base_url,
endpoint,
param_keys_values,
header_keys_values,
additional_params,
schedule_interval_minutes,
stop_after_hours,
time_to_start,
):
"""
TOOL: Validate and store API configuration for monitoring.
PURPOSE: Test an API endpoint and store the configuration if successful. This is STEP 1
of the monitoring setup process. If validation fails, retry with corrected parameters. If successful, use the returned config_id in activate_monitoring() function.
⚠️ CRITICAL: Even if success=True, you MUST manually check the 'sample_response' field
before proceeding to activate_monitoring(). The API call may return success=True but contain
error messages (like "401 Unauthorized", "Invalid API key", etc.) in the sample_response.
WORKFLOW:
1. Call this function to validate API configuration
2. If success=False: Fix parameters and retry this function
3. If success=True: MANUALLY INSPECT the 'sample_response' field for errors
4. If sample_response contains error messages: Fix API parameters and retry validation
5. If sample_response looks valid: Use config_id in activate_monitoring() to activate monitoring
Parameters:
- mcp_api_key: MCP API key serves as user identifier
- name: User-friendly name for the monitoring task
- description: Description of what is being monitored
- method: HTTP method (GET, POST, PUT, DELETE)
- base_url: The base URL of the API
- endpoint: The specific API endpoint
- param_keys_values: Parameter key-value pairs, one per line
- header_keys_values: Header key-value pairs, one per line
- additional_params: Optional JSON string for complex parameters
- schedule_interval_minutes: Minutes between calls
- stop_after_hours: Hours after which to stop (max 168 = 1 week)
- time_to_start: When to start the monitoring (datetime string or None for immediate)
Input Examples:
1. Simple GET request to monitor stock price:
mcp_api_key: "your_mcp_key_here"
name: "NVDA Stock Price"
description: "Monitor NVIDIA stock price every 30 minutes"
method: "GET"
base_url: "https://api.example.com"
endpoint: "stocks/NVDA"
param_keys_values: "symbol: NVDA\ninterval: 1min"
header_keys_values: "Authorization: Bearer your_token"
additional_params: "{}"
schedule_interval_minutes: 30
stop_after_hours: 24
time_to_start: ""
2. API with complex parameters:
mcp_api_key: "your_mcp_key_here"
name: "Weather Alert Monitor"
description: "Monitor severe weather alerts"
method: "POST"
base_url: "https://api.weather.com"
endpoint: "alerts"
param_keys_values: "lat: 40.7128\nlon: -74.0060"
header_keys_values: "X-API-Key: weather_key\nContent-Type: application/json"
additional_params: '{"severity": ["severe", "extreme"], "types": ["tornado", "hurricane"]}'
schedule_interval_minutes: 15
stop_after_hours: 48
time_to_start: "2024-06-15 09:00:00"
Returns:
- Dictionary with success status, config_id (needed for setup_scheduler), message, and sample_response
Example return:
{
"success": True,
"config_id": 123,
"message": "API call tested and stored successfully",
"sample_response": {...},
"stop_at": "2025-06-11T12:00:00Z",
"start_at": "2025-06-04T12:00:00Z"
}
NEXT STEP: If success=True, call activate_monitoring(config_id, mcp_api_key) to activate monitoring
"""
try:
# Validate input parameters
if not mcp_api_key or not mcp_api_key.strip():
return {
"success": False,
"message": "MCP API key is required",
"config_id": None,
}
if not name or not name.strip():
return {
"success": False,
"message": "Monitoring name is required",
"config_id": None,
}
if not base_url or not base_url.strip():
return {
"success": False,
"message": "Base URL is required",
"config_id": None,
}
if not method or method not in ["GET", "POST", "PUT", "DELETE"]:
return {
"success": False,
"message": "Valid HTTP method is required (GET, POST, PUT, DELETE)",
"config_id": None,
}
if (
not isinstance(schedule_interval_minutes, (int, float))
or schedule_interval_minutes < 1
or schedule_interval_minutes > 1440
):
return {
"success": False,
"message": "Schedule interval must be between 1 and 1440 minutes",
"config_id": None,
}
if (
not isinstance(stop_after_hours, (int, float))
or stop_after_hours < 1
or stop_after_hours > 168
):
return {
"success": False,
"message": "Stop after hours must be between 1 and 168 hours (1 week max)",
"config_id": None,
}
# Validate time_to_start if provided
if time_to_start:
try:
parsed_start_time = datetime.fromisoformat(
time_to_start.replace("Z", "+00:00")
)
if parsed_start_time < datetime.now():
return {
"success": False,
"message": "Start time cannot be in the past",
"config_id": None,
}
except ValueError:
return {
"success": False,
"message": "Invalid start time format",
"config_id": None,
}
else:
parsed_start_time = datetime.now() # Test the API call
result = api_client.call_api(
method=method,
base_url=base_url,
endpoint=endpoint,
param_keys_values=param_keys_values,
header_keys_values=header_keys_values,
additional_params=additional_params,
)
# Check if the API call failed
if isinstance(result, str) and result.startswith("Error"):
return {
"success": False,
"message": f"API call test failed: {result}",
"config_id": None,
}
# Generate config ID and calculate timestamps
config_data = {
"mcp_api_key": mcp_api_key,
"name": name,
"description": description,
"method": method,
"base_url": base_url,
"endpoint": endpoint,
"param_keys_values": param_keys_values,
"header_keys_values": header_keys_values,
"additional_params": additional_params,
"schedule_interval_minutes": schedule_interval_minutes,
"stop_after_hours": stop_after_hours,
}
# Generate unique config ID
config_str = json.dumps(config_data, sort_keys=True) + str(
datetime.now().timestamp()
)
config_id = int(hashlib.md5(config_str.encode()).hexdigest()[:7], 16)
# Calculate timestamps
created_at = datetime.now()
stop_at = parsed_start_time + timedelta(hours=stop_after_hours)
# Add metadata to config
config_data.update(
{
"config_id": config_id,
"created_at": created_at.isoformat(),
"start_at": parsed_start_time.isoformat(),
"stop_at": stop_at.isoformat(),
# @JamezyKim This will be used to track the status of whether the api is confirmed or not
"is_validated": False,
"api_response": result,
}
)
# Store configuration
# TODO: Implement database
db_password = os.getenv("DB_PASSWORD")
if not db_password:
return {
"success": False,
"message": "Database password not found in environment variables. Please set DB_PASSWORD.",
"config_id": None,
}
conn = psycopg2.connect(
database="testdb",
user="postgres",
host="localhost",
password=db_password,
port=5432,
)
cur = conn.cursor()
cur.execute(
"""
INSERT INTO api_configurations (
config_id, mcp_api_key, name, description, method,
base_url, endpoint, params, headers, additional_params,
is_validated, is_active, stop, schedule_interval_minutes,
time_to_start, created_at, validated_at
) VALUES (
%s, %s, %s, %s, %s, %s, %s, %s, %s, %s,
%s, %s, %s, %s, %s, %s, %s
)
""",
(
config_id,
mcp_api_key,
name,
description,
method,
base_url,
endpoint,
json.dumps(api_client.parse_key_value_string(param_keys_values)),
json.dumps(api_client.parse_key_value_string(header_keys_values)),
additional_params,
False,
False,
False,
schedule_interval_minutes,
parsed_start_time,
created_at,
None,
),
)
conn.commit()
cur.execute("SELECT * FROM api_configurations WHERE id = %s", (config_id,))
rows = cur.fetchall()
for row in rows:
print(row)
conn.close()
cur.close()
# Return success response
return {
"success": True,
"config_id": config_id,
"message": f"API call tested and stored successfully for '{name}'. Use this config_id in activate_monitoring() to activate monitoring.",
"sample_response": (
json.loads(result)
if result.startswith("{") or result.startswith("[")
else result
),
"start_at": parsed_start_time.isoformat(),
"stop_at": stop_at.isoformat(),
"schedule_interval_minutes": schedule_interval_minutes,
}
except Exception as e:
return {
"success": False,
"message": f"Validation failed with error: {str(e)}",
"config_id": None,
}
def activate_monitoring(config_id, mcp_api_key):
"""
TOOL: Activate periodic monitoring for a validated API configuration.
PURPOSE: Start automated recurring API calls based on a previously validated configuration.
This is STEP 2 of the monitoring setup process.
PREREQUISITE: Must call validate_api_configuration() first and obtain a config_id from successful validation. Make sure that the sample_response is what you expect
to see before proceeding with this function.
WORKFLOW:
1. First call validate_api_configuration() to get config_id
2. If validation successful, call this function with the config_id
3. Monitoring will run automatically according to the validated schedule
Parameters:
- config_id: The ID from successful validate_api_configuration() execution (required)
- mcp_api_key: User's MCP API key for verification (must match validation step)
Input Examples:
1. Activate scheduler for stock monitoring:
config_id: 123456789
mcp_api_key: "your_mcp_key_here"
2. Activate scheduler for weather alerts:
config_id: 987654321
mcp_api_key: "your_mcp_key_here"
NOTE: The config_id must be obtained from a successful validate_api_configuration() response.
The mcp_api_key must match the one used during validation.
Returns:
- Dictionary with success status and scheduling details
Example return:
{
"success": True,
"message": "Scheduler activated for 'NVDA Stock Price'",
"config_id": 123,
"schedule_interval_minutes": 20,
"stop_at": "2025-06-11T12:00:00Z",
"next_call_at": "2025-06-04T12:20:00Z"
}
ERROR HANDLING: If config_id not found or invalid, returns success=False with error message
"""
return {
"success": False,
"message": "Function not implemented yet; this is a placeholder.",
"config_id": config_id,
}
## testing
if __name__ == "__main__":
# Example usage
response = validate_api_configuration(
mcp_api_key="your_api_key",
name="Dog Facts API",
description="Monitor random dog facts from a free API",
method="GET",
base_url="https://dogapi.dog",
endpoint="api/v2/facts",
param_keys_values="",
header_keys_values="",
additional_params="{}",
schedule_interval_minutes=20,
stop_after_hours=24,
time_to_start="",
)
print(response)
|