MCP Fusion/Reference/Migration
Migration
Move an existing MCP server from the raw SDK to MCP Fusion incrementally: one tool domain at a time, from JSON.stringify responses to Presenters, redaction and rules.
MCP Fusion does not require a rewrite. The raw MCP SDK and MCP Fusion can coexist in one server, and most teams migrate one tool domain at a time, in the order of 15 to 30 minutes per domain. This page shows the shape of one such step.
Before: a raw SDK tool
typescript
server.setRequestHandler(CallToolRequestSchema, async (request) => {
if (request.params.name === 'get_invoice') {
const invoice = await db.invoices.findUnique({
where: { id: request.params.arguments.id },
});
return {
content: [{ type: 'text', text: JSON.stringify(invoice) }],
};
}
});The problems are structural. JSON.stringify(invoice) sends every column to the model, including the ones you forgot existed. Units live in tribal knowledge, so the model guesses. There is no place where redaction, validation or next actions could even happen.
After: the same tool in MVA
typescript
const InvoicePresenter = createPresenter('Invoice')
.schema({
id: t.string,
customer: t.string,
amount_cents: t.number.describe('CENTS, divide by 100'),
status: t.enum('draft', 'paid', 'overdue'),
})
.redactPII(['customer.email', 'customer.ssn'])
.rules(['amount_cents is in CENTS. Divide by 100.']);
export default f.query('billing.get_invoice')
.describe('Retrieve an invoice by ID')
.withString('id', 'Invoice ID')
.returns(InvoicePresenter)
.handle(async (input) => {
return db.invoices.findUnique({ where: { id: input.id } });
});Same handler logic. What changed:
| Concern | Raw SDK | MCP Fusion |
|---|---|---|
| Output shape | JSON.stringify, every column | Presenter schema, declared fields only |
| PII | On the wire | .redactPII() before serialization |
| Units and meaning | Prompt folklore | .rules() as system lines |
| Next actions | None | .suggest() affordances |
| Validation | Manual | Zod from the builder |
The incremental path
- Install side by side.
npm install @mcpfusion/coredoes not disturb the existing handlers. - Pick one tool domain. Usually the one that touches the most sensitive data.
- Write the Presenter first. Declare the fields the task needs, redact the rest, write the rules the model keeps getting wrong.
- Move the handler. The query logic usually survives unchanged.
- Wire
autoDiscover. New tools come fromsrc/tools/, old handlers keep working during the transition. - Lock and test.
mcpfusion lockthe new surface and add the egress assertions from Testing.
Coming from other frameworks
- From plain HTTP APIs.
@mcpfusion/openapi-gengenerates Models, Views and Agents from an existing OpenAPI or Swagger spec, so wrapping an internal API starts mostly generated. - From a Prisma schema.
@mcpfusion/prisma-gengenerates tools and Presenters with field level security and tenant isolation from schema annotations. - From n8n.
@mcpfusion/n8nturns n8n webhooks into tools with tag filtering. - From AWS internals.
@mcpfusion/awslifts Lambda functions and Step Functions into tools via resource tags.
Next steps
- The MVA pattern: what you are migrating toward
- Models and Presenters: the destination API
- Deploy: when the last domain moves, ship it free
