Skip to content
Agentmart
Submit a tool

tools

Building LLM tools with Vovk.ts — `deriveTools()` (procedures → tools) returning a `StandardToolV0[]` array, standalone tools via the `standard-tool` package…

Skill by finom

IndexedMIT★ 54
Write a review

Install

Works with Claude Code, Claude apps, Codex, Cursor, Gemini CLI, GitHub Copilot, VS Code, OpenCode, Goose, Windsurf. Read the repository before you give any tool access to your data.

npx agentmarket install skill/finom-tools

Asks which of your tools to add it to (Claude Code, Codex, Cursor, VS Code, Windsurf, Gemini CLI, Claude Desktop) and shows the change first. See https://agentmart.dev/cli.

Get the weekly diff

The weekly diff: one email a week with new agent tools, notable updates and grade changes, plus security alerts for tools you follow. Double opt-in, one-click unsubscribe.

We use your email only for this newsletter. Privacy

About

Building LLM tools with Vovk.ts — `deriveTools()` (procedures → tools) returning a `StandardToolV0[]` array, standalone tools via the `standard-tool` package, `@operation.tool({ name, title, description, hidden, meta })` decorator, `x-tool` metadata, `ToModelOutput` formatters (`DEFAULT`, `MCP`, `RAW`), the merged `inputSchema`, the `meta` option for passing context to procedures, `withDefaults` for baking auth into third-party API tools, and the `pick` / `omit` pattern for selecting specific procedures. Use whenever the user asks to expose an API to an LLM, wire up tool calling, build an MCP server, "let Claude / GPT call this", "turn my controllers into tools", "function calling with Vercel AI SDK", "standalone tool", "hide a procedure from the LLM", "tool that wraps a third-party SDK", or any variation. Does NOT cover procedure authoring → `procedure` skill. Does NOT cover the OpenAPI spec beyond `@operation`/`x-tool` → `openapi` skill. Does NOT cover third-party OpenAPI mixin setup → `mixins` skill.

Use cases: backend, cloud, ml, security

No reviews yet. Installed it? Reviews come from verified installers only. How reviews work

Permissions

What this skill can do and what it asks for, from its SKILL.md and code. Checked Oct 25, 2026.

Tools
No tools found
Secrets
None asked for
Install scripts
None found

Network hosts it talks to 1

  • codeload.github.com · found in install command

Files it touches

  • ~/.claude/skills/tools

What's inside

Skill name
tools
Description
Building LLM tools with Vovk.ts — `deriveTools()` (procedures → tools) returning a `StandardToolV0[]` array, standalone tools via the `standard-tool` package, `@operation.tool({ name, title, description, hidden, meta })` decorator, `x-tool` metadata, `ToModelOutput` formatters (`DEFAULT`, `MCP`, `RAW`), the merged `inputSchema`, the `meta` option for passing context to procedures, `withDefaults` for baking auth into third-party API tools, and the `pick` / `omit` pattern for selecting specific procedures. Use whenever the user asks to expose an API to an LLM, wire up tool calling, build an MCP server, "let Claude / GPT call this", "turn my controllers into tools", "function calling with Vercel AI SDK", "standalone tool", "hide a procedure from the LLM", "tool that wraps a third-party SDK", or any variation. Does NOT cover procedure authoring → `procedure` skill. Does NOT cover the OpenAPI spec beyond `@operation`/`x-tool` → `openapi` skill. Does NOT cover third-party OpenAPI mixin setup → `mixins` skill.
License
MIT
Instructions
487 lines in SKILL.md · view on GitHub

Before installing

  • Instructions call the network

Files (1)

  • SKILL.md

SKILL.md (first lines)

# Vovk.ts LLM tools

**`deriveTools({ modules })`** turns existing procedures (controllers, RPC modules, OpenAPI mixins) into tools automatically. It returns an **array** of tools, each satisfying [`StandardToolV0`](https://standard-tool.js.org/) — `{ name, title?, description, inputSchema?, outputSchema?, execute }`.

Standalone tools (no procedure backing — SDK wrappers, calculators, file ops) are plain objects of the same shape; the `standard-tool` package's `standardTool()` helper adds input/output validation. Both mix freely in one array and feed to OpenAI / Anthropic / Vercel AI SDK / MCP servers.

> **v4 removed `createTool`, `VovkTool`, `parameters`, `type` and `inputSchemas`.** Tools are the standard-tool shape now: one merged `inputSchema` instead of `parameters` + `inputSchemas`, and `deriveTools` returns the array directly instead of `{ tools, toolsByName }`.

**Out of scope:** procedure authoring (**`procedure`**), `@operation` for OpenAPI docs (**`openapi`**), third-party OpenAPI mixin setup (**`mixins`**). MCP server transport / hosting outside Vovk; **for Next.js, use `createMcpHandler` from the official MCP SDK (`@modelcontextprotocol/server`)** — example below.

> **Import path note.** Code samples import from `'@/client'`: the composed client generated into `src/client` (or `client/` when the app isn't in `src/app`). Custom `composedClient.outDir` changes the path. With segmented client, import from `@/client/<segment>`. Call shape identical. See **`rpc`** skill.

## `deriveTools` — core shape

```ts
import { deriveTools } from 'vovk';
import { TaskRPC, PetstoreAPI } from '@/client';
import UserController from '@/modules/user/user-controller';

const tools = deriveTools({
  modules: { UserController, TaskRPC, PetstoreAPI },
});
```

`modules` accepts record of:

- **Controllers** — execute via `.fn()` in-process, no HTTP.
- **RPC modules** (from `@/client`, or `@/client/<segment>` for segmented layout) — execute via HTTP using standard fetcher.
- **OpenAPI mixins** (same client surface) — execute via HTTP against third-party API. See **`mixins`** skill.

Each module yields one tool per procedure with `@operation` schema, not `hidden`.

### Return shape

```ts
const tools = deriveTools({ modules: { TaskRPC } });   // StandardToolV0[]

// Need name-keyed dispatch? Build the map yourself — v4 dropped `toolsByName`.
const byName = Object.fromEntries(tools.map((t) => [t.name, t]));
const result = await byName[call.name].execute(call.arguments);
```

### Each tool's fields

The type comes from the `standard-tool` package (`import type { StandardToolV0 } from 'standard-tool'`); `vovk` doesn't export it.

```ts
type StandardToolV0 = {
  name: string;                         // default: `${moduleName}_${handlerName}` — e.g. UserController_getUser
  title?: string;                       // from x-tool.title or operation.summary
  description: string;                  // x-tool.description, OR `${summary}\n${description}`, OR handlerName fallback
  inputSchema?: StandardSchemaV1 & StandardJSONSchemaV1;   // merged body/query/params, see below
  outputSchema?: StandardSchemaV1 & StandardJSONSchemaV1;  // procedure's output schema if declared
  meta?: Record<string, unknown>;       // verbatim from x-tool.meta — static data for consumers
  execute: (input, context?) => Promise<unknown>; // HTTP for RPC/mixins, .fn() for controllers
};
```

**`inputSchema` is one merged schema, nested not flat.** Each slot sits under its own key:

```ts
inputSchema['~standard'].jsonSchema.input({ target: 'draft-2020-12' })
// {
//   type: 'object',
//   properties: { body?: <body schema>, query?: <query schema>, params?: <params schema> },
//   required: [...],            // slots that exist in properties
//   additionalProperties: false,
// }
```

So `execute` is called as `tool.execute({ body, query, params })`, not `tool.execute({ ...flat })`.

It is simultaneously a **Standard Schema** (`~standard.validate`) and a **Standard JSON Schema** (`~standard.jsonSchema.input()`), so consumers take whichever they support without a conversion step.

**What its `validate` actually checks depends on the module kind:**

| Module kind | Slot schemas | `validate` behavior |
|---|---|---|
| Controllers / procedures | Your original Zod / Valibot / ArkType schemas | Envelope **and** slot values |
| RPC modules, OpenAPI mixins | Reconstructed from generated JSON Schema | **Envelope only** — required slots present, no unknown keys; values validated during execution |

Mixins therefore *do* produce usable tools including for MCP — see "Mixins and MCP" below.

## Customizing tool name + description

Default `name = ${ModuleName}_${handlerName}`, default `description = ${summary}\n${description}` from `@operation`. Override via `@operation.tool({ … })` (recommended cleaner form):

```ts
import { prefix, get, operation, procedure } from 'vovk';

@prefix('user')
export default class UserController {
  @operation.tool({
    name: 'get_user_by_id',                // overrides UserController_getUser
    title: 'Get user by ID',               // shown in MCP clients
    description: 'Retrieves a user by their unique ID, including name and email.',
  })
  @operation({ summary: 'Get user by ID', description: 'Retrieves a user by their unique ID.' })
  @get('{id}')
  static getUser = procedure({ /* ... */ });
}
```

Equivalent long form: `@operation({ ..., 'x-tool': { name, title, description, hidden, meta } })`. Keys (all optional):

| Key | Effect |
|---|---|
| `hidden: true` | Procedure excluded from `deriveTools` output. |
| `name` | Overrides default `ModuleName_handlerName`. |
| `title` | Optional title — used by MCP clients in tool-list UI. |
| `description` | Overrides `summary\ndescription` concatenation. |
| `meta` | Static `Record<string, unknown>` copied to `tool.meta` for consumers to read. Not sent to the model. |

Don't confuse `x-tool.meta` (static, per tool, ends up on `tool.meta`) with `deriveTools({ meta })` (runtime context handed to every procedure, readable via `req.vovk.meta()`).

## Hide procedures

Canonical: `hidden: true`.

From finom/vovk, MIT.

More from finom/vovk

Signals

Stars
54
Forks
0
Open issues
0
Last commit (this folder)
Oct 20, 2026 (7 days ago)
Last release
Oct 22, 2026 (5 days ago)

From GitHub (fetched Oct 24, 2026).

Details

License
MIT
Website
vovk.dev
First seen
Oct 24, 2026
Last checked
Oct 24, 2026

More from finom

Cite this page

tools skill. Agent Mart. https://agentmart.dev/skills/finom-tools (last updated 2026-10-24)