Mosta Net

io.github.apolocine由 GitHub 账号 apolocine 发布v2.0.42更新于 Oct 24, 2026

1 MCP server, 13 databases, zero config. Multi-protocol transport with Auth + RBAC.

概览

AI 生成的概览

通过 MCP 暴露由 schema 驱动的数据 API,为助手提供跨 13 种数据库方言的实体自动生成 CRUD 工具。

可以做什么
Octonet 是一个 Node.js 多传输协议服务器,把同一份 ORM schema 同时以十一种协议暴露,包括 MCP、REST、GraphQL、WebSocket、SSE、JSON-RPC、gRPC、tRPC、OData、NATS 和 Arrow Flight。在 MCP 上,它为每个实体自动生成约 15 个工具,覆盖 CRUD、计数、搜索、聚合、批量与关联操作。它还提供带作用域的多租户 API key 认证、RBAC、多项目路由,以及会从响应中剥离 password、hash、token、secret 等字段的清理中间件。
适用场景
当助手需要读写受支持数据库中的结构化业务数据,并且希望无需为每个实体编写工具代码就能通过 MCP 访问这些数据时,适合使用。也适合已经在使用 @mostajs 技术栈、希望把同一份 schema 在 REST 和 GraphQL 之外同时开放给 AI 代理的团队。
运行要求
以 npm 包(@mostajs/net)形式在本地 Node.js 上运行,通过 npx mostajs-net serve 启动。需要数据库方言与连接 URI(DB_DIALECT、SGBD_URI),首次启动还需要管理员引导凭据(OCTONET_ADMIN_EMAIL、OCTONET_ADMIN_PASSWORD)。客户端通过 X-API-Key 请求头、Bearer token 或 apikey 查询参数进行认证。文档还描述了托管端点 octonet.amia.fr/mcp。
安装前请注意
该服务器会写入你的数据库:MCP 工具包含 create、update、delete、upsert、updateMany 和 deleteMany,助手可以修改或删除记录。它涉及 DB_DIALECT、SGBD_URI、OCTONET_ADMIN_PASSWORD 和 API key 等凭据;README 说明在未提供密钥时 /mcp 会接受标记为 public-default 的公共回退密钥,并称其仅对 default 项目只读。管理路由可在运行时更改数据库方言与连接。沙箱密钥会过期且有配额限制。

安装

在 SourceWeft 中

  1. 打开 控制台中的 Mosta Net,将其添加到工作区。
  2. 为需要使用其工具的对话启用该服务。

Desktop only,通过 STDIO。 STDIO 服务会启动本地进程,因此需要 SourceWeft 桌面宿主。

其他 MCP 客户端

参照 仓库 中的启动说明。

README

@mostajs/net — Octonet

One schema, 11 transports, 13 databases, multi-tenant auth — out of the box. Schema-driven multi-protocol API server for the @mostajs ecosystem. Built with TypeScript on Fastify, designed for polyglot consumption (14 native NetClients).

[Octonet Logo]

[npm] [License] [mcp.so]

Author : Dr Hamid MADANI <[email protected]> Homepage : octonet.amia.fr · mcp.amia.fr


[Octonet stack as electrical sockets: @mostajs/orm plugs into 13 databases, @mostajs/net (Octonet) re-exposes them over 11 transports, Data-Plug bridges them, and NetClient fans out to 18 language clients consumed by any external app.]

The socket board. @mostajs/orm connects to 13 databases; Octonet (@mostajs/net) re-exposes the same entities over 11 transports (REST, WebSocket, gRPC, MQTT, AMQP…); NetClient then fans out to 18 language clients — so any external app plugs into your data, in any runtime.


Table of Contents

  1. What is Octonet
  2. Try in 2 clicks (T1 sandbox)
  3. 3-tier onboarding model
  4. 11 transports
  5. 13 databases
  6. Multi-tenant authentication
  7. Generic scope registry
  8. Multi-project support
  9. Quick start (self-host)
  10. Configuration (.env)
  11. API endpoints reference
  12. Architecture
  13. Boot sequence
  14. 14 polyglot NetClients
  15. Production deploy (amia.fr)
  16. License

What is Octonet

Octonet (@mostajs/net) is a Node.js multi-transport server that exposes a single @mostajs/orm schema as 11 different network protocols simultaneously : REST, GraphQL, WebSocket, SSE, JSON-RPC, MCP, gRPC, tRPC, OData, NATS, Arrow Flight.

The same User entity is reachable as :

bash
curl https://octonet.amia.fr/api/v1/User              # RESTcurl https://octonet.amia.fr/graphql -d '{"query":...}'  # GraphQLwscat -c wss://octonet.amia.fr/ws                     # WebSocketcurl -N https://octonet.amia.fr/mcp                   # MCP (Claude Desktop)# … 7 more

Backed by @mostajs/orm (13 SGBD dialects). Backed by @mostajs/rbac + @mostajs/auth + @mostajs/api-keys for multi-tenant identity. Backed by @mostajs/mproject for multi-project routing.

Octonet is the second cerebral lobe of the @mostajs trilogy :

  • #1 — @mostajs/orm : data persistence (13 databases)
  • #2 — Octonet : multi-protocol transport (11 wire protocols)
  • #3 — NetClients polyglottes : 14 native client libraries (Java, .NET, Python, Go, Swift, Kotlin, Dart, Rust, PHP, Ruby, Elixir, Lua, Delphi, Unity)

Try in 2 clicks (T1 sandbox)

The fastest way to test Octonet from any of the 14 runtimes :

  1. Open https://octonet.amia.fr/try
  2. Pick an alias (e.g. alice-42)
  3. Get an apikey scoped to your sandbox
bash
curl -X POST https://octonet.amia.fr/try \  -H "Content-Type: application/json" \  -d '{"alias":"alice-42"}'
# Response:{  "status": "ok",  "data": {    "alias": "alice-42",    "projectSlug": "sandbox-alice-42",    "apiKey": "sk_test_…(64 chars, shown ONCE)",    "permissions": { "projects":["sandbox-alice-42"], "operations":["read","write"], "transports":["rest","mcp"] },    "expiresAt": "2026-05-02T18:38:19.920Z",    "quota": { "reqPerDay": 500 },    "exampleCurl": "curl https://octonet.amia.fr/api/v1/sandbox-alice-42/User -H \"X-API-Key: sk_test_…\"",    "mcpUrl": "https://octonet.amia.fr/mcp"  }}

Your sandbox is :

  • A private SQLite file (isolated from other aliases)
  • Pre-seeded with User, Product, Order entities
  • Read+write CRUD via REST and MCP
  • 500 requests/day quota
  • TTL 7 days (auto-deleted if idle)
  • Free, no email required, anti-abuse rate-limited (10 sandboxes/h/IP)

Use the apikey in any of the 14 NetClients :

bash
# Java / .NET / Python / Go / etc.export MOSTAJS_NET_URL=https://octonet.amia.frexport MOSTAJS_NET_API_KEY=sk_test_…

3-tier onboarding model

TierCibleAuthQuotaUse case
T1 — Sandbox publique /try"I want to test in 10 minutes"alias seul (pas d'email)500 req/jour, TTL 7jdémo NetClients, intégration tests
T2 — Compte enregistré octocloud.amia.fr"j'utilise vraiment, gratuit"email + mot de passe10 000 req/jourapps personnelles, side-projects
T3 — Self-host npx @mostajs/net init"tes données chez toi"admin localaucuneenterprise, on-premise, AGPL

11 transports

Auto-generated from your registered schemas. Toggle each via env var (default : all enabled).

#TransportEndpointUse caseNotes
1REST/api/v1/{Entity} · /api/v1/{project}/{Entity}universel15 routes par entité (CRUD + count + search + aggregate + bulk + relations)
2GraphQL/graphql (POST)front-end richesschéma + GraphiQL IDE auto-générés via mercurius
3WebSocketwss://…/wstemps réelevents entity.created/updated/deleted/upserted broadcast
4SSE/events (GET stream)mobile / browser-friendlyserver-sent events
5JSON-RPC/rpc (POST)EVM-adjacent, classicJSON-RPC 2.0 + method discovery
6MCP/mcp (POST/GET SSE)agents IA (Claude, ChatGPT)15 tools/entité auto-générés (listed on mcp.so)
7gRPC:50051inter-services low-latency.proto auto-généré, 6 RPCs/entité
8tRPC/trpc/{Entity}.{op}TypeScript fullstacktype generation côté client
9OData/odata/{Collection} (+ $metadata)SAP/Microsoft DynamicsOData v4 ($filter, $select, $orderby)
10NATSmostajs.{Entity}.{op}pub/sub edgerequest-reply messaging
11Arrow Flight/arrow/*analytics columnairestreaming zero-copy

Le même schéma, 11 portes d'entrée différentes, 0 codegen.


13 databases

Persistence dialects fournis par @mostajs/orm :

CatégorieBasesDialect ID
SQL mainstreamPostgreSQL, MySQL, MariaDB, SQLitepostgres, mysql, mariadb, sqlite
SQL enterpriseOracle, SQL Server, DB2, SAP HANA, HSQLDB, Sybaseoracle, mssql, db2, hana, hsqldb, sybase
NewSQL / CloudCockroachDB, Google Cloud Spannercockroachdb, spanner
NoSQLMongoDBmongodb

Switch dialect = changer 1 ligne d'env :

bash
DB_DIALECT=postgres → DB_DIALECT=mongodbSGBD_URI=postgresql://… → SGBD_URI=mongodb://…

Multi-tenant authentication

Octonet utilise un middleware d'authentification basé sur API keys avec scopes (orienté machine-to-machine) + RBAC pour la gestion humaine. L'orchestrateur agnostique vit dans @mostajs/auth/lib/check-request.ts.

Flux d'auth d'une requête

HTTP Request  │  ▼authGuard (Fastify adapter)  │  ▼checkRequest (@mostajs/auth — framework-agnostic)  │  ├─ extract X-API-Key from header / Bearer token / ?apikey=  ├─ resolveApiKey (@mostajs/api-keys) — DB lookup + bcrypt verify  ├─ isScopeAuthorized (@mostajs/api-keys) — check scope.values  │     for each (scope, value) pair :  │       checks: [{scope:'projects', value:slug},  │                {scope:'operations', value:'read'|'write'|'admin'},  │                {scope:'transports', value:'rest'|'mcp'|...}]  ├─ touchApiKey — fire-and-forget : lastUsedAt, usageCount, lastIp  │  ▼ormHandler (entité CRUD) ─→ sanitizer (strip password/hash/tokens)  │  ▼HTTP Response

Scope-based permissions (generic, extensible)

Une apikey a la shape :

ts
{  permissions: {    scopes: {      projects:   ['my-project','demo'] | '*',     // declared by @mostajs/mproject      operations: ['read','write','admin'] | '*',  // declared by @mostajs/orm      transports: ['rest','graphql','mcp'] | '*',  // declared by @mostajs/net      // anything: any module can register a new scope    },    rateLimit: 500,  }}

@mostajs/api-keys ne connaît PAS les noms projects/operations/transports — c'est volontaire. Chaque module enregistre ses scopes au boot via registerScope(dialect, {name, label, …}). Le check est générique : isScopeAuthorized(perms, scope, value).

HTTP status mapping

CasHTTP codeBody
Pas d'apikey401{error: {code:'UNAUTHORIZED', message:'API key required…'}}
Apikey invalide / révoquée401{error: {code:'UNAUTHORIZED', message:'Invalid or revoked API key'}}
Apikey valide hors scope403{error: {code:'FORBIDDEN', message:'API key not authorized for X="Y"'}}
Apikey OK200/201{status:'ok', data: …} (sanitized — no password/hash)

MCP fallback (compat mcp.so)

L'endpoint /mcp autorise un fallback automatique sur l'apikey labelée public-default quand aucune clé n'est présentée — préserve la compat avec mcp.so / Claude Desktop. La clé publique est read-only sur le projet default uniquement → écritures bloquées.

Sanitizer

Les champs password, hash, verifyToken, resetToken, apiKeyHash, secret, privateKey sont automatiquement strippés de toutes les réponses JSON par un middleware global. Aucun risque de leak à travers /api/v1/User?limit=1.


Generic scope registry

Le catalogue des scopes vit en base de données du projet accueillant (pas de fichier JSON, pas de constantes hardcodées) :

sql
-- Auto-créées au boot via @mostajs/api-keysCREATE TABLE api_key_scopes (  id, name, label, description, icon, cardinality,  valuesSource ('static' | 'dynamic'), dynamicSourceRef);
CREATE TABLE api_key_scope_values (  id, scopeName, value, label, sortOrder, metadata);

Chaque module enregistre ses scopes au boot :

ts
import { registerScope } from '@mostajs/api-keys/server'
// Dans mosta-net/src/server.ts (boot)await registerScope(dialect, {  name: 'transports', label: 'Network transports',  cardinality: 'low', valuesSource: 'static',  staticValues: [    {value:'rest', sortOrder:1},    {value:'graphql', sortOrder:2},    // … 9 more  ],})
await registerScope(dialect, {  name: 'projects', label: 'Projects',  cardinality: 'high', valuesSource: 'dynamic',  dynamicSourceRef: 'Project.slug',  // queried at runtime})

L'admin UI charge le catalogue dynamique via GET /api/api-keys/scopes et rend une matrice (composant React ApiKeyScopeMatrix dans @mostajs/api-keys/components/).


Multi-project support

Via @mostajs/mproject — N bases de données isolées sur le même serveur.

Routes path-prefix

bash
# Default project (DB_DIALECT + SGBD_URI au boot)curl http://localhost:4488/api/v1/User
# Project nommé 'analytics'curl http://localhost:4488/api/v1/analytics/events
# Ou via header (équivalent)curl http://localhost:4488/api/v1/events -H "X-Project: analytics"

Ajouter un projet à l'exécution

bash
curl -X POST http://localhost:4488/api/projects \  -H "X-API-Key: <admin-key>" \  -d '{    "name": "analytics",    "dialect": "mongodb",    "uri": "mongodb://localhost:27017/analytics",    "schemas": [{"name":"Event", "fields":{"type":"string","ts":"date"}}]  }'

Persisté dans projects-tree.json (chemin : MOSTA_PROJECTS env var).


Quick start (self-host)

Install

bash
npm install @mostajs/net @mostajs/orm @mostajs/mproject \            @mostajs/rbac @mostajs/auth @mostajs/api-keys \            @mostajs/config better-sqlite3

Run with SQLite (zero infra)

bash
DB_DIALECT=sqlite \SGBD_URI=./data/octonet.db \DB_SCHEMA_STRATEGY=update \[email protected] \OCTONET_ADMIN_PASSWORD=ChangeMe123! \npx mostajs-net serve

Console output :

Loaded 3 schemas from schemas.json[DAL:SQLite] INIT_SCHEMA strategy=update {"entities":["User","Product","Order"]}✓ Apikey scopes registered (projects, operations, transports)✓ RBAC ready — [email protected] trial=…  public=…⚠ public demo apikey emitted ONCE → sk_live_xxxxxxxx…  (save it!)✓ Sanitizer middleware on rest, graphql, ws, sse, trpc, mcp, odata, jsonrpc✓ ApiKey middleware on rest, graphql, ws, sse, trpc, mcp, odata, jsonrpc✓ Protected ormHandler ready (sanitizer + apikey global wrapper)✓ T1 sandbox endpoint /try ready (rate-limited 10/h/IP, TTL 7d)
  @mostajs/net  v2.6.x  ─────────────────────────────────────────────────  Dialect:    sqlite (./data/octonet.db)  Entities:   User, Product, Order  (3)  Port:       4488  Strategy:   update  Transports: rest, graphql, ws, sse, trpc, mcp, odata, jsonrpc  (8)  Ready.  3 entities × 8 transports = 24 endpoints

Test

bash
# Sans apikey → 401curl http://localhost:4488/api/v1/User# {"error":{"code":"UNAUTHORIZED","message":"API key required…"}}
# Avec apikey publique (depuis les logs ↑)curl http://localhost:4488/api/v1/User -H "X-API-Key: sk_live_…"# {"status":"ok","data":[{"id":"…","email":"[email protected]",…}]}  ← password absent

Configuration (.env)

Database (mandatory)

bash
DB_DIALECT=postgres                                # any of 13 dialectsSGBD_URI=postgresql://user:pass@localhost:5432/dbDB_SCHEMA_STRATEGY=update                          # 'update' (recommandé prod) | 'create' (drop+recreate, dev only)DB_SHOW_SQL=false

System dialect (recommandé prod, optionnel) — v2.7.5+

Sépare la base système (apikeys, RBAC users, audit, plans, payments, project-life metadata) du dialect métier mutable. Sans ces variables, alias transparent vers le singleton métier (rétro-compat mono-base).

bash
MOSTA_SYSTEM_DIALECT=postgres                       # any of 13 dialectsMOSTA_SYSTEM_URI=postgresql://user:pass@localhost:5432/octonet_system

Voir section System dialect ci-dessous pour la motivation et les how-to.

Server

bash
MOSTA_NET_PORT=4488MOSTA_PROJECTS=./projects-tree.json                # path to multi-project configSCHEMAS_PATH=./schemas                              # directory scanning fallback

Transports (toggle each)

bash
MOSTA_NET_REST_ENABLED=trueMOSTA_NET_GRAPHQL_ENABLED=trueMOSTA_NET_WS_ENABLED=trueMOSTA_NET_SSE_ENABLED=trueMOSTA_NET_JSONRPC_ENABLED=trueMOSTA_NET_MCP_ENABLED=trueMOSTA_NET_TRPC_ENABLED=trueMOSTA_NET_ODATA_ENABLED=trueMOSTA_NET_GRPC_ENABLED=falseMOSTA_NET_NATS_ENABLED=falseMOSTA_NET_ARROW_ENABLED=false
MOSTA_NET_CORS_ORIGIN=*MOSTA_RATE_LIMIT_CLIENT=1000

RBAC bootstrap (lus via @mostajs/config — supports profile cascade MOSTA_ENV=DEV)

bash
[email protected]               # 1er boot only ; ignored afterOCTONET_ADMIN_PASSWORD=secret-12345OCTONET_ADMIN_FIRSTNAME=Admin                       # optionalOCTONET_ADMIN_LASTNAME=Octonet                      # optionalOCTONET_BOOTSTRAP_VERBOSE=false                     # detailed bootstrap logsOCTONET_OPEN_MODE=false                             # dev only — passe sans apikey

T1 sandbox (optional)

bash
OCTONET_TRIAL_DATA_DIR=./data/trials                # SQLite files per alias

Cloud middleware (optional, futur — partage DB méta avec Octocloud)

bash
OCTONET_META_URI=postgresql://user:pass@localhost:5432/octonet_meta   # shared meta DBPORTAL_DB_URI=postgresql://user:pass@localhost:5432/octonet_cloud     # legacy octocloud DB

API endpoints reference

Public

EndpointMéthodeAuthDescription
/healthGETopenserver status + transports + entities
/tryGETopenT1 sandbox provisioning HTML form
/tryPOSTopen (rate-limit 10/h/IP)crée sandbox + retourne apikey one-shot
/api/v1/healthGETopenhealth under api-versioned path

Project / entity CRUD (requires apikey)

EndpointMéthodeOpDescription
/api/v1/{Entity}GETfindAlllist entities of default project
/api/v1/{Entity}/:idGETfindByIdget one
/api/v1/{Entity}/countGETcountcount
/api/v1/{Entity}/oneGETfindOnefirst match
/api/v1/{Entity}/searchGETsearchtext search
/api/v1/{Entity}POSTcreateinsert
/api/v1/{Entity}/:idPUTupdatereplace
/api/v1/{Entity}/:idDELETEdeleteremove
/api/v1/{Entity}/:id/addToSetPOSTaddToSetadd to array
/api/v1/{Entity}/:id/pullPOSTpullremove from array
/api/v1/{Entity}/:id/incrementPOSTincrementnumeric add
/api/v1/{Entity}/upsertPOSTupsertinsert or update
/api/v1/{Entity}/aggregatePOSTaggregatepipeline
/api/v1/{Entity}/updateManyPOSTupdateManybulk update
/api/v1/{Entity}/deleteManyPOSTdeleteManybulk delete
/api/v1/{project}/{Entity}/…**same routes scoped to a project

Schema management (requires admin apikey)

EndpointMéthodeDescription
/api/upload-schemas-jsonPOSTpush schemas at runtime (triggers reload)
/api/apply-schemaPOSTapply schema diff
/api/compare-schemaPOSTdry-run schema diff
/api/schemas-configGETcurrent registered schemas

Auth & API keys (requires admin)

EndpointMéthodeDescription
/api/api-keysGET / POSTlist / issue keys
/api/api-keys/:idPUT / DELETEupdate / revoke
/api/api-keys/scopesGETlist registered scopes + values (for admin matrix UI)
/api/api-keys/scopesPOSTregister a new scope (admin)
/api/api-keys/scopes/:name/valuesPUT / DELETEmanage scope values

Transports natifs

EndpointDescription
/graphqlGraphQL endpoint + GraphiQL IDE
/wsWebSocket connection (entity events)
/eventsSSE stream
/rpcJSON-RPC 2.0
/mcpModel Context Protocol (Claude/Smithery/etc.)
/trpc/{Entity}.{op}tRPC procedure
/odata/{Collection} · /odata/$metadataOData v4

Multi-project management

EndpointMéthodeDescription
/api/projectsGETlist projects
/api/projectsPOSTadd project
/api/projects/:namePUT / DELETEedit / remove

Observability

EndpointDescription
/api/performancelive metrics (req/s, p50, p99)
/api/config-treeconfiguration tree (interactive)
/api/live-logstreaming log feed

Architecture

                                 ┌──────────────────────────────────┐                                 │       Fastify (port 4488)        │                                 └────────────────┬─────────────────┘                                                  │       ┌─────────────────────────────────────────┴──────────────────────────────┐       │                                                                        │       ▼                                                                        ▼┌────────────────────────┐                                       ┌────────────────────────┐│  Transports (11)       │                                       │  Direct Fastify routes ││  - REST                │                                       │  - /try                ││  - GraphQL (mercurius) │                                       │  - /api/projects/*     ││  - WS                  │                                       │  - /api/api-keys/*     ││  - SSE                 │                                       │  - /health, /metrics   ││  - JSON-RPC            │                                       └────────────────────────┘│  - MCP (SDK Anthropic) ││  - gRPC                │              ┌─────────────────────────────────────┐│  - tRPC                │              │  Auth pipeline                      ││  - OData               │              │  ┌──────────────┐                   ││  - NATS                │              │  │ extractAuth  │ ←  HTTP request   ││  - Arrow               ├──────────────┤  │ Context      │                   │└────────────────────────┘              │  └──────┬───────┘                   │                                        │         ▼                           │                                        │  ┌──────────────┐                   │                                        │  │ checkRequest │ ←  scope-checks   │                                        │  │ (mosta-auth) │                   │                                        │  └──────┬───────┘                   │                                        │         ▼                           │                                        │  ┌──────────────┐                   │                                        │  │ checkApiKey  │ ←  resolve+verify │                                        │  │ (api-keys)   │                   │                                        │  └──────┬───────┘                   │                                        └─────────┼───────────────────────────┘                                                  ▼                                        ┌────────────────────────┐                                        │ Sanitizer middleware   │                                        │ strips password/hash/  │                                        │ tokens before response │                                        └────────┬───────────────┘                                                 ▼                                        ┌────────────────────────┐                                        │ ormHandler             │                                        │ → ProjectManager.resolve│                                        │ → EntityService.execute │                                        └────────┬───────────────┘                                                 ▼                                        ┌────────────────────────┐                                        │ @mostajs/orm dialect   │                                        │ (13 SGBD)              │                                        └────────────────────────┘

Modules de l'écosystème consommés

ModuleRôle dans Octonet
@mostajs/ormpersistance (13 dialects)
@mostajs/mprojectgestion multi-projet (default + sandbox + abonnés)
@mostajs/rbacidentité (User, Role, Permission, Account) + AccountSchema + OCTONET_RBAC_SEED
@mostajs/authcheckRequest orchestrateur framework-agnostic, hashPassword
@mostajs/api-keysapikey CRUD + scopes (Scope/ScopeValue schemas) + checkApiKey + ApiKeyScopeMatrix admin UI
@mostajs/configenv var helper avec cascade MOSTA_ENV
@mostajs/cloud-middlewarequota / abonnement (optionnel — actif si Octocloud connecté)
@mostajs/replicatorCQRS multi-replica (optionnel)
@mostajs/project-lifepersistence schemas Project (optionnel — si stockage SGBD vs JSON)

System dialect (séparé du singleton métier)

Disponible depuis v2.7.5 — résout le bug « apikeys introuvables après /api/change-dialect » observé en prod.

Pourquoi deux dialects distincts ?

Octonet expose des routes admin qui mutent la connexion DB au runtime (/api/change-dialect, /api/reload-config, /api/reconnect) — légitime côté métier (les entités userland du projet courant peuvent migrer postgres → sqlite → mongodb selon les besoins de l'admin).

Mais les modules système (apikeys, RBAC users, audit, plans de souscription, payments, project-life metadata) doivent vivre dans une base stable qui ne suit pas ces mutations. Sinon : un changement de dialect métier rend les apikeys introuvables, l'admin se trouve verrouillé hors de l'IHM.

RôleVariable envMutable au runtime ?Lu par
Métier (entités userland)DB_DIALECT + SGBD_URIOui (IHM admin)EntityService, transports, routes data
Système (infra Octonet)MOSTA_SYSTEM_DIALECT + MOSTA_SYSTEM_URINon (stable)RBAC, apikey-middleware, account-scope, auth guards, sandbox /try

Configuration recommandée (prod multi-base)

bash
# Métier — peut bouger via /api/change-dialectDB_DIALECT=postgresSGBD_URI=postgresql://hmd:***@127.0.0.1:5432/octonet_business
# Système — stable, jamais touché par les routes adminMOSTA_SYSTEM_DIALECT=postgresMOSTA_SYSTEM_URI=postgresql://hmd:***@127.0.0.1:5432/octonet_system

Configuration mono-base (dev / déploiement simple)

Laisser MOSTA_SYSTEM_* vides → alias automatique vers le singleton métier (rétro-compat 100 %, comportement identique au pré-v2.7.5).

How-to

1. Migrer un déploiement existant vers le mode multi-base
bash
# 1. Sauvegarder la base actuellepg_dump octonet_business > backup-pre-split.sql
# 2. Créer la base système (vide — RBAC seed re-exécute au boot)createdb octonet_system
# 3. Ajouter MOSTA_SYSTEM_* dans .envecho 'MOSTA_SYSTEM_DIALECT=postgres' >> .env.localecho 'MOSTA_SYSTEM_URI=postgresql://hmd:***@127.0.0.1:5432/octonet_system' >> .env.local
# 4. Restart Octonet — le bootstrap RBAC + scopes seed sur octonet_systempm2 restart octonet-mcp
# 5. Restaurer les apikeys et RBAC users de l'ancienne base#    (à scripter selon convention métier — typiquement export/import des#    tables api_keys, users, roles, permissions, scopes, scope_values)
2. Vérifier que le système est bien isolé du métier
bash
# Avant /api/change-dialect : apikey doit fonctionnercurl -H "X-API-Key: sk_live_…" http://localhost:4488/api/auth/verify# → 200 OK
# Bouger le dialect métier vers SQLitecurl -X POST -H "Content-Type: application/json" \  -d '{"dialect":"sqlite","uri":":memory:","connect":true}' \  http://localhost:4488/api/change-dialect# → "Dialecte changé et connecté : sqlite"
# Re-tester l'apikey — DOIT toujours fonctionner (système intact)curl -H "X-API-Key: sk_live_…" http://localhost:4488/api/auth/verify# → 200 OK (bug résolu en v2.7.5)

Avant v2.7.5, le 2ᵉ curl retournait 503 metadata DB unavailable ou 401 PostgreSQL not connected. Call connect() first.

3. Lire le system dialect depuis du code applicatif
ts
import { getSystemDialect } from '@mostajs/data-plug'
const sysDialect = await getSystemDialect()// Utiliser comme un dialect normal pour requêter les tables système// (apikeys, users, roles, audit_log, plans, etc.)
4. Inspecter le bootstrap au démarrage

Au boot d'octonet-mcp, deux logs apparaissent :

✓ DB connectée: postgres                            ← métier✓ System dialect: postgres (octonet_system)         ← système (si MOSTA_SYSTEM_* défini)✓ RBAC ready — admin=… trial=… public=…             ← seed côté système✓ ApiKey middleware on REST/SSE/GraphQL/...         ← câblé sur système

Sites système dans src/server.ts (pour référence)

18 callers tirent désormais leur dialect via getSystemDialect() au lieu du singleton métier :

BlocSitesCaller
RBAC bootstrap1bootstrapRbac(systemDialect, …)
Scopes register4registerScope(systemDialect, …) × 3 + systemDialect.initSchema(scopeTables)
Middlewares globaux2createApiKeyMiddleware(() => systemDialect, …) + createAccountScopeMiddleware(() => systemDialect)
Middlewares per-transport2idem appliqués sur chaque transport.use(…)
Auth guards transports6authGuard(systemDialect, …) × 6 (SSE, GraphQL, JSON-RPC, gRPC, tRPC, OData)
Custom /api/auth/verify2checkApiKey(systemDialect, …) + new UserRepository(systemDialect)
Sandbox /try2registerTryRoutes({ dialect: systemDialect, … }) + startTrialCleanupJob({ dialect: systemDialect, … })

Le dialect métier (dialect) reste utilisé légitimement pour :

  • Bootstrap initial du singleton métier (L98) + pm.setDefault('default', dialect, …) (L126, L240)
  • Routes admin /api/reconnect, /api/change-dialect, /api/reload-config, /api/test-connection, /api/truncate-tables, /api/drop-tables — toutes opérations explicitement métier
  • EntityService qui sert les entités userland (opérations CRUD via les transports protégés)

Étapes du chantier (historique)

ÉtapeRepoLivré
1@mostajs/data-plug v1.2.2-1.2.4 (API getSystemDialect + façade ORM)npm
2@mostajs/net v2.7.5 (bootstrapSystemDialect au démarrage)git
3@mostajs/api-keys 0.2.3, @mostajs/payment 0.4.1, @mostajs/project-life 0.1.3, @mostajs/subscriptions-plan 0.3.5 (WeakMap repos + façade)npm
4@mostajs/net v2.7.5 (consumers basculent sur getSystemDialect() — 18 sites)git
5Tests d'intégration scénario /api/change-dialect postgres → sqlite⏳
6Déploiement amia + smoke test MOSTA_SYSTEM_URI⏳

Boot sequence

  1. Load .env via @mostajs/config (profile cascade MOSTA_ENV)
  2. Connect main dialect (SGBD_URI)
  3. Load schemas (priority : getAllSchemas() registry → schemas.json → SCHEMAS_PATH directory scan)
  4. dialect.initSchema(schemas) with strategy update/create
  5. Bootstrap RBAC (octonet-rbac-bootstrap.ts) :
    • register UserSchema/RoleSchema/PermissionSchema/PermissionCategorySchema/AccountSchema/ApiKeySchema
    • seedRBAC(OCTONET_RBAC_SEED) — 6 categories, 25 permissions, 4 roles (admin/subscriber/trial/public)
    • createAdmin() from OCTONET_ADMIN_EMAIL/PASSWORD
    • create Account trial-playground (type='trial')
    • create User public-demo (role=public)
    • create Account public-system (type='system')
    • generate ApiKey public-default scoped to default project (read-only, REST + MCP) — emitted ONCE in clear
  6. Register canonical scopes : projects (dynamic, Project.slug), operations (static : read/write/admin), transports (static : 11 values)
  7. Push default project to projects-tree.json (ownerId=admin, visibility=public)
  8. Load additional projects from projects-tree.json
  9. Wrap ormHandler with composeMiddleware([sanitizer, apikey], ormHandler) → protectedOrmHandler
  10. Start each enabled transport :
    • transport.use(loggingMiddleware)
    • transport.use(sanitizerMiddleware)
    • transport.use(apiKeyMiddleware)
    • transport.setHandler(ormHandler)
    • transport.start(config)
  11. Register Fastify routes :
    • registerDynamicRestRoutes(app, protectedOrmHandler, pm) — /api/v1/...
    • registerProjectRoutes(app, pm, protectedOrmHandler) — /:project/*
    • registerTryRoutes(app, {dialect, pm}) — /try POST
    • registerTryPage(app) — /try GET (HTML)
    • startTrialCleanupJob({dialect, pm}) — cron horaire TTL 7j
  12. Listen on port (MOSTA_NET_PORT)

14 polyglot NetClients

Octonet est consommable depuis 14 runtimes natifs, avec la même apikey, la même URL :

RuntimePackageRegistre
Node/TS@mostajs/net/client (built-in)npm
Javacom.mostajs:mostajs-net-clientMaven Central
Java + Spring Bootcom.mostajs:mostajs-net-client-spring-boot-starterMaven Central
.NETMostaJs.Net.ClientNuGet
Pythonmostajs-net-clientPyPI
Gogithub.com/apolocine/mosta-net-client-gopkg.go.dev
Swiftmosta-net-client-swiftSwift Package Index
Kotlinio.github.apolocine:mostajs-net-client-ktMaven Central
Dart / Fluttermostajs_net_clientpub.dev
Rustmostajs-net-clientcrates.io
PHPmostajs/net-clientPackagist
Rubymostajs-net-clientRubyGems
Elixirmostajs_net_clientHex.pm
Luamostajs-net-clientLuaRocks
DelphiMostaJsNetClientGetIt
Unity (C#)com.mostajs.net-clientOpenUPM

Monorepo : github.com/apolocine/mosta-net-clients

Chaque NetClient suit le même contrat d'API :

NetClient.create()  .url(...)  .apiKey(...)  .build()  .findAll(entity, filter, options)  .findById(entity, id)  .create(entity, data)  .update(entity, id, data)  .delete(entity, id)  .uploadSchemasJson(schemas)  .health()

Production deploy (amia.fr)

Le déploiement de référence tourne sur octonet.amia.fr + mcp.amia.fr (alias compat) en backend PostgreSQL :

URLRôle
https://octonet.amia.frOctonet server (REST, MCP, GraphQL, WS, SSE, tRPC, OData, JSON-RPC)
https://mcp.amia.fralias DNS de compatibilité — historique mcp.so
https://octocloud.amia.frOctocloud — portail SaaS Next.js (subscriptions, admin UI)

Le kit de déploiement complet est dans Entreprise/octonet-mcp/ :

  • apache/mcp.amia.fr.conf — vhost Apache2 (proxy SSE, WS upgrade, certs Let's Encrypt SAN)
  • ecosystem.config.cjs — config PM2
  • deploy.sh / install.sh / update.sh — scripts d'orchestration
  • tests/smoke-all.sh — suite de smoke tests (DNS, TLS, /health, SSE MCP, REST, /try, NetClient Java)

CLI

bash
npx mostajs-net serve                      # Start servernpx mostajs-net mcp                        # MCP-only modenpx mostajs-net generate-apikey <label>    # Émettre une apikey via CLInpx mostajs-net hash-password <password>   # Hash bcryptnpx mostajs-net info                       # JSON config dump
npx octonet-mcp --dialect=X --uri=Y        # Standalone MCP server (process séparé)

License

AGPL-3.0-or-later — usage libre tant que le code dérivé reste open-source. Licence commerciale disponible : [email protected]. Pricing par projet, pas par seat.

— (c) 2026 Dr Hamid MADANI <[email protected]>

来源:README.md,提交 2ba3569

工具

0
SourceWeft 尚未在沙箱中启动过该软件包,因此其工具未知。

版本历史

1
  1. v2.0.42最新Sep 16, 2026

评分

已满足适用检查项的 40%

该评分衡量此收录条目的完整程度,依据注册中心条目、端点与公开来源计算得出。它不是对服务器本身的评价,也不表示服务器安全或当前可用:可连通性是带日期的检查结果,评分也不包含安装量或用户评价。

  • 近 30 天内可连通25 分

    请保持端点能够响应 MCP 握手;SourceWeft 每 30 天探测一次。

  • 已声明认证方式10 分

    请在注册中心条目中声明凭据请求头,或保持端点能够响应探测,以便判定其认证方式。

  • 已列出工具15 分

    请让服务器在无凭据时响应 tools/list,或发布可在沙箱中无凭据启动的软件包。

  • 描述必需15 分
  • 图标10 分
  • 文档15 分
  • 许可证10 分

    请在仓库或注册中心条目中声明许可证。