@oneentry/mcp-platform-server 0.1.0 → 0.1.1
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 +113 -71
- package/data/permissions.json +411 -0
- package/dist/api/build-catalog.d.ts +24 -0
- package/dist/api/build-catalog.d.ts.map +1 -0
- package/dist/api/build-catalog.js +257 -0
- package/dist/api/build-catalog.js.map +1 -0
- package/dist/api/catalog.d.ts +22 -3
- package/dist/api/catalog.d.ts.map +1 -1
- package/dist/api/catalog.js +69 -4
- package/dist/api/catalog.js.map +1 -1
- package/dist/api/normalize-schema.d.ts +14 -0
- package/dist/api/normalize-schema.d.ts.map +1 -0
- package/dist/api/normalize-schema.js +151 -0
- package/dist/api/normalize-schema.js.map +1 -0
- package/dist/api/swagger-source.d.ts +22 -0
- package/dist/api/swagger-source.d.ts.map +1 -0
- package/dist/api/swagger-source.js +76 -0
- package/dist/api/swagger-source.js.map +1 -0
- package/dist/api/types.d.ts +1 -1
- package/dist/api/types.d.ts.map +1 -1
- package/dist/bin/cli.js +11 -3
- package/dist/bin/cli.js.map +1 -1
- package/dist/config/config.d.ts +84 -10
- package/dist/config/config.d.ts.map +1 -1
- package/dist/config/config.js +69 -6
- package/dist/config/config.js.map +1 -1
- package/dist/index.d.ts +9 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/knowledge/github.d.ts +46 -0
- package/dist/knowledge/github.d.ts.map +1 -0
- package/dist/knowledge/github.js +214 -0
- package/dist/knowledge/github.js.map +1 -0
- package/dist/knowledge/loader.d.ts +46 -19
- package/dist/knowledge/loader.d.ts.map +1 -1
- package/dist/knowledge/loader.js +92 -105
- package/dist/knowledge/loader.js.map +1 -1
- package/dist/knowledge/search.d.ts +11 -0
- package/dist/knowledge/search.d.ts.map +1 -1
- package/dist/knowledge/search.js +36 -3
- package/dist/knowledge/search.js.map +1 -1
- package/dist/knowledge/tar.d.ts +22 -0
- package/dist/knowledge/tar.d.ts.map +1 -0
- package/dist/knowledge/tar.js +120 -0
- package/dist/knowledge/tar.js.map +1 -0
- package/dist/knowledge/types.d.ts +31 -10
- package/dist/knowledge/types.d.ts.map +1 -1
- package/dist/server.d.ts +3 -2
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +13 -6
- package/dist/server.js.map +1 -1
- package/dist/session.d.ts +6 -0
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +8 -0
- package/dist/session.js.map +1 -1
- package/dist/tools/guide.d.ts.map +1 -1
- package/dist/tools/guide.js +9 -2
- package/dist/tools/guide.js.map +1 -1
- package/dist/tools/whoami.d.ts.map +1 -1
- package/dist/tools/whoami.js +4 -0
- package/dist/tools/whoami.js.map +1 -1
- package/dist/transports/http.d.ts.map +1 -1
- package/dist/transports/http.js +26 -1
- package/dist/transports/http.js.map +1 -1
- package/dist/transports/stdio.js +1 -1
- package/dist/transports/stdio.js.map +1 -1
- package/knowledge/operating-rules.md +176 -0
- package/package.json +4 -4
- package/data/catalog.json +0 -1
- package/data/knowledge.json +0 -1
package/README.md
CHANGED
|
@@ -3,14 +3,20 @@
|
|
|
3
3
|
MCP server that lets an AI agent **operate the OneEntry Admin API** — grounded in the project's own
|
|
4
4
|
rules rather than in guesswork.
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
Nothing is frozen into the package. Both halves are fetched at runtime and cached:
|
|
7
7
|
|
|
8
|
-
- **Knowledge.**
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
8
|
+
- **Knowledge.** Small markdown files from a public GitHub repository
|
|
9
|
+
([ONEENTRY-PLATFORM/oneentry-platform-rules](https://github.com/ONEENTRY-PLATFORM/oneentry-platform-rules)),
|
|
10
|
+
chunked into searchable sections. Editing a doc there — through the GitHub UI, a PR, whatever — takes effect on the next
|
|
11
|
+
restart of any server, with no npm release.
|
|
12
|
+
- **Actuation.** Every Admin API operation, built from the stand's own
|
|
13
|
+
`GET /api/admin/workflows/nodes/admin-api/swagger.json`, with parameter and body schemas, the
|
|
14
|
+
permission each one requires, and a risk classification — reachable through one generic invoke
|
|
15
|
+
tool instead of one tool per endpoint. The catalog always describes the API that is actually
|
|
16
|
+
running, not a snapshot of it.
|
|
17
|
+
|
|
18
|
+
The one thing still committed here is `data/permissions.json`: `@GrantByPermission` is a decorator
|
|
19
|
+
and never reaches any swagger, so that map has to be recovered from the CMS sources.
|
|
14
20
|
|
|
15
21
|
Only the Admin API is exposed.
|
|
16
22
|
|
|
@@ -29,7 +35,7 @@ Add to `.mcp.json` in the repo you work from:
|
|
|
29
35
|
"mcpServers": {
|
|
30
36
|
"oneentry-mcp-platform": {
|
|
31
37
|
"command": "npx",
|
|
32
|
-
"args": ["-y", "@oneentry/mcp-platform-server"
|
|
38
|
+
"args": ["-y", "@oneentry/mcp-platform-server"],
|
|
33
39
|
"env": {
|
|
34
40
|
"ONEENTRY_CMS_BASE_URL": "http://localhost:3003/api/admin",
|
|
35
41
|
"ONEENTRY_CMS_LOGIN": "your-admin-login",
|
|
@@ -40,8 +46,9 @@ Add to `.mcp.json` in the repo you work from:
|
|
|
40
46
|
}
|
|
41
47
|
```
|
|
42
48
|
|
|
43
|
-
|
|
44
|
-
|
|
49
|
+
No checkout of the CMS is needed. On first run the knowledge repository is downloaded once and
|
|
50
|
+
cached; later runs re-use the cache and only ask GitHub whether the commit moved, at most once an
|
|
51
|
+
hour.
|
|
45
52
|
|
|
46
53
|
backend-app must be running with `API_TYPE=/api/admin` (default port 3003).
|
|
47
54
|
|
|
@@ -63,43 +70,6 @@ arguments, so a prompt-injected instruction cannot swap identities:
|
|
|
63
70
|
|
|
64
71
|
Sessions never share tokens or confirm tokens. `GET /health` reports liveness and session count.
|
|
65
72
|
|
|
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
73
|
## The seven tools
|
|
104
74
|
|
|
105
75
|
| tool | what it does |
|
|
@@ -110,7 +80,7 @@ To point an MCP client at the containerised stdio server:
|
|
|
110
80
|
| `cms_api_search` | find operations by keyword / tag / method / mutating |
|
|
111
81
|
| `cms_api_describe` | params, body schema, required permission, risk, linked docs |
|
|
112
82
|
| `cms_api_call` | execute one operation; `dryRun` and confirm-gating for mutations |
|
|
113
|
-
| `cms_whoami` | mode, base URL, admin + permissions,
|
|
83
|
+
| `cms_whoami` | mode, base URL, admin + permissions, knowledge commit, catalog state and warnings |
|
|
114
84
|
|
|
115
85
|
Plus two MCP resources: `oneentry://knowledge/mcp/operating-rules` and `oneentry://knowledge/index`.
|
|
116
86
|
|
|
@@ -135,42 +105,114 @@ Read-only by default. `--allow` (or `ONEENTRY_MCP_ALLOW`) raises it:
|
|
|
135
105
|
- Every non-GET call is appended to a JSONL audit log (arguments are hashed, not stored). Required
|
|
136
106
|
in remote mode.
|
|
137
107
|
|
|
138
|
-
##
|
|
108
|
+
## Where the knowledge comes from
|
|
139
109
|
|
|
140
|
-
|
|
110
|
+
A public GitHub repository of small markdown files. Layout:
|
|
111
|
+
|
|
112
|
+
```
|
|
113
|
+
knowledge/
|
|
114
|
+
mcp/operating-rules.md -> docId "mcp/operating-rules"
|
|
115
|
+
back/docs/menus-module.md -> docId "back/docs/menus-module"
|
|
116
|
+
back/docs/orders-module/index.md -> docId "back/docs/orders-module"
|
|
117
|
+
back/docs/orders-module/status-axis.md-> docId "back/docs/orders-module/status-axis"
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
The docId is the path under `knowledge/` without `.md`; `<name>/index.md` collapses back to
|
|
121
|
+
`<name>`, which is what lets a long document be split into a directory of small files without
|
|
122
|
+
changing the id anything already links to. **No file over 12 KB** — the same cap `cms_docs_read`
|
|
123
|
+
applies to a section, so a section can never come back truncated.
|
|
124
|
+
|
|
125
|
+
At startup the server asks GitHub for the commit behind `--knowledge-ref` (one cheap request,
|
|
126
|
+
skipped entirely while the cache is younger than `--knowledge-ttl`, default 1 h), and downloads
|
|
127
|
+
`codeload.github.com/<repo>/tar.gz/<sha>` only when that commit has moved — one request for the
|
|
128
|
+
whole corpus, no API rate limit. The tree is unpacked into `--cache-dir` keyed by commit, so a
|
|
129
|
+
restart is instant and the previous commit is pruned.
|
|
130
|
+
|
|
131
|
+
| situation | what happens |
|
|
132
|
+
|---|---|
|
|
133
|
+
| cache fresh | no network at all |
|
|
134
|
+
| commit unchanged | one API request, no download |
|
|
135
|
+
| commit moved | one API request + one archive download |
|
|
136
|
+
| GitHub unreachable, cache present | the cached commit is used |
|
|
137
|
+
| GitHub unreachable, no cache | falls back to the bundled `operating-rules.md`, and says so in `cms_guide` and `cms_whoami` |
|
|
138
|
+
| `--offline` | cache and bundled rules only, never the network |
|
|
139
|
+
|
|
140
|
+
Which repository and which commit is a configuration choice, not a constant: `--knowledge-repo`
|
|
141
|
+
(`ONEENTRY_MCP_KNOWLEDGE_REPO`, default `ONEENTRY-PLATFORM/oneentry-platform-rules`) and
|
|
142
|
+
`--knowledge-ref`
|
|
143
|
+
(`ONEENTRY_MCP_KNOWLEDGE_REF`, default `main`) — a ref may be a branch, a tag or a commit sha, so a
|
|
144
|
+
stand can be frozen on a known-good corpus. `ONEENTRY_GITHUB_TOKEN` is optional and only raises the
|
|
145
|
+
API rate limit; the repo is public. `cms_whoami` reports the repo, ref and 12-character commit the
|
|
146
|
+
running server actually loaded.
|
|
147
|
+
|
|
148
|
+
### Reading the docs from a local folder instead
|
|
149
|
+
|
|
150
|
+
For testing, or for editing docs without committing, point the server at a directory:
|
|
141
151
|
|
|
142
152
|
```bash
|
|
143
|
-
|
|
144
|
-
|
|
153
|
+
ONEENTRY_MCP_KNOWLEDGE_PATH=../oneentry-platform-rules oneentry-mcp-platform
|
|
154
|
+
# or: oneentry-mcp-platform --knowledge-path ../oneentry-platform-rules
|
|
145
155
|
```
|
|
146
156
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
157
|
+
Either the clone root or its `knowledge/` directory works — the path is probed for a `knowledge`
|
|
158
|
+
subdirectory and used directly if there is none. While it is set, GitHub is never contacted and the
|
|
159
|
+
cache is not consulted, so edits take effect on the next restart with no commit and no push;
|
|
160
|
+
`cms_whoami` reports `source: "local"`. Leave it unset for the default, which is GitHub.
|
|
161
|
+
|
|
162
|
+
A path that cannot be read is a **startup error**, not a fallback: unlike GitHub being unreachable,
|
|
163
|
+
a bad path is a configuration mistake, and degrading silently to the bundled operating rules would
|
|
164
|
+
look like an empty corpus.
|
|
165
|
+
|
|
166
|
+
### Known limitation: retrieval is single-language
|
|
167
|
+
|
|
168
|
+
Search does not translate. The backend corpus is largely English, so a Russian question will not
|
|
169
|
+
find an English-only document no matter how it is weighted — and the reverse holds too. The fix is
|
|
170
|
+
content, not code: give such a document a short summary section in the other language, or ask in the
|
|
171
|
+
language the document is written in.
|
|
153
172
|
|
|
154
|
-
|
|
155
|
-
rewrites `local-static/swagger.json` on startup.
|
|
173
|
+
### Publishing CMS docs into it
|
|
156
174
|
|
|
157
|
-
The
|
|
175
|
+
The knowledge repo is what the server reads; the CMS repos remain where the docs are written.
|
|
176
|
+
To move them across:
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
npm run publish:knowledge -- --back ../dnk-back --front ../dnk-front --out ../oneentry-platform-rules
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
It copies `.claude/docs`, `.claude/tests` and `.claude/rules` from both checkouts, splits anything
|
|
183
|
+
over 12 KB at `##` boundaries, and reports files in the target it did not produce. It **does not
|
|
184
|
+
commit or push** — that diff is the moment internal text becomes public, and a human owns it.
|
|
185
|
+
`.claude/fixes` and the CMS `CLAUDE.md` files are deliberately not published.
|
|
186
|
+
|
|
187
|
+
## Where the catalog comes from
|
|
188
|
+
|
|
189
|
+
Two sources, because neither alone is enough:
|
|
190
|
+
|
|
191
|
+
1. `GET {baseUrl}/workflows/nodes/admin-api/swagger.json?langCode=en_US` — paths, operation ids and
|
|
192
|
+
schemas, straight from the stand you are pointed at. Cached per base URL, so an unreachable
|
|
193
|
+
stand still yields the last known catalog.
|
|
194
|
+
2. `data/permissions.json` — the `@GrantByPermission` decorators, which never reach swagger.
|
|
195
|
+
Regenerate it when the CMS changes its permissions:
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
npm run sync:permissions -- --back ../dnk-back
|
|
199
|
+
```
|
|
158
200
|
|
|
159
|
-
|
|
160
|
-
|
|
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.
|
|
201
|
+
That pass walks base classes too, since Nest derives the operation id from the *registered*
|
|
202
|
+
controller while the handler often lives in a parent.
|
|
163
203
|
|
|
164
|
-
|
|
165
|
-
`
|
|
204
|
+
Inconsistencies are surfaced as catalog `warnings` (visible in `cms_whoami`) rather than swallowed:
|
|
205
|
+
paths outside `/api/admin` (dropped — this server exposes the Admin API only), operations with no
|
|
206
|
+
`operationId`, handlers whose permission is known but which the stand does not expose, and
|
|
207
|
+
permissions required by controllers but absent from `AdminPermissionsEnum` — no admin can hold
|
|
208
|
+
those, so such endpoints answer 403 forever.
|
|
166
209
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
`orders.export`, `payments.export`) — no admin can hold these, so those endpoints always 403.
|
|
210
|
+
If the stand does not serve its swagger at all, the catalog is **empty** and says so loudly. Empty
|
|
211
|
+
is safe — there is nothing to call — but silence would read as "the CMS has no such endpoint".
|
|
170
212
|
|
|
171
213
|
### The swagger is not valid JSON Schema
|
|
172
214
|
|
|
173
|
-
|
|
215
|
+
Many `type` values in the source swagger are TypeScript expressions (`Record<string, any>`,
|
|
174
216
|
`CommonLocalizeInfos`, `AttributesSets`, `image`, `date`). The build normalizes what it can and
|
|
175
217
|
marks the rest `"x-loose": true` with the original under `x-source-type`. For loose fields the
|
|
176
218
|
`example` is the contract, and client-side body validation is deliberately advisory — the server
|