AgentStack
MCP verified MIT Self-run

Ageniti

mcp-ageniti-ageniti · by Ageniti

A standard SDK for building agent-facing apps across MCP, CLI, React, and AI tool stacks.

No reviews yet
0 installs
12 views
0.0% view→install

Install

$ agentstack add mcp-ageniti-ageniti

✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README — it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/mcp-ageniti-ageniti)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
1mo ago

Declared compatibility

Claude CodeClaude DesktopCursorWindsurf

Compatibility is declared by the source manifest. End-to-end runtime verification is coming — see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps — measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Ageniti? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Ageniti

The action primitive for apps that need to be callable by agents.

Website · GitHub · npm · Getting Started · API

Ageniti is the action primitive layer for apps that need to expose capabilities to agents, automation systems, and external tools. You define an action once — input contract, output contract, side effects, permissions — and any caller (CLI, HTTP, MCP, OpenAI / AI SDK tools, React UI, your own typed client) can invoke it through the same runtime, with the same streaming events, the same redaction, the same error contract.

> Stability — pre-1.0. Ageniti is currently 0.x. The action contract and > primary surfaces (CLI, HTTP, MCP, AI SDK) are stable enough for real use, but > minor versions may still introduce breaking changes to export shape, adapter > APIs, or manifest format until 1.0. Pin an exact version (@ageniti/core@0.1.x) > in production and read the [CHANGELOG](./CHANGELOG.md) before upgrading.

Why Ageniti

Modern apps want to be callable not just from people but from agents, scripts, and other apps. Today every entry point comes with its own glue: argv parsing, schema validation, tool descriptions, permission checks, log redaction, error shapes, idempotency, cancellation. Each surface re-implements the same things inconsistently.

Ageniti collapses all of that into one concept. Each action you declare runs through a single runtime that handles the cross-cutting concerns. Each surface is a thin adapter over the same contract. Streaming events let any consumer — agent caller, UI, log shipper — observe the action live without owning it.

Install

npm i @ageniti/core

Subpath exports:

| Subpath | What it gives you | |---|---| | @ageniti/core | Main authoring API plus packaging/project helpers such as buildArtifacts, packageArtifacts, publishArtifacts, createGuideDoc, exportDocs, initProject, doctorProject, and detectTypeScriptRuntime | | @ageniti/core/ai-sdk | createOpenAITools, createOpenAIResponsesTools, createAISDKTools, createFunctionCallingManifest | | @ageniti/core/adapters | Built-in surface adapters and helpers such as httpAdapter, mcpAdapter, aiSdkAdapter, cliAdapter, jsonAdapter, reactAdapter, devAdapter, defaultSurfaceAdapters, defineSurfaceAdapter, and findAdapter | | @ageniti/core/app, /core, /cli, /mcp, /dev, /manifest, /json-runner, /lint | Narrow imports for the corresponding runtime or surface modules | | @ageniti/core/http | createHttpHandler, createHttpServer, parseRequestBody, sendJson, sendText | | @ageniti/core/handlers | defineActions, actionFromHandler, actionsFromHandlers | | @ageniti/core/schema-adapter | wrapSchema, Zod / Standard Schema v1 interop | | @ageniti/core/schema | Schema helpers only | | @ageniti/core/client | createClient, AgenitiClientError | | @ageniti/core/client-gen | generateClientTypes, jsonSchemaToTs | | @ageniti/core/test-utils | createTestRuntime, expectOk, expectError, expectLog, collectStream, stubAction | | @ageniti/core/react | createReactActionAdapter, makeInvoker, streamAction (no React import) | | @ageniti/core/react-hooks | useAction — full state-machine hook (React peer dep) | | @ageniti/core/package.json | Package metadata for tooling that needs to inspect the published package |

The 5 Core Primitives

1. The Action Contract

import { defineAction, s } from "@ageniti/core";

export const createTask = defineAction({
  name: "create_task",
  description: "Create a task in the user's inbox.",
  sideEffects: "write",
  idempotency: "conditional",
  input: s.object({
    title: s.string().min(1),
    priority: s.enum(["low", "high"]).default("low"),
  }),
  output: s.object({ id: s.string(), title: s.string() }),
  async run({ title, priority }, ctx) {
    ctx.logger.info("Creating task", { title });
    const task = await ctx.services.tasks.create({ title, priority });
    return { id: task.id, title: task.title };
  },
});

The contract is the source of truth. Every surface — CLI flags, MCP tool definition, OpenAI tool spec, HTTP route, React hook, typed client — is derived from it. You never describe the same action twice.

2. Bring Your Own Schema

You don't have to use s.*. Zod, Valibot, ArkType, anything that quacks like Standard Schema v1 just works:

import { z } from "zod";
import { defineAction } from "@ageniti/core";

export const search = defineAction({
  name: "search_tasks",
  description: "Search for tasks matching a query.",
  input: z.object({ query: z.string(), limit: z.number().int().optional() }),
  output: z.object({ results: z.array(z.object({ id: z.string(), title: z.string() })) }),
  async run({ query, limit }) {
    return { results: await tasks.search(query, limit ?? 20) };
  },
});

Ageniti detects foreign schemas (anything with .safeParse / .parse / "~standard".validate) and wraps them transparently. JSON Schema for MCP and OpenAI tool descriptions is generated from the wrapped schema.

3. Bulk-Wrap Functions You Already Have

For Next.js Server Actions, tRPC procedures, or any plain functions:

import { actionsFromHandlers, s } from "@ageniti/core";
import * as handlers from "./app/actions/tasks"; // your existing functions

export const actions = actionsFromHandlers(handlers, {
  createTask: {
    description: "Create a task.",
    input: s.object({ title: s.string() }),
    sideEffects: "write",
  },
  searchTasks: {
    description: "Search tasks.",
    input: s.object({ query: s.string() }),
  },
});

Or defineActions for full control:

import { defineActions, s } from "@ageniti/core";

export const actions = defineActions({
  createTask: {
    description: "Create a task.",
    input: s.object({ title: s.string() }),
    run: async ({ title }) => tasks.create({ title }),
  },
  // function shorthand for read-only no-input actions
  ping: () => ({ ok: true, time: Date.now() }),
});

CamelCase keys are normalized to snake_case action names automatically.

4. Streaming Events

Every action runs through a runtime that emits live events as it executes. UIs, agents, and log shippers can subscribe without owning the action:

const events = runtime.stream("create_task", { title: "Ship v1" });

for await (const event of events) {
  if (event.type === "log") console.log(event.level, event.message);
  if (event.type === "progress") updateProgressBar(event.percent);
  if (event.type === "artifact") attachToUi(event.artifact);
  if (event.type === "result") finalize(event.envelope);
}

Events come from ctx.logger.*, ctx.progress.report(), and ctx.artifacts.add() inside your run() function. The CLI's --ndjson mode and the React hook are both built on this primitive.

5. Typed Client + Codegen

import { createClient } from "@ageniti/core/client";

// In-process
const client = createClient({ runtime });
const task = await client.create_task({ title: "Hello" });
//      ^? { id: string; title: string }

// Or talk to a remote @ageniti HTTP server
const remote = createClient({ url: "https://api.example.com" });
const tasks = await remote.search_tasks({ query: "today" });

Remote HTTP clients can send metadata, confirm, and idempotencyKey. Trusted user / auth must be resolved server-side via headers or resolveContext, not passed in the request body.

Generate .d.ts for the typed client surface from your action manifest:

import { generateClientTypes } from "@ageniti/core/client-gen";
import { writeFile } from "node:fs/promises";

await writeFile(".ageniti/client.d.ts", generateClientTypes(actions));

React

Two layers: a stateless adapter and a state-machine hook.

// app/components/CreateTaskButton.tsx
"use client";
import { useAction } from "@ageniti/core/react-hooks";
import { runtime } from "@/src/ageniti/app";
import { createTask } from "@/src/ageniti/actions/tasks";

export function CreateTaskButton() {
  const { invoke, status, data, error, logs, progress, cancel } =
    useAction(createTask, { runtime });

  return (
    <>
       invoke({ title: "Hello" })} disabled={status === "loading"}>
        {status === "loading" ? `${progress?.percent ?? 0}%` : "Create"}
      
      {status === "loading" && Cancel}
      {status === "success" && Created task {data.id}}
      {status === "error" && Error: {error.message}}
      {logs.map((l) => l.message).join("\n")}
    
  );
}

The hook subscribes to runtime.stream so logs / artifacts / progress update live during the invocation. Unmounts auto-abort.

Exposing Surfaces

import { createAgenitiApp, createMcpStdioServer } from "@ageniti/core";
import { actions } from "./actions";

export const app = createAgenitiApp({
  name: "tasks",
  actions,
  description: "Task management actions for operators, automation, and agent callers.",
});

// CLI
app.createCli().main();

// MCP stdio (auto-detects Content-Length or newline framing)
createMcpStdioServer({ actions: app.actions, runtime: app.runtime }).start();

// HTTP (Express / Hono / Next.js Route Handler / raw Node)
const handler = app.createHttpHandler();

// OpenAI / AI SDK tool specs
const openai = app.createOpenAITools();
const responses = app.createOpenAIResponsesTools();
const aiSdk = app.createAISDKTools();
const manifest = app.createFunctionCallingManifest();

Each surface is generated from the same action contract.

Runtime Capabilities

The runtime handles all the cross-cutting concerns so your run() function stays focused on business logic:

  • Validation (input, output, JSON-serializable check)
  • Permission gating (overridable permissionChecker)
  • Confirmation gate for destructive actions (machine surfaces require

{ confirm: true } or surface to be react/dev)

  • IdempotencyidempotencyKey replays a cached envelope scoped by

action, validated input, surface, and trusted caller fingerprint; LRU cap keeps memory bounded

  • Concurrency limits per action — returns CONCURRENCY_LIMIT (retryable)
  • Timeout + retry — per-attempt AbortController so retries see fresh

signal

  • Cancellation — external signal, CLI SIGINT, React unmount all wired
  • Streaming events — log / progress / artifact / result
  • Redaction — log fields, artifact metadata, error messages (Bearer /

JWT / sk- style tokens)

  • HooksonInvocationStart, onInvocationEnd for telemetry
  • Deprecated warnings — emitted on every invocation of a deprecated action

The Envelope

Every invocation returns the same envelope shape:

{
  ok: true,
  data: { /* validated output */ },
  artifacts: [...],
  logs: [...],
  meta: { action, invocationId, surface, durationMs, idempotent? },
}

Or on failure:

{
  ok: false,
  error: { code, message, issues, retryable },
  artifacts: [...],
  logs: [...],
  meta: { ... },
}

Standard error codes are exported as ERROR_CODES:

ACTION_NOT_FOUND, VALIDATION_ERROR, OUTPUT_VALIDATION_ERROR,
OUTPUT_SERIALIZATION_ERROR, AUTHENTICATION_ERROR, AUTHORIZATION_ERROR,
RATE_LIMITED, TIMEOUT, CANCELLED, CONFLICT, EXTERNAL_SERVICE_ERROR,
INTERNAL_ERROR, UNSUPPORTED_SURFACE, UNSAFE_ACTION,
CONFIRMATION_REQUIRED, CONCURRENCY_LIMIT

HTTP maps these to 400 / 401 / 403 / 404 / 405 / 409 / 413 / 415 / 429 / 499 / 500 / 502 / 504. CLI maps them to 0 / 1 / 2 / 3 / 4 / 5 / 124 / 130.

Testing

import { createTestRuntime, expectOk, expectError, collectStream } from "@ageniti/core/test-utils";
import { createTask } from "./actions/tasks";

test("create_task happy path", async () => {
  const t = createTestRuntime([createTask], { services: { tasks: stubTasksService } });
  const env = await t.invoke("create_task", { title: "Hello" });
  const data = expectOk(env);
  expect(data.title).toBe("Hello");
});

test("rejects empty title", async () => {
  const t = createTestRuntime([createTask]);
  const env = await t.invoke("create_task", { title: "" });
  expectError(env, "VALIDATION_ERROR");
});

test("emits progress events", async () => {
  const t = createTestRuntime([longRunning]);
  const events = await collectStream(t.stream("long_running", {}));
  const progress = events.filter((e) => e.type === "progress");
  expect(progress.length).toBeGreaterThan(0);
});

Drop-In Into An Existing App

You don't restructure your app. Pick the functions you want to expose, declare them as actions, mount the surfaces:

// app/actions/tasks.ts — your existing Server Actions / handlers
"use server";
export async function createTask(input: { title: string }) { /* ... */ }

// src/ageniti/app.ts — new
import { createAgenitiApp, actionsFromHandlers, s } from "@ageniti/core";
import * as handlers from "@/app/actions/tasks";

export const app = createAgenitiApp({
  name: "tasks",
  actions: actionsFromHandlers(handlers, {
    createTask: {
      description: "Create a task.",
      input: s.object({ title: s.string() }),
      sideEffects: "write",
    },
  }),
});

// app/api/[[...ageniti]]/route.ts
import { app } from "@/src/ageniti/app";
const handler = app.createHttpHandler();
export { handler as GET, handler as POST };

That's it. The same actions are now reachable from CLI (npx ageniti create-task --title hello), MCP (ageniti mcp --stdio), HTTP (/ageniti/...), OpenAI / AI SDK tools, and the React hook.

Examples

| File | Shows | |---|---| | [examples/hello.cli.js](examples/hello.cli.js) | Minimum viable action + CLI | | [examples/task-app.js](examples/task-app.js) | Real-world app with multiple actions | | [examples/demo.cli.js](examples/demo.cli.js) | Multi-surface demo app with CLI, dev, and MCP modes | | [examples/buildable-app.mjs](examples/buildable-app.mjs) | Minimal build-safe app export for launcher/package flows | | [examples/streaming.js](examples/streaming.js) | Live progress / log streaming | | [examples/zod-action.js](examples/zod-action.js) | Using Zod-style schemas | | [examples/typed-client.js](examples/typed-client.js) | Typed in-process client, raw envelopes, streams, and client codegen | | [examples/bulk-handlers.js](examples/bulk-handlers.js) | defineActions / actionsFromHandlers | | [examples/test-helpers.test.js](examples/test-helpers.test.js) | Testing actions | | [examples/openai-responses-host.js](examples/openai-responses-host.js) | OpenAI Responses tool spec | | [examples/ai-sdk-route.js](examples/ai-sdk-route.js) | Vercel AI SDK tool integration | | [examples/http-gateway.js](examples/http-gateway.js) | HTTP server with detailed status codes | | [examples/mcp-host.js](examples/mcp-host.js) | MCP host calling actions |

Documentation

  • [Getting Started](docs/getting-started.md)
  • [API Reference](docs/api.md)
  • [Scope](docs/scope.md)
  • [Skill Spec](docs/skill.md)
  • [Release Checklist](docs/release-checklist.md)

Contributing

PRs and issues welcome. See [CONTRIBUTING.md](CONTRIBUTING.md).

Security

See [SECURITY.md](SECURITY.md) for vulnerability reporting.

License

MIT — see [LICENSE](LICENSE).

Source & license

This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet — be the first.

Versions

  • v0.1.0 Imported from the upstream source.