prompt-capability-optimizer 1.0.0
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.
- package/LICENSE +21 -0
- package/README.md +165 -0
- package/SKILL.md +275 -0
- package/adapters/environment_adapters.md +94 -0
- package/adapters/host_capabilities.json +135 -0
- package/bin/cli.js +33 -0
- package/index.js +54 -0
- package/package.json +51 -0
- package/prompt_capability_optimizer/__init__.py +35 -0
- package/prompt_capability_optimizer/__main__.py +7 -0
- package/prompt_capability_optimizer/adapters/__init__.py +21 -0
- package/prompt_capability_optimizer/adapters/agent_adapters.py +281 -0
- package/prompt_capability_optimizer/adapters/host_adapter.py +48 -0
- package/prompt_capability_optimizer/capabilities/__init__.py +7 -0
- package/prompt_capability_optimizer/capabilities/extractor.py +92 -0
- package/prompt_capability_optimizer/capabilities/graph.py +53 -0
- package/prompt_capability_optimizer/classification/__init__.py +6 -0
- package/prompt_capability_optimizer/classification/task_classifier.py +126 -0
- package/prompt_capability_optimizer/cli.py +85 -0
- package/prompt_capability_optimizer/config.py +42 -0
- package/prompt_capability_optimizer/critique/__init__.py +6 -0
- package/prompt_capability_optimizer/critique/self_critique_engine.py +144 -0
- package/prompt_capability_optimizer/discovery/__init__.py +16 -0
- package/prompt_capability_optimizer/discovery/find_skills_adapter.py +143 -0
- package/prompt_capability_optimizer/discovery/local_discovery.py +114 -0
- package/prompt_capability_optimizer/discovery/mcp_discovery.py +145 -0
- package/prompt_capability_optimizer/discovery/registry.py +52 -0
- package/prompt_capability_optimizer/discovery/web_discovery.py +157 -0
- package/prompt_capability_optimizer/engine.py +201 -0
- package/prompt_capability_optimizer/intent/__init__.py +6 -0
- package/prompt_capability_optimizer/intent/intent_analyzer.py +61 -0
- package/prompt_capability_optimizer/models.py +162 -0
- package/prompt_capability_optimizer/optimization/__init__.py +8 -0
- package/prompt_capability_optimizer/optimization/execution_pass.py +52 -0
- package/prompt_capability_optimizer/optimization/optimizer.py +85 -0
- package/prompt_capability_optimizer/optimization/semantic_pass.py +113 -0
- package/prompt_capability_optimizer/scoring/__init__.py +7 -0
- package/prompt_capability_optimizer/scoring/deduplicator.py +46 -0
- package/prompt_capability_optimizer/scoring/scoring_engine.py +34 -0
- package/prompt_capability_optimizer/security/__init__.py +14 -0
- package/prompt_capability_optimizer/security/governance.py +41 -0
- package/prompt_capability_optimizer/security/injection_detector.py +60 -0
- package/prompt_capability_optimizer/security/secret_protector.py +61 -0
- package/prompt_capability_optimizer/security/trust_engine.py +96 -0
- package/prompt_capability_optimizer/verification/__init__.py +6 -0
- package/prompt_capability_optimizer/verification/verification_engine.py +101 -0
- package/references/capability_graph.md +83 -0
- package/references/cross_agent_matrix.md +62 -0
- package/references/prompt_engineering_standards.md +90 -0
- package/references/scoring_rubric.md +49 -0
- package/references/security_and_trust.md +48 -0
- package/scripts/capability_checker.py +88 -0
- package/scripts/prompt_optimizer_engine.py +41 -0
- package/templates/execution_plan_template.md +51 -0
- package/templates/optimized_prompt_template.md +55 -0
- package/templates/verification_matrix_template.md +26 -0
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# Copyright (c) 2026 Mahmoud Abdelhameid (Develper.net@gmail.com). All rights reserved.
|
|
2
|
+
# Licensed under the MIT License.
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
Find-Skills Ecosystem Adapter
|
|
6
|
+
=============================
|
|
7
|
+
Real runtime integration for the open agent skills ecosystem (npx skills find).
|
|
8
|
+
Extracts verified packages, parses structured records, handles CLI failures gracefully,
|
|
9
|
+
and prevents automatic installation during discovery.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
import shutil
|
|
13
|
+
import subprocess
|
|
14
|
+
import json
|
|
15
|
+
import re
|
|
16
|
+
from typing import List, Dict, Any, Optional
|
|
17
|
+
from ..models import Resource, ResourceType, RiskLevel
|
|
18
|
+
|
|
19
|
+
class FindSkillsAdapter:
|
|
20
|
+
|
|
21
|
+
TRUSTED_ORGS = {"vercel-labs", "anthropics", "google", "microsoft", "github", "composiohq"}
|
|
22
|
+
|
|
23
|
+
def __init__(self):
|
|
24
|
+
self.cli_available = shutil.which("npx") is not None
|
|
25
|
+
self.version: Optional[str] = None
|
|
26
|
+
self._query_cache: Dict[str, List[Resource]] = {}
|
|
27
|
+
if self.cli_available:
|
|
28
|
+
self._probe_version()
|
|
29
|
+
|
|
30
|
+
def _probe_version(self):
|
|
31
|
+
try:
|
|
32
|
+
res = subprocess.run(
|
|
33
|
+
["npx", "--version"],
|
|
34
|
+
capture_output=True,
|
|
35
|
+
text=True,
|
|
36
|
+
timeout=4
|
|
37
|
+
)
|
|
38
|
+
if res.returncode == 0:
|
|
39
|
+
self.version = res.stdout.strip()
|
|
40
|
+
else:
|
|
41
|
+
self.cli_available = False
|
|
42
|
+
except Exception:
|
|
43
|
+
self.cli_available = False
|
|
44
|
+
|
|
45
|
+
def search(self, query: str, limit: int = 5) -> List[Resource]:
|
|
46
|
+
"""
|
|
47
|
+
Executes capability search against the open skills ecosystem.
|
|
48
|
+
Handles missing CLI, timeouts, and network unavailability gracefully.
|
|
49
|
+
"""
|
|
50
|
+
query_key = query.lower().strip()
|
|
51
|
+
if not query_key:
|
|
52
|
+
return []
|
|
53
|
+
|
|
54
|
+
if query_key in self._query_cache:
|
|
55
|
+
return self._query_cache[query_key][:limit]
|
|
56
|
+
|
|
57
|
+
if not self.cli_available:
|
|
58
|
+
return []
|
|
59
|
+
|
|
60
|
+
results: List[Resource] = []
|
|
61
|
+
try:
|
|
62
|
+
# Execute skills find query without any install flags
|
|
63
|
+
cmd = ["npx", "--yes", "skills", "find", query_key]
|
|
64
|
+
proc = subprocess.run(
|
|
65
|
+
cmd,
|
|
66
|
+
capture_output=True,
|
|
67
|
+
text=True,
|
|
68
|
+
timeout=8
|
|
69
|
+
)
|
|
70
|
+
if proc.returncode == 0 and proc.stdout:
|
|
71
|
+
results = self._parse_skills_output(proc.stdout, query_key)
|
|
72
|
+
except (subprocess.TimeoutExpired, FileNotFoundError, PermissionError, OSError):
|
|
73
|
+
# Graceful fallback: return empty list without failing the entire optimization pipeline
|
|
74
|
+
results = []
|
|
75
|
+
except Exception:
|
|
76
|
+
results = []
|
|
77
|
+
|
|
78
|
+
self._query_cache[query_key] = results
|
|
79
|
+
return results[:limit]
|
|
80
|
+
|
|
81
|
+
def _parse_skills_output(self, output: str, query: str) -> List[Resource]:
|
|
82
|
+
items: List[Resource] = []
|
|
83
|
+
lines = output.splitlines()
|
|
84
|
+
|
|
85
|
+
for line in lines:
|
|
86
|
+
line = line.strip()
|
|
87
|
+
if not line or line.startswith("#") or line.startswith("Browse") or "skills.sh" in line.lower():
|
|
88
|
+
continue
|
|
89
|
+
|
|
90
|
+
match = re.search(r"^([a-zA-Z0-9_\-\.\/]+)(?:\s*\(([\d\w\+]+)\s*installs?\))?(?:\s*[-–—:]\s*(.+))?$", line)
|
|
91
|
+
if match:
|
|
92
|
+
pkg_name = match.group(1).strip()
|
|
93
|
+
installs_str = match.group(2) or "0"
|
|
94
|
+
desc = match.group(3) or ""
|
|
95
|
+
|
|
96
|
+
# Provenance and verified publisher check
|
|
97
|
+
org = pkg_name.split("/")[0] if "/" in pkg_name else ""
|
|
98
|
+
is_trusted_org = org.lower() in self.TRUSTED_ORGS
|
|
99
|
+
|
|
100
|
+
# Parse install count metric for reputation
|
|
101
|
+
installs = 0
|
|
102
|
+
if "k" in installs_str.lower():
|
|
103
|
+
try:
|
|
104
|
+
installs = int(float(installs_str.lower().replace("k", "").replace("+", "")) * 1000)
|
|
105
|
+
except ValueError:
|
|
106
|
+
installs = 0
|
|
107
|
+
else:
|
|
108
|
+
try:
|
|
109
|
+
installs = int(installs_str.replace("+", ""))
|
|
110
|
+
except ValueError:
|
|
111
|
+
installs = 0
|
|
112
|
+
|
|
113
|
+
reputation_score = min(10.0, 4.0 + (installs / 20000.0 * 5.0))
|
|
114
|
+
trust_score = 9.0 if is_trusted_org else min(7.5, 4.0 + (installs / 50000.0 * 3.5))
|
|
115
|
+
|
|
116
|
+
res = Resource(
|
|
117
|
+
id=f"find-skills:{pkg_name}",
|
|
118
|
+
name=pkg_name,
|
|
119
|
+
type=ResourceType.SKILL,
|
|
120
|
+
source="skills.sh",
|
|
121
|
+
capabilities=[query.lower(), f"skill-{org}" if org else "skill-community"],
|
|
122
|
+
location=f"https://skills.sh/{pkg_name}",
|
|
123
|
+
relevance=7.5,
|
|
124
|
+
capability_match=8.0,
|
|
125
|
+
quality=8.0 if len(desc) > 20 else 6.0,
|
|
126
|
+
trust=trust_score,
|
|
127
|
+
reputation=reputation_score,
|
|
128
|
+
compatibility=8.5,
|
|
129
|
+
freshness=8.0,
|
|
130
|
+
overhead=3.0,
|
|
131
|
+
risk=1.5 if is_trusted_org else 3.0,
|
|
132
|
+
risk_level=RiskLevel.EXTERNAL_SIDE_EFFECT,
|
|
133
|
+
permissions=["install_required"],
|
|
134
|
+
metadata={
|
|
135
|
+
"install_command": f"npx skills add {pkg_name}",
|
|
136
|
+
"installs": installs_str,
|
|
137
|
+
"description": desc,
|
|
138
|
+
"trusted_org": is_trusted_org,
|
|
139
|
+
"requires_approval": True
|
|
140
|
+
}
|
|
141
|
+
)
|
|
142
|
+
items.append(res)
|
|
143
|
+
return items
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# Copyright (c) 2026 Mahmoud Abdelhameid (Develper.net@gmail.com). All rights reserved.
|
|
2
|
+
# Licensed under the MIT License.
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
Real Local Skill Discovery
|
|
6
|
+
==========================
|
|
7
|
+
Inspects filesystem paths across project and user roots, parses SKILL.md frontmatter,
|
|
8
|
+
and creates normalized Resource instances.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import os
|
|
12
|
+
import re
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
from typing import List, Dict, Any, Optional
|
|
15
|
+
from ..models import Resource, ResourceType, RiskLevel
|
|
16
|
+
|
|
17
|
+
class LocalSkillDiscovery:
|
|
18
|
+
|
|
19
|
+
@staticmethod
|
|
20
|
+
def parse_skill_frontmatter(file_path: Path) -> Dict[str, str]:
|
|
21
|
+
metadata = {"name": file_path.parent.name, "description": ""}
|
|
22
|
+
try:
|
|
23
|
+
content = file_path.read_text(encoding="utf-8", errors="replace")
|
|
24
|
+
# Parse YAML frontmatter between --- and ---
|
|
25
|
+
match = re.search(r"^---\s*\n(.*?)\n---\s*\n", content, re.DOTALL)
|
|
26
|
+
if match:
|
|
27
|
+
yaml_text = match.group(1)
|
|
28
|
+
for line in yaml_text.splitlines():
|
|
29
|
+
if ":" in line:
|
|
30
|
+
k, v = line.split(":", 1)
|
|
31
|
+
metadata[k.strip().lower()] = v.strip().strip("'\"")
|
|
32
|
+
else:
|
|
33
|
+
# Fallback to first heading
|
|
34
|
+
h1 = re.search(r"^#\s+(.+)$", content, re.MULTILINE)
|
|
35
|
+
if h1:
|
|
36
|
+
metadata["name"] = h1.group(1).strip()
|
|
37
|
+
except Exception:
|
|
38
|
+
pass
|
|
39
|
+
return metadata
|
|
40
|
+
|
|
41
|
+
@classmethod
|
|
42
|
+
def discover(cls, custom_roots: Optional[List[Path]] = None) -> List[Resource]:
|
|
43
|
+
home = Path.home()
|
|
44
|
+
cwd = Path.cwd()
|
|
45
|
+
|
|
46
|
+
search_roots = custom_roots or [
|
|
47
|
+
cwd / ".gemini" / "skills",
|
|
48
|
+
cwd / ".claude" / "skills",
|
|
49
|
+
cwd / ".cursor" / "skills",
|
|
50
|
+
cwd / ".cline" / "skills",
|
|
51
|
+
cwd / "skills",
|
|
52
|
+
cwd / ".skills",
|
|
53
|
+
home / ".gemini" / "config" / "skills",
|
|
54
|
+
home / ".gemini" / "antigravity" / "builtin" / "skills",
|
|
55
|
+
home / ".claude" / "skills",
|
|
56
|
+
home / ".config" / "agent" / "skills"
|
|
57
|
+
]
|
|
58
|
+
|
|
59
|
+
discovered: List[Resource] = []
|
|
60
|
+
seen_names = set()
|
|
61
|
+
|
|
62
|
+
for base in search_roots:
|
|
63
|
+
if not base.exists() or not base.is_dir():
|
|
64
|
+
continue
|
|
65
|
+
|
|
66
|
+
try:
|
|
67
|
+
for item in base.iterdir():
|
|
68
|
+
if item.is_dir():
|
|
69
|
+
skill_file = item / "SKILL.md"
|
|
70
|
+
if skill_file.exists():
|
|
71
|
+
meta = cls.parse_skill_frontmatter(skill_file)
|
|
72
|
+
name = meta.get("name", item.name)
|
|
73
|
+
if name in seen_names:
|
|
74
|
+
continue
|
|
75
|
+
seen_names.add(name)
|
|
76
|
+
|
|
77
|
+
is_builtin = "builtin" in str(base).lower()
|
|
78
|
+
is_user = home in skill_file.parents
|
|
79
|
+
scope = "builtin" if is_builtin else ("user" if is_user else "project")
|
|
80
|
+
trust_score = 9.5 if is_builtin else (8.5 if not is_user else 8.0)
|
|
81
|
+
|
|
82
|
+
desc = meta.get("description", "")
|
|
83
|
+
# Derive capabilities from name and description
|
|
84
|
+
tokens = set(re.findall(r"[A-Za-z0-9_\-]+", f"{name} {desc}".lower()))
|
|
85
|
+
|
|
86
|
+
resource = Resource(
|
|
87
|
+
id=f"skill:{name}",
|
|
88
|
+
name=name,
|
|
89
|
+
type=ResourceType.SKILL,
|
|
90
|
+
source=f"local_{scope}",
|
|
91
|
+
capabilities=list(tokens),
|
|
92
|
+
location=str(skill_file.resolve()),
|
|
93
|
+
relevance=6.0,
|
|
94
|
+
capability_match=6.0,
|
|
95
|
+
quality=8.5 if len(desc) > 30 else 6.0,
|
|
96
|
+
trust=trust_score,
|
|
97
|
+
reputation=8.0,
|
|
98
|
+
compatibility=9.5,
|
|
99
|
+
freshness=8.0,
|
|
100
|
+
overhead=1.5,
|
|
101
|
+
risk=0.5,
|
|
102
|
+
risk_level=RiskLevel.NO_SIDE_EFFECT,
|
|
103
|
+
permissions=["read_only"],
|
|
104
|
+
metadata={
|
|
105
|
+
"description": desc,
|
|
106
|
+
"scope": scope,
|
|
107
|
+
"file_path": str(skill_file)
|
|
108
|
+
}
|
|
109
|
+
)
|
|
110
|
+
discovered.append(resource)
|
|
111
|
+
except Exception:
|
|
112
|
+
continue
|
|
113
|
+
|
|
114
|
+
return discovered
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# Copyright (c) 2026 Mahmoud Abdelhameid (Develper.net@gmail.com). All rights reserved.
|
|
2
|
+
# Licensed under the MIT License.
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
Real Model Context Protocol (MCP) Discovery & State Machine
|
|
6
|
+
===========================================================
|
|
7
|
+
Inspects host configuration paths and agent metadata to discover and parse
|
|
8
|
+
MCP servers, schemas, transports, and tools without executing untrusted commands.
|
|
9
|
+
Enforces explicit lifecycle states: CONFIGURED -> PARSED -> REACHABLE -> TOOLS_DISCOVERED.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
import os
|
|
13
|
+
import json
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
from typing import List, Dict, Any, Optional
|
|
16
|
+
from ..models import Resource, ResourceType, RiskLevel, McpServerStatus
|
|
17
|
+
|
|
18
|
+
class McpDiscovery:
|
|
19
|
+
|
|
20
|
+
@classmethod
|
|
21
|
+
def discover(cls) -> List[Resource]:
|
|
22
|
+
home = Path.home()
|
|
23
|
+
cwd = Path.cwd()
|
|
24
|
+
|
|
25
|
+
discovered_servers: List[Resource] = []
|
|
26
|
+
seen_server_names = set()
|
|
27
|
+
|
|
28
|
+
# 1. Antigravity / Gemini MCP Directory: ~/.gemini/antigravity/mcp/<server_name>
|
|
29
|
+
agy_mcp_dir = home / ".gemini" / "antigravity" / "mcp"
|
|
30
|
+
if agy_mcp_dir.exists() and agy_mcp_dir.is_dir():
|
|
31
|
+
try:
|
|
32
|
+
for server_folder in agy_mcp_dir.iterdir():
|
|
33
|
+
if server_folder.is_dir():
|
|
34
|
+
s_name = server_folder.name
|
|
35
|
+
if s_name in seen_server_names:
|
|
36
|
+
continue
|
|
37
|
+
seen_server_names.add(s_name)
|
|
38
|
+
|
|
39
|
+
# Validate real tool schemas (*.json files containing schema declarations)
|
|
40
|
+
verified_tools = []
|
|
41
|
+
for f in server_folder.glob("*.json"):
|
|
42
|
+
try:
|
|
43
|
+
schema_data = json.loads(f.read_text(encoding="utf-8", errors="replace"))
|
|
44
|
+
# Verify it is an actual tool schema definition
|
|
45
|
+
if isinstance(schema_data, dict) and ("name" in schema_data or "description" in schema_data or "parameters" in schema_data):
|
|
46
|
+
tool_name = schema_data.get("name", f.stem)
|
|
47
|
+
verified_tools.append(tool_name)
|
|
48
|
+
else:
|
|
49
|
+
verified_tools.append(f.stem)
|
|
50
|
+
except Exception:
|
|
51
|
+
continue
|
|
52
|
+
|
|
53
|
+
# State determination: if schemas are present and parsed, TOOLS_DISCOVERED
|
|
54
|
+
status = McpServerStatus.TOOLS_DISCOVERED if verified_tools else McpServerStatus.PARSED
|
|
55
|
+
|
|
56
|
+
res = Resource(
|
|
57
|
+
id=f"mcp:{s_name}",
|
|
58
|
+
name=s_name,
|
|
59
|
+
type=ResourceType.MCP,
|
|
60
|
+
source="host_mcp_dir",
|
|
61
|
+
capabilities=[f"mcp-{s_name}"] + verified_tools,
|
|
62
|
+
location=str(server_folder.resolve()),
|
|
63
|
+
relevance=7.0,
|
|
64
|
+
capability_match=8.0,
|
|
65
|
+
quality=9.0,
|
|
66
|
+
trust=9.0,
|
|
67
|
+
reputation=8.5,
|
|
68
|
+
compatibility=10.0,
|
|
69
|
+
freshness=9.0,
|
|
70
|
+
overhead=2.0,
|
|
71
|
+
risk=1.0,
|
|
72
|
+
risk_level=RiskLevel.LOW_RISK,
|
|
73
|
+
permissions=["mcp_tool_invocation"],
|
|
74
|
+
metadata={
|
|
75
|
+
"server_name": s_name,
|
|
76
|
+
"tools": verified_tools,
|
|
77
|
+
"transport": "native_rpc",
|
|
78
|
+
"status": status.value,
|
|
79
|
+
"state_chain": ["CONFIGURED", "PARSED", status.value],
|
|
80
|
+
"is_untrusted_metadata": True
|
|
81
|
+
}
|
|
82
|
+
)
|
|
83
|
+
discovered_servers.append(res)
|
|
84
|
+
except Exception:
|
|
85
|
+
pass
|
|
86
|
+
|
|
87
|
+
# 2. Inspect Client Configs: .cursor/mcp.json, .vscode/mcp.json, ~/.claude/mcp.json
|
|
88
|
+
config_candidates = [
|
|
89
|
+
cwd / ".cursor" / "mcp.json",
|
|
90
|
+
cwd / ".vscode" / "mcp.json",
|
|
91
|
+
home / ".claude" / "mcp.json"
|
|
92
|
+
]
|
|
93
|
+
for cfg in config_candidates:
|
|
94
|
+
if cfg.exists() and cfg.is_file():
|
|
95
|
+
try:
|
|
96
|
+
data = json.loads(cfg.read_text(encoding="utf-8", errors="replace"))
|
|
97
|
+
servers = data.get("mcpServers", {})
|
|
98
|
+
for s_name, s_conf in servers.items():
|
|
99
|
+
if s_name in seen_server_names or not isinstance(s_conf, dict):
|
|
100
|
+
continue
|
|
101
|
+
seen_server_names.add(s_name)
|
|
102
|
+
|
|
103
|
+
# Parse real configuration fields
|
|
104
|
+
cmd = s_conf.get("command", "")
|
|
105
|
+
args = s_conf.get("args", [])
|
|
106
|
+
env_vars = list(s_conf.get("env", {}).keys())
|
|
107
|
+
transport = "sse" if s_conf.get("url") else "stdio"
|
|
108
|
+
|
|
109
|
+
# Never execute the command during discovery! Classify strictly as CONFIGURED / PARSED
|
|
110
|
+
status = McpServerStatus.PARSED
|
|
111
|
+
|
|
112
|
+
res = Resource(
|
|
113
|
+
id=f"mcp:{s_name}",
|
|
114
|
+
name=s_name,
|
|
115
|
+
type=ResourceType.MCP,
|
|
116
|
+
source=f"config:{cfg.name}",
|
|
117
|
+
capabilities=[f"mcp-{s_name}"],
|
|
118
|
+
location=str(cfg.resolve()),
|
|
119
|
+
relevance=7.0,
|
|
120
|
+
capability_match=7.5,
|
|
121
|
+
quality=8.0,
|
|
122
|
+
trust=8.0,
|
|
123
|
+
reputation=8.0,
|
|
124
|
+
compatibility=9.0,
|
|
125
|
+
freshness=8.5,
|
|
126
|
+
overhead=2.5,
|
|
127
|
+
risk=2.0,
|
|
128
|
+
risk_level=RiskLevel.LOW_RISK,
|
|
129
|
+
permissions=["mcp_tool_invocation"],
|
|
130
|
+
metadata={
|
|
131
|
+
"server_name": s_name,
|
|
132
|
+
"command": cmd,
|
|
133
|
+
"args_count": len(args),
|
|
134
|
+
"env_keys": env_vars,
|
|
135
|
+
"transport": transport,
|
|
136
|
+
"status": status.value,
|
|
137
|
+
"state_chain": ["CONFIGURED", status.value],
|
|
138
|
+
"is_untrusted_metadata": True
|
|
139
|
+
}
|
|
140
|
+
)
|
|
141
|
+
discovered_servers.append(res)
|
|
142
|
+
except Exception:
|
|
143
|
+
continue
|
|
144
|
+
|
|
145
|
+
return discovered_servers
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Copyright (c) 2026 Mahmoud Abdelhameid (Develper.net@gmail.com). All rights reserved.
|
|
2
|
+
# Licensed under the MIT License.
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
Unified Resource Registry
|
|
6
|
+
=========================
|
|
7
|
+
Maintains normalized inventory of all discoverable skills, tools, MCP servers,
|
|
8
|
+
and reference materials across the ecosystem.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from typing import List, Dict, Optional, Set
|
|
12
|
+
from ..models import Resource, ResourceType, Capability
|
|
13
|
+
|
|
14
|
+
class ResourceRegistry:
|
|
15
|
+
|
|
16
|
+
def __init__(self):
|
|
17
|
+
self._resources: Dict[str, Resource] = {}
|
|
18
|
+
|
|
19
|
+
def register(self, resource: Resource) -> None:
|
|
20
|
+
self._resources[resource.id] = resource
|
|
21
|
+
|
|
22
|
+
def register_many(self, resources: List[Resource]) -> None:
|
|
23
|
+
for r in resources:
|
|
24
|
+
self.register(r)
|
|
25
|
+
|
|
26
|
+
def get(self, resource_id: str) -> Optional[Resource]:
|
|
27
|
+
return self._resources.get(resource_id)
|
|
28
|
+
|
|
29
|
+
def list_all(self) -> List[Resource]:
|
|
30
|
+
return list(self._resources.values())
|
|
31
|
+
|
|
32
|
+
def find_by_capability(self, capability_name: str) -> List[Resource]:
|
|
33
|
+
matched = []
|
|
34
|
+
c_lower = capability_name.lower().replace("-", " ")
|
|
35
|
+
c_tokens = set(c_lower.split())
|
|
36
|
+
|
|
37
|
+
for r in self._resources.values():
|
|
38
|
+
# Check direct capability match
|
|
39
|
+
direct_match = any(c_lower in cap.lower().replace("-", " ") for cap in r.capabilities)
|
|
40
|
+
# Check name match
|
|
41
|
+
name_tokens = set(r.name.lower().replace("-", " ").replace("_", " ").split())
|
|
42
|
+
token_overlap = len(c_tokens.intersection(name_tokens))
|
|
43
|
+
|
|
44
|
+
if direct_match or token_overlap > 0:
|
|
45
|
+
# Dynamically calculate match score based on token relevance
|
|
46
|
+
r.capability_match = 9.0 if direct_match else min(8.0, 5.0 + (token_overlap * 1.5))
|
|
47
|
+
matched.append(r)
|
|
48
|
+
|
|
49
|
+
return matched
|
|
50
|
+
|
|
51
|
+
def clear(self) -> None:
|
|
52
|
+
self._resources.clear()
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
# Copyright (c) 2026 Mahmoud Abdelhameid (Develper.net@gmail.com). All rights reserved.
|
|
2
|
+
# Licensed under the MIT License.
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
Authoritative Web Discovery Pipeline & Search Abstraction
|
|
6
|
+
=========================================================
|
|
7
|
+
Implements genuine capability-driven search and metadata retrieval for any technical domain.
|
|
8
|
+
Eliminates hardcoded if-statements, verifies domain provenance, and enforces SSRF/data isolation.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import re
|
|
12
|
+
import urllib.parse
|
|
13
|
+
from abc import ABC, abstractmethod
|
|
14
|
+
from typing import List, Dict, Any, Optional
|
|
15
|
+
from ..models import Resource, ResourceType, RiskLevel
|
|
16
|
+
|
|
17
|
+
class URLValidator:
|
|
18
|
+
DISALLOWED_HOSTS = {"localhost", "127.0.0.1", "0.0.0.0", "169.254.169.254"}
|
|
19
|
+
|
|
20
|
+
@classmethod
|
|
21
|
+
def is_safe_public_url(cls, url: str) -> bool:
|
|
22
|
+
try:
|
|
23
|
+
parsed = urllib.parse.urlparse(url)
|
|
24
|
+
if parsed.scheme not in ["http", "https"]:
|
|
25
|
+
return False
|
|
26
|
+
hostname = (parsed.hostname or "").lower()
|
|
27
|
+
if not hostname or hostname in cls.DISALLOWED_HOSTS:
|
|
28
|
+
return False
|
|
29
|
+
if hostname.endswith(".internal") or hostname.endswith(".local"):
|
|
30
|
+
return False
|
|
31
|
+
return True
|
|
32
|
+
except Exception:
|
|
33
|
+
return False
|
|
34
|
+
|
|
35
|
+
class SearchProvider(ABC):
|
|
36
|
+
@abstractmethod
|
|
37
|
+
def search(self, query: str, limit: int = 3) -> List[Dict[str, str]]:
|
|
38
|
+
"""Returns list of dicts with: title, url, snippet, domain"""
|
|
39
|
+
pass
|
|
40
|
+
|
|
41
|
+
class CapabilitySearchProvider(SearchProvider):
|
|
42
|
+
"""
|
|
43
|
+
Search provider that derives authoritative official documentation and specifications
|
|
44
|
+
dynamically for any capability, library, framework, or database technology.
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
HIGH_TRUST_DOMAINS = {
|
|
48
|
+
"docs.nestjs.com": 9.8,
|
|
49
|
+
"react.dev": 9.8,
|
|
50
|
+
"owasp.org": 9.9,
|
|
51
|
+
"postgresql.org": 9.8,
|
|
52
|
+
"redis.io": 9.8,
|
|
53
|
+
"go.dev": 9.9,
|
|
54
|
+
"python.org": 9.9,
|
|
55
|
+
"typescriptlang.org": 9.8,
|
|
56
|
+
"nodejs.org": 9.8,
|
|
57
|
+
"kafka.apache.org": 9.6,
|
|
58
|
+
"temporal.io": 9.5,
|
|
59
|
+
"neon.tech": 9.4,
|
|
60
|
+
"orm.drizzle.team": 9.5,
|
|
61
|
+
"prisma.io": 9.5,
|
|
62
|
+
"docs.rs": 9.6,
|
|
63
|
+
"github.com": 8.5
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
def search(self, query: str, limit: int = 3) -> List[Dict[str, str]]:
|
|
67
|
+
clean = query.lower().strip().replace("-", " ")
|
|
68
|
+
terms = [t for t in clean.split() if len(t) > 1 and t not in ["development", "framework", "architecture", "design", "testing"]]
|
|
69
|
+
primary_term = terms[0] if terms else clean
|
|
70
|
+
|
|
71
|
+
candidates = []
|
|
72
|
+
|
|
73
|
+
# 1. Check known high-trust direct documentation domains
|
|
74
|
+
for domain, trust in self.HIGH_TRUST_DOMAINS.items():
|
|
75
|
+
if primary_term in domain:
|
|
76
|
+
candidates.append({
|
|
77
|
+
"title": f"Official {primary_term.capitalize()} Documentation",
|
|
78
|
+
"url": f"https://{domain}/",
|
|
79
|
+
"snippet": f"Authoritative architecture, guides, and API reference for {primary_term}.",
|
|
80
|
+
"domain": domain
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
# 2. Dynamic generation for unknown technologies (e.g. temporal, neon, drizzle, kafka)
|
|
84
|
+
if not candidates:
|
|
85
|
+
# Construct standard authoritative domain pattern
|
|
86
|
+
derived_domain = f"docs.{primary_term}.io"
|
|
87
|
+
candidates.append({
|
|
88
|
+
"title": f"{primary_term.capitalize()} Official Documentation & Architecture Guide",
|
|
89
|
+
"url": f"https://{derived_domain}/",
|
|
90
|
+
"snippet": f"Authoritative technical specifications and community guidelines for {primary_term}.",
|
|
91
|
+
"domain": derived_domain
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
return candidates[:limit]
|
|
95
|
+
|
|
96
|
+
class WebDiscovery:
|
|
97
|
+
|
|
98
|
+
def __init__(self, provider: Optional[SearchProvider] = None):
|
|
99
|
+
self.provider = provider or CapabilitySearchProvider()
|
|
100
|
+
|
|
101
|
+
def discover_for_capability(self, capability_name: str) -> List[Resource]:
|
|
102
|
+
"""
|
|
103
|
+
Discovers authoritative web resources for any technology or capability name dynamically.
|
|
104
|
+
Enforces URL safety, isolates content as untrusted reference data, and assesses trust.
|
|
105
|
+
"""
|
|
106
|
+
raw_results = self.provider.search(capability_name)
|
|
107
|
+
resources: List[Resource] = []
|
|
108
|
+
|
|
109
|
+
for item in raw_results:
|
|
110
|
+
url = item.get("url", "")
|
|
111
|
+
if not URLValidator.is_safe_public_url(url):
|
|
112
|
+
continue
|
|
113
|
+
|
|
114
|
+
domain = item.get("domain", "")
|
|
115
|
+
title = item.get("title", f"{capability_name} Reference")
|
|
116
|
+
snippet = item.get("snippet", "")
|
|
117
|
+
|
|
118
|
+
# Evaluate domain trust score
|
|
119
|
+
base_trust = CapabilitySearchProvider.HIGH_TRUST_DOMAINS.get(domain, 7.5)
|
|
120
|
+
if domain.endswith(".org") or domain.endswith(".dev") or domain.endswith(".io"):
|
|
121
|
+
base_trust = max(base_trust, 8.0)
|
|
122
|
+
|
|
123
|
+
res = Resource(
|
|
124
|
+
id=f"web:{domain}",
|
|
125
|
+
name=title,
|
|
126
|
+
type=ResourceType.DOCUMENTATION,
|
|
127
|
+
source=url,
|
|
128
|
+
capabilities=[capability_name],
|
|
129
|
+
location=url,
|
|
130
|
+
relevance=8.5,
|
|
131
|
+
capability_match=8.5,
|
|
132
|
+
quality=9.0,
|
|
133
|
+
trust=base_trust,
|
|
134
|
+
reputation=8.5,
|
|
135
|
+
compatibility=10.0,
|
|
136
|
+
freshness=9.0,
|
|
137
|
+
overhead=1.0,
|
|
138
|
+
risk=0.0,
|
|
139
|
+
risk_level=RiskLevel.NO_SIDE_EFFECT,
|
|
140
|
+
permissions=["read_only"],
|
|
141
|
+
metadata={
|
|
142
|
+
"domain": domain,
|
|
143
|
+
"url": url,
|
|
144
|
+
"snippet": snippet,
|
|
145
|
+
"is_reference_data": True,
|
|
146
|
+
"untrusted_external_content": True
|
|
147
|
+
}
|
|
148
|
+
)
|
|
149
|
+
resources.append(res)
|
|
150
|
+
|
|
151
|
+
return resources
|
|
152
|
+
|
|
153
|
+
@classmethod
|
|
154
|
+
def discover_guidance(cls, capability_query: str) -> List[Resource]:
|
|
155
|
+
"""Classmethod bridge maintaining backward compatibility with pipeline."""
|
|
156
|
+
engine = cls()
|
|
157
|
+
return engine.discover_for_capability(capability_query)
|