New:Microsoft Teams Notifications Are Now Available in Socket.Learn more
Get Started

mcp-budget-governor

Package Overview
Dependencies
Maintainers
1
Versions
1
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

mcp-budget-governor

Distributed, cost-denominated budget enforcement for MCP servers: per-user quotas, per-tool limits, and a global spend circuit breaker backed by atomic Redis counters.

latest
Source
npmnpm
Version
0.1.0
Version published
Maintainers
1
Created
Source

mcp-budget-governor

The TypeScript sibling of the Python package. Same policy model, same key scheme, and — importantly — the same Lua scripts, loaded from lua/ at the repo root rather than reimplemented here.

npm install mcp-budget-governor ioredis
import { Redis } from 'ioredis';
import {
  Governor, Limit, Policy, PriceTable, RedisBackend, Scope, Unit, Window, usd,
} from 'mcp-budget-governor';

const policy = Policy.of(
  new Limit({ name: 'per_user_calls', cap: 2_000, window: Window.DAY, scope: Scope.USER }),
  new Limit({ name: 'burst', cap: 30, window: Window.MINUTE, scope: Scope.USER }),
  new Limit({
    name: 'global_spend',
    cap: usd(25),
    window: Window.DAY,
    unit: Unit.USD_MICROS,
    breaker: true,
    gated: false,
  }),
);

const governor = new Governor(policy, {
  backend: new RedisBackend(new Redis('redis://localhost')),
  prices: PriceTable.builtin(),
});

const decision = await governor.check({ user: 'u_42' });
if (!decision.allowed) throw new Error(`rate limited, retry in ${decision.retryAfter}s`);

const result = await callTheModel();
await governor.meterTokens('global_spend', 'claude-opus-5', {
  inputTokens: result.usage.input,
  outputTokens: result.usage.output,
});

Why this exists as a port rather than a rewrite

Most MCP servers are TypeScript, so a Python-only library addresses the minority of the ecosystem it is pitched at. But the interesting property isn't parity — it's that a Node server and a Python worker sharing one Redis enforce one budget. They are two clients of a single enforcement layer, not two libraries that happen to behave alike.

That works because the actual contract is not either language:

  • The Lua scripts are loaded from one directory by both packages. There is no translation to drift, because there is no translation.
  • The key scheme is the other half, and it is verified rather than asserted: conformance/generate_vectors.py emits keys, TTLs, buckets, USD conversions, price calculations, and script digests from the Python implementation, and the TypeScript suite checks itself against them. CI regenerates the vectors and fails if the committed ones are stale, so a Python-side change nobody mirrored breaks the build rather than passing against a fixture.
  • A live cross-language test. With a real Redis, conformance.test.ts shells out to the Python implementation mid-test and asserts a charge written by one language is visible to the other and that one cap is enforced across both.

API differences from Python

Same concepts, idiomatic naming — snake_case becomes camelCase, keyword arguments become an options object, and the two places where the languages genuinely differ:

PythonTypeScript
decision.raise_for_status()raiseForStatus(decision)
async with governor.reserved(...) as r:await governor.reserved(name, est, async (r) => { ... })
Limit("n", cap=1, window=Window.DAY)new Limit({ name: 'n', cap: 1, window: Window.DAY })
scope=(Scope.USER, Scope.TOOL)scope: [Scope.USER, Scope.TOOL]

The MemoryBackend needs no lock here: Node runs one statement sequence at a time and none of its critical sections await between reading a counter and writing it back. If you add an await in the middle of one, you have reintroduced the race the Python lock exists to prevent.

Client compatibility

RedisBackend takes anything matching RedisLikeeval(script, numKeys, ...args) and get(key). ioredis satisfies it as-is. node-redis v4 uses a different eval shape and needs a small adapter. The client is passed in rather than constructed so your app shares its existing pool.

Development

npm install
npm run typecheck
npm test                                          # unit + offline conformance
MCPBG_TEST_REDIS_URL=redis://localhost:6379/15 npm test   # + live cross-language

Without MCPBG_TEST_REDIS_URL the shared-Redis conformance tests skip; the key, price, and Lua-digest comparisons always run.

Keywords

mcp

FAQs

Package last updated on 06 Aug 2026

Related posts