Mooncore

Mooncore

A minimal Elixir framework for building APIs.

One concept. Every transport. Built-in devtools.

Mooncore replaces controllers, routes, and transport-specific handlers with a single idea: named operations called actions. Write the logic once, call it over HTTP, WebSocket, or directly from code — and watch it run in a live dashboard.

The Problem It Solves

When you build a typical API, the same business logic ends up scattered: one version for HTTP routes, another for WebSocket handlers, test helpers that fake HTTP requests. Add a new transport and you're duplicating again.

Mooncore collapses this. You define operations by name — "task.create", "user.login" — and the framework handles how they're called. HTTP, WebSocket, or direct Elixir function call: the same handler, unchanged.

What Are Actions?

An action is just a named function

It has a name

"task.create"

It takes parameters

A map of input data

It returns a result

That's it

Mooncore routes any transport — HTTP POST, WebSocket message, AI agent call — into that same function. No controllers, no route files, no "which layer owns this logic" decisions.

REST API thinking

POST /api/tasks
GET /api/tasks
POST /api/tasks/:id/assign

Mooncore thinking

"task.create"
"task.list"
"task.assign"

MCP Server

Mooncore includes a built-in Model Context Protocol (MCP) server that exposes your application's internals to AI tools, IDE extensions, and custom integrations. It implements the Streamable HTTP transport with JSON-RPC 2.0.

Security: The MCP server provides full access to action execution, code evaluation, and log inspection. Never enable mooncore_dev_tools in production.

Setup

Set MOONCORE_DEV_MODE=true environment variable on your system and enable mooncore_dev_tools in your config:

config :mooncore,
  mooncore_dev_tools: true,
  mcp_port: 4040   # default

The MCP endpoint is available at http://localhost:4040/mcp when the server is running.

Protocol

Mooncore implements the MCP specification (protocol version 2025-03-26) over HTTP POST with JSON-RPC 2.0:

POST http://localhost:4040/mcp
Content-Type: application/json

{"jsonrpc": "2.0", "id": 1, "method": "initialize", "params": {}}

Supported JSON-RPC methods include:

  • initialize — Handshake: protocol version, capabilities, server info
  • ping — Keepalive
  • tools/list — List available tools
  • tools/call — Call a tool by name
  • resources/list and resources/read — Browse read-only resources

Example initialize response:

{
  "protocolVersion": "2025-03-26",
  "capabilities": { "tools": {}, "resources": {} },
  "serverInfo": { "name": "mooncore", "version": "0.2.0" }
}

Tools

Tools are callable operations that can modify state or execute code.

run_action

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "run_action",
    "arguments": {
      "action": "task.create",
      "params": {"title": "New task"},
      "auth": {"roles": ["user"], "user": "alice"}
    }
  }
}

eval

{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "tools/call",
  "params": {
    "name": "eval",
    "arguments": { "code": "Enum.map(1..5, & &1 * 2)" }
  }
}

read_logs / clear_logs

{
  "jsonrpc": "2.0",
  "id": 3,
  "method": "tools/call",
  "params": {
    "name": "read_logs",
    "arguments": { "tag": "action", "since_id": 42 }
  }
}

Resources

Read-only resources provide context about the running application.

{
  "jsonrpc": "2.0",
  "id": 5,
  "method": "resources/read",
  "params": { "uri": "mooncore://actions" }
}

Examples: mooncore://actions, mooncore://apps, mooncore://clients, mooncore://config.

VS Code Integration

Add the MCP server to your editor integration in .vscode/mcp.json:

{
  "servers": {
    "mooncore": {
      "type": "http",
      "url": "http://localhost:4040/mcp"
    }
  }
}

JSON API

The dev server also exposes a simpler JSON API on the same port for direct HTTP access.

POST /api/mcp    — Generic MCP request
POST /api/eval   — Evaluate Elixir code
POST /api/action — Execute an action
GET  /api/logs   — Read logs (query: tag, since)
GET  /api/actions— List all actions
GET  /api/config — Get server config

Watcher

The Watcher collects in-memory logs (ring buffer) used by the dashboard and MCP log tools.

Mooncore.MCP.Watcher.log(:custom, %{message: "Something happened"})
Mooncore.MCP.Watcher.read(:action)
Mooncore.MCP.Watcher.read_since(42)

Elixir API

Mooncore.MCP.Server.list_actions()
Mooncore.MCP.Server.list_clients()
Mooncore.MCP.Server.server_info()
Mooncore.MCP.Server.run_action("task.create", %{"title" => "Test"}, nil)
Mooncore.MCP.Server.eval_code("1 + 1")
Mooncore.MCP.Server.read_logs(%{"tag" => "action"})

All functions require mooncore_dev_tools: true and will error when disabled.

Features

Transport-agnostic actions

HTTP, WebSocket, Elixir call, MCP, message queues — one handler, every transport.

Live devtools dashboard

Run actions, inspect logs, browse files, read guides — all in the browser at localhost:4040.

MCP server included

AI agents connect directly. Discover actions, call them, iterate — no HTTP client setup required.

Auth out of the box

JWT (RS256) with role-based access control. Add to router in one line.

No framework opinions

No ORM, no templates, no asset pipeline. Bring your own database and tools.

Functional by design

Parameters in, result out. No hidden state, no magic, easy to test.

Who It's For

Mooncore fits developers building:

JSON API backends

Mobile apps, SPAs, microservices

Real-time applications

WebSocket as a first-class requirement

Multi-tenant systems

Built-in tenant isolation

AI-integrated backends

Where agents need to call into your application

Note: If you need server-rendered HTML, Phoenix is the better choice. Mooncore handles the API layer and gets out of the way of everything else.

Get Started

Let AI Build For You

Copy paste this prompt to your favorite AI coding agent and watch it build a working app:

Create a simple to-do app using https://hexdocs.pm/mooncore/ and start with mooncore_dev_tools: true

Manual Installation

mix.exs

# mix.exs {:mooncore, "~> 0.2.0"}

config/config.exs

# config/config.exs config :mooncore, port: 4000, router: MyApp.Router, app_module: MyApp.App, mooncore_dev_tools: true, mcp_port: 4040

Run it

$ mix run --no-halt

Your API is on port 4000, devtools on port 4040.

Ready to Build Better APIs?

Start building with Mooncore today. Minimal, focused, and AI-ready.