Core features
Architecture
@businys/ops is a composable middleware pipeline built around a storage-agnostic adapter interface. Swap adapters without changing middleware. Add or disable layers without touching others.
Middleware pipeline
createMCPProxy() assembles the default pipeline in order. Each layer wraps the next — next() executes the downstream layers and ultimately the actual tool handler.
createLineageMiddlewareoptionalcreateTelemetryMiddlewareoptionalcreateMeteringMiddlewarecreateReputationMiddlewarecreateRateLimitMiddlewarecreateConfirmationMiddlewarecreateRevenueMiddlewareoptionalcreateAuditMiddlewaremiddleware: [...]optionalcreateMCPProxy()
Batteries-included pipeline. All middleware enabled by default except lineage, telemetry, and revenue (which require explicit configuration).
import { createMCPProxy, FileAdapter } from "@businys/ops"
const proxy = createMCPProxy({
// Storage backend (default: MemoryAdapter)
storage: new FileAdapter({ path: ".ops-data.json" }),
// Rate limit options
rateLimit: {
globalMax: 100, // calls per window across all agents
groupMax: 20, // calls per window per agent group
windowMs: 60_000, // window size in ms
},
// Disable specific layers
disable: {
reputation: false,
rateLimit: false,
metering: false,
audit: false,
confirmation: false,
},
// Audit log sink (default: process.stderr)
auditLog: (entry) => myLogger.info(entry),
// OpenTelemetry (optional)
telemetry: { tracer: opentelemetry.trace.getTracer("my-server") },
// Agent Lineage (optional)
lineage: { store: new MemoryLineageStore() },
// MCP Revenue (optional)
revenue: {
pricing: {
default: { perCall: 1 },
overrides: { expensive_tool: { perCall: 10 } },
},
},
// Custom middleware (appended last)
middleware: [myCustomMiddleware],
})Storage adapters
Every adapter implements the StorageAdapter interface. The interface covers call records, stats, reputation, loop detection, SSE subscriptions, and credit wallets. Swap adapters without changing any middleware.
MemoryAdapterIn-memory ring buffer. Zero config. Resets on restart. Default when no storage is passed.
FileAdapterJSON file on disk. Persists across restarts. Good for local dev and CI.
PostgresAdapterPostgreSQL via pg. Requires peer dependency: npm install pg. Full production support.
HostedAdapterIn-memory ring buffer + async batch flush to businysdotdev hosted dashboard. Team-accessible, persistent, with compliance export.
Custom middleware
Implement the Middleware interface to add your own layers:
import type { Middleware } from "@businys/ops"
const myMiddleware: Middleware = {
name: "my-middleware",
async execute(ctx, next) {
// ctx.toolName, ctx.agentId, ctx.input, ctx.bearerToken, ...
console.log("before:", ctx.toolName)
const result = await next() // call downstream
console.log("after:", result.isError ? "error" : "ok")
return result
},
}
const proxy = createMCPProxy({ middleware: [myMiddleware] })MiddlewareContext
| Field | Type | Description |
|---|---|---|
toolName | string | The MCP tool being called |
toolGroup | string | Group prefix (e.g. client from client_create) |
toolTier | "core" | "craft" | "kit" | Tool tier classification |
method | string | MCP method (e.g. tools/call) |
path | string | Request path |
input | Record<string, unknown> | Tool call arguments |
agentId | string | Agent identifier from the API key or header |
serverName | string | MCP server name |
startedAt | number | Unix timestamp ms when the call started |
destructive | boolean | True if the tool is marked as destructive |
bearerToken? | string | undefined | Raw bearer token from Authorization header |