bots-garden/mini-mepublic Fork
⑂ v1.0.6
Commits
⬇ Clone ▾
git clone https://git.rickub.com/bots-garden/mini-me.git
git clone ssh://git@rickub.com/bots-garden/mini-me.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

Download ZIP
🛟 Updated. 74efbf2 · on v1.0.6 · k33g · 3d ago
acp-client-tools.md · 206 lines · 10.3 KBmarkdown
Blame HistoryOpen raw

Reference: ACP client tools (specification)

The protocol an ACP client follows to offer its own tools to mini-me. In ACP mode (mm -acp), mm discovers the tools a client exposes as custom extension methods and the model calls them like its built-in tools. This page is the specification a client implements; the Go steps are in How to offer tools from your ACP client.

Scope

Item Value
Front end ACP mode only (mm -acp). The terminal, the window (-tui) and -p have no client: no client tool exists there.
Configuration acp.clientTools in the agent file.
Namespace org.mini-me
ACP mechanism Extensibility: methods whose name starts with _, capabilities in _meta. ACP defines no way to describe a method's parameters; this page defines mm's.
Who calls whom mm (the agent) sends the requests; the client answers them.

Identifiers

Identifier Kind Where
org.mini-me/tools _meta key clientCapabilities._meta of the initialize request.
_org.mini-me/tools/list request method, agent → client Discovery request only.
org.mini-me/sessionId _meta key params._meta of every tool call.
client_<name> tool name The name the model sees for the tool <name>.

Tool description

One JSON object per tool. The same object is used by both discovery modes.

Field Type Required Description
name string yes The tool's name, unique in the list. The model sees client_<name>, where every character outside [A-Za-z0-9] becomes _, runs of _ are collapsed, and leading/trailing _ are removed (open buffers → client_open_buffers).
description string no What the model reads to decide when to call the tool. Absent: Tool provided by the editor (<method>).
method string yes The extension method mm calls for this tool. Must start with _. Recommended form: _<reverse-dns>/<path>, for example _com.example/workspace/buffers.
inputSchema object no JSON Schema of the arguments. When present, type must be "object" (or absent). Absent: the tool takes no parameter.

Schema as the model sees it

The schema is passed to the model with these changes (the same as for MCP tools):

In inputSchema Declared to the model
required Removed from the schema; the names are appended to the description as Required parameters: a, b. mm checks them before the call.
enum Removed; the values are appended to the property's description as One of: x, y.
additionalProperties: false, $schema Removed.
type, properties Always present: type: "object", properties: {} when absent.

Validation of a list

Each entry is validated on its own. An invalid entry is skipped and a line is written on mm's stderr ([acp] client tools: entry <i> skipped: <reason>); the other entries are kept, and the session never fails because of the list.

Reason Cause
not a tool description: … The entry is not a JSON object of the shape above.
no name name is absent or blank.
method "…" must start with "_" (an ACP extension method) method is absent or not an extension method.
inputSchema.type must be "object", got … The schema describes something other than an object.
duplicate tool name "client_…" Two entries give the same model name; the first one is kept.

The tools are sorted by model name.

Discovery

The mode is set by acp.clientTools.discovery in the agent file. The client must use the mode the agent file names.

Mode meta (default)

The client puts the list in its initialize request. The list applies to every session of the connection.

{"jsonrpc":"2.0","id":0,"method":"initialize","params":{
  "protocolVersion":1,
  "clientInfo":{"name":"my-client","version":"1.0.0"},
  "clientCapabilities":{
    "_meta":{
      "org.mini-me/tools":[
        {"name":"open_buffers",
         "description":"List the files open in the editor.",
         "method":"_com.example/workspace/buffers",
         "inputSchema":{"type":"object",
                        "properties":{"language":{"type":"string","description":"Only the buffers of this language."}},
                        "required":["language"]}}
      ]
    }
  }
}}

In mode meta, the value true instead of a list gives no tool and the stderr line "org.mini-me/tools" is not a list of tools; a client that answers _org.mini-me/tools/list needs acp.clientTools.discovery: request.

Mode request

The client only advertises the capability:

"clientCapabilities":{"_meta":{"org.mini-me/tools":true}}

mm then sends _org.mini-me/tools/list while it handles session/new, session/load and session/resume, before it answers them. The client must therefore answer this request while it waits for its own session/new response (the ACP SDKs handle each incoming request concurrently).

Request:

{"jsonrpc":"2.0","id":7,"method":"_org.mini-me/tools/list",
 "params":{"sessionId":"20261110-224507-1f3a9c2e","cwd":"/home/me/project"}}
Param Type Description
sessionId string The id of the session being opened; the session/new response that carries it has not been sent yet.
cwd string The session's working directory, as the client sent it.

Response:

{"jsonrpc":"2.0","id":7,"result":{"tools":[
  {"name":"open_buffers","method":"_com.example/workspace/buffers"}
]}}
Outcome Effect
A tools array Those tools, validated as above, for this session only.
An error, no answer within acp.clientTools.timeout, or no tools array No client tool for this session; one stderr line; the session opens normally.

Each session asks again: two sessions of the same connection may have different tools.

Tool call

When the model calls client_<name>, mm sends a request to the tool's method.

Before the request

Check Result when it fails
Every parameter of required is present in the model's arguments. No request is sent; the model reads [client tool error: missing required parameters: a, b].
Permission: with acp.clientTools.permissions: ask, or with auto when yolo is false, mm sends session/request_permission to the client first (see session/request_permission requests sent). The tool call's title is client: <name>, its kind other. The model reads [client_<name> rejected by user].

Request

{"jsonrpc":"2.0","id":12,"method":"_com.example/workspace/buffers",
 "params":{"language":"go",
           "_meta":{"org.mini-me/sessionId":"20261110-224507-1f3a9c2e"}}}
Param Description
the model's arguments Copied as the model sent them, at the top level of params.
_meta["org.mini-me/sessionId"] The session the call belongs to. A _meta the model may have put in its arguments is replaced.

Response

Two shapes are accepted.

Content list (the shape of MCP's tools/call result):

{"jsonrpc":"2.0","id":12,"result":{
  "content":[{"type":"text","text":"main.go\nutil.go"}],
  "isError":false}}
Field Type Effect
content array The text of every block of type text, joined with no separator, is what the model reads. A block of another type is replaced by [client tool: non-text content of type <type> skipped].
isError boolean, optional true: the call is a failed call; the model reads [client tool error: <the text>].

Any other JSON value: a JSON string is given to the model unquoted; any other value (object, number, array without content) is given as its JSON text.

Errors

Situation What the model reads Turn
JSON-RPC error (for example -32601 Method not found) [client tool error: {"code":-32601,"message":"Method not found"}] Goes on.
No answer within acp.clientTools.timeout [client tool error: …], with the SDK's error for the expired deadline. mm sends $/cancel_request for the request. Goes on.
The turn is cancelled (session/cancel) mm sends $/cancel_request for the request. Ends as cancelled.
isError: true [client tool error: <text>] Goes on.

Every result, failed or not, is cut to maxOutput characters (head and tail kept), reported to the editor as the end of the tool call (session/update, tool_call_update), and counted by the loop detector like any tool call: the same call with the same answer repeated is flagged, then stops the turn.

Configuration

Key Default Effect on this protocol
acp.clientTools.enabled true false: org.mini-me/tools is ignored; no list request, no client tool.
acp.clientTools.discovery meta meta or request, as described above.
acp.clientTools.permissions auto auto: a call asks the client for permission only when yolo is false. ask: every call asks.
acp.clientTools.timeout 30s Bound of one tool call, and of the list request.

Log lines (mm's stderr)

Line When
[acp] client tools (meta): client_a, client_b After initialize, mode meta, when the client advertised a list.
[acp] session <id> client tools (request): client_a After a list request answered.
[acp] client tools: … A skipped entry, a failed list request, a bare true in mode meta.

Implementations

  • demo.acp.sdk/go: minime.Options.Tools and ToolDiscovery implement the client side of this page in Go; examples/clienttools is a to-do list offered as two tools.

See also

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
# Reference: ACP client tools (specification)

> The protocol an ACP client follows to offer its own tools to mini-me. In ACP mode (`mm -acp`), mm discovers the tools a client exposes as custom extension methods and the model calls them like its built-in tools. This page is the specification a client implements; the Go steps are in [How to offer tools from your ACP client](../how-to/offer-tools-from-an-acp-client.md).

## Scope

| Item | Value |
|------|-------|
| Front end | ACP mode only (`mm -acp`). The terminal, the window (`-tui`) and `-p` have no client: no client tool exists there. |
| Configuration | [`acp.clientTools`](configuration.md#acp-keys) in the agent file. |
| Namespace | `org.mini-me` |
| ACP mechanism | [Extensibility](https://agentclientprotocol.com/protocol/extensibility): methods whose name starts with `_`, capabilities in `_meta`. ACP defines no way to describe a method's parameters; this page defines mm's. |
| Who calls whom | mm (the agent) sends the requests; the client answers them. |

## Identifiers

| Identifier | Kind | Where |
|------------|------|-------|
| `org.mini-me/tools` | `_meta` key | `clientCapabilities._meta` of the `initialize` request. |
| `_org.mini-me/tools/list` | request method, agent → client | Discovery `request` only. |
| `org.mini-me/sessionId` | `_meta` key | `params._meta` of every tool call. |
| `client_<name>` | tool name | The name the model sees for the tool `<name>`. |

## Tool description

One JSON object per tool. The same object is used by both discovery modes.

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `name` | string | yes | The tool's name, unique in the list. The model sees `client_<name>`, where every character outside `[A-Za-z0-9]` becomes `_`, runs of `_` are collapsed, and leading/trailing `_` are removed (`open buffers` → `client_open_buffers`). |
| `description` | string | no | What the model reads to decide when to call the tool. Absent: `Tool provided by the editor (<method>).` |
| `method` | string | yes | The extension method mm calls for this tool. Must start with `_`. Recommended form: `_<reverse-dns>/<path>`, for example `_com.example/workspace/buffers`. |
| `inputSchema` | object | no | JSON Schema of the arguments. When present, `type` must be `"object"` (or absent). Absent: the tool takes no parameter. |

### Schema as the model sees it

The schema is passed to the model with these changes (the same as for MCP tools):

| In `inputSchema` | Declared to the model |
|------------------|-----------------------|
| `required` | Removed from the schema; the names are appended to the description as `Required parameters: a, b`. mm checks them before the call. |
| `enum` | Removed; the values are appended to the property's description as `One of: x, y.` |
| `additionalProperties: false`, `$schema` | Removed. |
| `type`, `properties` | Always present: `type: "object"`, `properties: {}` when absent. |

### Validation of a list

Each entry is validated on its own. An invalid entry is skipped and a line is written on mm's stderr (`[acp] client tools: entry <i> skipped: <reason>`); the other entries are kept, and the session never fails because of the list.

| Reason | Cause |
|--------|-------|
| `not a tool description: …` | The entry is not a JSON object of the shape above. |
| `no name` | `name` is absent or blank. |
| `method "…" must start with "_" (an ACP extension method)` | `method` is absent or not an extension method. |
| `inputSchema.type must be "object", got …` | The schema describes something other than an object. |
| `duplicate tool name "client_…"` | Two entries give the same model name; the first one is kept. |

The tools are sorted by model name.

## Discovery

The mode is set by `acp.clientTools.discovery` in the agent file. The client must use the mode the agent file names.

### Mode `meta` (default)

The client puts the list in its `initialize` request. The list applies to every session of the connection.

```json
{"jsonrpc":"2.0","id":0,"method":"initialize","params":{
  "protocolVersion":1,
  "clientInfo":{"name":"my-client","version":"1.0.0"},
  "clientCapabilities":{
    "_meta":{
      "org.mini-me/tools":[
        {"name":"open_buffers",
         "description":"List the files open in the editor.",
         "method":"_com.example/workspace/buffers",
         "inputSchema":{"type":"object",
                        "properties":{"language":{"type":"string","description":"Only the buffers of this language."}},
                        "required":["language"]}}
      ]
    }
  }
}}
```

In mode `meta`, the value `true` instead of a list gives no tool and the stderr line `"org.mini-me/tools" is not a list of tools; a client that answers _org.mini-me/tools/list needs acp.clientTools.discovery: request`.

### Mode `request`

The client only advertises the capability:

```json
"clientCapabilities":{"_meta":{"org.mini-me/tools":true}}
```

mm then sends `_org.mini-me/tools/list` while it handles `session/new`, `session/load` and `session/resume`, **before** it answers them. The client must therefore answer this request while it waits for its own `session/new` response (the ACP SDKs handle each incoming request concurrently).

Request:

```json
{"jsonrpc":"2.0","id":7,"method":"_org.mini-me/tools/list",
 "params":{"sessionId":"20261110-224507-1f3a9c2e","cwd":"/home/me/project"}}
```

| Param | Type | Description |
|-------|------|-------------|
| `sessionId` | string | The id of the session being opened; the `session/new` response that carries it has not been sent yet. |
| `cwd` | string | The session's working directory, as the client sent it. |

Response:

```json
{"jsonrpc":"2.0","id":7,"result":{"tools":[
  {"name":"open_buffers","method":"_com.example/workspace/buffers"}
]}}
```

| Outcome | Effect |
|---------|--------|
| A `tools` array | Those tools, validated as above, for this session only. |
| An error, no answer within `acp.clientTools.timeout`, or no `tools` array | No client tool for this session; one stderr line; the session opens normally. |

Each session asks again: two sessions of the same connection may have different tools.

## Tool call

When the model calls `client_<name>`, mm sends a request to the tool's `method`.

### Before the request

| Check | Result when it fails |
|-------|----------------------|
| Every parameter of `required` is present in the model's arguments. | No request is sent; the model reads `[client tool error: missing required parameters: a, b]`. |
| Permission: with `acp.clientTools.permissions: ask`, or with `auto` when `yolo` is `false`, mm sends `session/request_permission` to the client first (see [`session/request_permission` requests sent](acp.md#sessionrequest_permission-requests-sent)). The tool call's title is `client: <name>`, its kind `other`. | The model reads `[client_<name> rejected by user]`. |

### Request

```json
{"jsonrpc":"2.0","id":12,"method":"_com.example/workspace/buffers",
 "params":{"language":"go",
           "_meta":{"org.mini-me/sessionId":"20261110-224507-1f3a9c2e"}}}
```

| Param | Description |
|-------|-------------|
| the model's arguments | Copied as the model sent them, at the top level of `params`. |
| `_meta["org.mini-me/sessionId"]` | The session the call belongs to. A `_meta` the model may have put in its arguments is replaced. |

### Response

Two shapes are accepted.

Content list (the shape of MCP's `tools/call` result):

```json
{"jsonrpc":"2.0","id":12,"result":{
  "content":[{"type":"text","text":"main.go\nutil.go"}],
  "isError":false}}
```

| Field | Type | Effect |
|-------|------|--------|
| `content` | array | The `text` of every block of type `text`, joined with no separator, is what the model reads. A block of another type is replaced by `[client tool: non-text content of type <type> skipped]`. |
| `isError` | boolean, optional | `true`: the call is a failed call; the model reads `[client tool error: <the text>]`. |

Any other JSON value: a JSON string is given to the model unquoted; any other value (object, number, array without `content`) is given as its JSON text.

### Errors

| Situation | What the model reads | Turn |
|-----------|----------------------|------|
| JSON-RPC error (for example `-32601` Method not found) | `[client tool error: {"code":-32601,"message":"Method not found"}]` | Goes on. |
| No answer within `acp.clientTools.timeout` | `[client tool error: …]`, with the SDK's error for the expired deadline. mm sends `$/cancel_request` for the request. | Goes on. |
| The turn is cancelled (`session/cancel`) | mm sends `$/cancel_request` for the request. | Ends as cancelled. |
| `isError: true` | `[client tool error: <text>]` | Goes on. |

Every result, failed or not, is cut to `maxOutput` characters (head and tail kept), reported to the editor as the end of the tool call (`session/update`, `tool_call_update`), and counted by the loop detector like any tool call: the same call with the same answer repeated is flagged, then stops the turn.

## Configuration

| Key | Default | Effect on this protocol |
|-----|---------|-------------------------|
| `acp.clientTools.enabled` | `true` | `false`: `org.mini-me/tools` is ignored; no list request, no client tool. |
| `acp.clientTools.discovery` | `meta` | `meta` or `request`, as described above. |
| `acp.clientTools.permissions` | `auto` | `auto`: a call asks the client for permission only when `yolo` is `false`. `ask`: every call asks. |
| `acp.clientTools.timeout` | `30s` | Bound of one tool call, and of the list request. |

## Log lines (mm's stderr)

| Line | When |
|------|------|
| `[acp] client tools (meta): client_a, client_b` | After `initialize`, mode `meta`, when the client advertised a list. |
| `[acp] session <id> client tools (request): client_a` | After a list request answered. |
| `[acp] client tools: …` | A skipped entry, a failed list request, a bare `true` in mode `meta`. |

## Implementations

- [`demo.acp.sdk/go`](../../../demo.acp.sdk/go/README.en.md): `minime.Options.Tools` and `ToolDiscovery` implement the client side of this page in Go; `examples/clienttools` is a to-do list offered as two tools.

## See also

- [ACP client tools — explanation](../explanation/acp-client-tools.md) — why the protocol looks this way
- [How to offer tools from your ACP client](../how-to/offer-tools-from-an-acp-client.md)
- [Agent Client Protocol surface](acp.md)
- [Configuration file — `acp` keys](configuration.md#acp-keys)