@oneentry/mcp-platform-server 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +189 -0
- package/data/catalog.json +1 -0
- package/data/knowledge.json +1 -0
- package/dist/api/audit.d.ts +32 -0
- package/dist/api/audit.d.ts.map +1 -0
- package/dist/api/audit.js +35 -0
- package/dist/api/audit.js.map +1 -0
- package/dist/api/auth.d.ts +53 -0
- package/dist/api/auth.d.ts.map +1 -0
- package/dist/api/auth.js +126 -0
- package/dist/api/auth.js.map +1 -0
- package/dist/api/catalog.d.ts +39 -0
- package/dist/api/catalog.d.ts.map +1 -0
- package/dist/api/catalog.js +108 -0
- package/dist/api/catalog.js.map +1 -0
- package/dist/api/client.d.ts +60 -0
- package/dist/api/client.d.ts.map +1 -0
- package/dist/api/client.js +196 -0
- package/dist/api/client.js.map +1 -0
- package/dist/api/policy.d.ts +52 -0
- package/dist/api/policy.d.ts.map +1 -0
- package/dist/api/policy.js +0 -0
- package/dist/api/policy.js.map +1 -0
- package/dist/api/shape.d.ts +19 -0
- package/dist/api/shape.d.ts.map +1 -0
- package/dist/api/shape.js +151 -0
- package/dist/api/shape.js.map +1 -0
- package/dist/api/types.d.ts +85 -0
- package/dist/api/types.d.ts.map +1 -0
- package/dist/api/types.js +2 -0
- package/dist/api/types.js.map +1 -0
- package/dist/bin/cli.d.ts +3 -0
- package/dist/bin/cli.d.ts.map +1 -0
- package/dist/bin/cli.js +48 -0
- package/dist/bin/cli.js.map +1 -0
- package/dist/config/config.d.ts +108 -0
- package/dist/config/config.d.ts.map +1 -0
- package/dist/config/config.js +167 -0
- package/dist/config/config.js.map +1 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/knowledge/chunk.d.ts +35 -0
- package/dist/knowledge/chunk.d.ts.map +1 -0
- package/dist/knowledge/chunk.js +87 -0
- package/dist/knowledge/chunk.js.map +1 -0
- package/dist/knowledge/loader.d.ts +27 -0
- package/dist/knowledge/loader.d.ts.map +1 -0
- package/dist/knowledge/loader.js +125 -0
- package/dist/knowledge/loader.js.map +1 -0
- package/dist/knowledge/search.d.ts +34 -0
- package/dist/knowledge/search.d.ts.map +1 -0
- package/dist/knowledge/search.js +95 -0
- package/dist/knowledge/search.js.map +1 -0
- package/dist/knowledge/types.d.ts +47 -0
- package/dist/knowledge/types.d.ts.map +1 -0
- package/dist/knowledge/types.js +2 -0
- package/dist/knowledge/types.js.map +1 -0
- package/dist/server.d.ts +16 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +48 -0
- package/dist/server.js.map +1 -0
- package/dist/session.d.ts +43 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +75 -0
- package/dist/session.js.map +1 -0
- package/dist/tools/api-call.d.ts +5 -0
- package/dist/tools/api-call.d.ts.map +1 -0
- package/dist/tools/api-call.js +169 -0
- package/dist/tools/api-call.js.map +1 -0
- package/dist/tools/api-discovery.d.ts +5 -0
- package/dist/tools/api-discovery.d.ts.map +1 -0
- package/dist/tools/api-discovery.js +80 -0
- package/dist/tools/api-discovery.js.map +1 -0
- package/dist/tools/docs.d.ts +5 -0
- package/dist/tools/docs.d.ts.map +1 -0
- package/dist/tools/docs.js +113 -0
- package/dist/tools/docs.js.map +1 -0
- package/dist/tools/guide.d.ts +11 -0
- package/dist/tools/guide.d.ts.map +1 -0
- package/dist/tools/guide.js +67 -0
- package/dist/tools/guide.js.map +1 -0
- package/dist/tools/result.d.ts +19 -0
- package/dist/tools/result.d.ts.map +1 -0
- package/dist/tools/result.js +19 -0
- package/dist/tools/result.js.map +1 -0
- package/dist/tools/whoami.d.ts +5 -0
- package/dist/tools/whoami.d.ts.map +1 -0
- package/dist/tools/whoami.js +42 -0
- package/dist/tools/whoami.js.map +1 -0
- package/dist/transports/http.d.ts +10 -0
- package/dist/transports/http.d.ts.map +1 -0
- package/dist/transports/http.js +126 -0
- package/dist/transports/http.js.map +1 -0
- package/dist/transports/stdio.d.ts +8 -0
- package/dist/transports/stdio.d.ts.map +1 -0
- package/dist/transports/stdio.js +15 -0
- package/dist/transports/stdio.js.map +1 -0
- package/package.json +60 -0
package/README.md
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
# @oneentry/mcp-platform-server
|
|
2
|
+
|
|
3
|
+
MCP server that lets an AI agent **operate the OneEntry Admin API** — grounded in the project's own
|
|
4
|
+
rules rather than in guesswork.
|
|
5
|
+
|
|
6
|
+
Two things are bundled:
|
|
7
|
+
|
|
8
|
+
- **Knowledge.** ~1 MB of reference docs from `backend-app/.claude/**` and `frontend-app/.claude/**`,
|
|
9
|
+
split into ~1700 searchable sections, plus a hand-written `operating-rules.md` distilling the
|
|
10
|
+
payload rules that actually break calls.
|
|
11
|
+
- **Actuation.** All **478 Admin API operations** as a searchable catalog with parameter and body
|
|
12
|
+
schemas, the permission each one requires, and a risk classification — reachable through one
|
|
13
|
+
generic invoke tool instead of 478 separate ones.
|
|
14
|
+
|
|
15
|
+
Only the Admin API is exposed.
|
|
16
|
+
|
|
17
|
+
## Install
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm i -g @oneentry/mcp-platform-server # or use npx, below
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Local mode (agent and CMS on the same machine)
|
|
24
|
+
|
|
25
|
+
Add to `.mcp.json` in the repo you work from:
|
|
26
|
+
|
|
27
|
+
```json
|
|
28
|
+
{
|
|
29
|
+
"mcpServers": {
|
|
30
|
+
"oneentry-mcp-platform": {
|
|
31
|
+
"command": "npx",
|
|
32
|
+
"args": ["-y", "@oneentry/mcp-platform-server", "--back", "../backend-app", "--front", "../frontend-app"],
|
|
33
|
+
"env": {
|
|
34
|
+
"ONEENTRY_CMS_BASE_URL": "http://localhost:3003/api/admin",
|
|
35
|
+
"ONEENTRY_CMS_LOGIN": "your-admin-login",
|
|
36
|
+
"ONEENTRY_CMS_PASSWORD": "your-admin-password"
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
`--back`/`--front` are optional: with them the knowledge is read live from the checkouts, so edits
|
|
44
|
+
to `.claude/docs` take effect immediately; without them the bundled snapshot is used.
|
|
45
|
+
|
|
46
|
+
backend-app must be running with `API_TYPE=/api/admin` (default port 3003).
|
|
47
|
+
|
|
48
|
+
## Remote mode (hosted, many agents, one stand)
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
oneentry-mcp-platform --http --port 8931 --audit /var/log/oneentry-mcp-platform-audit.jsonl \
|
|
52
|
+
--base-url https://stand.example/api/admin \
|
|
53
|
+
--allowed-origins https://agent.example
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Each MCP session carries its own CMS identity, passed as connection headers — never as tool
|
|
57
|
+
arguments, so a prompt-injected instruction cannot swap identities:
|
|
58
|
+
|
|
59
|
+
| header | meaning |
|
|
60
|
+
|---|---|
|
|
61
|
+
| `x-cms-token` | pre-issued Admin API access token (preferred) |
|
|
62
|
+
| `x-cms-login` + `x-cms-password` | credentials to log in with |
|
|
63
|
+
|
|
64
|
+
Sessions never share tokens or confirm tokens. `GET /health` reports liveness and session count.
|
|
65
|
+
|
|
66
|
+
## Docker
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
cp .env.example .env # fill in ONEENTRY_CMS_LOGIN / ONEENTRY_CMS_PASSWORD
|
|
70
|
+
docker compose up --build mcp # remote mode on :8931
|
|
71
|
+
curl -s http://127.0.0.1:8931/health # {"ok":true,"mode":"remote","sessions":0}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
| service | profile | mode |
|
|
75
|
+
|---|---|---|
|
|
76
|
+
| `mcp` | — | remote (Streamable HTTP) on `:8931` |
|
|
77
|
+
| `mcp-live` | `live` | remote, knowledge read live from the mounted checkouts |
|
|
78
|
+
| `stdio` | `stdio` | local stdio — usable directly as an MCP client command |
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
docker compose --profile live up --build mcp-live
|
|
82
|
+
docker compose --profile stdio run --rm -T stdio
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
A stand running on the host is reachable as `host.docker.internal` (wired via `host-gateway`), so
|
|
86
|
+
the default base URL inside the container is `http://host.docker.internal:3003/api/admin`. The audit
|
|
87
|
+
log is bind-mounted to `./.audit`. Details and gotchas: [.claude/docs/docker.md](.claude/docs/docker.md).
|
|
88
|
+
|
|
89
|
+
To point an MCP client at the containerised stdio server:
|
|
90
|
+
|
|
91
|
+
```json
|
|
92
|
+
{
|
|
93
|
+
"mcpServers": {
|
|
94
|
+
"oneentry-mcp-platform": {
|
|
95
|
+
"command": "docker",
|
|
96
|
+
"args": ["compose", "-f", "/abs/path/to/docker-compose.yml", "--profile", "stdio",
|
|
97
|
+
"run", "--rm", "-T", "stdio"]
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## The seven tools
|
|
104
|
+
|
|
105
|
+
| tool | what it does |
|
|
106
|
+
|---|---|
|
|
107
|
+
| `cms_guide` | read first: mode, policy, API map, the order to use the other tools |
|
|
108
|
+
| `cms_docs_search` | search the knowledge base, returns sections with snippets |
|
|
109
|
+
| `cms_docs_read` | read one section, with its sibling sections listed for paging |
|
|
110
|
+
| `cms_api_search` | find operations by keyword / tag / method / mutating |
|
|
111
|
+
| `cms_api_describe` | params, body schema, required permission, risk, linked docs |
|
|
112
|
+
| `cms_api_call` | execute one operation; `dryRun` and confirm-gating for mutations |
|
|
113
|
+
| `cms_whoami` | mode, base URL, admin + permissions, catalog/knowledge versions and warnings |
|
|
114
|
+
|
|
115
|
+
Plus two MCP resources: `oneentry://knowledge/mcp/operating-rules` and `oneentry://knowledge/index`.
|
|
116
|
+
|
|
117
|
+
## Write safety
|
|
118
|
+
|
|
119
|
+
Read-only by default. `--allow` (or `ONEENTRY_MCP_ALLOW`) raises it:
|
|
120
|
+
|
|
121
|
+
| level | GET | POST/PUT/PATCH | DELETE |
|
|
122
|
+
|---|---|---|---|
|
|
123
|
+
| `read` (default) | ✅ | ❌ | ❌ |
|
|
124
|
+
| `write` | ✅ | ✅ | ❌ |
|
|
125
|
+
| `destructive` | ✅ | ✅ | ✅ confirm-gated |
|
|
126
|
+
|
|
127
|
+
- A refusal by level happens **before authentication** — no HTTP request is made at all.
|
|
128
|
+
- Deletes, and every path in the permanently gated list (`immutable-settings`, `admins`, `backups`,
|
|
129
|
+
`modules`, `payments/webhook`, `settings-general`, `system/captcha-keys`,
|
|
130
|
+
`auth/logout/all-users`), require a **confirm token**: the first call returns the token *and the
|
|
131
|
+
current state of the target*, fetched via the sibling GET, so a human can see what is about to
|
|
132
|
+
change. The token is bound to `hash(opId + arguments)`, single-use, valid 5 minutes.
|
|
133
|
+
- Permissions are checked locally first: if the admin lacks the `AdminPermissionsEnum` value the
|
|
134
|
+
operation declares, the call is refused without being sent.
|
|
135
|
+
- Every non-GET call is appended to a JSONL audit log (arguments are hashed, not stored). Required
|
|
136
|
+
in remote mode.
|
|
137
|
+
|
|
138
|
+
## Keeping the bundled data in sync
|
|
139
|
+
|
|
140
|
+
`data/catalog.json` and `data/knowledge.json` are committed build outputs:
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
npm run sync:from-cms -- --back ../backend-app --front ../frontend-app
|
|
144
|
+
npm run check:drift # CI: fails if the committed data is stale
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Both commands fall back to sibling checkouts (`../dnk-back`, `../dnk-front`) when the flags are
|
|
148
|
+
omitted, so the bare form works in the usual layout. `check:drift` runs automatically as
|
|
149
|
+
`prestart`, i.e. before `npm start` — it compares content only, and **skips** (exit 0) when no
|
|
150
|
+
checkout is next to the repo, so a deployment without the CMS sources still starts. It does not
|
|
151
|
+
run before `npm run dev`: the ts-morph pass over every controller takes ~20 s, which is too slow
|
|
152
|
+
for a restart loop.
|
|
153
|
+
|
|
154
|
+
Refreshing `swagger.json` itself is dnk-back's job — boot it once with `API_TYPE=/api/admin` and it
|
|
155
|
+
rewrites `local-static/swagger.json` on startup.
|
|
156
|
+
|
|
157
|
+
The catalog is built from two sources, because neither alone is enough:
|
|
158
|
+
|
|
159
|
+
1. `backend-app/local-static/swagger.json` — paths, operation ids and schemas.
|
|
160
|
+
2. `backend-app/src/**/*.controller.ts` via ts-morph — the `@GrantByPermission` decorators, which
|
|
161
|
+
never reach swagger. Base classes are walked, since Nest derives the operation id from the
|
|
162
|
+
registered controller while the handler often lives in a parent.
|
|
163
|
+
|
|
164
|
+
Two classes of inconsistency in dnk-back are surfaced as catalog `warnings` (visible in
|
|
165
|
+
`cms_whoami`) rather than silently swallowed:
|
|
166
|
+
|
|
167
|
+
- handlers that declare a permission but are missing from `swagger.json` — a stale swagger snapshot;
|
|
168
|
+
- permissions required by controllers but absent from `AdminPermissionsEnum` (`users.export`,
|
|
169
|
+
`orders.export`, `payments.export`) — no admin can hold these, so those endpoints always 403.
|
|
170
|
+
|
|
171
|
+
### The swagger is not valid JSON Schema
|
|
172
|
+
|
|
173
|
+
311 `type` values in the source swagger are TypeScript expressions (`Record<string, any>`,
|
|
174
|
+
`CommonLocalizeInfos`, `AttributesSets`, `image`, `date`). The build normalizes what it can and
|
|
175
|
+
marks the rest `"x-loose": true` with the original under `x-source-type`. For loose fields the
|
|
176
|
+
`example` is the contract, and client-side body validation is deliberately advisory — the server
|
|
177
|
+
is the real validator, so a call is never blocked because a loose field could not be checked.
|
|
178
|
+
|
|
179
|
+
## Tests
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
npm test # unit + MCP protocol + remote-mode transport (no stand needed)
|
|
183
|
+
npm run test:integration # against a live dnk-back; skips cleanly if unreachable
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
The integration suite needs backend-app on `:3003` with `API_TYPE=/api/admin` plus
|
|
187
|
+
`ONEENTRY_CMS_LOGIN`/`ONEENTRY_CMS_PASSWORD`. It walks search → describe → call, asserts a read-only refusal
|
|
188
|
+
sends nothing, and runs a full create → confirm-gated delete cycle on a throwaway template while
|
|
189
|
+
checking the audit log.
|