No description
  • Python 99.6%
  • Shell 0.4%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Kate Meerburg 826dfba237
Some checks failed
CI Checks / ci (push) Has been cancelled
CI Checks / Integration tests (latest) (push) Has been cancelled
CI Checks / Integration tests (stable) (push) Has been cancelled
Fix "Handler returned an invalid result" breaking every pre-2026 client
The action tools' outputSchemas declared a ["object", "null"] root, but
the MCP spec types an outputSchema root as literally "object", and
mcp's runner validates every outbound result against the negotiated
protocol version's wire surface - so tools/list itself failed
serialization for every pre-2026-07-28 client (including claude.ai),
surfacing as a bare -32603 "Handler returned an invalid result" on
every request once the write tools became visible. The transport tests
never negotiate an older protocol version, which is how this slipped
through; the new version-sweep regression test runs the runner's exact
serialization for every supported version.

Relatedly, the write endpoints' response bodies aren't uniformly
objects (several actions return a bare null; creating stock with
serial numbers returns a list), which failed the object-typed
output_model *after* a successful write. Those are now wrapped as
{"result": ...} (tools/_common.structured_result), and the action
schemas document the envelope.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QvNkMQJ5j9pKnAh9G7LCmz
2026-08-02 18:13:54 +02:00
.github/workflows Add code coverage in CI 2026-07-27 07:00:31 +00:00
inventree_mcp Fix "Handler returned an invalid result" breaking every pre-2026 client 2026-08-02 18:13:54 +02:00
.gitignore Initial commit 2026-07-26 03:10:56 +00:00
.pre-commit-config.yaml format fixes 2026-07-26 10:41:47 +00:00
AGENTS.md Update to new MCP standard 2026-07-30 03:32:35 +00:00
biome.json Initial commit 2026-07-26 03:10:56 +00:00
codecov.yml Add code coverage in CI 2026-07-27 07:00:31 +00:00
LICENSE Initial commit 2026-07-26 03:10:56 +00:00
MANIFEST.in Initial commit 2026-07-26 03:10:56 +00:00
pyproject.toml Update to new MCP standard 2026-07-30 03:32:35 +00:00
README.md Update README.md 2026-07-30 02:25:42 +00:00
run_tests.sh Run regression tests in CI 2026-07-26 10:48:18 +00:00
setup.cfg Initial commit 2026-07-26 03:10:56 +00:00

InvenTreeMCP

CI codecov

An MCP (Model Context Protocol) server for InvenTree, exposed as an InvenTree plugin. It lets MCP clients (Claude, other MCP-aware agents) query InvenTree inventory data over a Streamable HTTP endpoint.

Design

Every tool is a thin wrapper around InvenTree's own REST API view classes (see inventree_mcp/proxy.py), dispatched as the authenticated caller - MCP requests go through exactly the same permission checks, filtering, and serialization as the regular REST API. Tool code never queries the Django ORM directly.

Currently read-only, covering parts, stock items/locations, part categories, purchase/sales/return/ build orders (with line items and allocations), companies, contacts, addresses, manufacturer/ supplier parts, BOM items, attachments, parameters, stock tracking history, test results, and project codes. Once write tools land, the MCP_READ_ONLY setting (see Configuration) will block them by default regardless of the calling user's permissions.

Each tool's outputSchema and filter/ordering options are derived live from InvenTree's own serializers and views (not hand-maintained), so they can't drift as InvenTree evolves. Call describe_filters(resource) to see what's available for a given resource. The set of tools an MCP client sees is also filtered to what the calling user can actually use - though every call is still permission-checked in full regardless of what was advertised.

Setup

1. Install the plugin

Install via the InvenTree plugin manager, or via pip:

pip install inventree-mcp

Then enable the plugin under Admin > Plugins, and configure its settings (see Configuration below).

2. Create a token for your MCP client

Create an InvenTree API token for your MCP client.

3. Configure your MCP client

The endpoint is <your-inventree-server>/plugin/inventree-mcp/mcp/, using Streamable HTTP transport with an Authorization: Token <token> header.

For a client that supports remote Streamable HTTP servers directly, add:

{
  "mcpServers": {
    "inventree": {
      "url": "https://<your-inventree-server>/plugin/inventree-mcp/mcp/",
      "headers": {
        "Authorization": "Token <your-api-token>"
      }
    }
  }
}

For a client that only supports local (stdio) servers, bridge it with mcp-remote:

{
  "mcpServers": {
    "inventree": {
      "command": "npx",
      "args": [
        "mcp-remote",
        "https://<your-inventree-server>/plugin/inventree-mcp/mcp/",
        "--header",
        "Authorization: Token <your-api-token>"
      ]
    }
  }
}

Configuration

Under Settings > Plugin Settings:

  • Require Authentication (REQUIRE_AUTH, default True): reject unauthenticated requests. Only disable for local testing.
  • Read Only (MCP_READ_ONLY, default True): block all write actions via MCP, regardless of the calling user's permissions. A plugin-wide kill switch, independent of per-user roles.

Authentication

Access follows the calling user's normal InvenTree role assignments. Supported auth methods:

  • An InvenTree API token: Authorization: Token <token>.
  • Basic auth (username/password).
  • An OAuth2 bearer token: Authorization: Bearer <token>. A scoped token (e.g. r:view:part) narrows access below the underlying user's roles - useful for issuing an agent a tightly-scoped token without creating a separate low-privilege user.

Session/cookie auth is not supported (not meaningful for a machine client).