{"id":31553617,"url":"https://github.com/leafo/lapis-mcp","last_synced_at":"2025-10-04T20:27:11.903Z","repository":{"id":293449612,"uuid":"983954728","full_name":"leafo/lapis-mcp","owner":"leafo","description":"MCP server for Lapis apps","archived":false,"fork":false,"pushed_at":"2025-07-20T19:18:36.000Z","size":99,"stargazers_count":6,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-09-28T22:46:59.225Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"MoonScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/leafo.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-05-15T07:08:06.000Z","updated_at":"2025-08-09T14:40:34.000Z","dependencies_parsed_at":"2025-05-15T11:53:40.486Z","dependency_job_id":"d4ff756a-f606-479d-9300-6c85ebb29376","html_url":"https://github.com/leafo/lapis-mcp","commit_stats":null,"previous_names":["leafo/lapis-mcp"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/leafo/lapis-mcp","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leafo%2Flapis-mcp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leafo%2Flapis-mcp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leafo%2Flapis-mcp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leafo%2Flapis-mcp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/leafo","download_url":"https://codeload.github.com/leafo/lapis-mcp/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leafo%2Flapis-mcp/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278368035,"owners_count":25975378,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-04T02:00:05.491Z","response_time":63,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-10-04T20:27:09.917Z","updated_at":"2025-10-04T20:27:11.898Z","avatar_url":"https://github.com/leafo.png","language":"MoonScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Lapis MCP\n\nA libray for developing MCP servers in Lua/MoonScript. Also contains a default\nMCP server for communicating with Lapis web applications.\n\n\n## Installation\n\n```bash\nluarocks install lapis-mcp\n```\n\n## Lapis MCP Usage\n\nThis library provides a `lapis` subcommand, `mcp`, which can be used to start\nan MCP server tied to the Lapis application in the current directory.\n\n```\nlapis _ mcp\n```\n\n### Available Tools\n\n- **list_routes** - Lists all named routes in the Lapis application\n- **list_models** - Lists all database models defined in the application (classes that represent database tables)\n- **schema** - Shows the SQL schema for a specific database model (requires model_name parameter)\n\nThe server automatically discovers routes from your application's router and models from the `models/` directory.\n\n## Creating Your Own MCP Server\n\nThis project provides a reusable `McpServer` base class that you can extend to create your own MCP servers. Here's how to implement your own:\n\n### Key Features\n\n- **Inheritance-based tool registration** - Tools are inherited from parent classes, with the ability for subclasses to override tools by name\n- **Error handling** - Both exceptions and explicit error returns are handled\n- **Debug logging** - Optional debug output with colored console logging\n- **MCP protocol compliance** - Follows the MCP 2025-06-18 specification\n\n### Full Example: File System MCP Server\n\n#### Lua\n\n```lua\nlocal McpServer = require(\"lapis.mcp.server\").McpServer\nlocal json = require(\"cjson.safe\")\n\nlocal FileSystemMcpServer = McpServer:extend(\"FileSystemMcpServer\", {\n  server_name = \"filesystem-mcp\",\n  instructions = \"Tools to interact with the local filesystem\"\n})\n\nFileSystemMcpServer:add_tool({\n  name = \"list_files\",\n  description = \"Lists files in a directory\", \n  inputSchema = {\n    type = \"object\",\n    properties = {\n      path = {\n        type = \"string\",\n        description = \"Directory path to list\",\n        default = \".\"\n      }\n    },\n    -- Note: must serialize to an empty array in JSON\n    required = setmetatable({}, json.array_mt)\n  }\n}, function(self, params)\n  local path = params.path or \".\"\n  local files = {}\n  \n  for file in io.popen(\"ls -la '\" .. path .. \"'\"):lines() do\n    table.insert(files, file)\n  end\n  \n  return files\nend)\n\n-- Usage\nlocal server = FileSystemMcpServer({\n  debug = true\n})\nserver:run_stdio()\n```\n\n#### MoonScript\n\n```moonscript\nimport McpServer from require \"lapis.mcp.server\"\njson = require \"cjson.safe\"\n\nclass FileSystemMcpServer extends McpServer\n  @server_name: \"filesystem-mcp\"\n  @instructions: [[Tools to interact with the local filesystem]]\n\n  @add_tool {\n    name: \"list_files\"\n    description: \"Lists files in a directory\"\n    inputSchema: {\n      type: \"object\"\n      properties: {\n        path: {\n          type: \"string\"\n          description: \"Directory path to list\"\n          default: \".\"\n        }\n      }\n      -- Note: must serialize to an empty array in JSON\n      required: setmetatable {}, json.array_mt\n    }\n  }, (params) =\u003e\n    path = params.path or \".\"\n    files = {}\n\n    for file in io.popen(\"ls -la '#{path}'\")\\lines()\n      table.insert(files, file)\n\n    files\n\n-- Usage\nserver = FileSystemMcpServer {\n  debug: true\n}\nserver\\run_stdio!\n```\n\n### Basic Structure\n\n#### Lua\n\n```lua\n-- Import the base class\nlocal McpServer = require(\"lapis.mcp.server\").McpServer\n\n-- Create your custom server class\nlocal MyMcpServer = McpServer:extend(\"MyMcpServer\", {\n  server_name = \"my-mcp-server\",\n  server_version = \"1.0.0\", \n  server_vendor = \"Your Company\",\n  instructions = \"Your server description here\"\n})\n\n-- Usage\nlocal server = MyMcpServer({debug = true})\nserver:run_stdio()\n```\n\n#### MoonScript\n\n```moonscript\n-- Import the base class\nimport McpServer from require \"lapis.mcp.server\"\n\n-- Create your custom server class\nclass MyMcpServer extends McpServer\n  @server_name: \"my-mcp-server\"\n  @server_version: \"1.0.0\"\n  @server_vendor: \"Your Company\"\n  @instructions: [[Your server description here]]\n\n  new: (options = {}) =\u003e\n    super(options)\n    -- Initialize your server-specific state\n```\n\n### Adding Tools\n\nUse the `@add_tool` class method to register tools:\n\n#### Lua\n\n```lua\n-- Add a simple tool\nMyMcpServer:add_tool({\n  name = \"hello\",\n  description = \"Returns a greeting message\",\n  inputSchema = {\n    type = \"object\",\n    properties = {\n      name = {\n        type = \"string\",\n        description = \"Name to greet\"\n      }\n    },\n    required = {\"name\"}\n  },\n  annotations = {\n    title = \"Say Hello\"\n  }\n}, function(self, params)\n  return \"Hello, \" .. params.name .. \"!\"\nend)\n\n-- Add a tool with no parameters\nMyMcpServer:add_tool({\n  name = \"status\",\n  description = \"Returns server status\",\n  inputSchema = {\n    type = \"object\",\n    properties = {},\n    required = setmetatable({}, json.array_mt)  -- Empty array for no required params\n  },\n  annotations = {\n    title = \"Server Status\"\n  }\n}, function(self, params)\n  return {\n    status = \"running\",\n    timestamp = os.time()\n  }\nend)\n```\n\n#### MoonScript\n\n```moonscript\n-- Add a simple tool\n@add_tool {\n  name: \"hello\"\n  description: \"Returns a greeting message\"\n  inputSchema: {\n    type: \"object\"\n    properties: {\n      name: {\n        type: \"string\"\n        description: \"Name to greet\"\n      }\n    }\n    required: {\"name\"}\n  }\n  annotations: {\n    title: \"Say Hello\"\n  }\n}, (params) =\u003e\n  \"Hello, #{params.name}!\"\n\n-- Add a tool with no parameters\n@add_tool {\n  name: \"status\"\n  description: \"Returns server status\"\n  inputSchema: {\n    type: \"object\"\n    properties: {}\n    required: setmetatable {}, json.array_mt  -- Empty array for no required params\n  }\n  annotations: {\n    title: \"Server Status\"\n  }\n}, (params) =\u003e\n  {\n    status: \"running\"\n    timestamp: os.time()\n  }\n```\n\n### Error Handling\n\nTools can return errors using the `nil, error_message` pattern:\n\n#### Lua\n\n```lua\nMyMcpServer:add_tool({\n  name = \"divide\",\n  description = \"Divides two numbers\",\n  inputSchema = {\n    type = \"object\",\n    properties = {\n      a = { type = \"number\" },\n      b = { type = \"number\" }\n    },\n    required = {\"a\", \"b\"}\n  }\n}, function(self, params)\n  if params.b == 0 then\n    return nil, \"Division by zero is not allowed\"\n  end\n  \n  return params.a / params.b\nend)\n```\n\n#### MoonScript\n\n```moonscript\n@add_tool {\n  name: \"divide\"\n  description: \"Divides two numbers\"\n  inputSchema: {\n    type: \"object\"\n    properties: {\n      a: { type: \"number\" }\n      b: { type: \"number\" }\n    }\n    required: {\"a\", \"b\"}\n  }\n}, (params) =\u003e\n  if params.b == 0\n    return nil, \"Division by zero is not allowed\"\n\n  params.a / params.b\n```\n\n### Running Your Server\n\nYou can run your MCP server in two ways: directly using `run_stdio()` or with a CLI interface using the `run_cli` class method.\n\n#### Direct Execution\n\n##### Lua\n\n```lua\n-- Create and run your server\nlocal server = MyMcpServer({debug = true})\nserver:run_stdio()\n```\n\n##### MoonScript\n\n```moonscript\n-- Create and run your server\nserver = MyMcpServer({debug: true})\nserver\\run_stdio()\n```\n\n#### CLI Interface with `run_cli`\n\nThe `run_cli` class method provides a command-line interface with argument parsing for your MCP server:\n\n##### Lua\n\n```lua\n-- Run your server with CLI interface\nMyMcpServer:run_cli({\n  name = \"my-custom-server\"  -- Optional: override the CLI program name\n})\n```\n\n##### MoonScript\n\n```moonscript\n-- Run your server with CLI interface\nMyMcpServer\\run_cli {\n  name: \"my-custom-server\"  -- Optional: override the CLI program name\n}\n```\n\n#### CLI Options\n\nThe `run_cli` method provides several useful command-line options:\n\n\n- `--help` - Show all CLI options\n- `--debug` - Enable debug logging to stderr\n- `--skip-initialize` / `--skip-init` - Skip the initialize stage and listen for messages immediately\n- `--tool \u003ctool_name\u003e` - Immediately invoke a specific tool, print output and exit\n- `--tool-argument \u003cjson\u003e` / `--arg \u003cjson\u003e` - Pass arguments to the tool (in JSON format)\n- `--send-message \u003cmessage\u003e` - Send a raw message and exit\n\n#### Examples\n\n```bash\n# Run server normally\n./my_server.lua\n\n# Run with debug logging\n./my_server.lua --debug\n\n# Test a specific tool\n./my_server.lua --tool list_files --arg '{\"path\": \"/tmp\"}'\n\n# Send a raw MCP message\n./my_server.lua --send-message tools/list\n\n# Send the initialize message\n./my_server.lua --send-message initialize\n\n# Send a custom JSON message\n./my_server.lua --send-message '{\"jsonrpc\":\"2.0\",\"id\":\"test\",\"method\":\"tools/call\",\"params\":{\"name\":\"hello\",\"arguments\":{\"name\":\"World\"}}}'\n```\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fleafo%2Flapis-mcp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fleafo%2Flapis-mcp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fleafo%2Flapis-mcp/lists"}