Compare commits

..

3 Commits

Author SHA1 Message Date
Charles N Wyble
ea3b0907ae feat(scripts): add comprehensive validation script for all MCP/LSP servers
Created scripts/validate-all.sh to validate ALL servers with actual
protocol handshake messages:

Coverage:
- 29 MCP servers (Design, Infrastructure, Content, Communication,
  Analytics, Productivity, Reverse Engineering)
- 4 LSP servers (bash, docker, marksman, terraform-ls)

Features:
- Sends actual MCP initialize handshake to each container
- Sends actual LSP initialize handshake to LSP containers
- Categorizes results: PASSED, FAILED, SKIPPED, NEEDS_ENV,
  NEEDS_SERVICE, TRANSPORT_MISMATCH
- Provides detailed summary with server names and versions
- Color-coded output for easy scanning

Usage:
  ./scripts/validate-all.sh           # Test all servers
  ./scripts/validate-all.sh mcp       # MCP servers only
  ./scripts/validate-all.sh lsp       # LSP servers only
  ./scripts/validate-all.sh <service> # Specific service

This script implements the SDLC requirement for protocol validation.
Every server must pass build + start + protocol handshake to be
considered "working".
2026-02-20 09:24:59 -05:00
Charles N Wyble
32c003d2d9 docs(agents): enforce automatic commits and SDLC compliance
Added mandatory callout at top of AGENTS.md:

- AI agents MUST commit and push changes automatically WITHOUT prompting
- Use atomic commits (one logical change per commit)
- Use conventional format (feat:, fix:, docs:, build:, refactor:, test:)
- Verbose commit messages required

Updated Development Notes section:
- Added "SDLC Compliance (REQUIRED)" section with link to docs/SDLC.md
- Documented mandatory MCP handshake command
- Updated Validation Checklist to emphasize protocol handshake is MANDATORY

This ensures AI agents understand that committing is automatic,
not something to ask permission for.
2026-02-20 09:24:45 -05:00
Charles N Wyble
5fd45d48c9 docs: add SDLC.md with MCP/LSP validation requirements and commit policy
Defines the software development lifecycle for KNEL-AIMiddleware:

- Protocol validation is NON-NEGOTIABLE: build + start + protocol handshake
  ALL required before marking a server as "working"
- MCP initialize handshake: {"jsonrpc":"2.0","method":"initialize"...}
- STATUS.md is the single source of truth for server status
- Status categories: Working, Runtime Connection Required, Host-Only,
  Transport Mismatch, Build Failed, Runtime Issue
- Step-by-step process for adding new MCP/LSP servers
- Common Dockerfile patterns for Python/uv, Node/npx, Go
- Wrapper script pattern for Crush integration

Commit Policy (MANDATORY):
- AI agents MUST commit automatically WITHOUT prompting
- Atomic commits: one logical change per commit
- Conventional format: feat:, fix:, docs:, build:, refactor:, test:
- Verbose messages explaining what, why, and how validated
- Automatic push after each commit

Version: 1.0
2026-02-20 09:24:32 -05:00
3 changed files with 784 additions and 2 deletions

View File

@@ -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
View 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
View 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 "$@"