Custom Tools
Connect your own service's API as tools your agents can call. You define typed endpoints; m8tes exposes each one to the agent as a named tool and makes the call for you: IP-pinned, with your secret injected server-side and never exposed to the agent.
Use custom tools when the app you need isn't in the catalog and you already have a REST API for it.
m8tes runs the MCP server for you — you supply the endpoints, your agents get typed tools.
Building this into your own product, one agent per customer? See Your API as MCP tools for the end-to-end embed recipe, or Take actions in your product for the single-tenant version.
Create a custom tool
Each entry in tool_defs becomes a tool the agent sees by name (get_invoice, create_refund). Put {param} in a path to make it an argument (/invoices/{id}); any other arguments the agent passes go to the query string (GET/DELETE) or the JSON body (POST/PUT/PATCH). In the dashboard each tool_def shows as an Action ("Add action" adds one), but the SDK param name stays tool_defs.
Attach to an agent
Reference the server's slug in the agent's tools list, alongside catalog tools:
In the dashboard, open Apps → Add custom tool to create one, then enable it on an agent from its Configure → Custom tools section.
An agent can also propose a custom tool mid-run: it surfaces as a permission approval the owner approves or denies before the tool is created.
Authentication
The secret is encrypted at rest and injected by m8tes when it makes the call. Pick the auth_type your API expects:
Permissions
Read-only tools never ask. A GET tool def runs immediately, in every permission mode — it can't mutate anything, so it is treated like any other read. Plan for this: if a lookup against your API is itself sensitive, don't model it as GET, and don't rely on an approval prompt to gate it.
Write tools ask before each use, so a human stays in the loop on anything that changes state. To let a write run unattended (in scheduled tasks, webhook/email triggers, or API runs where nobody is watching), mark the server trusted: set the "Run without asking each time" toggle when you add it, or pass auto_approve=true to client.mcp_servers.create/update. An untrusted write pauses for approval; in an unattended run with no one to approve, the run is marked needs-approval, never silently failed.
Trust is per server, not per tool, so the usual shape is two servers against the same API: one holding the GET defs, one holding the writes you want gated.
Security model
- Egress is server-side and IP-pinned. The agent never connects to your service directly. m8tes resolves and pins the host to a validated public IP per call (no DNS-rebind), disables redirects, and caps the response. Private/metadata addresses are blocked.
- The secret never reaches the agent. It is injected into the outbound request by m8tes and scrubbed from any echoed response. API responses carry only
has_secret, never the value. - Strictly scoped. A custom tool is visible only to its owner (and, for multi-tenant setups, the
user_idend-user it was created for).
Manage
Next: Your API as MCP tools · Take actions in your product · Human-in-the-loop · Users
