Core CRUD
Endpoints for listing, reading, creating, updating, and deleting Toolkits.
A Toolkit is a driver-backed entity: its serialized shape carries the driver's
descriptor (allowUserInstances, executionLocation, canManageTools) and
embeds the driver itself under inf:driver. Read access is enforced by the
read_access model scope rather than a permission, so list and lookup routes
return only the toolkits the caller may see, each with a permissions object
describing what the caller can do.
The plain paged collection (GET /api/toolkits) is not gated by AI access. The
flat list, the single-toolkit lookup, and the write routes require AI access via
ai.verify, so AI must be enabled on the tenant for those.
GET /api/toolkits
List toolkits as a paged HAL collection, sorted by name.
Authentication: Required
Response:
A HAL collection (the db.query handler over the Toolkit model with the
read_access scope). Toolkit rows are embedded under _embedded["inf:toolkit"],
each eager-loading its integration association and embedding its driver under
inf:driver. The envelope carries start, count, and total. This route is
not gated by ai.verify.
Each row carries the driver descriptor fields (naturalId, allowUserInstances,
executionLocation, canManageTools), a permissions object, and the stored
columns (id, name, slug, type, description, instructions, ownerId,
shared, folderId, config, integrationId, source, sourceId,
timestamps).
{
"_links": {
"self": {
"href": "https://informer.example.com/api/toolkits"
}
},
"start": 0,
"count": 3,
"total": 3,
"_embedded": {
"inf:toolkit": [
{
"_links": {
"self": {
"href": "https://informer.example.com/api/toolkits/admin%3Afilesystem-tools"
},
"inf:toolkit-share": {
"href": "https://informer.example.com/api/toolkits/admin%3Afilesystem-tools/shares/{principalId}",
"templated": true
},
"inf:favorite": {
"href": "https://informer.example.com/api/toolkits/admin%3Afilesystem-tools/favorite"
},
"inf:toolkit-owner": {
"href": "https://informer.example.com/api/toolkits/admin%3Afilesystem-tools/owner"
},
"inf:toolkit-shares": {
"href": "https://informer.example.com/api/toolkits/admin%3Afilesystem-tools/shares"
},
"inf:toolkit-tools": {
"href": "https://informer.example.com/api/toolkits/admin%3Afilesystem-tools/tools"
},
"inf:toolkit-discover": {
"href": "https://informer.example.com/api/toolkits/admin%3Afilesystem-tools/discover"
}
},
"naturalId": "admin:filesystem-tools",
"allowUserInstances": true,
"executionLocation": "server",
"canManageTools": true,
"permissions": {
"write": true,
"edit": true,
"delete": true,
"share": true,
"assignTags": true,
"changeOwner": true
},
"id": "00000000-0000-4000-8000-000000000001",
"name": "Filesystem Tools",
"slug": "filesystem-tools",
"type": "custom",
"description": "Local filesystem operations exposed to the assistant.",
"instructions": "Use these tools to read and write files in the workspace.",
"ownerId": "admin",
"shared": true,
"folderId": null,
"config": {},
"integrationId": null,
"source": null,
"sourceId": null,
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z",
"tenant": "acme",
"integration": null,
"_embedded": {
"inf:driver": {
"_links": {
"self": {
"href": "https://informer.example.com/api/toolkits/admin%3Afilesystem-tools/driver"
}
},
"id": "custom",
"name": "Integration Toolkit",
"description": "Create API tools that call external services via an Integration",
"image": "/images/icons/toolkit-server.svg",
"viewComponent": "customToolkitView",
"executionLocation": "server",
"allowUserInstances": true,
"canManageTools": true,
"supportsIntegration": true,
"editorComponent": {}
}
}
},
{
"_links": {
"self": {
"href": "https://informer.example.com/api/toolkits/admin%3Agithub-integration"
},
"inf:toolkit-share": {
"href": "https://informer.example.com/api/toolkits/admin%3Agithub-integration/shares/{principalId}",
"templated": true
},
"inf:favorite": {
"href": "https://informer.example.com/api/toolkits/admin%3Agithub-integration/favorite"
},
"inf:toolkit-owner": {
"href": "https://informer.example.com/api/toolkits/admin%3Agithub-integration/owner"
},
"inf:toolkit-shares": {
"href": "https://informer.example.com/api/toolkits/admin%3Agithub-integration/shares"
},
"inf:toolkit-tools": {
"href": "https://informer.example.com/api/toolkits/admin%3Agithub-integration/tools"
},
"inf:toolkit-discover": {
"href": "https://informer.example.com/api/toolkits/admin%3Agithub-integration/discover"
}
},
"naturalId": "admin:github-integration",
"allowUserInstances": true,
"executionLocation": "server",
"canManageTools": true,
"permissions": {
"write": true,
"edit": true,
"delete": true,
"share": true,
"assignTags": true,
"changeOwner": true
},
"id": "00000000-0000-4000-8000-000000000002",
"name": "GitHub Integration",
"slug": "github-integration",
"type": "custom",
"description": "Access GitHub repositories and issues.",
"instructions": null,
"ownerId": "admin",
"shared": false,
"folderId": null,
"config": null,
"integrationId": null,
"source": null,
"sourceId": null,
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z",
"tenant": "acme",
"integration": null,
"_embedded": {
"inf:driver": {
"_links": {
"self": {
"href": "https://informer.example.com/api/toolkits/admin%3Agithub-integration/driver"
}
},
"id": "custom",
"name": "Integration Toolkit",
"description": "Create API tools that call external services via an Integration",
"image": "/images/icons/toolkit-server.svg",
"viewComponent": "customToolkitView",
"executionLocation": "server",
"allowUserInstances": true,
"canManageTools": true,
"supportsIntegration": true,
"editorComponent": {}
}
}
},
{
"_links": {
"self": {
"href": "https://informer.example.com/api/toolkits/admin%3Ascratch-toolkit"
},
"inf:toolkit-share": {
"href": "https://informer.example.com/api/toolkits/admin%3Ascratch-toolkit/shares/{principalId}",
"templated": true
},
"inf:favorite": {
"href": "https://informer.example.com/api/toolkits/admin%3Ascratch-toolkit/favorite"
},
"inf:toolkit-owner": {
"href": "https://informer.example.com/api/toolkits/admin%3Ascratch-toolkit/owner"
},
"inf:toolkit-shares": {
"href": "https://informer.example.com/api/toolkits/admin%3Ascratch-toolkit/shares"
},
"inf:toolkit-tools": {
"href": "https://informer.example.com/api/toolkits/admin%3Ascratch-toolkit/tools"
},
"inf:toolkit-discover": {
"href": "https://informer.example.com/api/toolkits/admin%3Ascratch-toolkit/discover"
}
},
"naturalId": "admin:scratch-toolkit",
"allowUserInstances": true,
"executionLocation": "server",
"canManageTools": true,
"permissions": {
"write": true,
"edit": true,
"delete": true,
"share": true,
"assignTags": true,
"changeOwner": true
},
"id": "00000000-0000-4000-8000-000000000003",
"name": "Scratch Toolkit",
"slug": "scratch-toolkit",
"type": "custom",
"description": null,
"instructions": null,
"ownerId": "admin",
"shared": false,
"folderId": null,
"config": null,
"integrationId": null,
"source": null,
"sourceId": null,
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z",
"tenant": "acme",
"integration": null,
"_embedded": {
"inf:driver": {
"_links": {
"self": {
"href": "https://informer.example.com/api/toolkits/admin%3Ascratch-toolkit/driver"
}
},
"id": "custom",
"name": "Integration Toolkit",
"description": "Create API tools that call external services via an Integration",
"image": "/images/icons/toolkit-server.svg",
"viewComponent": "customToolkitView",
"executionLocation": "server",
"allowUserInstances": true,
"canManageTools": true,
"supportsIntegration": true,
"editorComponent": {}
}
}
}
]
}
}
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
name | string | Filter by toolkit name |
type | string | Filter by toolkit type |
slug | string | Filter by slug |
GET /api/toolkits-list
List toolkits as a flat array. This is the UI-optimized list (no pagination envelope), built from a raw SQL query.
Authentication: Required
Pre-blocks: ai.verify (AI enabled on the tenant AND the caller has AI access)
Response:
A bare JSON array, not a HAL collection. Each row is a richer shape than the
paged collection's rows: alongside the stored columns it carries naturalId,
favorite (boolean), a permissions object, username, ownerName, and the
request-injected tags and sharing arrays.
[
{
"id": "00000000-0000-4000-8000-000000000001",
"name": "Filesystem Tools",
"type": "custom",
"description": "Local filesystem operations exposed to the assistant.",
"shared": true,
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z",
"ownerId": "admin",
"folderId": null,
"integrationId": null,
"username": "admin",
"favorite": false,
"naturalId": "admin:filesystem-tools",
"permissions": {
"write": true,
"edit": true,
"delete": true,
"share": true,
"assignTags": true,
"changeOwner": true
},
"ownerName": "acme Administrator",
"tags": [],
"sharing": []
},
{
"id": "00000000-0000-4000-8000-000000000002",
"name": "GitHub Integration",
"type": "custom",
"description": "Access GitHub repositories and issues.",
"shared": false,
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z",
"ownerId": "admin",
"folderId": null,
"integrationId": null,
"username": "admin",
"favorite": false,
"naturalId": "admin:github-integration",
"permissions": {
"write": true,
"edit": true,
"delete": true,
"share": true,
"assignTags": true,
"changeOwner": true
},
"ownerName": "acme Administrator",
"tags": [],
"sharing": []
},
{
"id": "00000000-0000-4000-8000-000000000003",
"name": "Scratch Toolkit",
"type": "custom",
"description": null,
"shared": false,
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z",
"ownerId": "admin",
"folderId": null,
"integrationId": null,
"username": "admin",
"favorite": false,
"naturalId": "admin:scratch-toolkit",
"permissions": {
"write": true,
"edit": true,
"delete": true,
"share": true,
"assignTags": true,
"changeOwner": true
},
"ownerName": "acme Administrator",
"tags": [],
"sharing": []
}
]
GET /api/toolkits/{id}
Get a single toolkit.
Authentication: Required
Pre-blocks: toolkit.lookup(params.id) (runs ai.verify, then resolves the toolkit via read_access)
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
id | string | Raw UUID or the natural id ownerId:slug; both resolve the same row |
Response:
The toolkit with its driver descriptor fields and permissions object. The
driver is embedded under _embedded["inf:driver"], and the toolkit links to its
tools (inf:toolkit-tools), owner (inf:toolkit-owner), shares
(inf:toolkit-shares, inf:toolkit-share), favorite (inf:favorite), and
discovery (inf:toolkit-discover) rels.
{
"_links": {
"self": {
"href": "https://informer.example.com/api/toolkits/00000000-0000-4000-8000-000000000001"
},
"inf:toolkit-share": {
"href": "https://informer.example.com/api/toolkits/00000000-0000-4000-8000-000000000001/shares/{principalId}",
"templated": true
},
"inf:favorite": {
"href": "https://informer.example.com/api/toolkits/00000000-0000-4000-8000-000000000001/favorite"
},
"inf:toolkit-owner": {
"href": "https://informer.example.com/api/toolkits/admin%3Afilesystem-tools/owner"
},
"inf:toolkit-shares": {
"href": "https://informer.example.com/api/toolkits/admin%3Afilesystem-tools/shares"
},
"inf:toolkit-tools": {
"href": "https://informer.example.com/api/toolkits/admin%3Afilesystem-tools/tools"
},
"inf:toolkit-discover": {
"href": "https://informer.example.com/api/toolkits/00000000-0000-4000-8000-000000000001/discover"
}
},
"naturalId": "admin:filesystem-tools",
"allowUserInstances": true,
"executionLocation": "server",
"canManageTools": true,
"permissions": {
"write": true,
"edit": true,
"delete": true,
"share": true,
"assignTags": true,
"changeOwner": true
},
"id": "00000000-0000-4000-8000-000000000001",
"name": "Filesystem Tools",
"slug": "filesystem-tools",
"type": "custom",
"description": "Local filesystem operations exposed to the assistant.",
"instructions": "Use these tools to read and write files in the workspace.",
"ownerId": "admin",
"shared": true,
"folderId": null,
"config": {},
"integrationId": null,
"source": null,
"sourceId": null,
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z",
"tenant": "acme",
"integration": null,
"_embedded": {
"inf:driver": {
"_links": {
"self": {
"href": "https://informer.example.com/api/toolkits/00000000-0000-4000-8000-000000000001/driver"
}
},
"id": "custom",
"name": "Integration Toolkit",
"description": "Create API tools that call external services via an Integration",
"image": "/images/icons/toolkit-server.svg",
"viewComponent": "customToolkitView",
"executionLocation": "server",
"allowUserInstances": true,
"canManageTools": true,
"supportsIntegration": true,
"editorComponent": {}
}
}
}
POST /api/toolkits
Create a toolkit.
Authentication: Required
Pre-blocks:
permission.toolkits.create(isDataWizard)checkToolkitPlan(a qualifying AI plan: Pro, Max, Max+, or BYOK)
Admins bypass both gates.
Request Body:
The payload is stripUnknown, so unrecognized fields are dropped rather than
rejected.
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Toolkit display name |
type | string | Yes | Toolkit type (mcp-stdio, mcp-remote, custom, informer) |
description | string | No | Toolkit description |
instructions | string | No | Usage instructions for the assistant |
config | object | No | Type-specific configuration |
integrationId | string | No | Associated Integration id (for OAuth) |
oauth | object | No | OAuth configuration (creates an Integration if not provided) |
shared | boolean | No | Team-shared toolkit (default false) |
slug is not accepted. The insert_unique_owner_slug database trigger
derives a unique slug from name, so any client-supplied slug is silently
dropped. ownerId is set to the caller's username.
Example Request (custom):
{
"name": "Workspace Files",
"type": "custom",
"description": "Local filesystem operations.",
"instructions": "Use these tools to read and write files in the workspace.",
"config": {},
"shared": true
}
Example Request (MCP remote with OAuth):
{
"name": "GitHub Toolkit",
"type": "mcp-remote",
"description": "GitHub API integration",
"config": {
"url": "https://mcp.github.com",
"transport": "sse"
},
"oauth": {
"resourceName": "GitHub",
"authorizationEndpoint": "https://github.com/login/oauth/authorize",
"tokenEndpoint": "https://github.com/login/oauth/access_token",
"scopes": ["repo", "read:user"],
"clientId": "your-client-id",
"clientSecret": "your-client-secret"
},
"shared": true
}
Response:
Responds 201 Created with the toolkit (driver embedded, derived slug) and a
Location header.
{
"name": "Workspace Files",
"type": "custom",
"description": "Local filesystem operations.",
"instructions": "Use these tools to read and write files in the workspace.",
"config": {},
"shared": true
}
{
"_links": {
"self": {
"href": "https://informer.example.com/api/toolkits/admin%3Aworkspace-files"
},
"inf:toolkit-share": {
"href": "https://informer.example.com/api/toolkits/admin%3Aworkspace-files/shares/{principalId}",
"templated": true
},
"inf:favorite": {
"href": "https://informer.example.com/api/toolkits/admin%3Aworkspace-files/favorite"
},
"inf:toolkit-owner": {
"href": "https://informer.example.com/api/toolkits/admin%3Aworkspace-files/owner"
},
"inf:toolkit-shares": {
"href": "https://informer.example.com/api/toolkits/admin%3Aworkspace-files/shares"
},
"inf:toolkit-tools": {
"href": "https://informer.example.com/api/toolkits/admin%3Aworkspace-files/tools"
},
"inf:toolkit-discover": {
"href": "https://informer.example.com/api/toolkits/admin%3Aworkspace-files/discover"
}
},
"naturalId": "admin:workspace-files",
"allowUserInstances": true,
"executionLocation": "server",
"canManageTools": true,
"permissions": {
"write": true,
"edit": true,
"delete": true,
"share": true,
"assignTags": true,
"changeOwner": true
},
"id": "00000000-0000-4000-8000-000000000001",
"tenant": "acme",
"name": "Workspace Files",
"type": "custom",
"description": "Local filesystem operations.",
"instructions": "Use these tools to read and write files in the workspace.",
"config": {},
"shared": true,
"integrationId": null,
"ownerId": "admin",
"updatedAt": "2026-01-15T16:20:00.000Z",
"createdAt": "2026-01-15T16:20:00.000Z",
"slug": "workspace-files",
"folderId": null,
"source": null,
"sourceId": null,
"_embedded": {
"inf:driver": {
"_links": {
"self": {
"href": "https://informer.example.com/api/toolkits/admin%3Aworkspace-files/driver"
}
},
"id": "custom",
"name": "Integration Toolkit",
"description": "Create API tools that call external services via an Integration",
"image": "/images/icons/toolkit-server.svg",
"viewComponent": "customToolkitView",
"executionLocation": "server",
"allowUserInstances": true,
"canManageTools": true,
"supportsIntegration": true,
"editorComponent": {}
}
}
}
OAuth Integration:
If oauth is provided without integrationId, an OAuth Integration is created
automatically, using Dynamic Client Registration (DCR) when the server supports
it.
Creating toolkits requires a Pro, Max, Max+, or BYOK AI plan. Users on a plan
that does not qualify receive 403 Forbidden. Admins bypass the plan and role
gates.
PUT /api/toolkits/{id}
Update a toolkit.
Authentication: Required
Pre-blocks: toolkit.lookup(params.id), then permission.toolkit.write (isDataWizard on the toolkit)
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
id | string | Raw UUID or the natural id ownerId:slug |
Request Body:
The payload is stripUnknown.
| Field | Type | Description |
|---|---|---|
name | string | Update name |
slug | string | Update slug |
description | string | null | Update description (null clears it) |
instructions | string | null | Update instructions (null clears it) |
config | object | null | Update configuration (null clears it) |
integrationId | string | null | Change Integration (null clears it) |
shared | boolean | Toggle team sharing |
Example Request:
{
"description": "Access GitHub repositories, issues, and pull requests.",
"shared": true
}
Response:
Responds 200 with the re-fetched toolkit. Runs in a database transaction.
{
"description": "Access GitHub repositories, issues, and pull requests.",
"shared": true
}
{
"_links": {
"self": {
"href": "https://informer.example.com/api/toolkits/00000000-0000-4000-8000-000000000001"
},
"inf:toolkit-share": {
"href": "https://informer.example.com/api/toolkits/00000000-0000-4000-8000-000000000001/shares/{principalId}",
"templated": true
},
"inf:favorite": {
"href": "https://informer.example.com/api/toolkits/00000000-0000-4000-8000-000000000001/favorite"
},
"inf:toolkit-owner": {
"href": "https://informer.example.com/api/toolkits/admin%3Agithub-integration/owner"
},
"inf:toolkit-shares": {
"href": "https://informer.example.com/api/toolkits/admin%3Agithub-integration/shares"
},
"inf:toolkit-tools": {
"href": "https://informer.example.com/api/toolkits/admin%3Agithub-integration/tools"
},
"inf:toolkit-discover": {
"href": "https://informer.example.com/api/toolkits/00000000-0000-4000-8000-000000000001/discover"
}
},
"naturalId": "admin:github-integration",
"allowUserInstances": true,
"executionLocation": "server",
"canManageTools": true,
"permissions": {
"write": true,
"edit": true,
"delete": true,
"share": true,
"assignTags": true,
"changeOwner": true
},
"id": "00000000-0000-4000-8000-000000000001",
"name": "GitHub Integration",
"slug": "github-integration",
"type": "custom",
"description": "Access GitHub repositories, issues, and pull requests.",
"instructions": null,
"ownerId": "admin",
"shared": true,
"folderId": null,
"config": null,
"integrationId": null,
"source": null,
"sourceId": null,
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z",
"tenant": "acme",
"integration": null,
"_embedded": {
"inf:driver": {
"_links": {
"self": {
"href": "https://informer.example.com/api/toolkits/00000000-0000-4000-8000-000000000001/driver"
}
},
"id": "custom",
"name": "Integration Toolkit",
"description": "Create API tools that call external services via an Integration",
"image": "/images/icons/toolkit-server.svg",
"viewComponent": "customToolkitView",
"executionLocation": "server",
"allowUserInstances": true,
"canManageTools": true,
"supportsIntegration": true,
"editorComponent": {}
}
}
}
DELETE /api/toolkits/{id}
Delete a toolkit permanently.
Authentication: Required
Pre-blocks: toolkit.lookup(params.id), then permission.toolkit.delete (admin or the toolkit owner)
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
id | string | Raw UUID or the natural id ownerId:slug |
Response:
Responds 200 with an empty body (Informer convention), not 204. Runs in a
database transaction.
This permanently removes the toolkit and cascades to its tools, shares, and chat/agent associations. This cannot be undone.
Toolkit Types
A toolkit's type selects its driver. The config shape is type-specific.
mcp-stdio
Local MCP server running as a subprocess:
{
"type": "mcp-stdio",
"config": {
"command": "node",
"args": ["server.js"]
}
}
mcp-remote
Remote MCP server over HTTP/SSE:
{
"type": "mcp-remote",
"config": {
"url": "https://mcp.example.com",
"transport": "sse",
"headers": {
"X-API-Key": "secret"
}
}
}
custom
User-defined tools that call external services through an Integration:
{
"type": "custom",
"config": {}
}
informer
Built-in Informer tools (no configuration needed).