Quickstart — Lightspeed
From zero to a running MCP server in under 30 seconds. The CLI scaffolds a production-ready project with autoDiscover() file-based routing, typed context, Presenters, middleware, testing, and pre-configured connections for Cursor, Claude Desktop, and Claude Code — no boilerplate.
Prerequisites
Node.js 18+ required.
npm install @vinkius-core/mcp-fusion @modelcontextprotocol/sdk zodAlready using a project?
If you're adding MCP Fusion to an existing Node.js project, the install above is all you need — then skip to Building Tools.
Scaffold
The CLI creates a complete project with all dependencies pre-installed:
npx fusion create my-serverThe interactive wizard runs:
Project name? (my-mcp-server) › my-server
Transport? [stdio, sse] › stdio
Vector? [vanilla, prisma, n8n, openapi, oauth] › vanilla
Include testing? › yes
● Scaffolding project — 14 files (6ms)
● Installing dependencies...
✔ Done
$ cd my-server
$ fusion dev
$ npm testSkip the wizard with --yes for defaults, or pass flags directly. For example, if you want to give Claude Desktop or Cursor secure access to your database, you can automatically generate a Postgres SQL Agent MCP through Prisma schemas without risking raw SQL injection vulnerabilities:
npx fusion create my-api --vector prisma --transport sse --yesPro-Tip: The
--vector prismacommand is the absolute fastest way to bridge Prisma to MCP. It leverages the MVA Presenter architecture to build an Egress Firewall, ensuring internal columns (likepassword_hashorssn) are stripped from memory before they ever reach the LLM Context Window.
What you get
my-server/
├── src/
│ ├── fusion.ts # initFusion<AppContext>()
│ ├── context.ts # AppContext type + factory
│ ├── server.ts # Bootstrap with autoDiscover
│ ├── tools/
│ │ └── system/
│ │ ├── health.ts # Health check with Presenter
│ │ └── echo.ts # Echo for connectivity testing
│ ├── presenters/
│ │ └── SystemPresenter.ts
│ ├── prompts/
│ │ └── greet.ts
│ └── middleware/
│ └── auth.ts
├── tests/
│ ├── setup.ts
│ └── system.test.ts
├── .cursor/mcp.json # Pre-configured for Cursor
├── .env.example
├── package.json
├── tsconfig.json
└── vitest.config.tsEvery file is real code — not stubs. The server boots, the tests pass, Cursor connects.
Run & Connect
cd my-server
fusion devThe server starts on stdio. Connect it to your MCP client:
Cursor — Zero-Click Integration
Already configured. The CLI generates .cursor/mcp.json automatically — open the project in Cursor and the MCP connection is live. No manual setup, no config editing. This is the fastest path from scaffold to working MCP server.
Claude Desktop
Add to your claude_desktop_config.json:
{
"mcpServers": {
"my-server": {
"command": "npx",
"args": ["tsx", "src/server.ts"]
}
}
}Claude Code
claude mcp add my-server npx tsx src/server.tsWindsurf
Add to your Windsurf MCP config (~/.codeium/windsurf/mcp_config.json):
{
"mcpServers": {
"my-server": {
"command": "npx",
"args": ["tsx", "src/server.ts"]
}
}
}Cline (VS Code Extension)
Add via Cline's MCP settings in VS Code — cline_mcp_settings.json:
{
"mcpServers": {
"my-server": {
"command": "npx",
"args": ["tsx", "src/server.ts"]
}
}
}VS Code + GitHub Copilot
Add to your .vscode/mcp.json:
{
"servers": {
"my-server": {
"command": "npx",
"args": ["tsx", "src/server.ts"]
}
}
}SSE transport
For network-accessible servers (multi-client, remote deployment):
npx fusion create my-api --transport sse
cd my-api
fusion dev
# Server running on http://localhost:3001/sseautoDiscover — file-based routing
This is the scaffolded project's superpower. No index.ts with 50 imports. No manual registry.register() calls. Drop a file in src/tools/ and it's a live MCP tool.
How it works
The generated server.ts calls autoDiscover() at startup:
// src/server.ts (scaffolded)
import { ToolRegistry, autoDiscover } from '@vinkius-core/mcp-fusion';
const registry = f.registry();
const discovered = await autoDiscover(registry, new URL('./tools', import.meta.url).pathname);
console.error(`📦 Discovered ${discovered.length} tool file(s)`);autoDiscover scans the entire src/tools/ tree, imports every .ts/.js file, extracts the tool builder, and registers it. .test.ts, .spec.ts, and .d.ts files are skipped automatically.
Naming convention
The directory structure becomes the tool namespace:
src/tools/
├── billing/
│ ├── get_invoice.ts → billing.get_invoice
│ └── pay.ts → billing.pay
├── users/
│ ├── list.ts → users.list
│ └── ban.ts → users.ban
└── system/
└── health.ts → system.healthThe tool's name field in the code is the source of truth — the directory just groups related files. Git diffs stay clean because adding a tool never touches a shared import file.
Export resolution
autoDiscover resolves exports in priority order:
| Priority | What it looks for | Example |
|---|---|---|
| 1 | export default | export default f.query('weather.get').handle(...) |
| 2 | Named tool export | export const tool = f.query('weather.get').handle(...) |
| 3 | Any exported builder | Scans all exports for objects with getName() |
The recommended pattern is export default:
// src/tools/weather/get.ts
import { f } from '../../fusion.js';
export default f.query('weather.get')
.describe('Get current weather for a city')
.withString('city', 'City name')
.handle(async (input) => {
return { city: input.city, temp_c: 18, condition: 'Clear' };
});Restart the dev server. weather_get is now callable by any MCP client.
Multiple tools in one file
Priority 3 enables exporting multiple tools from a single file:
// src/tools/billing/crud.ts
import { f } from '../../fusion.js';
export const listInvoices = f.query('billing.list_invoices')
.describe('List all invoices')
.handle(async () => ({ invoices: [] }));
export const createInvoice = f.mutation('billing.create_invoice')
.describe('Create an invoice')
.withNumber('amount', 'Invoice amount')
.handle(async (input) => ({ id: 'inv_1', amount: input.amount }));Both tools are discovered and registered — no extra wiring.
Advanced options
autoDiscover accepts an options object for fine-grained control:
await autoDiscover(registry, './src/tools', {
pattern: /\.tool\.ts$/, // only files ending in .tool.ts
recursive: true, // scan subdirectories (default: true)
loader: 'esm', // 'esm' (default) or 'cjs'
resolve: (mod) => { // custom export resolver
return mod.myTool as ToolBuilderLike;
},
});| Option | Default | Description |
|---|---|---|
pattern | /\.(ts|js|mjs|mts)$/ | Regex filter for file names |
recursive | true | Scan subdirectories |
loader | 'esm' | Module system — 'esm' uses import(), 'cjs' uses require() |
resolve | Priority cascade (default → tool → any) | Custom function to extract builders from module exports |
Test
The scaffolded project includes Vitest with a system test that verifies tool registration:
npm testThe test harness uses MVA_META_SYMBOL to call tools in-memory — no transport layer, no network. Add your own:
// tests/weather.test.ts
import { describe, it, expect } from 'vitest';
import { ToolRegistry, autoDiscover } from '@vinkius-core/mcp-fusion';
describe('weather.get', () => {
it('returns temperature for a city', async () => {
const registry = new ToolRegistry();
await autoDiscover(registry, new URL('../src/tools', import.meta.url).pathname);
const result = await registry.callTool('weather_get', { city: 'Tokyo' });
expect(result.content[0].text).toContain('Tokyo');
});
});Vectors
The --vector flag changes what gets scaffolded:
| Vector | What it adds |
|---|---|
vanilla | autoDiscover() file-based routing. Zero external deps |
prisma | prisma/schema.prisma + DB tool stubs + @vinkius-core/mcp-fusion-prisma-gen generator |
n8n | src/n8n.ts — N8nConnector auto-discovers webhook workflows as MCP tools |
openapi | openapi.yaml + SETUP.md — generates Models/Views/Agents from spec |
oauth | src/auth.ts + src/middleware/auth.ts — RFC 8628 Device Flow with requireAuth() |
# Database-driven MCP server
npx fusion create inventory-api --vector prisma --transport sse
# n8n workflow bridge
npx fusion create ops-bridge --vector n8n
# Authenticated API
npx fusion create secure-api --vector oauthEach vector adds its dependencies to package.json and environment variables to .env.example automatically.
Next steps
| What | Where |
|---|---|
| Understand tool definitions, annotations, Zod schemas | Building Tools |
| Shape what the LLM sees with Presenters | Presenter Guide |
| Add auth, rate limiting, logging | Middleware |
| Register prompts and dynamic manifests | Prompt Engine |
| Run the full test harness | Testing |
| Lock your capability surface | Capability Governance |
| Manual setup without the CLI | Quickstart — Traditional |
Go Live
Your server runs locally over Stdio. To expose it globally as a stateless HTTP endpoint, deploy to Vercel or Cloudflare Workers. Both adapters bridge the gap between MCP's long-lived process model and serverless runtimes — registry compilation is cached at cold start, warm requests execute with near-zero overhead.
Vercel — Next.js Edge Deployment
Drops into a Next.js App Router route. Edge Runtime for ~0ms cold starts, or Node.js Runtime for @vercel/postgres and heavier computation:
// app/api/mcp/route.ts
import { vercelAdapter } from '@vinkius-core/mcp-fusion-vercel';
export const POST = vercelAdapter({ registry, contextFactory });
export const runtime = 'edge'; // optional — global edge distributionCloudflare Workers — D1 & KV at the Edge
Your tools query D1 (SQLite at the edge) and KV with sub-millisecond latency from 300+ locations:
// src/worker.ts
import { cloudflareWorkersAdapter } from '@vinkius-core/mcp-fusion-cloudflare';
export default cloudflareWorkersAdapter({ registry, contextFactory });Full guides: Vercel Adapter · Cloudflare Adapter · Production Server