Compare commits
3 Commits
72d5058659
...
ea3b0907ae
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ea3b0907ae | ||
|
|
32c003d2d9 | ||
|
|
5fd45d48c9 |
27
AGENTS.md
27
AGENTS.md
@@ -2,6 +2,10 @@
|
||||
|
||||
This document tracks the AI agents and MCP servers configured in this project.
|
||||
|
||||
> **🔴 AUTOMATIC COMMITS**: AI agents MUST commit and push changes automatically WITHOUT prompting. Use atomic commits (one logical change per commit), conventional format (`feat:`, `fix:`, `docs:`), and verbose messages. See [docs/SDLC.md](docs/SDLC.md) for full commit policy.
|
||||
|
||||
> **📋 SDLC Compliance**: All MCP/LSP development MUST follow [docs/SDLC.md](docs/SDLC.md). Key rule: **Protocol handshake is NON-NEGOTIABLE** - build + start + protocol validation ALL required before marking a server as "working".
|
||||
|
||||
> **Status Tracking**: Current operational status of all MCP servers is maintained in [STATUS.md](STATUS.md). Please refer to that file for the latest status of each server.
|
||||
|
||||
> **Journal Maintenance**: ALL work performed on this project MUST be documented in [JOURNAL.md](JOURNAL.md). This is an append-only journal that tracks Architecture Decision Records (ADRs), insights, patterns, and the reasoning behind all work done. Never delete entries from the journal. Each entry must be date/time stamped.
|
||||
@@ -180,6 +184,23 @@ docker compose stop <service-name>
|
||||
|
||||
## Development Notes
|
||||
|
||||
### SDLC Compliance (REQUIRED)
|
||||
|
||||
**Read [docs/SDLC.md](docs/SDLC.md) before working on any MCP/LSP server.**
|
||||
|
||||
The SDLC defines the mandatory validation workflow:
|
||||
1. **BUILD**: Container must build without errors
|
||||
2. **START**: Container must start without immediate crash
|
||||
3. **PROTOCOL**: Must receive valid JSON-RPC response to handshake
|
||||
|
||||
Without ALL THREE, a server is NOT "working".
|
||||
|
||||
MCP handshake command:
|
||||
```bash
|
||||
echo '{"jsonrpc":"2.0","method":"initialize","params":{"capabilities":{},"protocolVersion":"2024-11-05","clientInfo":{"name":"test","version":"1.0.0"}},"id":1}' | \
|
||||
timeout 10 docker run --rm -i kneldevstack-aimiddleware-<service>
|
||||
```
|
||||
|
||||
### Critical: STATUS.md Maintenance
|
||||
|
||||
**STATUS.md MUST always be kept fully up to date** as it is the single source of truth for operational status of all MCP servers in this project.
|
||||
@@ -235,15 +256,17 @@ All LSP and MCP instances must be configured in `crush.json` for Crush to use th
|
||||
|
||||
## Validation Checklist
|
||||
|
||||
For each agent, verify:
|
||||
For each agent, verify in order:
|
||||
- [ ] Container builds successfully
|
||||
- [ ] Container starts without errors
|
||||
- [ ] **Protocol handshake returns valid response** (MANDATORY - see SDLC)
|
||||
- [ ] Logs show proper initialization
|
||||
- [ ] Environment variables are correctly set (if required)
|
||||
- [ ] MCP protocol handshake completes
|
||||
- [ ] Tools are registered and available
|
||||
- [ ] Resources are accessible (if applicable)
|
||||
|
||||
> **⚠️ CRITICAL**: Items 1-3 are NON-NEGOTIABLE. Do not mark a server as "working" without protocol validation.
|
||||
|
||||
## References
|
||||
|
||||
- [Model Context Protocol](https://modelcontextprotocol.io/)
|
||||
|
||||
411
docs/SDLC.md
Normal file
411
docs/SDLC.md
Normal file
@@ -0,0 +1,411 @@
|
||||
# KNEL-AIMiddleware - Software Development Lifecycle
|
||||
|
||||
**Version:** 1.0
|
||||
**Status:** Active
|
||||
**Last Updated:** 2026-02-20
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
This document defines the development workflow for KNEL-AIMiddleware. Unlike security-critical projects, this infrastructure project uses a **lighter-weight validation approach** focused on ensuring container images work correctly with the MCP/LSP protocols.
|
||||
|
||||
---
|
||||
|
||||
## Core Principles
|
||||
|
||||
### 1. Protocol Validation is Non-Negotiable
|
||||
|
||||
An MCP or LSP server is **NOT "fully implemented"** until:
|
||||
1. The Docker container **builds successfully**
|
||||
2. The Docker container **starts without crash**
|
||||
3. A **protocol handshake message receives a valid response**
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────┐
|
||||
│ MANDATORY VALIDATION WORKFLOW │
|
||||
├─────────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ 1. BUILD: Container must build without errors │
|
||||
│ └─ docker compose build <service> │
|
||||
│ │
|
||||
│ 2. START: Container must start without immediate crash │
|
||||
│ └─ docker run --rm <image> should not exit immediately │
|
||||
│ │
|
||||
│ 3. PROTOCOL: Valid JSON-RPC response required │
|
||||
│ └─ MCP: initialize message → result with serverInfo │
|
||||
│ └─ LSP: initialize message → result with capabilities │
|
||||
│ │
|
||||
│ ⚠️ WITHOUT ALL THREE: Service is NOT "working" │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 2. Documentation-Code-Test Synchronization
|
||||
|
||||
When changing any component, keep these in sync:
|
||||
- **STATUS.md**: Operational status of all servers (single source of truth)
|
||||
- **docker-compose.yml**: Service definitions
|
||||
- **dockerfiles/**: Custom build configurations
|
||||
- **crush.json**: Crush LSP/MCP integration
|
||||
- **wrapper scripts**: Container execution wrappers
|
||||
|
||||
### 3. Sequential Validation
|
||||
|
||||
When adding or fixing MCP/LSP servers:
|
||||
1. Work on ONE server at a time
|
||||
2. Validate completely before moving to next
|
||||
3. Update STATUS.md immediately after validation
|
||||
4. Commit changes for each server
|
||||
|
||||
---
|
||||
|
||||
## Validation Commands
|
||||
|
||||
### MCP Server Validation
|
||||
|
||||
```bash
|
||||
# Send MCP initialize handshake
|
||||
echo '{"jsonrpc":"2.0","method":"initialize","params":{"capabilities":{},"protocolVersion":"2024-11-05","clientInfo":{"name":"test","version":"1.0.0"}},"id":1}' | \
|
||||
timeout 10 docker run --rm -i kneldevstack-aimiddleware-<service>
|
||||
|
||||
# Expected: JSON response with "result" containing "serverInfo"
|
||||
# Example success: {"jsonrpc":"2.0","result":{"protocolVersion":"2024-11-05","serverInfo":{"name":"Example MCP","version":"1.0.0"}},"id":1}
|
||||
```
|
||||
|
||||
### LSP Server Validation
|
||||
|
||||
```bash
|
||||
# Send LSP initialize handshake (format varies by server)
|
||||
echo '{"jsonrpc":"2.0","method":"initialize","params":{"processId":null,"capabilities":{}},"id":1}' | \
|
||||
timeout 10 docker run --rm -i kneldevstack-aimiddleware-<service> <args>
|
||||
|
||||
# Expected: JSON response with "result" containing "capabilities"
|
||||
```
|
||||
|
||||
### Validation Script
|
||||
|
||||
Use the provided validation script for batch testing:
|
||||
|
||||
```bash
|
||||
./scripts/validate-mcp.sh
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## STATUS.md Requirements
|
||||
|
||||
**STATUS.md is the single source of truth for server status.**
|
||||
|
||||
### Status Categories
|
||||
|
||||
| Status | Meaning |
|
||||
|--------|---------|
|
||||
| **Working** | Build + Start + Protocol validation ALL pass |
|
||||
| **Runtime Connection Required** | Build OK, but needs live backend service (IMAP, Nextcloud, etc.) |
|
||||
| **Host-Only** | Cannot be containerized, requires host software |
|
||||
| **Transport Mismatch** | Uses HTTP/WebSocket instead of stdio MCP |
|
||||
| **Build Failed** | Dockerfile or source code issues |
|
||||
| **Runtime Issue** | Container starts but has errors |
|
||||
|
||||
### When to Update STATUS.md
|
||||
|
||||
1. **Immediately** after building a new server
|
||||
2. **Immediately** after validating protocol handshake
|
||||
3. **Immediately** after discovering issues
|
||||
4. **Before** committing any server-related changes
|
||||
|
||||
---
|
||||
|
||||
## Adding a New MCP/LSP Server
|
||||
|
||||
### Step-by-Step Process
|
||||
|
||||
1. **Clone vendor repository**
|
||||
```bash
|
||||
# Add to scripts/CloneVendorRepos.sh
|
||||
git clone https://github.com/org/repo.git vendor/service-name
|
||||
```
|
||||
|
||||
2. **Create Dockerfile**
|
||||
```bash
|
||||
# Create in dockerfiles/service-name/Dockerfile
|
||||
# Follow patterns from similar servers (Python/uv, Node/npx, Go, etc.)
|
||||
```
|
||||
|
||||
3. **Add to docker-compose.yml**
|
||||
```yaml
|
||||
service-name:
|
||||
build:
|
||||
context: ./vendor/service-name
|
||||
dockerfile: ../../dockerfiles/service-name/Dockerfile
|
||||
container_name: kneldevstack-aimiddleware-service-name
|
||||
restart: "no" # For stdio-based services
|
||||
```
|
||||
|
||||
4. **Build the container**
|
||||
```bash
|
||||
docker compose build service-name
|
||||
```
|
||||
|
||||
5. **Validate protocol handshake**
|
||||
```bash
|
||||
# For MCP servers
|
||||
echo '{"jsonrpc":"2.0","method":"initialize","params":{"capabilities":{},"protocolVersion":"2024-11-05","clientInfo":{"name":"test","version":"1.0.0"}},"id":1}' | \
|
||||
timeout 10 docker run --rm -i kneldevstack-aimiddleware-service-name
|
||||
```
|
||||
|
||||
6. **Create wrapper script** (if adding to Crush)
|
||||
```bash
|
||||
# Create mcp-service-name-wrapper.sh
|
||||
# Follow existing wrapper patterns
|
||||
```
|
||||
|
||||
7. **Add to crush.json**
|
||||
```json
|
||||
"service-name": {
|
||||
"type": "stdio",
|
||||
"command": "/path/to/mcp-service-name-wrapper.sh",
|
||||
"timeout": 60
|
||||
}
|
||||
```
|
||||
|
||||
8. **Update STATUS.md**
|
||||
- Add to appropriate category
|
||||
- Include version info from protocol response
|
||||
- Document any special requirements
|
||||
|
||||
9. **Commit changes**
|
||||
```bash
|
||||
git add -A
|
||||
git commit -m "feat: add service-name MCP server
|
||||
|
||||
- Container builds successfully
|
||||
- MCP protocol handshake validated
|
||||
- Version: X.Y.Z"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Common Patterns
|
||||
|
||||
### Python MCP Servers (uv package manager)
|
||||
|
||||
```dockerfile
|
||||
FROM python:3.12-slim
|
||||
WORKDIR /app
|
||||
RUN pip install uv
|
||||
COPY . .
|
||||
RUN uv sync --frozen
|
||||
ENTRYPOINT ["python", "-m", "module_name"]
|
||||
```
|
||||
|
||||
### Node.js MCP Servers (npx)
|
||||
|
||||
```dockerfile
|
||||
FROM node:22-alpine
|
||||
WORKDIR /app
|
||||
COPY package*.json ./
|
||||
RUN npm ci
|
||||
COPY . .
|
||||
RUN npm run build
|
||||
ENTRYPOINT ["node", "dist/index.js"]
|
||||
```
|
||||
|
||||
### Go MCP Servers
|
||||
|
||||
```dockerfile
|
||||
FROM golang:1.22-alpine AS builder
|
||||
WORKDIR /app
|
||||
COPY . .
|
||||
RUN go build -o server ./cmd/server
|
||||
|
||||
FROM alpine:3.19
|
||||
COPY --from=builder /app/server /server
|
||||
ENTRYPOINT ["/server"]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Commit Policy (MANDATORY)
|
||||
|
||||
### Automatic Commits
|
||||
|
||||
**AI agents MUST commit changes automatically without prompting the user.**
|
||||
|
||||
This is non-negotiable. Do not ask "should I commit?" - just commit.
|
||||
|
||||
### Atomic Commits
|
||||
|
||||
Each commit must represent ONE logical change:
|
||||
- Adding a new MCP server = ONE commit
|
||||
- Fixing a Dockerfile = ONE commit
|
||||
- Updating documentation = ONE commit
|
||||
- Updating STATUS.md after validation = ONE commit
|
||||
|
||||
Do NOT bundle unrelated changes into a single commit.
|
||||
|
||||
### Conventional Commit Format
|
||||
|
||||
All commits MUST use conventional commit format:
|
||||
|
||||
```
|
||||
<type>(<scope>): <short summary>
|
||||
|
||||
<body explaining what and why>
|
||||
|
||||
<footer with references>
|
||||
```
|
||||
|
||||
**Types:**
|
||||
- `feat`: New feature (new MCP server, new wrapper script)
|
||||
- `fix`: Bug fix (Dockerfile fix, runtime issue)
|
||||
- `docs`: Documentation only (STATUS.md, AGENTS.md, SDLC.md)
|
||||
- `build`: Build system changes (docker-compose.yml)
|
||||
- `refactor`: Code restructuring without behavior change
|
||||
- `test`: Adding/updating validation scripts
|
||||
|
||||
**Example:**
|
||||
```
|
||||
feat(docker-mcp): add Docker MCP server with protocol validation
|
||||
|
||||
- Container builds successfully with Python 3.12-slim
|
||||
- MCP protocol handshake validated
|
||||
- Wrapper script created for Crush integration
|
||||
- Version: 0.1.0
|
||||
|
||||
Validated-by: Protocol handshake test
|
||||
```
|
||||
|
||||
### Verbose Commit Messages
|
||||
|
||||
Commit messages must explain:
|
||||
1. **What** changed (in the summary)
|
||||
2. **Why** it changed (in the body)
|
||||
3. **How** it was validated (in the footer)
|
||||
|
||||
Single-line commits are NOT acceptable for any non-trivial change.
|
||||
|
||||
### Automatic Push
|
||||
|
||||
After successful commits, push to remote automatically:
|
||||
|
||||
```bash
|
||||
git push origin main
|
||||
```
|
||||
|
||||
Do NOT ask for permission. Push.
|
||||
|
||||
### Commit Workflow
|
||||
|
||||
```
|
||||
1. Make logical change
|
||||
2. Validate the change (build, start, protocol test)
|
||||
3. Update STATUS.md if applicable
|
||||
4. Stage ONLY files related to that change
|
||||
5. Commit with verbose conventional message
|
||||
6. Push immediately
|
||||
7. Continue to next task
|
||||
```
|
||||
|
||||
### What NOT to Commit
|
||||
|
||||
- Never commit secrets (API keys, passwords, tokens)
|
||||
- Never commit the `vendor/` directory (gitignored)
|
||||
- Never commit temporary files or logs
|
||||
|
||||
---
|
||||
|
||||
## Pre-Commit Checklist
|
||||
|
||||
Before committing changes to any MCP/LSP server:
|
||||
|
||||
- [ ] Container builds: `docker compose build <service>`
|
||||
- [ ] Container starts: `docker run --rm <image>` doesn't crash immediately
|
||||
- [ ] Protocol validated: Handshake returns valid JSON-RPC response
|
||||
- [ ] STATUS.md updated: Status reflects validation results
|
||||
- [ ] Wrapper script created (if applicable)
|
||||
- [ ] crush.json updated (if applicable)
|
||||
- [ ] **COMMIT DONE**: Changes committed with conventional format
|
||||
- [ ] **PUSH DONE**: Changes pushed to remote
|
||||
|
||||
---
|
||||
|
||||
## Wrapper Script Pattern
|
||||
|
||||
All wrapper scripts follow this pattern:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
CONTAINER_NAME="kneldevstack-aimiddleware-service-name-crush"
|
||||
|
||||
# Force remove existing container
|
||||
docker rm -f "${CONTAINER_NAME}" >/dev/null 2>&1 || true
|
||||
sleep 0.5
|
||||
|
||||
# Run container with explicit name
|
||||
docker run -i --rm \
|
||||
--name "${CONTAINER_NAME}" \
|
||||
-e ENV_VAR_1="${ENV_VAR_1:-}" \
|
||||
-e ENV_VAR_2="${ENV_VAR_2:-}" \
|
||||
kneldevstack-aimiddleware-service-name
|
||||
```
|
||||
|
||||
This pattern:
|
||||
- Prevents container name conflicts
|
||||
- Handles cleanup gracefully
|
||||
- Passes environment variables from host
|
||||
|
||||
---
|
||||
|
||||
## Validation Failure Categories
|
||||
|
||||
### 1. Build Failures
|
||||
- Dockerfile syntax errors
|
||||
- Missing dependencies
|
||||
- Build tool errors (TypeScript, Go, Rust)
|
||||
|
||||
**Action**: Fix Dockerfile, rebuild
|
||||
|
||||
### 2. Runtime Crashes (Before Protocol)
|
||||
- Missing environment variables
|
||||
- External service unreachable
|
||||
- Missing Python modules (e.g., pcbnew for KiCAD)
|
||||
|
||||
**Action**: Document in STATUS.md as "Runtime Connection Required" or "Host-Only"
|
||||
|
||||
### 3. Transport Mismatches
|
||||
- Server uses HTTP instead of stdio
|
||||
- Server uses WebSocket instead of stdio
|
||||
|
||||
**Action**: Document in STATUS.md as "Transport Mismatch"
|
||||
|
||||
### 4. Protocol Errors
|
||||
- Invalid JSON-RPC response
|
||||
- Wrong protocol version
|
||||
- Missing serverInfo/capabilities
|
||||
|
||||
**Action**: Debug server implementation or report upstream issue
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
- **STATUS.md** - Operational status (single source of truth)
|
||||
- **AGENTS.md** - Development workflow and server catalog
|
||||
- **JOURNAL.md** - Architecture decisions and work history
|
||||
- **scripts/validate-mcp.sh** - Batch validation script
|
||||
|
||||
---
|
||||
|
||||
## Version History
|
||||
|
||||
| Version | Date | Changes |
|
||||
|---------|------|---------|
|
||||
| 1.0 | 2026-02-20 | Initial SDLC document |
|
||||
|
||||
---
|
||||
|
||||
**This SDLC ensures MCP/LSP servers are actually functional, not just "built".**
|
||||
|
||||
**Copyright (c) 2026 Known Element Enterprises LLC**
|
||||
348
scripts/validate-all.sh
Executable file
348
scripts/validate-all.sh
Executable file
@@ -0,0 +1,348 @@
|
||||
#!/bin/bash
|
||||
# Comprehensive MCP/LSP Server Validation Script
|
||||
# Tests all servers with actual protocol messages
|
||||
#
|
||||
# Usage:
|
||||
# ./scripts/validate-all.sh # Test all servers
|
||||
# ./scripts/validate-all.sh mcp # Test only MCP servers
|
||||
# ./scripts/validate-all.sh lsp # Test only LSP servers
|
||||
# ./scripts/validate-all.sh <service> # Test specific service
|
||||
|
||||
set -e
|
||||
|
||||
# Colors
|
||||
GREEN='\033[0;32m'
|
||||
RED='\033[0;31m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m'
|
||||
|
||||
# Protocol messages
|
||||
MCP_INIT='{"jsonrpc":"2.0","method":"initialize","params":{"capabilities":{},"protocolVersion":"2024-11-05","clientInfo":{"name":"validate-all","version":"1.0.0"}},"id":1}'
|
||||
LSP_INIT='{"jsonrpc":"2.0","method":"initialize","params":{"processId":null,"capabilities":{},"rootUri":null,"workspaceFolders":null},"id":1}'
|
||||
|
||||
# Counters
|
||||
PASSED=0
|
||||
FAILED=0
|
||||
SKIPPED=0
|
||||
NEEDS_ENV=0
|
||||
NEEDS_SERVICE=0
|
||||
TRANSPORT_MISMATCH=0
|
||||
|
||||
# Results arrays
|
||||
declare -a RESULTS_PASS
|
||||
declare -a RESULTS_FAIL
|
||||
declare -a RESULTS_SKIP
|
||||
declare -a RESULTS_ENV
|
||||
declare -a RESULTS_SERVICE
|
||||
declare -a RESULTS_TRANSPORT
|
||||
|
||||
# MCP Servers configuration (container_name, timeout, env_vars...)
|
||||
declare -A MCP_SERVERS
|
||||
MCP_SERVERS=(
|
||||
# Design & Engineering
|
||||
["kneldevstack-aimiddleware-blender-mcp"]="10"
|
||||
["kneldevstack-aimiddleware-freecad-mcp"]="10"
|
||||
["kneldevstack-aimiddleware-gimp-mcp"]="10"
|
||||
["kneldevstack-aimiddleware-kicad-mcp"]="10 KICAD_HOST=host.docker.internal KICAD_PORT=5555"
|
||||
|
||||
# Hosting & Infrastructure
|
||||
["kneldevstack-aimiddleware-kubernetes-mcp"]="10"
|
||||
["kneldevstack-aimiddleware-docker-mcp"]="10"
|
||||
["kneldevstack-aimiddleware-proxmox-mcp"]="10 PROXMOX_HOST=https://proxmox.example.com PROXMOX_USER=root@pam PROXMOX_TOKEN=dummy PROXMOX_NODE=pve"
|
||||
["kneldevstack-aimiddleware-terraform-mcp"]="10"
|
||||
["kneldevstack-aimiddleware-cloudron-mcp"]="10 CLOUDRON_URL=https://cloudron.example.com CLOUDRON_TOKEN=dummy"
|
||||
|
||||
# Development Tools
|
||||
["kneldevstack-aimiddleware-context7-mcp"]="10 UPSTASH_REDIS_REST_URL=https://dummy.upstash.io UPSTASH_REDIS_REST_TOKEN=dummy"
|
||||
|
||||
# Content Management
|
||||
["kneldevstack-aimiddleware-nextcloud-mcp"]="10 NEXTCLOUD_HOST=https://nextcloud.example.com NEXTCLOUD_USERNAME=dummy NEXTCLOUD_PASSWORD=dummy"
|
||||
["kneldevstack-aimiddleware-ghost-mcp"]="10 GHOST_API_URL=https://ghost.example.com GHOST_ADMIN_API_KEY=012345678901234567890123:0123456789012345678901234567890123456789012345678901234567890123"
|
||||
["kneldevstack-aimiddleware-docspace-mcp"]="10 DOCSPACE_HOST=https://docspace.example.com DOCSPACE_TOKEN=dummy"
|
||||
["kneldevstack-aimiddleware-wordpress-mcp"]="10 WORDPRESS_URL=https://wordpress.example.com WORDPRESS_USERNAME=dummy WORDPRESS_APPLICATION_PASSWORD=dummy"
|
||||
|
||||
# Communication & Collaboration
|
||||
["kneldevstack-aimiddleware-discourse-mcp"]="10 DISCOURSE_URL=https://discourse.example.com DISCOURSE_API_KEY=dummy DISCOURSE_API_USERNAME=dummy"
|
||||
["kneldevstack-aimiddleware-imap-mcp"]="10 IMAP_HOST=imap.example.com IMAP_PORT=993 IMAP_USERNAME=dummy IMAP_PASSWORD=dummy"
|
||||
["kneldevstack-aimiddleware-postizz-mcp"]="10 POSTIZ_API_KEY=dummy POSTIZ_URL=https://postiz.example.com"
|
||||
|
||||
# Analytics & Security
|
||||
["kneldevstack-aimiddleware-matomo-mcp"]="10 MATOMO_URL=https://matomo.example.com MATOMO_TOKEN=dummy"
|
||||
["kneldevstack-aimiddleware-bitwarden-mcp"]="15 BITWARDEN_CLIENT_ID=dummy BITWARDEN_CLIENT_SECRET=dummy BITWARDEN_PASSWORD=dummy BITWARDEN_SERVER_URL=https://vault.bitwarden.com"
|
||||
|
||||
# Productivity & Automation
|
||||
["kneldevstack-aimiddleware-audiobook-mcp"]="10"
|
||||
["kneldevstack-aimiddleware-snipeit-mcp"]="10 SNIPEIT_URL=https://snipeit.example.com SNIPEIT_TOKEN=dummy"
|
||||
["kneldevstack-aimiddleware-mcp-redmine"]="10 REDMINE_URL=https://redmine.example.com REDMINE_API_KEY=dummy"
|
||||
["kneldevstack-aimiddleware-mcp-ansible"]="10"
|
||||
["kneldevstack-aimiddleware-elasticsearch-mcp"]="10 ELASTICSEARCH_URL=http://localhost:9200 ELASTICSEARCH_USERNAME=dummy ELASTICSEARCH_PASSWORD=dummy"
|
||||
["kneldevstack-aimiddleware-drawio-mcp"]="10"
|
||||
|
||||
# Additional Tools
|
||||
["kneldevstack-aimiddleware-penpot-mcp"]="10 PENPOT_URL=https://design.penpot.app PENPOT_TOKEN=dummy"
|
||||
["kneldevstack-aimiddleware-webserial-mcp"]="10 WEBSOCKET_URL=ws://host.docker.internal:3000"
|
||||
|
||||
# Reverse Engineering
|
||||
["kneldevstack-aimiddleware-ghidra-mcp"]="15"
|
||||
["kneldevstack-aimiddleware-reverse-engineering-assistant"]="15"
|
||||
)
|
||||
|
||||
# LSP Servers configuration
|
||||
declare -A LSP_SERVERS
|
||||
LSP_SERVERS=(
|
||||
["kneldevstack-aimiddleware-bash-language-server"]="10"
|
||||
["kneldevstack-aimiddleware-docker-language-server"]="10"
|
||||
["kneldevstack-aimiddleware-marksman"]="10"
|
||||
["kneldevstack-aimiddleware-terraform-ls"]="10"
|
||||
)
|
||||
|
||||
# Test MCP server
|
||||
test_mcp() {
|
||||
local container=$1
|
||||
local timeout=$2
|
||||
shift 2
|
||||
local env_vars=("$@")
|
||||
|
||||
# Check if image exists
|
||||
if ! docker image inspect "$container" &>/dev/null; then
|
||||
echo -e "${YELLOW}SKIP${NC} $container: Image not built"
|
||||
SKIPPED=$((SKIPPED + 1))
|
||||
RESULTS_SKIP+=("$container: image not built")
|
||||
return 2
|
||||
fi
|
||||
|
||||
# Build env args
|
||||
local env_args=""
|
||||
for env_var in "${env_vars[@]}"; do
|
||||
env_args="$env_args -e $env_var"
|
||||
done
|
||||
|
||||
# Run test
|
||||
local result
|
||||
result=$( (echo "$MCP_INIT" | timeout "$timeout" docker run --rm -i $env_args "$container" 2>&1) || true )
|
||||
|
||||
# Check for valid MCP response
|
||||
if echo "$result" | grep -q '"result".*"serverInfo"'; then
|
||||
local server_name version
|
||||
server_name=$(echo "$result" | grep -o '"name":"[^"]*"' | head -1 | cut -d'"' -f4)
|
||||
version=$(echo "$result" | grep -o '"version":"[^"]*"' | head -1 | cut -d'"' -f4)
|
||||
echo -e "${GREEN}PASS${NC} $container: $server_name v${version:-unknown}"
|
||||
PASSED=$((PASSED + 1))
|
||||
RESULTS_PASS+=("$container: $server_name v${version:-unknown}")
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Check for specific failure modes
|
||||
if echo "$result" | grep -qi "environment variable\|missing.*env\|required.*variable"; then
|
||||
echo -e "${YELLOW}ENV${NC} $container: Needs environment variables"
|
||||
NEEDS_ENV=$((NEEDS_ENV + 1))
|
||||
RESULTS_ENV+=("$container")
|
||||
return 3
|
||||
fi
|
||||
|
||||
if echo "$result" | grep -qi "connection refused\|not connected\|ECONNREFUSED\|ETIMEDOUT\|network unreachable"; then
|
||||
echo -e "${YELLOW}SVC${NC} $container: Needs backend service"
|
||||
NEEDS_SERVICE=$((NEEDS_SERVICE + 1))
|
||||
RESULTS_SERVICE+=("$container")
|
||||
return 4
|
||||
fi
|
||||
|
||||
if echo "$result" | grep -qi "http\|websocket\|ws://\|transport"; then
|
||||
echo -e "${BLUE}TRN${NC} $container: Transport mismatch (not stdio)"
|
||||
TRANSPORT_MISMATCH=$((TRANSPORT_MISMATCH + 1))
|
||||
RESULTS_TRANSPORT+=("$container")
|
||||
return 5
|
||||
fi
|
||||
|
||||
# Generic failure
|
||||
echo -e "${RED}FAIL${NC} $container: No valid response"
|
||||
FAILED=$((FAILED + 1))
|
||||
RESULTS_FAIL+=("$container: $(echo "$result" | head -1 | cut -c1-60)")
|
||||
return 1
|
||||
}
|
||||
|
||||
# Test LSP server
|
||||
test_lsp() {
|
||||
local container=$1
|
||||
local timeout=$2
|
||||
|
||||
# Check if image exists
|
||||
if ! docker image inspect "$container" &>/dev/null; then
|
||||
echo -e "${YELLOW}SKIP${NC} $container: Image not built"
|
||||
SKIPPED=$((SKIPPED + 1))
|
||||
RESULTS_SKIP+=("$container: image not built")
|
||||
return 2
|
||||
fi
|
||||
|
||||
# Run test
|
||||
local result
|
||||
result=$( (echo "$LSP_INIT" | timeout "$timeout" docker run --rm -i "$container" 2>&1) || true )
|
||||
|
||||
# Check for valid LSP response
|
||||
if echo "$result" | grep -q '"result".*"capabilities"'; then
|
||||
echo -e "${GREEN}PASS${NC} $container: LSP initialized"
|
||||
PASSED=$((PASSED + 1))
|
||||
RESULTS_PASS+=("$container: LSP initialized")
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Generic failure
|
||||
echo -e "${RED}FAIL${NC} $container: No valid response"
|
||||
FAILED=$((FAILED + 1))
|
||||
RESULTS_FAIL+=("$container: $(echo "$result" | head -1 | cut -c1-60)")
|
||||
return 1
|
||||
}
|
||||
|
||||
# Print summary
|
||||
print_summary() {
|
||||
echo ""
|
||||
echo -e "${BLUE}========================================${NC}"
|
||||
echo -e "${BLUE}VALIDATION SUMMARY${NC}"
|
||||
echo -e "${BLUE}========================================${NC}"
|
||||
echo ""
|
||||
|
||||
echo -e "${GREEN}PASSED ($PASSED):${NC}"
|
||||
if [ ${#RESULTS_PASS[@]} -gt 0 ]; then
|
||||
for r in "${RESULTS_PASS[@]}"; do
|
||||
echo " ✓ $r"
|
||||
done
|
||||
else
|
||||
echo " (none)"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
if [ ${#RESULTS_ENV[@]} -gt 0 ]; then
|
||||
echo -e "${YELLOW}NEEDS ENV VARS ($NEEDS_ENV):${NC}"
|
||||
for r in "${RESULTS_ENV[@]}"; do
|
||||
echo " ⚠ $r"
|
||||
done
|
||||
echo ""
|
||||
fi
|
||||
|
||||
if [ ${#RESULTS_SERVICE[@]} -gt 0 ]; then
|
||||
echo -e "${YELLOW}NEEDS BACKEND SERVICE ($NEEDS_SERVICE):${NC}"
|
||||
for r in "${RESULTS_SERVICE[@]}"; do
|
||||
echo " ⚠ $r"
|
||||
done
|
||||
echo ""
|
||||
fi
|
||||
|
||||
if [ ${#RESULTS_TRANSPORT[@]} -gt 0 ]; then
|
||||
echo -e "${BLUE}TRANSPORT MISMATCH ($TRANSPORT_MISMATCH):${NC}"
|
||||
for r in "${RESULTS_TRANSPORT[@]}"; do
|
||||
echo " ○ $r"
|
||||
done
|
||||
echo ""
|
||||
fi
|
||||
|
||||
if [ ${#RESULTS_SKIP[@]} -gt 0 ]; then
|
||||
echo -e "${YELLOW}SKIPPED ($SKIPPED):${NC}"
|
||||
for r in "${RESULTS_SKIP[@]}"; do
|
||||
echo " - $r"
|
||||
done
|
||||
echo ""
|
||||
fi
|
||||
|
||||
if [ ${#RESULTS_FAIL[@]} -gt 0 ]; then
|
||||
echo -e "${RED}FAILED ($FAILED):${NC}"
|
||||
for r in "${RESULTS_FAIL[@]}"; do
|
||||
echo " ✗ $r"
|
||||
done
|
||||
echo ""
|
||||
fi
|
||||
|
||||
echo -e "${BLUE}========================================${NC}"
|
||||
echo -e "Total: ${GREEN}$PASSED passed${NC}, ${RED}$FAILED failed${NC}, ${YELLOW}$SKIPPED skipped${NC}"
|
||||
echo -e " ${YELLOW}$NEEDS_ENV need env${NC}, ${YELLOW}$NEEDS_SERVICE need service${NC}, ${BLUE}$TRANSPORT_MISMATCH transport mismatch${NC}"
|
||||
echo -e "${BLUE}========================================${NC}"
|
||||
|
||||
# Return non-zero if any hard failures
|
||||
[ $FAILED -eq 0 ]
|
||||
}
|
||||
|
||||
# Main
|
||||
main() {
|
||||
local mode="${1:-all}"
|
||||
|
||||
echo -e "${BLUE}========================================${NC}"
|
||||
echo -e "${BLUE}KNEL-AIMiddleware Validation${NC}"
|
||||
echo -e "${BLUE}========================================${NC}"
|
||||
echo ""
|
||||
|
||||
case "$mode" in
|
||||
mcp)
|
||||
echo -e "${BLUE}Testing MCP Servers...${NC}"
|
||||
echo ""
|
||||
for container in "${!MCP_SERVERS[@]}"; do
|
||||
config="${MCP_SERVERS[$container]}"
|
||||
read -ra parts <<< "$config"
|
||||
timeout="${parts[0]}"
|
||||
env_vars=("${parts[@]:1}")
|
||||
test_mcp "$container" "$timeout" "${env_vars[@]}" || true
|
||||
done
|
||||
;;
|
||||
lsp)
|
||||
echo -e "${BLUE}Testing LSP Servers...${NC}"
|
||||
echo ""
|
||||
for container in "${!LSP_SERVERS[@]}"; do
|
||||
config="${LSP_SERVERS[$container]}"
|
||||
read -ra parts <<< "$config"
|
||||
timeout="${parts[0]}"
|
||||
test_lsp "$container" "$timeout" || true
|
||||
done
|
||||
;;
|
||||
all)
|
||||
echo -e "${BLUE}Testing MCP Servers...${NC}"
|
||||
echo ""
|
||||
for container in "${!MCP_SERVERS[@]}"; do
|
||||
config="${MCP_SERVERS[$container]}"
|
||||
read -ra parts <<< "$config"
|
||||
timeout="${parts[0]}"
|
||||
env_vars=("${parts[@]:1}")
|
||||
test_mcp "$container" "$timeout" "${env_vars[@]}" || true
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo -e "${BLUE}Testing LSP Servers...${NC}"
|
||||
echo ""
|
||||
for container in "${!LSP_SERVERS[@]}"; do
|
||||
config="${LSP_SERVERS[$container]}"
|
||||
read -ra parts <<< "$config"
|
||||
timeout="${parts[0]}"
|
||||
test_lsp "$container" "$timeout" || true
|
||||
done
|
||||
;;
|
||||
*)
|
||||
# Test specific service
|
||||
if [[ -v MCP_SERVERS["kneldevstack-aimiddleware-$mode"] ]]; then
|
||||
container="kneldevstack-aimiddleware-$mode"
|
||||
config="${MCP_SERVERS[$container]}"
|
||||
read -ra parts <<< "$config"
|
||||
timeout="${parts[0]}"
|
||||
env_vars=("${parts[@]:1}")
|
||||
test_mcp "$container" "$timeout" "${env_vars[@]}"
|
||||
elif [[ -v LSP_SERVERS["kneldevstack-aimiddleware-$mode"] ]]; then
|
||||
container="kneldevstack-aimiddleware-$mode"
|
||||
config="${LSP_SERVERS[$container]}"
|
||||
read -ra parts <<< "$config"
|
||||
timeout="${parts[0]}"
|
||||
test_lsp "$container" "$timeout"
|
||||
else
|
||||
echo -e "${RED}Unknown service: $mode${NC}"
|
||||
echo "Available MCP services: ${!MCP_SERVERS[@]#kneldevstack-aimiddleware-}"
|
||||
echo "Available LSP services: ${!LSP_SERVERS[@]#kneldevstack-aimiddleware-}"
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ "$mode" != "all" ] && [ "$mode" != "mcp" ] && [ "$mode" != "lsp" ]; then
|
||||
# Single service test, no summary
|
||||
exit $?
|
||||
fi
|
||||
|
||||
print_summary
|
||||
}
|
||||
|
||||
main "$@"
|
||||
Reference in New Issue
Block a user