cortexdb-mcp 0.2.0__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.
- cortexdb_mcp/__init__.py +3 -0
- cortexdb_mcp/api.py +132 -0
- cortexdb_mcp/config.py +40 -0
- cortexdb_mcp/insights.py +640 -0
- cortexdb_mcp/server.py +1085 -0
- cortexdb_mcp-0.2.0.dist-info/METADATA +276 -0
- cortexdb_mcp-0.2.0.dist-info/RECORD +9 -0
- cortexdb_mcp-0.2.0.dist-info/WHEEL +4 -0
- cortexdb_mcp-0.2.0.dist-info/entry_points.txt +2 -0
cortexdb_mcp/__init__.py
ADDED
cortexdb_mcp/api.py
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"""REST API for the CortexDB insights engine.
|
|
2
|
+
|
|
3
|
+
Exposes a lightweight FastAPI application that the GTM web dashboard calls to
|
|
4
|
+
display proactive insights. Results are cached with a configurable TTL (default
|
|
5
|
+
5 minutes) so the engine is not re-run on every request.
|
|
6
|
+
|
|
7
|
+
Configuration is read from environment variables:
|
|
8
|
+
|
|
9
|
+
- ``CORTEXDB_URL`` -- CortexDB base URL (default ``http://localhost:3141``)
|
|
10
|
+
- ``CORTEXDB_API_KEY`` -- Optional bearer token
|
|
11
|
+
- ``CORTEXDB_TENANT_ID``-- Optional tenant scope
|
|
12
|
+
- ``INSIGHTS_CACHE_TTL``-- Cache lifetime in seconds (default ``300``)
|
|
13
|
+
|
|
14
|
+
Run directly::
|
|
15
|
+
|
|
16
|
+
uvicorn cortexdb_mcp.api:app --host 0.0.0.0 --port 8080
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from __future__ import annotations
|
|
20
|
+
|
|
21
|
+
import logging
|
|
22
|
+
import os
|
|
23
|
+
import time
|
|
24
|
+
from typing import Any
|
|
25
|
+
|
|
26
|
+
from fastapi import FastAPI
|
|
27
|
+
from fastapi.middleware.cors import CORSMiddleware
|
|
28
|
+
|
|
29
|
+
from cortexdb_mcp.insights import InsightsEngine
|
|
30
|
+
|
|
31
|
+
logger = logging.getLogger("cortexdb_mcp.api")
|
|
32
|
+
|
|
33
|
+
# ---------------------------------------------------------------------------
|
|
34
|
+
# Configuration
|
|
35
|
+
# ---------------------------------------------------------------------------
|
|
36
|
+
|
|
37
|
+
CORTEXDB_URL = os.environ.get("CORTEXDB_URL", "http://localhost:3141")
|
|
38
|
+
CORTEXDB_API_KEY = os.environ.get("CORTEXDB_API_KEY")
|
|
39
|
+
CORTEXDB_TENANT_ID = os.environ.get("CORTEXDB_TENANT_ID")
|
|
40
|
+
INSIGHTS_CACHE_TTL = int(os.environ.get("INSIGHTS_CACHE_TTL", "300"))
|
|
41
|
+
|
|
42
|
+
# ---------------------------------------------------------------------------
|
|
43
|
+
# Cache
|
|
44
|
+
# ---------------------------------------------------------------------------
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class InsightsCache:
|
|
48
|
+
"""Simple in-memory cache with TTL for generated insights."""
|
|
49
|
+
|
|
50
|
+
def __init__(self, ttl_seconds: int = 300) -> None:
|
|
51
|
+
self.ttl_seconds = ttl_seconds
|
|
52
|
+
self._data: list[dict[str, Any]] | None = None
|
|
53
|
+
self._timestamp: float = 0.0
|
|
54
|
+
|
|
55
|
+
def get(self) -> list[dict[str, Any]] | None:
|
|
56
|
+
"""Return cached insights if still valid, otherwise None."""
|
|
57
|
+
if self._data is not None and (time.monotonic() - self._timestamp) < self.ttl_seconds:
|
|
58
|
+
return self._data
|
|
59
|
+
return None
|
|
60
|
+
|
|
61
|
+
def set(self, data: list[dict[str, Any]]) -> None:
|
|
62
|
+
"""Store insights in the cache."""
|
|
63
|
+
self._data = data
|
|
64
|
+
self._timestamp = time.monotonic()
|
|
65
|
+
|
|
66
|
+
def invalidate(self) -> None:
|
|
67
|
+
"""Force-expire the cache."""
|
|
68
|
+
self._data = None
|
|
69
|
+
self._timestamp = 0.0
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
_cache = InsightsCache(ttl_seconds=INSIGHTS_CACHE_TTL)
|
|
73
|
+
|
|
74
|
+
# ---------------------------------------------------------------------------
|
|
75
|
+
# FastAPI app
|
|
76
|
+
# ---------------------------------------------------------------------------
|
|
77
|
+
|
|
78
|
+
app = FastAPI(
|
|
79
|
+
title="CortexDB Insights API",
|
|
80
|
+
description="Proactive insights for the CortexDB GTM web dashboard.",
|
|
81
|
+
version="0.1.0",
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
app.add_middleware(
|
|
85
|
+
CORSMiddleware,
|
|
86
|
+
allow_origins=["*"],
|
|
87
|
+
allow_methods=["GET", "POST", "OPTIONS"],
|
|
88
|
+
allow_headers=["*"],
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def _engine() -> InsightsEngine:
|
|
93
|
+
"""Build a fresh InsightsEngine from environment configuration."""
|
|
94
|
+
return InsightsEngine(
|
|
95
|
+
cortex_url=CORTEXDB_URL,
|
|
96
|
+
api_key=CORTEXDB_API_KEY,
|
|
97
|
+
tenant_id=CORTEXDB_TENANT_ID,
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
@app.get("/api/insights")
|
|
102
|
+
async def get_insights() -> dict[str, Any]:
|
|
103
|
+
"""Return proactive insights as JSON.
|
|
104
|
+
|
|
105
|
+
Results are cached for ``INSIGHTS_CACHE_TTL`` seconds (default 300).
|
|
106
|
+
"""
|
|
107
|
+
cached = _cache.get()
|
|
108
|
+
if cached is not None:
|
|
109
|
+
return {"insights": cached, "cached": True}
|
|
110
|
+
|
|
111
|
+
engine = _engine()
|
|
112
|
+
insights = await engine.generate_all()
|
|
113
|
+
serialized = [i.to_dict() for i in insights]
|
|
114
|
+
_cache.set(serialized)
|
|
115
|
+
return {"insights": serialized, "cached": False}
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
@app.post("/api/insights/refresh")
|
|
119
|
+
async def refresh_insights() -> dict[str, Any]:
|
|
120
|
+
"""Force-refresh the insights cache and return fresh results."""
|
|
121
|
+
_cache.invalidate()
|
|
122
|
+
engine = _engine()
|
|
123
|
+
insights = await engine.generate_all()
|
|
124
|
+
serialized = [i.to_dict() for i in insights]
|
|
125
|
+
_cache.set(serialized)
|
|
126
|
+
return {"insights": serialized, "cached": False}
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
@app.get("/api/health")
|
|
130
|
+
async def health() -> dict[str, str]:
|
|
131
|
+
"""Health check for the insights API."""
|
|
132
|
+
return {"status": "ok"}
|
cortexdb_mcp/config.py
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"""Configuration management for the CortexDB MCP server.
|
|
2
|
+
|
|
3
|
+
Reads settings from environment variables with sensible defaults.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
import os
|
|
9
|
+
from dataclasses import dataclass
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@dataclass(frozen=True)
|
|
13
|
+
class CortexMCPConfig:
|
|
14
|
+
"""Configuration for connecting to a CortexDB instance.
|
|
15
|
+
|
|
16
|
+
Attributes:
|
|
17
|
+
url: Base URL of the CortexDB HTTP API.
|
|
18
|
+
api_key: Optional API key for authenticated access.
|
|
19
|
+
timeout: HTTP request timeout in seconds.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
url: str = "http://localhost:3141"
|
|
23
|
+
api_key: str | None = None
|
|
24
|
+
timeout: float = 30.0
|
|
25
|
+
|
|
26
|
+
@classmethod
|
|
27
|
+
def from_env(cls) -> CortexMCPConfig:
|
|
28
|
+
"""Build configuration from environment variables.
|
|
29
|
+
|
|
30
|
+
Environment variables
|
|
31
|
+
---------------------
|
|
32
|
+
CORTEXDB_URL -- CortexDB base URL (default ``http://localhost:3141``)
|
|
33
|
+
CORTEXDB_API_KEY -- API key (default ``None``)
|
|
34
|
+
CORTEXDB_TIMEOUT -- Request timeout in seconds (default ``30.0``)
|
|
35
|
+
"""
|
|
36
|
+
return cls(
|
|
37
|
+
url=os.environ.get("CORTEXDB_URL", cls.url),
|
|
38
|
+
api_key=os.environ.get("CORTEXDB_API_KEY", cls.api_key),
|
|
39
|
+
timeout=float(os.environ.get("CORTEXDB_TIMEOUT", str(cls.timeout))),
|
|
40
|
+
)
|