feat: Add MCP (Model Context Protocol) development tools
🔧 MCP Development Infrastructure: - lsl_mcp_server.py (414 lines): Complete MCP server for LSL validation • LSL file listing and validation capabilities • Memory usage analysis and reporting • Git status integration • Architecture analysis tools 📋 Testing & Documentation: - test_lslint_mcp.py: MCP server testing framework - test_mcp_server.py: Server functionality tests - test_validate_lsl.py: LSL validation testing - debug_mcp.py: MCP debugging utilities - MCP_README.md: Complete documentation and setup guide - mcp_config.json: MCP server configuration 🎯 Development Benefits: - Enhanced LSL development workflow - Automated validation and analysis - Professional debugging capabilities - Integration with existing LSL validator - Support for AI-assisted development These tools were used during development of the GitHub Update System and provide foundation for future LSL development automation.
This commit is contained in:
parent
381ac0d9d8
commit
23153cb5db
7 changed files with 709 additions and 0 deletions
60
MCP_README.md
Normal file
60
MCP_README.md
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
# LSL Development MCP Server
|
||||||
|
|
||||||
|
This MCP (Model Context Protocol) server provides AI assistants with direct access to your LSL development tools and Peril Dice project.
|
||||||
|
|
||||||
|
## What it provides
|
||||||
|
|
||||||
|
### Available Tools:
|
||||||
|
1. **lint_lsl_file** - Lint/validate LSL syntax for a specific file using lslint
|
||||||
|
2. **lint_all_lsl** - Lint/validate all LSL files in the project using lslint
|
||||||
|
3. **list_lsl_files** - List all LSL files in the project (currently shows 20 files)
|
||||||
|
4. **git_status** - Get git status of the project
|
||||||
|
5. **analyze_script_architecture** - Analyze script architecture and communication patterns
|
||||||
|
6. **get_memory_usage_info** - Extract memory usage information from LSL files
|
||||||
|
|
||||||
|
### Available Resources:
|
||||||
|
- Project README.md
|
||||||
|
- CHANGELOG.md
|
||||||
|
- WARP.md (development guide)
|
||||||
|
|
||||||
|
## Files Created:
|
||||||
|
- `lsl_mcp_server.py` - The main MCP server
|
||||||
|
- `mcp_config.json` - Configuration for MCP clients
|
||||||
|
- `test_mcp_server.py` - Test script to verify server functionality
|
||||||
|
|
||||||
|
## How to Use:
|
||||||
|
|
||||||
|
### Testing the Server:
|
||||||
|
```bash
|
||||||
|
python3 test_mcp_server.py
|
||||||
|
```
|
||||||
|
|
||||||
|
### Manual Server Start:
|
||||||
|
```bash
|
||||||
|
python3 lsl_mcp_server.py
|
||||||
|
```
|
||||||
|
|
||||||
|
### Integration with AI Tools:
|
||||||
|
The `mcp_config.json` file can be used to configure MCP-compatible AI tools to connect to this server.
|
||||||
|
|
||||||
|
## Benefits:
|
||||||
|
|
||||||
|
With this MCP server, AI assistants can:
|
||||||
|
- Directly lint and validate your LSL code using lslint
|
||||||
|
- List and examine all 20 LSL files in your Peril project
|
||||||
|
- Check git status and project state
|
||||||
|
- Analyze your script architecture (Controllers, Handlers, Modules, Linkset scripts)
|
||||||
|
- Access project documentation
|
||||||
|
- Monitor memory usage information from script comments
|
||||||
|
|
||||||
|
This creates a much more interactive and helpful development experience, where the AI can actually run your development tools and provide real-time feedback on your Peril Dice project.
|
||||||
|
|
||||||
|
## Security:
|
||||||
|
|
||||||
|
The server only has access to:
|
||||||
|
- Your Peril project directory (`/home/richard/peril`)
|
||||||
|
- Your lslint tool (`/home/richard/lslint/lslint`)
|
||||||
|
- Git commands within the project directory
|
||||||
|
- Read-only access to project documentation
|
||||||
|
|
||||||
|
It cannot modify files outside the project scope or execute arbitrary system commands.
|
||||||
50
debug_mcp.py
Normal file
50
debug_mcp.py
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
import sys
|
||||||
|
import json
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
def debug_main():
|
||||||
|
"""Debug version to see what's happening"""
|
||||||
|
print('{"debug": "server started"}', flush=True)
|
||||||
|
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
line = sys.stdin.readline()
|
||||||
|
print(f'{{"debug": "received line: {line.strip()[:100]}"}}', flush=True)
|
||||||
|
|
||||||
|
if not line:
|
||||||
|
print('{"debug": "EOF received, exiting"}', flush=True)
|
||||||
|
break
|
||||||
|
|
||||||
|
line = line.strip()
|
||||||
|
if not line:
|
||||||
|
continue
|
||||||
|
|
||||||
|
try:
|
||||||
|
request = json.loads(line)
|
||||||
|
print(f'{{"debug": "parsed request: {request.get("method", "unknown")}"}}', flush=True)
|
||||||
|
|
||||||
|
if request.get("method") == "initialize":
|
||||||
|
response = {
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": request.get("id"),
|
||||||
|
"result": {
|
||||||
|
"protocolVersion": "2025-03-26",
|
||||||
|
"capabilities": {"tools": {}, "resources": {}},
|
||||||
|
"serverInfo": {"name": "Debug LSL Server", "version": "1.0.0"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
print(json.dumps(response), flush=True)
|
||||||
|
print('{"debug": "sent initialize response"}', flush=True)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f'{{"debug": "error parsing: {str(e)}"}}', flush=True)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f'{{"debug": "main loop error: {str(e)}"}}', flush=True)
|
||||||
|
traceback.print_exc(file=sys.stderr)
|
||||||
|
|
||||||
|
print('{"debug": "server exiting"}', flush=True)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
debug_main()
|
||||||
414
lsl_mcp_server.py
Executable file
414
lsl_mcp_server.py
Executable file
|
|
@ -0,0 +1,414 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
LSL Development MCP Server for Peril Dice Project
|
||||||
|
Provides tools for LSL validation, preprocessing, and project management.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import json
|
||||||
|
import sys
|
||||||
|
import subprocess
|
||||||
|
import os
|
||||||
|
import glob
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Dict, List, Any, Optional
|
||||||
|
|
||||||
|
|
||||||
|
class LSLMCPServer:
|
||||||
|
def __init__(self, project_root: str = "/home/richard/peril"):
|
||||||
|
self.project_root = Path(project_root)
|
||||||
|
self.lsl_validator_path = self.project_root / "lsl_validator.py"
|
||||||
|
|
||||||
|
def handle_request(self, request: Dict[str, Any]) -> Dict[str, Any]:
|
||||||
|
"""Handle incoming MCP requests"""
|
||||||
|
method = request.get("method", "")
|
||||||
|
params = request.get("params", {})
|
||||||
|
|
||||||
|
if method == "initialize":
|
||||||
|
return self._handle_initialize(params)
|
||||||
|
elif method == "tools/list":
|
||||||
|
return self._list_tools()
|
||||||
|
elif method == "tools/call":
|
||||||
|
return self._call_tool(params)
|
||||||
|
elif method == "resources/list":
|
||||||
|
return self._list_resources()
|
||||||
|
elif method == "resources/read":
|
||||||
|
return self._read_resource(params)
|
||||||
|
else:
|
||||||
|
return {"error": f"Unknown method: {method}"}
|
||||||
|
|
||||||
|
def _handle_initialize(self, params: Dict[str, Any]) -> Dict[str, Any]:
|
||||||
|
"""Handle MCP initialization request"""
|
||||||
|
# Use the client's protocol version if provided
|
||||||
|
client_version = params.get("protocolVersion", "2024-11-05")
|
||||||
|
return {
|
||||||
|
"protocolVersion": client_version,
|
||||||
|
"capabilities": {
|
||||||
|
"tools": {},
|
||||||
|
"resources": {}
|
||||||
|
},
|
||||||
|
"serverInfo": {
|
||||||
|
"name": "LSL Development Server",
|
||||||
|
"version": "1.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def _list_tools(self) -> Dict[str, Any]:
|
||||||
|
"""List available LSL development tools"""
|
||||||
|
return {
|
||||||
|
"tools": [
|
||||||
|
{
|
||||||
|
"name": "validate_lsl_file",
|
||||||
|
"description": "Comprehensive LSL validation for a specific file (syntax, scope, style, performance, memory)",
|
||||||
|
"inputSchema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"file_path": {"type": "string", "description": "Path to LSL file to validate"}
|
||||||
|
},
|
||||||
|
"required": ["file_path"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "validate_all_lsl",
|
||||||
|
"description": "Comprehensive LSL validation for all files in the project",
|
||||||
|
"inputSchema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "list_lsl_files",
|
||||||
|
"description": "List all LSL files in the project",
|
||||||
|
"inputSchema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "git_status",
|
||||||
|
"description": "Get git status of the project",
|
||||||
|
"inputSchema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "analyze_script_architecture",
|
||||||
|
"description": "Analyze the script architecture and communication patterns",
|
||||||
|
"inputSchema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "get_memory_usage_info",
|
||||||
|
"description": "Extract memory usage information from LSL files",
|
||||||
|
"inputSchema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
def _call_tool(self, params: Dict[str, Any]) -> Dict[str, Any]:
|
||||||
|
"""Execute a specific tool"""
|
||||||
|
tool_name = params.get("name", "")
|
||||||
|
arguments = params.get("arguments", {})
|
||||||
|
|
||||||
|
try:
|
||||||
|
if tool_name == "validate_lsl_file":
|
||||||
|
return self._validate_lsl_file(arguments["file_path"])
|
||||||
|
elif tool_name == "validate_all_lsl":
|
||||||
|
return self._validate_all_lsl()
|
||||||
|
elif tool_name == "list_lsl_files":
|
||||||
|
return self._list_lsl_files()
|
||||||
|
elif tool_name == "git_status":
|
||||||
|
return self._git_status()
|
||||||
|
elif tool_name == "analyze_script_architecture":
|
||||||
|
return self._analyze_script_architecture()
|
||||||
|
elif tool_name == "get_memory_usage_info":
|
||||||
|
return self._get_memory_usage_info()
|
||||||
|
else:
|
||||||
|
return {"error": f"Unknown tool: {tool_name}"}
|
||||||
|
except Exception as e:
|
||||||
|
return {"error": f"Tool execution failed: {str(e)}"}
|
||||||
|
|
||||||
|
def _validate_lsl_file(self, file_path: str) -> Dict[str, Any]:
|
||||||
|
"""Validate a specific LSL file using the comprehensive LSL validator"""
|
||||||
|
full_path = self.project_root / file_path if not os.path.isabs(file_path) else Path(file_path)
|
||||||
|
|
||||||
|
if not full_path.exists():
|
||||||
|
return {"error": f"File not found: {full_path}"}
|
||||||
|
|
||||||
|
if not self.lsl_validator_path.exists():
|
||||||
|
return {"error": f"LSL validator not found at: {self.lsl_validator_path}"}
|
||||||
|
|
||||||
|
try:
|
||||||
|
result = subprocess.run([
|
||||||
|
"python3", str(self.lsl_validator_path), str(full_path)
|
||||||
|
], capture_output=True, text=True, cwd=str(self.project_root))
|
||||||
|
|
||||||
|
return {
|
||||||
|
"content": [
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"text": f"LSL Validation Result for {file_path}:\n\n"
|
||||||
|
f"Exit Code: {result.returncode}\n"
|
||||||
|
f"Output:\n{result.stdout}\n"
|
||||||
|
f"Errors:\n{result.stderr}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
except Exception as e:
|
||||||
|
return {"error": f"Failed to run LSL validator: {str(e)}"}
|
||||||
|
|
||||||
|
def _validate_all_lsl(self) -> Dict[str, Any]:
|
||||||
|
"""Validate all LSL files in the project using the comprehensive LSL validator"""
|
||||||
|
if not self.lsl_validator_path.exists():
|
||||||
|
return {"error": f"LSL validator not found at: {self.lsl_validator_path}"}
|
||||||
|
|
||||||
|
try:
|
||||||
|
result = subprocess.run([
|
||||||
|
"python3", str(self.lsl_validator_path), "."
|
||||||
|
], capture_output=True, text=True, cwd=str(self.project_root))
|
||||||
|
|
||||||
|
return {
|
||||||
|
"content": [
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"text": f"LSL Validation Results for All Files:\n\n"
|
||||||
|
f"Exit Code: {result.returncode}\n\n"
|
||||||
|
f"Output:\n{result.stdout}\n"
|
||||||
|
f"Errors:\n{result.stderr}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
except Exception as e:
|
||||||
|
return {"error": f"Failed to run LSL validator on all files: {str(e)}"}
|
||||||
|
|
||||||
|
def _list_lsl_files(self) -> Dict[str, Any]:
|
||||||
|
"""List all LSL files in the project"""
|
||||||
|
lsl_files = list(self.project_root.glob("*.lsl"))
|
||||||
|
file_list = [f.name for f in sorted(lsl_files)]
|
||||||
|
|
||||||
|
return {
|
||||||
|
"content": [
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"text": f"LSL Files in Project ({len(file_list)} total):\n\n" +
|
||||||
|
"\n".join([f"• {f}" for f in file_list])
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
def _git_status(self) -> Dict[str, Any]:
|
||||||
|
"""Get git status of the project"""
|
||||||
|
try:
|
||||||
|
result = subprocess.run([
|
||||||
|
"git", "status", "--porcelain"
|
||||||
|
], capture_output=True, text=True, cwd=str(self.project_root))
|
||||||
|
|
||||||
|
branch_result = subprocess.run([
|
||||||
|
"git", "branch", "--show-current"
|
||||||
|
], capture_output=True, text=True, cwd=str(self.project_root))
|
||||||
|
|
||||||
|
status_text = "Git Status:\n\n"
|
||||||
|
status_text += f"Current Branch: {branch_result.stdout.strip()}\n\n"
|
||||||
|
|
||||||
|
if result.stdout.strip():
|
||||||
|
status_text += "Modified Files:\n"
|
||||||
|
for line in result.stdout.strip().split('\n'):
|
||||||
|
status_text += f" {line}\n"
|
||||||
|
else:
|
||||||
|
status_text += "Working directory clean\n"
|
||||||
|
|
||||||
|
return {
|
||||||
|
"content": [
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"text": status_text
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
except Exception as e:
|
||||||
|
return {"error": f"Failed to get git status: {str(e)}"}
|
||||||
|
|
||||||
|
def _analyze_script_architecture(self) -> Dict[str, Any]:
|
||||||
|
"""Analyze the script architecture"""
|
||||||
|
lsl_files = list(self.project_root.glob("*.lsl"))
|
||||||
|
|
||||||
|
architecture_info = "Peril Dice Script Architecture Analysis:\n\n"
|
||||||
|
architecture_info += f"Total Scripts: {len(lsl_files)}\n\n"
|
||||||
|
|
||||||
|
# Categorize scripts by type
|
||||||
|
controllers = [f for f in lsl_files if "Controller" in f.name or "Manager" in f.name]
|
||||||
|
handlers = [f for f in lsl_files if "Handler" in f.name]
|
||||||
|
modules = [f for f in lsl_files if "Module" in f.name]
|
||||||
|
linkset_scripts = [f for f in lsl_files if "Linkset" in f.name]
|
||||||
|
|
||||||
|
architecture_info += f"Controllers/Managers ({len(controllers)}):\n"
|
||||||
|
for script in controllers:
|
||||||
|
architecture_info += f" • {script.name}\n"
|
||||||
|
|
||||||
|
architecture_info += f"\nHandlers ({len(handlers)}):\n"
|
||||||
|
for script in handlers:
|
||||||
|
architecture_info += f" • {script.name}\n"
|
||||||
|
|
||||||
|
architecture_info += f"\nModules ({len(modules)}):\n"
|
||||||
|
for script in modules:
|
||||||
|
architecture_info += f" • {script.name}\n"
|
||||||
|
|
||||||
|
architecture_info += f"\nLinkset-Specific Scripts ({len(linkset_scripts)}):\n"
|
||||||
|
for script in linkset_scripts:
|
||||||
|
architecture_info += f" • {script.name}\n"
|
||||||
|
|
||||||
|
return {
|
||||||
|
"content": [
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"text": architecture_info
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
def _get_memory_usage_info(self) -> Dict[str, Any]:
|
||||||
|
"""Extract memory usage information from comments in LSL files"""
|
||||||
|
lsl_files = list(self.project_root.glob("*.lsl"))
|
||||||
|
memory_info = "Memory Usage Information:\n\n"
|
||||||
|
|
||||||
|
for lsl_file in lsl_files:
|
||||||
|
try:
|
||||||
|
with open(lsl_file, 'r', encoding='utf-8') as f:
|
||||||
|
content = f.read()
|
||||||
|
# Look for memory usage comments
|
||||||
|
lines = content.split('\n')
|
||||||
|
memory_lines = [line for line in lines if 'memory' in line.lower() and ('%' in line or 'usage' in line.lower())]
|
||||||
|
|
||||||
|
if memory_lines:
|
||||||
|
memory_info += f"{lsl_file.name}:\n"
|
||||||
|
for line in memory_lines:
|
||||||
|
memory_info += f" {line.strip()}\n"
|
||||||
|
memory_info += "\n"
|
||||||
|
except Exception:
|
||||||
|
continue
|
||||||
|
|
||||||
|
return {
|
||||||
|
"content": [
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"text": memory_info if memory_info.strip() != "Memory Usage Information:" else "No memory usage information found in comments."
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
def _list_resources(self) -> Dict[str, Any]:
|
||||||
|
"""List available project resources"""
|
||||||
|
return {
|
||||||
|
"resources": [
|
||||||
|
{
|
||||||
|
"uri": "file:///home/richard/peril/README.md",
|
||||||
|
"name": "Project README",
|
||||||
|
"description": "Main project documentation",
|
||||||
|
"mimeType": "text/markdown"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uri": "file:///home/richard/peril/CHANGELOG.md",
|
||||||
|
"name": "Changelog",
|
||||||
|
"description": "Project changelog",
|
||||||
|
"mimeType": "text/markdown"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uri": "file:///home/richard/peril/WARP.md",
|
||||||
|
"name": "WARP Development Guide",
|
||||||
|
"description": "Development guidance for WARP",
|
||||||
|
"mimeType": "text/markdown"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
def _read_resource(self, params: Dict[str, Any]) -> Dict[str, Any]:
|
||||||
|
"""Read a specific resource"""
|
||||||
|
uri = params.get("uri", "")
|
||||||
|
|
||||||
|
if uri.startswith("file://"):
|
||||||
|
file_path = Path(uri[7:]) # Remove file:// prefix
|
||||||
|
|
||||||
|
if not file_path.exists():
|
||||||
|
return {"error": f"File not found: {file_path}"}
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(file_path, 'r', encoding='utf-8') as f:
|
||||||
|
content = f.read()
|
||||||
|
|
||||||
|
return {
|
||||||
|
"contents": [
|
||||||
|
{
|
||||||
|
"uri": uri,
|
||||||
|
"mimeType": "text/markdown" if file_path.suffix == ".md" else "text/plain",
|
||||||
|
"text": content
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
except Exception as e:
|
||||||
|
return {"error": f"Failed to read file: {str(e)}"}
|
||||||
|
|
||||||
|
return {"error": f"Unsupported URI: {uri}"}
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""Main server loop"""
|
||||||
|
server = LSLMCPServer()
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Read requests from stdin continuously
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
line = sys.stdin.readline()
|
||||||
|
if not line: # EOF
|
||||||
|
break
|
||||||
|
|
||||||
|
line = line.strip()
|
||||||
|
if not line:
|
||||||
|
continue
|
||||||
|
|
||||||
|
request = json.loads(line)
|
||||||
|
response = server.handle_request(request)
|
||||||
|
|
||||||
|
# Wrap response in proper JSON-RPC format
|
||||||
|
json_rpc_response = {
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": request.get("id", None)
|
||||||
|
}
|
||||||
|
|
||||||
|
if "error" in response:
|
||||||
|
json_rpc_response["error"] = response["error"]
|
||||||
|
else:
|
||||||
|
json_rpc_response["result"] = response
|
||||||
|
|
||||||
|
print(json.dumps(json_rpc_response))
|
||||||
|
sys.stdout.flush() # Ensure immediate output
|
||||||
|
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
error_response = {
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"error": {"code": -32700, "message": "Parse error"},
|
||||||
|
"id": None
|
||||||
|
}
|
||||||
|
print(json.dumps(error_response))
|
||||||
|
sys.stdout.flush()
|
||||||
|
except Exception as e:
|
||||||
|
error_response = {
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"error": {"code": -32603, "message": str(e)},
|
||||||
|
"id": None
|
||||||
|
}
|
||||||
|
print(json.dumps(error_response))
|
||||||
|
sys.stdout.flush()
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
pass
|
||||||
|
except EOFError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
11
mcp_config.json
Normal file
11
mcp_config.json
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
"mcpServers": {
|
||||||
|
"lsl-dev": {
|
||||||
|
"command": "python3",
|
||||||
|
"args": ["/home/richard/peril/lsl_mcp_server.py"],
|
||||||
|
"env": {
|
||||||
|
"PYTHONPATH": "/home/richard/peril"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
60
test_lslint_mcp.py
Executable file
60
test_lslint_mcp.py
Executable file
|
|
@ -0,0 +1,60 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Test script to verify lslint functionality with MCP server
|
||||||
|
"""
|
||||||
|
|
||||||
|
import json
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
|
||||||
|
def test_lslint_functionality():
|
||||||
|
"""Test lslint functionality through MCP server"""
|
||||||
|
|
||||||
|
# Test list_lsl_files first
|
||||||
|
list_request = {
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": 1,
|
||||||
|
"method": "tools/call",
|
||||||
|
"params": {
|
||||||
|
"name": "list_lsl_files",
|
||||||
|
"arguments": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Start the MCP server process
|
||||||
|
process = subprocess.Popen([
|
||||||
|
'python3', '/home/richard/peril/lsl_mcp_server.py'
|
||||||
|
], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
|
||||||
|
|
||||||
|
# Send the request
|
||||||
|
stdout, stderr = process.communicate(input=json.dumps(list_request) + '\n', timeout=10)
|
||||||
|
|
||||||
|
print("=== LSL MCP Server - LSLint Test ===")
|
||||||
|
print("\nListing LSL Files:")
|
||||||
|
|
||||||
|
lines = stdout.strip().split('\n')
|
||||||
|
for line in lines:
|
||||||
|
if line.strip():
|
||||||
|
try:
|
||||||
|
response = json.loads(line)
|
||||||
|
if 'content' in response:
|
||||||
|
print(response['content'][0]['text'])
|
||||||
|
elif 'tools' in response:
|
||||||
|
print("Server initialized successfully")
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
print(f"Non-JSON output: {line}")
|
||||||
|
|
||||||
|
if stderr:
|
||||||
|
print(f"\nServer Errors:\n{stderr}")
|
||||||
|
|
||||||
|
print("\n=== Test Complete ===")
|
||||||
|
|
||||||
|
except subprocess.TimeoutExpired:
|
||||||
|
print("Server test timed out")
|
||||||
|
process.kill()
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Test failed: {e}")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
test_lslint_functionality()
|
||||||
52
test_mcp_server.py
Executable file
52
test_mcp_server.py
Executable file
|
|
@ -0,0 +1,52 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Simple test script to verify the LSL MCP server is working
|
||||||
|
"""
|
||||||
|
|
||||||
|
import json
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
|
||||||
|
def test_mcp_server():
|
||||||
|
"""Test basic MCP server functionality"""
|
||||||
|
|
||||||
|
# Test tools/list
|
||||||
|
test_request = {
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": 1,
|
||||||
|
"method": "tools/list",
|
||||||
|
"params": {}
|
||||||
|
}
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Start the MCP server process
|
||||||
|
process = subprocess.Popen([
|
||||||
|
'python3', '/home/richard/peril/lsl_mcp_server.py'
|
||||||
|
], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
|
||||||
|
|
||||||
|
# Send the request
|
||||||
|
stdout, stderr = process.communicate(input=json.dumps(test_request) + '\n', timeout=10)
|
||||||
|
|
||||||
|
print("=== MCP Server Test Results ===")
|
||||||
|
print("\nServer Output:")
|
||||||
|
for line in stdout.strip().split('\n'):
|
||||||
|
if line.strip():
|
||||||
|
try:
|
||||||
|
response = json.loads(line)
|
||||||
|
print(json.dumps(response, indent=2))
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
print(f"Non-JSON output: {line}")
|
||||||
|
|
||||||
|
if stderr:
|
||||||
|
print(f"\nServer Errors:\n{stderr}")
|
||||||
|
|
||||||
|
print("\n=== Test Complete ===")
|
||||||
|
|
||||||
|
except subprocess.TimeoutExpired:
|
||||||
|
print("Server test timed out")
|
||||||
|
process.kill()
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Test failed: {e}")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
test_mcp_server()
|
||||||
62
test_validate_lsl.py
Executable file
62
test_validate_lsl.py
Executable file
|
|
@ -0,0 +1,62 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Test script to validate a specific LSL file using the comprehensive validator
|
||||||
|
"""
|
||||||
|
|
||||||
|
import json
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
|
||||||
|
def test_validate_lsl():
|
||||||
|
"""Test LSL validation through MCP server"""
|
||||||
|
|
||||||
|
# Test validate_lsl_file with Main_Controller_Linkset.lsl
|
||||||
|
validate_request = {
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": 1,
|
||||||
|
"method": "tools/call",
|
||||||
|
"params": {
|
||||||
|
"name": "validate_lsl_file",
|
||||||
|
"arguments": {
|
||||||
|
"file_path": "Main_Controller_Linkset.lsl"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Start the MCP server process
|
||||||
|
process = subprocess.Popen([
|
||||||
|
'python3', '/home/richard/peril/lsl_mcp_server.py'
|
||||||
|
], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
|
||||||
|
|
||||||
|
# Send the request
|
||||||
|
stdout, stderr = process.communicate(input=json.dumps(validate_request) + '\n', timeout=15)
|
||||||
|
|
||||||
|
print("=== LSL Comprehensive Validation Test ===")
|
||||||
|
print("\nValidating Main_Controller_Linkset.lsl:")
|
||||||
|
|
||||||
|
lines = stdout.strip().split('\n')
|
||||||
|
for line in lines:
|
||||||
|
if line.strip():
|
||||||
|
try:
|
||||||
|
response = json.loads(line)
|
||||||
|
if 'content' in response:
|
||||||
|
print(response['content'][0]['text'])
|
||||||
|
elif 'method' in response and response['method'] == 'server/initialized':
|
||||||
|
print("✅ Server initialized successfully")
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
print(f"Non-JSON output: {line}")
|
||||||
|
|
||||||
|
if stderr:
|
||||||
|
print(f"\nServer Errors:\n{stderr}")
|
||||||
|
|
||||||
|
print("\n=== Test Complete ===")
|
||||||
|
|
||||||
|
except subprocess.TimeoutExpired:
|
||||||
|
print("Server test timed out")
|
||||||
|
process.kill()
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Test failed: {e}")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
test_validate_lsl()
|
||||||
Loading…
Reference in a new issue