Self-host the engine
Run the Noodle Seed engine yourself — local development with no account, the standalone service, and the portability guarantee.
Noodle is built so the engine is yours to run. The compiler, runtime, protocol/transport, compute sandbox, authoring SDK, and CLI are the open-source core (see the open-core table in the the open-core boundary). You can develop, run, and operate Noodle MCP servers without a Noodle Seed account.
There are two self-host levels, smallest first:
- Local dev (zero account, zero config) —
noodle dev, already covered below. - Standalone service — the multi-tenant deploy service on your own host.
1. Local dev — zero account, zero login
With Node 24+, the magic moment needs no account, no service, and no global install:
npx @noodleseed/one@latest init my-app # or: npm i -g @noodleseed/one && noodle init my-app
cd my-app
noodle dev
: # → MCP endpoint: http://127.0.0.1:<port>/o/local/my-app/dev/mcpnoodle init is safe to re-run — it only adds missing scaffold files and preserves your edits (pass
--force to overwrite, --dry-run --json to preview).
noodle dev boots the full runtime in-process, in-memory, on loopback — no Postgres, no master key, no
OAuth. It hot-reloads server.ts on save. noodle validate (compile only) and noodle test (compile + MCP
smoke) are the one-shot variants. None of these require noodle login or noodle link. See
hosted-quickstart.md for the full local author loop.
2. Run the standalone service
The deploy service is a single stateless process that accepts tenant-scoped deploys and serves each app at
/o/{org}/{app}/mcp (or /o/{org}/{app}/{env}/mcp). Build the workspace, then run the service binary:
git clone https://github.com/NoodleSeed-com/noodle-core
cd noodle-core
pnpm install
pnpm build
node packages/service/dist/main.js
: # → Noodle deploy service listening at http://127.0.0.1:8787In its default form it runs in-memory on loopback with the control plane OPEN — a throwaway local multi-tenant instance. It boots, recovers, and serves tenant MCP routes with no external dependencies.
Deploys need a deployer identity. A deploy defaults to the
owner-onlyaccess mode, and identity access modes require an authenticated deployer — so the bare open service serves apps but will reject an unauthenticatednoodle deploy. To exercise the full deploy → call loop on the real binary, configure a deployer identity (the control-plane + owner auth knobs under Configuration below) — or just run the end-to-end harness, which boots the real binary with a local issuer and runs a deploy → call sweep:
pnpm e2e # or: node scripts/e2e-localhost.mjsFor the single-app inner loop with zero auth or config, prefer noodle dev (Section 1): it runs the same
runtime in-process and is the fastest way to see the engine serve MCP locally.
Loopback-only by default, fail-closed otherwise. The open mode is safe only because it binds loopback. The service refuses to expose a non-loopback bind without deploy authentication — set a control-auth mode (below) before binding a public interface.
Configuration
The service is configured entirely through environment variables. Pick persistence and auth independently.
Network
| Variable | Default | Purpose |
|---|---|---|
PORT | 8787 | Listen port. |
HOST | 127.0.0.1 | Bind address. Use 0.0.0.0 only with auth + a TLS proxy. |
PUBLIC_BASE_URL | — | External URL used when building endpoint URLs in responses. |
NOODLE_TRUST_PROXY | off | 1/true behind a TLS-terminating proxy (enforces HTTPS + HSTS, trusts X-Forwarded-Proto). |
NOODLE_LOG_LEVEL | info | debug | info | warn | error. |
NOODLE_WARM_ALL | off | Eager recompile-all-on-boot for pinned single-instance/on-prem; default is lazy recompile-on-first-request. |
Persistence (omit both for in-memory; deploys are then lost on restart)
| Variable | Purpose |
|---|---|
NOODLE_DATA_DIR | File-backed JSON artifact store in a local directory. |
DATABASE_URL | Postgres connection string (postgres://…). |
When any persistence backend is set, secret encryption is required (fail-closed):
| Variable | Purpose |
|---|---|
NOODLE_SECRET_MASTER_KEY | Base64 32-byte key (e.g. openssl rand -base64 32); AES-256-GCM, key stays in process memory. |
Control-plane + owner auth (required before exposing off loopback)
- Control-plane deploys: set
NOODLE_GOOGLE_CLIENT_IDto require a Google ID token for deploys (org membership gates them).NOODLE_CONTROL_PLANE_ADMINSis a comma-separated list of immutable canonical principal subjects (plus exact Google workload subjects when those workloads need admin operations). Direct-Google-only deployments temporarily accept admin emails for compatibility, but must replace them with subjects before configuring WorkOS.NOODLE_CONTROL_PLANE_ALLOWED_EMAIL_DOMAINremains signup policy, not authorization. - Owner-only end-user auth, self-hosted authorization server: set
NOODLE_OAUTH_ISSUERplus the Google client credsNOODLE_OAUTH_GOOGLE_CLIENT_ID/NOODLE_OAUTH_GOOGLE_CLIENT_SECRET/NOODLE_OAUTH_GOOGLE_REDIRECT_URI(optionalNOODLE_OAUTH_SIGNING_KEY,NOODLE_OAUTH_ALLOWED_EMAIL_DOMAIN). The service then runs the authorization server (DCR + PKCE, federating human login through the configured upstream) so standard clients can sign in. Direct Google is the compatibility/default upstream. To make WorkOS available behind the same Noodle issuer, configure the complete WorkOS unit below; configuration alone does not change the Google/0% rollout. See ADR 0042. - Owner-only with an external issuer: set
NOODLE_OAUTH_ISSUER+NOODLE_OAUTH_JWKS_URI; the runtime is only the resource server. See ADR 0041.
Optional WorkOS upstream-human unit (all three values or none)
| Variable | Purpose |
|---|---|
NOODLE_OAUTH_WORKOS_CLIENT_ID | AuthKit client for this environment. |
NOODLE_OAUTH_WORKOS_REALM | Stable, environment-specific realm stored in immutable identity links. |
NOODLE_OAUTH_WORKOS_API_KEY | Server API key; inject from a version-pinned secret, never plain config. |
NOODLE_OAUTH_WORKOS_AUTHENTICATION_METHODS | Optional comma-separated allowlist. Defaults to GoogleOAuth,MagicAuth; GitHubOAuth, Password, and SSO require an explicit compatibility release. |
NOODLE_OAUTH_CONSOLE_CLIENT_ID + NOODLE_CONSOLE_URL | Optional stable first-party Console public client and exact Console origin; configure both together. |
Register the exact derived callback <NOODLE_OAUTH_ISSUER>/oauth/workos/callback. A partial unit fails
startup. Keep environments isolated and never log or render these values. Rollout state, identity import, and
rollback are PostgreSQL-backed operator concerns described in the
WorkOS migration runbook; they are not environment variables.
Direct Google control-plane compatibility and workload identity are separate. During migration,
NOODLE_GOOGLE_HUMAN_AUTH_ENABLED=true retains the former; NOODLE_GOOGLE_WORKLOAD_SUBJECTS lists exact
immutable CI/build subjects for the latter. Finalization may set human compatibility to false, but it must
retain the workload list and NOODLE_GOOGLE_CLIENT_ID audience.
Optional billing observation and validation
| Variable | Purpose |
|---|---|
NOODLE_BILLING_USAGE_HMAC_KEY | Stable base64-encoded 32-byte key that enables fail-open shadow observation of admitted connector-backed tools/call dispatches. Omit it to keep metering not_started. |
NOODLE_BILLING_METER_VALIDATION_ENABLED | Explicitly enables the PostgreSQL-only fail-open version 2 validation mirror, durable writer health, and bounded maintenance/reconciliation scheduler. It does not prepare an epoch or activate enforcement. |
NOODLE_BILLING_METER_CPU_ALWAYS_ALLOCATED | Required true assertion whenever validation is enabled. The operator must separately ensure the host really supplies continuous CPU and keeps at least one instance/process running. |
Use a distinct key per environment, and give every service replica in one environment the same value. Generate
one with openssl rand -base64 32. Durable multi-replica reporting requires the shared PostgreSQL backend;
an in-memory observer is process-local and resets on restart. Shadow observations are diagnostics only: this
setting does not enable quota denial, overage, invoice evidence, or production-app enforcement. Changing the
key breaks retry identity continuity, so rotate it only through a coordinated rollout that avoids serving
traffic from old-key and new-key replicas at the same time.
Validation additionally requires the shared PostgreSQL backend and a full lowercase 40-character
NOODLE_BUILD_SHA. Set both validation variables to true only after the process has continuous CPU outside
request handling; an incomplete combination fails service startup. Every replica may run the validation
runtime because PostgreSQL elects one scheduler leader, but at least one replica must remain warm for health
evidence to stay fresh. Prepare and retire the release-bound validation epoch only through the audited CLI/API
procedure in the
authoritative-meter readiness runbook. Customer reads
remain shadow/partial, and validation failure never changes request admission.
A persistent, encrypted, identity-protected self-host therefore looks like:
DATABASE_URL=postgres://user:pw@db.internal:5432/noodle \
NOODLE_SECRET_MASTER_KEY="$(openssl rand -base64 32)" \
NOODLE_OAUTH_ISSUER=https://noodle.example.com \
NOODLE_OAUTH_GOOGLE_CLIENT_ID=… NOODLE_OAUTH_GOOGLE_CLIENT_SECRET=… \
NOODLE_OAUTH_GOOGLE_REDIRECT_URI=https://noodle.example.com/oauth/google/callback \
PUBLIC_BASE_URL=https://noodle.example.com HOST=0.0.0.0 NOODLE_TRUST_PROXY=1 \
node packages/service/dist/main.jsThe Postgres schema is created on first boot. Managed-cloud connector and key-custody adapters are composed outside the public self-host entrypoint; the in-memory path pulls none of them.
3. Anti-rug-pull guarantee — you own your app
Noodle Seed's business is distribution and generation, not lock-in. Concretely:
-
Your
server.tsis yours — and it is the source of truth. It is plain TypeScript using the open-source authoring SDK (bundled in the Apache-2.0@noodleseed/onepackage). It is declarative data in TypeScript syntax, not imperative code:fulfilbodies are symbolically recorded, not executed, and the SDK compiles it to the internal manifest. Keepserver.tsin your own git repository — it is the user-owned, diffable, reviewable, portable artifact, not the hosted deployment. -
The engine is open and free to self-host. The compiler, runtime, protocol/transport, compute sandbox, authoring SDK, and CLI run on your own infrastructure forever (Section 2). The same
server.tsruns unchanged on a self-hosted engine —noodle devand a self-hosted deploy service use the same runtime. -
The eject path is simply: keep
server.tsin version control, run the open-source engine yourself, and point your MCP clients at your own endpoint. No data is trapped behind the managed service. -
Manifest export (quiet fallback).
noodle export manifestcompilesserver.tslocally — no service, no login — and writes a vendor-neutral manifest JSON:noodle export manifest --output manifest.jsonThis is retained as a quiet fallback for users who want the compiled data shape. The foregrounded user-owned artifact is
server.ts; the manifest/runtime-artifact is otherwise an internal intermediate representation that lets one runtime serve many MCP servers and is not a public authoring surface.
Honest limits (today): the manifest schema does not yet carry a formal cross-version compatibility SLA, and commercial governance modules (advanced policy/audit/auth) are separate from the open core. Self-hosting gives you the full open-core engine; it does not bundle those commercial modules. See the open-core module roadmap.