Skip to content

Register a tool manifest

View as Markdown
POST
/v1/tools
curl --request POST \
--url https://example.com/v1/tools \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{ "id": "example", "projectId": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0", "description": "example", "version": "example", "input": {}, "output": {}, "needs": [ { "name": "example", "optional": true } ], "effects": [ { "kind": "reads", "resource": "example", "notes": "example" } ], "transport": "auto", "mcpEndpoint": "example", "metadata": {}, "mutating": true, "needsApprovalWhenUnattended": true, "sandbox": "none", "limits": { "memMB": 1, "cpuMs": 1 }, "network": { "kind": "none" }, "needsSpec": { "env": { "additionalProperty": {} }, "secrets": { "additionalProperty": {} }, "config": { "additionalProperty": {} }, "capabilities": [ "example" ], "bindings": [ "example" ] }, "codeArtifactRef": { "kind": "oci", "imageRef": "example", "modulePath": "example", "artifactVersion": "example" }, "spec": { "kind": "http", "method": "GET", "urlTemplate": "example", "headers": [ { "name": "example", "value": "example" } ], "authorization": { "kind": "bearer", "secretRef": { "envName": "example", "name": "example" } }, "requestBody": { "kind": "json-input" }, "timeoutMs": 1, "parseJson": true, "successStatus": { "min": 1, "max": 1 } } }'

Body is a ToolManifest (Tool minus its runtime handler). Server validates via @kindgi/tools.validateToolManifest. Metadata only: the handler is not uploaded through this route and must already be available to the runtime. A tool never gets a model provider’s key: one that declares (needsSpec.secrets) or sends (spec.authorization.secretRef) a secret a provider registration of the tenant names, in any env, is refused. Where each secret it names is read is recorded on the version (secretScopes): the first of its own scope, its project’s org and the tenant that has the secret and that the caller administers, else the broadest they administer; the runtime reads it there only.

Idempotency-Key
string
>= 1 characters

Caller-supplied idempotency key, scoped to the caller: the same key from someone else in the tenant is their own request (from 0.1.5). Retries with the same key return the original response byte-identical (per docs/API-ROUTE-CONVENTIONS.md §3.1). A retry sent while the first request still runs is answered 409 idempotency-key-in-flight with Retry-After, on a runtime whose store holds keys (from 0.1.5); retry after it, and you get the first request’s answer. An answer that carries a secret (a new API key or public run token, a session token, a generated signing secret) isn’t kept: a retry gets 409 idempotency-key-replay-withheld, with the first request’s status and when it succeeded (from 0.1.5).

Media typeapplication/json

ToolManifest — Tool minus its runtime handler. Validated server-side via @kindgi/tools.validateToolManifest. Metadata-only registration: the handler is not uploaded and must already be available to the runtime.

object
id
required

ToolId — dotted namespace (e.g. acme.verify-citation).

string
>= 1 characters
projectId
required

Project this belongs to (its content scope). Required: missing, or not a project in the caller’s tenant → 400 bad-input.

string format: uuid
description
required
string
>= 1 characters
version
string
/^\d+\.\d+\.\d+$/
input
required

JSON Schema (Draft 2020-12) for the tool input.

object
key
additional properties
any
output
required

JSON Schema (Draft 2020-12) for the tool output.

object
key
additional properties
any
needs
Array<object>
object
name
required
string
>= 1 characters
optional
boolean
effects
Array<object>
object
kind
required
string
Allowed values: reads writes deletes network spawns-run emits-event external-side-effect sensitive-data-egress
resource
string
notes
string
transport
string
Allowed values: auto native mcp
mcpEndpoint
string
metadata
object
key
additional properties
any
mutating

Semantic marker: true when this tool causes observable side effects (writes state, calls external APIs with mutations, sends messages). Read-only tools set false. Absent defaults to true. Consumed by the HITL default classifier — a read-only tool passes straight through, a mutating tool asks on first use.

boolean
needsApprovalWhenUnattended

true: in a run no person started (one whose startedBy isn’t person), every call of this tool waits for a person’s yes, whatever the agent’s approval rules say, and a flow’s tool step that calls it is refused. Absent means false.

boolean
sandbox

Isolation posture the runtime enforces around the handler. Optional additive field.

string
Allowed values: none context-isolated strict
limits

Sandbox-enforced resource caps at dispatch. Optional additive field.

object
memMB
required
integer
>= 1
cpuMs
required
integer
>= 1
network
One of:

Network egress policy. Optional additive field. Discriminated on kind.

object
kind
required
string
Allowed values: none unrestricted
needsSpec

Typed discriminated needs (env / secrets / config / capabilities / bindings). Optional additive field.

object
env
object
key
additional properties
object
secrets
object
key
additional properties
object
config
object
key
additional properties
object
capabilities
Array<string>
bindings
Array<string>
codeArtifactRef
One of:
object
kind
required
Allowed value: oci
imageRef
required
string
>= 1 characters
modulePath
required
string
>= 1 characters
artifactVersion
required
string
>= 1 characters
spec
One of:

Declarative HTTP-invocation spec. Attached to ToolManifest.spec under the discriminant kind: 'http'. The runtime Tool.handler is synthesized by the ‘http’ spec synthesizer to perform URL-template substitution, secret-ref resolution via ToolContext.resolveSecret, and the outbound fetch. All fields serialize cleanly to JSON.

object
kind
required
Allowed value: http
method
required
string
Allowed values: GET POST PUT PATCH DELETE
urlTemplate
required

URL template with {param} placeholders substituted from the tool’s input at invoke time.

string
>= 1 characters
headers
Array<object>
object
name
required
string
>= 1 characters
value
required
string
authorization
One of:
object
kind
required
Allowed value: bearer
secretRef
required
object
envName
required
string
>= 1 characters
name
required
string
>= 1 characters
requestBody
One of:
object
kind
required
Allowed value: json-input
timeoutMs

Wall-clock timeout in ms. Default 30000.

integer
>= 1
parseJson

When true (default), the response body is parsed as JSON before returning to the invoker.

boolean
successStatus
object
min
required
integer
>= 100 <= 599
max
required
integer
>= 100 <= 599

Tool registered.

Media typeapplication/json
object
toolId
required
string
Examplegenerated
{
"toolId": "example"
}

Validation failed (see details.issues); or projectId isn’t a project id (a UUID). Or provider-key-refused: the tool names a model provider’s key (details.secret, details.providerId); store the key it needs under its own name (the same value is fine) and name that. Or validation-failed for a metadata key under kindgi.: those are the runtime’s own (details.issues, at /metadata/<key>).

Media typeapplication/json
object
error
required
object
code
required

Stable machine-readable discriminant. Values match domain error codes (see docs/API-ROUTE-CONVENTIONS.md §4.3).

string
message
required
string
details

Optional, kind-specific.

object
key
additional properties
any
requestId
required

Server-assigned request id; also echoed via X-Request-Id header.

string
Examplegenerated
{
"error": {
"code": "example",
"message": "example",
"details": {},
"requestId": "example"
}
}

Missing / malformed / expired / revoked bearer token.

Media typeapplication/json
object
error
required
object
code
required

Stable machine-readable discriminant. Values match domain error codes (see docs/API-ROUTE-CONVENTIONS.md §4.3).

string
message
required
string
details

Optional, kind-specific.

object
key
additional properties
any
requestId
required

Server-assigned request id; also echoed via X-Request-Id header.

string
Examplegenerated
{
"error": {
"code": "example",
"message": "example",
"details": {},
"requestId": "example"
}
}

The body’s projectId names no project of this tenant (project-not-found).

Media typeapplication/json
object
error
required
object
code
required

Stable machine-readable discriminant. Values match domain error codes (see docs/API-ROUTE-CONVENTIONS.md §4.3).

string
message
required
string
details

Optional, kind-specific.

object
key
additional properties
any
requestId
required

Server-assigned request id; also echoed via X-Request-Id header.

string
Examplegenerated
{
"error": {
"code": "example",
"message": "example",
"details": {},
"requestId": "example"
}
}

tool-already-registered: that (id, version) is taken. Or tool-project-mismatch: the tool’s versions live in another project (a tool belongs to the project its first version was published into and never moves, though in a tenant with environment orders a version may be made in another project of that project’s order; the message doesn’t name the project). Or tool-kind-mismatch: the tool’s active versions are of another kind, an MCP endpoint’s tool (details.endpointId) where this version is published here, or the other way round; a tool’s active versions are all one kind, and nothing was written (details.toolId, details.version). Or environment-takes-promotions: the project is a later environment of an environment order, which takes builds only by promotion from the one before it; publish in the order’s first environment instead (details.firstProjectId, when you can read that project; details.position, the project’s place from 0). Nothing is written. Or registry-read-only: this registry takes no writes (under kindgi dev, the pack’s files are the source); the message says what to do instead.

Media typeapplication/json
object
error
required
object
code
required

Stable machine-readable discriminant. Values match domain error codes (see docs/API-ROUTE-CONVENTIONS.md §4.3).

string
message
required
string
details

Optional, kind-specific.

object
key
additional properties
any
requestId
required

Server-assigned request id; also echoed via X-Request-Id header.

string
Examplegenerated
{
"error": {
"code": "example",
"message": "example",
"details": {},
"requestId": "example"
}
}

The request body is over the API’s limit (request-too-large; details.maxBytes says how much).

Media typeapplication/json
object
error
required
object
code
required

Stable machine-readable discriminant. Values match domain error codes (see docs/API-ROUTE-CONVENTIONS.md §4.3).

string
message
required
string
details

Optional, kind-specific.

object
key
additional properties
any
requestId
required

Server-assigned request id; also echoed via X-Request-Id header.

string
Examplegenerated
{
"error": {
"code": "example",
"message": "example",
"details": {},
"requestId": "example"
}
}

rate-limit-exceeded with details.limit: "schema-compile-time", on a server with a compile budget (Kindgi Cloud): this tenant’s schemas spent details.budgetMs compiling in the last 60 seconds. Nothing was stored; Retry-After says when to send it again.

Media typeapplication/json
object
error
required
object
code
required

Stable machine-readable discriminant. Values match domain error codes (see docs/API-ROUTE-CONVENTIONS.md §4.3).

string
message
required
string
details

Optional, kind-specific.

object
key
additional properties
any
requestId
required

Server-assigned request id; also echoed via X-Request-Id header.

string
Examplegenerated
{
"error": {
"code": "example",
"message": "example",
"details": {},
"requestId": "example"
}
}

Server error (unmapped domain code or framework crash).

Media typeapplication/json
object
error
required
object
code
required

Stable machine-readable discriminant. Values match domain error codes (see docs/API-ROUTE-CONVENTIONS.md §4.3).

string
message
required
string
details

Optional, kind-specific.

object
key
additional properties
any
requestId
required

Server-assigned request id; also echoed via X-Request-Id header.

string
Examplegenerated
{
"error": {
"code": "example",
"message": "example",
"details": {},
"requestId": "example"
}
}

See also