Initial release: Lua MCP server library
Zero-dependency MCP (Model Context Protocol) server in pure Lua. Only requires luasocket. 2MB RSS vs Python FastMCP's 97MB. - json.lua: pure Lua JSON encoder/decoder (~150 lines) - lmcp.lua: MCP server with streamable-http transport (~230 lines) - example_server.lua: shell/file tools demo Implements MCP 2025-03-26: initialize, tools/list, tools/call, notifications/initialized, ping. JSON-RPC 2.0. SSE support. CORS. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
#!/usr/bin/env lua
|
||||
-- Example lmcp server — shell tools
|
||||
-- Usage: lua example_server.lua [port]
|
||||
|
||||
local dir = arg[0]:match('(.*/)') or './'
|
||||
package.path = package.path .. ';' .. dir .. '?.lua'
|
||||
|
||||
local lmcp = require('lmcp')
|
||||
|
||||
local server = lmcp.new("example-tools", {
|
||||
port = tonumber(arg[1]) or 8080,
|
||||
})
|
||||
|
||||
server:tool("shell", "Execute a shell command", {
|
||||
type = "object",
|
||||
properties = {
|
||||
command = { type = "string", description = "Shell command to execute" },
|
||||
timeout = { type = "integer", description = "Timeout in seconds", default = 30 },
|
||||
},
|
||||
required = { "command" },
|
||||
}, function(args)
|
||||
local handle = io.popen(args.command .. ' 2>&1', 'r')
|
||||
if not handle then return "Error: could not execute command" end
|
||||
local result = handle:read('*a')
|
||||
handle:close()
|
||||
return result ~= '' and result or '(no output)'
|
||||
end)
|
||||
|
||||
server:tool("read_file", "Read a file", {
|
||||
type = "object",
|
||||
properties = {
|
||||
path = { type = "string", description = "File path to read" },
|
||||
},
|
||||
required = { "path" },
|
||||
}, function(args)
|
||||
local f = io.open(args.path, 'r')
|
||||
if not f then return "Error: could not open " .. args.path end
|
||||
local content = f:read('*a')
|
||||
f:close()
|
||||
return content
|
||||
end)
|
||||
|
||||
server:tool("write_file", "Write content to a file", {
|
||||
type = "object",
|
||||
properties = {
|
||||
path = { type = "string", description = "File path to write" },
|
||||
content = { type = "string", description = "Content to write" },
|
||||
},
|
||||
required = { "path", "content" },
|
||||
}, function(args)
|
||||
local f = io.open(args.path, 'w')
|
||||
if not f then return "Error: could not open " .. args.path .. " for writing" end
|
||||
f:write(args.content)
|
||||
f:close()
|
||||
return string.format("Written %d bytes to %s", #args.content, args.path)
|
||||
end)
|
||||
|
||||
server:tool("list_dir", "List directory contents", {
|
||||
type = "object",
|
||||
properties = {
|
||||
path = { type = "string", description = "Directory path", default = "." },
|
||||
},
|
||||
}, function(args)
|
||||
local path = args.path or '.'
|
||||
local handle = io.popen('ls -1 ' .. path:gsub("'", "'\\''") .. ' 2>&1')
|
||||
if not handle then return "Error: could not list " .. path end
|
||||
local result = handle:read('*a')
|
||||
handle:close()
|
||||
return result
|
||||
end)
|
||||
|
||||
io.stderr:write("Starting lmcp example server...\n")
|
||||
server:run()
|
||||
Reference in New Issue
Block a user