{
  "markdown": "# MCP Moira\n\nAgent Workflow Engine for AI agents.\n\n**Primary users:** AI agents via MCP protocol. Web UI is supplementary for workflow management.\n\nSee [docs/VISION.md](docs/VISION.md) for product vision and design principles.\n\n## Two ways to run Moira\n\n- **Self-host (this repository, Apache-2.0)** — run the full engine + Web UI + MCP\n  server in a single Docker container on your own infrastructure. Free and open\n  source; your data stays with you. Start in the [Quick Start](#self-host-recommended)\n  below.\n- **Moira Cloud (managed)** — a hosted instance with nothing to operate, at\n  [moira-mcp.com](https://moira-mcp.com).\n\nBoth run the **same engine and MCP tools**. Self-host is a single-tenant\nprivate-team deployment with administrator-approved accounts. Cloud adds managed\nhosting and SaaS-only policy and administration, including social login, legal\nconsent, email verification, and the broader multi-user administration surface.\n\n## Architecture\n\n**Monorepo**: Clean separation of concerns with npm workspaces\n**Workflow Engine**: Node-graph execution over a set of node types (@mcp-moira/workflow-engine)\n**MCP Server**: HTTP protocol server exposing the MCP tools (@mcp-moira/mcp-server)\n**Web Backend**: Express API server (@mcp-moira/web-backend)\n**Web Frontend**: React UI with webpack (@mcp-moira/web-frontend)\n**Docs**: Astro 5 + Starlight documentation site, EN+RU (@mcp-moira/docs)\n**Shared**: Database layer + Better Auth + logging (@mcp-moira/shared)\n**Database**: Modular repository pattern with Drizzle ORM\n**Settings System**: Universal settings with encryption and dynamic UI generation\n**Docker Deployment**: Multi-stage container with TypeScript validation\n**Validation**: JSON Schema with AJV\n\n### Package Structure\n\n- **packages/workflow-engine/** - Core node-graph execution engine\n- **packages/mcp-server/** - MCP protocol HTTP server with tools\n- **packages/web-backend/** - Express API for workflow management\n- **packages/web-frontend/** - React UI for workflow visualization\n- **packages/docs/** - Astro 5 + Starlight documentation site (EN+RU), built into the image and served at `/docs`\n- **packages/shared/** - Database layer (schema, connection, repositories) + Better Auth + logging\n  - `database/` - Modular repositories (Workflow, Execution, Settings)\n  - `auth/` - Better Auth configuration\n  - `logging/` - Structured logging\n- **Docker Config** (`config/`) - Unified container deployment configuration\n\n## Quick Start\n\n### Self-Host (recommended)\n\nRun a complete Moira instance locally with Docker — no source build required:\n\n```bash\ncp .env.example .env       # defaults work locally; review host, port, and artifact domain for another host\ndocker compose up -d\n```\n\nThen open:\n\n- **Web UI**: http://localhost:8080\n- **Documentation**: http://localhost:8080/docs/\n- **MCP endpoint**: http://localhost:8080/mcp\n\nThe image is pulled from the public registry by default. Data (SQLite + execution\nstorage) persists in `./data`. See [Self-Hosting](#self-host-recommended) or the in-app docs\nat `/docs/` for the full reference.\n\n### Updating / Upgrading\n\nUpdate a normal self-host installation with the standard Compose commands:\n\n```bash\ndocker compose pull\ndocker compose up -d\ndocker compose ps\n```\n\nOlder `.env` files may still override Compose with the removed `0.3.5` tag; change that line once to\n`MOIRA_IMAGE=ghcr.io/moira-mcp/moira:latest` before updating.\n\nThe image protects existing self-host data before its startup migrations: it creates and verifies a\ncoherent SQLite backup, includes the prompt manifest, and keeps three rotating recovery states under\n`data/.moira-startup-backups/`. If initialization fails, it restores the database and manifest before\nrefusing to start the services. A persistent pending marker also restores the verified state before the\nnext attempt if the container or host was interrupted mid-initialization. A fresh installation skips\nthe nonexistent-database backup and uses only a temporary persistent marker so an interrupted first\nstart is removed before retry.\n\nThe complete automatic recovery behavior and optional pinned-image preflight are documented in\n[Self-hosting: Updating and Recovery](packages/docs/src/content/docs/docs/getting-started/self-hosting.mdx#updating-and-recovery), with a matching [Russian version](packages/docs/src/content/docs/ru/docs/getting-started/self-hosting.mdx#обновление-и-восстановление). Release notes are on the [GitHub Releases](https://github.com/moira-mcp/moira/releases) page.\n\n### Local Development (from source)\n\nFor contributors who want to build and run from the source tree, switch\n`docker-compose.yml` to **Option B** first — comment out the `image:` line and\nuncomment the `build:` block (the file documents both options inline). Then:\n\n```bash\nnpm install\ndocker compose up -d --build   # builds the image locally from config/Dockerfile\n# Web UI: http://localhost:8080  |  MCP: http://localhost:8080/mcp\n```\n\n(The default `docker-compose.yml` uses the prebuilt public image — `docker compose\nup -d` without `--build` — which is the recommended self-host path.)\n\n### Testing\n\nThe integration/API/E2E suites run against a local Docker container, configured by\n`.env.local`. Copy the template once before running them (or before\n`npm run docker:restart`):\n\n```bash\ncp .env.local.example .env.local   # then set BETTER_AUTH_SECRET\nnpm test              # All tests\nnpm run test:unit     # Unit tests only (no container needed)\nnpm run test:e2e      # E2E tests\n```\n\n### Code Quality\n\n```bash\nnpm run fix                   # ESLint + Prettier fix all files\n```\n\n**Configuration in `.env`** (copy from `.env.example`):\n\n- MOIRA_PORT: External access port (default 8080)\n- MOIRA_HOST: Public host:port the instance is served on (default localhost:8080)\n- STATIC_ARTIFACTS_DOMAIN: Wildcard subdomain base for published artifacts\n- BETTER_AUTH_SECRET: generated and persisted on first start when empty; set it\n  explicitly only when you want to manage the auth signing secret yourself\n- Database: SQLite at `./data/moira.db` (bind-mounted, persists across restarts)\n- Admin: ADMIN_EMAIL, ADMIN_PASSWORD (auto-generated on first start if unset)\n\n## Authentication\n\nMCP Moira uses Better Auth with OAuth 2.1 for centralized authentication.\n\n**Browser Access:**\n\n- Email/password login at http://localhost:8080/login\n- GitHub/Google OAuth (saas mode only; disabled in self-host)\n- Better Auth UI components (Tailwind + shadcn/ui)\n\n**MCP Clients:**\n\n- OAuth 2.1 authorization code flow\n- HTTP 401 triggers OAuth discovery\n- Dynamic Client Registration (DCR) supported\n- Access token required for all MCP tool calls\n\n**Protected:**\n\n- All MCP tools require authentication\n- All API routes (/api/_) require authentication (except /api/auth/_)\n- Centralized protection via middleware (no manual checks)\n\n**Testing:**\n\n```bash\ndocker compose up -d\n# Access:        http://localhost:8080/login\n# MCP Inspector: http://localhost:8080/mcp\n```\n\nSee [docs/AUTHENTICATION.md](docs/AUTHENTICATION.md) for complete setup and OAuth flow details.\n\n### MCP Configuration\n\nPoint your MCP client (e.g. Claude Code) at your running instance:\n\n| Server        | URL                       | Purpose                       |\n| ------------- | ------------------------- | ----------------------------- |\n| `moira-local` | http://localhost:8080/mcp | Your local self-host instance |\n\n```json\n{\n  \"mcpServers\": {\n    \"moira-local\": { \"url\": \"http://localhost:8080/mcp\" }\n  }\n}\n```\n\n> Replace `localhost:8080` with your own host/port (`MOIRA_HOST`) if you serve Moira\n> on a different address.\n\n## Representative Node Examples\n\nThe examples below show common graph patterns; they are not the complete node-type inventory. See\nthe [Nodes reference](packages/docs/src/content/docs/docs/concepts/nodes.mdx) for every supported\ntype and its current contract, including automatic note operations and file materialization.\n\n### Start Node\n\n```json\n{\n  \"type\": \"start\",\n  \"id\": \"start\",\n  \"connections\": { \"default\": \"next-node-id\" }\n}\n```\n\n### Agent Directive Node\n\n```json\n{\n  \"type\": \"agent-directive\",\n  \"id\": \"task\",\n  \"directive\": \"Task instruction\",\n  \"completionCondition\": \"Success criteria\",\n  \"inputSchema\": {/* JSON Schema */},\n  \"connections\": { \"success\": \"next-node-id\" }\n}\n```\n\n### Condition Node\n\n```json\n{\n  \"type\": \"condition\",\n  \"id\": \"check\",\n  \"condition\": {\n    \"operator\": \"gte\",\n    \"left\": { \"contextPath\": \"score\" },\n    \"right\": 8\n  },\n  \"connections\": {\n    \"true\": \"success-path\",\n    \"false\": \"failure-path\"\n  }\n}\n```\n\n### Telegram Notification Node\n\n```json\n{\n  \"type\": \"telegram-notification\",\n  \"id\": \"notify\",\n  \"message\": \"Task completed: {{result}}\",\n  \"chatId\": \"{{user_chat_id}}\",\n  \"connections\": { \"default\": \"next-node-id\" }\n}\n```\n\n### End Node\n\n```json\n{\n  \"type\": \"end\",\n  \"id\": \"end\",\n  \"finalOutput\": [\"result\", \"score\"]\n}\n```\n\n### Expression Node\n\n```json\n{\n  \"type\": \"expression\",\n  \"id\": \"increment-counter\",\n  \"expressions\": [\"counter = counter + 1\"],\n  \"connections\": { \"default\": \"next-step\" }\n}\n```\n\n### Teleport Node\n\n```json\n{\n  \"type\": \"teleport\",\n  \"id\": \"teleport-replan\",\n  \"directive\": \"Rewrite the development plan\",\n  \"completionCondition\": \"New plan created\",\n  \"hint\": \"Use when plan needs restructuring\",\n  \"connections\": { \"success\": \"plan-node\" }\n}\n```\n\n### Subgraph Node\n\n```json\n{\n  \"type\": \"subgraph\",\n  \"id\": \"run-subtask\",\n  \"graphId\": \"subtask-workflow\",\n  \"inputMapping\": { \"parentVar\": \"subVar\" },\n  \"outputMapping\": { \"subResult\": \"parentResult\" },\n  \"connections\": { \"success\": \"next-step\" }\n}\n```\n\n### Lock Node\n\n```json\n{\n  \"type\": \"lock\",\n  \"id\": \"approval-gate\",\n  \"reason\": \"Waiting for user approval before deployment\",\n  \"connections\": { \"unlocked\": \"next-step\" }\n}\n```\n\nPauses execution until explicitly unlocked. Sends PIN via Telegram with inline approve button. Unlockable via MCP tool, web UI, or Telegram callback.\n\n## Workflow Format\n\n```json\n{\n  \"id\": \"workflow-id\",\n  \"metadata\": {\n    \"name\": \"Workflow Name\",\n    \"version\": \"1.0.0\",\n    \"description\": \"What this workflow does\"\n  },\n  \"nodes\": [/* Node definitions */]\n}\n```\n\n## Templates\n\nVariables processed in `directive`, `completionCondition`, and `message` fields:\n\n- `{{variable}}` - Context variable\n- `{{nested.path}}` - Object property access\n- `{{executionId}}` - System: current process ID\n- `{{workflowId}}` - System: current workflow ID\n\n## MCP Tools\n\n```bash\n# Workflow Management\nlist\nstart {\"workflowId\": \"workflow-id\"}\nstep {\"processId\": \"process-id\", \"input\": \"data\"}\nmanage {\"action\": \"create\", \"workflow\": {...}}\nmanage {\"action\": \"edit\", \"workflowId\": \"workflow-id\", \"changes\": {...}}\nmanage {\"action\": \"get\", \"workflowId\": \"workflow-id\"}\n\n# Session Information\nsession {\"action\": \"user\"}\nsession {\"action\": \"executions\"}\nsession {\"action\": \"execution_context\", \"executionId\": \"execution-id\"}\nsession {\"action\": \"current_step\", \"executionId\": \"execution-id\"}\n\n# Execution Locking\nlock {\"action\": \"lock\", \"executionId\": \"execution-id\", \"reason\": \"Awaiting approval\"}\nlock {\"action\": \"unlock\", \"executionId\": \"execution-id\", \"pin\": \"123456\"}\nlock {\"action\": \"status\", \"executionId\": \"execution-id\"}\nlock {\"action\": \"list\"}\n\n# User Settings\nsettings {\"action\": \"get\"}\nsettings {\"action\": \"get\", \"category\": \"ui\"}\nsettings {\"action\": \"set\", \"key\": \"ui.theme\", \"value\": \"dark\"}\nsettings {\"action\": \"list\"}\n\n# Workflow Tokens\ntoken {\"action\": \"upload\", \"ttlMinutes\": 60}\ntoken {\"action\": \"download\", \"workflowId\": \"workflow-id\", \"ttlMinutes\": 60}\n\n# Documentation\nhelp\nhelp {\"topic\": \"tools\"}\nhelp {\"topic\": \"step\"}\n```\n\n## File Structure\n\n```\npackages/workflow-engine/  # Core execution engine\npackages/mcp-server/       # MCP HTTP server (internal port, behind nginx)\npackages/web-backend/      # Express API (internal port, behind nginx)\npackages/web-frontend/     # React UI (static build served by nginx)\ndata/                      # SQLite database (moira.db)\nworkflows/                 # Bundled public workflow catalog\ndocs/                      # Technical documentation\n```\n\n## Development\n\nAll development happens through Docker containers.\n\n```bash\ndocker compose up -d --build  # Build and run the container\nnpm test                      # Run all tests\nnpm run fix                   # ESLint + Prettier fix\n```\n\n**Database**: SQLite at DB_PATH (default: ./data/moira.db)\n**Migrations**: Drizzle ORM (`npx tsx scripts/run-migrations.ts`)\n**Storage**: Workflows and executions in database with user isolation\n\n## Documentation\n\n**User Documentation**: Served by your running instance at `/docs/` (EN) and `/ru/docs/` (RU), built from `packages/docs` (Starlight).\n\n**Technical Documentation**: `/docs` directory - system reference, API specs, development guides.\n\n**[Project Checklist](docs/PROJECT_CHECKLIST.md)** - mandatory pre-commit checks executed by development workflows.\n\n## Claude Code Commands\n\nCustom slash commands in `/commands` directory. See [commands/README.md](commands/README.md) for installation and usage.\n\n## HTTP Transport\n\n### Architecture\n\n- **Stateless Mode**: Each HTTP request creates new transport, no session storage\n- **JSON-RPC 2.0**: MCP protocol over HTTP with proper error handling\n- **Direct Tools**: MCP tools integrated in single process\n- **Environment Inheritance**: HTTP server environment variables passed to tools\n\n### Endpoints\n\n```http\nPOST /mcp     # JSON-RPC requests (tools calls)\nGET  /health  # Server health check\n```\n\n### Environment Variables\n\n```bash\n# Required for Telegram integration\nTELEGRAM_BOT_TOKEN=your_bot_token\nTELEGRAM_DEFAULT_CHAT_ID=your_chat_id\n\n# Optional\nMCP_PORT=4202  # Internal MCP server port (accessed via nginx proxy)\nLOG_LEVEL=info\nDEBUG_CONSOLE=true  # Console logging for development\nWORKFLOWS_DIR=./packages/web-backend/workflows/production\n```\n\n## Configuration\n\nMCP server configuration (see [MCP Configuration](#mcp-configuration) for details):\n\n```json\n{\n  \"mcpServers\": {\n    \"moira-local\": {\n      \"url\": \"http://localhost:8080/mcp\",\n      \"type\": \"http\"\n    }\n  }\n}\n```\n\nEnvironment variables passed via HTTP headers (recommended for HTTP transport).\n\nAlternative: Set environment variables in your `.env` file.\n\n## Code Quality\n\n### ESLint + Prettier\n\nProject uses ESLint with TypeScript support and Prettier for code formatting.\n\n```bash\nnpm run fix   # Auto-fix lint errors and format code\n```\n\n**Pre-commit Hook:**\nHusky pre-commit hook automatically runs ESLint and Prettier on staged files.\n\n**Configuration:**\n\n- `.eslintrc.json` - ESLint rules (strict for production code, relaxed for tests)\n- `.prettierrc` - Prettier formatting rules\n- Production code: `any` types are errors, must be properly typed\n- Test code: `any` types allowed for flexibility\n\n## Security\n\n### Rate Limiting\n\nProtection against spam and DoS attacks with tiered limits:\n\n- **API routes** (`/api/*`): 100 requests/minute\n- **Auth routes** (`/api/auth/*`): 100 requests/minute\n- **MCP endpoint** (`/mcp`): 30 requests/minute\n\nExceeded limits return HTTP 429 Too Many Requests.\n\n### Data Size Limits\n\nProtection against oversized payloads:\n\n- **Workflow JSON**: max 5MB\n- **Execution context**: max 10MB\n\nExceeded limits return HTTP 413 Payload Too Large.\n\n### GeoIP Logging\n\nRequest logging includes country detection via geoip-lite:\n\n```json\n{\n  \"method\": \"POST\",\n  \"path\": \"/api/workflows\",\n  \"ip\": \"203.0.113.1\",\n  \"country\": \"US\",\n  \"duration\": 45,\n  \"status\": 200\n}\n```\n\n## Admin Features\n\n### User Management\n\nAdmin panel at `/admin/users` provides:\n\n- **User list** with approval, email verification, and blocked status\n- **User details** page with sessions, OAuth connections, email history\n- **Approve** pending self-host registrations\n- **Session management** - revoke individual sessions or all sessions\n- **OAuth management** - revoke tokens by provider or all OAuth connections\n- **Block/Unblock** users with reason\n- **Send verification email** manually\n- **Send password reset email** manually\n- **Set a temporary password** for an ordinary user when email delivery is unavailable\n\n### Execution Monitoring\n\nThe Cloud `multiUserAdmin` capability enables the cross-user panel at `/admin/executions`. It is\nserver-denied and hidden by the default self-host policy:\n\n- View all user executions\n- Filter by user, status\n- Search by execution ID or workflow ID\n- Inspect execution context and variables\n\n### Email History\n\nTrack every email attempt:\n\n- Verification emails\n- Password reset emails\n- Notifications\n- Status (`sent`, `failed`, or log-only `logged`) with error messages\n\n## Email Features\n\n### Email Verification (SaaS)\n\n- Verification email sent on SaaS signup; self-host registration uses\n  administrator approval instead\n- Link expires in 24 hours\n- Admin can resend manually\n\n### Password Reset\n\n- With a real SMTP or Brevo provider, the user requests via `/forgot-password`\n  and receives a reset link\n- Link expires in 1 hour\n- Without real delivery, the reset form and email-send actions report the\n  capability as unavailable; an administrator can set a temporary password for\n  an ordinary user and require replacement at the next login\n\n### Email Provider\n\nConfigured via environment variables:\n\n```bash\nEMAIL_PROVIDER=smtp          # smtp, brevo, auto, none, or explicit test sink\nEMAIL_FROM=noreply@domain    # Required for real delivery\nSMTP_HOST=smtp.example.com\nSMTP_PORT=587\nSMTP_REQUIRE_TLS=true\n# SMTP_USER and SMTP_PASSWORD are optional, but must be supplied together\n```\n\nReal delivery supports generic SMTP and Brevo. With `EMAIL_PROVIDER=auto` (or\nunset), a complete SMTP configuration takes precedence and a legacy\n`BREVO_API_KEY` plus `EMAIL_FROM` configuration remains supported. The explicit\n`test` provider logs messages and is never advertised as real delivery.\n\n## Documentation Map\n\nWhere things are documented. After changing code, find the area below and update\nthe matching file in the same change.\n\n### Public docs — `packages/docs/src/content/docs/docs/` (EN) + `…/ru/docs/` (RU)\n\nRendered to the docs site (`/docs`) and read by users. Each EN page has an RU mirror.\n\n| Area            | Covers                                                                                  | Path               |\n| --------------- | --------------------------------------------------------------------------------------- | ------------------ |\n| Getting started | Introduction, quickstart, self-hosting                                                  | `getting-started/` |\n| Concepts        | Workflows, nodes, templates, notes, artifacts                                           | `concepts/`        |\n| Guides          | Writing directives, creating & editing workflows                                        | `guides/`          |\n| Reference       | Tools, input schema, magic variables, condition operators, validation, workflow catalog | `reference/`       |\n| Integration     | MCP clients, Claude Code, agent guide, Telegram setup, troubleshooting                  | `integration/`     |\n| Patterns        | Branching, validation loop, escalation, subagent review, workspace, and more            | `patterns/`        |\n\n### Internal docs — `docs/`\n\nFor contributors working on the codebase (implementation detail, not end-user docs).\n\n| File                   | Covers                                               | Path                                                              |\n| ---------------------- | ---------------------------------------------------- | ----------------------------------------------------------------- |\n| Development setup      | Build, Docker, local dev, project structure          | `docs/DEVELOPMENT.md`                                             |\n| Testing                | Test types, runner, fixtures, antipatterns           | `docs/TESTING.md` + `docs/testing/`                               |\n| API                    | Backend & admin HTTP API reference                   | `docs/API.md`                                                     |\n| System architecture    | Engine, storage, MCP transport, handlers, validation | `docs/SYSTEM.md`                                                  |\n| Authentication         | Better Auth, OAuth 2.1, API tokens                   | `docs/AUTHENTICATION.md`                                          |\n| Web UI                 | Frontend architecture, components                    | `docs/WEB-UI.md`                                                  |\n| Audit system           | Audit logging design                                 | `docs/AUDIT-SYSTEM.md`                                            |\n| Workflows              | Workflow authoring, tools, catalog                   | `docs/WORKFLOW.md`, `docs/WORKFLOWS.md`, `docs/WORKFLOW-TOOLS.md` |\n| Design system          | UI design tokens and components                      | `docs/DESIGN-SYSTEM.md`                                           |\n| Documentation style    | How to write internal **and** public docs            | `docs/DOCUMENTATION-STYLE-GUIDE.md`                               |\n| Logging                | Structured logging conventions                       | `docs/LOGGING.md`                                                 |\n| Issue management       | GitHub issue conventions                             | `docs/ISSUE-MANAGEMENT.md`                                        |\n| Architecture decisions | ADRs (licensing, OSS model, …)                       | `docs/adr/`                                                       |\n| Deployment             | Environment variables, restart procedures            | `docs/deployment/`                                                |\n| Legal                  | License/legal notes                                  | `docs/legal/`                                                     |\n\n## Contributing\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md) for setup, the PR flow, DCO sign-off, and how\nreleases are automated (Conventional Commits → semantic-release → versioned GHCR\nimage). For upgrading a self-host instance, see [Updating / Upgrading](#updating--upgrading).\n\n## License\n\n[Apache License 2.0](LICENSE)\n",
  "bytes": 22095,
  "sha": "f46ec8d29bc3616428ea2c9cf4f7ad7452e5f67e5e2e8118c089c2aa899d0c90",
  "repo_slug": "moira-mcp/moira",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_moira_mcp_moira_5805a5c8/readme"
}