vite-plugin-mcp-builder 0.0.1

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/README.md ADDED
@@ -0,0 +1,166 @@
1
+ # Vite Plugin: MCP Build
2
+
3
+ This Vite plugin helps develop and build Model Context Protocol (MCP) handlers.
4
+
5
+ Key features:
6
+
7
+ - Development server that mounts an MCP handler under `/mcp`.
8
+ - Production build that produces a single bundle at `dist/app.js`.
9
+ - Scans configured directories for `*.tool`, `*.prompt` and `*.resource` files to include in the bundle.
10
+
11
+ ## Overview
12
+
13
+ The plugin scans the project files defined by the `dirs` option and exposes a development endpoint at `/mcp` that serves those definitions dynamically. For production it bundles the detected definitions into a single output file `dist/app.js`.
14
+
15
+ ## Installation
16
+
17
+ Install with your package manager:
18
+
19
+ ```bash
20
+ yarn add -D vite-plugin-mcp-build
21
+ # or
22
+ npm install -D vite-plugin-mcp-build
23
+ ```
24
+
25
+ ## Usage (example `vite.config.ts`)
26
+
27
+ ```ts
28
+ import { defineConfig } from 'vite'
29
+ import mcpPlugin from 'vite-plugin-mcp-build'
30
+
31
+ export default defineConfig({
32
+ plugins: [
33
+ mcpPlugin({
34
+ // optional plugin properties shown below
35
+ server: './src/createServer.js',
36
+ main: './src/main.js',
37
+ dirs: [
38
+ { dir: './src/calculadora' }
39
+ ]
40
+ })
41
+ ]
42
+ })
43
+ ```
44
+
45
+ ## Plugin options
46
+
47
+ All options are optional. Defaults are shown where applicable.
48
+
49
+ - `root?: string` — Project root used to resolve relative paths. Defaults to `process.cwd()`.
50
+ - `cacheDir?: string` — Directory where generated helper files are written (e.g. `createInstance.js`). Default: `.mcp`.
51
+ - `server?: string` — Path to the server factory module used in production. Default: internal `src-dev/createServer.js` (resolved relative to `root`).
52
+ - `devHandler?: string` — Path to the development handler module used by the Vite dev server. Default: internal `src-dev/devHandler.js` (resolved relative to `root`).
53
+ - `main?: string` — The main production entry module used for SSR build. Default: internal `src-dev/main.js` (resolved relative to `root`).
54
+ - `include?: string[]` — Glob patterns used to match tool/prompt/resource files inside each `dirs` entry. Default patterns (the plugin supports both `.ts` and `.js`):
55
+
56
+ ```
57
+ [
58
+ "**/*.tool.ts",
59
+ "**/*.prompt.ts",
60
+ "**/*.resource.ts",
61
+ "**/*.tool.js",
62
+ "**/*.prompt.js",
63
+ "**/*.resource.js"
64
+ ]
65
+ ```
66
+
67
+ Note: the original source contained a typo (`promt`). The plugin's intended pattern is `prompt`.
68
+
69
+ - `dirs?: { dir: string; include?: string[]; skip?: boolean }[]` — Array of directories to scan. Each entry:
70
+ - `dir` (required): directory path (relative to `root`) to scan.
71
+ - `include` (optional): per-dir globs overriding the global `include` list.
72
+ - `skip` (optional): if `true` the directory is ignored.
73
+
74
+ Default: `[{ dir: 'src', include: [], skip: false }]` — the plugin will scan `src` by default.
75
+
76
+ ## Development mode
77
+
78
+ Run Vite in dev mode (e.g. `yarn dev`). The plugin configures the dev server and mounts the MCP handler under `/mcp` (the path is registered by the plugin's middleware).
79
+
80
+ By default Vite's dev server will include the plugin's middleware under the `/mcp` route. Example local URL:
81
+
82
+ ```
83
+ http://localhost:5173/mcp
84
+ ```
85
+
86
+ Register this URL in your agent during development, e.g.:
87
+
88
+ ```json
89
+ {
90
+ "servers": {
91
+ "my-mcp-dev": {
92
+ "type": "http",
93
+ "url": "http://localhost:5173/mcp"
94
+ }
95
+ }
96
+ }
97
+ ```
98
+
99
+ ## Production build
100
+
101
+ Run your normal Vite build (e.g. `yarn build`). The plugin configures the build to produce a single SSR entry output named `app.js` (written under the `dist` directory by default). That file is suitable to load in a production process that creates the server instance and starts transports.
102
+
103
+ Example `main.js` (production runner):
104
+
105
+ ```ts
106
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
107
+ import createInstance from "@mcp/createInstance.js";
108
+
109
+ const server = await createInstance();
110
+ const transport = new StdioServerTransport();
111
+ await server.connect(transport);
112
+ ```
113
+
114
+ ## Defining tools, prompts and resources
115
+
116
+ Tools, prompts and resources are defined with the helper registrations (see `src/define.ts`). Typical usage registers a tool with a title, description, input schema and an implementation function. Example (TypeScript):
117
+
118
+ ```ts
119
+ import { z } from 'zod';
120
+ import { defineRegisterTool } from '@mcp/define';
121
+
122
+ export default defineRegisterTool(
123
+ 'divide',
124
+ {
125
+ title: 'Divide two numbers',
126
+ description: 'Divides two given numbers.',
127
+ inputSchema: {
128
+ number1: z.number(),
129
+ number2: z.number(),
130
+ },
131
+ },
132
+ async ({ number1, number2 }: any) => {
133
+ if (typeof number1 !== 'number' || typeof number2 !== 'number') {
134
+ throw new Error('Parameters must be numbers.');
135
+ }
136
+ return {
137
+ content: [{ type: 'text', text: String(number1 / number2) }]
138
+ };
139
+ }
140
+ );
141
+ ```
142
+
143
+ The registration helpers (`defineRegisterTool`, `defineRegisterPrompt`, `defineRegisterResource`) allow describing handlers without requiring a server instance at definition time.
144
+
145
+ ## Example project layout
146
+
147
+ ```bash
148
+ packages/example/src/
149
+ server.ts
150
+ calculadora/
151
+ dividir.tool.ts
152
+ multiplicar.tool.ts
153
+ nombre.resource.ts
154
+ ```
155
+
156
+ With the configuration above, the plugin will find `dividir.tool.ts`, `multiplicar.tool.ts` and `nombre.resource.ts` and include them in the production bundle.
157
+
158
+ ## Troubleshooting
159
+
160
+ - If files are not detected, verify your `dirs` entries and `include` globs, and ensure file extensions (`.ts`/`.js`) match your build.
161
+ - Inspect Vite's console output for plugin scan and build messages.
162
+
163
+ ---
164
+
165
+ If you want, I can also add concrete type signatures for the `defineRegister*` helpers and a small example that consumes `dist/app.js` in a production process.
166
+
@@ -0,0 +1,22 @@
1
+ import { PromptCallback, McpServer, ResourceMetadata, ReadResourceCallback, ResourceTemplate, ReadResourceTemplateCallback, ToolCallback } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import { ZodRawShapeCompat, AnySchema } from '@modelcontextprotocol/sdk/server/zod-compat.js';
3
+ import { ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';
4
+
5
+ type PromptArgsRawShape = ZodRawShapeCompat;
6
+ declare const defineRegisterTool: <OutputArgs extends ZodRawShapeCompat | AnySchema, InputArgs extends undefined | ZodRawShapeCompat | AnySchema = undefined>(name: string, config: {
7
+ title?: string;
8
+ description?: string;
9
+ inputSchema?: InputArgs;
10
+ outputSchema?: OutputArgs;
11
+ annotations?: ToolAnnotations;
12
+ _meta?: Record<string, unknown>;
13
+ }, cb: ToolCallback<InputArgs>) => (server: McpServer) => void;
14
+ declare const defineRegisterPrompt: <Args extends PromptArgsRawShape>(name: string, config: {
15
+ title?: string;
16
+ description?: string;
17
+ argsSchema?: Args;
18
+ }, cb: PromptCallback<Args>) => (server: McpServer) => void;
19
+ declare const defineRegisterResource: (name: string, uriOrTemplate: string, config: ResourceMetadata, readCallback: ReadResourceCallback) => (server: McpServer) => void;
20
+ declare const defineRegisterResourceV2: (name: string, uriOrTemplate: ResourceTemplate, config: ResourceMetadata, readCallback: ReadResourceTemplateCallback) => (server: McpServer) => void;
21
+
22
+ export { defineRegisterPrompt, defineRegisterResource, defineRegisterResourceV2, defineRegisterTool };
package/dist/define.js ADDED
@@ -0,0 +1,46 @@
1
+ const defineRegisterTool = (name, config, cb) => {
2
+ return (server) => {
3
+ try {
4
+ console.log("RegisterTool:", name);
5
+ server.registerTool(name, config, cb);
6
+ } catch (error) {
7
+ console.error("RegisterTool:", error);
8
+ }
9
+ };
10
+ };
11
+ const defineRegisterPrompt = (name, config, cb) => {
12
+ return (server) => {
13
+ try {
14
+ console.log("RegisterPrompt:", name);
15
+ server.registerPrompt(name, config, cb);
16
+ } catch (error) {
17
+ console.error("RegisterPrompt:", error);
18
+ }
19
+ };
20
+ };
21
+ const defineRegisterResource = (name, uriOrTemplate, config, readCallback) => {
22
+ return (server) => {
23
+ try {
24
+ console.log("RegisterResource:", name);
25
+ server.registerResource(name, uriOrTemplate, config, readCallback);
26
+ } catch (error) {
27
+ console.error("RegisterResource:", error);
28
+ }
29
+ };
30
+ };
31
+ const defineRegisterResourceV2 = (name, uriOrTemplate, config, readCallback) => {
32
+ return (server) => {
33
+ try {
34
+ console.log("RegisterResource:", name);
35
+ server.registerResource(name, uriOrTemplate, config, readCallback);
36
+ } catch (error) {
37
+ console.error("RegisterResourceV2:", error);
38
+ }
39
+ };
40
+ };
41
+ export {
42
+ defineRegisterPrompt,
43
+ defineRegisterResource,
44
+ defineRegisterResourceV2,
45
+ defineRegisterTool
46
+ };
@@ -0,0 +1,19 @@
1
+ import { Plugin } from 'vite';
2
+
3
+ type PluginOpts = {
4
+ root?: string;
5
+ cacheDir?: string;
6
+ server?: string;
7
+ devHandler?: string;
8
+ main?: string;
9
+ include?: string[];
10
+ dirs?: {
11
+ dir: string;
12
+ include?: string[];
13
+ skip?: boolean;
14
+ }[];
15
+ };
16
+
17
+ declare const mcpPlugin: (opts: PluginOpts) => Plugin[];
18
+
19
+ export { mcpPlugin as default, mcpPlugin };
package/dist/index.js ADDED
@@ -0,0 +1,100 @@
1
+ import express from "express";
2
+ import { assertConfig } from "./model";
3
+ import { writeCreateInstance } from "./createInstanceFile";
4
+ const mcpPlugin = (opts) => {
5
+ const conf = assertConfig(opts);
6
+ writeCreateInstance(conf);
7
+ const isReload = (file) => {
8
+ return conf.hmrDirs.find((it) => file.startsWith(it));
9
+ };
10
+ return [
11
+ {
12
+ name: "vite-plugin-mcp-alias",
13
+ enforce: "pre",
14
+ config: () => {
15
+ return {
16
+ resolve: {
17
+ alias: {
18
+ [`${conf.moduleId}/main.js`]: conf.mainFile,
19
+ [`${conf.moduleId}/createServer.js`]: conf.serverFile,
20
+ [`${conf.moduleId}/createInstance.js`]: conf.createInstanceFile
21
+ }
22
+ }
23
+ };
24
+ }
25
+ },
26
+ {
27
+ name: "vite-plugin-mcp-server",
28
+ enforce: "pre",
29
+ apply: "serve",
30
+ config: () => {
31
+ return {
32
+ appType: "custom",
33
+ server: {
34
+ cors: true
35
+ }
36
+ };
37
+ },
38
+ configureServer: async (devServer) => {
39
+ const {
40
+ //
41
+ watcher,
42
+ restart,
43
+ middlewares,
44
+ ssrLoadModule,
45
+ ssrFixStacktrace
46
+ } = devServer;
47
+ var appServer = express();
48
+ const onReload = async (file) => {
49
+ if (isReload(file)) {
50
+ writeCreateInstance(conf);
51
+ restart();
52
+ }
53
+ };
54
+ watcher.on("all", (_, file) => onReload(file));
55
+ console.log("Load devHandlerFile!");
56
+ const { createHandler } = await ssrLoadModule(conf.devHandlerFile, {
57
+ fixStacktrace: true
58
+ });
59
+ const handler = await createHandler({});
60
+ appServer.use("/", async (req, res, next) => {
61
+ try {
62
+ handler(req, res, next);
63
+ } catch (error) {
64
+ ssrFixStacktrace(error);
65
+ process.exitCode = 1;
66
+ next(error);
67
+ }
68
+ });
69
+ middlewares.use("/mcp", appServer);
70
+ }
71
+ },
72
+ {
73
+ name: "vite-plugin-mcp-build",
74
+ enforce: "pre",
75
+ config: () => {
76
+ return {
77
+ appType: "custom",
78
+ target: "esnext",
79
+ emptyOutDir: true,
80
+ build: {
81
+ ssr: conf.mainFile,
82
+ rollupOptions: {
83
+ output: {
84
+ format: "es",
85
+ entryFileNames: "app.js",
86
+ chunkFileNames: "bin/[name].js",
87
+ assetFileNames: "assets/[name].[ext]"
88
+ }
89
+ }
90
+ }
91
+ };
92
+ }
93
+ }
94
+ ];
95
+ };
96
+ var src_default = mcpPlugin;
97
+ export {
98
+ src_default as default,
99
+ mcpPlugin
100
+ };
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "vite-plugin-mcp-builder",
3
+ "version": "0.0.1",
4
+ "description": "Vite plugin to build and serve MCP (Model Context Protocol) servers",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "exports": {
8
+ ".": {
9
+ "import": "./dist/index.js",
10
+ "types": "./dist/index.d.ts"
11
+ },
12
+ "./define": {
13
+ "import": "./dist/define.js",
14
+ "types": "./dist/define.d.ts"
15
+ }
16
+ },
17
+ "files": [
18
+ "dist",
19
+ "src-dev",
20
+ "LICENSE"
21
+ ],
22
+ "scripts": {
23
+ "build": "tsup",
24
+ "prepublish": "yarn build",
25
+ "prepack": "yarn build"
26
+ },
27
+ "keywords": [
28
+ "vite",
29
+ "plugin",
30
+ "mcp",
31
+ "model-context-protocol",
32
+ "build-tool"
33
+ ],
34
+ "author": "Willyams Yujra <yracnet@gmail.com>",
35
+ "license": "MIT",
36
+ "homepage": "https://github.com/yracnet/vite-plugin-mcp-builder",
37
+ "repository": {
38
+ "type": "git",
39
+ "url": "https://github.com/yracnet/vite-plugin-mcp-builder"
40
+ },
41
+ "peerDependencies": {
42
+ "@modelcontextprotocol/sdk": "^1.26.0",
43
+ "vite": "^3 || ^4 || ^5 || ^6 || ^7",
44
+ "glob": "^13.0.0"
45
+ },
46
+ "dependencies": {},
47
+ "devDependencies": {
48
+ "@types/node": "^24.10.1",
49
+ "glob": "^13.0.1",
50
+ "globals": "^16.5.0",
51
+ "tsup": "^8.5.1",
52
+ "typescript": "~5.9.3",
53
+ "vite": "^7.2.4"
54
+ }
55
+ }
@@ -0,0 +1,10 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+
3
+ export default () => {
4
+ const servidor = new McpServer({
5
+ name: "mcp-example",
6
+ version: "1.0.0",
7
+ });
8
+ return servidor;
9
+ }
10
+
@@ -0,0 +1,33 @@
1
+ import express from "express"
2
+ import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
3
+ import createInstance from "@mcp/createInstance.js"
4
+ import cors from 'cors';
5
+ import { randomUUID } from 'node:crypto';
6
+
7
+ export const createHandler = async ({
8
+ stateless = true
9
+ }) => {
10
+ const handler = express();
11
+ handler.use(express.json());
12
+ handler.use(cors({
13
+ origin: '*',
14
+ methods: ['GET', 'POST', 'DELETE', 'OPTIONS'],
15
+ allowedHeaders: ['Content-Type', 'mcp-session-id', 'Last-Event-ID', 'mcp-protocol-version'],
16
+ exposedHeaders: ['mcp-session-id', 'mcp-protocol-version']
17
+ }));
18
+
19
+ const transport = new StreamableHTTPServerTransport({
20
+ sessionIdGenerator: stateless ? undefined : randomUUID,
21
+ retryInterval: 2000,
22
+ });
23
+ const server = await createInstance();
24
+ server.connect(transport);
25
+
26
+ handler.all('/', async (req, res) => {
27
+ const sessionId = req.headers['mcp-session-id'];
28
+ console.log(`\n${req.method} ${req.originalUrl}`, req.body, sessionId);
29
+ await transport.handleRequest(req, res, req.body);
30
+ });
31
+ return handler;
32
+ }
33
+
@@ -0,0 +1,6 @@
1
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
2
+ import createInstance from "@mcp/createInstance.js"
3
+
4
+ const server = await createInstance();
5
+ const transport = new StdioServerTransport();
6
+ await server.connect(transport);