hubris-mcp 0.1.0 → 0.2.0

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.
Files changed (4) hide show
  1. package/README.md +131 -118
  2. package/dist/index.js +64 -51
  3. package/dist/tools.js +970 -44
  4. package/package.json +3 -3
package/dist/tools.js CHANGED
@@ -21,15 +21,6 @@ export const TOOLS = [
21
21
  "additionalProperties": false,
22
22
  "$schema": "http://json-schema.org/draft-07/schema#"
23
23
  },
24
- "annotations": {
25
- "readOnlyHint": true,
26
- "destructiveHint": false,
27
- "idempotentHint": true,
28
- "openWorldHint": false
29
- },
30
- "execution": {
31
- "taskSupport": "forbidden"
32
- },
33
24
  "outputSchema": {
34
25
  "type": "object",
35
26
  "properties": {
@@ -46,12 +37,26 @@ export const TOOLS = [
46
37
  "type": "string",
47
38
  "description": "Human-readable model name."
48
39
  },
40
+ "tool": {
41
+ "type": "string",
42
+ "enum": [
43
+ "chat_complete",
44
+ "embeddings_create",
45
+ "rerank",
46
+ "decisions_ask",
47
+ "image_generate",
48
+ "speech_create",
49
+ "transcription_create",
50
+ "video_create"
51
+ ],
52
+ "description": "The tool that runs this model, e.g. \"chat_complete\" for text models or \"video_create\" for video ones."
53
+ },
49
54
  "capabilities": {
50
55
  "type": "array",
51
56
  "items": {
52
57
  "type": "string"
53
58
  },
54
- "description": "Any of: vision, image_gen, transcription, audio_in, audio_out, audio (legacy, means either audio direction), tools, reasoning, web_search."
59
+ "description": "Any of: vision, image_gen, transcription, audio_in, audio_out, audio (legacy, means either audio direction), decisions, rerank, tools, reasoning, web_search."
55
60
  },
56
61
  "contextLength": {
57
62
  "type": "number",
@@ -94,6 +99,7 @@ export const TOOLS = [
94
99
  "required": [
95
100
  "id",
96
101
  "displayName",
102
+ "tool",
97
103
  "capabilities",
98
104
  "contextLength",
99
105
  "pricing"
@@ -111,12 +117,21 @@ export const TOOLS = [
111
117
  ],
112
118
  "additionalProperties": false,
113
119
  "$schema": "http://json-schema.org/draft-07/schema#"
120
+ },
121
+ "annotations": {
122
+ "readOnlyHint": true,
123
+ "destructiveHint": false,
124
+ "idempotentHint": true,
125
+ "openWorldHint": false
126
+ },
127
+ "execution": {
128
+ "taskSupport": "forbidden"
114
129
  }
115
130
  },
116
131
  {
117
132
  "name": "models_search",
118
133
  "title": "Search models",
119
- "description": "Find models that fit a task. Filters by name, capability, price ceiling and context window, and can sort the result. This is the tool to reach for when choosing a model — it does the filtering server-side and returns at most 50 rows.\n\nAll filters combine with AND, and every one of them is optional: calling with no arguments returns the first 50 active models.\n\nTwo things worth knowing about prices. `maxInputPer1MRub` keeps only models billed per token, because a ruble-per-million ceiling is meaningless for a model billed per image. The `cheap_input` and `cheap_output` sorts push non-token models to the end of the list for the same reason — their token rate reads as zero, which would otherwise put video models at the top of \"cheapest\".",
134
+ "description": "Find models that fit a task. Filters by name, the tool that runs the model, capability, price ceiling and context window, and can sort the result. This is the tool to reach for when choosing a model — it does the filtering server-side and returns at most 50 rows.\n\nAll filters combine with AND, and every one of them is optional: calling with no arguments returns the first 50 active models.\n\nTwo things worth knowing about prices. `maxInputPer1MRub` keeps only models billed per token, because a ruble-per-million ceiling is meaningless for a model billed per image. The `cheap_input` and `cheap_output` sorts push non-token models to the end of the list for the same reason — their token rate reads as zero, which would otherwise put video models at the top of \"cheapest\".",
120
135
  "inputSchema": {
121
136
  "type": "object",
122
137
  "properties": {
@@ -124,6 +139,20 @@ export const TOOLS = [
124
139
  "type": "string",
125
140
  "description": "Case-insensitive substring matched against the model id and display name, e.g. \"claude\" or \"gpt\"."
126
141
  },
142
+ "tool": {
143
+ "type": "string",
144
+ "enum": [
145
+ "chat_complete",
146
+ "embeddings_create",
147
+ "rerank",
148
+ "decisions_ask",
149
+ "image_generate",
150
+ "speech_create",
151
+ "transcription_create",
152
+ "video_create"
153
+ ],
154
+ "description": "Keep only models run by this tool: \"chat_complete\" for text, \"embeddings_create\", \"rerank\", \"decisions_ask\", \"image_generate\", \"speech_create\", \"transcription_create\" or \"video_create\". The way to find a model for any tool other than chat_complete."
155
+ },
127
156
  "capability": {
128
157
  "type": "string",
129
158
  "enum": [
@@ -135,9 +164,11 @@ export const TOOLS = [
135
164
  "audio_out",
136
165
  "audio",
137
166
  "image_gen",
138
- "transcription"
167
+ "transcription",
168
+ "decisions",
169
+ "rerank"
139
170
  ],
140
- "description": "Keep only models with this capability. vision — reads images. image_gen — draws them. transcription — speech to text via /v1/audio/transcriptions. audio_in — accepts an audio recording in chat. audio_out — answers with speech. audio — legacy, matches either audio direction. tools — function calling. reasoning — extended thinking. web_search — built-in web search."
171
+ "description": "Keep only models with this capability. vision — reads images. image_gen — draws them. transcription — speech to text via /v1/audio/transcriptions. audio_in — accepts an audio recording in chat. audio_out — answers with speech. audio — legacy, matches either audio direction. tools — function calling. reasoning — extended thinking. web_search — built-in web search. decisions — yes/no, choice and scale answers with probabilities via /v1/decisions (no text output). rerank — orders documents by relevance to a query via /v1/rerank (no text output)."
141
172
  },
142
173
  "maxInputPer1MRub": {
143
174
  "type": "number",
@@ -161,15 +192,6 @@ export const TOOLS = [
161
192
  "additionalProperties": false,
162
193
  "$schema": "http://json-schema.org/draft-07/schema#"
163
194
  },
164
- "annotations": {
165
- "readOnlyHint": true,
166
- "destructiveHint": false,
167
- "idempotentHint": true,
168
- "openWorldHint": false
169
- },
170
- "execution": {
171
- "taskSupport": "forbidden"
172
- },
173
195
  "outputSchema": {
174
196
  "type": "object",
175
197
  "properties": {
@@ -186,12 +208,26 @@ export const TOOLS = [
186
208
  "type": "string",
187
209
  "description": "Human-readable model name."
188
210
  },
211
+ "tool": {
212
+ "type": "string",
213
+ "enum": [
214
+ "chat_complete",
215
+ "embeddings_create",
216
+ "rerank",
217
+ "decisions_ask",
218
+ "image_generate",
219
+ "speech_create",
220
+ "transcription_create",
221
+ "video_create"
222
+ ],
223
+ "description": "The tool that runs this model, e.g. \"chat_complete\" for text models or \"video_create\" for video ones."
224
+ },
189
225
  "capabilities": {
190
226
  "type": "array",
191
227
  "items": {
192
228
  "type": "string"
193
229
  },
194
- "description": "Any of: vision, image_gen, transcription, audio_in, audio_out, audio (legacy, means either audio direction), tools, reasoning, web_search."
230
+ "description": "Any of: vision, image_gen, transcription, audio_in, audio_out, audio (legacy, means either audio direction), decisions, rerank, tools, reasoning, web_search."
195
231
  },
196
232
  "contextLength": {
197
233
  "type": "number",
@@ -234,6 +270,7 @@ export const TOOLS = [
234
270
  "required": [
235
271
  "id",
236
272
  "displayName",
273
+ "tool",
237
274
  "capabilities",
238
275
  "contextLength",
239
276
  "pricing"
@@ -248,12 +285,21 @@ export const TOOLS = [
248
285
  ],
249
286
  "additionalProperties": false,
250
287
  "$schema": "http://json-schema.org/draft-07/schema#"
288
+ },
289
+ "annotations": {
290
+ "readOnlyHint": true,
291
+ "destructiveHint": false,
292
+ "idempotentHint": true,
293
+ "openWorldHint": false
294
+ },
295
+ "execution": {
296
+ "taskSupport": "forbidden"
251
297
  }
252
298
  },
253
299
  {
254
300
  "name": "models_get_pricing",
255
301
  "title": "Get model pricing",
256
- "description": "The full price of one model in rubles — the authoritative answer to \"what does this cost\".\n\nPrefer this over the pricing embedded in models_list and models_search whenever the model is not billed per token. Those two return \"0.00\" token rates for such models; only this tool returns `perUnit`, where the real price per image, per second or per thousand characters lives.\n\nErrors with InvalidParams if the model id is unknown or the model is no longer active.",
302
+ "description": "The full price of one model in rubles — the authoritative answer to \"what does this cost\".\n\nPrefer this over the pricing embedded in models_list and models_search whenever the model is not billed per token. Those two return \"0.00\" token rates for such models; only this tool returns `perUnit`, where the real price per image, per second or per thousand characters lives.\n\nFor speech models it also lists the voices speech_create accepts (`supportedVoices`), for video models the durations, resolutions and aspect ratios video_create accepts (`video`).\n\nErrors with InvalidParams if the model id is unknown or the model is no longer active.",
257
303
  "inputSchema": {
258
304
  "type": "object",
259
305
  "properties": {
@@ -268,15 +314,6 @@ export const TOOLS = [
268
314
  "additionalProperties": false,
269
315
  "$schema": "http://json-schema.org/draft-07/schema#"
270
316
  },
271
- "annotations": {
272
- "readOnlyHint": true,
273
- "destructiveHint": false,
274
- "idempotentHint": true,
275
- "openWorldHint": false
276
- },
277
- "execution": {
278
- "taskSupport": "forbidden"
279
- },
280
317
  "outputSchema": {
281
318
  "type": "object",
282
319
  "properties": {
@@ -332,6 +369,56 @@ export const TOOLS = [
332
369
  "additionalProperties": false
333
370
  },
334
371
  "description": "Present only for models not billed per token. This is where their real price lives."
372
+ },
373
+ "supportedVoices": {
374
+ "type": "array",
375
+ "items": {
376
+ "type": "string"
377
+ },
378
+ "description": "Speech models only: voice names to pass as `voice` to speech_create. Absent when the model has no list."
379
+ },
380
+ "video": {
381
+ "type": "object",
382
+ "properties": {
383
+ "durations": {
384
+ "type": "array",
385
+ "items": {
386
+ "type": "number"
387
+ },
388
+ "description": "Allowed `duration` values in seconds. Empty when the model does not take this parameter."
389
+ },
390
+ "resolutions": {
391
+ "type": "array",
392
+ "items": {
393
+ "type": "string"
394
+ },
395
+ "description": "Allowed `resolution` values, e.g. \"720p\". Empty when not selectable."
396
+ },
397
+ "aspectRatios": {
398
+ "type": "array",
399
+ "items": {
400
+ "type": "string"
401
+ },
402
+ "description": "Allowed `aspect_ratio` values, e.g. \"16:9\". Empty when not selectable."
403
+ },
404
+ "generateAudio": {
405
+ "type": "boolean",
406
+ "description": "Whether `generate_audio` is available on this model."
407
+ },
408
+ "seed": {
409
+ "type": "boolean",
410
+ "description": "Whether `seed` is available on this model."
411
+ }
412
+ },
413
+ "required": [
414
+ "durations",
415
+ "resolutions",
416
+ "aspectRatios",
417
+ "generateAudio",
418
+ "seed"
419
+ ],
420
+ "additionalProperties": false,
421
+ "description": "Video models only: the values video_create accepts for this model."
335
422
  }
336
423
  },
337
424
  "required": [
@@ -343,16 +430,6 @@ export const TOOLS = [
343
430
  ],
344
431
  "additionalProperties": false,
345
432
  "$schema": "http://json-schema.org/draft-07/schema#"
346
- }
347
- },
348
- {
349
- "name": "balance_get",
350
- "title": "Get account balance",
351
- "description": "Current balance of the Hubris account the API key belongs to, in rubles.\n\nWorth checking before a long or expensive run: requests are refused once the balance is spent. The balance can go slightly negative — one operation is allowed to overdraw it, and the next one is refused.\n\nTwo representations of the same number come back. Use `balanceKopecks` for arithmetic and comparisons — it is an exact integer string. Use `balanceRub` for display.",
352
- "inputSchema": {
353
- "$schema": "http://json-schema.org/draft-07/schema#",
354
- "type": "object",
355
- "properties": {}
356
433
  },
357
434
  "annotations": {
358
435
  "readOnlyHint": true,
@@ -362,6 +439,16 @@ export const TOOLS = [
362
439
  },
363
440
  "execution": {
364
441
  "taskSupport": "forbidden"
442
+ }
443
+ },
444
+ {
445
+ "name": "balance_get",
446
+ "title": "Get account balance",
447
+ "description": "Current balance of the Hubris account the API key belongs to, in rubles.\n\nWorth checking before a long or expensive run: requests are refused once the balance is spent. The balance can go slightly negative — one operation is allowed to overdraw it, and the next one is refused.\n\nTwo representations of the same number come back. Use `balanceKopecks` for arithmetic and comparisons — it is an exact integer string. Use `balanceRub` for display.",
448
+ "inputSchema": {
449
+ "type": "object",
450
+ "properties": {},
451
+ "$schema": "http://json-schema.org/draft-07/schema#"
365
452
  },
366
453
  "outputSchema": {
367
454
  "type": "object",
@@ -381,12 +468,21 @@ export const TOOLS = [
381
468
  ],
382
469
  "additionalProperties": false,
383
470
  "$schema": "http://json-schema.org/draft-07/schema#"
471
+ },
472
+ "annotations": {
473
+ "readOnlyHint": true,
474
+ "destructiveHint": false,
475
+ "idempotentHint": true,
476
+ "openWorldHint": false
477
+ },
478
+ "execution": {
479
+ "taskSupport": "forbidden"
384
480
  }
385
481
  },
386
482
  {
387
483
  "name": "chat_complete",
388
484
  "title": "Chat completion",
389
- "description": "Run a chat completion on any model in the Hubris catalogue and get the answer back. Full parity with POST /v1/chat/completions — same request shape, same response shape, including tool calls, structured output and reasoning. Streaming is not available here: MCP tool calls are synchronous, and `stream` is ignored if you pass it.\n\nThis is how you reach a model you cannot reach otherwise — pick an id with models_search, then call it here. Useful for delegating a subtask to a cheaper or a stronger model than the one you are running on.\n\nThe call spends real money from the account balance: it is billed per token at the catalogue price, in rubles. balance_get shows what is left.",
485
+ "description": "Run a chat completion on any model in the Hubris catalogue and get the answer back. Full parity with POST /v1/chat/completions — same request shape, same response shape, including tool calls, structured output and reasoning. Streaming is not available here: MCP tool calls are synchronous, and `stream` is ignored if you pass it.\n\nThis is how you reach a model you cannot reach otherwise — pick an id with models_search, then call it here. Useful for delegating a subtask to a cheaper or a stronger model than the one you are running on.\n\nChat models that draw (Gemini Image, GPT-5 Image) take modalities [\"image\",\"text\"]; their pictures come back as image content next to the JSON. Voice answers of audio models need streaming and are available through the HTTP API only.\n\nThe call spends real money from the account balance: it is billed per token at the catalogue price, in rubles. balance_get shows what is left.",
390
486
  "inputSchema": {
391
487
  "type": "object",
392
488
  "properties": {
@@ -471,6 +567,17 @@ export const TOOLS = [
471
567
  "reasoning": {
472
568
  "description": "Extended thinking on models with the \"reasoning\" capability: {effort:\"low\"|\"medium\"|\"high\"}, {max_tokens:N}, or {enabled:false} to turn it off."
473
569
  },
570
+ "modalities": {
571
+ "type": "array",
572
+ "items": {
573
+ "type": "string",
574
+ "enum": [
575
+ "text",
576
+ "image"
577
+ ]
578
+ },
579
+ "description": "[\"image\",\"text\"] on chat models that draw (Gemini Image, GPT-5 Image): the pictures come back as image content."
580
+ },
474
581
  "stop": {
475
582
  "anyOf": [
476
583
  {
@@ -506,5 +613,824 @@ export const TOOLS = [
506
613
  "execution": {
507
614
  "taskSupport": "forbidden"
508
615
  }
616
+ },
617
+ {
618
+ "name": "embeddings_create",
619
+ "title": "Create embeddings",
620
+ "description": "Turn text into embedding vectors with any embedding model in the Hubris catalogue — for semantic search, RAG, deduplication and clustering. Same as POST /v1/embeddings, OpenAI shape: data[i].embedding is the vector for input[i].\n\nPass a list of strings to embed a batch in one call, which is faster and cheaper than one call per string. Vectors are long: 1536 numbers make about 30 KB of JSON, and the whole answer lands in your context. Embed only what you will actually store or compare, use `dimensions` where the model allows it, and send large batches through the HTTP API (POST /v1/embeddings).\n\nSpends money from the account balance: billed per input token. usage.cost_rub is what this call cost.",
621
+ "inputSchema": {
622
+ "type": "object",
623
+ "properties": {
624
+ "model": {
625
+ "type": "string",
626
+ "description": "Model id from the catalogue, vendor included and matched exactly, e.g. \"openai/text-embedding-3-small\". Find one with models_search and tool: \"embeddings_create\"."
627
+ },
628
+ "input": {
629
+ "anyOf": [
630
+ {
631
+ "type": "string"
632
+ },
633
+ {
634
+ "type": "array",
635
+ "items": {
636
+ "type": "string"
637
+ },
638
+ "minItems": 1,
639
+ "maxItems": 16
640
+ }
641
+ ],
642
+ "description": "Text to embed: one string, or a list of up to 16 strings embedded in one call."
643
+ },
644
+ "dimensions": {
645
+ "type": "integer",
646
+ "exclusiveMinimum": 0,
647
+ "description": "Shorter vectors, only on models that support it (openai/text-embedding-3-*). Leave out otherwise."
648
+ }
649
+ },
650
+ "required": [
651
+ "model",
652
+ "input"
653
+ ],
654
+ "additionalProperties": false,
655
+ "$schema": "http://json-schema.org/draft-07/schema#"
656
+ },
657
+ "annotations": {
658
+ "readOnlyHint": false,
659
+ "destructiveHint": false,
660
+ "idempotentHint": false,
661
+ "openWorldHint": true
662
+ },
663
+ "execution": {
664
+ "taskSupport": "forbidden"
665
+ }
666
+ },
667
+ {
668
+ "name": "rerank",
669
+ "title": "Rerank documents",
670
+ "description": "Order documents by how well they answer a query, best first, with a relevance score each. Same as POST /v1/rerank. Typical use: a vector or keyword search finds 50–100 candidates, rerank picks the few that really answer the question, and only those go to the model — answers get more accurate and prompts shorter.\n\nresults[].index points into the documents list you sent. Scores are comparable only within one response.\n\nSpends money from the account balance: Cohere models are billed per search (up to 100 documents), the rest per input token. usage.cost_rub is what this call cost.",
671
+ "inputSchema": {
672
+ "type": "object",
673
+ "properties": {
674
+ "model": {
675
+ "type": "string",
676
+ "description": "Model id from the catalogue, vendor included and matched exactly, e.g. \"cohere/rerank-v3.5\". Find one with models_search and tool: \"rerank\"."
677
+ },
678
+ "query": {
679
+ "type": "string",
680
+ "minLength": 1,
681
+ "description": "The question or search query to rank the documents against."
682
+ },
683
+ "documents": {
684
+ "type": "array",
685
+ "items": {
686
+ "type": "string"
687
+ },
688
+ "minItems": 1,
689
+ "maxItems": 1000,
690
+ "description": "Candidate documents as plain text, 1 to 1000 of them. Their order in the answer is by relevance."
691
+ },
692
+ "top_n": {
693
+ "type": "integer",
694
+ "exclusiveMinimum": 0,
695
+ "description": "Return only this many best documents. Leave out to get all of them, ranked."
696
+ }
697
+ },
698
+ "required": [
699
+ "model",
700
+ "query",
701
+ "documents"
702
+ ],
703
+ "additionalProperties": false,
704
+ "$schema": "http://json-schema.org/draft-07/schema#"
705
+ },
706
+ "annotations": {
707
+ "readOnlyHint": false,
708
+ "destructiveHint": false,
709
+ "idempotentHint": false,
710
+ "openWorldHint": true
711
+ },
712
+ "execution": {
713
+ "taskSupport": "forbidden"
714
+ }
715
+ },
716
+ {
717
+ "name": "decisions_ask",
718
+ "title": "Ask a decision model",
719
+ "description": "Ask a decision model (Jev, Clef, Mercury Decide and others) structured questions about some data and get probabilities instead of text. Same as POST /v1/decisions. Question types: \"noul\" — yes or no, answered as the probability of yes; \"choice\" — one option out of criteria; \"score\" — a level on the scale given in criteria. All questions are answered in one call.\n\nGood for classification, routing and triage where you need a calibrated number rather than prose — and much cheaper than asking a chat model.\n\nSpends money from the account balance: billed per input token only. usage.cost_rub is what this call cost.",
720
+ "inputSchema": {
721
+ "type": "object",
722
+ "properties": {
723
+ "model": {
724
+ "type": "string",
725
+ "description": "Model id from the catalogue, vendor included and matched exactly, e.g. \"typesafe/jev-1.13\". Find one with models_search and tool: \"decisions_ask\"."
726
+ },
727
+ "state": {
728
+ "anyOf": [
729
+ {
730
+ "type": "string"
731
+ },
732
+ {
733
+ "type": "object",
734
+ "additionalProperties": {}
735
+ },
736
+ {
737
+ "type": "array",
738
+ "items": {}
739
+ }
740
+ ],
741
+ "description": "The data the questions are about: a string, an object or an array."
742
+ },
743
+ "questions": {
744
+ "type": "object",
745
+ "additionalProperties": {
746
+ "type": "object",
747
+ "additionalProperties": {}
748
+ },
749
+ "description": "Questions by key, e.g. {\"urgent\": {\"type\": \"noul\", \"instructions\": \"Is this urgent?\"}, \"team\": {\"type\": \"choice\", \"instructions\": \"Which team?\", \"criteria\": {\"billing\": \"Payments\", \"tech\": \"Outages\"}}}. \"score\" takes criteria as an array of level descriptions. Each key comes back in answers."
750
+ }
751
+ },
752
+ "required": [
753
+ "model",
754
+ "state",
755
+ "questions"
756
+ ],
757
+ "additionalProperties": false,
758
+ "$schema": "http://json-schema.org/draft-07/schema#"
759
+ },
760
+ "annotations": {
761
+ "readOnlyHint": false,
762
+ "destructiveHint": false,
763
+ "idempotentHint": false,
764
+ "openWorldHint": true
765
+ },
766
+ "execution": {
767
+ "taskSupport": "forbidden"
768
+ }
769
+ },
770
+ {
771
+ "name": "image_generate",
772
+ "title": "Generate an image",
773
+ "description": "Draw an image from a text description with an image model from the Hubris catalogue (FLUX, Recraft, Seedream, GPT Image and others) and get the picture back right away as image content. Same as POST /v1/images/generations.\n\nOnly models whose `tool` is \"image_generate\" work here. Models that draw inside a chat answer and also write text (Gemini Image, GPT-5 Image) have tool \"chat_complete\" and run there. Sizes such as 4K can be heavier than your client accepts in one answer — ask for 2K or less here.\n\nSpends money from the account balance: most image models are billed per image, some per megapixel or per token — models_get_pricing shows the price before you call. The charge shows up in usage_get.",
774
+ "inputSchema": {
775
+ "type": "object",
776
+ "properties": {
777
+ "model": {
778
+ "type": "string",
779
+ "description": "Image model id, vendor included and matched exactly, e.g. \"black-forest-labs/flux.2-pro\". Find one with models_search and tool: \"image_generate\"."
780
+ },
781
+ "prompt": {
782
+ "type": "string",
783
+ "minLength": 1,
784
+ "description": "What to draw. Be specific about subject, style and composition."
785
+ },
786
+ "n": {
787
+ "type": "integer",
788
+ "minimum": 1,
789
+ "maximum": 2,
790
+ "description": "How many images to draw, 1 or 2. Each one is billed. Defaults to 1."
791
+ },
792
+ "size": {
793
+ "type": "string",
794
+ "description": "Image size such as \"1024x1024\", or a tier such as \"2K\" on models that use tiers. Leave out for the model default."
795
+ }
796
+ },
797
+ "required": [
798
+ "model",
799
+ "prompt"
800
+ ],
801
+ "additionalProperties": false,
802
+ "$schema": "http://json-schema.org/draft-07/schema#"
803
+ },
804
+ "annotations": {
805
+ "readOnlyHint": false,
806
+ "destructiveHint": false,
807
+ "idempotentHint": false,
808
+ "openWorldHint": true
809
+ },
810
+ "execution": {
811
+ "taskSupport": "forbidden"
812
+ }
813
+ },
814
+ {
815
+ "name": "speech_create",
816
+ "title": "Text to speech",
817
+ "description": "Read text aloud with a text-to-speech model from the Hubris catalogue and get the audio file back as audio content. Same as POST /v1/audio/speech.\n\nMany models need a voice: the list of voices is on the model card (models_get_pricing → supportedVoices) — pick one from there. The answer is mp3 unless you ask for pcm. Up to 5 000 characters per call, a few minutes of speech; split longer texts or use the HTTP API (POST /v1/audio/speech).\n\nSpends money from the account balance: priced per character of text or per second of audio, depending on the model — models_get_pricing shows which. The charge shows up in usage_get.",
818
+ "inputSchema": {
819
+ "type": "object",
820
+ "properties": {
821
+ "model": {
822
+ "type": "string",
823
+ "description": "Speech model id, vendor included and matched exactly, e.g. \"microsoft/mai-voice-2-flash\". Find one with models_search and tool: \"speech_create\"."
824
+ },
825
+ "input": {
826
+ "type": "string",
827
+ "minLength": 1,
828
+ "maxLength": 5000,
829
+ "description": "Text to read aloud, up to 5 000 characters."
830
+ },
831
+ "voice": {
832
+ "type": "string",
833
+ "description": "Voice name from the model card. Required when the model has a list of voices."
834
+ },
835
+ "response_format": {
836
+ "type": "string",
837
+ "enum": [
838
+ "mp3",
839
+ "pcm"
840
+ ],
841
+ "description": "Audio format: \"mp3\" (default here, plays everywhere) or \"pcm\" (raw 16-bit samples)."
842
+ }
843
+ },
844
+ "required": [
845
+ "model",
846
+ "input"
847
+ ],
848
+ "additionalProperties": false,
849
+ "$schema": "http://json-schema.org/draft-07/schema#"
850
+ },
851
+ "annotations": {
852
+ "readOnlyHint": false,
853
+ "destructiveHint": false,
854
+ "idempotentHint": false,
855
+ "openWorldHint": true
856
+ },
857
+ "execution": {
858
+ "taskSupport": "forbidden"
859
+ }
860
+ },
861
+ {
862
+ "name": "transcription_create",
863
+ "title": "Speech to text",
864
+ "description": "Transcribe a recording to text with a speech recognition model from the Hubris catalogue (Whisper, GPT-4o Transcribe, Deepgram, ElevenLabs Scribe and others). Same as POST /v1/audio/transcriptions with the audio sent as base64.\n\nPass the file content itself, base64-encoded — links to files are not accepted. Every byte of the recording is written out inside this call, so it suits clips of seconds, not minutes; send longer recordings through the HTTP API (POST /v1/audio/transcriptions).\n\nSpends money from the account balance: most models are billed per second or minute of audio, some per token. usage.cost_rub is what this call cost.",
865
+ "inputSchema": {
866
+ "type": "object",
867
+ "properties": {
868
+ "model": {
869
+ "type": "string",
870
+ "description": "Recognition model id, vendor included and matched exactly, e.g. \"openai/whisper-1\". Find one with models_search and tool: \"transcription_create\"."
871
+ },
872
+ "audio_base64": {
873
+ "type": "string",
874
+ "minLength": 1,
875
+ "description": "The recording, base64-encoded, without a \"data:\" prefix."
876
+ },
877
+ "format": {
878
+ "type": "string",
879
+ "minLength": 1,
880
+ "description": "Audio format of the recording: wav, mp3, flac, m4a, ogg, webm or aac."
881
+ },
882
+ "language": {
883
+ "type": "string",
884
+ "description": "Language of the speech as an ISO-639-1 code, e.g. \"ru\". Helps accuracy; leave out to detect it automatically."
885
+ }
886
+ },
887
+ "required": [
888
+ "model",
889
+ "audio_base64",
890
+ "format"
891
+ ],
892
+ "additionalProperties": false,
893
+ "$schema": "http://json-schema.org/draft-07/schema#"
894
+ },
895
+ "annotations": {
896
+ "readOnlyHint": false,
897
+ "destructiveHint": false,
898
+ "idempotentHint": false,
899
+ "openWorldHint": true
900
+ },
901
+ "execution": {
902
+ "taskSupport": "forbidden"
903
+ }
904
+ },
905
+ {
906
+ "name": "video_create",
907
+ "title": "Start a video generation",
908
+ "description": "Start generating a video from a text prompt with a video model from the Hubris catalogue (Veo, Kling, Seedance, Wan, Hailuo, Runway and others). Same as POST /v1/videos. Generation takes from one to several minutes, so this returns a task id right away; poll video_get with it every 15–30 seconds until status is \"completed\" or \"failed\".\n\nAllowed durations, resolutions and aspect ratios differ per model — models_get_pricing lists them under `video`. This tool takes a text prompt only: starting from images or a source video, and models that need a source — video editing, upscaling and talking avatars (FLUX Video Edit, FLUX Video Upscale, Runway Aleph, HeyGen Avatar) — work through the HTTP API (POST /v1/videos).\n\nConnected through OAuth (Claude, Cursor, VS Code)? Video needs the permission to create videos on the consent screen. If this tool answers that videos:write is missing, reconnect.\n\nSpends money from the account balance: priced per second of video. The largest possible cost is held when the task starts, the actual cost is charged when it completes and the difference is returned; a failed generation returns the whole hold.",
909
+ "inputSchema": {
910
+ "type": "object",
911
+ "properties": {
912
+ "model": {
913
+ "type": "string",
914
+ "description": "Video model id, vendor included and matched exactly, e.g. \"kwaivgi/kling-v3.0-pro\". Find one with models_search and tool: \"video_create\"."
915
+ },
916
+ "prompt": {
917
+ "type": "string",
918
+ "minLength": 1,
919
+ "maxLength": 50000,
920
+ "description": "What should happen in the video: subject, action, camera, style."
921
+ },
922
+ "duration": {
923
+ "type": "integer",
924
+ "minimum": 1,
925
+ "maximum": 60,
926
+ "description": "Length in seconds, from the values the model supports."
927
+ },
928
+ "resolution": {
929
+ "type": "string",
930
+ "description": "Resolution such as \"720p\" or \"1080p\", from the values the model supports."
931
+ },
932
+ "aspect_ratio": {
933
+ "type": "string",
934
+ "description": "Frame shape such as \"16:9\" or \"9:16\", from the values the model supports."
935
+ },
936
+ "generate_audio": {
937
+ "type": "boolean",
938
+ "description": "Generate a soundtrack, on models that can. Usually costs more per second."
939
+ },
940
+ "seed": {
941
+ "type": "integer",
942
+ "description": "Fixed seed for a repeatable result, on models that support it."
943
+ },
944
+ "idempotency_key": {
945
+ "type": "string",
946
+ "maxLength": 255,
947
+ "description": "Your own unique string for this request. Repeating the call with the same key returns the same task instead of starting and paying for a second one."
948
+ }
949
+ },
950
+ "required": [
951
+ "model",
952
+ "prompt"
953
+ ],
954
+ "additionalProperties": false,
955
+ "$schema": "http://json-schema.org/draft-07/schema#"
956
+ },
957
+ "annotations": {
958
+ "readOnlyHint": false,
959
+ "destructiveHint": false,
960
+ "idempotentHint": false,
961
+ "openWorldHint": true
962
+ },
963
+ "execution": {
964
+ "taskSupport": "forbidden"
965
+ }
966
+ },
967
+ {
968
+ "name": "video_get",
969
+ "title": "Check a video generation",
970
+ "description": "Status of a video task started with video_create: \"pending\", \"in_progress\", \"completed\" or \"failed\". Same as GET /v1/videos/{id}.\n\nWhile the video is being made, usage.estimated_cost is the amount held on the balance. Once it is \"completed\", usage.cost is the final price and the answer carries a link to the video file as an MCP resource (video/mp4) — read that resource to get the video itself. The file is kept for 72 hours. Files over 25 MB are not served as a resource; download those over HTTP (GET /v1/videos/{id}/content) with the same key.\n\nFree to call: it only reads the task. Poll every 15–30 seconds, not more often.",
971
+ "inputSchema": {
972
+ "type": "object",
973
+ "properties": {
974
+ "id": {
975
+ "type": "string",
976
+ "format": "uuid",
977
+ "description": "Task id returned by video_create."
978
+ }
979
+ },
980
+ "required": [
981
+ "id"
982
+ ],
983
+ "additionalProperties": false,
984
+ "$schema": "http://json-schema.org/draft-07/schema#"
985
+ },
986
+ "outputSchema": {
987
+ "type": "object",
988
+ "properties": {
989
+ "id": {
990
+ "type": "string",
991
+ "description": "Task id."
992
+ },
993
+ "status": {
994
+ "type": "string",
995
+ "enum": [
996
+ "pending",
997
+ "in_progress",
998
+ "completed",
999
+ "failed"
1000
+ ],
1001
+ "description": "\"pending\" and \"in_progress\" — keep polling; \"completed\" — the video is ready; \"failed\" — the hold is returned."
1002
+ },
1003
+ "created": {
1004
+ "type": "integer",
1005
+ "description": "When the task was started, Unix seconds."
1006
+ },
1007
+ "unsigned_urls": {
1008
+ "type": "array",
1009
+ "items": {
1010
+ "type": "string"
1011
+ },
1012
+ "description": "HTTP download links for the finished video; they need the same Bearer key. The MCP resource link in the answer needs nothing extra."
1013
+ },
1014
+ "usage": {
1015
+ "type": "object",
1016
+ "properties": {
1017
+ "cost": {
1018
+ "type": "number",
1019
+ "description": "Final price in kopecks, once completed."
1020
+ },
1021
+ "estimated_cost": {
1022
+ "type": "number",
1023
+ "description": "Amount held on the balance while the video is being made, in kopecks."
1024
+ }
1025
+ },
1026
+ "additionalProperties": false,
1027
+ "description": "Money: the hold while in progress, the final price once completed."
1028
+ },
1029
+ "error": {
1030
+ "type": "string",
1031
+ "description": "Why the generation failed, when status is \"failed\"."
1032
+ }
1033
+ },
1034
+ "required": [
1035
+ "id",
1036
+ "status",
1037
+ "created"
1038
+ ],
1039
+ "additionalProperties": false,
1040
+ "$schema": "http://json-schema.org/draft-07/schema#"
1041
+ },
1042
+ "annotations": {
1043
+ "readOnlyHint": true,
1044
+ "destructiveHint": false,
1045
+ "idempotentHint": true,
1046
+ "openWorldHint": false
1047
+ },
1048
+ "execution": {
1049
+ "taskSupport": "forbidden"
1050
+ }
1051
+ },
1052
+ {
1053
+ "name": "youtube_transcribe",
1054
+ "title": "Transcribe a YouTube video",
1055
+ "description": "Transcript or summary of a YouTube video by its link. Same as POST /v1/video/transcriptions. The video is checked before any model is called: a deleted, private or link-only video, a live stream and a video longer than four hours are refused without charge.\n\nmode \"exact\" gives a word-for-word transcript, each line with an [HH:MM:SS] timecode, optionally labelled by speaker. mode \"fast\" gives a summary with key points and rough timecodes — several times faster and cheaper on long videos. An hour-long video in \"exact\" takes several minutes, which may exceed your client's tool timeout; prefer \"fast\" there.\n\nSpends money from the account balance: billed per token of the model doing the work. usage.cost_rub is what this call cost.",
1056
+ "inputSchema": {
1057
+ "type": "object",
1058
+ "properties": {
1059
+ "url": {
1060
+ "type": "string",
1061
+ "minLength": 1,
1062
+ "maxLength": 2000,
1063
+ "description": "Link to the YouTube video, e.g. \"https://youtu.be/ITL6WqcV6sE\"."
1064
+ },
1065
+ "mode": {
1066
+ "type": "string",
1067
+ "enum": [
1068
+ "exact",
1069
+ "fast"
1070
+ ],
1071
+ "description": "\"exact\" — word-for-word transcript with timecodes (default); \"fast\" — summary with key points."
1072
+ },
1073
+ "diarize": {
1074
+ "type": "boolean",
1075
+ "description": "With mode \"exact\": label lines by speaker (\"Speaker 1:\", or by name when it is said in the video)."
1076
+ }
1077
+ },
1078
+ "required": [
1079
+ "url"
1080
+ ],
1081
+ "additionalProperties": false,
1082
+ "$schema": "http://json-schema.org/draft-07/schema#"
1083
+ },
1084
+ "annotations": {
1085
+ "readOnlyHint": false,
1086
+ "destructiveHint": false,
1087
+ "idempotentHint": false,
1088
+ "openWorldHint": true
1089
+ },
1090
+ "execution": {
1091
+ "taskSupport": "forbidden"
1092
+ }
1093
+ },
1094
+ {
1095
+ "name": "usage_get",
1096
+ "title": "Get spending for a period",
1097
+ "description": "What this connection has spent over a period: requests, tokens, cache savings and the total in rubles. Same as GET /v1/usage. With an API key that is the key's spending; connected through OAuth, it is the spending of the whole app connection over the period, not just of the current hourly token.\n\nUse it to report what a run cost, to check spending against a budget, or to see the charge of tools that do not return their own price (image_generate, speech_create). balance_get shows what is left on the account.\n\nFree to call: it only reads.",
1098
+ "inputSchema": {
1099
+ "type": "object",
1100
+ "properties": {
1101
+ "period": {
1102
+ "type": "string",
1103
+ "enum": [
1104
+ "today",
1105
+ "24h",
1106
+ "7d",
1107
+ "30d",
1108
+ "mtd"
1109
+ ],
1110
+ "description": "Period: \"today\", \"24h\" (default), \"7d\", \"30d\" or \"mtd\" — month to date. All times in UTC."
1111
+ }
1112
+ },
1113
+ "additionalProperties": false,
1114
+ "$schema": "http://json-schema.org/draft-07/schema#"
1115
+ },
1116
+ "outputSchema": {
1117
+ "type": "object",
1118
+ "properties": {
1119
+ "object": {
1120
+ "type": "string",
1121
+ "const": "usage"
1122
+ },
1123
+ "period": {
1124
+ "type": "object",
1125
+ "properties": {
1126
+ "from": {
1127
+ "type": "string",
1128
+ "format": "date-time"
1129
+ },
1130
+ "to": {
1131
+ "type": "string",
1132
+ "format": "date-time"
1133
+ },
1134
+ "shortcut": {
1135
+ "anyOf": [
1136
+ {
1137
+ "type": "string",
1138
+ "enum": [
1139
+ "today",
1140
+ "24h",
1141
+ "7d",
1142
+ "30d",
1143
+ "mtd"
1144
+ ]
1145
+ },
1146
+ {
1147
+ "type": "null"
1148
+ }
1149
+ ]
1150
+ }
1151
+ },
1152
+ "required": [
1153
+ "from",
1154
+ "to",
1155
+ "shortcut"
1156
+ ],
1157
+ "additionalProperties": false
1158
+ },
1159
+ "scope": {
1160
+ "anyOf": [
1161
+ {
1162
+ "type": "object",
1163
+ "properties": {
1164
+ "key_id": {
1165
+ "type": "string",
1166
+ "format": "uuid"
1167
+ },
1168
+ "key_prefix": {
1169
+ "type": "string"
1170
+ }
1171
+ },
1172
+ "required": [
1173
+ "key_id",
1174
+ "key_prefix"
1175
+ ],
1176
+ "additionalProperties": false
1177
+ },
1178
+ {
1179
+ "type": "object",
1180
+ "properties": {
1181
+ "account": {
1182
+ "type": "boolean",
1183
+ "const": true
1184
+ },
1185
+ "key_id": {
1186
+ "anyOf": [
1187
+ {
1188
+ "type": "string",
1189
+ "format": "uuid"
1190
+ },
1191
+ {
1192
+ "type": "null"
1193
+ }
1194
+ ]
1195
+ }
1196
+ },
1197
+ "required": [
1198
+ "account",
1199
+ "key_id"
1200
+ ],
1201
+ "additionalProperties": false
1202
+ }
1203
+ ]
1204
+ },
1205
+ "totals": {
1206
+ "type": "object",
1207
+ "properties": {
1208
+ "requests": {
1209
+ "type": "integer",
1210
+ "minimum": 0
1211
+ },
1212
+ "prompt_tokens": {
1213
+ "type": "integer",
1214
+ "minimum": 0
1215
+ },
1216
+ "completion_tokens": {
1217
+ "type": "integer",
1218
+ "minimum": 0
1219
+ },
1220
+ "total_tokens": {
1221
+ "type": "integer",
1222
+ "minimum": 0
1223
+ },
1224
+ "cost_rub": {
1225
+ "type": "number"
1226
+ },
1227
+ "cost_kopecks": {
1228
+ "type": "string"
1229
+ },
1230
+ "cache_read_tokens": {
1231
+ "type": "integer"
1232
+ },
1233
+ "cache_write_tokens": {
1234
+ "type": "integer"
1235
+ },
1236
+ "reasoning_tokens": {
1237
+ "type": "integer"
1238
+ },
1239
+ "cache_hit_rate": {
1240
+ "type": "number"
1241
+ },
1242
+ "cache_savings_kopecks": {
1243
+ "type": "string"
1244
+ },
1245
+ "cache_savings_rub": {
1246
+ "type": "number"
1247
+ }
1248
+ },
1249
+ "required": [
1250
+ "requests",
1251
+ "prompt_tokens",
1252
+ "completion_tokens",
1253
+ "total_tokens",
1254
+ "cost_rub",
1255
+ "cost_kopecks",
1256
+ "cache_read_tokens",
1257
+ "cache_write_tokens",
1258
+ "reasoning_tokens",
1259
+ "cache_hit_rate",
1260
+ "cache_savings_kopecks",
1261
+ "cache_savings_rub"
1262
+ ],
1263
+ "additionalProperties": false
1264
+ },
1265
+ "granularity": {
1266
+ "anyOf": [
1267
+ {
1268
+ "type": "string",
1269
+ "enum": [
1270
+ "hour",
1271
+ "day"
1272
+ ]
1273
+ },
1274
+ {
1275
+ "type": "null"
1276
+ }
1277
+ ]
1278
+ },
1279
+ "buckets": {
1280
+ "anyOf": [
1281
+ {
1282
+ "type": "array",
1283
+ "items": {
1284
+ "type": "object",
1285
+ "properties": {
1286
+ "bucket": {
1287
+ "type": "string",
1288
+ "format": "date-time"
1289
+ },
1290
+ "cost_rub": {
1291
+ "type": "number"
1292
+ },
1293
+ "cost_kopecks": {
1294
+ "type": "string"
1295
+ },
1296
+ "requests": {
1297
+ "type": "integer",
1298
+ "minimum": 0
1299
+ }
1300
+ },
1301
+ "required": [
1302
+ "bucket",
1303
+ "cost_rub",
1304
+ "cost_kopecks",
1305
+ "requests"
1306
+ ],
1307
+ "additionalProperties": false
1308
+ }
1309
+ },
1310
+ {
1311
+ "type": "null"
1312
+ }
1313
+ ]
1314
+ },
1315
+ "by_key": {
1316
+ "anyOf": [
1317
+ {
1318
+ "type": "array",
1319
+ "items": {
1320
+ "type": "object",
1321
+ "properties": {
1322
+ "key_id": {
1323
+ "anyOf": [
1324
+ {
1325
+ "type": "string",
1326
+ "format": "uuid"
1327
+ },
1328
+ {
1329
+ "type": "null"
1330
+ }
1331
+ ]
1332
+ },
1333
+ "key_prefix": {
1334
+ "type": [
1335
+ "string",
1336
+ "null"
1337
+ ]
1338
+ },
1339
+ "name": {
1340
+ "type": [
1341
+ "string",
1342
+ "null"
1343
+ ]
1344
+ },
1345
+ "requests": {
1346
+ "type": "integer",
1347
+ "minimum": 0
1348
+ },
1349
+ "total_tokens": {
1350
+ "type": "integer",
1351
+ "minimum": 0
1352
+ },
1353
+ "cost_kopecks": {
1354
+ "type": "string"
1355
+ }
1356
+ },
1357
+ "required": [
1358
+ "key_id",
1359
+ "key_prefix",
1360
+ "name",
1361
+ "requests",
1362
+ "total_tokens",
1363
+ "cost_kopecks"
1364
+ ],
1365
+ "additionalProperties": false
1366
+ }
1367
+ },
1368
+ {
1369
+ "type": "null"
1370
+ }
1371
+ ]
1372
+ },
1373
+ "by_model": {
1374
+ "anyOf": [
1375
+ {
1376
+ "type": "array",
1377
+ "items": {
1378
+ "type": "object",
1379
+ "properties": {
1380
+ "model": {
1381
+ "type": "string"
1382
+ },
1383
+ "requests": {
1384
+ "type": "integer",
1385
+ "minimum": 0
1386
+ },
1387
+ "prompt_tokens": {
1388
+ "type": "integer",
1389
+ "minimum": 0
1390
+ },
1391
+ "completion_tokens": {
1392
+ "type": "integer",
1393
+ "minimum": 0
1394
+ },
1395
+ "cost_kopecks": {
1396
+ "type": "string"
1397
+ }
1398
+ },
1399
+ "required": [
1400
+ "model",
1401
+ "requests",
1402
+ "prompt_tokens",
1403
+ "completion_tokens",
1404
+ "cost_kopecks"
1405
+ ],
1406
+ "additionalProperties": false
1407
+ }
1408
+ },
1409
+ {
1410
+ "type": "null"
1411
+ }
1412
+ ]
1413
+ }
1414
+ },
1415
+ "required": [
1416
+ "object",
1417
+ "period",
1418
+ "scope",
1419
+ "totals",
1420
+ "granularity",
1421
+ "buckets"
1422
+ ],
1423
+ "additionalProperties": false,
1424
+ "$schema": "http://json-schema.org/draft-07/schema#"
1425
+ },
1426
+ "annotations": {
1427
+ "readOnlyHint": true,
1428
+ "destructiveHint": false,
1429
+ "idempotentHint": true,
1430
+ "openWorldHint": false
1431
+ },
1432
+ "execution": {
1433
+ "taskSupport": "forbidden"
1434
+ }
509
1435
  }
510
1436
  ];