Moul

Built-in Model Context Protocol (MCP) Server

Native MCP server enabling AI coding assistants to inspect schemas, execute CRUD, manage background jobs, and monitor metrics.

moul includes a native Model Context Protocol (MCP) server powered by github.com/mark3labs/mcp-go. This empowers AI coding assistants (Claude Desktop, Cursor, Antigravity, Windsurf, Claude Code) with deep schema inspection, data manipulation, worker orchestration, and observability control directly over your backend.


Transport Modes

Moul supports two transport modes to fit every development and production workflow:

1. Local Stdio Transport (moul mcp)

Communicates directly over standard input and standard output streams (stdin/stdout) via JSON-RPC.

  • Zero Secrets Required: Operates with the filesystem permissions of the executing local user. You do not need to supply MOUL_ADMIN_KEY or MOUL_JWT_SECRET.
  • Ideal For: Local desktop assistants like Claude Desktop, local Cursor processes, Antigravity CLI, or CI/CD test pipelines.

2. Streamable HTTP & SSE Transport (/api/mcp)

Active automatically whenever the server is running (moul start or your custom Go embedded binary).

  • Modern MCP 2025 Spec: Supports stateful and stateless direct JSON-RPC POST requests to /api/mcp.
  • Legacy SSE Spec: Supports Server-Sent Events at /api/mcp and message posting at /api/mcp/message.
  • Ideal For: Remote MCP setups, shared team development servers, containerized instances, or Cursor HTTP connections.

HTTP Authentication Methods

When communicating with the HTTP or SSE endpoint (http://localhost:8090/api/mcp), requests must be authenticated using the server's configured admin key (MOUL_ADMIN_KEY).

Moul provides two distinct header authentication methods:

Method 1: Bearer Token Authorization Header (Authorization)

The industry-standard OAuth 2.0 / HTTP Bearer convention. This is the recommended method for Cursor, Windsurf, and modern AI coding assistants.

POST /api/mcp HTTP/1.1
Host: localhost:8090
Authorization: Bearer <MOUL_ADMIN_KEY>
Content-Type: application/json

Method 2: Dedicated Admin Key Header (X-Admin-Key)

A custom header designed for API gateways, proxies, cloud load balancers, and shell scripts where setting standard Authorization headers might conflict with upstream proxies.

POST /api/mcp HTTP/1.1
Host: localhost:8090
X-Admin-Key: <MOUL_ADMIN_KEY>
Content-Type: application/json

Query Parameter Fallback

For restricted clients or environments where custom request headers cannot be configured, Moul also accepts the admin key via URL query parameter: http://localhost:8090/api/mcp?adminKey=<MOUL_ADMIN_KEY>


Assistant Configuration

Configure remote Streamable HTTP MCP in .cursor/mcp.json using the standard Authorization: Bearer header:

{
  "mcpServers": {
    "moul": {
      "type": "http",
      "url": "http://localhost:8090/api/mcp",
      "headers": {
        "Authorization": "Bearer admin-key-dev-secret-change-me"
      }
    }
  }
}

Configure remote Streamable HTTP MCP in .cursor/mcp.json using the X-Admin-Key header:

{
  "mcpServers": {
    "moul": {
      "type": "http",
      "url": "http://localhost:8090/api/mcp",
      "headers": {
        "X-Admin-Key": "admin-key-dev-secret-change-me"
      }
    }
  }
}

Launch a local moul binary process over stdio without running a separate HTTP server process. Configure in .cursor/mcp.json:

{
  "mcpServers": {
    "moul": {
      "command": "moul",
      "args": ["mcp"],
      "env": {
        "MOUL_DB_PATH": "moul-local.db"
      }
    }
  }
}

Add to claude_desktop_config.json (on macOS: ~/Library/Application Support/Claude/claude_desktop_config.json, on Windows: %APPDATA%\Claude\claude_desktop_config.json):

{
  "mcpServers": {
    "moul": {
      "command": "/usr/local/bin/moul",
      "args": ["mcp"],
      "env": {
        "MOUL_DB_PATH": "/Users/username/myproject/moul-local.db"
      }
    }
  }
}

Verify your MCP server directly via raw JSON-RPC tool calls:

Using Bearer Token:

curl -X POST "http://localhost:8090/api/mcp" \
  -H "Authorization: Bearer admin-key-dev-secret-change-me" \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "moul_list_collections",
      "arguments": {}
    }
  }'

Using X-Admin-Key:

curl -X POST "http://localhost:8090/api/mcp" \
  -H "X-Admin-Key: admin-key-dev-secret-change-me" \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 2,
    "method": "tools/call",
    "params": {
      "name": "moul_get_system_metrics",
      "arguments": {}
    }
  }'

Custom Binaries & Custom MCP Tools

When embedding Moul as a Go library via pkg/app, the built-in MCP server remains fully operational across both CLI Stdio mode and HTTP mode.

You can also register custom, domain-specific MCP tools:

package main

import (
	"context"
	"fmt"

	"github.com/mark3labs/mcp-go/mcp"
	"github.com/moul-dev/moul-dev/pkg/app"
)

func main() {
	moulApp := app.New(app.Config{
		Version: "1.0.0-custom",
	})

	// Register a custom MCP tool
	discountTool := mcp.NewTool(
		"calculate_customer_discount",
		mcp.WithDescription("Calculate customer discount rate"),
		mcp.WithString("tier", mcp.Required(), mcp.Description("Tier: standard, gold, platinum")),
		mcp.WithNumber("amount", mcp.Required(), mcp.Description("Order amount")),
	)

	moulApp.RegisterMCPTool(discountTool, func(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
		tier := req.GetString("tier", "standard")
		amount := req.GetFloat("amount", 0.0)
		return mcp.NewToolResultText(fmt.Sprintf("Tier %s, Amount $%.2f", tier, amount)), nil
	})

	// Guard console output so stdio MCP transport isn't corrupted
	if !app.IsMCP() {
		fmt.Println("🚀 Server running on http://localhost:8090")
	}

	moulApp.Start(context.Background())
}

Check out the full runnable example in examples/custom-binary-with-mcp.


Available MCP Tools Catalog

The built-in MCP server exposes 17+ high-level operational tools categorized by capability:

MCP Tool NameCategoryDescription
moul_list_collectionsSchemaList all dynamic collection schemas and tables.
moul_get_collectionSchemaGet detailed schema definition, field types, and access rules.
moul_create_collectionSchemaCreate a new dynamic collection and SQLite table.
moul_delete_collectionSchemaDelete a collection and drop its SQLite table.
moul_list_recordsCRUDQuery paginated records with optional filters.
moul_get_recordCRUDRetrieve a single record by collection name and ID.
moul_create_recordCRUDInsert a new dynamic record into a collection.
moul_update_recordCRUDUpdate an existing record by ID.
moul_delete_recordCRUDDelete a record by ID.
moul_list_worker_jobsWorkersList background jobs by status (available, executing, retryable, etc.).
moul_enqueue_jobWorkersEnqueue a new background worker job.
moul_cancel_jobWorkersCancel a pending or retryable worker job.
moul_list_feature_flagsFlagsList OpenFeature flags and targeting gate rules.
moul_set_feature_flagFlagsCreate or update a feature flag and rollout percentage.
moul_get_system_metricsMetricsFetch host CPU, Memory, Disk, and load metrics.
moul_get_analytics_summaryObservabilityFetch visitor and request analytics totals.
moul_list_requestsObservabilityQuery recent HTTP request logs.

On this page