A complete Lua implementation of the Model Context Protocol specification, enabling seamless integration between Large Language Models (LLMs) and external systems through a standardized communication protocol.
The Model Context Protocol (MCP) is an open protocol that standardizes how applications provide context to LLMs. This Lua implementation provides a fully-featured MCP SDK that allows developers to build both MCP clients and servers in Lua, enabling:
- Tools: Expose functions that LLMs can invoke
- Resources: Share data and content with LLMs
- Prompts: Provide reusable prompt templates
- Standardized Communication: JSON-RPC 2.0 over stdio transport
- ✅ Full JSON-RPC 2.0 implementation
- ✅ stdio transport (standard input/output communication)
- ✅ SSE (Server-Sent Events) transport
- ✅ Protocol lifecycle management (initialize, shutdown)
- ✅ Error handling with standard JSON-RPC error codes
- ✅ Tools: Define and execute functions with JSON Schema validation
- ✅ Resources: Expose data with URI-based access and MIME types
- ✅ Prompts: Create reusable prompt templates with arguments
- ✅ Logging: Structured logging support
- ✅ Completion: Auto-completion support for arguments
- ✅ Sampling: LLM sampling configuration
- ✅ Security Layer: Rate limiting, access control, input validation
- ✅ Async Operations: Promise-based async/await pattern
- ✅ Event System: Event emitter for lifecycle hooks
- ✅ Schema Validation: JSON Schema support for input/output validation
- ✅ Error Tracking: Comprehensive error handling and recovery
# Clone the repository
git clone https://github.com/yourusername/lua-mcp.git
cd lua-mcp
# Run tests to verify installation
lua tests/run_all_tests.lua#!/usr/bin/env lua
-- Add the library to path
package.path = package.path .. ";./lua-mcp/src/?.lua"
local json = require("mcp.foundation.json")
local json_rpc = require("mcp.protocol.json_rpc")
local StdioTransport = require("mcp.transport.stdio")
-- Create a simple MCP server
local server = {}
function server:new()
local self = setmetatable({}, {__index = server})
-- Initialize transport
self.transport = StdioTransport:new()
self.transport:connect()
-- Define available tools
self.tools = {
{
name = "calculate",
description = "Perform basic calculations",
inputSchema = {
type = "object",
properties = {
operation = { type = "string", enum = {"add", "subtract", "multiply", "divide"} },
a = { type = "number" },
b = { type = "number" }
},
required = {"operation", "a", "b"}
}
}
}
return self
end
function server:handle_message(message)
local method = json_rpc.get_method(message)
local params = json_rpc.get_params(message) or {}
local id = json_rpc.get_id(message)
if method == "initialize" then
return json_rpc.create_response({
protocolVersion = "2024-11-05",
capabilities = {
tools = { listSupported = true, callSupported = true }
},
serverInfo = { name = "my-server", version = "1.0.0" }
}, id)
elseif method == "tools/list" then
return json_rpc.create_response({ tools = self.tools }, id)
elseif method == "tools/call" then
-- Handle tool execution
local result = self:execute_tool(params.name, params.arguments)
return json_rpc.create_response(result, id)
else
return json_rpc.create_error_response(
json_rpc.create_error(json_rpc.ErrorCodes.METHOD_NOT_FOUND, "Method not found"),
id
)
end
end
function server:run()
while true do
local line = io.stdin:read("*l")
if not line then break end
if line ~= "" then
local success, message = pcall(json_rpc.parse, line)
if success then
local response = self:handle_message(message)
if response then
self.transport:send(response)
end
end
end
end
end
-- Run the server
local my_server = server:new()
my_server:run()The repository includes a fully-featured demo server that showcases all MCP capabilities:
# Run the demo server
lua demo_mcp_server.lua
# In another terminal, test with a single request
echo '{"jsonrpc":"2.0","method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test-client","version":"1.0.0"}},"id":1}' | lua demo_mcp_server.lua
# Run comprehensive tests
./test_comprehensive.shThe implementation passes all protocol compliance tests:
=== Lua MCP Demo Server Test Suite ===
Testing Initialize... ✓ PASS
Testing List Tools... ✓ PASS
Testing Add Tool (5 + 3)... ✓ PASS
Testing Echo Tool... ✓ PASS
Testing Get Time Tool... ✓ PASS
Testing List Resources... ✓ PASS
Testing Read Welcome Resource... ✓ PASS
Testing Read Config Resource... ✓ PASS
Testing List Prompts... ✓ PASS
Testing Get Greeting Prompt... ✓ PASS
Testing Invalid Method (Error)... ✓ PASS
Testing Invalid Tool (Error)... ✓ PASS
Testing Invalid Resource (Error)... ✓ PASS
Testing Invalid Prompt (Error)... ✓ PASS
Total Tests: 14
Passed: 14
Failed: 0
This implementation follows the Model Context Protocol specification exactly:
- Messages are newline-delimited JSON-RPC 2.0
- No embedded newlines in messages
- stderr used only for logging (clients may ignore)
- stdout used only for valid MCP messages
- Request/response pattern with unique IDs
- Notification support (no ID required)
- Batch message support
- Standard error codes:
-32700: Parse error-32600: Invalid request-32601: Method not found-32602: Invalid params-32603: Internal error
initialize: Establish protocol version and capabilitiesshutdown: Clean termination (via transport)
tools/list: List available tools with schemastools/call: Execute a tool with arguments
resources/list: List available resourcesresources/read: Read resource content by URIresources/subscribe: Subscribe to resource changesresources/unsubscribe: Unsubscribe from changes
prompts/list: List available prompt templatesprompts/get: Get a prompt with arguments
lua-mcp/
├── src/mcp/
│ ├── foundation/ # Core utilities
│ │ ├── json.lua # JSON encoding/decoding
│ │ ├── logger.lua # Structured logging
│ │ ├── async.lua # Async/await implementation
│ │ ├── events.lua # Event emitter
│ │ ├── errors.lua # Error handling
│ │ └── schema.lua # JSON Schema validation
│ ├── protocol/ # Protocol implementation
│ │ ├── json_rpc.lua # JSON-RPC 2.0
│ │ ├── lifecycle.lua # Protocol lifecycle
│ │ └── router.lua # Message routing
│ ├── transport/ # Transport layers
│ │ ├── stdio.lua # Standard I/O transport
│ │ ├── sse.lua # Server-Sent Events
│ │ └── base.lua # Base transport class
│ ├── features/ # MCP features
│ │ ├── tools.lua # Tool management
│ │ ├── resources.lua # Resource management
│ │ ├── prompts.lua # Prompt templates
│ │ └── completion.lua# Auto-completion
│ ├── security/ # Security layer
│ │ ├── validator.lua # Input validation
│ │ ├── rate_limiter.lua # Rate limiting
│ │ └── access_control.lua # Access control
│ └── core/ # High-level components
│ ├── server.lua # MCP server
│ └── client.lua # MCP client
├── examples/ # Example implementations
├── tests/ # Test suite
└── docs/ # Documentation
The implementation includes a comprehensive security layer:
- JSON Schema validation for all inputs
- Maximum message size limits
- Sanitization of outputs
- Configurable request limits per client
- Sliding window algorithm
- Burst protection
- Tool/resource access restrictions
- Path traversal prevention
- Dangerous pattern blocking
- All operations logged with correlation IDs
- Security events tracked
- Performance metrics captured
local BaseTransport = require("mcp.transport.base")
local CustomTransport = {}
setmetatable(CustomTransport, {__index = BaseTransport})
function CustomTransport:new(config)
local self = BaseTransport.new(config)
setmetatable(self, CustomTransport)
-- Custom initialization
return self
end
function CustomTransport:send(message)
-- Custom send implementation
end
function CustomTransport:receive()
-- Custom receive implementation
endlocal Security = require("mcp.security")
local secure_server = {
security = Security:new({
validation = { enabled = true, max_message_size = 1024 * 1024 },
rate_limiting = { enabled = true, max_requests = 60 },
access_control = { enabled = true, allowed_tools = {"safe_tool"} }
})
}
function secure_server:handle_request(message, client_id)
local valid, err = self.security:validate_message(message, client_id)
if not valid then
return json_rpc.create_error_response(err, message.id)
end
-- Process validated request
endlua tests/run_all_tests.lualua tests/run_integration_test.lua./test_comprehensive.shContributions are welcome! Please ensure:
- All tests pass
- New features include tests
- Code follows existing patterns
- Documentation is updated
MIT License - See LICENSE file for details
- Model Context Protocol specification by Anthropic
- Lua community for foundational libraries
For issues, questions, or contributions:
- Open an issue on GitHub
- Check the MCP specification for protocol details
- Review the test suite for usage examples