packkit-mcp 0.1.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.
Files changed (3) hide show
  1. package/README.md +30 -0
  2. package/package.json +38 -0
  3. package/server.js +131 -0
package/README.md ADDED
@@ -0,0 +1,30 @@
1
+ # packkit-mcp
2
+
3
+ An [MCP](https://modelcontextprotocol.io) server for **[Packkit](https://github.com/DanMat/create-packkit)** — let AI agents (Claude Desktop, Cursor, Windsurf, …) scaffold modern npm packages, CLIs, HTTP services, and front-end apps as a native tool.
4
+
5
+ ## Tools
6
+
7
+ - **`packkit_schema`** — every option, preset, and alias as JSON (call first to learn the interface).
8
+ - **`packkit_preview`** — the files a config would generate, without writing anything.
9
+ - **`packkit_scaffold`** — generate a project to disk (optional `git init` + install).
10
+
11
+ ## Setup
12
+
13
+ Add to your MCP client config (e.g. Claude Desktop's `claude_desktop_config.json`):
14
+
15
+ ```json
16
+ {
17
+ "mcpServers": {
18
+ "packkit": {
19
+ "command": "npx",
20
+ "args": ["-y", "packkit-mcp"]
21
+ }
22
+ }
23
+ }
24
+ ```
25
+
26
+ Then ask your agent things like *"scaffold a React component library called ui with Storybook"* or *"preview a Hono service named api"*.
27
+
28
+ ## License
29
+
30
+ [MIT](https://github.com/DanMat/create-packkit/blob/main/LICENSE) © DanMat
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "packkit-mcp",
3
+ "version": "0.1.0",
4
+ "description": "MCP server for Packkit — let AI agents scaffold modern npm packages, CLIs, services, and apps as a native tool.",
5
+ "type": "module",
6
+ "bin": {
7
+ "packkit-mcp": "server.js"
8
+ },
9
+ "files": [
10
+ "server.js",
11
+ "README.md"
12
+ ],
13
+ "engines": {
14
+ "node": ">=18"
15
+ },
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "git+https://github.com/DanMat/create-packkit.git",
19
+ "directory": "mcp"
20
+ },
21
+ "keywords": [
22
+ "mcp",
23
+ "model-context-protocol",
24
+ "scaffold",
25
+ "generator",
26
+ "npm-package",
27
+ "packkit",
28
+ "ai",
29
+ "agent"
30
+ ],
31
+ "author": "DanMat <dannymatthew@gmail.com>",
32
+ "license": "MIT",
33
+ "homepage": "https://danmat.github.io/create-packkit/",
34
+ "dependencies": {
35
+ "@modelcontextprotocol/sdk": "^1.29.0",
36
+ "create-packkit": "^1.1.0"
37
+ }
38
+ }
package/server.js ADDED
@@ -0,0 +1,131 @@
1
+ #!/usr/bin/env node
2
+ // Packkit MCP server — exposes Packkit scaffolding as Model Context Protocol
3
+ // tools so agents (Claude Desktop, Cursor, etc.) can generate projects natively.
4
+
5
+ import { mkdir, writeFile } from 'node:fs/promises';
6
+ import { existsSync, readdirSync } from 'node:fs';
7
+ import { dirname, join, resolve } from 'node:path';
8
+ import { spawnSync } from 'node:child_process';
9
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
10
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
11
+ import { ListToolsRequestSchema, CallToolRequestSchema } from '@modelcontextprotocol/sdk/types.js';
12
+ import {
13
+ generate,
14
+ fromPreset,
15
+ normalizeConfig,
16
+ OPTIONS,
17
+ PRESET_INFO,
18
+ PRESET_ALIASES,
19
+ } from 'create-packkit/core';
20
+
21
+ const configFrom = ({ name, preset, options }) => {
22
+ const base = { name, ...(options || {}) };
23
+ return preset ? fromPreset(preset, base) : normalizeConfig(base);
24
+ };
25
+
26
+ const TOOLS = [
27
+ {
28
+ name: 'packkit_schema',
29
+ description:
30
+ 'Return every Packkit option, preset, and shortcut alias as JSON. Call this first to learn what can be configured.',
31
+ inputSchema: { type: 'object', properties: {} },
32
+ },
33
+ {
34
+ name: 'packkit_preview',
35
+ description:
36
+ 'Preview the files Packkit would generate for a config, without writing anything. Returns the stack summary and the file tree.',
37
+ inputSchema: {
38
+ type: 'object',
39
+ properties: {
40
+ name: { type: 'string', description: 'Package name' },
41
+ preset: { type: 'string', description: 'A preset or alias (e.g. ts-lib, react-lib, node-service, rlib)' },
42
+ options: { type: 'object', description: 'Any options from packkit_schema (e.g. { "framework": "vue", "target": ["library"] })' },
43
+ },
44
+ required: ['name'],
45
+ },
46
+ },
47
+ {
48
+ name: 'packkit_scaffold',
49
+ description:
50
+ 'Generate a project to disk. Writes files under <directory>/<name> (or ./<name>), optionally runs git init and installs dependencies.',
51
+ inputSchema: {
52
+ type: 'object',
53
+ properties: {
54
+ name: { type: 'string', description: 'Package name (also the folder name)' },
55
+ preset: { type: 'string', description: 'A preset or alias' },
56
+ options: { type: 'object', description: 'Any options from packkit_schema' },
57
+ directory: { type: 'string', description: 'Parent directory to create the project in (default: current working directory)' },
58
+ install: { type: 'boolean', description: 'Install dependencies (default false)' },
59
+ git: { type: 'boolean', description: 'git init + initial commit (default false)' },
60
+ },
61
+ required: ['name'],
62
+ },
63
+ },
64
+ ];
65
+
66
+ const text = (t) => ({ content: [{ type: 'text', text: t }] });
67
+ const fail = (t) => ({ content: [{ type: 'text', text: t }], isError: true });
68
+
69
+ async function writeProject(targetDir, files) {
70
+ for (const [rel, contents] of Object.entries(files)) {
71
+ const full = join(targetDir, rel);
72
+ await mkdir(dirname(full), { recursive: true });
73
+ await writeFile(full, contents);
74
+ }
75
+ }
76
+
77
+ function fileTree(files) {
78
+ return Object.keys(files).sort().map((p) => ` ${p}`).join('\n');
79
+ }
80
+
81
+ const server = new Server({ name: 'packkit', version: '0.1.0' }, { capabilities: { tools: {} } });
82
+
83
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: TOOLS }));
84
+
85
+ server.setRequestHandler(CallToolRequestSchema, async (req) => {
86
+ const { name, arguments: args = {} } = req.params;
87
+ try {
88
+ if (name === 'packkit_schema') {
89
+ return text(JSON.stringify({ options: OPTIONS, presets: PRESET_INFO, aliases: PRESET_ALIASES }, null, 2));
90
+ }
91
+
92
+ if (name === 'packkit_preview') {
93
+ const { files, summary } = generate(configFrom(args));
94
+ return text(`Stack: ${summary.stack.join(' · ')}\nFiles (${summary.fileCount}):\n${fileTree(files)}`);
95
+ }
96
+
97
+ if (name === 'packkit_scaffold') {
98
+ const config = configFrom(args);
99
+ if (!config.name) return fail('A "name" is required.');
100
+ const parent = args.directory ? resolve(args.directory) : process.cwd();
101
+ const targetDir = join(parent, config.name);
102
+ if (existsSync(targetDir) && readdirSync(targetDir).length > 0) {
103
+ return fail(`Target directory "${targetDir}" is not empty.`);
104
+ }
105
+ const { files, summary } = generate(config);
106
+ await writeProject(targetDir, files);
107
+
108
+ const steps = [];
109
+ if (args.git) {
110
+ spawnSync('git', ['init', '--quiet'], { cwd: targetDir });
111
+ spawnSync('git', ['add', '-A'], { cwd: targetDir });
112
+ spawnSync('git', ['commit', '-m', 'Initial commit from Packkit', '--quiet'], { cwd: targetDir });
113
+ steps.push('git initialized');
114
+ }
115
+ if (args.install) {
116
+ const ok = spawnSync(config.packageManager, ['install'], { cwd: targetDir }).status === 0;
117
+ steps.push(ok ? 'dependencies installed' : 'install failed (run it manually)');
118
+ }
119
+ return text(
120
+ `Created ${summary.name} at ${targetDir}\n${summary.fileCount} files · ${summary.stack.join(' · ')}` +
121
+ (steps.length ? `\n${steps.join('; ')}` : ''),
122
+ );
123
+ }
124
+
125
+ return fail(`Unknown tool: ${name}`);
126
+ } catch (err) {
127
+ return fail(`Error: ${err instanceof Error ? err.message : String(err)}`);
128
+ }
129
+ });
130
+
131
+ await server.connect(new StdioServerTransport());