@oneentry/mcp-platform-server 0.1.5 → 0.1.6

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.
@@ -1,6 +1,6 @@
1
1
  # Operating rules for the OneEntry Admin API
2
2
 
3
- Read this before your first write. Every rule here has broken a real payload; each links to the document explaining it in full. When one applies to what you are about to do, follow the pointer before you build the body.
3
+ Read this before your first write. Every rule here has broken a real payload, and each links to the document explaining it. When one applies, follow the pointer before you build the body.
4
4
 
5
5
  → `mcp/docs/server/doc-map` · `mcp/docs/server/payload-conventions`
6
6
 
@@ -9,15 +9,13 @@ Read this before your first write. Every rule here has broken a real payload; ea
9
9
  1. `cms_guide` once, at the start.
10
10
  2. `cms_docs_search` for the entity you are about to touch — **before** the payload, not after a 400.
11
11
  3. `cms_api_search` for the operation, then `cms_api_describe` for its shape.
12
- 4. `cms_api_call` with `dryRun: true` for anything that mutates, then again with the confirm token if one was issued.
12
+ 4. `cms_api_call` with `dryRun: true` for anything that mutates, then again with the confirm token. Files go through `cms_upload_file` or `cms_import_file_from_url`.
13
13
 
14
14
  Never invent a path, an operation id or a body key. `cms_api_search` is the only authority on what exists.
15
15
 
16
16
  ## Trust the example not the type
17
17
 
18
- The API document carries field types that are not JSON Schema types. `cms_api_describe` normalises what it can and marks the rest `"x-loose": true`.
19
-
20
- For those, **the `example` is the contract** — copy its shape. Validation here is advisory; the instance is the real validator, so a call is never blocked over a field we could not check. A field flagged `x-example-mismatch` contradicts its own type, and the example wins there too.
18
+ The API document carries field types that are not JSON Schema types. `cms_api_describe` normalises what it can and marks the rest `"x-loose": true`, and for those **the `example` is the contract**. A field flagged `x-example-mismatch` contradicts its own type, and the example wins there too; a `curatedBody` beats both.
21
19
 
22
20
  → `mcp/docs/server/cms-api-describe#loose-fields`
23
21
 
@@ -29,7 +27,7 @@ Titles and descriptive content live under `localizeInfos`, keyed by locale code:
29
27
  { "localizeInfos": { "en_US": { "title": "Summer sale" } } }
30
28
  ```
31
29
 
32
- Required on a product, effectively required on a page. Do not hardcode `en_US`: read the active locales with `AdminLocalesController_findAllActive` and write every one the content is meant to appear in.
30
+ Required on a product, effectively required on a page. Never hardcode `en_US`: read the active locales and write every one the content is meant to appear in. The one structure that is **not** locale keyed is an option's extra value.
33
31
 
34
32
  → `mcp/docs/api/locales`
35
33
 
@@ -41,90 +39,90 @@ Required on a product, effectively required on a page. Do not hardcode `en_US`:
41
39
  { "attributesSets": { "en_US": { "string_id42": "SKU-1" } } }
42
40
  ```
43
41
 
44
- The inner key is `<attribute type>_id<attribute id>`, read from the entity's attribute set. A flat one-level map is accepted, answers 201 and stores nothing — so read the entity back by id after creating it.
42
+ The inner key is `<attribute type>_id<attribute id>`, from the entity's attribute set. A flat one-level map is accepted, answers 201 and stores nothing — read the entity back by id.
45
43
 
46
44
  → `mcp/docs/api/attribute-sets`
47
45
 
48
46
  ## Positions are lexorank or numeric depending on the endpoint
49
47
 
50
- Ordering is a lexorank **string** on parent-scoped Admin operations and a **number** on flat lists and the Content API. Never sort a lexorank numerically, and never reorder by patching the field use that entity's position operation.
48
+ Ordering is a lexorank **string** on parent-scoped Admin operations and a **number** on flat lists and public reads. Never sort a lexorank numerically, never reorder by patching the field, and never send a string one back to an update.
51
49
 
52
50
  → `mcp/docs/server/payload-conventions#position-is-a-lexorank-string-or-a-number`
53
51
 
54
52
  ## A read straight after a write can lag
55
53
 
56
- Reading an entity **by id** shows your write immediately. Lists and searches may not, for a few seconds.
57
-
58
- If a list does not show what you just created, re-read by id. **Never repeat the write** — you get a duplicate that consumes quota and has to be cleaned up by hand. And never swallow a failed read into an empty result: "empty" and "malformed" then look alike, and the next run recreates everything.
54
+ Reading an entity **by id** shows your write immediately; lists and searches may lag by seconds. So re-read by id and **never repeat the write** — that makes a duplicate somebody cleans up by hand. Never swallow a failed read into an empty result either: the next run then recreates everything.
59
55
 
60
56
  ## A 200 means accepted not applied
61
57
 
62
- Several endpoints take the body as one opaque value, so a wrong **shape** is stored as happily as a right one and the answer is still `200`.
63
-
64
- Confirm a write by its effect, and **through the read its consumer uses**. The raw record echoes your input back, wrong shape included, while the projection a site receives shows nothing — verifying through the endpoint you wrote to proves little.
58
+ Several endpoints take the body as one opaque value, so a wrong **shape** is stored as happily as a right one and the answer is still `200`. Confirm a write by its effect, **through the read its consumer uses** — the raw record echoes your input back, wrong shape included.
65
59
 
66
60
  → `mcp/docs/api/silent-no-ops`
67
61
 
68
62
  ## An omitted field can mean clear it
69
63
 
70
- Most updates merge. A few apply an omitted field as **"set it to nothing"**, and still answer `200`: a page without `parentId` moves to the root, a block without `blockPages` detaches from every page, a menu item without its parent reference flattens, a user without `formData` loses it.
64
+ Most updates merge. A few apply an omitted field as **"set it to nothing"** and still answer `200`: a page loses `parentId` to the root, a block loses every page attachment, a menu item flattens, a form loses its bindings and their submissions. Products merge, so "PUT always replaces" is the wrong lesson.
71
65
 
72
- Products, `generalTypeId` and `attributeSetId` merge, so "PUT always replaces" is the wrong lesson. Read, change what you meant to, send it back whole — then check the fields that were **not** in your body.
66
+ Read, change what you meant to, send it back whole — then check the fields that were **not** in your body.
73
67
 
74
68
  → `mcp/docs/server/payload-conventions#an-omitted-field-can-mean-clear-it`
75
69
 
76
70
  ## Prefer marker over id
77
71
 
78
- Blocks, forms, menus, templates, general types and modules are addressed by a `marker` or `identifier` stable across instances. A numeric `id` is not, and a `404` on an id you were given is usually that. Where an operation accepts either, use the marker.
72
+ Blocks, forms, menus, templates, general types and modules carry a `marker` or `identifier` stable across instances. A numeric `id` is not, and a `404` on an id you were handed is usually that. Where both are accepted, use the marker.
79
73
 
80
74
  ## Baseline data already exists do not recreate it
81
75
 
82
- Every instance arrives populated: user groups, modules, general types, attribute set and field types, locales, block types with their default templates, the singleton settings.
76
+ Every instance arrives populated: user groups, modules, general types, attribute set and field types, locales, block types, the singleton settings. **List first, create second** — the dangerous duplicates (user groups, modules, attribute set types, settings) succeed silently.
83
77
 
84
- **List first, create second.** Some duplicates fail loudly, which is harmless. The dangerous ones user groups, modules, attribute set types, settings **succeed silently**.
85
-
86
- Two lists are the exception and start **empty**: product statuses and template previews. Nothing seeds them, nothing reports their absence, and without them no product is sellable and no upload gets a preview. There, create.
78
+ Two lists start **empty**: product statuses and template previews. Nothing reports their absence, yet without them no product is sellable and no upload gets a preview. There, create.
87
79
 
88
80
  → `mcp/docs/api/baseline-data`
89
81
 
90
82
  ## Never touch these without a human saying so
91
83
 
92
- Mutations on the instance's own configuration — admins, modules, backups, settings — are permanently confirm-gated at every allow level. `cms_guide` prints the exact list.
93
-
94
- The gate is not a suggestion. State what you intend to change, show the human the dry run's `target`, and wait for a yes here.
84
+ Mutations on the instance's own configuration — admins, modules, backups, settings — are confirm-gated at every allow level, and `cms_guide` prints the list. State what you intend to change, show the dry run's `target`, wait for a yes.
95
85
 
96
86
  → `mcp/docs/server/allow-levels#paths-that-are-always-confirm-gated`
97
87
 
98
88
  ## Permissions are checked before the request is sent
99
89
 
100
- Each operation declares the permission it needs, and this server refuses locally when the admin does not hold it. Nothing is sent, so nothing changed. A refusal means **ask for the grant** and stop no retry and no sibling operation gets past it.
90
+ Each operation declares the permission it needs, and this server refuses locally when the admin does not hold it nothing is sent. **Ask for the grant** and stop: no retry and no sibling operation gets past it.
101
91
 
102
92
  → `mcp/docs/api/admins-and-permissions`
103
93
 
104
94
  ## Truncated responses are deliberate
105
95
 
106
- A large response comes back with a `_truncated` envelope reporting what was shown and what the total was. That is this server capping what it hands you, not the API. Do not retry hoping for more narrow the request with the operation's own `limit`, `offset` and filters.
96
+ A large response comes back with a `_truncated` envelope saying what was shown and what the total was this server capping the answer, not the API. Do not retry for more; narrow the request with the operation's `limit`, `offset` and filters.
107
97
 
108
98
  → `mcp/docs/server/response-shaping`
109
99
 
110
100
  ## Operations with a single supported path
111
101
 
112
- One route works and the obvious alternative does not. Use it directly.
102
+ One route works and the obvious alternative does not.
113
103
 
114
- - **Create a form** — wrap in `newForm`, with `type` (`data` for a contact form) though the schema omits it.
115
- - **Replace an attribute set schema** — send the schema object itself. Wrapped as `{ "schema": … }` it answers 200 and destroys it.
104
+ - **Create a form** — wrapped in `newForm`, with `type`, which the schema omits.
105
+ - **Replace an attribute set schema** — the schema object itself. Wrapped as `{ "schema": … }` it answers 200 and destroys it.
116
106
  - **Update a product** — include `blocks` (`[]` if nothing to set), never `forms`.
117
- - **Create a menu** — with `pagesIds: []`, attaching pages later. Non-empty on create answers 500.
118
- - **Set a product status** — `statusId` in the product update. Bulk `set-status` takes it in a field named `id`, and given `statusId` it nulls the status and answers `201 true`.
107
+ - **Create a menu** — with `pagesIds: []`; non-empty answers 500. Nesting and labels come later.
108
+ - **Set a product status** — `statusId` in the product update, not bulk `set-status`.
109
+ - **Upload a file** — `cms_upload_file` or `cms_import_file_from_url`; `cms_api_call` sends JSON only.
119
110
 
120
111
  ## List products and other calls whose input is split
121
112
 
122
- `POST /products/all` is the only way to list products, and its input is split: **paging and `langCode` go in the query, the body is an array of filters** — `[]` for none. Sent in the body they are ignored, and the 400 blames `langCode` for a value you never sent.
123
-
124
- Copy `example` from `cms_api_describe` whole: separate `params` and `body` schemas do not assemble into an obvious call, and `example` is already one.
113
+ `POST /products/all` is the only way to list products, and its input is split: **paging and `langCode` in the query, the body an array of filters** — `[]` for none. Sent in the body they are ignored, and the 400 blames `langCode` for a value you never sent. Copy `example` from `cms_api_describe` whole, and prefer `curatedBody` where it appears.
125
114
 
126
115
  A 5xx outside these two lists means stop and report it, with the operation id and the request.
127
116
 
117
+ ## Reading it back is not always verifying
118
+
119
+ Two cases where the habit is not enough:
120
+
121
+ - **A batch write** can miss one entity while every response reports success. Re-read **all** of them — for products, by ids in one call — and retry the mismatches. Calculated values such as ratings arrive after a delay: wait, then check again.
122
+ - **A field that exists for the admin panel** — an option's extra value, a flag like `multiselect` — comes back from every read exactly as sent, while the panel still shows it empty. Get a human to look, or report the check as incomplete and say what is unverified.
123
+
124
+ → `mcp/docs/api/bulk-content-migration#panel-facing-fields-cannot-be-verified-by-reading`
125
+
128
126
  ## Where to look next
129
127
 
130
- `mcp/docs/server/doc-map` lists every document with a reason to read it. The corpus is **English** — search it in English whatever language you answer in.
128
+ `mcp/docs/server/doc-map` lists every document with a reason to read it, and `mcp/docs/api/content-modelling` covers where content should go. The corpus is **English** — search it in English whatever language you answer in.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oneentry/mcp-platform-server",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "description": "MCP server that lets an AI agent operate the OneEntry Admin API, grounded in the project's own rules",
5
5
  "license": "MIT",
6
6
  "type": "module",