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

@ultimat3/mcp

v18.0.0

Published

MCP server, dev tools, and the action-to-tool projection — one authz system, two surfaces

Readme

@ultimat3/mcp 🤖

The MCP surface. An agent that can reach this package needs no framework documentation — it asks instead of guessing.

The dev server: x mcp serve

| Tool | Scope | Answers | |---|---|---| | routes.list | dev:read | route table — url, render mode, offline strategy, hydrate, budget | | schema.describe | dev:read | entities with columns, types, invariants | | policies.list | dev:read | every policy: permission, subject, enforcement points | | actions.describe | dev:read | actions + queries: input/output schema, policy, cache tags, MCP exposure | | jobs.inspect | dev:read | job definitions, retry policy, steps (omit name for all) | | queue.depth | dev:read | pending / running / failed per queue | | manifest.read | dev:read | x.manifest.json verbatim | | errors.explain | dev:read | stable X_* code → cause + exact fix command + docs | | db.query | db:read | read-only, enforced four ways — SELECT-only role, BEGIN READ ONLY, one-statement parse, 5s/1000-row/256 KiB caps | | db.migrate | db:migrate | branch DB only — refuses production and any non-branch target | | tests.run | dev:test | runs the suite (executes project code) | | verify.run | dev:test | x verify — the shippable contract | | logs.tail | dev:logs | last N lines, optionally per runtime role |

db.query and db.migrate are gated and say so in their own description, so a model that reads only the catalog still knows what it is holding.

db.query's four layers

| Layer | Mechanism | Where | |---|---|---| | 1. Role | ultimate_readonlyNOLOGIN, SELECT on every table present and future, nothing on sequences; assumed with SET LOCAL ROLE inside the transaction, never via a second connection string | @ultimat3/db | | 2. Transaction | BEGIN READ ONLYROLLBACK on one reserved connection — Postgres refuses the write even if a grant is wrong | @ultimat3/db | | 3. Parse | one statement, a read leader, no mutating keyword at statement level, no lock — clause or pg_advisory_* call — and no call into a banned function family, matched by prefix of the called name — quoted and schema-qualified spellings included — so a new spelling is refused by default and a column sharing a prefix is not; on a form with literals and comments blanked | readonly-sql.ts | | 4. Limits | SET LOCAL statement_timeout, a hard 1000-row ceiling (limit clamps into it, never past it) and a 256 KiB byte cap | query-limits.ts |

The answer carries guards — the layers that actually engaged — plus truncatedBy and bytes. A layer that could not engage (a managed Postgres that refuses CREATE ROLE) is absent from the list, never assumed. Truncation is never silent.

One authz system, two surfaces

Every action with mcp: { expose: true } becomes a tool for free, and the tool's handle reaches the same invoke the HTTP route reaches — the projection's run is that call with surface: 'mcp', nothing more. Policy evaluation lives inside invoke. (An action has no .run member; run is the projection seam, and a query's half of it is sourceFor.)

HTTP  POST /api/posts/publish ─┐
                               ├─→ invoke(action, input, { surface, actor }) ─→ policy ─→ handler
MCP   tools/call publishPost  ─┘

mcp: { visibleTo: [...] } on the action or query travels with the projection too — the only declaration surface outcome 1 has for a projected tool. Catalog audience, never authz.

The projection itself declares no scope — a projection cannot know what a token means. defineAppMcp's scopes: map (below) may attach one afterward, as a capability of the CONNECTION rather than a second gate: it decides before the policy runs and never reads the input, so the two cannot disagree. There is no MCP-specific authorization code to review beyond it.

Security posture: three outcomes, hidden ≠ forbidden

| Refused by | Declared by | Answer | Wire | |---|---|---|---| | role | visibleTo | omitted from tools/list, ToolNotFound on call, no data | -32601 | | scope | scope | Forbidden, naming the missing scope + a runnable fix | -32600, X_MCP_SCOPE_DENIED | | policy | the primitive's own policy | isError result carrying code/cause/fix | X_FORBIDDEN |

Forbidden confirms a tool exists, which turns an authz boundary into a catalog an agent can enumerate by probing. So a role-hidden tool is indistinguishable from an absent one — even for a caller holding every scope in the system. A scope refusal is the opposite case: the caller was already shown the tool and can legitimately fix this, so hiding it would only strand a well-behaved client.

| Rule | Detail | |---|---| | A role list is fail-closed | a visibleTo role list admits only the roles it names, so a caller carrying no role matches none of them | | A predicate audience sees the caller and nothing else | it is handed McpCaller — never the call arguments, so two calls with different inputs cannot answer differently. Must return the literal true; if it throws, the tool is hidden | | tools/list is answered per caller | filtered on every call against the caller the transport resolved — one per HTTP request, one per stdio connection — never a static catalog | | Gate order | visibility → scope → arguments → policy; the scope gate never waits on a policy run against attacker-supplied input | | Every outcome is audited | one line per tools/call; hidden/scope/policy at warn, ok and invalid-args at info — see audit.ts. A tool that renders its OWN isError result may name the code it refused with (McpToolResult.code, audit-only, never on the wire) and is then classified by the same outcomeForCode a thrown error is — otherwise every self-rendered refusal lands in the policy-denied bucket a prober's name walk is alerted from | | Audit lines carry no payload | tool, outcome, actor, code. Never arguments, never rows | | No trusted-tool mode | there is no flag that skips policy evaluation |

Executable contract: security.test.ts. Rationale: docs/architecture/11-ai-surface.md.

Their apps are AI-first too

A generated app exposes its own MCP surface with one call, so the user's agents can drive the user's app:

// apps/admin/src/mcp.ts
import { defineAppMcp, t } from '@ultimat3/mcp';

export const mcp = defineAppMcp({
  name: 'acme-admin',
  include: 'exposed',                    // every action/query with mcp: { expose: true }
  resources: [orgExport],
  prompts: ['apps/web/app/posts/prompts/summarize.v3.md'],
  tools: {
    seatReport: {                        // the key IS the tool name
      description: 'Seats used, remaining and the plan limit. Read-only.',
      input: t.object({}),               // any Standard Schema
      policy: 'org:administer',          // an existing permission, never a new rule
      destructive: false,
      async handle({ ctx }) {
        return seats(await ctx.orgs.byId(ctx.actor.orgId));
      },
    },
  },
  scopes: { 'admin:seats': ['seatReport'] },   // scope name → tool NAMES, by string
  resolveToken: (token) => sessions.resolveAgentToken(token),
});

// app.config.ts
routes: [mcp.route]                      // POST /mcp, rate-limited per method class

include: 'exposed' reads the action and query registries instead of asking for actions: [...] / queries: [...] — the registries already know who opted in, and a second hand-maintained list is a thing that goes stale silently. The explicit arrays still work and win over the registry's copy of the same name.

The two lists are read differently, on purpose. include sweeps: it holds every primitive the app registered, so one that never opted in is passed over. actions:/queries: are written out: naming a primitive there is the request to expose it, so one that never declared mcp: { expose: true } is X_MCP_TOOL_UNDECLARED at boot — a listed tool is never silently missing from the catalog, and exposure stays declared next to the policy. Two primitives reaching one tool name is X_MCP_TOOL_DUPLICATE, also at boot.

Both lists take the primitives themselves, exactly as the app declared them:

import { publishPost } from '../api/posts';

defineAppMcp({ name: 'postly', actions: [publishPost] });
// X_MCP_TOOL_UNDECLARED unless publishPost declared mcp: { expose: true }

One adapter serves both routes, so a written-out primitive runs through the same invoke (or sourceFor) the swept one does — the list changes which tools are NAMED, never how one runs. An action that was never handed to defineApi has no export name, and is X_ACTION_UNREGISTERED rather than a tool called '' that nothing could call.

The tool name is the export name, verbatimpublishPost, never publish_post. This server answers tools/call for that name and no other, so every surface that PUBLISHES a name has to publish the same one: action.tool(), query.tool(), x-ultimate.mcpTool in openapi.json, and ActionDescriptor.mcp.tool. The projection reads primitive.mcp?.name ?? primitive.name, so the export name is the default and mcp.name is an explicit override — unreachable from action() or query(), whose declarations carry no name field, and available only to a hand-authored ProjectablePrimitive passed to defineAppMcp's tools:. The three action publishers snake_cased the name As of 2026-08, so an agent reading the spec called a tool the catalog never contained and got ToolNotFound. src/cross-surface.test.ts is what makes a fourth spelling a failing test rather than a note.

A hand-written tool's policy is a permission, evaluated through the same guard() an HTTP request goes through, so a tool cannot acquire a second authz path. A tool without one is X_MCP_TOOL_UNSAFE at boot, and an unmarked tool is metered as a write.

scopes: (type McpScopes, applied through the exported withScopes) is outcome 2's declaration surface: a scope name → the TOOL NAMES it covers, however each one reached the catalog — a projected action, a projected query, or a key in tools. It lives here, not beside the action, because a scope is a capability of the CONNECTION's token — what x token grant <scope> names — not a fact about the operation; the policy beside the action stays the only rule that reads the input. A name this server does not project is X_MCP_SCOPE_UNKNOWN at boot; one tool claimed by two scopes is X_MCP_SCOPE_CONFLICT.

Transports

| Transport | Entry | Auth | |---|---|---| | HTTP | mcpHttpRoute({ server, resolveToken })POST /mcp | Authorization: Bearer <token>Actor { kind: 'agent' } | | stdio | serveStdio({ server, caller }) | none — the peer already owns the shell |

The HTTP transport exports a route descriptor, not a mounted handler: a host owns the lifecycle, and the descriptor stays drivable from a bare Request in a test. It carries rateLimitClass(body) because all MCP traffic is one URL — a per-route bucket would charge initialize to the write bucket and throttle an agent on its handshake.

Reads: 120/min per caller. Writes: 20/min. Unresolvable calls bill the write bucket (fail-closed).

handle enforces those numbers itself, As of 2026-08-24 — they were published on the descriptor and applied by no mount point before that, so the ceiling was really Bun's accept rate. It cannot be done from outside: rateLimitClass(body) takes an already-parsed body and handle is the only thing that parses one. The bucket is @ultimat3/http's, keyed per actor per class; over the limit is 429 + Retry-After + X_MCP_RATE_LIMITED.

| Knob | Where | Default | |---|---|---| | the numbers | mcpHttpRoute({ rateLimits }) · defineAppMcp({ rateLimits }) | MCP_RATE_LIMITS | | where they are counted | mcpHttpRoute({ rateLimitStore }) · defineAppMcp({ rateLimitStore }) | a per-process memory store — N replicas behind one URL each enforce the full allowance, so a fleet passes postgresRateLimitStore({ executor }) |

Resources

| URI | Contents | |---|---| | ultimate://manifest | x.manifest.json — the generated facts | | ultimate://openapi.json | OpenAPI 3.1 projected from actions and queries | | ultimate://routes | route table | | ultimate://schema | entities, columns, invariants |

Providers are injected thunks: @ultimat3/manifest and @ultimat3/render sit in this same tier, so the CLI wires them and this package owns only the shape and the URIs.

Argument validation

tools/list hands the agent a JSON Schema, so that document is the thing enforced — there is no second private validator a tool could be judged against instead. validate-args.ts implements the emitted subset (objects, arrays, enums, required, additionalProperties, bounds, default) and applies declared defaults. Actions still re-parse authoritatively inside their own handler.

Errors

| Code | Meaning | |---|---| | X_MCP_TOOL_UNKNOWN | no visible tool by that name — absent and role-hidden are one answer | | X_MCP_SCOPE_DENIED | visible, but the connection's token lacks the scope | | X_MCP_SCOPE_UNKNOWN | defineAppMcp's scopes: names a tool this server does not project | | X_MCP_SCOPE_CONFLICT | two scopes in defineAppMcp's scopes: claim one tool | | X_MCP_ARGS_INVALID | arguments failed the declared schema | | X_MCP_PROTOCOL | malformed envelope, unknown method, bad auth header | | X_MCP_QUERY_REJECTED | db.query given anything but one read-only statement | | X_MCP_NOT_BRANCH_DB | db.migrate aimed at a production or otherwise non-branch database | | X_MCP_RESOURCE_DUPLICATE | two resources claim one ultimate:// URI — refused at registration, as a duplicate tool name is | | X_MCP_RATE_LIMITED | the caller spent its per-minute allowance for this request's class. Its own code rather than @ultimat3/http's X_RATE_LIMITED because the KNOB differs — rateLimits on the route, never rateLimit.buckets in app.config.ts |