Skip to content

Expose a plugin operation as an AI tool

What you're doing

This is different from Use the MCP server with an AI agent — that guide is about your coding agent (Claude Code, Cursor) getting grounded while it writes your plugin. This guide is about the ERP product's own embedded AI assistant calling your plugin's real operations for an end user, at runtime, once your plugin is installed.

Declare which of your plugin's REST endpoints are safe for the AI to call, under what permission, with what risk level. The platform reads this at install time and registers real, callable tools — no separate admin step, no retraining, no hand-written tool-registry entry.

Your plugin's REST APIsYour declared AI tools
Who calls itAny authorized callerThe platform's AI assistant, on a user's behalf
DefaultEvery endpoint you writeNone — opt-in only
Where it's declaredYour controller codemetadata/tool/*.json files

Never expose every endpoint automatically. An internal cache-clear endpoint or an admin-only bulk-delete has no business being AI-callable just because it exists — only declare the operations you've deliberately decided are safe for an AI to invoke on a user's behalf.

The file

One JSON file per tool, under your plugin's metadata/tool/ directory — same convention as metadata/page/, metadata/form/, metadata/provider/. Real, shipped example — hello-plugin's own metadata/tool/hello.greeting.get.json:

json
{
  "toolCode": "hello.greeting.get",
  "name": "Get Hello Greeting",
  "description": "Returns hello-plugin's demo greeting for the current tenant.",
  "inputSchema": { "type": "object", "properties": {} },
  "handlerType": "REST",
  "handlerConfig": {
    "path": "/api/v1/plugins/hello-plugin/greeting",
    "method": "GET"
  },
  "requiredPermission": "HELLO_PLUGIN_DEMO",
  "applicationCode": "hello-plugin",
  "riskLevel": "LOW",
  "strictPermissionCheck": false
}

handlerConfig also accepts pathParams/queryParams (input keys substituted into the path/query string) and bodyFromInput: true (the whole input map sent as a POST body) — see hcm-ai-intelligence's own 18 tool files for real examples of each, including a real cross-plugin one (employee.search calling hcm-employee's own endpoint, not hcm-ai-intelligence's own namespace — a deliberately supported pattern for an AI-assistant module that fronts several other plugins).

The namespace rule

handlerConfig.path must be under /api/v1/plugins/** (any plugin's own namespace) or /api/v1/entities/** (the Entity Engine data API). A tool pointed at an internal/admin/authoring route is rejected at install — before your plugin touches anything else.

Ownership

Re-installing/upgrading your own plugin re-registers your own tools idempotently. Declaring a toolCode another plugin already owns — or one that was created manually outside any plugin — fails install with a clear error; tool codes aren't a shared free-for-all namespace.

Disabling or uninstalling your plugin deactivates its tools (not a hard delete) — re-enabling reactivates them.

Ground yourself first

bash
erp_get_schema {"name":"plugin-manifest"}

Look at hcm-ai-intelligence's real metadata/tool/*.json files for the fullest working example of pathParams/queryParams/bodyFromInput in practice, and for riskLevel: "HIGH" + strictPermissionCheck: true pairing on a genuinely mutating operation.

How to verify it worked

Install your plugin, then check the discovery endpoint lists your tool:

bash
curl localhost:8080/api/v1/agents/metadata/tools \
  -H "X-Tenant-Id: <id>" -H "X-Actor: <actor>" | grep your.tool.code

Common mistakes

SymptomCauseFix
Install fails: "not under an allowed namespace"handlerConfig.path points outside /api/v1/plugins/** or /api/v1/entities/**An AI tool can only call a real plugin business endpoint or the Entity Engine, never an internal/admin route
Install fails: tool already existstoolCode collides with a manually-created tool or another plugin's toolPick a more specific, namespaced toolCode (e.g. <your-plugin>.<noun>.<verb>)
Tool still callable after uninstallYou're checking a cached listTools are deactivated, not deleted — re-query the discovery endpoint
AI never calls your toolrequiredPermission the calling user lacks, or riskLevel/policy gating it outCheck the user's actual permission grant first