---
title: Functions as tools
description: Reuse a function as an AI tool without duplicating its schemas or business logic.
pagination: false
sidebar:
  icon: braces
---

Turn an existing function into a tool with `.asTool()` so an agent or MCP client can call it. Keep the business logic in the function and add a description and execution policy for AI callers.

> **Before you begin**
>
> Start with an [installed minimal app](/docs/learn/create-an-app). Function-backed tools need no
> LangChain integration. [MCP](/docs/modules/ai/mcp) and [native
> agents](/guides/ai/build-an-offline-agent) each add their own selected dependencies when you
> choose those execution paths.

1. ## Define the function

    This small function returns a greeting. In a real app, the function might look up a product or fetch an order the current user is allowed to see.

    ```ts title="src/services/hello/functions/hello.function.ts"
    /** Returns a validated named greeting and logs each invocation through RELKIT's request context. */
    import { defineFunction } from "@relkit/app/functions";
    import { z } from "@relkit/app/schema";

    const hello = defineFunction({
      id: "hello.greet",

      input: z.object({ name: z.string().min(1).default("world") }),
      output: z.object({ message: z.string() }),

      /**
       * Logs the greeting invocation and returns the validated greeting response.
       * @param input - Validated name from the function schema.
       * @param context - RELKIT invocation context owning structured logging.
       * @returns Greeting response matching the output schema.
       */
      handler: async ({ name }, context) => {
        context.log.info("hello invoked", { name });

        return { message: `Hello, ${name}!` };
      },
    });

    export default hello;
    ```

2. ## Turn it into a tool

    Import the function into a tool file and call `.asTool()`:

    ```ts title="src/services/hello/tools/lookup.tool.ts"
    /** Exposes the hello function as a read-only greeting tool with its existing two-second timeout. */
    import hello from "@app/services/hello/functions/hello.function.js";

    export default hello.asTool({
      id: "hello.lookup",
      description: "Read a greeting for a supplied name",

      sideEffect: "read",
      approval: "never",
      timeoutMs: 2_000,
    });
    ```

    The tool accepts the same input and returns the same output as `hello`. The function remains callable by the rest of your app.

    Use a normal `defineFunction` here. Event-only functions created with `defineEventFunction` cannot become tools.

3. ## Use the tool

    Add `lookup` to an [agent's tools](/docs/modules/ai/agents), or call `hello.lookup` from [an MCP client](/docs/modules/ai/mcp). Both use the same greeting function.

    `.asTool()` and [`defineTool({ target: hello, ... })`](/docs/modules/ai/tools) are alternatives; you do not need both. Both expose the tool to MCP by default. Set `mcp: false` if the tool should be available only inside your app.
