> Source: https://builder.ema.ai/v2/integrations-data/the-tool-editor
> Title: The Tool Editor

# The Tool Editor

A **Tool** is a single capability an AI Employee can invoke at runtime — "create a ticket," "look up an order," "send a message." The Tool editor is where you define exactly what a Tool does: the inputs it accepts, how it reaches the external system, and the shape of the result it returns. Every Tool belongs to an integration and inherits that integration's authentication.

Open the editor from an integration's **Tools** section by adding a new Tool or selecting an existing one. New Tools always start as a **draft** and become callable only after you **publish** them. The editor is a two-pane layout: the editable Tool definition on the left, and a live **Test** panel on the right.

> [INFO]
> **Who can edit.** Only an admin on the integration's owner tenant can create, edit, or publish Tools. A child tenant granted access to the integration can view its Tools but cannot change them.

## Anatomy of a Tool

Every Tool has the same core definition regardless of how it executes:

Field

Purpose

Name

The human-readable display name.

Internal name

An auto-generated slug (lowercase, underscores) used as the stable identifier in references and code.

Description

What the Tool does. The agent reads this to decide when to call the Tool, so write it for the model, not just for humans.

Tool type

How the Tool executes: **HTTP** or **TS Script**.

Input schema

The typed parameters the Tool accepts.

Output schema

A description (and optional field list) of what the Tool returns.

Write Tool

A flag marking the Tool as state-changing (a write), which affects how the agent treats it.

Tags

Optional labels for organizing Tools.

## Defining the input schema

The input schema describes the parameters the Tool accepts. Each field has a name, a display name, a type, a required flag, and an optional description. Supported field types are:

`string`, `date`, `number`, `boolean`, `enum` (with a list of allowed values), `object`, and `array`.

Object and array fields can nest, up to **three levels** deep. Internally the schema round-trips to standard JSON Schema, so a field's display name, parameter bindings, and dependency hints are preserved across edits without polluting the schema itself.

Two advanced per-field options shape how the field is filled at runtime:

-   **Parameter binding** — instead of letting the model fill a field, bind it to a fixed source: `user_input` (collected from the end user in a form), `static` (a constant value), or `context` (read from a path in the workflow run). Bound fields drive human-in-the-loop form generation in the AI Employee builder automatically.
-   **Depends on** — declare that this input is supplied at runtime by the output of another published Tool in the same integration. This is how you chain Tools, for example resolving an account ID with one Tool before passing it to another.

## Tool type: HTTP

An **HTTP** Tool makes an outbound request to a REST endpoint. You configure:

-   **Method** — `GET`, `POST`, `PUT`, `PATCH`, or `DELETE`.
-   **URL** — the request URL. When the integration defines a `base_url` setting, the editor renders it as a fixed prefix and you supply only the relative path.
-   **Headers** — request headers as key/value pairs.
-   **URL parameters** — query-string parameters.
-   **Body** — the request body (for methods that send one). Use **Generate from inputs** to scaffold a JSON body from your input schema.

### Referencing inputs, credentials, and settings

URL, header, parameter, and body fields accept `{{...}}` template references. There are exactly three supported namespaces — anything else is flagged by the editor's linter before you can ship a broken Tool:

Reference

Resolves to

Example

`{{input.X}}`

A value from the Tool's input schema, supplied by the caller at runtime

`{{input.channel}}`

`{{credential.X}}`

A per-connection credential from the active connection (a connection-level auth field)

`{{credential.api_token}}`

`{{setting.X}}`

A template-level setting on the integration, such as the base URL or a region

`{{setting.base_url}}`

Insert a reference from the `{x}` popover, which lists exactly the inputs, credentials, and settings available for this Tool. Nested paths like `{{input.user.email}}` are accepted as long as the top-level name exists.

Here is the verified shape of a real HTTP Tool — Slack's "Send Message":

```yaml
executor: http
executor_config:
  method: POST
  url_template: "https://slack.com/api/chat.postMessage"
  headers:
    Content-Type: application/json
  body_template: |
    {"channel": "{{input.channel}}", "text": "{{input.text}}"}
  timeout_seconds: 10
  auth_type: bearer_token
input_schema:
  type: object
  required: [channel, text]
  properties:
    channel:
      type: string
      description: Channel ID or name
    text:
      type: string
      description: Message text
```

At call time the `http` executor resolves the templates, injects the connection's auth, runs the request, and returns the response — you never handle the token yourself.

## Tool type: TS Script

A **TS Script** Tool runs a TypeScript function in a sandbox instead of making a single declarative request. Reach for this when one HTTP call isn't enough — you need to transform inputs, branch on a response, page through results, or call several endpoints in sequence.

The editor provides a Monaco code editor with full TypeScript autocomplete. A read-only prefix declares an `Inputs` interface generated from your input schema, so your code is typed against the exact parameters you defined. To make authenticated calls back to the integration's endpoints you use the provided `integrations` binding and the `call_integration` API — the editor autocompletes the integration's symbolic name and red-squiggles typos. Your script never sees raw credentials; tenant credentials are injected into the script's input under a reserved key at execution time and resolved by the platform.

> [WARNING]
> TS Script Tools cannot call an LLM — the script sandbox sets the LLM-call budget to zero, so `call_llm` is intentionally unavailable. A script Tool transforms data and calls integration endpoints; reasoning belongs in the agent that calls the Tool.

The read-only prefix in the editor is a convenience, not the security boundary. The real guarantees come from the script-executor: static validation when you save, and a V8 sandbox at runtime. Switching a draft between HTTP and TS Script is allowed; the editor warns before discarding type-specific content you've already entered.

## The output schema

The output schema tells the agent what the Tool returns so it can use the result. At minimum, provide a one-sentence **output description**. You can optionally add a field list for richer hints. After running a test, you can save the response as the output schema in one click. For HTTP and TS Script Tools the output schema is pure JSON Schema — no bindings or lookups.

## Test, validate, and publish

The right pane runs the Tool against a real connection without leaving the editor:

1.  Pick a **connection** (connection template) to run against.
2.  Fill in a JSON **input** matching your schema.
3.  Select **Run test**. The **Output** card shows the result, status, and duration.

Two more controls guard quality:

-   **Validate** checks the Tool's persisted configuration for broken references and missing pieces — for example a `{{credential.X}}` that no longer exists. Because validation runs against saved state, the editor warns you if you have unsaved edits when you run it.
-   **Publish** moves the Tool from **draft** to **published**, making it callable by AI Employees. Publishing enforces a minimum bar, including a non-empty output description. Edits to an already-published Tool go live immediately — there is no re-draft cycle — so make corrections deliberately.

Other actions in the header let you **Clone** a Tool as a new draft (a fast way to build a variant) and **Delete** a Tool (a soft delete that cascades cleanly).

## Custom integrations end to end

A custom integration plus its Tools is the path to wrapping any external API:

1.  **Create the integration.** On the Integrations page, create a new integration via API. Give it a name, description, and category. It starts as a draft.
2.  **Configure authentication.** Choose an auth scheme (`api_key`, `basic`, `oauth2`, or `none`) and declare the auth fields. The scheme is fixed once set; you can append or remove individual fields later. Mark sensitive fields so the UI masks them.
3.  **Add a connection template** and connect, so you have a live connection to test against.
4.  **Build Tools.** Add one or more Tools using the editor above, referencing `{{input.*}}`, `{{credential.*}}`, and `{{setting.*}}` as needed. Test each one.
5.  **Publish** each Tool, then add the integration's Tools to an AI Employee's workflow.

## What's next

-   [Integrations Hub](/builder/v2/integrations-data/integrations-hub) — install integrations, manage connections, and register MCP servers.
-   [Data Connectors](/builder/v2/integrations-data/data-connectors) — sync external documents into Knowledge bases.
