关于 Octonet Mcp
Octonet 是 Node.js 服务端,可将同一 ORM 模式通过 11 种网络协议开放,供使用 13 种数据库的应用和 AI Agent 接入。它集成多租户 API 密钥认证与 RBAC,并自动生成接口,包括 MCP。
主要功能
- 01同一模式支持 11 种协议
- 02支持 13 种数据库
- 03自动生成 CRUD 与查询工具
- 04多租户 API 密钥与 RBAC
- 05多项目数据库路由
适用场景
- 01通过 MCP 向 AI Agent 开放数据库实体
- 02通过 REST 和 GraphQL 提供相同数据
- 03将不同项目路由至隔离数据库
MCP 相关
Octonet 通过 MCP 端点开放根据模式生成的实体工具。API 密钥权限范围可按项目、操作和传输协议限制访问;公共密钥回退仅支持读取。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
45收录的工具列表 · 更新于 2 周前
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| filter | string | 否 | JSON 筛选对象(MongoDB 风格) |
| limit | number | 否 | 返回结果的最大数量 |
| skip | number | 否 | 要跳过的结果数 |
| sort | string | 否 | JSON 排序对象,例如 {"name":1} |
详细介绍
@mostajs/net — Octonet
开箱即用:一种架构、11 种传输方式、13 个数据库、多租户身份验证。 面向 @mostajs 生态系统、由架构驱动的多协议 API 服务端。基于 TypeScript 和 Fastify 构建,支持多语言调用(14 个原生 NetClient)。
作者:Dr Hamid MADANI <[email protected]> 主页:octonet.amia.fr · mcp.amia.fr
插座板。
@mostajs/orm连接到 13 个数据库;Octonet (@mostajs/net)通过 11 种传输方式(REST、 WebSocket、gRPC、MQTT、AMQP……)重新提供相同的实体;随后 NetClient 扩展为 18 种语言的 客户端——让任何外部应用都能在任意运行时接入你的数据。
目录
- 什么是 Octonet
- 两步体验(T1 沙盒)
- 三级入门模式
- 11 种传输方式
- 13 个数据库
- 多租户身份验证
- 通用范围注册表
- 多项目支持
- 快速开始(自托管)
- 配置(.env)
- API 端点参考
- 架构
- 启动顺序
- 14 个多语言 NetClient
- 生产环境部署(amia.fr)
- 许可证
什么是 Octonet
Octonet(@mostajs/net)是一个 Node.js 多传输服务端,可将单个 @mostajs/orm 架构同时公开为 11 种不同的网络协议:REST、GraphQL、WebSocket、SSE、JSON-RPC、MCP、gRPC、tRPC、OData、NATS、Arrow Flight。
同一个 User 实体可通过以下方式访问:
curl https://octonet.amia.fr/api/v1/User # REST
curl https://octonet.amia.fr/graphql -d '{"query":...}' # GraphQL
wscat -c wss://octonet.amia.fr/ws # WebSocket
curl -N https://octonet.amia.fr/mcp # MCP (Claude Desktop)
# … 7 more
底层由 @mostajs/orm 提供支持(支持 13 种数据库方言)。多租户身份由 @mostajs/rbac + @mostajs/auth + @mostajs/api-keys 提供支持。多项目路由由 @mostajs/mproject 提供支持。
Octonet 是 @mostajs 三部曲的第二个大脑叶:
- #1 —
@mostajs/orm:数据持久化(13 个数据库) - #2 — Octonet:多协议传输(11 种线协议)
- #3 — 多语言 NetClient:14 个原生客户端库(Java、.NET、Python、Go、Swift、Kotlin、Dart、Rust、PHP、Ruby、Elixir、Lua、Delphi、Unity)
两步体验(T1 沙盒)
从 14 种运行时中的任何一种测试 Octonet,最快只需:
- 打开 https://octonet.amia.fr/try
- 选择一个别名(例如
alice-42) - 获取一个作用于你的沙盒的 apikey
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"
}
}
你的沙盒具有以下特性:
- 一个私有的 SQLite 文件(与其他别名隔离)
- 预先填充了
User、Product、Order实体 - 通过 REST 和 MCP 执行读写 CRUD 操作
- 每日限额为 500 个请求
- 有效期为 7 天(闲置时自动删除)
- 免费,无需电子邮件,并设有防滥用速率限制(每个 IP 每小时最多 10 个沙盒)
在任意一个 14 个 NetClient 中使用 apikey:
# Java / .NET / Python / Go / etc.
export MOSTAJS_NET_URL=https://octonet.amia.fr
export MOSTAJS_NET_API_KEY=sk_test_…
3 层入门模式
| 层级 | 目标用户 | 身份验证 | 配额 | 使用场景 |
|---|---|---|---|---|
T1 — 公共沙盒 /try | “我想在 10 分钟内试用” | 仅别名(无需邮箱) | 每天 500 次请求,TTL 7 天 | NetClients 演示、集成测试 |
| T2 — 注册账户 octocloud.amia.fr | “我确实要用,免费” | 邮箱 + 密码 | 每天 10 000 次请求 | 个人应用、业余项目 |
T3 — 自托管 npx @mostajs/net init | “数据留在你自己这里” | 本地管理员 | 无 | 企业、内部部署、AGPL |
11 种传输方式
根据已注册的架构自动生成。可通过环境变量逐一启用或停用(默认全部启用)。
| # | 传输方式 | 端点 | 使用场景 | 备注 |
|---|---|---|---|---|
| 1 | REST | /api/v1/{Entity} · /api/v1/{project}/{Entity} | 通用 | 每个实体 15 个路由(CRUD + count + search + aggregate + bulk + relations) |
| 2 | GraphQL | /graphql (POST) | 丰富的前端 | 通过 mercurius 自动生成架构 + GraphiQL IDE |
| 3 | WebSocket | wss://…/ws | 实时 | 广播 entity.created/updated/deleted/upserted 事件 |
| 4 | SSE | /events (GET stream) | 适用于移动设备 / 浏览器 | 服务器发送事件 |
| 5 | JSON-RPC | /rpc (POST) | EVM 相邻领域、经典用途 | JSON-RPC 2.0 + 方法发现 |
| 6 | MCP | /mcp (POST/GET SSE) | AI Agent(Claude、ChatGPT) | 每个实体自动生成 15 个工具(在 mcp.so 上列出) |
| 7 | gRPC | :50051 | 低延迟服务间通信 | 自动生成 .proto,每个实体 6 个 RPC |
| 8 | tRPC | /trpc/{Entity}.{op} | TypeScript 全栈 | 在客户端生成类型 |
| 9 | OData | /odata/{Collection} (+ $metadata) | SAP/Microsoft Dynamics | OData v4 ($filter、$select、$orderby) |
| 10 | NATS | mostajs.{Entity}.{op} | 边缘发布/订阅 | 请求-响应消息传递 |
| 11 | Arrow Flight | /arrow/* | 列式分析 | 零拷贝流式传输 |
同一套架构,11 个不同入口,0 代码生成。
13 种数据库
由 @mostajs/orm 提供的持久化方言:
| 类别 | 数据库 | 方言 ID |
|---|---|---|
| 主流 SQL | PostgreSQL、MySQL、MariaDB、SQLite | postgres、mysql、mariadb、sqlite |
| 企业级 SQL | Oracle、SQL Server、DB2、SAP HANA、HSQLDB、Sybase | oracle、mssql、db2、hana、hsqldb、sybase |
| NewSQL / 云 | CockroachDB、Google Cloud Spanner | cockroachdb、spanner |
| NoSQL | MongoDB | mongodb |
切换方言 = 更改 1 行环境变量:
DB_DIALECT=postgres → DB_DIALECT=mongodb
SGBD_URI=postgresql://… → SGBD_URI=mongodb://…
多租户身份验证
Octonet 使用基于 带作用域的 API 密钥(面向机器间通信)的身份验证中间件,以及用于人工管理的 RBAC。与具体实现无关的协调器位于 @mostajs/auth/lib/check-request.ts。
请求的身份验证流程
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
基于作用域的权限(通用、可扩展)
API 密钥的结构如下:
{
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 并不知道 projects/operations/transports 这些名称——这是有意为之。每个模块都会在启动时通过 registerScope(dialect, {name, label, …}) 注册其作用域。检查过程是通用的:isScopeAuthorized(perms, scope, value)。
HTTP 状态码映射
| 情况 | HTTP 代码 | Body |
|---|---|---|
| 没有 API 密钥 | 401 | {error: {code:'UNAUTHORIZED', message:'API key required…'}} |
| API 密钥无效 / 已撤销 | 401 | {error: {code:'UNAUTHORIZED', message:'Invalid or revoked API key'}} |
| API 密钥有效,但超出作用域 | 403 | {error: {code:'FORBIDDEN', message:'API key not authorized for X="Y"'}} |
| API 密钥有效 | 200/201 | {status:'ok', data: …}(已净化——不含密码 / 哈希) |
MCP 回退(兼容 mcp.so)
当未提供密钥时,/mcp 端点会自动回退使用标记为 public-default 的 API 密钥——以保留与 mcp.so / Claude Desktop 的兼容性。此公共密钥仅对 default 项目具有只读权限 → 禁止写入。
清理器
password、hash、verifyToken、resetToken、apiKeyHash、secret、privateKey 字段会由全局中间件从所有 JSON 响应中自动剥离。通过 /api/v1/User?limit=1 不会有数据泄露风险。
通用作用域注册表
作用域目录存储在接入项目的数据库中(不是 JSON 文件,也不是硬编码常量):
-- Auto-créées au boot via @mostajs/api-keys
CREATE 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
);
每个模块在启动时注册其作用域:
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
})
管理界面通过 GET /api/api-keys/scopes 加载动态目录,并呈现为矩阵(@mostajs/api-keys/components/ 中的 React 组件 ApiKeyScopeMatrix)。
多项目支持
通过 @mostajs/mproject,在同一台服务器上使用 N 个相互隔离的数据库。
路径前缀路由
# 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"
在运行时添加项目
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"}}]
}'
持久化在 projects-tree.json 中(路径:MOSTA_PROJECTS 环境变量)。
快速开始(自托管)
安装
npm install @mostajs/net @mostajs/orm @mostajs/mproject \
@mostajs/rbac @mostajs/auth @mostajs/api-keys \
@mostajs/config better-sqlite3
使用 SQLite 运行(无需基础设施)
DB_DIALECT=sqlite \
SGBD_URI=./data/octonet.db \
DB_SCHEMA_STRATEGY=update \
[email protected] \
OCTONET_ADMIN_PASSWORD=ChangeMe123! \
npx mostajs-net serve
控制台输出:
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
测试
# Sans apikey → 401
curl 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
配置(.env)
数据库(必填)
DB_DIALECT=postgres # any of 13 dialects
SGBD_URI=postgresql://user:pass@localhost:5432/db
DB_SCHEMA_STRATEGY=update # 'update' (recommandé prod) | 'create' (drop+recreate, dev only)
DB_SHOW_SQL=false
系统方言(生产环境推荐,可选)— v2.7.5+
将系统数据库(apikeys、RBAC 用户、审计、套餐、付款、项目生命周期元数据)与可变的业务方言分离。如果不设置这些变量,则透明地别名到单例业务数据库(向后兼容单数据库模式)。
MOSTA_SYSTEM_DIALECT=postgres # any of 13 dialects
MOSTA_SYSTEM_URI=postgresql://user:pass@localhost:5432/octonet_system
有关动机和操作指南,请参阅下文的独立系统方言部分。
服务器
MOSTA_NET_PORT=4488
MOSTA_PROJECTS=./projects-tree.json # path to multi-project config
SCHEMAS_PATH=./schemas # directory scanning fallback
传输方式(分别切换)
MOSTA_NET_REST_ENABLED=true
MOSTA_NET_GRAPHQL_ENABLED=true
MOSTA_NET_WS_ENABLED=true
MOSTA_NET_SSE_ENABLED=true
MOSTA_NET_JSONRPC_ENABLED=true
MOSTA_NET_MCP_ENABLED=true
MOSTA_NET_TRPC_ENABLED=true
MOSTA_NET_ODATA_ENABLED=true
MOSTA_NET_GRPC_ENABLED=false
MOSTA_NET_NATS_ENABLED=false
MOSTA_NET_ARROW_ENABLED=false
MOSTA_NET_CORS_ORIGIN=*
MOSTA_RATE_LIMIT_CLIENT=1000
RBAC 引导配置(通过 @mostajs/config 读取——支持配置级联 MOSTA_ENV=DEV)
[email protected] # 1er boot only ; ignored after
OCTONET_ADMIN_PASSWORD=secret-12345
OCTONET_ADMIN_FIRSTNAME=Admin # optional
OCTONET_ADMIN_LASTNAME=Octonet # optional
OCTONET_BOOTSTRAP_VERBOSE=false # detailed bootstrap logs
OCTONET_OPEN_MODE=false # dev only — passe sans apikey
T1 沙盒(可选)
OCTONET_TRIAL_DATA_DIR=./data/trials # SQLite files per alias
云中间件(可选,未来支持——与 Octocloud 共享元数据库)
OCTONET_META_URI=postgresql://user:pass@localhost:5432/octonet_meta # shared meta DB
PORTAL_DB_URI=postgresql://user:pass@localhost:5432/octonet_cloud # legacy octocloud DB
API 端点参考
公开端点
| 端点 | 方法 | 身份验证 | 描述 |
|---|---|---|---|
/health | GET | 公开 | 服务器状态 + 传输方式 + 实体 |
/try | GET | 公开 | T1 沙盒配置 HTML 表单 |
/try | POST | 公开(每个 IP 每小时限 10 次) | 创建沙盒 + 返回一次性 apikey |
/api/v1/health | GET | 公开 | API 版本化路径下的健康状态 |
项目 / 实体 CRUD(需要 apikey)
| 端点 | 方法 | 操作 | 描述 |
|---|---|---|---|
/api/v1/{Entity} | GET | findAll | 列出默认项目中的实体 |
/api/v1/{Entity}/:id | GET | findById | 获取单个实体 |
/api/v1/{Entity}/count | GET | count | 计数 |
/api/v1/{Entity}/one | GET | findOne | 获取第一条匹配项 |
/api/v1/{Entity}/search | GET | search | 文本搜索 |
/api/v1/{Entity} | POST | create | 插入 |
/api/v1/{Entity}/:id | PUT | update | 替换 |
/api/v1/{Entity}/:id | DELETE | delete | 删除 |
/api/v1/{Entity}/:id/addToSet | POST | addToSet | 添加到数组 |
/api/v1/{Entity}/:id/pull | POST | pull | 从数组中移除 |
/api/v1/{Entity}/:id/increment | POST | increment | 数值递增 |
/api/v1/{Entity}/upsert | POST | upsert | 插入或更新 |
/api/v1/{Entity}/aggregate | POST | aggregate | 聚合管道 |
/api/v1/{Entity}/updateMany | POST | updateMany | 批量更新 |
/api/v1/{Entity}/deleteMany | POST | deleteMany | 批量删除 |
/api/v1/{project}/{Entity}/… | * | * | 作用域限定到项目的相同路由 |
模式管理(需要管理员 apikey)
| 端点 | 方法 | 描述 |
|---|---|---|
/api/upload-schemas-json | POST | 在运行时推送模式(触发重新加载) |
/api/apply-schema | POST | 应用模式差异 |
/api/compare-schema | POST | 试运行模式差异 |
/api/schemas-config | GET | 当前已注册的模式 |
身份验证和 API 密钥(需要管理员权限)
| 端点 | 方法 | 描述 |
|---|---|---|
/api/api-keys | GET / POST | 列出 / 签发密钥 |
/api/api-keys/:id | PUT / DELETE | 更新 / 撤销 |
/api/api-keys/scopes | GET | 列出已注册的作用域及其值(供管理员矩阵 UI 使用) |
/api/api-keys/scopes | POST | 注册新的作用域(管理员) |
/api/api-keys/scopes/:name/values | PUT / DELETE | 管理作用域值 |
原生传输方式
| 端点 | 描述 |
|---|---|
/graphql | GraphQL 端点 + GraphiQL IDE |
/ws | WebSocket 连接(实体事件) |
/events | SSE 流 |
/rpc | JSON-RPC 2.0 |
/mcp | Model Context Protocol(Claude/Smithery 等) |
/trpc/{Entity}.{op} | tRPC 过程 |
/odata/{Collection} · /odata/$metadata | OData v4 |
多项目管理
| 端点 | 方法 | 描述 |
|---|---|---|
/api/projects | GET | 列出项目 |
/api/projects | POST | 添加项目 |
/api/projects/:name | PUT / DELETE | 编辑 / 移除 |
可观测性
| 端点 | 描述 |
|---|---|
/api/performance | 实时指标(req/s、p50、p99) |
/api/config-tree | 配置树(交互式) |
/api/live-log | 流式日志馈送 |
架构
┌──────────────────────────────────┐
│ 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) │
└────────────────────────┘
使用的生态系统模块
| 模块 | 在 Octonet 中的作用 |
|---|---|
@mostajs/orm | 持久化(13 种方言) |
@mostajs/mproject | 多项目管理(default + sandbox + 订阅者) |
@mostajs/rbac | 身份管理(User、Role、Permission、Account)+ AccountSchema + OCTONET_RBAC_SEED |
@mostajs/auth | 与框架无关的 checkRequest 编排器、hashPassword |
@mostajs/api-keys | API 密钥 CRUD + 作用域(Scope/ScopeValue schemas)+ checkApiKey + ApiKeyScopeMatrix 管理员 UI |
@mostajs/config | 带有 MOSTA_ENV 级联的环境变量辅助工具 |
@mostajs/cloud-middleware | 配额 / 订阅(可选——连接 Octocloud 时启用) |
@mostajs/replicator | CQRS 多副本(可选) |
@mostajs/project-life | Project 持久化 schemas(可选——用于采用 SGBD 而非 JSON 存储的情况) |
系统方言(与业务单例分离)
自 v2.7.5 起提供——解决了生产环境中观察到的 “
/api/change-dialect后找不到 API 密钥” 问题。
为什么要使用两种不同的方言?
Octonet 提供了一些管理路由,可在运行时修改数据库连接 (/api/change-dialect、/api/reload-config、/api/reconnect)——这对业务侧来说是合理的 (当前项目的 userland 实体可以根据管理员需求,从 postgres 迁移至 sqlite,再迁移至 mongodb)。
但系统模块 (API 密钥、RBAC users、审计、订阅计划、payments、project-life 元数据) 必须存放在一个稳定的数据库中,不受这些变更影响。否则:业务方言变更会导致找不到 API 密钥,管理员也会被锁在管理界面之外。
| 角色 | 环境变量 | 可在运行时修改? | 读取方 |
|---|---|---|---|
| 业务 (userland 实体) | DB_DIALECT + SGBD_URI | 是 (管理员 UI) | EntityService、传输方式、数据路由 |
| 系统 (Octonet 基础设施) | MOSTA_SYSTEM_DIALECT + MOSTA_SYSTEM_URI | 否 (稳定) | RBAC、apikey-middleware、account-scope、auth guards、sandbox /try |
推荐配置 (生产环境多数据库)
# Métier — peut bouger via /api/change-dialect
DB_DIALECT=postgres
SGBD_URI=postgresql://hmd:***@127.0.0.1:5432/octonet_business
# Système — stable, jamais touché par les routes admin
MOSTA_SYSTEM_DIALECT=postgres
MOSTA_SYSTEM_URI=postgresql://hmd:***@127.0.0.1:5432/octonet_system
单数据库配置 (开发 / 简单部署)
将 MOSTA_SYSTEM_* 留空 → 自动别名至业务单例 (100% 向后兼容,行为与 v2.7.5 之前相同)。
操作指南
1. 将现有部署迁移至多数据库模式
# 1. Sauvegarder la base actuelle
pg_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 .env
echo 'MOSTA_SYSTEM_DIALECT=postgres' >> .env.local
echo 'MOSTA_SYSTEM_URI=postgresql://hmd:***@127.0.0.1:5432/octonet_system' >> .env.local
# 4. Restart Octonet — le bootstrap RBAC + scopes seed sur octonet_system
pm2 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. 验证系统与业务已正确隔离
# Avant /api/change-dialect : apikey doit fonctionner
curl -H "X-API-Key: sk_live_…" http://localhost:4488/api/auth/verify
# → 200 OK
# Bouger le dialect métier vers SQLite
curl -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)
在 v2.7.5 之前,第二条 curl 会返回 503 metadata DB unavailable 或 401 PostgreSQL not connected. Call connect() first.
3. 在应用代码中读取系统方言
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. 检查启动引导
octonet-mcp 启动时,会显示两条日志:
✓ 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
src/server.ts 中的系统位置 (供参考)
现在有 18 个调用方通过 getSystemDialect() 获取方言,而非使用业务单例:
| 模块 | 位置 | 调用方 |
|---|---|---|
| RBAC 引导 | 1 | bootstrapRbac(systemDialect, …) |
| Scope 注册 | 4 | registerScope(systemDialect, …) × 3 + systemDialect.initSchema(scopeTables) |
| 全局中间件 | 2 | createApiKeyMiddleware(() => systemDialect, …) + createAccountScopeMiddleware(() => systemDialect) |
| 按传输方式应用的中间件 | 2 | 在每个 transport.use(…) 上应用同样的中间件 |
| 传输方式的身份验证守卫 | 6 | authGuard(systemDialect, …) × 6 (SSE、GraphQL、JSON-RPC、gRPC、tRPC、OData) |
自定义 /api/auth/verify | 2 | checkApiKey(systemDialect, …) + new UserRepository(systemDialect) |
Sandbox /try | 2 | registerTryRoutes({ dialect: systemDialect, … }) + startTrialCleanupJob({ dialect: systemDialect, … }) |
业务方言 (dialect) 仍在以下场景中合理使用:
- 业务单例的初始引导 (
L98) +pm.setDefault('default', dialect, …)(L126、L240) - 管理路由
/api/reconnect、/api/change-dialect、/api/reload-config、/api/test-connection、/api/truncate-tables、/api/drop-tables——这些操作都明确属于业务范畴 - 为 userland 实体提供服务的
EntityService(通过受保护的传输方式执行 CRUD 操作)
项目阶段 (历史记录)
| 阶段 | 仓库 | 交付内容 |
|---|---|---|
| 1 | @mostajs/data-plug v1.2.2-1.2.4 (API getSystemDialect + ORM 门面) | npm |
| 2 | @mostajs/net v2.7.5 (启动时执行 bootstrapSystemDialect) | 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 仓库 + 门面) | npm |
| 4 | @mostajs/net v2.7.5 (消费者切换为使用 getSystemDialect()——18 个位置) | git |
| 5 | /api/change-dialect 场景的集成测试:postgres → sqlite | ⏳ |
| 6 | 部署到 amia + MOSTA_SYSTEM_URI 冒烟测试 | ⏳ |
启动序列
- 通过
@mostajs/config加载.env(配置文件级联MOSTA_ENV) - 连接主方言(
SGBD_URI) - 加载架构(优先级:
getAllSchemas()注册表 →schemas.json→ 扫描SCHEMAS_PATH目录) - 使用策略
update/create执行dialect.initSchema(schemas) - 引导 RBAC(
octonet-rbac-bootstrap.ts):- 注册 UserSchema/RoleSchema/PermissionSchema/PermissionCategorySchema/AccountSchema/ApiKeySchema
seedRBAC(OCTONET_RBAC_SEED)— 6 个类别、25 项权限、4 个角色(admin/subscriber/trial/public)- 根据
OCTONET_ADMIN_EMAIL/PASSWORD执行createAdmin() - 创建 Account
trial-playground(type='trial') - 创建 User
public-demo(role=public) - 创建 Account
public-system(type='system') - 生成作用域限定为
default项目的 ApiKeypublic-default(只读,REST + MCP)——仅以明文输出一次
- 注册规范作用域:
projects(动态,Project.slug)、operations(静态:read/write/admin)、transports(静态:11 个值) - 将默认项目推送到
projects-tree.json(ownerId=admin,visibility=public) - 从
projects-tree.json加载其他项目 - 使用
composeMiddleware([sanitizer, apikey], ormHandler)包装 ormHandler →protectedOrmHandler - 启动每个已启用的传输方式:
transport.use(loggingMiddleware)transport.use(sanitizerMiddleware)transport.use(apiKeyMiddleware)transport.setHandler(ormHandler)transport.start(config)
- 注册 Fastify 路由:
registerDynamicRestRoutes(app, protectedOrmHandler, pm)—/api/v1/...registerProjectRoutes(app, pm, protectedOrmHandler)—/:project/*registerTryRoutes(app, {dialect, pm})—/tryPOSTregisterTryPage(app)—/tryGET(HTML)startTrialCleanupJob({dialect, pm})— 每小时运行的 cron 任务,TTL 为 7 天
- 监听端口(
MOSTA_NET_PORT)
14 种多语言 NetClient
Octonet 可供 14 种原生运行时使用,使用相同的 apikey 和 URL:
| 运行时 | 软件包 | 注册表 |
|---|---|---|
| Node/TS | @mostajs/net/client(内置) | npm |
| Java | com.mostajs:mostajs-net-client | Maven Central |
| Java + Spring Boot | com.mostajs:mostajs-net-client-spring-boot-starter | Maven Central |
| .NET | MostaJs.Net.Client | NuGet |
| Python | mostajs-net-client | PyPI |
| Go | github.com/apolocine/mosta-net-client-go | pkg.go.dev |
| Swift | mosta-net-client-swift | Swift Package Index |
| Kotlin | io.github.apolocine:mostajs-net-client-kt | Maven Central |
| Dart / Flutter | mostajs_net_client | pub.dev |
| Rust | mostajs-net-client | crates.io |
| PHP | mostajs/net-client | Packagist |
| Ruby | mostajs-net-client | RubyGems |
| Elixir | mostajs_net_client | Hex.pm |
| Lua | mostajs-net-client | LuaRocks |
| Delphi | MostaJsNetClient | GetIt |
| Unity (C#) | com.mostajs.net-client | OpenUPM |
Monorepo:github.com/apolocine/mosta-net-clients
每个 NetClient 都遵循相同的 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()
生产环境部署(amia.fr)
参考部署使用 PostgreSQL 后端,运行于 octonet.amia.fr + mcp.amia.fr(兼容别名):
| URL | 作用 |
|---|---|
https://octonet.amia.fr | Octonet 服务(REST、MCP、GraphQL、WS、SSE、tRPC、OData、JSON-RPC) |
https://mcp.amia.fr | 兼容性 DNS 别名 — 历史域名 mcp.so |
https://octocloud.amia.fr | Octocloud — SaaS Next.js 门户(订阅、管理 UI) |
完整的部署套件位于 Entreprise/octonet-mcp/:
apache/mcp.amia.fr.conf— Apache2 虚拟主机(SSE 代理、WS 升级、Let's Encrypt SAN 证书)ecosystem.config.cjs— PM2 配置deploy.sh/install.sh/update.sh— 编排脚本tests/smoke-all.sh— 冒烟测试套件(DNS、TLS、/health、SSE MCP、REST、/try、Java NetClient)
CLI
npx mostajs-net serve # Start server
npx mostajs-net mcp # MCP-only mode
npx mostajs-net generate-apikey <label> # Émettre une apikey via CLI
npx mostajs-net hash-password <password> # Hash bcrypt
npx mostajs-net info # JSON config dump
npx octonet-mcp --dialect=X --uri=Y # Standalone MCP server (process séparé)
许可证
AGPL-3.0-or-later — 可自由使用,前提是衍生代码保持开源。
可购买商业许可证:[email protected]。按项目定价,不按席位定价。
— (c) 2026 Dr Hamid MADANI <[email protected]>
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。