Appearance
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 APIs | Your declared AI tools | |
|---|---|---|
| Who calls it | Any authorized caller | The platform's AI assistant, on a user's behalf |
| Default | Every endpoint you write | None — opt-in only |
| Where it's declared | Your controller code | metadata/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.codeCommon mistakes
| Symptom | Cause | Fix |
|---|---|---|
| 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 exists | toolCode collides with a manually-created tool or another plugin's tool | Pick a more specific, namespaced toolCode (e.g. <your-plugin>.<noun>.<verb>) |
| Tool still callable after uninstall | You're checking a cached list | Tools are deactivated, not deleted — re-query the discovery endpoint |
| AI never calls your tool | requiredPermission the calling user lacks, or riskLevel/policy gating it out | Check the user's actual permission grant first |
What to read next
- Use the MCP server with an AI agent — the other MCP concept: grounding your coding agent while you build, not this guide's runtime AI-tool-calling
- Create a plugin from scratch