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