Skip to content

Stop Writing MCP Servers Like It's 2024.

Most MCP servers today dump raw database JSON and pray the LLM figures it out. **MCP Fusion** introduces the MVA (Model-View-Agent) architecture — giving your tools a deterministic View layer with a Structured Perception Layer on your data like trained engineers, not guessing machines.

DOMAIN: MCP SERVERS

Raw JSON.
Switch/case.
Hope the AI doesn't hallucinate.

That's how every MCP server works today.

**MCP Fusion** introduces MVA (Model-View-Agent) — a completely new way to build MCP servers where every response is a structured perception package: validated data, domain rules, server-rendered charts, and explicit next-action hints. The AI doesn't guess. It knows.

CAPABILITIES
20+
ARCHITECTURE
MVA
CONTEXT CONTROL
Deterministic

Your handler returns raw data. The framework does the rest.

typescript
import { createPresenter, ui, defineTool } from '@vinkius-core/mcp-fusion';
import { z } from 'zod';

// 1. Define the Presenter — the MVA View Layer
export const InvoicePresenter = createPresenter('Invoice')
    .schema(z.object({
        id: z.string(),
        amount_cents: z.number(),
        status: z.enum(['paid', 'pending', 'overdue']),
    }))
    .systemRules(['CRITICAL: amount_cents is in CENTS. Divide by 100.'])
    .uiBlocks((inv) => [
        ui.echarts({ series: [{ type: 'gauge', data: [{ value: inv.amount_cents / 100 }] }] }),
    ])
    .suggestActions((inv) =>
        inv.status === 'pending'
            ? [{ tool: 'billing.pay', reason: 'Process payment' }]
            : []
    );

// 2. Attach to any tool — handler returns raw data
const billing = defineTool<AppContext>('billing', {
    actions: {
        get_invoice: {
            returns: InvoicePresenter,
            params: { id: 'string' },
            handler: async (ctx, args) => await ctx.db.invoices.findUnique(args.id),
        },
    },
});
~npm install @vinkius-core/mcp-fusion zod
WHAT CHANGES

Without MVA vs With MVA

Every line is a capability that exists in **MCP Fusion** today. Not a roadmap. Not a promise.

Without MVA
With MVA (**MCP Fusion**)
Tool count
50 individual tools. LLM sees ALL. Token explosion.
Action consolidation — 5,000+ ops behind ONE tool via discriminator. 10x fewer tokens.
Response
JSON.stringify() — the AI parses and guesses.
Structured perception package — validated data + rules + UI + affordances.
Domain context
None. 45000 — dollars? cents? yen?
System rules travel with the data. The AI knows it's cents.
Next actions
AI hallucinates tool names.
Agentic HATEOAS — .suggestActions() with explicit hints based on data state.
Large datasets
10,000 rows dump into context window.
Cognitive guardrails — .agentLimit(50) truncation + filter guidance.
Security
Internal fields leak to LLM.
Schema as boundary — Zod .strict() rejects undeclared fields with actionable errors. Automatic.
Charts
Not possible — text only.
UI Blocks — ECharts, Mermaid diagrams, summaries — server-rendered.
Routing
switch/case with 50 branches.
Hierarchical groups — platform.users.list — infinite nesting.
Error recovery
throw Error — AI gives up.
Self-healing — toolError() with recovery hints + retry args.
Token cost
Full JSON payloads every time.
TOON encoding — toonSuccess() reduces tokens by ~40%.
Type safety
Manual casting, no client types.
tRPC-style client — createFusionClient() with full end-to-end inference.
Reusability
Same entity rendered differently everywhere.
Presenter — define once, reuse across all tools. Same rules, same UI.
SEE THE FULL COMPARISON WITH CODE EXAMPLES →
WHAT WE SOLVE

Three problems.
Framework-level solutions.

Every claim below maps to real code in the repository. Not a roadmap. Not a promise.

01

Egress Firewall

The problem: The developer does SELECT * and calls JSON.stringify(). Passwords, API keys, tenant IDs — all leaked to the LLM provider over the network. A compliance nightmare waiting to happen.

The mechanism: The Zod .schema() on every Presenter physically strips undeclared fields in server RAM via Zod.parse(). Sensitive data is destroyed before serialization — not by developer discipline, but by the framework itself. Combined with .strict() on inputs, this creates a bidirectional data boundary on every tool.

typescript
const UserPresenter = createPresenter('User')
    .schema(z.object({
        id: z.string(),
        name: z.string(),
        email: z.string(),
        // password_hash, tenant_id, internal_flags
        // → physically absent from output. Not filtered. GONE.
    }));

SEE HOW IT WORKS →

02

Context Tree-Shaking

The problem: To teach the AI about invoices, tasks, sprints, and users, the company writes a 10,000-token system prompt — sent on every call. The LLM loses coherence in the middle of the text, misapplies rules across domains, and the company pays for irrelevant tokens on every request.

The mechanism: Just like webpack tree-shaking removes unused code from a bundle, .systemRules() removes unused rules from the agent's context window. Domain rules travel with the data — the invoice rule only exists in the prompt at the exact millisecond the agent processes an invoice. Token overhead drops from ~2,000/call to ~200/call.

typescript
// Invoice rules — sent ONLY when invoice data is returned
const InvoicePresenter = createPresenter('Invoice')
    .schema(invoiceSchema)
    .systemRules((invoice, ctx) => [
        'CRITICAL: amount_cents is in CENTS. Divide by 100.',
        ctx?.user?.role !== 'admin'
            ? 'RESTRICTED: Mask exact totals for non-admin users.'
            : null,
    ]);

// Task rules — sent ONLY when task data is returned
const TaskPresenter = createPresenter('Task')
    .schema(taskSchema)
    .systemRules(['Use emojis: 🔄 In Progress, ✅ Done, ❌ Blocked']);

SEE HOW IT WORKS →

03

SSR for Agents

The problem: The developer begs in the prompt: "Please generate valid ECharts JSON." The AI gets the syntax wrong 20% of the time. The UI breaks. Charts become a probabilistic coinflip instead of deterministic output.

The mechanism: The agent is demoted to its correct role — a messenger. Complex chart configs, Mermaid diagrams, and Markdown tables are compiled server-side in Node.js (100% deterministic) via .uiBlocks(). The AI receives a [SYSTEM] pass-through directive and forwards the block unchanged. Visual hallucination drops to zero.

typescript
const InvoicePresenter = createPresenter('Invoice')
    .schema(invoiceSchema)
    .uiBlocks((invoice) => [
        ui.echarts({
            series: [{ type: 'gauge', data: [{ value: invoice.amount_cents / 100 }] }],
        }),
        ui.table(
            ['Field', 'Value'],
            [['Status', invoice.status], ['Amount', `$${invoice.amount_cents / 100}`]],
        ),
    ]);
// The LLM passes the chart config through. It never generates it.

SEE HOW IT WORKS →

THE MVA ARCHITECTURE

MVC was designed
for humans.
Agents are not
humans.

MVA replaces the human-centric View with the Presenter — an agent-centric perception layer that tells the AI exactly how to interpret, display, and act on domain data. This is not an iteration on MVC. It is a replacement.

// MODEL

Zod schema validates and filters data. Unknown fields rejected with actionable errors. The LLM cannot inject parameters your schema does not declare.

// PRESENTER

JIT rules, server-rendered UI, cognitive guardrails, action affordances — all deterministic, all framework-enforced.

TECHNICAL AUTHORITY

What we
built.

Every capability designed for autonomous AI agents operating over the Model Context Protocol.

01 // MVA

Presenter Engine

Domain-level Presenters validate data, inject rules, render charts, and suggest actions. Define once, reuse everywhere.

EXPLORE →
02 // ROUTING

Action Consolidation

Nest 5,000+ operations into grouped namespaces. The LLM sees ONE tool, not fifty. Token usage drops by 10x.

EXPLORE →
03 // SECURITY

Context Derivation

defineMiddleware() derives and injects typed data into context. Zod .strict() protects handlers from hallucinated params.

EXPLORE →
04 // RESILIENCE

Self-Healing Errors

toolError() provides structured recovery hints with suggested actions. Agents self-correct without human intervention.

EXPLORE →
05 // AFFORDANCE

Agentic HATEOAS

.suggestActions() tells agents what to do next based on data state. Reduces action hallucination through explicit affordances.

EXPLORE →
06 // GUARDRAILS

Cognitive Limits

.agentLimit() truncates large datasets and teaches agents to use filters. Prevents context DDoS and manages API costs.

EXPLORE →
07 // STATE

Temporal Awareness

RFC 7234-inspired cache-control signals prevent LLM Temporal Blindness. Cross-domain causal invalidation after mutations.

EXPLORE →
08 // CLIENT

Type-Safe Client

createFusionClient() provides end-to-end type safety from server to client. Wrong action name? TypeScript catches it at build time.

EXPLORE →
READ THE MVA GUIDE

The AI doesn't guess.
It knows.

MVA is a new architectural pattern. The Presenter replaces the View with a deterministic perception layer — domain rules, rendered charts, action affordances, and cognitive guardrails. Every response is structured. Every action is explicit.

READ THE FULL MVA GUIDE →