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.
|
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.
|
> **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.
|
> **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
|
## 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
|
### 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.
|
**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
|
## Validation Checklist
|
||||||
|
|
||||||
For each agent, verify:
|
For each agent, verify in order:
|
||||||
- [ ] Container builds successfully
|
- [ ] Container builds successfully
|
||||||
- [ ] Container starts without errors
|
- [ ] Container starts without errors
|
||||||
|
- [ ] **Protocol handshake returns valid response** (MANDATORY - see SDLC)
|
||||||
- [ ] Logs show proper initialization
|
- [ ] Logs show proper initialization
|
||||||
- [ ] Environment variables are correctly set (if required)
|
- [ ] Environment variables are correctly set (if required)
|
||||||
- [ ] MCP protocol handshake completes
|
|
||||||
- [ ] Tools are registered and available
|
- [ ] Tools are registered and available
|
||||||
- [ ] Resources are accessible (if applicable)
|
- [ ] Resources are accessible (if applicable)
|
||||||
|
|
||||||
|
> **⚠️ CRITICAL**: Items 1-3 are NON-NEGOTIABLE. Do not mark a server as "working" without protocol validation.
|
||||||
|
|
||||||
## References
|
## References
|
||||||
|
|
||||||
- [Model Context Protocol](https://modelcontextprotocol.io/)
|
- [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