@toa.io/extensions.exposition 1.0.0-alpha.284 → 1.0.0-alpha.285

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,17 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ # [1.0.0-alpha.285](https://github.com/toa-io/toa/compare/v1.0.0-alpha.284...v1.0.0-alpha.285) (2026-09-05)
7
+
8
+ ### Bug Fixes
9
+
10
+ * **exposition:** a procedure is named in characters a tool's name may hold ([857ff75](https://github.com/toa-io/toa/commit/857ff75858e633682d5c245eccde3dc00797ec00))
11
+
12
+ ### Features
13
+
14
+ * **exposition:** a tool says what to call it, beside what it is ([c94dcd1](https://github.com/toa-io/toa/commit/c94dcd10ab5a2875975fdba94b37dae128f454c4))
15
+
16
+
6
17
  # [1.0.0-alpha.284](https://github.com/toa-io/toa/compare/v1.0.0-alpha.283...v1.0.0-alpha.284) (2026-09-05)
7
18
 
8
19
  ### Bug Fixes
@@ -37,7 +37,9 @@ A tool is an RTD method that says it is one, named as the [procedure](rpc.md#the
37
37
  /hot:
38
38
  GET:
39
39
  query: { criteria: temperature=gt=80 }
40
- mcp:tool: The pots that are too hot to pour.
40
+ mcp:tool:
41
+ title: Hot pots
42
+ description: The pots that are too hot to pour.
41
43
  endpoint: enumerate
42
44
  ```
43
45
 
@@ -48,6 +50,10 @@ it would spend a model's context on what it has no business calling.
48
50
  The value is what the tool is, and stating it is what publishes it — there is no way to publish one
49
51
  that says nothing, because a tool a model cannot read the purpose of is one it cannot choose.
50
52
 
53
+ A `title` is what a person is shown where a client lists what it may call. Without one a client has
54
+ only the name, which is an address — `apps._identity._id.repos.POST` — and reads as one. A
55
+ description alone is written as the value; a title beside it is written as a mapping.
56
+
51
57
  An operation [states what it is](/documentation/component/declaration.md) as well, and that is not
52
58
  this: it is written without knowledge of any route, and a tool is an operation and a route together.
53
59
  The two routes above are one operation and two tools, and one sentence is not true of both. The
@@ -13,27 +13,31 @@ one an application could choose is one it could collide with a route of its own.
13
13
 
14
14
  ## The name
15
15
 
16
- A procedure is an RTD method — a node and a verb — and its name is written the way the node is
17
- declared: the route template, with a variable marked by a leading `_`, and the verb as the last
18
- segment.
16
+ A procedure is an RTD method — a node and a verb — and its name is the route template with a
17
+ variable marked by a leading `_` and the verb as the last segment, joined by `.`.
18
+
19
+ The separator is `.` and not `/` because a name is a tool's name too, and
20
+ [MCP](mcp.md) names the characters one may hold: letters, digits, `_`, `-` and `.`. A client that
21
+ receives one outside that set may refuse the tool, and one that accepts it rewrites what it shows
22
+ a model — so what is published has to be spellable as it stands.
19
23
 
20
24
  | route | verb | method |
21
25
  | --- | --- | --- |
22
- | `/pots` | `GET` | `pots/GET` |
23
- | `/pots` | `POST` | `pots/POST` |
24
- | `/pots/:id` | `GET` | `pots/_id/GET` |
25
- | `/identity/tokens/:identity` | `POST` | `identity/tokens/_identity/POST` |
26
- | `/files/**` | `GET` | `files/__/GET` |
26
+ | `/pots` | `GET` | `pots.GET` |
27
+ | `/pots` | `POST` | `pots.POST` |
28
+ | `/pots/:id` | `GET` | `pots._id.GET` |
29
+ | `/identity/tokens/:identity` | `POST` | `identity.tokens._identity.POST` |
30
+ | `/files/**` | `GET` | `files.__.GET` |
27
31
  | `/` | `GET` | `GET` |
28
32
 
29
- The verb is always the last segment, so `/pots/GET` answering `POST` is `pots/GET/POST` and
30
- `/pots` answering `GET` is `pots/GET`. Nothing is declared to make a name: a re-mounted route is
33
+ The verb is always the last segment, so `/pots/GET` answering `POST` is `pots.GET.POST` and
34
+ `/pots` answering `GET` is `pots.GET`. Nothing is declared to make a name: a re-mounted route is
31
35
  a renamed procedure, because the name is the address.
32
36
 
33
37
  ## What has a name
34
38
 
35
39
  A segment is addressed where it holds only `A-Z`, `a-z`, `0-9` and `-`. `_` is the name's own,
36
- marking a variable, and `__` the rest of a path.
40
+ marking a variable, and `__` the rest of a path; `.` is what divides one segment from the next.
37
41
 
38
42
  A route with a segment holding anything else — a `.`, a `_`, a `*`, a variable that is not one
39
43
  word — has no name. It is served over HTTP as it always was; what it loses is the address, so
@@ -51,16 +55,16 @@ A key the template names is a route variable, and is taken by the path. `query`
51
55
  querystring. Whatever is left is the body.
52
56
 
53
57
  ```json
54
- {"jsonrpc": "2.0", "id": 1, "method": "pots/_id/GET", "params": {"id": "a1b2"}}
58
+ {"jsonrpc": "2.0", "id": 1, "method": "pots._id.GET", "params": {"id": "a1b2"}}
55
59
  ```
56
60
 
57
61
  ```json
58
- {"jsonrpc": "2.0", "id": 2, "method": "pots/POST",
62
+ {"jsonrpc": "2.0", "id": 2, "method": "pots.POST",
59
63
  "params": {"title": "Kettle", "volume": 1.7}}
60
64
  ```
61
65
 
62
66
  ```json
63
- {"jsonrpc": "2.0", "id": 3, "method": "pots/GET",
67
+ {"jsonrpc": "2.0", "id": 3, "method": "pots.GET",
64
68
  "params": {"query": {"criteria": "volume=gt=1", "limit": 10}}}
65
69
  ```
66
70
 
@@ -87,8 +91,8 @@ A request may carry an array of calls instead of one, and answers an array of wh
87
91
  answered — shorter than what it was given, where some were notifications.
88
92
 
89
93
  ```json
90
- [{"jsonrpc": "2.0", "id": 1, "method": "pots/_id/GET", "params": {"id": "a1b2"}},
91
- {"jsonrpc": "2.0", "method": "pots/_id/DELETE", "params": {"id": "c3d4"}}]
94
+ [{"jsonrpc": "2.0", "id": 1, "method": "pots._id.GET", "params": {"id": "a1b2"}},
95
+ {"jsonrpc": "2.0", "method": "pots._id.DELETE", "params": {"id": "c3d4"}}]
92
96
  ```
93
97
 
94
98
  They run one after another, in the order given. `batch` is how many one request may carry, 32
@@ -127,7 +131,7 @@ in its manifest, and is what a caller reads.
127
131
  ## Authorization
128
132
 
129
133
  A procedure is authorized as the resource is, against the path and the verb its name states.
130
- A token restricted to `/pots/:id/` for `GET` authorizes `pots/_id/GET` and nothing else,
134
+ A token restricted to `/pots/:id/` for `GET` authorizes `pots._id.GET` and nothing else,
131
135
  whichever way the call arrives.
132
136
 
133
137
  [`anonymous`](access.md#anonymous) is the one directive that reads a call differently from a
@@ -8,7 +8,8 @@ Feature: Model Context Protocol
8
8
  says.
9
9
 
10
10
  What a tool is, is stated on the route and nowhere else. The operation states what it is
11
- too, and that is not this: one operation mounted on two routes is two tools.
11
+ too, and that is not this: one operation mounted on two routes is two tools. A `title`
12
+ beside the description is what a person is shown where a client lists what it may call.
12
13
 
13
14
  Two revisions are answered from one endpoint that remembers nothing between requests: the
14
15
  modern one, where every request carries its own version and capabilities, and the one
@@ -42,7 +43,9 @@ Feature: Model Context Protocol
42
43
  GET:
43
44
  query:
44
45
  criteria: volume>=100
45
- mcp:tool: The pots that hold a hundred or more, newest first.
46
+ mcp:tool:
47
+ title: Large pots
48
+ description: The pots that hold a hundred or more, newest first.
46
49
  endpoint: enumerate
47
50
  /unpublished:
48
51
  GET: enumerate
@@ -160,7 +163,7 @@ Feature: Model Context Protocol
160
163
  id: 2
161
164
  result:
162
165
  tools:
163
- - name: pots/GET
166
+ - name: pots.GET
164
167
  description: All the pots, newest first.
165
168
  inputSchema:
166
169
  type: object
@@ -178,7 +181,7 @@ Feature: Model Context Protocol
178
181
  additionalProperties: false
179
182
  annotations:
180
183
  readOnlyHint: true
181
- - name: pots/POST
184
+ - name: pots.POST
182
185
  description: Start a new pot brewing.
183
186
  inputSchema:
184
187
  type: object
@@ -192,7 +195,7 @@ Feature: Model Context Protocol
192
195
  - title
193
196
  - volume
194
197
  additionalProperties: false
195
- - name: pots/_id/GET
198
+ - name: pots._id.GET
196
199
  description: One pot, by its id.
197
200
  inputSchema:
198
201
  type: object
@@ -202,7 +205,8 @@ Feature: Model Context Protocol
202
205
  required:
203
206
  - id
204
207
  additionalProperties: false
205
- - name: pots/large/GET
208
+ - name: pots.large.GET
209
+ title: Large pots
206
210
  description: The pots that hold a hundred or more, newest first.
207
211
  annotations:
208
212
  readOnlyHint: true
@@ -212,11 +216,11 @@ Feature: Model Context Protocol
212
216
  """
213
217
  And the reply does not contain:
214
218
  """
215
- pots/guarded/GET
219
+ pots.guarded.GET
216
220
  """
217
221
  And the reply does not contain:
218
222
  """
219
- pots/unpublished/GET
223
+ pots.unpublished.GET
220
224
  """
221
225
  And the reply does not contain:
222
226
  """
@@ -235,10 +239,10 @@ Feature: Model Context Protocol
235
239
  content-type: application/json
236
240
  mcp-protocol-version: 2026-07-28
237
241
  mcp-method: tools/call
238
- mcp-name: pots/unpublished/GET
242
+ mcp-name: pots.unpublished.GET
239
243
 
240
244
  {"jsonrpc": "2.0", "id": 30, "method": "tools/call",
241
- "params": {"name": "pots/unpublished/GET", "arguments": {},
245
+ "params": {"name": "pots.unpublished.GET", "arguments": {},
242
246
  "_meta": {"io.modelcontextprotocol/protocolVersion": "2026-07-28",
243
247
  "io.modelcontextprotocol/clientCapabilities": {}}}}
244
248
  """
@@ -283,7 +287,7 @@ Feature: Model Context Protocol
283
287
  id: 20
284
288
  result:
285
289
  tools:
286
- - name: pots/GET
290
+ - name: pots.GET
287
291
  """
288
292
 
289
293
  Scenario: A tool takes what the procedure takes
@@ -295,10 +299,10 @@ Feature: Model Context Protocol
295
299
  content-type: application/json
296
300
  mcp-protocol-version: 2026-07-28
297
301
  mcp-method: tools/call
298
- mcp-name: pots/_id/GET
302
+ mcp-name: pots._id.GET
299
303
 
300
304
  {"jsonrpc": "2.0", "id": 3, "method": "tools/call",
301
- "params": {"name": "pots/_id/GET",
305
+ "params": {"name": "pots._id.GET",
302
306
  "arguments": {"id": "4c4759e6f9c74da989d64511df42d6f4"},
303
307
  "_meta": {"io.modelcontextprotocol/protocolVersion": "2026-07-28",
304
308
  "io.modelcontextprotocol/clientCapabilities": {}}}}
@@ -326,10 +330,10 @@ Feature: Model Context Protocol
326
330
  content-type: application/json
327
331
  mcp-protocol-version: 2026-07-28
328
332
  mcp-method: tools/call
329
- mcp-name: pots/POST
333
+ mcp-name: pots.POST
330
334
 
331
335
  {"jsonrpc": "2.0", "id": 4, "method": "tools/call",
332
- "params": {"name": "pots/POST", "arguments": {"title": "Kettle", "volume": 1.7},
336
+ "params": {"name": "pots.POST", "arguments": {"title": "Kettle", "volume": 1.7},
333
337
  "_meta": {"io.modelcontextprotocol/protocolVersion": "2026-07-28",
334
338
  "io.modelcontextprotocol/clientCapabilities": {}}}}
335
339
  """
@@ -354,10 +358,10 @@ Feature: Model Context Protocol
354
358
  content-type: application/json
355
359
  mcp-protocol-version: 2026-07-28
356
360
  mcp-method: tools/call
357
- mcp-name: kettles/GET
361
+ mcp-name: kettles.GET
358
362
 
359
363
  {"jsonrpc": "2.0", "id": 5, "method": "tools/call",
360
- "params": {"name": "kettles/GET", "arguments": {},
364
+ "params": {"name": "kettles.GET", "arguments": {},
361
365
  "_meta": {"io.modelcontextprotocol/protocolVersion": "2026-07-28",
362
366
  "io.modelcontextprotocol/clientCapabilities": {}}}}
363
367
  """
@@ -403,10 +407,10 @@ Feature: Model Context Protocol
403
407
  content-type: application/json
404
408
  mcp-protocol-version: 2026-07-28
405
409
  mcp-method: tools/call
406
- mcp-name: pots/GET
410
+ mcp-name: pots.GET
407
411
 
408
412
  {"jsonrpc": "2.0", "id": 7, "method": "tools/call",
409
- "params": {"name": "pots/POST", "arguments": {},
413
+ "params": {"name": "pots.POST", "arguments": {},
410
414
  "_meta": {"io.modelcontextprotocol/protocolVersion": "2026-07-28",
411
415
  "io.modelcontextprotocol/clientCapabilities": {}}}}
412
416
  """
@@ -484,7 +488,7 @@ Feature: Model Context Protocol
484
488
  named a record that is not the caller's, which it may correct itself by naming another.
485
489
  A challenge here would send the client to ask for a scope that would not help.
486
490
 
487
- # developer:secret, who is not an `admin` and so may not reach `pots/guarded/GET`
491
+ # developer:secret, who is not an `admin` and so may not reach `pots.guarded.GET`
488
492
  Given the `identity.basic` database contains:
489
493
  | _id | authority | username | password |
490
494
  | efe3a65ebbee47ed95a73edd911ea328 | nex | developer | $2b$10$ZRSKkgZoGnrcTNA5w5eCcu3pxDzdTduhteVYXcp56AaNcilNkwJ.O |
@@ -498,10 +502,10 @@ Feature: Model Context Protocol
498
502
  content-type: application/json
499
503
  mcp-protocol-version: 2026-07-28
500
504
  mcp-method: tools/call
501
- mcp-name: pots/guarded/GET
505
+ mcp-name: pots.guarded.GET
502
506
 
503
507
  {"jsonrpc": "2.0", "id": 31, "method": "tools/call",
504
- "params": {"name": "pots/guarded/GET", "arguments": {},
508
+ "params": {"name": "pots.guarded.GET", "arguments": {},
505
509
  "_meta": {"io.modelcontextprotocol/protocolVersion": "2026-07-28",
506
510
  "io.modelcontextprotocol/clientCapabilities": {}}}}
507
511
  """
@@ -531,10 +535,10 @@ Feature: Model Context Protocol
531
535
  content-type: application/json
532
536
  mcp-protocol-version: 2026-07-28
533
537
  mcp-method: tools/call
534
- mcp-name: pots/_id/GET
538
+ mcp-name: pots._id.GET
535
539
 
536
540
  {"jsonrpc": "2.0", "id": 32, "method": "tools/call",
537
- "params": {"name": "pots/_id/GET",
541
+ "params": {"name": "pots._id.GET",
538
542
  "arguments": {"id": "not-an-id"},
539
543
  "_meta": {"io.modelcontextprotocol/protocolVersion": "2026-07-28",
540
544
  "io.modelcontextprotocol/clientCapabilities": {}}}}
@@ -570,10 +574,10 @@ Feature: Model Context Protocol
570
574
  content-type: application/json
571
575
  mcp-protocol-version: 2026-07-28
572
576
  mcp-method: tools/call
573
- mcp-name: echo/GET
577
+ mcp-name: echo.GET
574
578
 
575
579
  {"jsonrpc": "2.0", "id": 10, "method": "tools/call",
576
- "params": {"name": "echo/GET", "arguments": {},
580
+ "params": {"name": "echo.GET", "arguments": {},
577
581
  "_meta": {"io.modelcontextprotocol/protocolVersion": "2026-07-28",
578
582
  "io.modelcontextprotocol/clientCapabilities": {}}}}
579
583
  """
@@ -612,10 +616,10 @@ Feature: Model Context Protocol
612
616
  content-type: application/json
613
617
  mcp-protocol-version: 2026-07-28
614
618
  mcp-method: tools/call
615
- mcp-name: echo/GET
619
+ mcp-name: echo.GET
616
620
 
617
621
  {"jsonrpc": "2.0", "id": 11, "method": "tools/call",
618
- "params": {"name": "echo/GET", "arguments": {"greeting": "hello"},
622
+ "params": {"name": "echo.GET", "arguments": {"greeting": "hello"},
619
623
  "_meta": {"io.modelcontextprotocol/protocolVersion": "2026-07-28",
620
624
  "io.modelcontextprotocol/clientCapabilities": {}}}}
621
625
  """
@@ -119,7 +119,7 @@ Feature: Authorization code flow
119
119
  id: 1
120
120
  result:
121
121
  tools:
122
- - name: pots/GET
122
+ - name: pots.GET
123
123
  """
124
124
 
125
125
  Scenario: A code is spent once
@@ -43,7 +43,7 @@ Feature: JSON-RPC
43
43
  accept: application/yaml
44
44
  content-type: application/json
45
45
 
46
- {"jsonrpc": "2.0", "id": 1, "method": "pots/_id/GET",
46
+ {"jsonrpc": "2.0", "id": 1, "method": "pots._id.GET",
47
47
  "params": {"id": "4c4759e6f9c74da989d64511df42d6f4"}}
48
48
  """
49
49
  Then the following reply is sent:
@@ -67,7 +67,7 @@ Feature: JSON-RPC
67
67
  accept: application/yaml
68
68
  content-type: application/json
69
69
 
70
- {"jsonrpc": "2.0", "id": 2, "method": "pots/POST",
70
+ {"jsonrpc": "2.0", "id": 2, "method": "pots.POST",
71
71
  "params": {"title": "Kettle", "volume": 1.7}}
72
72
  """
73
73
  Then the following reply is sent:
@@ -88,7 +88,7 @@ Feature: JSON-RPC
88
88
  accept: application/yaml
89
89
  content-type: application/json
90
90
 
91
- {"jsonrpc": "2.0", "id": 3, "method": "pots/GET",
91
+ {"jsonrpc": "2.0", "id": 3, "method": "pots.GET",
92
92
  "params": {"query": {"limit": 1}}}
93
93
  """
94
94
  Then the following reply is sent:
@@ -108,7 +108,7 @@ Feature: JSON-RPC
108
108
  host: nex.toa.io
109
109
  content-type: application/json
110
110
 
111
- {"jsonrpc": "2.0", "method": "pots/POST", "params": {"title": "Pot", "volume": 1}}
111
+ {"jsonrpc": "2.0", "method": "pots.POST", "params": {"title": "Pot", "volume": 1}}
112
112
  """
113
113
  Then the following reply is sent:
114
114
  """
@@ -123,7 +123,7 @@ Feature: JSON-RPC
123
123
  accept: application/yaml
124
124
  content-type: application/json
125
125
 
126
- {"jsonrpc": "2.0", "id": 4, "method": "kettles/GET", "params": {}}
126
+ {"jsonrpc": "2.0", "id": 4, "method": "kettles.GET", "params": {}}
127
127
  """
128
128
  Then the following reply is sent:
129
129
  """
@@ -163,7 +163,7 @@ Feature: JSON-RPC
163
163
  accept: application/yaml
164
164
  content-type: application/json
165
165
 
166
- {"jsonrpc": "2.0", "id": 17, "method": "pots/GET", "params": {}}
166
+ {"jsonrpc": "2.0", "id": 17, "method": "pots.GET", "params": {}}
167
167
  """
168
168
  Then the following reply is sent:
169
169
  """
@@ -216,7 +216,7 @@ Feature: JSON-RPC
216
216
  accept: application/yaml
217
217
  content-type: application/json
218
218
 
219
- {"jsonrpc": "2.0", "id": 5, "method": "pots/_id/GET", "params": {}}
219
+ {"jsonrpc": "2.0", "id": 5, "method": "pots._id.GET", "params": {}}
220
220
  """
221
221
  Then the following reply is sent:
222
222
  """
@@ -236,7 +236,7 @@ Feature: JSON-RPC
236
236
  accept: application/yaml
237
237
  content-type: application/json
238
238
 
239
- {"jsonrpc": "2.0", "id": 6, "method": "pots/faulty/GET", "params": {}}
239
+ {"jsonrpc": "2.0", "id": 6, "method": "pots.faulty.GET", "params": {}}
240
240
  """
241
241
  Then the following reply is sent:
242
242
  """
@@ -256,7 +256,7 @@ Feature: JSON-RPC
256
256
  accept: application/yaml
257
257
  content-type: application/json
258
258
 
259
- {"jsonrpc": "2.0", "id": 7, "method": "pots/guarded/GET", "params": {}}
259
+ {"jsonrpc": "2.0", "id": 7, "method": "pots.guarded.GET", "params": {}}
260
260
  """
261
261
  Then the following reply is sent:
262
262
  """
@@ -271,10 +271,10 @@ Feature: JSON-RPC
271
271
  accept: application/yaml
272
272
  content-type: application/json
273
273
 
274
- [{"jsonrpc": "2.0", "id": 8, "method": "pots/_id/GET",
274
+ [{"jsonrpc": "2.0", "id": 8, "method": "pots._id.GET",
275
275
  "params": {"id": "4c4759e6f9c74da989d64511df42d6f4"}},
276
- {"jsonrpc": "2.0", "id": 9, "method": "kettles/GET", "params": {}},
277
- {"jsonrpc": "2.0", "method": "pots/POST", "params": {"title": "Pot", "volume": 1}}]
276
+ {"jsonrpc": "2.0", "id": 9, "method": "kettles.GET", "params": {}},
277
+ {"jsonrpc": "2.0", "method": "pots.POST", "params": {"title": "Pot", "volume": 1}}]
278
278
  """
279
279
  Then the following reply is sent:
280
280
  """
@@ -299,9 +299,9 @@ Feature: JSON-RPC
299
299
  accept: application/yaml
300
300
  content-type: application/json
301
301
 
302
- [{"jsonrpc": "2.0", "id": 13, "method": "pots/GET", "params": {}},
303
- {"jsonrpc": "2.0", "id": 14, "method": "pots/GET", "params": {}},
304
- {"jsonrpc": "2.0", "id": 15, "method": "pots/GET", "params": {}}]
302
+ [{"jsonrpc": "2.0", "id": 13, "method": "pots.GET", "params": {}},
303
+ {"jsonrpc": "2.0", "id": 14, "method": "pots.GET", "params": {}},
304
+ {"jsonrpc": "2.0", "id": 15, "method": "pots.GET", "params": {}}]
305
305
  """
306
306
  Then the following reply is sent:
307
307
  """
@@ -320,8 +320,8 @@ Feature: JSON-RPC
320
320
  host: nex.toa.io
321
321
  content-type: application/json
322
322
 
323
- [{"jsonrpc": "2.0", "method": "pots/POST", "params": {"title": "One", "volume": 1}},
324
- {"jsonrpc": "2.0", "method": "pots/POST", "params": {"title": "Two", "volume": 2}}]
323
+ [{"jsonrpc": "2.0", "method": "pots.POST", "params": {"title": "One", "volume": 1}},
324
+ {"jsonrpc": "2.0", "method": "pots.POST", "params": {"title": "Two", "volume": 2}}]
325
325
  """
326
326
  Then the following reply is sent:
327
327
  """
@@ -356,7 +356,7 @@ Feature: JSON-RPC
356
356
  accept: application/yaml
357
357
  content-type: application/json
358
358
 
359
- {"jsonrpc": "1.0", "id": 10, "method": "pots/GET"}
359
+ {"jsonrpc": "1.0", "id": 10, "method": "pots.GET"}
360
360
  """
361
361
  Then the following reply is sent:
362
362
  """
@@ -394,8 +394,8 @@ Feature: JSON-RPC
394
394
  accept: application/yaml
395
395
  content-type: application/json
396
396
 
397
- [{"jsonrpc": "2.0", "id": 11, "method": "pots/GET", "params": {}},
398
- {"jsonrpc": "2.0", "id": 12, "method": "pots/GET", "params": {}}]
397
+ [{"jsonrpc": "2.0", "id": 11, "method": "pots.GET", "params": {}},
398
+ {"jsonrpc": "2.0", "id": 12, "method": "pots.GET", "params": {}}]
399
399
  """
400
400
  Then the following reply is sent:
401
401
  """
@@ -421,7 +421,7 @@ Feature: JSON-RPC
421
421
  accept: application/yaml
422
422
  content-type: application/json
423
423
 
424
- {"jsonrpc": "2.0", "id": 9, "method": "pots/GET", "params": {}}
424
+ {"jsonrpc": "2.0", "id": 9, "method": "pots.GET", "params": {}}
425
425
  """
426
426
  Then the following reply is sent:
427
427
  """
@@ -158,8 +158,9 @@ export class Gateway {
158
158
  /*
159
159
  * The gateway waits for the branches it discovers, but a component's own resources —
160
160
  * a storage, a queue — are still connecting when it answers. Fifty milliseconds was
161
- * enough until the composition grew; a scenario that asks too early reads the 404 that
162
- * precedes the route.
161
+ * enough until the composition grew, then a hundred; a scenario that asks too early
162
+ * reads the 404 that precedes the route, which `realtime` was failing on in two runs
163
+ * of three. It is a sleep and not a poll, so it is raised rather than fixed.
163
164
  */
164
165
  await timeout(DISCOVERY)
165
166
  }
@@ -217,7 +218,7 @@ const DEFAULT_TREE = JSON.stringify({
217
218
  } satisfies syntax.Node)
218
219
 
219
220
  /** Milliseconds a composition is given to finish connecting what it needs. */
220
- const DISCOVERY = 100
221
+ const DISCOVERY = 500
221
222
 
222
223
  const DEFAULT_PROPERTIES: Partial<http.Options> = {
223
224
  authorities: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@toa.io/extensions.exposition",
3
- "version": "1.0.0-alpha.284",
3
+ "version": "1.0.0-alpha.285",
4
4
  "type": "module",
5
5
  "description": "Toa Exposition",
6
6
  "author": "temich <tema.gurtovoy@gmail.com>",
@@ -58,5 +58,5 @@
58
58
  "@types/cors": "2.8.19",
59
59
  "@types/negotiator": "0.6.5"
60
60
  },
61
- "gitHead": "006755556879e91e8d68fa86753aa3b475bdf4bf"
61
+ "gitHead": "44ed1be7e322a5ea8f1a8ed85ba96b9dfaf28224"
62
62
  }
@@ -8,6 +8,9 @@ export interface Introspection {
8
8
  * one sentence cannot be true of both. The operation's own is for the Introspection.
9
9
  */
10
10
  description?: string
11
+
12
+ /** what a person is shown where a client lists this method, which a name is not */
13
+ title?: string
11
14
  route?: Record<string, Schema>
12
15
  query?: Record<string, Schema>
13
16
 
@@ -40,7 +43,7 @@ export function order (introspection: Introspection): Introspection {
40
43
  return ordered
41
44
  }
42
45
 
43
- const KEYS = ['description', 'route', 'query', 'headers', 'input', 'output', 'errors'] as const
46
+ const KEYS = ['title', 'description', 'route', 'query', 'headers', 'input', 'output', 'errors'] as const
44
47
 
45
48
  /**
46
49
  * The schema of one input property, taken out of it: a property another family fills is
@@ -54,6 +54,7 @@ export async function list (tree: Tree, context: http.Context): Promise<Tool[]>
54
54
  // in the order the revision documents one, which is the order it is read in
55
55
  const tool: Tool = {
56
56
  name: named,
57
+ ...introspection.title === undefined ? {} : { title: introspection.title },
57
58
  ...described === undefined ? {} : { description: described },
58
59
  inputSchema: input(introspection, variables.map((variable) => variable.name)),
59
60
  ...schema === undefined ? {} : { outputSchema: schema },
@@ -66,7 +66,10 @@ export interface Content {
66
66
  export interface Tool {
67
67
  name: string
68
68
 
69
- /** what the operation states it is; absent where it states nothing */
69
+ /** what a person is shown where a client lists this tool; a name is an address */
70
+ title?: string
71
+
72
+ /** what the route states this method is */
70
73
  description?: string
71
74
  inputSchema: object
72
75
  outputSchema?: object