npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

algenta-tools

v1.0.0

Published

Vercel AI SDK tool integration for Algenta: a governed-execution-aware ToolSet wrapping a self-hosted Algenta engine's MCP tool surface

Readme

algenta-tools

npm License: Apache-2.0

Docs: docs.algenta.ai · All integrations

Vercel AI SDK (ai v7) tool integration for Algenta: createAlgentaTools, a factory that connects to your own self-hosted Algenta engine's MCP endpoint (via @ai-sdk/mcp's real MCP client) and returns an Algenta-aware AI SDK ToolSet ready to pass to generateText / streamText / an Agent. It layers on:

  • Tool-profile filtering — expose only observe (read-only, the default), govern, execute, or the opt-in full registry, per contracts/integration-tool-contract.json.
  • Never-model-facing field scrubbing — force/override_safety (operator/break-glass-only fields on execute_decision's real schema) are stripped from every tool's advertised JSON Schema and from the arguments object actually forwarded to the wrapped MCP call, in every profile.
  • execute_decision's typed success/denial contract — a successful call is parsed into a typed ExecutionReceipt; a blocked call surfaces as a typed ExecutionBlockedError thrown from execute(), carrying the engine's real named safety gate. See Executing a decision below for the full mapping.

Prerequisites

  • Node.js 22 or later.
  • Your own running, self-hosted Algenta engine, reachable over HTTP — createAlgentaTools never talks to any Algenta-hosted service (see Self-hosted-only below). If you don't have one running yet, skip to Try it locally below — it exercises this package's real tool listing, schemas, and receipt shapes against a local stub server instead, no engine required.
  • A model provider configured for the AI SDK (an API key such as OPENAI_API_KEY, set however your chosen AI SDK provider expects it) — only needed once you get to an actual generateText / streamText call in Quickstart below; nothing before that requires one.

Install

npm install algenta-tools ai zod

(swap in whichever package manager your project already uses — pnpm add/yarn add take the same package names).

ai (^7.0.0) and zod (^4.0.0) are peer dependencies — you already have them in any project using the AI SDK. This package's only real dependency is @ai-sdk/mcp, the AI SDK's own current MCP client package (see Why @ai-sdk/mcp and not ai below). It does not depend on the published algenta-sdk npm package — that package is a thin HTTP/gRPC client for Algenta's REST-shaped API surface (datasets, runtime, simulations), not an MCP client, so it has nothing this package's MCP-protocol tool-calling path would use (see Why not reuse algenta-sdk's MCP_ENDPOINT/DEFAULT_BASE_URL constants below for the one overlap that was considered and rejected). This package never depends on, imports, or bundles any part of the Algenta engine itself.

Building from source

To develop this package itself rather than consume the published one, work from a clone:

git clone https://github.com/thyn-ai/algenta-integrations.git
cd algenta-integrations/typescript/algenta-tools
pnpm install
pnpm --filter algenta-tools build

See Testing this package's own test suite below for how to run its tests from there.

Self-hosted-only

createAlgentaTools talks to your own self-hosted Algenta engine over its MCP endpoint. There is no Algenta-hosted cloud service for it to fall back to — the endpoint always resolves to somewhere you run, in this order:

  1. baseUrl passed to createAlgentaTools,
  2. the ALGENTA_BASE_URL environment variable,
  3. http://localhost:8000/mcp (the default for a local self-hosted engine).

Quickstart

Needs a running self-hosted engine and a configured model provider — see Prerequisites above. No engine yet? See Try it locally below instead.

import { streamText } from "ai";
import { createAlgentaTools } from "algenta-tools";

// Talks to your own self-hosted engine (ALGENTA_BASE_URL, or the baseUrl option below).
const tools = await createAlgentaTools({ baseUrl: "http://localhost:8000/mcp", profile: "observe" });

const result = streamText({
  model: "openai/gpt-5",
  tools,
  prompt: "What's the expected value of scenario X?",
});

profile: "observe" is also the default if you omit it — the model can call get_contract / query_data / simulate / recommend, and nothing that writes, plans, or executes anything. See Tool profiles to opt into more.

Every other tool's result is returned as its own real, freeform response body (a plain pass-through). execute_decision is the one exception — see Executing a decision below.

Try it locally (no live engine required)

Everything in this package except an actual model turn can be exercised without a live Algenta engine, using the same stub MCP server this package's own test suite runs against (src/test-support/stub-server.ts). This needs a clone of this repository (see Building from source above) — the stub server isn't part of the published package.

cd algenta-integrations/typescript/algenta-tools
pnpm install
pnpm --filter algenta-tools example

That runs examples/try-it-locally.ts, which:

  1. starts the stub server and connects createAlgentaTools to it like a real engine,
  2. lists the real tool names in the observe and execute profiles,
  3. prints execute_decision's real advertised schema, showing force/override_safety already stripped,
  4. calls log_decision and execute_decision for real and prints the real ExecutionReceipt, and
  5. calls execute_decision again on the same decision_id and prints the real ExecutionBlockedError this produces (the "idempotency" gate).

Swap the stub's URL for your own engine's and the same code talks to the real thing.

Recipes

Ten runnable, tested recipes for the most popular AI SDK patterns — governed agents, typed denials, receipt-typed results, BM25 retrieval with decision-memory logging, decision simulation as a tool, profile-filtered toolsets, streaming governed turns, human-in-the-loop approvals, generateObject decision schemas, and audit-logging middleware — live in ../../recipes, each with its own test suite and a zero-credential run command (pnpm --filter algenta-tools-recipes recipe:NN). See the recipe index.

Tool profiles

| Profile | Adds | Notes | |---|---|---| | observe (default) | get_contract, query_data, simulate, recommend | Read-only. | | govern | + plan_decision, log_decision | Propose/record decisions; never executes. | | execute | + execute_decision | Real-world execution — see below. | | full | everything the connected engine advertises | Opt-in only; admin/ops tooling. |

const tools = await createAlgentaTools({ baseUrl: "...", profile: "execute" });

An observe-profile ToolSet genuinely does not contain execute_decision (or anything govern/execute-tier) — it's not just undocumented, the model has no way to know it exists. force/override_safety are never exposed either, in any profile: stripped from the advertised JSON Schema and scrubbed from the arguments object actually forwarded to the wrapped MCP call, in case something upstream still tried to pass one.

Executing a decision

execute_decision(decision_id, webhook_url, timeout_seconds?, force?, override_safety?, metadata?) dispatches one already-logged decision (from log_decision) for real-world execution — a webhook delivery. There is no separate approval-pending state to wait out: the real engine's call is synchronous. It either:

  • Succeeds (200) and returns a real ExecutionReceipt — decision_id, webhook_url, execution_status ("delivered" | "failed"), response_code, executed_at, policy_snapshot_id, schema_snapshot_id, manifest_version, payload_summary, safety_overridden — which createAlgentaTools parses and returns from execute() like any other successful tool call, or

  • Is blocked, in the same call, naming exactly one of three real safety gates:

    • "idempotency" — this decision_id was already delivered; bypassable only by a human operator passing force: true for one re-execution,
    • "confidence" — the logged decision's confidence is below policy.min_confidence,
    • "risk_floor" — the logged decision's risk_p5 is below -policy.risk_floor,

    the last two bypassable only by a human operator passing override_safety: true. Neither force nor override_safety is ever model-facing — see Tool profiles above.

A blocked call throws an ExecutionBlockedError from execute() — the same native "tool call failed" idiom every other tool-level error in this package already goes through (AI SDK surfaces a thrown error as a tool-error part). ExecutionBlockedError carries the engine's real gate ("idempotency" | "confidence" | "risk_floor"), code (e.g. "execution_blocked_confidence"), and overrideHint, so your code can branch on error.gate directly instead of re-parsing error.message:

import { ExecutionBlockedError } from "algenta-tools";

try {
  const receipt = await tools.execute_decision!.execute!(
    { decision_id, webhook_url },
    executionOptions,
  );
} catch (error) {
  if (error instanceof ExecutionBlockedError) {
    // error.gate: "idempotency" | "confidence" | "risk_floor"
    // error.code, error.overrideHint carry the engine's own values verbatim.
  }
}

There is no approval-pause state here, so createAlgentaTools sets no needsApproval (or any other pause/resume gate) on execute_decision — same as every other tool. A prior version of this package modeled an approval-pending flow keyed on a plan_hash/approval_state shape; that shape does not exist anywhere on the real execute_decision tool, and has been removed.

This is the full mapping execute_decision goes through:

| Real engine response | Result | |---|---| | 200, a valid ExecutionReceipt | Returned as a typed ExecutionReceipt | | Blocked on a named gate (idempotency / confidence / risk_floor) | Throws ExecutionBlockedError, with gate/code/overrideHint | | Any other tool-error result | Throws a plain Error |

Every other tool's result — plan_decision's DecisionPlan summary, log_decision's {decision_id, chosen_action, expected_value, confidence, created_at, note}, query_data's rows, etc. — is returned from execute() unchanged; none of them share execute_decision's receipt/denial shape, so this package doesn't try to parse them into it.

Why @ai-sdk/mcp and not ai itself?

AI SDK's MCP client support (experimental_createMCPClient / createMCPClient) used to live directly in the ai package, but — verified directly against the installed packages while building this integration, not assumed from memory — it has since moved into its own dedicated @ai-sdk/mcp package (ai's own dist/index.d.ts no longer exports an MCP client at all in the version this package was built and tested against). @ai-sdk/mcp's own changelog documents the migration explicitly: import { experimental_createMCPClient } from "ai" becomes import { experimental_createMCPClient } from "@ai-sdk/mcp". This package depends on @ai-sdk/mcp directly rather than assuming it ships bundled inside ai.

Why not reuse algenta-sdk's MCP_ENDPOINT/DEFAULT_BASE_URL constants?

The published algenta-sdk package exports DEFAULT_BASE_URL (https://api.algenta.ai) and MCP_ENDPOINT (https://api.algenta.ai/mcp) — checked directly against the installed package while building this integration. Both point at Algenta's hosted cloud endpoint, which is exactly the default this package must never use (see Self-hosted-only above and the contract's self_hosted_only_note). createAlgentaTools therefore defines its own DEFAULT_ALGENTA_BASE_URL = "http://localhost:8000/mcp", matching the sibling pydantic-ai-algenta package's own default, instead of importing a constant from algenta-sdk that would silently point every unconfigured caller at Algenta's cloud. This was the only thing algenta-sdk had that overlapped with this package's job at all, and it turned out to be exactly the wrong default — so this package does not declare algenta-sdk as a dependency (see Install above).

Why a factory function and not a class?

The sibling Python package exposes AlgentaToolset, a pydantic_ai.toolsets.wrapper.WrapperToolset subclass, because pydantic-ai's own tool-calling surface is built around a Toolset abstraction that frameworks are expected to subclass. AI SDK has no equivalent abstraction — a ToolSet is just Record<string, Tool>, and the idiomatic way real MCP integrations in this ecosystem expose their tools is a plain factory function returning that record, not a class wrapping one. createAlgentaTools follows that convention rather than inventing a parallel "toolset" concept AI SDK doesn't have.

Advanced: bringing your own MCP client or tool set

import { connectAlgentaMCPClient, createAlgentaTools } from "algenta-tools";

// Reuse an already-connected client across multiple profiles/calls, or configure it yourself
// (custom headers, an OAuth provider, maxRetries, ...).
const client = await connectAlgentaMCPClient({ baseUrl: "http://localhost:8000/mcp" });
const observeTools = await createAlgentaTools({ client, profile: "observe" });
const executeTools = await createAlgentaTools({ client, profile: "execute" });
// ... later: await client.close();

tools (a pre-built Record<string, Tool>) is also accepted instead of any connection option, for wrapping a hand-built or already-fetched tool set without talking to MCP at all — mirroring AlgentaToolset's wrapped= escape hatch on the Python side. tools and the connection options (client/baseUrl/headers/mcpClientConfig) are mutually exclusive.

Testing this package's own test suite (not your agent)

The test suite (src/*.test.ts) runs a real @modelcontextprotocol/sdk McpServer over a real local node:http socket (src/test-support/stub-server.ts) — a deliberately fake, deterministic stand-in for a self-hosted Algenta MCP endpoint, never a real engine (none is reachable in CI) — and drives it with a real @ai-sdk/mcp MCPClient and a real createAlgentaTools, over the real wire. Profile-filtering and schema/argument-scrubbing unit tests additionally use an in-memory fake ToolSet (via the tools option above) where a network round trip isn't the thing under test.

cd typescript/algenta-tools
pnpm install
pnpm --filter algenta-tools test

For a hands-on, interactive walkthrough instead of the automated suite, see Try it locally above.