icycache 0.3.2__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.
- icycache/__init__.py +32 -0
- icycache/__main__.py +9 -0
- icycache/cli.py +171 -0
- icycache/config/icycache.gateway.json +111 -0
- icycache/config/icycache.json +149 -0
- icycache/config/normalization_rules.json +5832 -0
- icycache/config/semantic_cache.json +8 -0
- icycache/config/tools_registry.json +10 -0
- icycache/src/icy_cache_store.py +217 -0
- icycache/src/icy_core.py +380 -0
- icycache/src/icy_normalize.py +197 -0
- icycache/src/icy_paths.py +76 -0
- icycache/src/icy_semantic.py +197 -0
- icycache/src/mcp_gateway.py +360 -0
- icycache/src/mcp_server.py +1319 -0
- icycache/src/mcp_stdio_bridge.py +83 -0
- icycache/src/mcp_stdio_entry.py +23 -0
- icycache/src/prefix_proxy.py +336 -0
- icycache/src/server.py +1142 -0
- icycache/src/tool_proxy.py +655 -0
- icycache/src/upstream_client.py +98 -0
- icycache/src/upstream_utils.py +135 -0
- icycache/static/dashboard.html +2385 -0
- icycache/static/icywebgl.js +2190 -0
- icycache/static/logo.svg +58 -0
- icycache/static/three.min.js +6 -0
- icycache-0.3.2.dist-info/METADATA +422 -0
- icycache-0.3.2.dist-info/RECORD +31 -0
- icycache-0.3.2.dist-info/WHEEL +4 -0
- icycache-0.3.2.dist-info/entry_points.txt +2 -0
- icycache-0.3.2.dist-info/licenses/LICENSE +21 -0
icycache/__init__.py
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""IcyCache — passerelle LLM universelle avec cache local.
|
|
2
|
+
|
|
3
|
+
Le code vit dans `icycache/src/`, avec `config/` et `static/` a cote — exactement
|
|
4
|
+
la disposition du depot (`src/`, `config/`, `static/`). Comme dans le depot, les
|
|
5
|
+
modules s'importent a plat (`import server`, `import icy_core`, ...) : on ajoute
|
|
6
|
+
donc `src/` au `sys.path` pour que les imports fonctionnent a l'identique dans
|
|
7
|
+
les deux modes (checkout source et installation pip).
|
|
8
|
+
|
|
9
|
+
`PROJECT_ROOT` est le repertoire qui contient `config/` et `static/` :
|
|
10
|
+
- mode depot -> la racine du repo
|
|
11
|
+
- mode installe -> le paquet lui-meme (site-packages/icycache)
|
|
12
|
+
"""
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
import sys
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
|
|
18
|
+
__version__ = "0.2.0"
|
|
19
|
+
|
|
20
|
+
_HERE = Path(__file__).resolve().parent
|
|
21
|
+
|
|
22
|
+
_SRC = _HERE / "src"
|
|
23
|
+
if _SRC.is_dir() and str(_SRC) not in sys.path:
|
|
24
|
+
sys.path.insert(0, str(_SRC))
|
|
25
|
+
|
|
26
|
+
# La racine qui porte config/ et static/.
|
|
27
|
+
if (_HERE / "config").is_dir():
|
|
28
|
+
PROJECT_ROOT = _HERE
|
|
29
|
+
else:
|
|
30
|
+
PROJECT_ROOT = _HERE.parent
|
|
31
|
+
|
|
32
|
+
__all__ = ["__version__", "PROJECT_ROOT"]
|
icycache/__main__.py
ADDED
icycache/cli.py
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
"""CLI IcyCache.
|
|
2
|
+
|
|
3
|
+
icycache serve # la gateway HTTP (port 8080)
|
|
4
|
+
icycache mcp # la couche MCP (SSE 8081 / HTTP 8084 / stdio)
|
|
5
|
+
icycache doctor # diagnostic : chemins, config, upstreams, base
|
|
6
|
+
icycache paths # ou sont stockees les donnees
|
|
7
|
+
icycache version
|
|
8
|
+
|
|
9
|
+
`serve` et `mcp` relancent les vrais scripts (`src/server.py`, `src/mcp_server.py`)
|
|
10
|
+
dans un sous-processus : la CLI n'ecrit aucune logique de demarrage, elle ne fait
|
|
11
|
+
que choisir le point d'entree et transmettre les arguments.
|
|
12
|
+
"""
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
import argparse
|
|
16
|
+
import json
|
|
17
|
+
import os
|
|
18
|
+
import subprocess
|
|
19
|
+
import sys
|
|
20
|
+
from pathlib import Path
|
|
21
|
+
|
|
22
|
+
from . import PROJECT_ROOT, __version__
|
|
23
|
+
|
|
24
|
+
_SRC = PROJECT_ROOT / "src"
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _run(script: str, extra: list[str]) -> int:
|
|
28
|
+
target = _SRC / script
|
|
29
|
+
if not target.exists():
|
|
30
|
+
print(f"[icycache] introuvable: {target}", file=sys.stderr)
|
|
31
|
+
return 2
|
|
32
|
+
cmd = [sys.executable, str(target), *extra]
|
|
33
|
+
print(f"[icycache] {' '.join(cmd)}", file=sys.stderr)
|
|
34
|
+
return subprocess.call(cmd)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _cmd_serve(args) -> int:
|
|
38
|
+
extra: list[str] = []
|
|
39
|
+
if args.host:
|
|
40
|
+
extra += ["--host", args.host]
|
|
41
|
+
if args.port:
|
|
42
|
+
extra += ["--port", str(args.port)]
|
|
43
|
+
return _run("server.py", extra)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _cmd_mcp(args) -> int:
|
|
47
|
+
# stdio passe par une entree dediee : l'import de mcp_server.py ecrit sur
|
|
48
|
+
# stdout, qui appartient au JSON-RPC sur ce transport.
|
|
49
|
+
if args.mode == "mcp-stdio":
|
|
50
|
+
return _run("mcp_stdio_entry.py", [])
|
|
51
|
+
return _run("mcp_server.py", ["--mode", args.mode])
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _cmd_paths(args) -> int:
|
|
55
|
+
sys.path.insert(0, str(_SRC))
|
|
56
|
+
from icy_paths import DATA_DIR, IS_SOURCE_CHECKOUT, PROJECT_ROOT as ROOT
|
|
57
|
+
|
|
58
|
+
print(f"mode : {'depot (source)' if IS_SOURCE_CHECKOUT else 'installe (pip)'}")
|
|
59
|
+
print(f"PROJECT_ROOT : {ROOT}")
|
|
60
|
+
print(f"DATA_DIR : {DATA_DIR}")
|
|
61
|
+
print(f"config gateway : {ROOT / 'config' / 'icycache.gateway.json'}")
|
|
62
|
+
print(f"config legacy : {ROOT / 'config' / 'icycache.json'}")
|
|
63
|
+
print(f"base (cache.db) : {DATA_DIR / 'db' / 'cache.db'}")
|
|
64
|
+
print(f"logs : {DATA_DIR / 'logs'}")
|
|
65
|
+
print(f"static : {ROOT / 'static'}")
|
|
66
|
+
return 0
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def _cmd_doctor(args) -> int:
|
|
70
|
+
sys.path.insert(0, str(_SRC))
|
|
71
|
+
import icy_paths
|
|
72
|
+
|
|
73
|
+
problems: list[str] = []
|
|
74
|
+
|
|
75
|
+
print("== IcyCache ==")
|
|
76
|
+
print(f"version : {__version__}")
|
|
77
|
+
print(f"python : {sys.executable}")
|
|
78
|
+
print(f"PROJECT_ROOT : {icy_paths.PROJECT_ROOT}")
|
|
79
|
+
print(f"DATA_DIR : {icy_paths.DATA_DIR}")
|
|
80
|
+
print(f"mode : {'depot (source)' if icy_paths.IS_SOURCE_CHECKOUT else 'installe (pip)'}")
|
|
81
|
+
|
|
82
|
+
cfg_path = Path(os.environ.get("ICYCACHE_CONFIG") or (icy_paths.PROJECT_ROOT / "config" / "icycache.gateway.json"))
|
|
83
|
+
print(f"\n== config ==\n{cfg_path}")
|
|
84
|
+
if cfg_path.exists():
|
|
85
|
+
try:
|
|
86
|
+
cfg = json.loads(cfg_path.read_text(encoding="utf-8"))
|
|
87
|
+
except Exception as exc: # noqa: BLE001
|
|
88
|
+
problems.append(f"config illisible: {exc}")
|
|
89
|
+
cfg = {}
|
|
90
|
+
ups = sorted(cfg.get("upstreams", {}))
|
|
91
|
+
gw = cfg.get("gateway", {})
|
|
92
|
+
print(f"upstreams : {len(ups)} -> {', '.join(ups)}")
|
|
93
|
+
print(f"default : {gw.get('default_upstream') or '(aucun - explicite obligatoire)'}")
|
|
94
|
+
print(f"sticky_upstream : {gw.get('sticky_upstream')}")
|
|
95
|
+
cache = cfg.get("cache", {})
|
|
96
|
+
print(f"cache : max_entries={cache.get('max_entries')} "
|
|
97
|
+
f"semantic={cache.get('enable_semantic')} ttl={cache.get('ttl_seconds')}")
|
|
98
|
+
db = icy_paths.resolve_data_path(cache.get("db_path"), "db/cache.db")
|
|
99
|
+
else:
|
|
100
|
+
problems.append(f"config absent: {cfg_path}")
|
|
101
|
+
db = icy_paths.DATA_DIR / "db" / "cache.db"
|
|
102
|
+
|
|
103
|
+
print(f"\n== base ==\n{db}")
|
|
104
|
+
print(f"existe : {db.exists()}"
|
|
105
|
+
+ (f" ({db.stat().st_size} octets)" if db.exists() else ""))
|
|
106
|
+
parent = db.parent
|
|
107
|
+
if not parent.exists():
|
|
108
|
+
problems.append(f"repertoire de base absent (sera cree au demarrage): {parent}")
|
|
109
|
+
elif not os.access(parent, os.W_OK):
|
|
110
|
+
problems.append(f"repertoire de base non inscriptible: {parent}")
|
|
111
|
+
|
|
112
|
+
static = icy_paths.PROJECT_ROOT / "static" / "dashboard.html"
|
|
113
|
+
print(f"\n== dashboard ==\n{static}\nexiste : {static.exists()}")
|
|
114
|
+
if not static.exists():
|
|
115
|
+
problems.append(f"dashboard absent: {static}")
|
|
116
|
+
|
|
117
|
+
print()
|
|
118
|
+
if problems:
|
|
119
|
+
print("== PROBLEMES ==")
|
|
120
|
+
for p in problems:
|
|
121
|
+
print(f" - {p}")
|
|
122
|
+
return 1
|
|
123
|
+
print("== OK ==")
|
|
124
|
+
return 0
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def _cmd_version(args) -> int:
|
|
128
|
+
print(__version__)
|
|
129
|
+
return 0
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def build_parser() -> argparse.ArgumentParser:
|
|
133
|
+
parser = argparse.ArgumentParser(
|
|
134
|
+
prog="icycache",
|
|
135
|
+
description="IcyCache — passerelle LLM universelle avec cache local.",
|
|
136
|
+
)
|
|
137
|
+
sub = parser.add_subparsers(dest="cmd")
|
|
138
|
+
|
|
139
|
+
p = sub.add_parser("serve", help="Demarrer la gateway HTTP (defaut 127.0.0.1:8080).")
|
|
140
|
+
p.add_argument("--host", default=None)
|
|
141
|
+
p.add_argument("--port", type=int, default=None)
|
|
142
|
+
p.set_defaults(func=_cmd_serve)
|
|
143
|
+
|
|
144
|
+
p = sub.add_parser("mcp", help="Demarrer la couche MCP.")
|
|
145
|
+
p.add_argument("--mode", default="mcp-sse",
|
|
146
|
+
choices=["proxy", "mcp-stdio", "mcp-sse", "mcp-http", "all"])
|
|
147
|
+
p.set_defaults(func=_cmd_mcp)
|
|
148
|
+
|
|
149
|
+
p = sub.add_parser("doctor", help="Diagnostic de l'installation.")
|
|
150
|
+
p.set_defaults(func=_cmd_doctor)
|
|
151
|
+
|
|
152
|
+
p = sub.add_parser("paths", help="Afficher ou sont stockees les donnees.")
|
|
153
|
+
p.set_defaults(func=_cmd_paths)
|
|
154
|
+
|
|
155
|
+
p = sub.add_parser("version", help="Afficher la version.")
|
|
156
|
+
p.set_defaults(func=_cmd_version)
|
|
157
|
+
|
|
158
|
+
return parser
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def main(argv: list[str] | None = None) -> int:
|
|
162
|
+
parser = build_parser()
|
|
163
|
+
args = parser.parse_args(argv)
|
|
164
|
+
if not getattr(args, "func", None):
|
|
165
|
+
parser.print_help()
|
|
166
|
+
return 0
|
|
167
|
+
return args.func(args)
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
if __name__ == "__main__": # pragma: no cover
|
|
171
|
+
raise SystemExit(main())
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
{
|
|
2
|
+
"proxy": {
|
|
3
|
+
"host": "127.0.0.1",
|
|
4
|
+
"port": 8080,
|
|
5
|
+
"timeout": 120
|
|
6
|
+
},
|
|
7
|
+
"mcp": {
|
|
8
|
+
"host": "127.0.0.1",
|
|
9
|
+
"port": 8081,
|
|
10
|
+
"transport": ["stdio", "sse"]
|
|
11
|
+
},
|
|
12
|
+
"mcp_gateway": {
|
|
13
|
+
"host": "127.0.0.1",
|
|
14
|
+
"port": 8083,
|
|
15
|
+
"transport": ["stdio", "sse"],
|
|
16
|
+
"_note": "Serveur MCP de la gateway. 8081 est servi par mcp_server.py (serveur MCP)."
|
|
17
|
+
},
|
|
18
|
+
"gateway": {
|
|
19
|
+
"host": "127.0.0.1",
|
|
20
|
+
"port": 8082,
|
|
21
|
+
"default_upstream": "omniroute",
|
|
22
|
+
"ws_delta_interval_s": 0.25,
|
|
23
|
+
"sticky_upstream": true,
|
|
24
|
+
"_note": "default_upstream = defaut EXPLICITE de la config (pas de fallback code vers OmniRoute). null = le client doit nommer son upstream (prefixe /<upstream>/v1/..., header X-IcyCache-Upstream ou champ 'upstream')."
|
|
25
|
+
},
|
|
26
|
+
"upstreams": {
|
|
27
|
+
"omniroute": {"base_url": "http://localhost:20128", "kind": "openai"},
|
|
28
|
+
"lmstudio": {"base_url": "http://localhost:1234", "kind": "openai"},
|
|
29
|
+
"ollama": {"base_url": "http://localhost:11434", "kind": "openai"},
|
|
30
|
+
"openai": {"base_url": "https://api.openai.com", "kind": "openai"},
|
|
31
|
+
"anthropic": {"base_url": "https://api.anthropic.com", "kind": "anthropic"},
|
|
32
|
+
"nvidia": {"base_url": "https://integrate.api.nvidia.com/v1", "kind": "openai"},
|
|
33
|
+
"groq": {"base_url": "https://api.groq.com/openai/v1", "kind": "openai"},
|
|
34
|
+
"cerebras": {"base_url": "https://api.cerebras.ai/v1", "kind": "openai", "headers": {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) HermesAgent/0.22.2"}},
|
|
35
|
+
"openrouter": {"base_url": "https://openrouter.ai/api/v1", "kind": "openai"},
|
|
36
|
+
"kilo": {"base_url": "https://ai-gateway.kilo.ai/api/v1", "kind": "openai"},
|
|
37
|
+
"nous": {"base_url": "https://inference-api.nousresearch.com/v1", "kind": "openai"},
|
|
38
|
+
"copilot": {"base_url": "https://api.githubcopilot.com", "kind": "openai"},
|
|
39
|
+
"ai-gateway": {"base_url": "https://ai-gateway.vercel.sh/v1", "kind": "openai"},
|
|
40
|
+
"huggingface": {"base_url": "https://router.huggingface.co/v1", "kind": "openai"},
|
|
41
|
+
"google-aistudio": {"base_url": "https://generativelanguage.googleapis.com/v1beta/openai", "kind": "openai", "strip_v1": true},
|
|
42
|
+
"llm7io": {"base_url": "https://api.llm7.io/v1", "kind": "openai"},
|
|
43
|
+
"mistral": {"base_url": "https://api.mistral.ai/v1", "kind": "openai"},
|
|
44
|
+
"cloudflare": {"base_url": "https://api.cloudflare.com/client/v4/accounts/dfbe889cfe78700a4d10897cfd3b581d/ai/v1", "kind": "openai", "headers": {"cf-aig-gateway-id": "default"}}
|
|
45
|
+
},
|
|
46
|
+
"cache": {
|
|
47
|
+
"db_path": "db/cache.db",
|
|
48
|
+
"max_entries": 50000,
|
|
49
|
+
"enable_semantic": false,
|
|
50
|
+
"semantic_threshold": 0.95,
|
|
51
|
+
"ttl_seconds": 604800,
|
|
52
|
+
"cache_when_temperature_unset": true,
|
|
53
|
+
"embeddings_ttl_seconds": 604800
|
|
54
|
+
},
|
|
55
|
+
"loop_guard": {
|
|
56
|
+
"enabled": true,
|
|
57
|
+
"window_seconds": 300,
|
|
58
|
+
"tools": {"warn_after": 3, "block_after": 5, "max_cycle_len": 3},
|
|
59
|
+
"llm": {"warn_after": 3, "action": "warn", "block_after": 6}
|
|
60
|
+
},
|
|
61
|
+
"tool_cache": {
|
|
62
|
+
"enabled": true,
|
|
63
|
+
"default": "allow",
|
|
64
|
+
"max_result_bytes": 10485760,
|
|
65
|
+
"downstream": {
|
|
66
|
+
"github": {"transport": "stdio", "command": "npx", "args": ["-y", "@modelcontextprotocol/server-github"]},
|
|
67
|
+
"fetch": {"transport": "stdio", "command": "uvx", "args": ["mcp-server-fetch@2026.10.10"]},
|
|
68
|
+
"omniroute": {"transport": "sse", "url": "http://127.0.0.1:20128/mcp"},
|
|
69
|
+
"qwen-chroma": {"transport": "stdio", "command": "python", "args": ["C:/AI/EmbeddingDB/hermes_qdrant_mcp.py"]},
|
|
70
|
+
"icycache": {"transport": "sse", "url": "http://127.0.0.1:8081/sse"},
|
|
71
|
+
"loom": {"transport": "stdio", "command": "D:/Loom/.venv/Scripts/loom-mcp.exe"},
|
|
72
|
+
"wispr_flow_mcp": {"transport": "stdio", "command": "wispr-flow-mcp"},
|
|
73
|
+
"dak-notebook": {"transport": "stdio", "command": "dak-notebook"},
|
|
74
|
+
"dak-viz": {"transport": "stdio", "command": "dak-viz"},
|
|
75
|
+
"dak-bigquery": {"transport": "stdio", "command": "dak-bigquery"},
|
|
76
|
+
"dak-gcs": {"transport": "stdio", "command": "dak-gcs"},
|
|
77
|
+
"dak-spanner": {"transport": "stdio", "command": "dak-spanner"}
|
|
78
|
+
},
|
|
79
|
+
"policy": {
|
|
80
|
+
"github.*": {"ttl_seconds": 3600},
|
|
81
|
+
"fetch.*": {"ttl_seconds": 3600},
|
|
82
|
+
"omniroute.*": {"ttl_seconds": 1800},
|
|
83
|
+
"qwen-chroma.*": {"ttl_seconds": 7200},
|
|
84
|
+
"icycache.*": {"ttl_seconds": 300},
|
|
85
|
+
"loom.*": {"ttl_seconds": 3600},
|
|
86
|
+
"wispr_flow_mcp.*": {"ttl_seconds": 600},
|
|
87
|
+
"dak-.*": {"ttl_seconds": 1800}
|
|
88
|
+
},
|
|
89
|
+
"_example": {
|
|
90
|
+
"downstream": {"srv1": {"transport": "stdio", "command": "node", "args": ["server.js"]}},
|
|
91
|
+
"policy": {"srv1.nom_du_tool": {"ttl_seconds": 60}}
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
"normalization": {
|
|
95
|
+
"remove_politeness": true,
|
|
96
|
+
"canonical_synonyms": {
|
|
97
|
+
"config": "configuration",
|
|
98
|
+
"setup": "configuration",
|
|
99
|
+
"stp": "",
|
|
100
|
+
"s'il te pla\u00eet": "",
|
|
101
|
+
"please": "",
|
|
102
|
+
"can you": "",
|
|
103
|
+
"peux-tu": ""
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
"logging": {
|
|
107
|
+
"level": "INFO",
|
|
108
|
+
"file": "logs/app.log",
|
|
109
|
+
"max_size_mb": 10
|
|
110
|
+
}
|
|
111
|
+
}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
{
|
|
2
|
+
"proxy": {
|
|
3
|
+
"host": "127.0.0.1",
|
|
4
|
+
"port": 8080,
|
|
5
|
+
"target_provider": "http://localhost:20128/v1/chat/completions",
|
|
6
|
+
"api_key": null,
|
|
7
|
+
"timeout": 120
|
|
8
|
+
},
|
|
9
|
+
"mcp": {
|
|
10
|
+
"host": "127.0.0.1",
|
|
11
|
+
"port": 8081,
|
|
12
|
+
"transport": [
|
|
13
|
+
"stdio",
|
|
14
|
+
"sse"
|
|
15
|
+
],
|
|
16
|
+
"_note": "8081 = transport SSE (clients legacy / Hermes). Le transport moderne streamable-http ecoute sur mcp_http.port."
|
|
17
|
+
},
|
|
18
|
+
"mcp_http": {
|
|
19
|
+
"host": "127.0.0.1",
|
|
20
|
+
"port": 8084,
|
|
21
|
+
"_note": "Streamable HTTP (transport standard des clients MCP recents). Endpoint: http://127.0.0.1:8084/mcp"
|
|
22
|
+
},
|
|
23
|
+
"cache": {
|
|
24
|
+
"db_path": "db/cache.db",
|
|
25
|
+
"max_entries": 200000,
|
|
26
|
+
"enable_semantic": true,
|
|
27
|
+
"semantic_threshold": 0.80,
|
|
28
|
+
"ttl_seconds": 2592000
|
|
29
|
+
},
|
|
30
|
+
"tool_cache": {
|
|
31
|
+
"enabled": true,
|
|
32
|
+
"ttl_seconds": 3600,
|
|
33
|
+
"window_seconds": 1800,
|
|
34
|
+
"tools": {
|
|
35
|
+
"warn_after": 3,
|
|
36
|
+
"block_after": 5,
|
|
37
|
+
"max_cycle_len": 3
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"tool_proxy": {
|
|
41
|
+
"list_cache_seconds": 30,
|
|
42
|
+
"_note": "Jetons de portabilite: {PROJECT_ROOT} = racine du projet, {PYTHON} = interpreteur du venv. Le cache d'outils est OPT-IN; 'cache_tools' = allowlist stricte; sinon 'cache: true' active la detection anti-ecriture (create_/write_/delete_/push_... jamais caches).",
|
|
43
|
+
"servers": {
|
|
44
|
+
"fetch": {
|
|
45
|
+
"command": "uvx",
|
|
46
|
+
"args": ["mcp-server-fetch@2026.10.10"],
|
|
47
|
+
"cache": true
|
|
48
|
+
},
|
|
49
|
+
"github": {
|
|
50
|
+
"command": "npx",
|
|
51
|
+
"args": ["-y", "@modelcontextprotocol/server-github"],
|
|
52
|
+
"env": {
|
|
53
|
+
"GITHUB_PERSONAL_ACCESS_TOKEN": "@hermes:mcp_servers.github"
|
|
54
|
+
},
|
|
55
|
+
"cache": true,
|
|
56
|
+
"cache_tools": {
|
|
57
|
+
"_note": "Allowlist stricte des outils de LECTURE reels de @modelcontextprotocol/server-github (26 outils au total). Les 12 outils d'ecriture (create_*, push_files, fork_repository, merge_*, update_*) ne sont JAMAIS mis en cache: sinon l'ecriture est sautee silencieusement.",
|
|
58
|
+
"search_issues": true,
|
|
59
|
+
"search_code": true,
|
|
60
|
+
"search_repositories": true,
|
|
61
|
+
"search_users": true,
|
|
62
|
+
"get_issue": true,
|
|
63
|
+
"get_pull_request": true,
|
|
64
|
+
"get_pull_request_files": true,
|
|
65
|
+
"get_pull_request_status": true,
|
|
66
|
+
"get_pull_request_comments": true,
|
|
67
|
+
"get_pull_request_reviews": true,
|
|
68
|
+
"get_file_contents": true,
|
|
69
|
+
"list_issues": true,
|
|
70
|
+
"list_pull_requests": true,
|
|
71
|
+
"list_commits": true
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
"qwen-chroma": {
|
|
75
|
+
"command": "C:\\AI\\EmbeddingDB\\.venv\\Scripts\\python.exe",
|
|
76
|
+
"args": ["C:\\AI\\EmbeddingDB\\hermes_qdrant_mcp.py"],
|
|
77
|
+
"cache": true,
|
|
78
|
+
"ttl_seconds": 259200,
|
|
79
|
+
"_note": "cache: true + detection anti-ecriture: memory_search_tool / hybrid_search_tool / memory_stats_tool sont caches; memory_add_tool / memory_delete_tool / rebuild_bm25_index_tool sont executes a chaque appel."
|
|
80
|
+
},
|
|
81
|
+
"pwsh": {
|
|
82
|
+
"command": "uvx",
|
|
83
|
+
"args": ["pwsh-exec@1.0.1"],
|
|
84
|
+
"cache": false
|
|
85
|
+
},
|
|
86
|
+
"filesystem": {
|
|
87
|
+
"command": "npx",
|
|
88
|
+
"args": ["-y", "@modelcontextprotocol/server-filesystem", "D:\\\\", "C:\\\\Users\\\\Tech\\\\AppData\\\\Local\\\\hermes"],
|
|
89
|
+
"cache": false
|
|
90
|
+
},
|
|
91
|
+
"websearch": {
|
|
92
|
+
"command": "uvx",
|
|
93
|
+
"args": ["mcp-server-brave-search@2026.10.10"],
|
|
94
|
+
"env": {
|
|
95
|
+
"BRAVE_API_KEY": "@hermes:mcp_servers.brave"
|
|
96
|
+
},
|
|
97
|
+
"cache": true
|
|
98
|
+
},
|
|
99
|
+
"sqlite": {
|
|
100
|
+
"command": "uvx",
|
|
101
|
+
"args": ["mcp-server-sqlite@2025.4.25", "--db-path", "D:\\IcyCache\\db\\cache.db"],
|
|
102
|
+
"cache": true
|
|
103
|
+
},
|
|
104
|
+
"docker": {
|
|
105
|
+
"command": "uvx",
|
|
106
|
+
"args": ["mcp-server-docker@0.3.0"],
|
|
107
|
+
"cache": false
|
|
108
|
+
},
|
|
109
|
+
"postgres": {
|
|
110
|
+
"command": "uvx",
|
|
111
|
+
"args": ["mcp-server-postgres@0.1.0"],
|
|
112
|
+
"env": {
|
|
113
|
+
"POSTGRES_CONNECTION_STRING": "@hermes:mcp_servers.postgres"
|
|
114
|
+
},
|
|
115
|
+
"cache": false
|
|
116
|
+
},
|
|
117
|
+
"redis": {
|
|
118
|
+
"command": "uvx",
|
|
119
|
+
"args": ["mcp-server-redis@0.1.1"],
|
|
120
|
+
"env": {
|
|
121
|
+
"REDIS_URL": "@hermes:mcp_servers.redis"
|
|
122
|
+
},
|
|
123
|
+
"cache": true
|
|
124
|
+
},
|
|
125
|
+
"kubernetes": {
|
|
126
|
+
"command": "uvx",
|
|
127
|
+
"args": ["mcp-server-kubernetes@0.1.6"],
|
|
128
|
+
"cache": false
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
"normalization": {
|
|
133
|
+
"remove_politeness": true,
|
|
134
|
+
"canonical_synonyms": {
|
|
135
|
+
"config": "configuration",
|
|
136
|
+
"setup": "configuration",
|
|
137
|
+
"stp": "",
|
|
138
|
+
"s'il te pla\u00eet": "",
|
|
139
|
+
"please": "",
|
|
140
|
+
"can you": "",
|
|
141
|
+
"peux-tu": ""
|
|
142
|
+
}
|
|
143
|
+
},
|
|
144
|
+
"logging": {
|
|
145
|
+
"level": "INFO",
|
|
146
|
+
"file": "logs/app.log",
|
|
147
|
+
"max_size_mb": 10
|
|
148
|
+
}
|
|
149
|
+
}
|