@tac0de/project-bootstrap-mcp 1.1.1 → 1.2.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/README.md CHANGED
@@ -61,7 +61,7 @@ This project turns the MCP (Management Control Plane) bootstrap documentation in
61
61
  ```json
62
62
  {
63
63
  "command": "npx",
64
- "args": ["-y", "project-bootstrap-mcp"]
64
+ "args": ["-y", "@tac0de/project-bootstrap-mcp"]
65
65
  }
66
66
  ```
67
67
 
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ require('../dist/index.js');
File without changes
package/dist/index.d.ts CHANGED
@@ -1,5 +1,3 @@
1
1
  import BootstrapStore from './store';
2
- import createApp from './app';
3
- import startServer from './server';
4
- export { BootstrapStore, createApp, startServer };
2
+ export { BootstrapStore };
5
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,cAAc,MAAM,SAAS,CAAC;AACrC,OAAO,SAAS,MAAM,OAAO,CAAC;AAC9B,OAAO,WAAW,MAAM,UAAU,CAAC;AAEnC,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAMA,OAAO,cAAc,MAAM,SAAS,CAAC;AAqMrC,OAAO,EAAE,cAAc,EAAE,CAAC"}
package/dist/index.js CHANGED
@@ -3,10 +3,187 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.startServer = exports.createApp = exports.BootstrapStore = void 0;
6
+ exports.BootstrapStore = void 0;
7
+ const index_js_1 = require("@modelcontextprotocol/sdk/server/index.js");
8
+ const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
9
+ const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
7
10
  const store_1 = __importDefault(require("./store"));
8
11
  exports.BootstrapStore = store_1.default;
9
- const app_1 = __importDefault(require("./app"));
10
- exports.createApp = app_1.default;
11
- const server_1 = __importDefault(require("./server"));
12
- exports.startServer = server_1.default;
12
+ // Create MCP server
13
+ const server = new index_js_1.Server({
14
+ name: '@tac0de/project-bootstrap-mcp',
15
+ version: '1.1.2',
16
+ }, {
17
+ capabilities: {
18
+ tools: {},
19
+ },
20
+ });
21
+ const store = new store_1.default();
22
+ // List available tools
23
+ server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => {
24
+ return {
25
+ tools: [
26
+ {
27
+ name: 'list_bootstraps',
28
+ description: 'List all bootstrap project definitions',
29
+ inputSchema: {
30
+ type: 'object',
31
+ properties: {},
32
+ },
33
+ },
34
+ {
35
+ name: 'create_bootstrap',
36
+ description: 'Create a new bootstrap project definition with steps and criteria',
37
+ inputSchema: {
38
+ type: 'object',
39
+ properties: {
40
+ name: {
41
+ type: 'string',
42
+ description: 'Name of the bootstrap project',
43
+ },
44
+ description: {
45
+ type: 'string',
46
+ description: 'Description of the bootstrap project',
47
+ },
48
+ primaryAction: {
49
+ type: 'string',
50
+ description: 'The primary action to be performed',
51
+ },
52
+ targetPlatforms: {
53
+ type: 'array',
54
+ items: {
55
+ type: 'string',
56
+ },
57
+ description: 'Target platforms for this bootstrap',
58
+ },
59
+ successCriteria: {
60
+ type: 'array',
61
+ items: {
62
+ type: 'string',
63
+ },
64
+ description: 'Criteria for successful completion',
65
+ },
66
+ steps: {
67
+ type: 'array',
68
+ items: {
69
+ type: 'object',
70
+ properties: {
71
+ title: {
72
+ type: 'string',
73
+ description: 'Title of the step',
74
+ },
75
+ detail: {
76
+ type: 'string',
77
+ description: 'Detailed instructions for the step',
78
+ },
79
+ },
80
+ required: ['title', 'detail'],
81
+ },
82
+ description: 'Steps to complete the bootstrap',
83
+ },
84
+ },
85
+ required: ['name', 'description', 'primaryAction', 'steps'],
86
+ },
87
+ },
88
+ {
89
+ name: 'get_bootstrap',
90
+ description: 'Get a specific bootstrap project by ID',
91
+ inputSchema: {
92
+ type: 'object',
93
+ properties: {
94
+ id: {
95
+ type: 'string',
96
+ description: 'The ID of the bootstrap project',
97
+ },
98
+ },
99
+ required: ['id'],
100
+ },
101
+ },
102
+ ],
103
+ };
104
+ });
105
+ // Handle tool execution
106
+ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
107
+ const { name, arguments: args } = request.params;
108
+ switch (name) {
109
+ case 'list_bootstraps': {
110
+ const items = store.list();
111
+ return {
112
+ content: [
113
+ {
114
+ type: 'text',
115
+ text: JSON.stringify({ items }, null, 2),
116
+ },
117
+ ],
118
+ };
119
+ }
120
+ case 'create_bootstrap': {
121
+ const payload = {
122
+ name: String(args?.name),
123
+ description: String(args?.description),
124
+ primaryAction: String(args?.primaryAction),
125
+ targetPlatforms: Array.isArray(args?.targetPlatforms)
126
+ ? args.targetPlatforms.map(String)
127
+ : [],
128
+ successCriteria: Array.isArray(args?.successCriteria)
129
+ ? args.successCriteria.map(String)
130
+ : [],
131
+ steps: Array.isArray(args?.steps)
132
+ ? args.steps
133
+ : [],
134
+ };
135
+ const saved = store.add(payload);
136
+ return {
137
+ content: [
138
+ {
139
+ type: 'text',
140
+ text: JSON.stringify(saved, null, 2),
141
+ },
142
+ ],
143
+ };
144
+ }
145
+ case 'get_bootstrap': {
146
+ const id = String(args?.id);
147
+ const record = store.find(id);
148
+ if (!record) {
149
+ return {
150
+ content: [
151
+ {
152
+ type: 'text',
153
+ text: JSON.stringify({ error: 'Bootstrap not found' }, null, 2),
154
+ },
155
+ ],
156
+ isError: true,
157
+ };
158
+ }
159
+ return {
160
+ content: [
161
+ {
162
+ type: 'text',
163
+ text: JSON.stringify(record, null, 2),
164
+ },
165
+ ],
166
+ };
167
+ }
168
+ default:
169
+ return {
170
+ content: [
171
+ {
172
+ type: 'text',
173
+ text: JSON.stringify({ error: 'Unknown tool' }, null, 2),
174
+ },
175
+ ],
176
+ isError: true,
177
+ };
178
+ }
179
+ });
180
+ // Start the server
181
+ async function main() {
182
+ const transport = new stdio_js_1.StdioServerTransport();
183
+ await server.connect(transport);
184
+ console.error('Project Bootstrap MCP server running on stdio');
185
+ }
186
+ main().catch((error) => {
187
+ console.error('Fatal error:', error);
188
+ process.exit(1);
189
+ });
package/dist/package.json CHANGED
@@ -1,14 +1,14 @@
1
1
  {
2
2
  "name": "@tac0de/project-bootstrap-mcp",
3
- "version": "1.1.0",
3
+ "version": "1.1.2",
4
4
  "description": "Project Bootstrap MCP API tooling for launching MCP bootstrap definitions and documentation.",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
7
- "project-bootstrap-mcp": "dist/bin/project-bootstrap-mcp.js"
7
+ "project-bootstrap-mcp": "bin/project-bootstrap-mcp.js"
8
8
  },
9
9
  "scripts": {
10
10
  "build": "tsc",
11
- "start": "npm run build && node ./dist/bin/project-bootstrap-mcp.js",
11
+ "start": "npm run build && node ./bin/project-bootstrap-mcp.js",
12
12
  "test": "node --test -r ts-node/register test/store.test.ts"
13
13
  },
14
14
  "keywords": [
package/package.json CHANGED
@@ -1,14 +1,14 @@
1
1
  {
2
2
  "name": "@tac0de/project-bootstrap-mcp",
3
- "version": "1.1.1",
4
- "description": "Project Bootstrap MCP API tooling for launching MCP bootstrap definitions and documentation.",
3
+ "version": "1.2.0",
4
+ "description": "MCP server for managing project bootstrap definitions with steps and success criteria.",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
7
- "project-bootstrap-mcp": "dist/bin/project-bootstrap-mcp.js"
7
+ "project-bootstrap-mcp": "bin/project-bootstrap-mcp.js"
8
8
  },
9
9
  "scripts": {
10
10
  "build": "tsc",
11
- "start": "npm run build && node ./dist/bin/project-bootstrap-mcp.js",
11
+ "start": "npm run build && node ./bin/project-bootstrap-mcp.js",
12
12
  "test": "node --test -r ts-node/register test/store.test.ts"
13
13
  },
14
14
  "keywords": [
@@ -42,10 +42,9 @@
42
42
  "url": "https://github.com/tac0de/project-bootstrap-mcp"
43
43
  },
44
44
  "dependencies": {
45
- "express": "^4.19.2"
45
+ "@modelcontextprotocol/sdk": "^1.25.1"
46
46
  },
47
47
  "devDependencies": {
48
- "@types/express": "^5.0.6",
49
48
  "@types/node": "^25.0.3",
50
49
  "ts-node": "^10.9.2",
51
50
  "typescript": "^5.9.3"
package/src/index.ts CHANGED
@@ -1,5 +1,204 @@
1
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
2
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
3
+ import {
4
+ CallToolRequestSchema,
5
+ ListToolsRequestSchema,
6
+ } from '@modelcontextprotocol/sdk/types.js';
1
7
  import BootstrapStore from './store';
2
- import createApp from './app';
3
- import startServer from './server';
8
+ import type { BootstrapPayload } from './types';
4
9
 
5
- export { BootstrapStore, createApp, startServer };
10
+ // Create MCP server
11
+ const server = new Server(
12
+ {
13
+ name: '@tac0de/project-bootstrap-mcp',
14
+ version: '1.1.2',
15
+ },
16
+ {
17
+ capabilities: {
18
+ tools: {},
19
+ },
20
+ }
21
+ );
22
+
23
+ const store = new BootstrapStore();
24
+
25
+ // List available tools
26
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
27
+ return {
28
+ tools: [
29
+ {
30
+ name: 'list_bootstraps',
31
+ description: 'List all bootstrap project definitions',
32
+ inputSchema: {
33
+ type: 'object',
34
+ properties: {},
35
+ },
36
+ },
37
+ {
38
+ name: 'create_bootstrap',
39
+ description: 'Create a new bootstrap project definition with steps and criteria',
40
+ inputSchema: {
41
+ type: 'object',
42
+ properties: {
43
+ name: {
44
+ type: 'string',
45
+ description: 'Name of the bootstrap project',
46
+ },
47
+ description: {
48
+ type: 'string',
49
+ description: 'Description of the bootstrap project',
50
+ },
51
+ primaryAction: {
52
+ type: 'string',
53
+ description: 'The primary action to be performed',
54
+ },
55
+ targetPlatforms: {
56
+ type: 'array',
57
+ items: {
58
+ type: 'string',
59
+ },
60
+ description: 'Target platforms for this bootstrap',
61
+ },
62
+ successCriteria: {
63
+ type: 'array',
64
+ items: {
65
+ type: 'string',
66
+ },
67
+ description: 'Criteria for successful completion',
68
+ },
69
+ steps: {
70
+ type: 'array',
71
+ items: {
72
+ type: 'object',
73
+ properties: {
74
+ title: {
75
+ type: 'string',
76
+ description: 'Title of the step',
77
+ },
78
+ detail: {
79
+ type: 'string',
80
+ description: 'Detailed instructions for the step',
81
+ },
82
+ },
83
+ required: ['title', 'detail'],
84
+ },
85
+ description: 'Steps to complete the bootstrap',
86
+ },
87
+ },
88
+ required: ['name', 'description', 'primaryAction', 'steps'],
89
+ },
90
+ },
91
+ {
92
+ name: 'get_bootstrap',
93
+ description: 'Get a specific bootstrap project by ID',
94
+ inputSchema: {
95
+ type: 'object',
96
+ properties: {
97
+ id: {
98
+ type: 'string',
99
+ description: 'The ID of the bootstrap project',
100
+ },
101
+ },
102
+ required: ['id'],
103
+ },
104
+ },
105
+ ],
106
+ };
107
+ });
108
+
109
+ // Handle tool execution
110
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
111
+ const { name, arguments: args } = request.params;
112
+
113
+ switch (name) {
114
+ case 'list_bootstraps': {
115
+ const items = store.list();
116
+ return {
117
+ content: [
118
+ {
119
+ type: 'text',
120
+ text: JSON.stringify({ items }, null, 2),
121
+ },
122
+ ],
123
+ };
124
+ }
125
+
126
+ case 'create_bootstrap': {
127
+ const payload: BootstrapPayload = {
128
+ name: String(args?.name),
129
+ description: String(args?.description),
130
+ primaryAction: String(args?.primaryAction),
131
+ targetPlatforms: Array.isArray(args?.targetPlatforms)
132
+ ? args.targetPlatforms.map(String)
133
+ : [],
134
+ successCriteria: Array.isArray(args?.successCriteria)
135
+ ? args.successCriteria.map(String)
136
+ : [],
137
+ steps: Array.isArray(args?.steps)
138
+ ? (args.steps as BootstrapPayload['steps'])
139
+ : [],
140
+ };
141
+
142
+ const saved = store.add(payload);
143
+ return {
144
+ content: [
145
+ {
146
+ type: 'text',
147
+ text: JSON.stringify(saved, null, 2),
148
+ },
149
+ ],
150
+ };
151
+ }
152
+
153
+ case 'get_bootstrap': {
154
+ const id = String(args?.id);
155
+ const record = store.find(id);
156
+
157
+ if (!record) {
158
+ return {
159
+ content: [
160
+ {
161
+ type: 'text',
162
+ text: JSON.stringify({ error: 'Bootstrap not found' }, null, 2),
163
+ },
164
+ ],
165
+ isError: true,
166
+ };
167
+ }
168
+
169
+ return {
170
+ content: [
171
+ {
172
+ type: 'text',
173
+ text: JSON.stringify(record, null, 2),
174
+ },
175
+ ],
176
+ };
177
+ }
178
+
179
+ default:
180
+ return {
181
+ content: [
182
+ {
183
+ type: 'text',
184
+ text: JSON.stringify({ error: 'Unknown tool' }, null, 2),
185
+ },
186
+ ],
187
+ isError: true,
188
+ };
189
+ }
190
+ });
191
+
192
+ // Start the server
193
+ async function main() {
194
+ const transport = new StdioServerTransport();
195
+ await server.connect(transport);
196
+ console.error('Project Bootstrap MCP server running on stdio');
197
+ }
198
+
199
+ main().catch((error) => {
200
+ console.error('Fatal error:', error);
201
+ process.exit(1);
202
+ });
203
+
204
+ export { BootstrapStore };
@@ -1,26 +0,0 @@
1
- #!/usr/bin/env node
2
- import startServer from '../src/server.js';
3
-
4
- function parsePort(args: string[], envPort: string | undefined): number {
5
- let portValue = envPort || '4000';
6
- args.forEach((arg, index, list) => {
7
- if (arg === '--port' && list[index + 1]) {
8
- portValue = list[index + 1];
9
- }
10
- if (arg.startsWith('--port=')) {
11
- portValue = arg.split('=')[1];
12
- }
13
- if (arg === '-p' && list[index + 1]) {
14
- portValue = list[index + 1];
15
- }
16
- });
17
- const parsed = Number.parseInt(portValue, 10);
18
- if (Number.isNaN(parsed)) {
19
- console.error(`invalid port value: ${portValue}`);
20
- process.exit(1);
21
- }
22
- return parsed;
23
- }
24
-
25
- const port = parsePort(process.argv.slice(2), process.env.PORT);
26
- startServer({ port });
package/src/app.ts DELETED
@@ -1,73 +0,0 @@
1
- import express, { Express, Request, Response, NextFunction } from 'express';
2
- import pkg from '../package.json';
3
- import { validateBootstrapPayload } from './validators';
4
- import BootstrapStore from './store';
5
- import type { BootstrapPayload } from './types';
6
-
7
- interface CreateAppOptions {
8
- store?: BootstrapStore;
9
- }
10
-
11
- export default function createApp(options: CreateAppOptions = {}) {
12
- const store = options.store ?? new BootstrapStore();
13
- const app: Express = express();
14
-
15
- app.use(express.json());
16
-
17
- app.get('/api/status', (_req: Request, res: Response) => {
18
- res.json({
19
- service: pkg.name,
20
- version: pkg.version,
21
- uptime: process.uptime(),
22
- timestamp: new Date().toISOString(),
23
- });
24
- });
25
-
26
- app.get('/api/bootstraps', (_req: Request, res: Response) => {
27
- res.json({ items: store.list() });
28
- });
29
-
30
- app.post('/api/bootstraps', (req: Request, res: Response) => {
31
- const validation = validateBootstrapPayload(req.body);
32
- if (!validation.valid) {
33
- return res.status(400).json({ errors: validation.errors });
34
- }
35
- const payload: BootstrapPayload = {
36
- name: req.body.name,
37
- description: req.body.description,
38
- primaryAction: req.body.primaryAction,
39
- targetPlatforms: Array.isArray(req.body.targetPlatforms)
40
- ? req.body.targetPlatforms.map(String)
41
- : [],
42
- successCriteria: Array.isArray(req.body.successCriteria)
43
- ? req.body.successCriteria.map(String)
44
- : [],
45
- steps: Array.isArray(req.body.steps)
46
- ? (req.body.steps as BootstrapPayload['steps'])
47
- : [],
48
- };
49
- const saved = store.add(payload);
50
- res.status(201).json(saved);
51
- });
52
-
53
- app.get('/api/bootstraps/:id', (req: Request, res: Response) => {
54
- const record = store.find(req.params.id);
55
- if (!record) {
56
- return res.status(404).json({ error: 'bootstrap not found' });
57
- }
58
- res.json(record);
59
- });
60
-
61
- app.use((_req: Request, res: Response) => {
62
- res.status(404).json({ error: 'not found' });
63
- });
64
-
65
- app.use((err: Error, _req: Request, res: Response, next: NextFunction) => {
66
- // eslint-disable-next-line no-console
67
- console.error('internal error', err);
68
- res.status(500).json({ error: 'internal server error' });
69
- next(err);
70
- });
71
-
72
- return { app, store };
73
- }
package/src/server.ts DELETED
@@ -1,44 +0,0 @@
1
- import type { Express } from 'express';
2
- import type { Server } from 'http';
3
- import createApp from './app';
4
-
5
- export interface StartServerOptions {
6
- port?: number;
7
- onStart?: (message: string, port: number) => void;
8
- }
9
-
10
- export interface StartServerResult {
11
- app: Express;
12
- server: Server;
13
- }
14
-
15
- export default function startServer({
16
- port,
17
- onStart,
18
- }: StartServerOptions = {}): StartServerResult {
19
- const defaultPort = Number(process.env.PORT) || 4000;
20
- const resolvedPort = port ?? defaultPort;
21
- const { app } = createApp();
22
- const server = app.listen(resolvedPort, () => {
23
- const message = `Project Bootstrap MCP listening on port ${resolvedPort}`;
24
- if (typeof onStart === 'function') {
25
- onStart(message, resolvedPort);
26
- } else {
27
- // eslint-disable-next-line no-console
28
- console.log(message);
29
- }
30
- });
31
-
32
- const graceful = () => {
33
- server.close(() => {
34
- // eslint-disable-next-line no-console
35
- console.log('Project Bootstrap MCP shutting down');
36
- process.exit(0);
37
- });
38
- };
39
-
40
- process.on('SIGINT', graceful);
41
- process.on('SIGTERM', graceful);
42
-
43
- return { app, server };
44
- }
package/src/validators.ts DELETED
@@ -1,43 +0,0 @@
1
- import type { BootstrapPayload, BootstrapStep } from './types';
2
-
3
- export interface ValidationResult {
4
- valid: boolean;
5
- errors: string[];
6
- }
7
-
8
- export function validateBootstrapPayload(payload: unknown): ValidationResult {
9
- const errors: string[] = [];
10
- if (!payload || typeof payload !== 'object') {
11
- errors.push('payload must be an object');
12
- return { valid: false, errors };
13
- }
14
-
15
- const typedPayload = payload as BootstrapPayload;
16
- const { name, description, primaryAction, steps } = typedPayload;
17
-
18
- if (!name || typeof name !== 'string') {
19
- errors.push('name is required and must be a string');
20
- }
21
- if (!description || typeof description !== 'string') {
22
- errors.push('description is required and must be a string');
23
- }
24
- if (!primaryAction || typeof primaryAction !== 'string') {
25
- errors.push('primaryAction is required and must be a string');
26
- }
27
-
28
- if (!Array.isArray(steps) || steps.length === 0) {
29
- errors.push('steps must be a non-empty array');
30
- } else {
31
- steps.forEach((step, index) => {
32
- const currentStep = step as BootstrapStep | undefined;
33
- if (!currentStep || typeof currentStep.title !== 'string') {
34
- errors.push(`steps[${index}].title is required`);
35
- }
36
- if (!currentStep || typeof currentStep.detail !== 'string') {
37
- errors.push(`steps[${index}].detail is required`);
38
- }
39
- });
40
- }
41
-
42
- return { valid: errors.length === 0, errors };
43
- }