iflow-mcp_anton-prosterity-documentation-search-enhanced 1.9.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.
Files changed (26) hide show
  1. documentation_search_enhanced/__init__.py +14 -0
  2. documentation_search_enhanced/__main__.py +6 -0
  3. documentation_search_enhanced/config.json +1674 -0
  4. documentation_search_enhanced/config_manager.py +233 -0
  5. documentation_search_enhanced/config_validator.py +79 -0
  6. documentation_search_enhanced/content_enhancer.py +578 -0
  7. documentation_search_enhanced/docker_manager.py +87 -0
  8. documentation_search_enhanced/logger.py +179 -0
  9. documentation_search_enhanced/main.py +2170 -0
  10. documentation_search_enhanced/project_generator.py +260 -0
  11. documentation_search_enhanced/project_scanner.py +85 -0
  12. documentation_search_enhanced/reranker.py +230 -0
  13. documentation_search_enhanced/site_index_builder.py +274 -0
  14. documentation_search_enhanced/site_index_downloader.py +222 -0
  15. documentation_search_enhanced/site_search.py +1325 -0
  16. documentation_search_enhanced/smart_search.py +473 -0
  17. documentation_search_enhanced/snyk_integration.py +657 -0
  18. documentation_search_enhanced/vector_search.py +303 -0
  19. documentation_search_enhanced/version_resolver.py +189 -0
  20. documentation_search_enhanced/vulnerability_scanner.py +545 -0
  21. documentation_search_enhanced/web_scraper.py +117 -0
  22. iflow_mcp_anton_prosterity_documentation_search_enhanced-1.9.0.dist-info/METADATA +195 -0
  23. iflow_mcp_anton_prosterity_documentation_search_enhanced-1.9.0.dist-info/RECORD +26 -0
  24. iflow_mcp_anton_prosterity_documentation_search_enhanced-1.9.0.dist-info/WHEEL +4 -0
  25. iflow_mcp_anton_prosterity_documentation_search_enhanced-1.9.0.dist-info/entry_points.txt +2 -0
  26. iflow_mcp_anton_prosterity_documentation_search_enhanced-1.9.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,233 @@
1
+ """
2
+ Environment-aware configuration manager for documentation-search-enhanced MCP server.
3
+ Supports development, staging, and production environments with different settings.
4
+ """
5
+
6
+ import json
7
+ import os
8
+ from typing import Dict, Any, Optional
9
+ from importlib import resources
10
+ from dataclasses import dataclass
11
+
12
+
13
+ @dataclass
14
+ class EnvironmentConfig:
15
+ """Configuration for a specific environment"""
16
+
17
+ logging_level: str = "INFO"
18
+ cache_ttl_hours: float = 24
19
+ cache_max_entries: int = 1000
20
+ rate_limit_enabled: bool = True
21
+ requests_per_minute: int = 60
22
+ max_concurrent_requests: int = 10
23
+ request_timeout_seconds: int = 30
24
+ features: Optional[Dict[str, bool]] = None
25
+
26
+ def __post_init__(self):
27
+ if self.features is None:
28
+ self.features = {
29
+ "caching_enabled": True,
30
+ "real_time_search": True,
31
+ "github_integration": True,
32
+ "rate_limiting": self.rate_limit_enabled,
33
+ "analytics": True,
34
+ }
35
+
36
+
37
+ class ConfigManager:
38
+ """Manages environment-specific configurations"""
39
+
40
+ def __init__(self):
41
+ self.environment = self._detect_environment()
42
+ self.base_config = self._load_base_config()
43
+ self.env_config = self._get_environment_config()
44
+
45
+ def _detect_environment(self) -> str:
46
+ """Detect current environment from environment variables"""
47
+ env = os.getenv("ENVIRONMENT", os.getenv("ENV", "development")).lower()
48
+
49
+ # Common environment name mappings
50
+ env_mappings = {
51
+ "dev": "development",
52
+ "develop": "development",
53
+ "development": "development",
54
+ "stage": "staging",
55
+ "staging": "staging",
56
+ "prod": "production",
57
+ "production": "production",
58
+ "test": "testing",
59
+ "testing": "testing",
60
+ }
61
+
62
+ return env_mappings.get(env, "development")
63
+
64
+ def _load_base_config(self) -> Dict[str, Any]:
65
+ """Load base configuration from config.json"""
66
+ try:
67
+ # Try to load from package resources first (for installed package)
68
+ try:
69
+ config_text = resources.read_text(
70
+ "documentation_search_enhanced", "config.json"
71
+ )
72
+ config = json.loads(config_text)
73
+ except (FileNotFoundError, ModuleNotFoundError):
74
+ # Fallback to relative path (for development)
75
+ config_path = os.path.join(os.path.dirname(__file__), "config.json")
76
+ with open(config_path, "r") as f:
77
+ config = json.load(f)
78
+ except Exception:
79
+ # Final fallback - return minimal config
80
+ config = {"docs_urls": {}, "cache": {"enabled": True}}
81
+
82
+ return config
83
+
84
+ def _get_environment_config(self) -> EnvironmentConfig:
85
+ """Get configuration for current environment"""
86
+ environments = {
87
+ "development": EnvironmentConfig(
88
+ logging_level="DEBUG",
89
+ cache_ttl_hours=1,
90
+ cache_max_entries=100,
91
+ rate_limit_enabled=False,
92
+ requests_per_minute=120,
93
+ max_concurrent_requests=20,
94
+ request_timeout_seconds=60,
95
+ features={
96
+ "caching_enabled": True,
97
+ "real_time_search": True,
98
+ "github_integration": True,
99
+ "rate_limiting": False,
100
+ "analytics": True,
101
+ },
102
+ ),
103
+ "testing": EnvironmentConfig(
104
+ logging_level="WARN",
105
+ cache_ttl_hours=0.5,
106
+ cache_max_entries=50,
107
+ rate_limit_enabled=True,
108
+ requests_per_minute=30,
109
+ max_concurrent_requests=5,
110
+ request_timeout_seconds=15,
111
+ features={
112
+ "caching_enabled": False,
113
+ "real_time_search": True,
114
+ "github_integration": False,
115
+ "rate_limiting": True,
116
+ "analytics": False,
117
+ },
118
+ ),
119
+ "staging": EnvironmentConfig(
120
+ logging_level="INFO",
121
+ cache_ttl_hours=12,
122
+ cache_max_entries=500,
123
+ rate_limit_enabled=True,
124
+ requests_per_minute=60,
125
+ max_concurrent_requests=10,
126
+ request_timeout_seconds=30,
127
+ features={
128
+ "caching_enabled": True,
129
+ "real_time_search": True,
130
+ "github_integration": True,
131
+ "rate_limiting": True,
132
+ "analytics": True,
133
+ },
134
+ ),
135
+ "production": EnvironmentConfig(
136
+ logging_level="ERROR",
137
+ cache_ttl_hours=24,
138
+ cache_max_entries=1000,
139
+ rate_limit_enabled=True,
140
+ requests_per_minute=60,
141
+ max_concurrent_requests=10,
142
+ request_timeout_seconds=30,
143
+ features={
144
+ "caching_enabled": True,
145
+ "real_time_search": True,
146
+ "github_integration": True,
147
+ "rate_limiting": True,
148
+ "analytics": True,
149
+ },
150
+ ),
151
+ }
152
+
153
+ return environments.get(self.environment, environments["development"])
154
+
155
+ def get_config(self) -> Dict[str, Any]:
156
+ """Get merged configuration for current environment"""
157
+ # Start with base config
158
+ merged_config = self.base_config.copy()
159
+
160
+ # Override with environment-specific settings
161
+ if "server_config" not in merged_config:
162
+ merged_config["server_config"] = {}
163
+
164
+ merged_config["server_config"].update(
165
+ {
166
+ "environment": self.environment,
167
+ "logging_level": self.env_config.logging_level,
168
+ "max_concurrent_requests": self.env_config.max_concurrent_requests,
169
+ "request_timeout_seconds": self.env_config.request_timeout_seconds,
170
+ "features": self.env_config.features,
171
+ }
172
+ )
173
+
174
+ if "cache" not in merged_config:
175
+ merged_config["cache"] = {}
176
+
177
+ features = self.env_config.features or {}
178
+ merged_config["cache"].update(
179
+ {
180
+ "ttl_hours": self.env_config.cache_ttl_hours,
181
+ "max_entries": self.env_config.cache_max_entries,
182
+ "enabled": features.get("caching_enabled", True),
183
+ }
184
+ )
185
+
186
+ if "rate_limiting" not in merged_config:
187
+ merged_config["rate_limiting"] = {}
188
+
189
+ merged_config["rate_limiting"].update(
190
+ {
191
+ "enabled": self.env_config.rate_limit_enabled,
192
+ "requests_per_minute": self.env_config.requests_per_minute,
193
+ }
194
+ )
195
+
196
+ return merged_config
197
+
198
+ def get_docs_urls(self) -> Dict[str, str]:
199
+ """Get documentation URLs with environment filtering"""
200
+ docs_urls = {}
201
+ config = self.get_config()
202
+
203
+ for lib_name, lib_data in config.get("docs_urls", {}).items():
204
+ if isinstance(lib_data, dict):
205
+ # Check if library is enabled for this environment
206
+ environments = lib_data.get(
207
+ "environments", ["development", "staging", "production"]
208
+ )
209
+ if self.environment in environments:
210
+ docs_urls[lib_name] = lib_data.get("url", "")
211
+ else:
212
+ # Legacy format - always include
213
+ docs_urls[lib_name] = lib_data
214
+
215
+ return docs_urls
216
+
217
+ def is_feature_enabled(self, feature_name: str) -> bool:
218
+ """Check if a feature is enabled in current environment"""
219
+ features = self.env_config.features or {}
220
+ return features.get(feature_name, False)
221
+
222
+ def get_cache_config(self) -> Dict[str, Any]:
223
+ """Get cache configuration for current environment"""
224
+ features = self.env_config.features or {}
225
+ return {
226
+ "ttl_hours": self.env_config.cache_ttl_hours,
227
+ "max_entries": self.env_config.cache_max_entries,
228
+ "enabled": features.get("caching_enabled", True),
229
+ }
230
+
231
+
232
+ # Global configuration manager
233
+ config_manager = ConfigManager()
@@ -0,0 +1,79 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Pydantic models for validating the config.json file.
4
+ """
5
+
6
+ from pydantic import BaseModel, Field, HttpUrl, field_validator
7
+ from typing import Dict, List, Optional
8
+
9
+
10
+ class AutoApproveConfig(BaseModel):
11
+ get_docs: bool = True
12
+ suggest_libraries: bool = True
13
+ health_check: bool = True
14
+ get_cache_stats: bool = True
15
+ clear_cache: bool = False
16
+
17
+
18
+ class FeatureConfig(BaseModel):
19
+ caching_enabled: bool = True
20
+ real_time_search: bool = True
21
+ github_integration: bool = True
22
+ rate_limiting: bool = True
23
+ analytics: bool = True
24
+
25
+
26
+ class ServerConfig(BaseModel):
27
+ name: str = "documentation-search-enhanced"
28
+ version: Optional[str] = None
29
+ logging_level: str = "INFO"
30
+ max_concurrent_requests: int = 10
31
+ request_timeout_seconds: int = 30
32
+ auto_approve: AutoApproveConfig = Field(default_factory=AutoApproveConfig)
33
+ features: FeatureConfig = Field(default_factory=FeatureConfig)
34
+
35
+
36
+ class CacheConfig(BaseModel):
37
+ ttl_hours: int = 24
38
+ max_entries: int = 1000
39
+ enabled: bool = True
40
+ persistence_enabled: bool = False
41
+ cleanup_interval_minutes: int = 60
42
+ persist_path: Optional[str] = None
43
+
44
+
45
+ class RateLimitingConfig(BaseModel):
46
+ enabled: bool = True
47
+ requests_per_minute: int = 60
48
+ burst_requests: int = 10
49
+
50
+
51
+ class DocsURL(BaseModel):
52
+ url: HttpUrl
53
+ category: str
54
+ learning_curve: str
55
+ tags: List[str]
56
+ priority: str
57
+ auto_approve: bool
58
+
59
+
60
+ class Config(BaseModel):
61
+ version: str
62
+ server_config: ServerConfig = Field(default_factory=ServerConfig)
63
+ cache: CacheConfig = Field(default_factory=CacheConfig)
64
+ rate_limiting: RateLimitingConfig = Field(default_factory=RateLimitingConfig)
65
+ docs_urls: Dict[str, DocsURL]
66
+ categories: Dict[str, List[str]]
67
+
68
+ @field_validator("server_config", "cache", "rate_limiting", mode="before")
69
+ @classmethod
70
+ def check_nested_dicts(cls, v):
71
+ return v or {}
72
+
73
+
74
+ def validate_config(data: Dict) -> Config:
75
+ """
76
+ Validates the configuration dictionary against the Pydantic model.
77
+ Raises a ValidationError if the data is invalid.
78
+ """
79
+ return Config.model_validate(data)