@vinkius-core/mcp-fusion 1.9.0 โ 1.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +39 -0
- package/README.md +129 -197
- package/dist/prompt/CursorCodec.d.ts +40 -0
- package/dist/prompt/CursorCodec.d.ts.map +1 -0
- package/dist/prompt/CursorCodec.js +121 -0
- package/dist/prompt/CursorCodec.js.map +1 -0
- package/dist/prompt/HydrationSandbox.d.ts +55 -0
- package/dist/prompt/HydrationSandbox.d.ts.map +1 -0
- package/dist/prompt/HydrationSandbox.js +122 -0
- package/dist/prompt/HydrationSandbox.js.map +1 -0
- package/dist/prompt/PromptRegistry.d.ts +65 -0
- package/dist/prompt/PromptRegistry.d.ts.map +1 -1
- package/dist/prompt/PromptRegistry.js +105 -1
- package/dist/prompt/PromptRegistry.js.map +1 -1
- package/dist/prompt/definePrompt.d.ts +4 -0
- package/dist/prompt/definePrompt.d.ts.map +1 -1
- package/dist/prompt/definePrompt.js +6 -0
- package/dist/prompt/definePrompt.js.map +1 -1
- package/dist/prompt/types.d.ts +31 -0
- package/dist/prompt/types.d.ts.map +1 -1
- package/dist/server/ServerAttachment.d.ts.map +1 -1
- package/dist/server/ServerAttachment.js +7 -5
- package/dist/server/ServerAttachment.js.map +1 -1
- package/llms.txt +34 -2
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,45 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [1.11.0] - 2026-02-23
|
|
9
|
+
|
|
10
|
+
### ๐ Stateless Cursor Pagination for Prompts
|
|
11
|
+
|
|
12
|
+
**MCP Fusion** now provides O(1) memory, cryptographic cursor-based pagination for `prompts/list`. Instead of loading thousands of prompts into memory or sending large payloads to MCP clients, the framework emits pages using an RFC-compliant cursor algorithm powered by the native Web Crypto API.
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
|
|
16
|
+
- **`PromptRegistry.configurePagination({ pageSize })`:** Enables stateless pagination. By default, pagination is disabled (all prompts returned).
|
|
17
|
+
- **`CursorCodec` module:** Implements a robust encoded cursor utilizing native `globalThis.crypto.subtle`. Zero external crypto dependencies.
|
|
18
|
+
- **Server integration:** Automatically extracts the `cursor` param from the `prompts/list` MCP request, decodes it, applies filters, and generates the `nextCursor` transparently.
|
|
19
|
+
- **Tamper resistance:** Adulterated cursors fallback gracefully to the first page without crashing the server.
|
|
20
|
+
- **Progress Notifications Integration:** Full E2E testing of `ProgressSink` mapping to `notifications/progress`. Generator handlers firing `yield progress()` map seamlessly without overhead.
|
|
21
|
+
- **Cooperative Cancellation Integration:** Full E2E testing of `AbortSignal` interception causing runaway generators and chains to abort instantly.
|
|
22
|
+
|
|
23
|
+
## [1.10.0] - 2026-02-23
|
|
24
|
+
|
|
25
|
+
### Hydration Timeout Sandbox โ Graceful Degradation for Prompt Hydration
|
|
26
|
+
|
|
27
|
+
**MCP Fusion** now protects prompt handlers from slow/failing external data sources via the **Hydration Timeout Sandbox**. When a handler fetches data from Jira, Stripe, databases, or any external source and the call hangs, the framework enforces a strict deadline, unblocks the UI immediately, and returns a structured SYSTEM ALERT.
|
|
28
|
+
|
|
29
|
+
### Added
|
|
30
|
+
|
|
31
|
+
- **`HydrationSandbox` module** (`src/prompt/HydrationSandbox.ts`): Core timeout mechanism using `Promise.race`. Wraps handler execution with a strict deadline and catches both timeouts and handler errors, converting them to graceful `<hydration_alert>` XML-structured messages.
|
|
32
|
+
- **`hydrationTimeout` config** on `definePrompt()`: Per-prompt deadline in milliseconds. Example: `definePrompt('briefing', { hydrationTimeout: 3000, handler: ... })`.
|
|
33
|
+
- **`setDefaultHydrationTimeout(ms)`** on `PromptRegistry`: Global safety net for ALL prompts. Individual prompt timeouts override the registry default.
|
|
34
|
+
- **Three-scenario coverage**: Handler completes โ normal result. Handler exceeds deadline โ TIMEOUT alert. Handler throws โ ERROR alert. The UI ALWAYS unblocks.
|
|
35
|
+
- **Timer cleanup**: `clearTimeout` via `finally` block โ no resource leaks, no dangling timers keeping Node.js alive.
|
|
36
|
+
- **Zero overhead**: When no timeout is configured, no timer is created, no `Promise.race` wrapping โ the handler runs directly.
|
|
37
|
+
- **Interceptor composition**: Prompt Interceptors still execute after a timeout, ensuring compliance headers and tenant context are always injected.
|
|
38
|
+
- **`getHydrationTimeout()`** on `PromptBuilder` interface: Read the configured timeout for introspection and testing.
|
|
39
|
+
- **17 new tests**: Unit tests covering timeout, early completion, error-as-degradation, timer cleanup, non-Error throws, plus integration tests for per-prompt config, registry defaults, override precedence, backward compatibility, and interceptor composition after timeout.
|
|
40
|
+
|
|
41
|
+
### Design Influences
|
|
42
|
+
|
|
43
|
+
- Go's `context.WithDeadline` (structured cancellation)
|
|
44
|
+
- gRPC deadline propagation (strict, per-RPC)
|
|
45
|
+
- Resilience4j TimeLimiter (JVM circuit breaker pattern)
|
|
46
|
+
|
|
8
47
|
## [1.9.0] - 2026-02-23
|
|
9
48
|
|
|
10
49
|
### Intent Mutex (Anti-Race Condition)
|
package/README.md
CHANGED
|
@@ -1,40 +1,49 @@
|
|
|
1
1
|
<div align="center">
|
|
2
|
-
<h1>โก๏ธ
|
|
3
|
-
<p
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
<h1>โก๏ธ MCP Fusion</h1>
|
|
3
|
+
<p>MVA (Model-View-Agent) framework for the Model Context Protocol.</p>
|
|
4
|
+
|
|
6
5
|
[](https://www.npmjs.com/package/@vinkius-core/mcp-fusion)
|
|
7
6
|
[](https://www.typescriptlang.org/)
|
|
8
7
|
[](https://modelcontextprotocol.io/)
|
|
9
8
|
[](LICENSE)
|
|
10
9
|
</div>
|
|
11
10
|
|
|
12
|
-
<
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
11
|
+
<p align="center">
|
|
12
|
+
<a href="https://vinkius-labs.github.io/mcp-fusion/">Documentation</a> ยท
|
|
13
|
+
<a href="https://vinkius-labs.github.io/mcp-fusion/quickstart">Quickstart</a> ยท
|
|
14
|
+
<a href="https://vinkius-labs.github.io/mcp-fusion/api-reference">API Reference</a> ยท
|
|
15
|
+
<a href="https://vinkius-labs.github.io/mcp-fusion/examples">Examples</a> ยท
|
|
16
|
+
<a href="https://vinkius-labs.github.io/mcp-fusion/cost-and-hallucination">Why MCP Fusion</a>
|
|
17
|
+
</p>
|
|
19
18
|
|
|
20
19
|
---
|
|
21
20
|
|
|
22
21
|
## Overview
|
|
23
22
|
|
|
24
|
-
**MCP Fusion**
|
|
23
|
+
**MCP Fusion** adds an MVA Presenter layer between your data and the AI agent. The Presenter validates data through a Zod schema, strips undeclared fields, attaches just-in-time domain rules, renders UI blocks server-side, and suggests next actions โ all before the response reaches the network.
|
|
25
24
|
|
|
26
25
|
```text
|
|
27
26
|
Model (Zod Schema) โ View (Presenter) โ Agent (LLM)
|
|
28
27
|
validates perceives acts
|
|
29
28
|
```
|
|
30
29
|
|
|
31
|
-
The Presenter is
|
|
30
|
+
The Presenter is domain-level, not tool-level. Define `InvoicePresenter` once โ every tool that returns invoices uses it. Same validation, same rules, same UI, same affordances.
|
|
32
31
|
|
|
33
|
-
|
|
32
|
+
## Installation
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
npm install @vinkius-core/mcp-fusion zod
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
**MCP Fusion** has a required peer dependency on `@modelcontextprotocol/sdk` and `zod`:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
npm install @modelcontextprotocol/sdk @vinkius-core/mcp-fusion zod
|
|
42
|
+
```
|
|
34
43
|
|
|
35
|
-
##
|
|
44
|
+
## Quick Start
|
|
36
45
|
|
|
37
|
-
|
|
46
|
+
### 1. Define a Presenter
|
|
38
47
|
|
|
39
48
|
```typescript
|
|
40
49
|
import { createPresenter, ui } from '@vinkius-core/mcp-fusion';
|
|
@@ -46,12 +55,7 @@ export const InvoicePresenter = createPresenter('Invoice')
|
|
|
46
55
|
amount_cents: z.number(),
|
|
47
56
|
status: z.enum(['paid', 'pending', 'overdue']),
|
|
48
57
|
}))
|
|
49
|
-
.systemRules(
|
|
50
|
-
'CRITICAL: amount_cents is in CENTS. Divide by 100 before display.',
|
|
51
|
-
ctx?.user?.role !== 'admin'
|
|
52
|
-
? 'RESTRICTED: Do not reveal exact totals to non-admin users.'
|
|
53
|
-
: null,
|
|
54
|
-
])
|
|
58
|
+
.systemRules(['CRITICAL: amount_cents is in CENTS. Divide by 100 before display.'])
|
|
55
59
|
.uiBlocks((invoice) => [
|
|
56
60
|
ui.echarts({
|
|
57
61
|
series: [{ type: 'gauge', data: [{ value: invoice.amount_cents / 100 }] }],
|
|
@@ -67,32 +71,7 @@ export const InvoicePresenter = createPresenter('Invoice')
|
|
|
67
71
|
);
|
|
68
72
|
```
|
|
69
73
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
```text
|
|
73
|
-
๐ DATA โ Validated through Zod .strict() โ undeclared fields rejected
|
|
74
|
-
๐ RULES โ "amount_cents is in CENTS. Divide by 100."
|
|
75
|
-
๐ UI BLOCKS โ ECharts gauge rendered server-side
|
|
76
|
-
โ ๏ธ GUARDRAIL โ "50 shown, 250 hidden. Use filters."
|
|
77
|
-
๐ AFFORDANCE โ "โ billing.pay: Process payment"
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
Presenters compose via `.embed()` โ child Presenter rules, UI blocks, and suggestions merge automatically:
|
|
81
|
-
|
|
82
|
-
```typescript
|
|
83
|
-
const InvoicePresenter = createPresenter('Invoice')
|
|
84
|
-
.schema(invoiceSchema)
|
|
85
|
-
.embed('client', ClientPresenter)
|
|
86
|
-
.embed('payment_method', PaymentMethodPresenter);
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
---
|
|
90
|
-
|
|
91
|
-
## Tool Definition
|
|
92
|
-
|
|
93
|
-
Two APIs, identical output. `defineTool()` uses JSON shorthand (no Zod imports). `createTool()` uses full Zod schemas.
|
|
94
|
-
|
|
95
|
-
### `defineTool()` โ JSON-First
|
|
74
|
+
### 2. Define a Tool
|
|
96
75
|
|
|
97
76
|
```typescript
|
|
98
77
|
import { defineTool } from '@vinkius-core/mcp-fusion';
|
|
@@ -129,39 +108,56 @@ const billing = defineTool<AppContext>('billing', {
|
|
|
129
108
|
});
|
|
130
109
|
```
|
|
131
110
|
|
|
132
|
-
###
|
|
111
|
+
### 3. Attach to Server
|
|
133
112
|
|
|
134
113
|
```typescript
|
|
135
|
-
import {
|
|
136
|
-
|
|
137
|
-
const billing = createTool<AppContext>('billing')
|
|
138
|
-
.description('Billing operations')
|
|
139
|
-
.commonSchema(z.object({ workspace_id: z.string() }))
|
|
140
|
-
.action({
|
|
141
|
-
name: 'get_invoice',
|
|
142
|
-
readOnly: true,
|
|
143
|
-
returns: InvoicePresenter,
|
|
144
|
-
schema: z.object({ id: z.string() }),
|
|
145
|
-
handler: async (ctx, args) =>
|
|
146
|
-
await ctx.db.invoices.findUnique({ where: { id: args.id } }),
|
|
147
|
-
});
|
|
148
|
-
```
|
|
114
|
+
import { ToolRegistry } from '@vinkius-core/mcp-fusion';
|
|
149
115
|
|
|
150
|
-
|
|
116
|
+
const tools = new ToolRegistry<AppContext>();
|
|
117
|
+
tools.register(billing);
|
|
118
|
+
|
|
119
|
+
tools.attachToServer(server, {
|
|
120
|
+
contextFactory: (extra) => createAppContext(extra),
|
|
121
|
+
});
|
|
122
|
+
```
|
|
151
123
|
|
|
152
|
-
|
|
124
|
+
The handler returns raw data. The framework does the rest:
|
|
153
125
|
|
|
154
126
|
```text
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
127
|
+
๐ DATA โ Zod-validated. Undeclared fields stripped.
|
|
128
|
+
๐ RULES โ "amount_cents is in CENTS. Divide by 100."
|
|
129
|
+
๐ UI โ ECharts gauge config โ server-rendered, deterministic.
|
|
130
|
+
โ ๏ธ GUARDRAIL โ "50 shown, 250 hidden. Use filters."
|
|
131
|
+
๐ AFFORDANCE โ "โ billing.pay: Process payment"
|
|
160
132
|
```
|
|
161
133
|
|
|
162
|
-
|
|
134
|
+
## Features
|
|
135
|
+
|
|
136
|
+
### Presenter โ MVA View Layer
|
|
163
137
|
|
|
164
|
-
|
|
138
|
+
Domain-level perception layer with schema validation, JIT system rules, server-rendered UI blocks, cognitive guardrails, action affordances, and relational composition via `.embed()`.
|
|
139
|
+
|
|
140
|
+
```typescript
|
|
141
|
+
const InvoicePresenter = createPresenter('Invoice')
|
|
142
|
+
.schema(invoiceSchema)
|
|
143
|
+
.systemRules((invoice, ctx) => [
|
|
144
|
+
'CRITICAL: amount_cents is in CENTS.',
|
|
145
|
+
ctx?.user?.role !== 'admin' ? 'Mask exact totals.' : null,
|
|
146
|
+
])
|
|
147
|
+
.uiBlocks((inv) => [ui.echarts(chartConfig)])
|
|
148
|
+
.agentLimit(50, (omitted) => ui.summary(`50 shown, ${omitted} hidden.`))
|
|
149
|
+
.suggestActions((inv) => inv.status === 'pending'
|
|
150
|
+
? [{ tool: 'billing.pay', reason: 'Process payment' }]
|
|
151
|
+
: []
|
|
152
|
+
)
|
|
153
|
+
.embed('client', ClientPresenter);
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
โ [Presenter docs](https://vinkius-labs.github.io/mcp-fusion/presenter) ยท [Anatomy](https://vinkius-labs.github.io/mcp-fusion/mva/presenter-anatomy) ยท [Context Tree-Shaking](https://vinkius-labs.github.io/mcp-fusion/mva/context-tree-shaking)
|
|
157
|
+
|
|
158
|
+
### Action Consolidation & Hierarchical Groups
|
|
159
|
+
|
|
160
|
+
50 actions โ 5 tools. A discriminator enum routes to the correct action. Groups nest arbitrarily with `.group()`.
|
|
165
161
|
|
|
166
162
|
```typescript
|
|
167
163
|
createTool<AppContext>('platform')
|
|
@@ -176,26 +172,18 @@ createTool<AppContext>('platform')
|
|
|
176
172
|
// Discriminator values: users.list | users.ban | billing.refund
|
|
177
173
|
```
|
|
178
174
|
|
|
179
|
-
|
|
175
|
+
โ [Building Tools](https://vinkius-labs.github.io/mcp-fusion/building-tools) ยท [Routing](https://vinkius-labs.github.io/mcp-fusion/routing) ยท [Tool Exposition](https://vinkius-labs.github.io/mcp-fusion/tool-exposition)
|
|
180
176
|
|
|
181
|
-
|
|
177
|
+
### Prompt Engine
|
|
182
178
|
|
|
183
|
-
Full MCP `prompts/list` + `prompts/get`
|
|
179
|
+
Full MCP `prompts/list` + `prompts/get` with `PromptMessage.fromView()` โ decomposes a Presenter view into XML-tagged prompt messages. Same source of truth as tool responses, zero duplication.
|
|
184
180
|
|
|
185
181
|
```typescript
|
|
186
|
-
import { definePrompt, PromptMessage } from '@vinkius-core/mcp-fusion';
|
|
187
|
-
|
|
188
182
|
const AuditPrompt = definePrompt<AppContext>('financial_audit', {
|
|
189
|
-
|
|
190
|
-
description: 'Run a compliance audit on an invoice.',
|
|
191
|
-
args: {
|
|
192
|
-
invoiceId: 'string',
|
|
193
|
-
depth: { enum: ['quick', 'thorough'] as const },
|
|
194
|
-
} as const,
|
|
183
|
+
args: { invoiceId: 'string', depth: { enum: ['quick', 'thorough'] as const } } as const,
|
|
195
184
|
middleware: [requireAuth, requireRole('auditor')],
|
|
196
185
|
handler: async (ctx, { invoiceId, depth }) => {
|
|
197
186
|
const invoice = await ctx.db.invoices.get(invoiceId);
|
|
198
|
-
|
|
199
187
|
return {
|
|
200
188
|
messages: [
|
|
201
189
|
PromptMessage.system('You are a Senior Financial Auditor.'),
|
|
@@ -207,50 +195,27 @@ const AuditPrompt = definePrompt<AppContext>('financial_audit', {
|
|
|
207
195
|
});
|
|
208
196
|
```
|
|
209
197
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
Decomposes a `ResponseBuilder` (from `Presenter.make()`) into XML-tagged prompt messages. Rules, data, UI blocks, and action suggestions from the Presenter are extracted into semantically separated blocks โ same source of truth as the Tool response, zero duplication:
|
|
213
|
-
|
|
214
|
-
```text
|
|
215
|
-
Presenter.make(data, ctx) โ ResponseBuilder
|
|
216
|
-
โ
|
|
217
|
-
โโ <domain_rules> โ system role โ Presenter's systemRules()
|
|
218
|
-
โโ <dataset> โ user role โ Validated JSON
|
|
219
|
-
โโ <visual_context> โ user role โ UI blocks (ECharts, Mermaid, tables)
|
|
220
|
-
โโ <system_guidance> โ system role โ Hints + HATEOAS action suggestions
|
|
221
|
-
```
|
|
222
|
-
|
|
223
|
-
---
|
|
198
|
+
โ [Prompt Engine docs](https://vinkius-labs.github.io/mcp-fusion/prompts)
|
|
224
199
|
|
|
225
|
-
|
|
200
|
+
### Middleware
|
|
226
201
|
|
|
227
202
|
tRPC-style context derivation with pre-compiled chains:
|
|
228
203
|
|
|
229
204
|
```typescript
|
|
230
|
-
import { defineMiddleware } from '@vinkius-core/mcp-fusion';
|
|
231
|
-
|
|
232
205
|
const requireAuth = defineMiddleware(async (ctx: { token: string }) => {
|
|
233
206
|
const user = await db.getUser(ctx.token);
|
|
234
207
|
if (!user) throw new Error('Unauthorized');
|
|
235
|
-
return { user }; //
|
|
236
|
-
});
|
|
237
|
-
|
|
238
|
-
// Apply globally or per-action
|
|
239
|
-
defineTool<AppContext>('projects', {
|
|
240
|
-
middleware: [requireAuth, requireRole('editor')],
|
|
241
|
-
actions: { ... },
|
|
208
|
+
return { user }; // merged into ctx, TS infers { user: User }
|
|
242
209
|
});
|
|
243
210
|
```
|
|
244
211
|
|
|
245
|
-
|
|
212
|
+
โ [Middleware docs](https://vinkius-labs.github.io/mcp-fusion/middleware)
|
|
246
213
|
|
|
247
|
-
|
|
214
|
+
### Self-Healing Errors
|
|
248
215
|
|
|
249
|
-
Structured errors with recovery instructions
|
|
216
|
+
Structured errors with recovery instructions and suggested actions:
|
|
250
217
|
|
|
251
218
|
```typescript
|
|
252
|
-
import { toolError } from '@vinkius-core/mcp-fusion';
|
|
253
|
-
|
|
254
219
|
return toolError('ProjectNotFound', {
|
|
255
220
|
message: `Project '${id}' does not exist.`,
|
|
256
221
|
suggestion: 'Call projects.list first to get valid IDs.',
|
|
@@ -258,19 +223,13 @@ return toolError('ProjectNotFound', {
|
|
|
258
223
|
});
|
|
259
224
|
```
|
|
260
225
|
|
|
261
|
-
|
|
262
|
-
<tool_error code="ProjectNotFound">
|
|
263
|
-
<message>Project 'xyz' does not exist.</message>
|
|
264
|
-
<recovery>Call projects.list first to get valid IDs.</recovery>
|
|
265
|
-
<available_actions>projects.list</available_actions>
|
|
266
|
-
</tool_error>
|
|
267
|
-
```
|
|
226
|
+
Zod `.strict()` on all input schemas โ hallucinated parameters rejected with per-field correction prompts.
|
|
268
227
|
|
|
269
|
-
|
|
228
|
+
โ [Error Handling docs](https://vinkius-labs.github.io/mcp-fusion/error-handling) ยท [Cognitive Guardrails](https://vinkius-labs.github.io/mcp-fusion/mva/cognitive-guardrails)
|
|
270
229
|
|
|
271
|
-
|
|
230
|
+
### Type-Safe Client
|
|
272
231
|
|
|
273
|
-
End-to-end type inference from server to client
|
|
232
|
+
End-to-end type inference from server to client:
|
|
274
233
|
|
|
275
234
|
```typescript
|
|
276
235
|
import { createFusionClient } from '@vinkius-core/mcp-fusion/client';
|
|
@@ -278,31 +237,17 @@ import type { AppRouter } from './server';
|
|
|
278
237
|
|
|
279
238
|
const client = createFusionClient<AppRouter>(transport);
|
|
280
239
|
const result = await client.execute('billing.get_invoice', { workspace_id: 'ws_1', id: 'inv_42' });
|
|
281
|
-
// ^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
282
|
-
// autocomplete typed args
|
|
283
240
|
```
|
|
284
241
|
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
## Registry & Server Integration
|
|
288
|
-
|
|
289
|
-
```typescript
|
|
290
|
-
import { ToolRegistry, PromptRegistry } from '@vinkius-core/mcp-fusion';
|
|
242
|
+
โ [FusionClient docs](https://vinkius-labs.github.io/mcp-fusion/fusion-client)
|
|
291
243
|
|
|
292
|
-
|
|
293
|
-
tools.register(billing);
|
|
294
|
-
tools.register(projects);
|
|
244
|
+
### State Sync
|
|
295
245
|
|
|
296
|
-
|
|
297
|
-
prompts.register(AuditPrompt);
|
|
298
|
-
prompts.register(SummarizePrompt);
|
|
246
|
+
RFC 7234-inspired cache-control signals. Causal invalidation after mutations:
|
|
299
247
|
|
|
300
|
-
|
|
248
|
+
```typescript
|
|
301
249
|
tools.attachToServer(server, {
|
|
302
|
-
|
|
303
|
-
filter: { tags: ['public'] }, // Tag-based context gating
|
|
304
|
-
toolExposition: 'flat', // 'flat' or 'grouped' wire format
|
|
305
|
-
stateSync: { // RFC 7234-inspired cache signals
|
|
250
|
+
stateSync: {
|
|
306
251
|
defaults: { cacheControl: 'no-store' },
|
|
307
252
|
policies: [
|
|
308
253
|
{ match: 'sprints.update', invalidates: ['sprints.*'] },
|
|
@@ -310,96 +255,83 @@ tools.attachToServer(server, {
|
|
|
310
255
|
],
|
|
311
256
|
},
|
|
312
257
|
});
|
|
313
|
-
|
|
314
|
-
prompts.attachToServer(server, {
|
|
315
|
-
contextFactory: (extra) => createAppContext(extra),
|
|
316
|
-
});
|
|
317
258
|
```
|
|
318
259
|
|
|
319
|
-
|
|
260
|
+
โ [State Sync docs](https://vinkius-labs.github.io/mcp-fusion/state-sync)
|
|
320
261
|
|
|
321
|
-
|
|
262
|
+
### Observability & Tracing
|
|
322
263
|
|
|
323
|
-
|
|
264
|
+
Zero-overhead typed event system. OpenTelemetry-compatible tracing with structural subtyping:
|
|
324
265
|
|
|
325
266
|
```typescript
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
yield progress(90, 'Running analysis...');
|
|
330
|
-
return success(analysisResult);
|
|
331
|
-
}
|
|
267
|
+
billing.debug(createDebugObserver());
|
|
268
|
+
tools.enableDebug(createDebugObserver((event) => opentelemetry.addEvent(event.type, event)));
|
|
269
|
+
tools.enableTracing(tracer);
|
|
332
270
|
```
|
|
333
271
|
|
|
334
|
-
|
|
272
|
+
โ [Observability](https://vinkius-labs.github.io/mcp-fusion/observability) ยท [Tracing](https://vinkius-labs.github.io/mcp-fusion/tracing)
|
|
335
273
|
|
|
336
|
-
|
|
274
|
+
### Runtime Guards
|
|
337
275
|
|
|
338
|
-
|
|
276
|
+
Concurrency bulkhead, timeout enforcement, and circuit breakers per-tool:
|
|
339
277
|
|
|
340
|
-
|
|
341
|
-
import { createDebugObserver } from '@vinkius-core/mcp-fusion';
|
|
278
|
+
โ [Runtime Guards docs](https://vinkius-labs.github.io/mcp-fusion/runtime-guards)
|
|
342
279
|
|
|
343
|
-
|
|
344
|
-
billing.debug(createDebugObserver());
|
|
345
|
-
|
|
346
|
-
// Global โ propagates to all registered tools
|
|
347
|
-
tools.enableDebug(createDebugObserver((event) => {
|
|
348
|
-
opentelemetry.addEvent(event.type, event);
|
|
349
|
-
}));
|
|
350
|
-
```
|
|
280
|
+
### Streaming Progress
|
|
351
281
|
|
|
352
|
-
|
|
282
|
+
Generator handlers yield progress events โ automatically forwarded as MCP `notifications/progress`:
|
|
353
283
|
|
|
354
284
|
```typescript
|
|
355
|
-
|
|
356
|
-
|
|
285
|
+
handler: async function* (ctx, args) {
|
|
286
|
+
yield progress(10, 'Cloning repository...');
|
|
287
|
+
yield progress(50, 'Building AST...');
|
|
288
|
+
yield progress(90, 'Running analysis...');
|
|
289
|
+
return success(analysisResult);
|
|
290
|
+
}
|
|
357
291
|
```
|
|
358
292
|
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
## Capability Matrix
|
|
293
|
+
## All Capabilities
|
|
362
294
|
|
|
363
295
|
| Capability | Mechanism |
|
|
364
296
|
|---|---|
|
|
365
|
-
| **Presenter** |
|
|
366
|
-
| **Cognitive Guardrails** | `.agentLimit(max, onTruncate)` โ
|
|
297
|
+
| **Presenter** | `.schema()`, `.systemRules()`, `.uiBlocks()`, `.suggestActions()`, `.embed()` |
|
|
298
|
+
| **Cognitive Guardrails** | `.agentLimit(max, onTruncate)` โ truncation + filter guidance |
|
|
367
299
|
| **Action Consolidation** | Multiple actions โ single MCP tool with discriminator enum |
|
|
368
300
|
| **Hierarchical Groups** | `.group()` โ namespace 5,000+ actions as `module.action` |
|
|
369
|
-
| **Prompt Engine** | `definePrompt()` with flat schema
|
|
370
|
-
| **MVA-Driven Prompts** | `PromptMessage.fromView()` โ Presenter โ XML-tagged prompt messages |
|
|
301
|
+
| **Prompt Engine** | `definePrompt()` with flat schema, middleware, `PromptMessage.fromView()` |
|
|
371
302
|
| **Context Derivation** | `defineMiddleware()` โ tRPC-style typed context merging |
|
|
372
303
|
| **Self-Healing Errors** | `toolError()` โ structured recovery with action suggestions |
|
|
304
|
+
| **Strict Validation** | Zod `.merge().strict()` โ unknown fields rejected with actionable errors |
|
|
373
305
|
| **Type-Safe Client** | `createFusionClient<T>()` โ full inference from server to client |
|
|
374
306
|
| **Streaming Progress** | `yield progress()` โ MCP `notifications/progress` |
|
|
375
|
-
| **State Sync** | RFC 7234 cache-control
|
|
376
|
-
| **Tool Exposition** | `'flat'` or `'grouped'` wire format
|
|
307
|
+
| **State Sync** | RFC 7234 cache-control โ `invalidates`, `no-store`, `immutable` |
|
|
308
|
+
| **Tool Exposition** | `'flat'` or `'grouped'` wire format |
|
|
377
309
|
| **Tag Filtering** | RBAC context gating โ `{ tags: ['core'] }` / `{ exclude: ['internal'] }` |
|
|
378
310
|
| **Observability** | Zero-overhead debug observers + OpenTelemetry-compatible tracing |
|
|
311
|
+
| **Runtime Guards** | Concurrency bulkhead, timeout enforcement, circuit breakers |
|
|
379
312
|
| **TOON Encoding** | Token-Optimized Object Notation โ ~40% fewer tokens |
|
|
380
|
-
| **Validation** | Zod `.merge().strict()` โ unknown fields rejected with actionable errors |
|
|
381
313
|
| **Introspection** | Runtime metadata via `fusion://manifest.json` MCP resource |
|
|
382
|
-
| **Immutability** | `Object.freeze()` after `buildToolDefinition()`
|
|
383
|
-
|
|
384
|
-
---
|
|
314
|
+
| **Immutability** | `Object.freeze()` after `buildToolDefinition()` |
|
|
385
315
|
|
|
386
316
|
## Documentation
|
|
387
317
|
|
|
318
|
+
Full documentation available at **[vinkius-labs.github.io/mcp-fusion](https://vinkius-labs.github.io/mcp-fusion/)**.
|
|
319
|
+
|
|
388
320
|
| Guide | |
|
|
389
321
|
|---|---|
|
|
390
|
-
|
|
|
391
|
-
|
|
|
392
|
-
|
|
|
393
|
-
|
|
|
394
|
-
|
|
|
395
|
-
|
|
|
396
|
-
|
|
|
397
|
-
|
|
|
398
|
-
|
|
|
399
|
-
|
|
|
400
|
-
|
|
|
401
|
-
|
|
402
|
-
|
|
322
|
+
| [MVA Architecture](https://vinkius-labs.github.io/mcp-fusion/mva-pattern) | The MVA pattern and manifesto |
|
|
323
|
+
| [Quickstart](https://vinkius-labs.github.io/mcp-fusion/quickstart) | Build a Fusion server from zero |
|
|
324
|
+
| [Presenter](https://vinkius-labs.github.io/mcp-fusion/presenter) | Schema, rules, UI blocks, affordances, composition |
|
|
325
|
+
| [Prompt Engine](https://vinkius-labs.github.io/mcp-fusion/prompts) | `definePrompt()`, `PromptMessage.fromView()`, registry |
|
|
326
|
+
| [Context Tree-Shaking](https://vinkius-labs.github.io/mcp-fusion/mva/context-tree-shaking) | JIT rules vs global system prompts |
|
|
327
|
+
| [Cognitive Guardrails](https://vinkius-labs.github.io/mcp-fusion/mva/cognitive-guardrails) | Truncation, strict validation, self-healing |
|
|
328
|
+
| [Cost & Hallucination](https://vinkius-labs.github.io/mcp-fusion/cost-and-hallucination) | Token reduction analysis |
|
|
329
|
+
| [Middleware](https://vinkius-labs.github.io/mcp-fusion/middleware) | Context derivation, authentication |
|
|
330
|
+
| [State Sync](https://vinkius-labs.github.io/mcp-fusion/state-sync) | Cache-control signals, causal invalidation |
|
|
331
|
+
| [Runtime Guards](https://vinkius-labs.github.io/mcp-fusion/runtime-guards) | Concurrency, timeouts, circuit breakers |
|
|
332
|
+
| [Observability](https://vinkius-labs.github.io/mcp-fusion/observability) | Debug observers, tracing |
|
|
333
|
+
| [Cookbook](https://vinkius-labs.github.io/mcp-fusion/examples) | Real-world patterns |
|
|
334
|
+
| [API Reference](https://vinkius-labs.github.io/mcp-fusion/api-reference) | Complete typings |
|
|
403
335
|
|
|
404
336
|
## Requirements
|
|
405
337
|
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export interface CursorPayload {
|
|
2
|
+
after: string;
|
|
3
|
+
}
|
|
4
|
+
export type CursorMode = 'signed' | 'encrypted';
|
|
5
|
+
export interface CursorCodecOptions {
|
|
6
|
+
/**
|
|
7
|
+
* 'signed' (default): HMAC signature appended to base64 payload. Payload is visible but tamper-proof.
|
|
8
|
+
* 'encrypted': AES-GCM encryption. Payload is completely hidden and tamper-proof.
|
|
9
|
+
*/
|
|
10
|
+
mode?: CursorMode;
|
|
11
|
+
/**
|
|
12
|
+
* Optional 32-byte secret key.
|
|
13
|
+
* If not provided, a random ephemeral key is generated per process.
|
|
14
|
+
*/
|
|
15
|
+
secret?: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Stateless Cryptographic Cursor for pagination using Web Crypto API.
|
|
19
|
+
*
|
|
20
|
+
* Works in Node >= 18, Deno, Bun, and Cloudflare Workers.
|
|
21
|
+
*/
|
|
22
|
+
export declare class CursorCodec {
|
|
23
|
+
private readonly _mode;
|
|
24
|
+
private readonly _secretBytes;
|
|
25
|
+
private _hmacKey?;
|
|
26
|
+
private _aesKey?;
|
|
27
|
+
constructor(options?: CursorCodecOptions);
|
|
28
|
+
private getHmacKey;
|
|
29
|
+
private getAesKey;
|
|
30
|
+
/**
|
|
31
|
+
* Asynchronously encodes a payload into a URL-safe cursor string.
|
|
32
|
+
*/
|
|
33
|
+
encode(payload: CursorPayload): Promise<string>;
|
|
34
|
+
/**
|
|
35
|
+
* Asynchronously decodes and verifies a cursor string back into its payload.
|
|
36
|
+
* Returns undefined if the cursor is invalid, tampered with, or from a different process/key.
|
|
37
|
+
*/
|
|
38
|
+
decode(cursor: string): Promise<CursorPayload | undefined>;
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=CursorCodec.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CursorCodec.d.ts","sourceRoot":"","sources":["../../src/prompt/CursorCodec.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC1B,KAAK,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,WAAW,CAAC;AAEhD,MAAM,WAAW,kBAAkB;IAC/B;;;OAGG;IACH,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACnB;AAwBD;;;;GAIG;AACH,qBAAa,WAAW;IACpB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAa;IACnC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAa;IAC1C,OAAO,CAAC,QAAQ,CAAC,CAAY;IAC7B,OAAO,CAAC,OAAO,CAAC,CAAY;gBAEhB,OAAO,CAAC,EAAE,kBAAkB;YAe1B,UAAU;YAaV,SAAS;IAavB;;OAEG;IACG,MAAM,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC;IA6BrD;;;OAGG;IACG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC;CAmDnE"}
|