Browse documentation

Connect

Tools, MCP, and OpenAPI

Add local functions and authorized remote tools through one lazy catalog.

Local tools are normal Zod-backed functions:

export const searchDocs = app.fn({
  description: "Search product documentation",
  input: z.object({ query: z.string().min(1) }),
  output: z.array(z.object({ title: z.string(), url: z.string().url() })),
  run: ({ query }) => docs.search(query),
});

const github = app.mcp("github");
export const tools = app.tools({ searchDocs, github });

Importing this registry and assigning it to a function or agent completes registration. Local functions are read tools by default. Mark a tool as a write only when it changes external state; writes require approval by default.

In the personal dashboard, open Connections and paste the server’s HTTPS MCP URL. Flary discovers its OAuth service, opens the consent page, receives the callback in your Worker, encrypts the credential, checks the tool list, and makes the tools available to new agent turns. You do not edit TypeScript or copy an MCP token.

The backend template stays code-first. Its optional GitHub example generates the source and trusted token resolver. A custom backend can declare a logical source and resolve it from its own connection store:

const connections = app.mcp({
  namespace: "connections",
  connection: "my-mcp-store",
});

Add an OpenAPI service with one source declaration:

const billing = app.openapi({
  namespace: "billing",
  spec: "./openapi/billing.yaml",
  connection: "billing-api",
});

Built-in coding tools

app.workspace() is a complete durable file and Git source. It adds list, stat, glob, grep, read, diff, write, edit, batchEdit, move, delete, and the governed Git operations. File writes and state-changing Git operations require approval by default.

app.sandbox() is separate. It runs Linux commands, tests, builds, package installation, and durable processes. Use the workspace source for file and Git state. Use the Sandbox source for programs that need a Linux process.

See the complete Codex-style coding agent for the real starter files, every tool name, the isolated executor flow, a durable reviewer subagent, checkpoints, and reconnect code.

Small core, lazy extensions

The model sees one bounded execute tool. The tool instructions include the names and purpose of configured core workspace, shell, and browser actions. The agent therefore knows that actions such as workspace.grep, workspace.edit, and shell.exec exist without a catalog search.

The exact action schemas are still lazy. Generated code describes a selected action before it calls it. MCP, OpenAPI, local functions, skills, and large or changing catalogs stay fully lazy. This keeps the stable coding surface easy to use and prevents hundreds of external schemas from entering every model request.

Every call passes through capability checks, policy, approval, input validation, redaction, limits, and durable replay. Provider, MCP, and API credentials stay in trusted host code.

OpenAPI GET, HEAD, and OPTIONS operations are reads by default. Mutating methods require approval by default. A remote specification cannot lower that protection.

Tested starter source

import { z } from "flary";

import { app } from "./flary";
import { generated } from "./flary.generated";

export const searchDocs = app.fn({
  description: "Search the product documentation",
  input: z.object({ query: z.string().min(1) }),
  output: z.array(
    z.object({
      title: z.string(),
      url: z.string().url(),
      excerpt: z.string(),
    }),
  ),
  run: ({ query }) => [
    {
      title: `Documentation result for ${query}`,
      url: "https://example.com/docs",
      excerpt: "Replace this function with your documentation search.",
    },
  ],
});

const optionalTools = {
  ...(generated.features.mcp
    ? {
        github: app.mcp({
          namespace: "github",
          connection: "github",
          url: "https://api.githubcopilot.com/mcp/readonly",
        }),
      }
    : {}),
  ...(generated.features.browser
    ? { browser: app.browser({ profile: "thread" }) }
    : {}),
  ...(generated.features.sandbox
    ? { shell: app.sandbox({ network: "restricted", sleepAfter: "10m" }) }
    : {}),
};

/** Tools for finite support functions. */
export const supportTools = app.tools({ searchDocs });

/**
 * A complete coding workspace.
 *
 * app.workspace() supplies durable list, stat, glob, grep, read, diff,
 * write, edit, batch-edit, move, delete, and Git tools. app.sandbox()
 * supplies Linux commands and durable processes when that feature is enabled.
 */
export const codingTools = app.tools({
  workspace: app.workspace({ branch: "run" }),
  ...optionalTools,
});