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_KEYorMOUL_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/mcpand 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/jsonMethod 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/jsonQuery 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 Name | Category | Description |
|---|---|---|
moul_list_collections | Schema | List all dynamic collection schemas and tables. |
moul_get_collection | Schema | Get detailed schema definition, field types, and access rules. |
moul_create_collection | Schema | Create a new dynamic collection and SQLite table. |
moul_delete_collection | Schema | Delete a collection and drop its SQLite table. |
moul_list_records | CRUD | Query paginated records with optional filters. |
moul_get_record | CRUD | Retrieve a single record by collection name and ID. |
moul_create_record | CRUD | Insert a new dynamic record into a collection. |
moul_update_record | CRUD | Update an existing record by ID. |
moul_delete_record | CRUD | Delete a record by ID. |
moul_list_worker_jobs | Workers | List background jobs by status (available, executing, retryable, etc.). |
moul_enqueue_job | Workers | Enqueue a new background worker job. |
moul_cancel_job | Workers | Cancel a pending or retryable worker job. |
moul_list_feature_flags | Flags | List OpenFeature flags and targeting gate rules. |
moul_set_feature_flag | Flags | Create or update a feature flag and rollout percentage. |
moul_get_system_metrics | Metrics | Fetch host CPU, Memory, Disk, and load metrics. |
moul_get_analytics_summary | Observability | Fetch visitor and request analytics totals. |
moul_list_requests | Observability | Query recent HTTP request logs. |
Outbound HTTP Webhooks
Connect Moul collections to external systems with synchronous before-hooks, async after-hooks, and HMAC-SHA256 signatures.
First-Party Analytics & Observability
Built-in privacy-preserving analytics, visitor session deduplication, UTM campaign tracking, and zero-latency request logging.