as-redis-mcp-server 1.0.0__tar.gz
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.
- as_redis_mcp_server-1.0.0/.env.example +64 -0
- as_redis_mcp_server-1.0.0/.idea/.gitignore +8 -0
- as_redis_mcp_server-1.0.0/.idea/git_toolbox_blame.xml +6 -0
- as_redis_mcp_server-1.0.0/.idea/inspectionProfiles/Project_Default.xml +5 -0
- as_redis_mcp_server-1.0.0/.idea/misc.xml +6 -0
- as_redis_mcp_server-1.0.0/.idea/modules.xml +8 -0
- as_redis_mcp_server-1.0.0/.idea/redis-mcp.iml +9 -0
- as_redis_mcp_server-1.0.0/.idea/workspace.xml +70 -0
- as_redis_mcp_server-1.0.0/.qoder/repowiki/knowledge/zh/FastMCP - Third-party MCP Framework/FastMCP - Third-party MCP Framework.md +19 -0
- as_redis_mcp_server-1.0.0/.qoder/repowiki/knowledge/zh/Python /344/276/235/350/265/226/347/256/241/347/220/206/357/274/210pyproject + hatchling/357/274/211/Python /344/276/235/350/265/226/347/256/241/347/220/206/357/274/210pyproject + hatchling/357/274/211.md" +17 -0
- as_redis_mcp_server-1.0.0/.qoder/repowiki/knowledge/zh/Python /345/214/205/346/236/204/345/273/272/344/270/216/345/256/271/345/231/250/345/214/226/357/274/210Hatchling + Docker/357/274/211/Python /345/214/205/346/236/204/345/273/272/344/270/216/345/256/271/345/231/250/345/214/226/357/274/210Hatchling + Docker/357/274/211.md" +19 -0
- as_redis_mcp_server-1.0.0/.qoder/repowiki/knowledge/zh/Qoder IDE - MCP Host Client/Qoder IDE - MCP Host Client.md +20 -0
- as_redis_mcp_server-1.0.0/.qoder/repowiki/knowledge/zh/Redis - In-memory Data Store/Redis - In-memory Data Store.md +24 -0
- as_redis_mcp_server-1.0.0/.qoder/repowiki/knowledge/zh/Redis MCP Server /351/241/271/347/233/256/346/240/271/Redis MCP Server /346/265/213/350/257/225/345/245/227/344/273/266/_module.yaml" +8 -0
- as_redis_mcp_server-1.0.0/.qoder/repowiki/knowledge/zh/Redis MCP Server /351/241/271/347/233/256/346/240/271/Redis MCP Server /346/265/213/350/257/225/345/245/227/344/273/266//346/212/200/346/234/257/346/240/210.md" +1 -0
- as_redis_mcp_server-1.0.0/.qoder/repowiki/knowledge/zh/Redis MCP Server /351/241/271/347/233/256/346/240/271/Redis MCP Server /346/265/213/350/257/225/345/245/227/344/273/266//346/236/266/346/236/204/350/256/276/350/256/241.md" +4 -0
- as_redis_mcp_server-1.0.0/.qoder/repowiki/knowledge/zh/Redis MCP Server /351/241/271/347/233/256/346/240/271/Redis MCP Server /346/265/213/350/257/225/345/245/227/344/273/266//346/246/202/350/277/260.md" +1 -0
- as_redis_mcp_server-1.0.0/.qoder/repowiki/knowledge/zh/Redis MCP Server /351/241/271/347/233/256/346/240/271/Redis MCP Server /346/265/213/350/257/225/345/245/227/344/273/266//347/274/226/347/240/201/350/247/204/350/214/203.md" +4 -0
- as_redis_mcp_server-1.0.0/.qoder/repowiki/knowledge/zh/Redis MCP Server /351/241/271/347/233/256/346/240/271/_module.yaml" +12 -0
- as_redis_mcp_server-1.0.0/.qoder/repowiki/knowledge/zh/Redis MCP Server /351/241/271/347/233/256/346/240/271//346/212/200/346/234/257/346/240/210.md" +1 -0
- as_redis_mcp_server-1.0.0/.qoder/repowiki/knowledge/zh/Redis MCP Server /351/241/271/347/233/256/346/240/271//346/236/266/346/236/204/350/256/276/350/256/241.md" +1 -0
- as_redis_mcp_server-1.0.0/.qoder/repowiki/knowledge/zh/Redis MCP Server /351/241/271/347/233/256/346/240/271//346/246/202/350/277/260.md" +1 -0
- as_redis_mcp_server-1.0.0/.qoder/repowiki/knowledge/zh/Redis MCP Server /351/241/271/347/233/256/346/240/271//347/211/271/346/256/212/351/205/215/347/275/256/344/270/216/345/221/275/344/273/244.md" +1 -0
- as_redis_mcp_server-1.0.0/.qoder/repowiki/knowledge/zh/Redis MCP Server /351/241/271/347/233/256/346/240/271//347/274/226/347/240/201/350/247/204/350/214/203.md" +4 -0
- as_redis_mcp_server-1.0.0/.qoder/repowiki/knowledge/zh/_index.yaml +30 -0
- as_redis_mcp_server-1.0.0/.qoder/repowiki/knowledge/zh//344/270/232/345/212/241/346/234/257/350/257/255/350/241/250//344/270/232/345/212/241/346/234/257/350/257/255/350/241/250.md +39 -0
- as_redis_mcp_server-1.0.0/.qoder/repowiki/knowledge/zh//345/211/215/347/253/257/346/240/267/345/274/217/347/263/273/347/273/237/357/274/232/346/234/254/351/241/271/347/233/256/344/270/215/346/266/211/345/217/212/345/211/215/347/253/257 UI//345/211/215/347/253/257/346/240/267/345/274/217/347/263/273/347/273/237/357/274/232/346/234/254/351/241/271/347/233/256/344/270/215/346/266/211/345/217/212/345/211/215/347/253/257 UI.md" +9 -0
- as_redis_mcp_server-1.0.0/.qoder/repowiki/knowledge/zh//345/237/272/344/272/216 pydantic-settings /347/232/204/347/216/257/345/242/203/345/217/230/351/207/217/351/205/215/347/275/256/347/263/273/347/273/237//345/237/272/344/272/216 pydantic-settings /347/232/204/347/216/257/345/242/203/345/217/230/351/207/217/351/205/215/347/275/256/347/263/273/347/273/237.md" +36 -0
- as_redis_mcp_server-1.0.0/.qoder/repowiki/knowledge/zh//345/237/272/344/272/216 structlog /347/232/204/347/273/223/346/236/204/345/214/226/346/227/245/345/277/227/347/263/273/347/273/237//345/237/272/344/272/216 structlog /347/232/204/347/273/223/346/236/204/345/214/226/346/227/245/345/277/227/347/263/273/347/273/237.md" +28 -0
- as_redis_mcp_server-1.0.0/.qoder/repowiki/knowledge/zh//347/273/237/344/270/200/351/224/231/350/257/257/346/250/241/345/236/213/344/270/216/345/267/245/345/205/267/345/261/202/345/274/202/345/270/270/345/244/204/347/220/206//347/273/237/344/270/200/351/224/231/350/257/257/346/250/241/345/236/213/344/270/216/345/267/245/345/205/267/345/261/202/345/274/202/345/270/270/345/244/204/347/220/206.md +51 -0
- as_redis_mcp_server-1.0.0/.qoder/repowiki/zh/content/MCP /345/267/245/345/205/267/345/217/202/350/200/203/MCP /345/267/245/345/205/267/345/217/202/350/200/203.md" +444 -0
- as_redis_mcp_server-1.0.0/.qoder/repowiki/zh/content/MCP /345/267/245/345/205/267/345/217/202/350/200/203//346/225/260/346/215/256/350/256/277/351/227/256/345/267/245/345/205/267.md" +450 -0
- as_redis_mcp_server-1.0.0/.qoder/repowiki/zh/content/MCP /345/267/245/345/205/267/345/217/202/350/200/203//346/231/272/350/203/275/350/276/205/345/212/251/345/267/245/345/205/267.md" +362 -0
- as_redis_mcp_server-1.0.0/.qoder/repowiki/zh/content/MCP /345/267/245/345/205/267/345/217/202/350/200/203//347/233/221/346/216/247/345/210/206/346/236/220/345/267/245/345/205/267.md" +428 -0
- as_redis_mcp_server-1.0.0/.qoder/repowiki/zh/content/Redis /345/256/242/346/210/267/347/253/257/351/233/206/346/210/220/Redis /345/256/242/346/210/267/347/253/257/351/233/206/346/210/220.md" +388 -0
- as_redis_mcp_server-1.0.0/.qoder/repowiki/zh/content/Redis /345/256/242/346/210/267/347/253/257/351/233/206/346/210/220//346/211/253/346/217/217/346/223/215/344/275/234.md" +396 -0
- as_redis_mcp_server-1.0.0/.qoder/repowiki/zh/content/Redis /345/256/242/346/210/267/347/253/257/351/233/206/346/210/220//346/225/260/346/215/256/345/210/206/346/236/220.md" +312 -0
- as_redis_mcp_server-1.0.0/.qoder/repowiki/zh/content/Redis /345/256/242/346/210/267/347/253/257/351/233/206/346/210/220//350/277/236/346/216/245/347/256/241/347/220/206.md" +331 -0
- as_redis_mcp_server-1.0.0/.qoder/repowiki/zh/content//345/217/257/350/247/202/346/265/213/346/200/247/344/270/216/347/233/221/346/216/247//345/217/257/350/247/202/346/265/213/346/200/247/344/270/216/347/233/221/346/216/247.md +476 -0
- as_redis_mcp_server-1.0.0/.qoder/repowiki/zh/content//345/217/257/350/247/202/346/265/213/346/200/247/344/270/216/347/233/221/346/216/247//345/256/241/350/256/241/346/227/245/345/277/227/347/263/273/347/273/237.md +321 -0
- as_redis_mcp_server-1.0.0/.qoder/repowiki/zh/content//345/217/257/350/247/202/346/265/213/346/200/247/344/270/216/347/233/221/346/216/247//346/200/247/350/203/275/346/214/207/346/240/207/346/224/266/351/233/206.md +417 -0
- as_redis_mcp_server-1.0.0/.qoder/repowiki/zh/content//345/217/257/350/247/202/346/265/213/346/200/247/344/270/216/347/233/221/346/216/247//347/273/223/346/236/204/345/214/226/346/227/245/345/277/227/350/256/260/345/275/225.md +424 -0
- as_redis_mcp_server-1.0.0/.qoder/repowiki/zh/content//345/256/211/345/205/250/346/234/272/345/210/266//345/256/211/345/205/250/346/234/272/345/210/266.md +480 -0
- as_redis_mcp_server-1.0.0/.qoder/repowiki/zh/content//345/256/211/345/205/250/346/234/272/345/210/266//346/225/260/346/215/256/350/204/261/346/225/217.md +423 -0
- as_redis_mcp_server-1.0.0/.qoder/repowiki/zh/content//345/256/211/345/205/250/346/234/272/345/210/266//347/231/275/345/220/215/345/215/225/347/256/241/347/220/206.md +364 -0
- as_redis_mcp_server-1.0.0/.qoder/repowiki/zh/content//345/256/211/345/205/250/346/234/272/345/210/266//351/200/237/347/216/207/351/231/220/345/210/266.md +318 -0
- as_redis_mcp_server-1.0.0/.qoder/repowiki/zh/content//345/256/211/345/205/250/346/234/272/345/210/266//351/224/256/350/256/277/351/227/256/346/216/247/345/210/266.md +289 -0
- as_redis_mcp_server-1.0.0/.qoder/repowiki/zh/content//345/277/253/351/200/237/345/274/200/345/247/213.md +231 -0
- as_redis_mcp_server-1.0.0/.qoder/repowiki/zh/content//346/236/266/346/236/204/350/256/276/350/256/241//346/225/260/346/215/256/346/265/201/350/256/276/350/256/241.md +513 -0
- as_redis_mcp_server-1.0.0/.qoder/repowiki/zh/content//346/236/266/346/236/204/350/256/276/350/256/241//346/236/266/346/236/204/350/256/276/350/256/241.md +474 -0
- as_redis_mcp_server-1.0.0/.qoder/repowiki/zh/content//346/236/266/346/236/204/350/256/276/350/256/241//346/240/270/345/277/203/346/236/266/346/236/204.md +458 -0
- as_redis_mcp_server-1.0.0/.qoder/repowiki/zh/content//346/236/266/346/236/204/350/256/276/350/256/241//347/273/204/344/273/266/350/256/276/350/256/241/Redis /350/277/236/346/216/245/347/256/241/347/220/206/345/231/250.md" +356 -0
- as_redis_mcp_server-1.0.0/.qoder/repowiki/zh/content//346/236/266/346/236/204/350/256/276/350/256/241//347/273/204/344/273/266/350/256/276/350/256/241//346/225/260/346/215/256/346/250/241/345/236/213/347/273/204/344/273/266.md +400 -0
- as_redis_mcp_server-1.0.0/.qoder/repowiki/zh/content//346/236/266/346/236/204/350/256/276/350/256/241//347/273/204/344/273/266/350/256/276/350/256/241//347/273/204/344/273/266/344/272/244/344/272/222/346/250/241/345/274/217.md +418 -0
- as_redis_mcp_server-1.0.0/.qoder/repowiki/zh/content//346/236/266/346/236/204/350/256/276/350/256/241//347/273/204/344/273/266/350/256/276/350/256/241//347/273/204/344/273/266/350/256/276/350/256/241.md +525 -0
- as_redis_mcp_server-1.0.0/.qoder/repowiki/zh/content//346/236/266/346/236/204/350/256/276/350/256/241//347/273/204/344/273/266/350/256/276/350/256/241//351/205/215/347/275/256/347/256/241/347/220/206/347/273/204/344/273/266.md +301 -0
- as_redis_mcp_server-1.0.0/.qoder/repowiki/zh/content//346/236/266/346/236/204/350/256/276/350/256/241//351/233/206/346/210/220/346/250/241/345/274/217.md +362 -0
- as_redis_mcp_server-1.0.0/.qoder/repowiki/zh/content//346/265/213/350/257/225/346/214/207/345/215/227.md +352 -0
- as_redis_mcp_server-1.0.0/.qoder/repowiki/zh/content//351/203/250/347/275/262/344/270/216/350/277/220/347/273/264/Docker /345/256/271/345/231/250/345/214/226/351/203/250/347/275/262.md" +394 -0
- as_redis_mcp_server-1.0.0/.qoder/repowiki/zh/content//351/203/250/347/275/262/344/270/216/350/277/220/347/273/264//344/272/221/345/271/263/345/217/260/351/203/250/347/275/262.md +411 -0
- as_redis_mcp_server-1.0.0/.qoder/repowiki/zh/content//351/203/250/347/275/262/344/270/216/350/277/220/347/273/264//346/225/205/351/232/234/346/216/222/346/237/245/344/270/216/350/257/212/346/226/255.md +439 -0
- as_redis_mcp_server-1.0.0/.qoder/repowiki/zh/content//351/203/250/347/275/262/344/270/216/350/277/220/347/273/264//347/233/221/346/216/247/344/270/216/345/221/212/350/255/246.md +363 -0
- as_redis_mcp_server-1.0.0/.qoder/repowiki/zh/content//351/203/250/347/275/262/344/270/216/350/277/220/347/273/264//351/203/250/347/275/262/344/270/216/350/277/220/347/273/264.md +381 -0
- as_redis_mcp_server-1.0.0/.qoder/repowiki/zh/content//351/205/215/347/275/256/347/256/241/347/220/206.md +344 -0
- as_redis_mcp_server-1.0.0/.qoder/repowiki/zh/content//351/241/271/347/233/256/346/246/202/350/277/260.md +413 -0
- as_redis_mcp_server-1.0.0/.qoder/repowiki/zh/meta/repowiki-metadata.json +1 -0
- as_redis_mcp_server-1.0.0/.tmp/tmpds10bsy4.tar.gz +0 -0
- as_redis_mcp_server-1.0.0/.tmp/tmpeot_imzx/input.json +6 -0
- as_redis_mcp_server-1.0.0/Dockerfile +20 -0
- as_redis_mcp_server-1.0.0/PKG-INFO +358 -0
- as_redis_mcp_server-1.0.0/README.md +323 -0
- as_redis_mcp_server-1.0.0/pyproject.toml +66 -0
- as_redis_mcp_server-1.0.0/spec/spec.md +1311 -0
- as_redis_mcp_server-1.0.0/src/__init__.py +0 -0
- as_redis_mcp_server-1.0.0/src/config.py +47 -0
- as_redis_mcp_server-1.0.0/src/errors.py +87 -0
- as_redis_mcp_server-1.0.0/src/main.py +39 -0
- as_redis_mcp_server-1.0.0/src/mcp/__init__.py +1 -0
- as_redis_mcp_server-1.0.0/src/mcp/server.py +83 -0
- as_redis_mcp_server-1.0.0/src/models/__init__.py +0 -0
- as_redis_mcp_server-1.0.0/src/models/schema.py +147 -0
- as_redis_mcp_server-1.0.0/src/observability/__init__.py +0 -0
- as_redis_mcp_server-1.0.0/src/observability/audit.py +84 -0
- as_redis_mcp_server-1.0.0/src/observability/logger.py +51 -0
- as_redis_mcp_server-1.0.0/src/observability/metrics.py +99 -0
- as_redis_mcp_server-1.0.0/src/redis_client/__init__.py +0 -0
- as_redis_mcp_server-1.0.0/src/redis_client/analyzer.py +204 -0
- as_redis_mcp_server-1.0.0/src/redis_client/client.py +77 -0
- as_redis_mcp_server-1.0.0/src/redis_client/scanner.py +83 -0
- as_redis_mcp_server-1.0.0/src/security/__init__.py +0 -0
- as_redis_mcp_server-1.0.0/src/security/keyfilter.py +53 -0
- as_redis_mcp_server-1.0.0/src/security/limiter.py +61 -0
- as_redis_mcp_server-1.0.0/src/security/masker.py +79 -0
- as_redis_mcp_server-1.0.0/src/security/whitelist.py +82 -0
- as_redis_mcp_server-1.0.0/src/server.py +317 -0
- as_redis_mcp_server-1.0.0/src/tools/__init__.py +1 -0
- as_redis_mcp_server-1.0.0/src/tools/advisor_tool.py +97 -0
- as_redis_mcp_server-1.0.0/src/tools/analyze_tool.py +26 -0
- as_redis_mcp_server-1.0.0/src/tools/health_tool.py +91 -0
- as_redis_mcp_server-1.0.0/src/tools/inspect_tool.py +118 -0
- as_redis_mcp_server-1.0.0/src/tools/memory_tool.py +24 -0
- as_redis_mcp_server-1.0.0/src/tools/readonly_tool.py +96 -0
- as_redis_mcp_server-1.0.0/src/tools/search_tool.py +32 -0
- as_redis_mcp_server-1.0.0/src/tools/slowlog_tool.py +94 -0
- as_redis_mcp_server-1.0.0/tests/__init__.py +1 -0
- as_redis_mcp_server-1.0.0/tests/conftest.py +56 -0
- as_redis_mcp_server-1.0.0/tests/test_advisor_tool.py +44 -0
- as_redis_mcp_server-1.0.0/tests/test_analyze_tool.py +36 -0
- as_redis_mcp_server-1.0.0/tests/test_health_tool.py +28 -0
- as_redis_mcp_server-1.0.0/tests/test_inspect_tool.py +69 -0
- as_redis_mcp_server-1.0.0/tests/test_memory_tool.py +46 -0
- as_redis_mcp_server-1.0.0/tests/test_readonly_tool.py +78 -0
- as_redis_mcp_server-1.0.0/tests/test_search_tool.py +43 -0
- as_redis_mcp_server-1.0.0/tests/test_security.py +166 -0
- as_redis_mcp_server-1.0.0/tests/test_server.py +53 -0
- as_redis_mcp_server-1.0.0/tests/test_slowlog_tool.py +23 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# Redis Connection
|
|
2
|
+
REDIS_HOST=127.0.0.1
|
|
3
|
+
REDIS_PORT=6379
|
|
4
|
+
REDIS_DB=0
|
|
5
|
+
REDIS_USERNAME=default
|
|
6
|
+
REDIS_PWD=
|
|
7
|
+
REDIS_SSL=false
|
|
8
|
+
REDIS_SSL_CA_CERTS=
|
|
9
|
+
REDIS_CLUSTER_MODE=false
|
|
10
|
+
|
|
11
|
+
# Connection Pool
|
|
12
|
+
REDIS_MAX_CONNECTIONS=20
|
|
13
|
+
REDIS_SOCKET_TIMEOUT=3
|
|
14
|
+
REDIS_CONNECT_TIMEOUT=3
|
|
15
|
+
|
|
16
|
+
# Security
|
|
17
|
+
# Key prefix whitelist (glob patterns, comma-separated)
|
|
18
|
+
# Example: cache:*,session:*,user:*,order:*
|
|
19
|
+
# Leave empty to allow all keys (development only!)
|
|
20
|
+
KEY_PREFIX_WHITELIST=
|
|
21
|
+
|
|
22
|
+
# Limits
|
|
23
|
+
MAX_SCAN_COUNT=100
|
|
24
|
+
MAX_VALUE_LENGTH=2000
|
|
25
|
+
RATE_LIMIT_QPS=20
|
|
26
|
+
|
|
27
|
+
# Logging
|
|
28
|
+
MCP_REDIS_LOG_LEVEL=INFO
|
|
29
|
+
# ============================================================
|
|
30
|
+
# Redis MCP Server Configuration
|
|
31
|
+
# ============================================================
|
|
32
|
+
# Copy this file to .env and edit values for your environment.
|
|
33
|
+
# Environment variables take precedence over config file values.
|
|
34
|
+
# ============================================================
|
|
35
|
+
|
|
36
|
+
# --- Redis Connection ---
|
|
37
|
+
REDIS_HOST=127.0.0.1
|
|
38
|
+
REDIS_PORT=6379
|
|
39
|
+
REDIS_DB=0
|
|
40
|
+
REDIS_USERNAME=default
|
|
41
|
+
REDIS_PWD=
|
|
42
|
+
REDIS_SSL=false
|
|
43
|
+
REDIS_SSL_CA_CERTS=
|
|
44
|
+
|
|
45
|
+
# --- Redis Cluster ---
|
|
46
|
+
REDIS_CLUSTER_MODE=false
|
|
47
|
+
|
|
48
|
+
# --- Connection Pool ---
|
|
49
|
+
REDIS_MAX_CONNECTIONS=20
|
|
50
|
+
REDIS_SOCKET_TIMEOUT=3
|
|
51
|
+
REDIS_CONNECT_TIMEOUT=3
|
|
52
|
+
|
|
53
|
+
# --- Security ---
|
|
54
|
+
# Key prefix whitelist (comma-separated glob patterns)
|
|
55
|
+
# Empty = allow all keys (development only)
|
|
56
|
+
KEY_PREFIX_WHITELIST=
|
|
57
|
+
|
|
58
|
+
# --- Limits ---
|
|
59
|
+
MAX_SCAN_COUNT=100
|
|
60
|
+
MAX_VALUE_LENGTH=2000
|
|
61
|
+
RATE_LIMIT_QPS=20
|
|
62
|
+
|
|
63
|
+
# --- Observability ---
|
|
64
|
+
MCP_REDIS_LOG_LEVEL=INFO
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<project version="4">
|
|
3
|
+
<component name="ProjectModuleManager">
|
|
4
|
+
<modules>
|
|
5
|
+
<module fileurl="file://$PROJECT_DIR$/.idea/redis-mcp.iml" filepath="$PROJECT_DIR$/.idea/redis-mcp.iml" />
|
|
6
|
+
</modules>
|
|
7
|
+
</component>
|
|
8
|
+
</project>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<module type="JAVA_MODULE" version="4">
|
|
3
|
+
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
|
4
|
+
<exclude-output />
|
|
5
|
+
<content url="file://$MODULE_DIR$" />
|
|
6
|
+
<orderEntry type="jdk" jdkName="Python 3.14" jdkType="Python SDK" />
|
|
7
|
+
<orderEntry type="sourceFolder" forTests="false" />
|
|
8
|
+
</component>
|
|
9
|
+
</module>
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<project version="4">
|
|
3
|
+
<component name="AutoImportSettings">
|
|
4
|
+
<option name="autoReloadType" value="SELECTIVE" />
|
|
5
|
+
</component>
|
|
6
|
+
<component name="ChangeListManager">
|
|
7
|
+
<list default="true" id="45c0c31a-69f6-49c5-9277-81663ff4069f" name="Changes" comment="" />
|
|
8
|
+
<option name="SHOW_DIALOG" value="false" />
|
|
9
|
+
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
|
10
|
+
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
|
11
|
+
<option name="LAST_RESOLUTION" value="IGNORE" />
|
|
12
|
+
</component>
|
|
13
|
+
<component name="MavenImportPreferences">
|
|
14
|
+
<option name="generalSettings">
|
|
15
|
+
<MavenGeneralSettings>
|
|
16
|
+
<option name="localRepository" value="E:\soft\Maven\repository" />
|
|
17
|
+
<option name="useMavenConfig" value="false" />
|
|
18
|
+
<option name="userSettingsFile" value="E:\soft\Maven\apache-maven-3.6.3\conf\settings.xml" />
|
|
19
|
+
</MavenGeneralSettings>
|
|
20
|
+
</option>
|
|
21
|
+
</component>
|
|
22
|
+
<component name="ProjectColorInfo"><![CDATA[{
|
|
23
|
+
"associatedIndex": 1
|
|
24
|
+
}]]></component>
|
|
25
|
+
<component name="ProjectId" id="3GUOFBDUh9hDtpzkffz1cr0Ucy8" />
|
|
26
|
+
<component name="ProjectViewState">
|
|
27
|
+
<option name="hideEmptyMiddlePackages" value="true" />
|
|
28
|
+
<option name="showLibraryContents" value="true" />
|
|
29
|
+
</component>
|
|
30
|
+
<component name="PropertiesComponent"><![CDATA[{
|
|
31
|
+
"keyToString": {
|
|
32
|
+
"ModuleVcsDetector.initialDetectionPerformed": "true",
|
|
33
|
+
"RunOnceActivity.ShowReadmeOnStart": "true",
|
|
34
|
+
"RunOnceActivity.typescript.service.memoryLimit.init": "true",
|
|
35
|
+
"com.intellij.ml.llm.matterhorn.ej.ui.settings.DefaultModelSelectionForGA.v1": "true",
|
|
36
|
+
"junie.onboarding.icon.badge.shown": "true",
|
|
37
|
+
"last_opened_file_path": "F:/ai/learn/redis-mcp",
|
|
38
|
+
"node.js.detected.package.eslint": "true",
|
|
39
|
+
"node.js.detected.package.tslint": "true",
|
|
40
|
+
"node.js.selected.package.eslint": "(autodetect)",
|
|
41
|
+
"node.js.selected.package.tslint": "(autodetect)",
|
|
42
|
+
"nodejs_package_manager_path": "npm",
|
|
43
|
+
"settings.editor.selected.configurable": "MavenSettings",
|
|
44
|
+
"to.speed.mode.migration.done": "true",
|
|
45
|
+
"vue.rearranger.settings.migration": "true"
|
|
46
|
+
}
|
|
47
|
+
}]]></component>
|
|
48
|
+
<component name="SharedIndexes">
|
|
49
|
+
<attachedChunks>
|
|
50
|
+
<set>
|
|
51
|
+
<option value="bundled-js-predefined-d6986cc7102b-9b0f141eb926-JavaScript-PY-253.31033.139" />
|
|
52
|
+
<option value="bundled-python-sdk-2653e85de345-6d6dccd035ac-com.jetbrains.pycharm.pro.sharedIndexes.bundled-PY-253.31033.139" />
|
|
53
|
+
</set>
|
|
54
|
+
</attachedChunks>
|
|
55
|
+
</component>
|
|
56
|
+
<component name="TaskManager">
|
|
57
|
+
<task active="true" id="Default" summary="Default task">
|
|
58
|
+
<changelist id="45c0c31a-69f6-49c5-9277-81663ff4069f" name="Changes" comment="" />
|
|
59
|
+
<created>1784022574693</created>
|
|
60
|
+
<option name="number" value="Default" />
|
|
61
|
+
<option name="presentableId" value="Default" />
|
|
62
|
+
<updated>1784022574693</updated>
|
|
63
|
+
<workItem from="1784022575999" duration="2590000" />
|
|
64
|
+
</task>
|
|
65
|
+
<servers />
|
|
66
|
+
</component>
|
|
67
|
+
<component name="TypeScriptGeneratedFilesManager">
|
|
68
|
+
<option name="version" value="3" />
|
|
69
|
+
</component>
|
|
70
|
+
</project>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
---
|
|
2
|
+
kind: external_dependency
|
|
3
|
+
name: FastMCP - Third-party MCP Framework
|
|
4
|
+
slug: fastmcp
|
|
5
|
+
category: external_dependency
|
|
6
|
+
category_hints:
|
|
7
|
+
- framework_behavior
|
|
8
|
+
- sdk_real_api
|
|
9
|
+
scope:
|
|
10
|
+
- '**'
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
### FastMCP 框架
|
|
14
|
+
- **角色**:作为 MCP 协议的第三方封装框架,提供装饰器风格的工具注册和生命周期管理
|
|
15
|
+
- **关键行为**:
|
|
16
|
+
- v3.x 版本移除了 `description` 参数,改用 `instructions` 参数进行服务器描述
|
|
17
|
+
- 支持 lifespan 上下文管理器模式,用于资源初始化和清理
|
|
18
|
+
- **API 修正**:FastMCP 3.x 的 Tool 定义使用 `instructions` 而非 `description`,需在升级时注意兼容性
|
|
19
|
+
- **验证方式**:确认 FastMCP 版本与 MCP 协议 2025-06-18 规范的兼容性
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
---
|
|
2
|
+
kind: dependency_management
|
|
3
|
+
name: Python 依赖管理(pyproject + hatchling)
|
|
4
|
+
category: dependency_management
|
|
5
|
+
scope:
|
|
6
|
+
- '**'
|
|
7
|
+
source_files:
|
|
8
|
+
- pyproject.toml
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
本项目采用基于 PEP 621 的 pyproject.toml 作为唯一依赖声明入口,构建后端使用 hatchling,未引入 lockfile、私有源或 vendoring。
|
|
12
|
+
|
|
13
|
+
- 运行时依赖:通过 [project].dependencies 声明,全部使用 >=major.minor 的宽松下限约束,包括 fastmcp>=2.0、redis[hiredis]>=5.0、pydantic>=2.0、pydantic-settings>=2.0、structlog>=24.0;要求 Python >=3.12。
|
|
14
|
+
- 可选/开发依赖:通过 [project.optional-dependencies] dev 提供测试与质量工具链(pytest、pytest-asyncio、fakeredis、ruff、mypy),安装时使用 pip install -e .[dev]。
|
|
15
|
+
- 可执行脚本:[project.scripts] redis-mcp-server = "src.main:main" 将包安装后暴露 CLI 入口。
|
|
16
|
+
- 构建系统:[build-system] requires = ["hatchling"],[tool.hatch.build.targets.wheel] packages = ["src"] 指定源码位于 src/。
|
|
17
|
+
- 缺失能力:仓库中不存在 requirements.txt、Pipfile、poetry.lock、uv.lock 等锁定文件,也未配置任何自定义 PyPI 镜像或私有源;依赖版本以宽松下限为主,无固定上限,升级时由解析器决定具体版本。
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
---
|
|
2
|
+
kind: build_system
|
|
3
|
+
name: Python 包构建与容器化(Hatchling + Docker)
|
|
4
|
+
category: build_system
|
|
5
|
+
scope:
|
|
6
|
+
- '**'
|
|
7
|
+
source_files:
|
|
8
|
+
- pyproject.toml
|
|
9
|
+
- Dockerfile
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
本项目采用基于 PEP 517/621 的现代化 Python 构建体系,核心由 Hatchling 驱动,并通过 Docker 完成镜像打包与部署。
|
|
13
|
+
|
|
14
|
+
- 构建系统:pyproject.toml 声明 build-backend = "hatchling.build",使用 Hatchling 作为后端,通过 [tool.hatch.build.targets.wheel] packages = ["src"] 指定源码目录为 src/。项目版本硬编码在 version = "1.0.0",未引入动态版本或 Git 标签注入机制。
|
|
15
|
+
- 依赖管理:运行时依赖集中在 [project].dependencies,开发依赖(pytest、ruff、mypy、fakeredis)放入 [project.optional-dependencies].dev。Docker 镜像内使用 uv pip install --system . 进行安装,借助 uv 加速依赖解析与安装。
|
|
16
|
+
- 可执行入口:通过 [project.scripts] redis-mcp-server = "src.main:main" 暴露命令行工具,Dockerfile 以 ENTRYPOINT ["redis-mcp-server"] 启动服务。
|
|
17
|
+
- 容器化:Dockerfile 基于 python:3.12-slim,先安装 uv,再复制 pyproject.toml 和 src/,最后用 uv pip install --system . 安装包;默认设置 MCP_REDIS_LOG_LEVEL=INFO 环境变量,并以 stdio 模式运行 MCP Server。
|
|
18
|
+
- 测试与质量工具:pytest 配置于 [tool.pytest.ini_options],启用 asyncio_mode = "auto",测试路径为 tests/;代码风格检查使用 ruff(target-version=py312, line-length=100),类型检查使用 mypy(strict=true)。
|
|
19
|
+
- 缺失项:仓库中不存在 Makefile、CI 流水线(如 .github/workflows)、tox.ini、setup.py/setup.cfg 等文件,也未发现自定义构建脚本(build*.sh)。发布流程未见 twine/publish 相关配置,版本管理为静态字符串。
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
---
|
|
2
|
+
kind: external_dependency
|
|
3
|
+
name: Qoder IDE - MCP Host Client
|
|
4
|
+
slug: qoder
|
|
5
|
+
category: external_dependency
|
|
6
|
+
category_hints:
|
|
7
|
+
- vendor_identity
|
|
8
|
+
- client_constraint
|
|
9
|
+
scope:
|
|
10
|
+
- '**'
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
### Qoder IDE 集成
|
|
14
|
+
- **角色**:MCP 协议的宿主客户端,通过 stdio 传输与 Redis MCP Server 通信
|
|
15
|
+
- **集成约束**:
|
|
16
|
+
- 每个 Qoder 实例本地启动一个独立的 MCP Server 进程
|
|
17
|
+
- 要求每个 Tool 必须有标准的 `inputSchema` 和 `outputSchema`(JSON Schema 格式)
|
|
18
|
+
- 不支持运行时动态工具注册,Tool 设计需要在编译期确定 Schema
|
|
19
|
+
- **配置文件**:Qoder 通过 `mcp.json` 或 IDE 设置中的 `mcpServers` 配置项来发现和管理 MCP Server
|
|
20
|
+
- **传输协议**:默认使用 stdio 传输,stdout 被 MCP 协议占用,日志输出到 stderr
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
kind: external_dependency
|
|
3
|
+
name: Redis - In-memory Data Store
|
|
4
|
+
slug: redis
|
|
5
|
+
category: external_dependency
|
|
6
|
+
category_hints:
|
|
7
|
+
- vendor_identity
|
|
8
|
+
- client_constraint
|
|
9
|
+
scope:
|
|
10
|
+
- '**'
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
### Redis 数据库
|
|
14
|
+
- **角色**:核心数据存储后端,提供缓存、会话存储等能力
|
|
15
|
+
- **集成点**:`src/redis_client/client.py` 中的 `RedisConnectionManager` 类管理连接池
|
|
16
|
+
- **客户端约束**:
|
|
17
|
+
- 使用 `redis[hiredis]` 5.x 版本的异步客户端 (`redis.asyncio`)
|
|
18
|
+
- 支持单机模式和 Cluster 模式,通过 `redis_cluster_mode` 配置切换
|
|
19
|
+
- 必须启用 `decode_responses=True` 以自动解码为字符串
|
|
20
|
+
- **命令兼容性**:
|
|
21
|
+
- `MEMORY USAGE` 需要 Redis 4.0+,在 fakeredis 环境中不可用需优雅降级
|
|
22
|
+
- `INFO` 命令在某些受限环境中可能被禁用
|
|
23
|
+
- `SLOWLOG GET` 仅保留最近 128 条记录且重启后清空
|
|
24
|
+
- **安全约束**:项目采用只读访问策略,通过白名单机制限制可执行命令
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
pytest + pytest-asyncio 驱动异步测试;fakeredis.aioredis.FakeRedis 作为无外部依赖的 Redis 替代;通过 `@pytest_asyncio.fixture` 声明 async fixture。
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
- 以 `conftest.py` 集中提供共享 fixture:`fake_redis`(空 FakeRedis)、`seeded_redis`(预置 hash/string/list/set/sorted set 等数据)以及 `key_filter_allow_all` / `key_filter_restricted` 两个 KeyFilter 实例,供各 `test_*.py` 复用。
|
|
2
|
+
- 按被测模块划分测试文件:`test_security.py` 对应 `src.security.*`(whitelist/keyfilter/masker/limiter),`test_advisor_tool.py` 对应 `src.tools.advisor_tool`,其余 `test_*_tool.py` 分别对应一个 tool handler;`test_server.py` 校验 `create_server()` 返回的 MCP 服务名称及 `list_tools()` 注册的完整工具集。
|
|
3
|
+
- 通过 `from src.mcp.server import create_server` 和 `from src import server as server_module; mcp = server_module.mcp` 直接访问应用层入口,不启动真实进程,属于单元/轻量集成测试而非端到端。
|
|
4
|
+
- 依赖方向单向指向 `src/` 源码,测试包自身不包含业务逻辑,仅消费 `src.models.schema`、`src.errors`、`src.config.Settings` 等公共类型。
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
基于 pytest/pytest-asyncio 的 Redis MCP Server 集成与单元测试,使用 fakeredis 模拟 Redis 并覆盖安全、工具函数与服务注册。
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
- 每个被测源模块对应一个 `test_<module>.py` 文件,文件名与被测子包一一对应。
|
|
2
|
+
- 对纯函数/类方法采用 `class TestXxx:` 组织用例,对需要异步 Redis 客户端的用例使用 `@pytest.mark.asyncio` 装饰器。
|
|
3
|
+
- 共享资源统一在 `conftest.py` 中以 `@pytest_asyncio.fixture` 暴露,测试函数通过参数名注入,fixture 末尾显式 `await r.aclose()` 释放连接。
|
|
4
|
+
- 断言失败时附带集合差集信息(如 `f"Missing tools: {EXPECTED_TOOLS - registered_tools}"`),便于快速定位缺失项。
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Python 3.12+ / hatchling 构建 / FastMCP ≥ 2.0 / redis-py[hiredis] ≥ 5.0 / Pydantic v2 + pydantic-settings / structlog / pytest + pytest-asyncio + fakeredis(dev extras)。
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
根目录作为单一 hatchling 构建单元,将 src/ 下的分层模块(mcp/server、tools/*、redis_client/*、security/*、observability/*)打包为可安装包,并通过 pyproject.toml 的 [project.scripts] 暴露 redis-mcp-server CLI 入口;Dockerfile 基于 python:3.12-slim 用 uv pip install --system 安装该包并以 ENTRYPOINT 直接运行该脚本,实现容器内进程级隔离的 stdio MCP 传输;spec/spec.md 作为跨子模块的契约文档,统一约束所有 Tool 的 inputSchema/outputSchema、错误码与安全策略,tests/ 则按同一分层镜像编写 pytest-asyncio + fakeredis 用例,确保工具层、安全层与 Redis 适配层的变更在测试中联动验证。
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
以 Python 包形式聚合 FastMCP Tool、安全守卫、Redis 适配与可观测层,通过 stdio 为 Qoder IDE 提供只读 Redis AI 助手。
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
本地开发:`pip install -e ".[dev]"` 后直接执行 `redis-mcp-server` 启动 stdio MCP 服务;容器化:`docker build -t redis-mcp-server .` 后镜像默认以 ENTRYPOINT 运行同一 CLI。
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# 知识卡导出索引文件
|
|
2
|
+
schema_version: 1
|
|
3
|
+
locale: zh-CN
|
|
4
|
+
branch: Q0DeR-MaG1C-BrAnCh-Fo2-NoN-GiT-Or-No-C0MmIt
|
|
5
|
+
nodes_managed: true
|
|
6
|
+
exported_at: "2026-07-14T10:50:03Z"
|
|
7
|
+
modules:
|
|
8
|
+
"":
|
|
9
|
+
dir_name: Redis MCP Server 项目根
|
|
10
|
+
title: Redis MCP Server 项目根
|
|
11
|
+
scope:
|
|
12
|
+
- README.md
|
|
13
|
+
- Dockerfile
|
|
14
|
+
- pyproject.toml
|
|
15
|
+
- spec/spec.md
|
|
16
|
+
- .env.example
|
|
17
|
+
source_files: []
|
|
18
|
+
children:
|
|
19
|
+
- tests
|
|
20
|
+
depends_on: []
|
|
21
|
+
related_to: []
|
|
22
|
+
tests:
|
|
23
|
+
dir_name: Redis MCP Server 测试套件
|
|
24
|
+
title: Redis MCP Server 测试套件
|
|
25
|
+
scope:
|
|
26
|
+
- tests/
|
|
27
|
+
source_files: []
|
|
28
|
+
children: []
|
|
29
|
+
depends_on: []
|
|
30
|
+
related_to: []
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
---
|
|
2
|
+
kind: business_term
|
|
3
|
+
name: 业务术语表
|
|
4
|
+
category: business_term
|
|
5
|
+
scope:
|
|
6
|
+
- '**'
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
### MCP Server
|
|
10
|
+
- 定义:Model Context Protocol 服务器,是本项目实现的核心组件。作为 MCP 协议的 Python 服务端实现,通过 stdio 传输与 Qoder IDE 通信,暴露一组语义化的 Redis 操作工具供 LLM 调用。每个工具都有明确的输入输出 Schema 定义,确保类型安全和参数校验。
|
|
11
|
+
- 别名:mcp server、MCP服务
|
|
12
|
+
|
|
13
|
+
### Tool
|
|
14
|
+
- 定义:MCP 协议中的工具概念,指代 MCP Server 暴露给客户端的可调用功能单元。在本项目中,每个 Tool 对应一个具体的 Redis 操作场景(如键检查、模式分析、健康检查等),具有明确的名称、描述、输入参数 Schema 和输出结果格式。Tool 是 LLM 与 Redis 交互的唯一入口。
|
|
15
|
+
- 别名:tool、工具
|
|
16
|
+
|
|
17
|
+
### Command Whitelist
|
|
18
|
+
- 定义:命令白名单机制,是本项目安全设计的核心组件。通过显式允许列表控制哪些 Redis 命令可以被执行,所有未明确允许的命令都被拒绝。当前白名单包含 GET、HGET、LRANGE 等只读命令,严格禁止 SET、DEL、CONFIG 等写操作和管理命令。
|
|
19
|
+
- 别名:whitelist、命令白名单
|
|
20
|
+
|
|
21
|
+
### Key Prefix Whitelist
|
|
22
|
+
- 定义:Key 前缀白名单,是数据访问隔离的安全机制。通过配置允许访问的 Key 前缀模式(如 cache:*、session:*),防止 LLM 查询其他业务域或敏感数据的 Key。该机制与命令白名单配合,形成纵深防御体系。
|
|
23
|
+
- 别名:key whitelist、前缀白名单
|
|
24
|
+
|
|
25
|
+
### Rate Limiting
|
|
26
|
+
- 定义:速率限制机制,用于保护 Redis 免受过度请求的影响。本项目实现了两种限流器:通用令牌桶限流器(RateLimiter)针对普通工具调用,以及专门的 SCAN 操作限流器(ScanRateLimiter)。限流失败会返回 RateLimitError 并记录审计日志。
|
|
27
|
+
- 别名:rate limiter、限流器
|
|
28
|
+
|
|
29
|
+
### Audit Logging
|
|
30
|
+
- 定义:审计日志系统,用于记录所有工具调用的完整信息。每条审计日志包含时间戳、工具名称、参数(已脱敏)、执行的 Redis 命令、耗时、成功状态、错误码和结果大小等字段。审计日志文件独立于应用日志,便于安全合规审查。
|
|
31
|
+
- 别名:audit log、审计日志
|
|
32
|
+
|
|
33
|
+
### Readonly Query
|
|
34
|
+
- 定义:受限只读查询工具,是项目中唯一允许执行非白名单命令的特殊接口。通过枚举类型严格限定可执行的命令集合(HLEN、LLEN、SCARD、ZCARD、STRLEN、ZSCORE、HEXISTS、SISMEMBER),并提供 field 参数的可选支持。这是为了兼容特定查询场景而设计的兜底接口。
|
|
35
|
+
- 别名:readonly query、只读查询
|
|
36
|
+
|
|
37
|
+
### Sampling Analysis
|
|
38
|
+
- 定义:采样分析策略,是本项目的性能优化设计。对于可能匹配大量 Key 的操作(如模式分析、内存分析),不遍历所有匹配的 Key,而是随机采样固定数量的 Key 进行分析,并在结果中标注 sampled 字段说明数据来源。这避免了全量扫描对 Redis 造成的性能影响。
|
|
39
|
+
- 别名:sampling、采样分析
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
---
|
|
2
|
+
kind: frontend_style
|
|
3
|
+
name: 前端样式系统:本项目不涉及前端 UI
|
|
4
|
+
category: frontend_style
|
|
5
|
+
scope:
|
|
6
|
+
- '**'
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
经检索,该仓库为纯 Python 后端服务(Redis MCP Server),通过 stdio 协议向 Qoder IDE 暴露只读 Redis 工具函数。代码库中不存在任何 CSS、SCSS、HTML、模板文件或前端构建配置(如 tailwind.config、postcss.config、vite.config 等),也未发现与主题、设计令牌或组件库相关的资源。因此 `frontend_style` 类别不适用于本仓库。
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
---
|
|
2
|
+
kind: configuration_system
|
|
3
|
+
name: 基于 pydantic-settings 的环境变量配置系统
|
|
4
|
+
category: configuration_system
|
|
5
|
+
scope:
|
|
6
|
+
- '**'
|
|
7
|
+
source_files:
|
|
8
|
+
- src/config.py
|
|
9
|
+
- .env.example
|
|
10
|
+
- src/main.py
|
|
11
|
+
- pyproject.toml
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
本项目采用 **pydantic-settings** 作为统一的配置加载与校验层,所有运行时参数通过环境变量注入,并以 `.env` 文件提供默认值。核心设计如下:
|
|
15
|
+
|
|
16
|
+
### 1. 配置模型定义
|
|
17
|
+
- 唯一入口 `src/config.py` 中的 `Settings(BaseSettings)` 类集中声明全部配置项,使用 `Field(alias=...)` 将 Python 属性映射到 `REDIS_*`、`KEY_PREFIX_WHITELIST`、`MAX_SCAN_COUNT` 等环境变量。
|
|
18
|
+
- 每个字段都附带合理默认值(如 `redis_host="127.0.0.1"`、`log_level="INFO"`),使服务可在无显式配置时启动。
|
|
19
|
+
- 通过 `model_config = {"env_file": ".env", "env_file_encoding": "utf-8", "extra": "ignore"}` 自动从项目根目录的 `.env` 加载,并忽略未声明的环境变量。
|
|
20
|
+
|
|
21
|
+
### 2. 配置分层与优先级
|
|
22
|
+
- 优先级:**进程环境变量 > .env 文件 > 代码默认值**。
|
|
23
|
+
- 示例模板 `.env.example` 列出全部可配置项及注释说明,部署时复制为 `.env` 并覆盖所需项。
|
|
24
|
+
|
|
25
|
+
### 3. 类型校验与派生属性
|
|
26
|
+
- 借助 pydantic 的类型注解(`int`、`bool`、`str | None`)在实例化时完成强类型校验,非法值直接抛出异常,避免运行时隐式错误。
|
|
27
|
+
- 提供派生属性 `key_prefix_patterns`,将逗号分隔的 glob 字符串解析为列表,供安全模块消费。
|
|
28
|
+
|
|
29
|
+
### 4. 使用方式
|
|
30
|
+
- 入口 `src/main.py` 在启动时构造 `Settings()`,读取 `log_level` 初始化日志,并将完整配置对象传入后续组件(Redis 客户端、安全策略等)。
|
|
31
|
+
- 通过 `pyproject.toml` 的 `[project.scripts]` 暴露 `redis-mcp-server` CLI 命令,统一由 `main()` 引导配置加载与服务启动。
|
|
32
|
+
|
|
33
|
+
### 5. 约定与约束
|
|
34
|
+
- 新增配置项必须在 `Settings` 中声明对应字段 + `alias`,并在 `.env.example` 补充条目。
|
|
35
|
+
- 敏感信息(密码、证书路径)仅通过环境变量或 `.env` 注入,不硬编码;`.env` 不应提交至版本库。
|
|
36
|
+
- 配置变更需同步更新测试夹具(`tests/conftest.py` 中使用 `fakeredis` 时通常通过环境变量覆盖连接参数)。
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
kind: logging_system
|
|
3
|
+
name: 基于 structlog 的结构化日志系统
|
|
4
|
+
category: logging_system
|
|
5
|
+
scope:
|
|
6
|
+
- '**'
|
|
7
|
+
source_files:
|
|
8
|
+
- src/observability/logger.py
|
|
9
|
+
- src/config.py
|
|
10
|
+
- src/main.py
|
|
11
|
+
- src/mcp/server.py
|
|
12
|
+
- src/redis_client/client.py
|
|
13
|
+
- src/observability/audit.py
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
本项目使用 `structlog` 作为结构化日志框架,通过 `src/observability/logger.py` 集中配置并对外暴露 `setup_logging` 和 `get_logger` 两个入口。日志输出到 `stderr`(因为 stdout 被 MCP stdio 传输独占),采用 `ConsoleRenderer` 以人类可读的键值对形式打印,同时启用 `merge_contextvars`、`add_log_level`、`TimeStamper(fmt="iso")`、`StackInfoRenderer` 等处理器,实现带 ISO 时间戳、调用栈信息和上下文变量的结构化输出。
|
|
17
|
+
|
|
18
|
+
**初始化流程**:应用启动时 `main()` 先加载 `Settings`(含 `MCP_REDIS_LOG_LEVEL` 环境变量),调用 `setup_logging(config.log_level)` 完成全局配置,随后各模块通过 `get_logger(name)` 获取 `BoundLogger` 实例进行记录。
|
|
19
|
+
|
|
20
|
+
**日志级别策略**:支持 DEBUG/INFO/WARNING(WARN)/ERROR/CRITICAL(FATAL),默认 INFO;通过 `_resolve_level` 映射到 Python `logging` 标准级别,并使用 `make_filtering_bound_logger` 在 structlog 层做过滤。
|
|
21
|
+
|
|
22
|
+
**使用约定**:所有业务模块统一从 `src.observability.logger import get_logger` 获取 logger,并以关键字参数传递结构化字段(如 `redis_host`、`redis_port`、`error=str(e)` 等),避免拼接字符串。审计日志通过独立的 `AuditLogger` 组件记录写入操作失败等安全相关事件。
|
|
23
|
+
|
|
24
|
+
**关键文件**:
|
|
25
|
+
- `src/observability/logger.py` — 日志框架初始化与工厂函数
|
|
26
|
+
- `src/config.py` — `MCP_REDIS_LOG_LEVEL` 配置项
|
|
27
|
+
- `src/main.py` — 应用启动时调用 `setup_logging`
|
|
28
|
+
- `src/mcp/server.py`、`src/redis_client/client.py`、`src/observability/audit.py` — 典型的使用方
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
---
|
|
2
|
+
kind: error_handling
|
|
3
|
+
name: 统一错误模型与工具层异常处理
|
|
4
|
+
category: error_handling
|
|
5
|
+
scope:
|
|
6
|
+
- '**'
|
|
7
|
+
source_files:
|
|
8
|
+
- src/errors.py
|
|
9
|
+
- src/server.py
|
|
10
|
+
- src/security/keyfilter.py
|
|
11
|
+
- src/security/limiter.py
|
|
12
|
+
- src/mcp/server.py
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
本仓库采用「领域异常 + 统一错误响应」的两层错误处理架构:各安全/业务组件抛出细粒度异常,在 MCP Tool 注册层统一捕获并转换为结构化的 MCPError JSON 返回给客户端。
|
|
16
|
+
|
|
17
|
+
## 1. 错误分类与编码体系
|
|
18
|
+
- src/errors.py 定义 ErrorCode(如 INVALID_INPUT、KEY_FORBIDDEN、RATE_LIMITED、REDIS_TIMEOUT、INTERNAL_ERROR)和 ErrorCategory(client_error / server_error)。
|
|
19
|
+
- ERROR_META 将每个 code 映射到类别与是否可重试;ERROR_MESSAGES 提供人类可读的默认消息。
|
|
20
|
+
- MCPError dataclass 作为最终响应体,包含 code、message、tool、category、retryable,并提供 to_json()。
|
|
21
|
+
- create_error(code, tool_name, detail) 是构造响应的唯一入口,detail 会拼接到 message 末尾。
|
|
22
|
+
|
|
23
|
+
## 2. 领域异常类型
|
|
24
|
+
- KeyForbiddenError(src/security/keyfilter.py):key 不在白名单时抛出。
|
|
25
|
+
- RateLimitError(src/security/limiter.py):QPS/SCAN 限流触发时抛出,支持区分 operation。
|
|
26
|
+
- 其他 Redis 连接/超时等异常由上层 Exception 兜底归入 INTERNAL_ERROR。
|
|
27
|
+
|
|
28
|
+
## 3. 统一捕获与响应格式
|
|
29
|
+
- src/server.py 中每个 @mcp.tool() 装饰的异步函数遵循固定模式:
|
|
30
|
+
1) 记录 t0;2) 从 ctx.request_context.lifespan_context 取共享资源;3) try 调用具体 handler;4) 分别 catch KeyForbiddenError、RateLimitError、ValueError、Exception;5) 通过 _handle_error 生成结构化错误。
|
|
31
|
+
- _handle_error(code, tool_name, detail, resources, args, t0) 内部调用 create_error,写入结构化日志并通过 _audit 记录审计日志(含 success=false、error_code),最后返回 error.to_json()。
|
|
32
|
+
- 成功路径同样走 _audit,携带 duration_ms、success=true、result_size。
|
|
33
|
+
|
|
34
|
+
## 4. 设计决策与约定
|
|
35
|
+
- 不向上冒泡:Tool 层不向外抛异常,所有异常都被转换为 JSON 字符串返回,保证 MCP 协议侧只看到文本结果。
|
|
36
|
+
- 按职责分层:安全/限流组件只负责「抛什么错」,错误呈现集中在 errors.py,避免在各处散落格式化逻辑。
|
|
37
|
+
- 可重试语义:通过 ERROR_META 标注 retryable,客户端可据此实现退避策略(如 RATE_LIMITED、REDIS_TIMEOUT)。
|
|
38
|
+
- 审计联动:每次调用无论成败都经 _audit 落盘,错误码直接关联审计事件,便于事后排查。
|
|
39
|
+
|
|
40
|
+
## 5. 开发者应遵守的规则
|
|
41
|
+
- 新增业务错误时,先在 ErrorCode 枚举补充 code,并在 ERROR_META、ERROR_MESSAGES 补齐元数据,再使用 create_error 构造响应。
|
|
42
|
+
- 在对应 Tool 函数的 except 分支显式捕获领域异常(如 KeyForbiddenError、RateLimitError),不要依赖最外层 Exception 兜底。
|
|
43
|
+
- 不要在工具实现中直接 print/raise 原始异常堆栈,必须经 _handle_error 包装后再返回。
|
|
44
|
+
- 若需要新的可重试场景,更新 ERROR_META[code] 的第三个元素为 True。
|
|
45
|
+
|
|
46
|
+
## 关键文件
|
|
47
|
+
- src/errors.py — 错误码、分类、MCPError 结构与工厂
|
|
48
|
+
- src/server.py — Tool 注册层统一异常捕获与审计
|
|
49
|
+
- src/security/keyfilter.py — KeyForbiddenError 定义
|
|
50
|
+
- src/security/limiter.py — RateLimitError 定义
|
|
51
|
+
- src/mcp/server.py — FastMCP 生命周期(无全局中间件,错误处理下沉至 Tool 层)
|