magebitcom / magento2-mcp-catalog-tools
Catalog-domain MCP tools for Magebit_Mcp (read + write over products and categories)
Magento2 MCP - Catalog Tools
This is a sub-module for the Magento2 MCP module
Catalog-domain MCP tools for Magebit_Mcp. Exposes catalog products and
categories — paginated reads, single-entity reads with field-resolver-driven
shape, and writes (create / update / delete) wired through Magento service
contracts.
Each tool is a thin wrapper over the corresponding Magento service contract
(ProductRepositoryInterface, CategoryRepositoryInterface,
CategoryListInterface, StockRegistryInterface,
CategoryManagementInterface). Read responses are composed from field
resolvers that 3rd-party modules can extend; writes go through the same
repositories the admin UI uses, so server-side validation and reindex hooks
fire identically.
Install
composer require magebitcom/magento2-mcp-catalog-tools
bin/magento module:enable Magebit_McpCatalogTools
bin/magento setup:upgrade
bin/magento setup:di:compile
bin/magento cache:flush
Tool catalog
Products (read)
| Tool | What it does |
|---|---|
catalog.product.list |
Paginated product search; filter by sku (exact / *glob* / array), name substring, status, visibility, type_id, attribute_set_id, price range, qty range, category_id, website_id, created_at range, updated_at range, has_special_price (boolean; presence-only, ignores the special-price date window). |
catalog.product.get |
Single product by numeric id or SKU. Default response includes identity, state, pricing, tier prices, stock, categories (ids + names), websites, media gallery, links, configurable / bundle option metadata, configurable child variants (variants — id, sku, name, price, special_price, status per child), custom attributes, and timestamps; narrow with fields / exclude. |
Categories (read)
| Tool | What it does |
|---|---|
catalog.category.list |
Paginated category search; filter by name substring, is_active, include_in_menu, parent_id, level range. |
catalog.category.get |
Single category by numeric id; tree metadata, content, meta, state, plus the product ids assigned to the category (drop with exclude: ["products"]). Reads at global/default scope unless store_id is given. |
Products (write)
Write tools require the global magebit_mcp/general/allow_writes flag and
the token's own allow_writes flag to be 1. All writes require explicit
confirmation so MCP clients prompt before firing.
| Tool | Confirm? | What it does |
|---|---|---|
catalog.product.create |
yes | Create a product. Required: sku, name, price, attribute_set_id, type_id, status, visibility (plus weight for physical types). Accepts top-level scalars (description, url_key, tax_class_id, meta_*) plus custom_attributes, website_ids, category_ids. Values are saved at global/default scope. |
catalog.product.update |
yes | PATCH-style update by id or sku; only fields you provide are touched. Use new_sku to rename. Saves at global/default scope; pass store_code for a deliberate store-view override. |
catalog.product.delete |
yes | Permanently delete a product. |
Stock (write)
| Tool | Confirm? | What it does |
|---|---|---|
catalog.product.stock.set |
yes | Set stock levels and settings for up to 200 SKUs per call: qty, is_in_stock, manage_stock, backorders, min_qty, notify_stock_qty, min_sale_qty, max_sale_qty. Only the fields you pass per item are changed, and setting one clears its use_config_* flag so the value actually takes effect. Reports per-item success or failure, so one bad SKU doesn't fail the batch. |
catalog.product.create also accepts qty / is_in_stock so a new product
lands sellable in one call.
These stock tools target stores with Multi-Source Inventory (MSI) disabled.
They write Magento's legacy single-stock tables via StockRegistryInterface,
which is the whole inventory model on an MSI-free store.
If MSI is enabled, use
Magebit_McpInventoryTools
instead — inventory.source_item.set addresses a specific source, whereas a
legacy write resolves to the default source only. With that module installed,
every result row from catalog.product.stock.set on a multi-source store
carries a warning saying exactly that. Without it the check assumes
single-source and stays quiet; the seam is
Magebit\McpCatalogTools\Api\SingleSourceModeCheckerInterface.
One MSI quirk worth knowing: while MSI is installed it forces min_qty to 0
on read whenever backorders are enabled (AdaptMinQtyToBackordersPlugin), so a
stored threshold reads back as zero. Without MSI the stored value is returned
as written.
Media (write)
| Tool | Confirm? | What it does |
|---|---|---|
catalog.product.media.add |
yes | Upload an image to a product gallery. content_base64 takes the raw bytes base64-encoded, or an RFC 2397 data: URI. JPEG / PNG / GIF, 8 MB max. |
catalog.product.media.update |
yes | PATCH-style metadata update by entry_id — label, position, disabled, types. The file itself is not replaceable; remove and re-add. |
catalog.product.media.remove |
yes | Permanently remove a gallery entry. The file is deleted, not just unlinked. |
The image type is detected from the decoded bytes, never from the supplied
filename — a payload that doesn't decode as a real image is rejected, and the
stored extension is derived from the sniffed type. Filenames are stripped of
path components before use.
Which types are accepted is decided by Magento's own
Magento\Framework\Api\ImageContentValidator, the same service the gallery
save uses, so a store that widens that allowlist through di.xml widens this
tool with it. Out of the box that means JPEG, PNG and GIF — not WebP.
Known Magento behaviour: catalog.product.media.update goes through
ProductAttributeMediaGalleryManagementInterface::update(), which re-copies the
image file on every call (photo.jpg becomes photo_1.jpg, then
photo_1_1.jpg). The gallery entry keeps its id and points at the newest file;
the previous file is left on disk. This is Magento's behaviour, not this
module's — budget for it if you script bulk metadata updates.
types assigns image roles (image, small_image, thumbnail,
swatch_image). Each role belongs to one image at a time, so assigning it here
removes it from whichever image held it before.
Request size. Base64 inflates a file by roughly a third, and the MCP
endpoint caps request bodies at 256 KB by default. For real product photos raise
Stores → Configuration → Magebit → MCP Server → Max Request Body (KB) (an
8 MB image needs about 11000) and raise the matching web-server limit —
nginx client_max_body_size or Apache LimitRequestBody — otherwise the upload
is rejected before Magento sees it.
Categories (write)
| Tool | Confirm? | What it does |
|---|---|---|
catalog.category.create |
yes | Create a category under an existing parent. Values are saved at global/default scope. |
catalog.category.update |
yes | PATCH-style update by id. Changing parent_id triggers a tree move via CategoryManagementInterface::move() (path / level rebuild); use after_id to control sibling ordering at the destination. Saves at global/default scope; pass store_id for a deliberate store-view override. |
catalog.category.delete |
yes | Permanently delete a category and its descendants. Cascades. |
Every write tool also implements Magebit\Mcp\Api\UnderlyingAclAwareInterface
with Magento_Catalog::products / Magento_Catalog::categories as the
underlying Magento admin resource, so they block calls from admins who
wouldn't be allowed to perform the same action in the admin UI.
Upgrade notes
- Global-scope writes by default.
catalog.product.create/
catalog.product.updateandcatalog.category.create/
catalog.category.updatenow save attribute values at global/default
scope, matching REST/all/V1/products. Previously, calling these tools
from the frontend area silently wrote store-view override rows instead of
updating the default value.catalog.product.updategained an optional
store_codeargument (a store view code, or"all"/omitted for global)
for intentional store-view overrides;catalog.category.updatekeeps its
existing integerstore_idargument for the same purpose (categories are
always created at global scope — there is no store-scoped
catalog.category.create). Override rows created by earlier versions of
these tools are not repaired automatically — reapply the desired value at
global scope (or the correct store view) if you need to clean one up.
catalog.product.getreads the resolved store view, so a pre-existing
store-view override row will still mask a newly written global value when
reading back — such overrides are not repaired automatically. catalog.category.getreads true admin scope by default. Without a
store_id, the tool now reads at admin/default scope as documented. One
consequence: theproducts.product_idsslice always lists every product
assigned to the category, not a store-view-filtered subset — pass
exclude: ["products"]if you don't need it.catalog.product.listhas a newhas_special_pricefilter — boolean,
presence-only (it does not evaluatespecial_from_date/
special_to_date).catalog.product.gethas a newvariantsslice for configurable
products: id, sku, name, price, special_price, and status for each child.
Extending
See docs/EXTENDING.md for:
- adding a new field to any tool response via
ProductFieldResolverInterface
/CategoryFieldResolverInterface; - adding a new filter to
catalog.product.list/catalog.category.list
viaProductFilterTranslatorInterface/
CategoryFilterTranslatorInterface; - the ACL layering rules for custom write tools.
License
Released under the MIT License.
Magebit - Full-service e-commerce agency
No changelog yet
The vendor hasn't published a changelog. Tagged releases appear in the Versions tab.
| Version | Stability | QA Status | Compatibility | Released |
|---|---|---|---|---|
| v1.2.1 | stable | Fail | Magento 2.4.7-2.4.9 Details | 2026-08-19 10:15:46 |
| v1.2.0 | stable | Fail | Magento 2.4.7-2.4.9 Details | 2026-08-13 11:42:29 |
| v1.1.1 | stable | Fail | Magento 2.4.7-2.4.9 Details | 2026-08-05 08:59:46 |
| v1.1.0 | stable | Not tested | Not yet tested Details | 2026-08-05 08:59:46 |
| v1.0.0 | stable | Fail | Magento 2.4.7-2.4.9 Details | 2026-05-27 08:34:14 |
| v0.0.2 | stable | Not tested | Not yet tested Details | 2026-05-11 17:10:21 |
| v0.0.1 | stable | Not tested | Not yet tested Details | 2026-05-06 09:49:01 |
Requires 3
| Package | Constraint |
|---|---|
| magebitcom/magento2-mcp-module | ^1.1 |
| magento/framework | ^103.0 |
| php | >=8.1 |
Compatibility
Each Magento release line is installed on its supported PHP versions, then the module is built (DI compilation + static-content deploy) and its unit and integration suites are run. The matrix shows the lines and PHP versions the module is confirmed to install and run on. Code-quality results further down (phpstan, phpcs, …) are reported separately and never affect compatibility.
Code Quality
Advisory checks against the module's source. Static analysis runs once across the whole module; PHPStan re-runs per Magento + PHP version because resolvable symbols differ between releases. These NEVER affect the Compatibility badge. A phpcs finding can't make a module incompatible.
Static analysis
Coding standards (phpcs), mess detection (phpmd), copy-pasted code (cpd), PHP cross-version compatibility, composer.json validity. Each runs once for the whole module.
| Tool | Status | Findings | Summary |
|---|---|---|---|
| PHPCS | Fail | 64 | 31 errors, 33 warnings (ruleset: Magento2), 7 auto-fixable with phpcbf |
| PHPMD | Warning | 29 | 29 rule violations (UnusedPrivateField:29) |
| Cpd | Warning | 7 | 7 duplicated chunks spanning 327 total lines (min-lines=5, min-tokens=70) |
| Composer validate | Pass | 0 |
PHPStan
Type-checks the module's PHP against a real Magento install at the configured gate level. Re-runs per Magento and PHP version because resolvable symbols differ between releases.
Tests
Unit and integration suites, run for each applicable Magento and PHP version. A test failure speaks to the module's behaviour, not its compatibility with a Magento line, so it is reported here separately and never reddens the compatibility matrix.
Unit tests
Integration tests
| Magento | PHP 8.2 | PHP 8.3 | PHP 8.4 | PHP 8.5 |
|---|---|---|---|---|
| 2.4.7 | N/A | N/A | ||
| 2.4.8 | N/A | N/A | ||
| 2.4.9 | N/A | N/A |
Security
Security checks run directly against the module: an audit of its declared dependencies for known vulnerabilities (composer audit) and a scan of its source for malware and web-shell signatures. Each runs once. A malware detection fails the version outright.
More from magebitcom
View vendorMagebit Agentic Commerce extension
Magebit Universal Commerce extension
Module documentation viewer for Magento 2 admin
This module enables Montonio Hirepurchase with Hyva Checkout
Turn an existing module into recurring revenue.
If you already maintain a Magento 2 module on GitHub or GitLab, listing it on Packagento takes about five minutes. We mirror your tags, handle distribution signing, and route paid licenses through Stripe Connect, so you can keep shipping the way you already do.