by vinkius-labs
TypeScript framework for building production MCP servers. Fluent tool API, FSM gating, presenters, semantic routing, cache hints, Zod validation. Model-View-Agent architecture for the Model Context Protocol.
# Add to your Claude Code skills
git clone https://github.com/vinkius-labs/vurb.tsLast scanned: 5/30/2026
{
"issues": [
{
"type": "npm-audit",
"message": "@aws-sdk/xml-builder: Vulnerability found",
"severity": "medium"
},
{
"type": "npm-audit",
"message": "@hono/node-server: @hono/node-server has authorization bypass for protected static paths via encoded slashes in Serve Static Middleware",
"severity": "high"
},
{
"type": "npm-audit",
"message": "brace-expansion: brace-expansion: Zero-step sequence causes process hang and memory exhaustion",
"severity": "medium"
},
{
"type": "npm-audit",
"message": "esbuild: esbuild enables any website to send any requests to the development server and read the response",
"severity": "medium"
},
{
"type": "npm-audit",
"message": "express-rate-limit: express-rate-limit: IPv4-mapped IPv6 addresses bypass per-client rate limiting on servers with dual-stack network",
"severity": "high"
},
{
"type": "npm-audit",
"message": "fast-uri: fast-uri vulnerable to path traversal via percent-encoded dot segments",
"severity": "high"
},
{
"type": "npm-audit",
"message": "fast-xml-parser: fast-xml-parser has stack overflow in XMLBuilder with preserveOrder",
"severity": "high"
},
{
"type": "npm-audit",
"message": "flatted: flatted vulnerable to unbounded recursion DoS in parse() revive phase",
"severity": "high"
},
{
"type": "npm-audit",
"message": "hono: Hono Vulnerable to Cookie Attribute Injection via Unsanitized domain and path in setCookie()",
"severity": "high"
},
{
"type": "npm-audit",
"message": "ip-address: ip-address has XSS in Address6 HTML-emitting methods",
"severity": "medium"
},
{
"type": "npm-audit",
"message": "path-to-regexp: path-to-regexp vulnerable to Denial of Service via sequential optional groups",
"severity": "high"
},
{
"type": "npm-audit",
"message": "picomatch: Picomatch: Method Injection in POSIX Character Classes causes incorrect Glob Matching",
"severity": "high"
},
{
"type": "npm-audit",
"message": "postcss: PostCSS has XSS via Unescaped </style> in its CSS Stringify Output",
"severity": "medium"
},
{
"type": "npm-audit",
"message": "qs: qs has a remotely triggerable DoS: qs.stringify crashes with TypeError on null/undefined entries in comma-format arrays when encodeValuesOnly is set",
"severity": "medium"
},
{
"type": "npm-audit",
"message": "vite: Vite Vulnerable to Path Traversal in Optimized Deps `.map` Handling",
"severity": "medium"
},
{
"type": "npm-audit",
"message": "vitepress: Vulnerability found",
"severity": "medium"
},
{
"type": "npm-audit",
"message": "yaml: yaml is vulnerable to Stack Overflow via deeply nested YAML collections",
"severity": "medium"
}
],
"status": "WARNING",
"scannedAt": "2026-05-30T15:20:40.758Z",
"npmAuditRan": true,
"pipAuditRan": true
}No comments yet. Be the first to share your thoughts!
Requires a passing catalog security scan. Resolve the flagged issues and resubmit to enable featuring.
The TypeScript framework for MCP Servers.
Presenters shape perception. A typed layer between your data and the AI agent — strips undeclared fields, redacts PII, gates tools by workflow state, and deploys to any edge.
Building with Vurb.ts? Come talk to us — Join the Discord → Questions, war stories, and what you're shipping. The founder is in there.
Documentation · Quick Start · API Reference · llms.txt · Discord
Every raw MCP server does the same thing: JSON.stringify() the database row and ships it to the LLM. The AI receives password_hash, customer_ssn, internal_margin — every column. No governance. No rules. No perception control.
Vurb.ts gives you three ways to fix this — pick the one that fits your team:
Define your entire MCP server in a single vurb.yaml. No TypeScript. No build step.
# vurb.yaml — a complete MCP server
version: "1.0"
server:
name: "github-tools"
connections:
github:
type: rest
base_url: "https://api.github.com"
auth:
type: bearer
token: "${SECRETS.GITHUB_TOKEN}"
tools:
- name: search_repos
description: "Search GitHub repositories"
instruction: "Use for finding projects by topic or keyword."
rules:
- "Max 10 results per query"
parameters:
query: { type: string, required: true }
execute:
connection: github
method: GET
path: "/search/repositories"
query: { q: "{{query}}", per_page: "10" }
response:
extract: ["items[].{full_name, description, stargazers_count, html_url}"]
vurb yaml dev # MCP server running — zero TypeScript
The Presenter is a typed perception layer. Your handler returns raw data. The Presenter shapes everything the agent sees:
Handler (raw data) Presenter Agent (LLM)
────────────────── ───────── ──────────
{ amount_cents, → Schema (allowlist) → Structured
password_hash, + Rules (contextual) perception
customer_ssn, + PII redaction package
internal_margin } + Suggested next actions
- password_hash ← STRIPPED
- customer_ssn ← REDACTED
- internal_margin ← STRIPPED
import { createPresenter, f, t } from '@vurb/core';
const InvoicePresenter = createPresenter('Invoice')
.schema({ id: t.string, amount_cents: t.number, status: t.enum('paid', 'pending') })
.redactPII(['*.customer_ssn'])
.rules(['amount_cents is in CENTS — divide by 100 for display.'])
.suggest((inv) => inv.status === 'pending'
? [suggest('billing.pay', 'Invoice pending — process payment')]
: [suggest('billing.archive', 'Invoice settled — archive it')]);
export default f.query('billing.get_invoice')
.describe('Get an invoice by ID')
.withString('id', 'Invoice ID')
.returns(InvoicePresenter)
.handle(async (input, ctx) => ctx.db.invoices.findUnique({ where: { id: input.id } }));
Undeclared fields are stripped at RAM level. PII is redacted after UI logic runs (Late Guillotine). Rules travel with data, not in the system prompt. Next actions are computed from data state, not hardcoded.
The FSM State Gate makes it physically impossible for the AI to call tools out of order. If the state is empty, cart.pay doesn't exist in tools/list:
const gate = f.fsm({
id: 'checkout', initial: 'empty',
states: {
empty: { on: { ADD_ITEM: 'has_items' } },
has_items: { on: { CHECKOUT: 'payment' } },
payment: { on: { PAY: 'confirmed' } },
confirmed: { type: 'final' },
},
});
export default f.mutation('cart.pay')
.bindState('payment', 'PAY') // Invisible until 'payment' state
.handle(async (input, ctx) => ctx.db.payments.process(input.method));
| State | Visible tools |
|---|---|
empty |
cart.add_item, cart.view |
has_items |
cart.add_item, cart.checkout, cart.view |
payment |
cart.pay, cart.view |
confirmed |
cart.view |
npx @vurb/core create my-server
cd my-server && npm run dev
Drop a file in src/tools/, restart — it's a live MCP tool:
src/tools/
├── billing/
│ ├── get_invoice.ts → billing.get_invoice
│ └── pay.ts → billing.pay
└── users/
└── list.ts → users.list
Same code, any platform. Zero changes:
vurb deploy # Vinkius Edge (default)
vercel deploy # Vercel Functions
wrangler deploy # Cloudflare Workers
vurb create my-server # Vanilla — file-based routing
vurb create my-api --vector prisma # Prisma — CRUD with field-level security
vurb create ops-bridge --vector n8n # n8n — workflow bridge
vurb create petstore --vector openapi # OpenAPI → MCP in one command
vurb create my-server --target vercel --yes # Vercel Functions target
vurb create my-server --target cloudflare --yes # Cloudflare Workers target
Vurb.ts ships a SKILL.md — a machine-readable architectural contract. Your AI agent reads the spec and writes the entire server. First pass, no corrections.
Open your project in Cursor, Claude Code, GitHub Copilot, or Windsurf and prompt:
"Build an MCP server for patient records with Prisma. Redact SSN and diagnosis from LLM output. Add an FSM that gates discharge tools until attending physician signs off."
The agent reads the spec, produces correct Presenters, middleware, FSM gating, and file-based routing. You review the PR.
📄 Machine-readable spec: vurb.vinkius.com/llms.txt — optimized for LLM consumption.
Egress Firewall (Presenter schema allowlist) · PII Redaction with Late Guillotine · FSM State Gate (tools disappear by state) · A2A Protocol Bridge (@vurb/a2a — expose MCP servers as A2A-compliant agents with Agent Cards and task delegation) · Multi-Agent Swarm (@vurb/swarm — HMAC-SHA256 delegation, namespace isolation, W3C tracing) · Middleware (pre-compiled, zero-allocation) · tRPC-style typed client · Self-healing errors · State Sync (RFC 7234 cache signals) · Zero-trust Sandbox (V8 isolate) · Prompt Engine · Agent Skills · Capability Governance (SHA-256 lockfile) · Inspector (real-time TUI dashboard) · Declarative YAML engine (@vurb/yaml)
Turn existing infrastructure into MCP servers:
# OpenAPI / Swagger → typed MCP tools
npx openapi-gen generate -i ./petstore.yaml -o ./generated
# Prisma → CRUD tools with field-level security
npx prisma generate # uses vurb-prisma-gen
# n8n → auto-discover webhook workflows
const n8n = await createN8nConnector({ url, apiKey, includeTags: ['ai-enabled'] });
| Package | Purpose |
|---|---|
@vurb/core |
Framework core — Presenters, Fluent API, middleware, routing |
@vurb/yaml |
Declarative YAML engine — define MCP servers without code |
@vurb/swarm |
Multi-agent orchestration — Federated Handoff Protocol |
@vurb/a2a |
A2A Protocol Bridge — Agent Cards, task delegation, structured message exchange |
@vurb/testing |
In-memory pipeline testing with MVA layer assertions |
@vurb/inspector |
Real-time terminal dashboard via Shadow Socket |
| Package | Target |
|---|---|
@vurb/vercel |
Vercel Functions (Edge / Node.js) |
@vurb/cloudflare |
Cloudflare Workers |
| Package | Purpose |
|---|---|
@vurb/openapi-gen |
OpenAPI 3.x / Swagger 2.0 → MCP tools |
@vurb/prisma-gen |
Prisma schema → CRUD tools with field-level security |
@vurb/n8n |
n8n workflows → MCP tools |
@vurb/aws |
AWS Lambda & Step Functions → MCP tools |
| [`@vurb/sk |