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

@ultimat3/mcp

Package Overview
Dependencies
Maintainers
1
Versions
37
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@ultimat3/mcp

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

Source
npmnpm
Version
11.3.0
Version published
Weekly downloads
1.4K
283.52%
Maintainers
1
Weekly downloads
 
Created
Source

@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

ToolScopeAnswers
routes.listdev:readroute table — url, render mode, offline strategy, hydrate, budget
schema.describedev:readentities with columns, types, invariants
policies.listdev:readevery policy: permission, subject, enforcement points
actions.describedev:readactions + queries: input/output schema, policy, cache tags, MCP exposure
jobs.inspectdev:readjob definitions, retry policy, steps (omit name for all)
queue.depthdev:readpending / running / failed per queue
manifest.readdev:readx.manifest.json verbatim
errors.explaindev:readstable X_* code → cause + exact fix command + docs
db.querydb:readread-only, enforced four ways — SELECT-only role, BEGIN READ ONLY, one-statement parse, 5s/1000-row/256 KiB caps
db.migratedb:migratebranch DB only — refuses production and any non-branch target
tests.rundev:testruns the suite (executes project code)
verify.rundev:testx verify — the shippable contract
logs.taildev:logslast 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

LayerMechanismWhere
1. Roleultimate_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. TransactionBEGIN READ ONLYROLLBACK on one reserved connection — Postgres refuses the write even if a grant is wrong@ultimat3/db
3. Parseone 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 blankedreadonly-sql.ts
4. LimitsSET LOCAL statement_timeout, a hard 1000-row ceiling (limit clamps into it, never past it) and a 256 KiB byte capquery-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 byDeclared byAnswerWire
rolevisibleToomitted from tools/list, ToolNotFound on call, no data-32601
scopescopeForbidden, naming the missing scope + a runnable fix-32600, X_MCP_SCOPE_DENIED
policythe primitive's own policyisError result carrying code/cause/fixX_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.

RuleDetail
A role list is fail-closeda 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 elseit 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 callerfiltered on every call against the caller the transport resolved — one per HTTP request, one per stdio connection — never a static catalog
Gate ordervisibility → scope → arguments → policy; the scope gate never waits on a policy run against attacker-supplied input
Every outcome is auditedone 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 payloadtool, outcome, actor, code. Never arguments, never rows
No trusted-tool modethere 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

TransportEntryAuth
HTTPmcpHttpRoute({ server, resolveToken })POST /mcpAuthorization: Bearer <token>Actor { kind: 'agent' }
stdioserveStdio({ server, caller })none — the peer already owns the shell

The HTTP transport exports a route descriptor, not a mounted handler: @ultimat3/http 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. Writes: 20/min. Unresolvable calls bill the write bucket (fail-closed).

Resources

URIContents
ultimate://manifestx.manifest.json — the generated facts
ultimate://openapi.jsonOpenAPI 3.1 projected from actions and queries
ultimate://routesroute table
ultimate://schemaentities, 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

CodeMeaning
X_MCP_TOOL_UNKNOWNno visible tool by that name — absent and role-hidden are one answer
X_MCP_SCOPE_DENIEDvisible, but the connection's token lacks the scope
X_MCP_SCOPE_UNKNOWNdefineAppMcp's scopes: names a tool this server does not project
X_MCP_SCOPE_CONFLICTtwo scopes in defineAppMcp's scopes: claim one tool
X_MCP_ARGS_INVALIDarguments failed the declared schema
X_MCP_PROTOCOLmalformed envelope, unknown method, bad auth header
X_MCP_QUERY_REJECTEDdb.query given anything but one read-only statement
X_MCP_NOT_BRANCH_DBdb.migrate aimed at a production or otherwise non-branch database
X_MCP_RESOURCE_DUPLICATEtwo resources claim one ultimate:// URI — refused at registration, as a duplicate tool name is

FAQs

Package last updated on 24 Aug 2026

Related posts