@bamboocss/mcp 1.11.1 → 1.11.2
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/dist/index.cjs +258 -0
- package/dist/index.d.cts +47 -0
- package/dist/index.d.mts +47 -0
- package/dist/index.mjs +211 -264
- package/package.json +12 -12
- package/dist/index.js +0 -323
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
//#region \0rolldown/runtime.js
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
11
|
+
key = keys[i];
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
13
|
+
get: ((k) => from[k]).bind(null, key),
|
|
14
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
20
|
+
value: mod,
|
|
21
|
+
enumerable: true
|
|
22
|
+
}) : target, mod));
|
|
23
|
+
//#endregion
|
|
24
|
+
let _modelcontextprotocol_sdk_server_mcp_js = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
25
|
+
let _modelcontextprotocol_sdk_server_stdio_js = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
26
|
+
let _bamboocss_logger = require("@bamboocss/logger");
|
|
27
|
+
let _bamboocss_node = require("@bamboocss/node");
|
|
28
|
+
let _bamboocss_token_dictionary = require("@bamboocss/token-dictionary");
|
|
29
|
+
let path = require("path");
|
|
30
|
+
let zod_v4 = require("zod/v4");
|
|
31
|
+
zod_v4 = __toESM(zod_v4);
|
|
32
|
+
let _clack_prompts = require("@clack/prompts");
|
|
33
|
+
_clack_prompts = __toESM(_clack_prompts);
|
|
34
|
+
let fs = require("fs");
|
|
35
|
+
//#region src/server.ts
|
|
36
|
+
const tokenCategorySchema = zod_v4.enum(_bamboocss_token_dictionary.TOKEN_CATEGORIES).optional().describe("Filter by token category");
|
|
37
|
+
const json = (data) => ({ content: [{
|
|
38
|
+
type: "text",
|
|
39
|
+
text: JSON.stringify(data)
|
|
40
|
+
}] });
|
|
41
|
+
/**
|
|
42
|
+
* Create an MCP server with all tools registered.
|
|
43
|
+
* This is separated from `startMcpServer` to allow testing with custom transports.
|
|
44
|
+
*/
|
|
45
|
+
function createMcpServer(options) {
|
|
46
|
+
const { ctx } = options;
|
|
47
|
+
const server = new _modelcontextprotocol_sdk_server_mcp_js.McpServer({
|
|
48
|
+
name: "@bamboocss/mcp",
|
|
49
|
+
version: "1.0.0"
|
|
50
|
+
});
|
|
51
|
+
const recipeNames = ctx.recipes.keys;
|
|
52
|
+
const patternNames = ctx.patterns.keys;
|
|
53
|
+
const recipeNameSchema = recipeNames.length ? zod_v4.enum(recipeNames).optional().describe("Filter by recipe name") : zod_v4.string().optional().describe("Filter by recipe name");
|
|
54
|
+
const patternNameSchema = patternNames.length ? zod_v4.enum(patternNames).optional().describe("Filter by pattern name") : zod_v4.string().optional().describe("Filter by pattern name");
|
|
55
|
+
server.registerTool("get_tokens", {
|
|
56
|
+
description: "Get all design tokens with their values, CSS variables, and usage examples",
|
|
57
|
+
inputSchema: { category: tokenCategorySchema }
|
|
58
|
+
}, async ({ category }) => {
|
|
59
|
+
const spec = ctx.getSpecOfType("tokens");
|
|
60
|
+
const data = category ? spec.data.filter((group) => group.type === category) : spec.data;
|
|
61
|
+
return json({
|
|
62
|
+
type: spec.type,
|
|
63
|
+
data
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
server.registerTool("get_semantic_tokens", {
|
|
67
|
+
description: "Get semantic tokens with their conditional values (responsive, color modes)",
|
|
68
|
+
inputSchema: { category: tokenCategorySchema }
|
|
69
|
+
}, async ({ category }) => {
|
|
70
|
+
const spec = ctx.getSpecOfType("semantic-tokens");
|
|
71
|
+
const data = category ? spec.data.filter((group) => group.type === category) : spec.data;
|
|
72
|
+
return json({
|
|
73
|
+
type: spec.type,
|
|
74
|
+
data
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
server.registerTool("get_recipes", {
|
|
78
|
+
description: "Get component recipes with their variants, default values, and usage examples",
|
|
79
|
+
inputSchema: { name: recipeNameSchema }
|
|
80
|
+
}, async ({ name }) => {
|
|
81
|
+
const spec = ctx.getSpecOfType("recipes");
|
|
82
|
+
const data = name ? spec.data.filter((item) => item.name === name) : spec.data;
|
|
83
|
+
return json({
|
|
84
|
+
type: spec.type,
|
|
85
|
+
data
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
server.registerTool("get_patterns", {
|
|
89
|
+
description: "Get layout patterns with their properties and usage examples",
|
|
90
|
+
inputSchema: { name: patternNameSchema }
|
|
91
|
+
}, async ({ name }) => {
|
|
92
|
+
const spec = ctx.getSpecOfType("patterns");
|
|
93
|
+
const data = name ? spec.data.filter((item) => item.name === name) : spec.data;
|
|
94
|
+
return json({
|
|
95
|
+
type: spec.type,
|
|
96
|
+
data
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
server.registerTool("get_conditions", { description: "Get all conditions (breakpoints, pseudo-classes, color modes) and their CSS values" }, async () => json(ctx.getSpecOfType("conditions")));
|
|
100
|
+
server.registerTool("get_keyframes", { description: "Get keyframe animations defined in the theme" }, async () => json(ctx.getSpecOfType("keyframes")));
|
|
101
|
+
server.registerTool("get_text_styles", { description: "Get text style compositions for typography" }, async () => json(ctx.getSpecOfType("text-styles")));
|
|
102
|
+
server.registerTool("get_layer_styles", { description: "Get layer style compositions for visual styling" }, async () => json(ctx.getSpecOfType("layer-styles")));
|
|
103
|
+
server.registerTool("get_animation_styles", { description: "Get animation style compositions" }, async () => json(ctx.getSpecOfType("animation-styles")));
|
|
104
|
+
server.registerTool("get_color_palette", { description: "Get the color palette with all color values" }, async () => json(ctx.getSpecOfType("color-palette")));
|
|
105
|
+
server.registerTool("get_config", { description: "Get the resolved Bamboo CSS configuration including paths, JSX settings, and output options" }, async () => json(ctx.config));
|
|
106
|
+
server.registerTool("get_usage_report", {
|
|
107
|
+
description: "Get a usage report of design tokens and recipes across the codebase. Shows which tokens/recipes are used, unused, or missing. Useful for auditing, cleanup, and identifying dead code.",
|
|
108
|
+
inputSchema: { scope: zod_v4.enum([
|
|
109
|
+
"all",
|
|
110
|
+
"token",
|
|
111
|
+
"recipe"
|
|
112
|
+
]).optional().describe("Analysis scope: token, recipe, or all (default)") }
|
|
113
|
+
}, async ({ scope }) => {
|
|
114
|
+
const result = (0, _bamboocss_node.analyze)(ctx);
|
|
115
|
+
const includeTokens = !scope || scope === "all" || scope === "token";
|
|
116
|
+
const includeRecipes = !scope || scope === "all" || scope === "recipe";
|
|
117
|
+
const report = {};
|
|
118
|
+
if (includeTokens && !ctx.tokens.isEmpty) report.tokens = result.getTokenReport().report.getSummary();
|
|
119
|
+
if (includeRecipes && !ctx.recipes.isEmpty()) report.recipes = result.getRecipeReport().report;
|
|
120
|
+
return json(report);
|
|
121
|
+
});
|
|
122
|
+
return server;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Start the MCP server with the given options.
|
|
126
|
+
* By default, uses StdioServerTransport for CLI usage.
|
|
127
|
+
*/
|
|
128
|
+
async function startMcpServer(options = {}) {
|
|
129
|
+
const { cwd = process.cwd(), config: configPath, silent = false, transport } = options;
|
|
130
|
+
if (silent) _bamboocss_logger.logger.level = "silent";
|
|
131
|
+
const resolvedCwd = (0, path.resolve)(cwd);
|
|
132
|
+
const resolvedConfigPath = configPath ? (0, path.resolve)(configPath) : void 0;
|
|
133
|
+
const server = createMcpServer({ ctx: await (0, _bamboocss_node.loadConfigAndCreateContext)({
|
|
134
|
+
cwd: resolvedCwd,
|
|
135
|
+
configPath: resolvedConfigPath
|
|
136
|
+
}) });
|
|
137
|
+
const serverTransport = transport ?? new _modelcontextprotocol_sdk_server_stdio_js.StdioServerTransport();
|
|
138
|
+
await server.connect(serverTransport);
|
|
139
|
+
console.error("Bamboo CSS MCP server started");
|
|
140
|
+
console.error(`Working directory: ${resolvedCwd}`);
|
|
141
|
+
if (resolvedConfigPath) console.error(`Config path: ${resolvedConfigPath}`);
|
|
142
|
+
return server;
|
|
143
|
+
}
|
|
144
|
+
//#endregion
|
|
145
|
+
//#region src/clients.ts
|
|
146
|
+
const MCP_CLIENTS = {
|
|
147
|
+
claude: {
|
|
148
|
+
name: "claude",
|
|
149
|
+
label: "Claude (.mcp.json)",
|
|
150
|
+
configPath: ".mcp.json",
|
|
151
|
+
configKey: "mcpServers"
|
|
152
|
+
},
|
|
153
|
+
cursor: {
|
|
154
|
+
name: "cursor",
|
|
155
|
+
label: "Cursor (.cursor/mcp.json)",
|
|
156
|
+
configPath: ".cursor/mcp.json",
|
|
157
|
+
configKey: "mcpServers"
|
|
158
|
+
},
|
|
159
|
+
vscode: {
|
|
160
|
+
name: "vscode",
|
|
161
|
+
label: "VS Code (.vscode/mcp.json)",
|
|
162
|
+
configPath: ".vscode/mcp.json",
|
|
163
|
+
configKey: "servers"
|
|
164
|
+
},
|
|
165
|
+
windsurf: {
|
|
166
|
+
name: "windsurf",
|
|
167
|
+
label: "Windsurf (.windsurf/mcp.json)",
|
|
168
|
+
configPath: ".windsurf/mcp.json",
|
|
169
|
+
configKey: "mcpServers"
|
|
170
|
+
},
|
|
171
|
+
codex: {
|
|
172
|
+
name: "codex",
|
|
173
|
+
label: "Codex (.codex/mcp.json)",
|
|
174
|
+
configPath: ".codex/mcp.json",
|
|
175
|
+
configKey: "mcpServers"
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
const CLIENT_NAMES = Object.keys(MCP_CLIENTS);
|
|
179
|
+
function isValidClient(client) {
|
|
180
|
+
return CLIENT_NAMES.includes(client);
|
|
181
|
+
}
|
|
182
|
+
function getClientConfig(client) {
|
|
183
|
+
return MCP_CLIENTS[client];
|
|
184
|
+
}
|
|
185
|
+
function generateMcpConfig(clientConfig) {
|
|
186
|
+
const serverConfig = {
|
|
187
|
+
command: "npx",
|
|
188
|
+
args: ["bamboo", "mcp"]
|
|
189
|
+
};
|
|
190
|
+
return { [clientConfig.configKey]: { bamboo: serverConfig } };
|
|
191
|
+
}
|
|
192
|
+
//#endregion
|
|
193
|
+
//#region src/init.ts
|
|
194
|
+
async function initMcpConfig(options = {}) {
|
|
195
|
+
const { cwd = process.cwd() } = options;
|
|
196
|
+
let { clients } = options;
|
|
197
|
+
_clack_prompts.intro("Bamboo MCP Setup");
|
|
198
|
+
if (!clients || clients.length === 0) {
|
|
199
|
+
const selected = await _clack_prompts.multiselect({
|
|
200
|
+
message: "Select AI clients to configure:",
|
|
201
|
+
options: CLIENT_NAMES.map((client) => ({
|
|
202
|
+
value: client,
|
|
203
|
+
label: MCP_CLIENTS[client].label
|
|
204
|
+
})),
|
|
205
|
+
required: true
|
|
206
|
+
});
|
|
207
|
+
if (_clack_prompts.isCancel(selected)) {
|
|
208
|
+
_clack_prompts.cancel("Setup cancelled.");
|
|
209
|
+
process.exit(0);
|
|
210
|
+
}
|
|
211
|
+
clients = selected;
|
|
212
|
+
}
|
|
213
|
+
const validClients = clients.filter((client) => {
|
|
214
|
+
if (!isValidClient(client)) {
|
|
215
|
+
_bamboocss_logger.logger.warn("mcp:init", `Unknown client: ${client}`);
|
|
216
|
+
return false;
|
|
217
|
+
}
|
|
218
|
+
return true;
|
|
219
|
+
});
|
|
220
|
+
if (validClients.length === 0) {
|
|
221
|
+
_clack_prompts.cancel("No valid clients selected.");
|
|
222
|
+
process.exit(1);
|
|
223
|
+
}
|
|
224
|
+
const results = [];
|
|
225
|
+
for (const client of validClients) {
|
|
226
|
+
const clientConfig = getClientConfig(client);
|
|
227
|
+
const configPath = (0, path.resolve)(cwd, clientConfig.configPath);
|
|
228
|
+
const configDir = (0, path.dirname)(configPath);
|
|
229
|
+
if (!(0, fs.existsSync)(configDir)) (0, fs.mkdirSync)(configDir, { recursive: true });
|
|
230
|
+
const newConfig = generateMcpConfig(clientConfig);
|
|
231
|
+
let finalConfig = newConfig;
|
|
232
|
+
if ((0, fs.existsSync)(configPath)) try {
|
|
233
|
+
const existingContent = (0, fs.readFileSync)(configPath, "utf-8");
|
|
234
|
+
const existingConfig = JSON.parse(existingContent);
|
|
235
|
+
finalConfig = {
|
|
236
|
+
...existingConfig,
|
|
237
|
+
[clientConfig.configKey]: {
|
|
238
|
+
...existingConfig[clientConfig.configKey],
|
|
239
|
+
...newConfig[clientConfig.configKey]
|
|
240
|
+
}
|
|
241
|
+
};
|
|
242
|
+
} catch {}
|
|
243
|
+
(0, fs.writeFileSync)(configPath, JSON.stringify(finalConfig, null, 2));
|
|
244
|
+
results.push({
|
|
245
|
+
client,
|
|
246
|
+
path: clientConfig.configPath,
|
|
247
|
+
created: true
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
_clack_prompts.note(results.map((r) => `${r.client}: ${r.path}`).join("\n"), "Created MCP configurations");
|
|
251
|
+
_clack_prompts.outro("MCP setup complete! Your AI assistants can now use Bamboo CSS tools.");
|
|
252
|
+
return results;
|
|
253
|
+
}
|
|
254
|
+
//#endregion
|
|
255
|
+
exports.MCP_CLIENTS = MCP_CLIENTS;
|
|
256
|
+
exports.createMcpServer = createMcpServer;
|
|
257
|
+
exports.initMcpConfig = initMcpConfig;
|
|
258
|
+
exports.startMcpServer = startMcpServer;
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { Transport } from "@modelcontextprotocol/sdk/shared/transport.js";
|
|
3
|
+
import { BambooContext } from "@bamboocss/node";
|
|
4
|
+
|
|
5
|
+
//#region src/server.d.ts
|
|
6
|
+
interface CreateMcpServerOptions {
|
|
7
|
+
ctx: BambooContext;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Create an MCP server with all tools registered.
|
|
11
|
+
* This is separated from `startMcpServer` to allow testing with custom transports.
|
|
12
|
+
*/
|
|
13
|
+
declare function createMcpServer(options: CreateMcpServerOptions): McpServer;
|
|
14
|
+
interface StartMcpServerOptions {
|
|
15
|
+
cwd?: string;
|
|
16
|
+
config?: string;
|
|
17
|
+
silent?: boolean;
|
|
18
|
+
transport?: Transport;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Start the MCP server with the given options.
|
|
22
|
+
* By default, uses StdioServerTransport for CLI usage.
|
|
23
|
+
*/
|
|
24
|
+
declare function startMcpServer(options?: StartMcpServerOptions): Promise<McpServer>;
|
|
25
|
+
//#endregion
|
|
26
|
+
//#region src/clients.d.ts
|
|
27
|
+
type McpClient = 'claude' | 'cursor' | 'vscode' | 'windsurf' | 'codex';
|
|
28
|
+
interface McpClientConfig {
|
|
29
|
+
name: string;
|
|
30
|
+
label: string;
|
|
31
|
+
configPath: string;
|
|
32
|
+
configKey: 'mcpServers' | 'servers';
|
|
33
|
+
}
|
|
34
|
+
declare const MCP_CLIENTS: Record<McpClient, McpClientConfig>;
|
|
35
|
+
//#endregion
|
|
36
|
+
//#region src/init.d.ts
|
|
37
|
+
interface InitMcpConfigOptions {
|
|
38
|
+
cwd?: string;
|
|
39
|
+
clients?: McpClient[];
|
|
40
|
+
}
|
|
41
|
+
declare function initMcpConfig(options?: InitMcpConfigOptions): Promise<{
|
|
42
|
+
client: McpClient;
|
|
43
|
+
path: string;
|
|
44
|
+
created: boolean;
|
|
45
|
+
}[]>;
|
|
46
|
+
//#endregion
|
|
47
|
+
export { type CreateMcpServerOptions, type InitMcpConfigOptions, MCP_CLIENTS, type McpClient, type McpClientConfig, type StartMcpServerOptions, createMcpServer, initMcpConfig, startMcpServer };
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { BambooContext } from "@bamboocss/node";
|
|
3
|
+
import { Transport } from "@modelcontextprotocol/sdk/shared/transport.js";
|
|
4
|
+
|
|
5
|
+
//#region src/server.d.ts
|
|
6
|
+
interface CreateMcpServerOptions {
|
|
7
|
+
ctx: BambooContext;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Create an MCP server with all tools registered.
|
|
11
|
+
* This is separated from `startMcpServer` to allow testing with custom transports.
|
|
12
|
+
*/
|
|
13
|
+
declare function createMcpServer(options: CreateMcpServerOptions): McpServer;
|
|
14
|
+
interface StartMcpServerOptions {
|
|
15
|
+
cwd?: string;
|
|
16
|
+
config?: string;
|
|
17
|
+
silent?: boolean;
|
|
18
|
+
transport?: Transport;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Start the MCP server with the given options.
|
|
22
|
+
* By default, uses StdioServerTransport for CLI usage.
|
|
23
|
+
*/
|
|
24
|
+
declare function startMcpServer(options?: StartMcpServerOptions): Promise<McpServer>;
|
|
25
|
+
//#endregion
|
|
26
|
+
//#region src/clients.d.ts
|
|
27
|
+
type McpClient = 'claude' | 'cursor' | 'vscode' | 'windsurf' | 'codex';
|
|
28
|
+
interface McpClientConfig {
|
|
29
|
+
name: string;
|
|
30
|
+
label: string;
|
|
31
|
+
configPath: string;
|
|
32
|
+
configKey: 'mcpServers' | 'servers';
|
|
33
|
+
}
|
|
34
|
+
declare const MCP_CLIENTS: Record<McpClient, McpClientConfig>;
|
|
35
|
+
//#endregion
|
|
36
|
+
//#region src/init.d.ts
|
|
37
|
+
interface InitMcpConfigOptions {
|
|
38
|
+
cwd?: string;
|
|
39
|
+
clients?: McpClient[];
|
|
40
|
+
}
|
|
41
|
+
declare function initMcpConfig(options?: InitMcpConfigOptions): Promise<{
|
|
42
|
+
client: McpClient;
|
|
43
|
+
path: string;
|
|
44
|
+
created: boolean;
|
|
45
|
+
}[]>;
|
|
46
|
+
//#endregion
|
|
47
|
+
export { type CreateMcpServerOptions, type InitMcpConfigOptions, MCP_CLIENTS, type McpClient, type McpClientConfig, type StartMcpServerOptions, createMcpServer, initMcpConfig, startMcpServer };
|
package/dist/index.mjs
CHANGED
|
@@ -1,283 +1,230 @@
|
|
|
1
|
-
// src/server.ts
|
|
2
1
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
2
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
3
|
import { logger } from "@bamboocss/logger";
|
|
5
4
|
import { analyze, loadConfigAndCreateContext } from "@bamboocss/node";
|
|
6
5
|
import { TOKEN_CATEGORIES } from "@bamboocss/token-dictionary";
|
|
7
|
-
import { resolve } from "path";
|
|
6
|
+
import { dirname, resolve } from "path";
|
|
8
7
|
import * as z from "zod/v4";
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
import * as p from "@clack/prompts";
|
|
9
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
10
|
+
//#region src/server.ts
|
|
11
|
+
const tokenCategorySchema = z.enum(TOKEN_CATEGORIES).optional().describe("Filter by token category");
|
|
12
|
+
const json = (data) => ({ content: [{
|
|
13
|
+
type: "text",
|
|
14
|
+
text: JSON.stringify(data)
|
|
15
|
+
}] });
|
|
16
|
+
/**
|
|
17
|
+
* Create an MCP server with all tools registered.
|
|
18
|
+
* This is separated from `startMcpServer` to allow testing with custom transports.
|
|
19
|
+
*/
|
|
13
20
|
function createMcpServer(options) {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
server.registerTool(
|
|
92
|
-
"get_animation_styles",
|
|
93
|
-
{ description: "Get animation style compositions" },
|
|
94
|
-
async () => json(ctx.getSpecOfType("animation-styles"))
|
|
95
|
-
);
|
|
96
|
-
server.registerTool(
|
|
97
|
-
"get_color_palette",
|
|
98
|
-
{ description: "Get the color palette with all color values" },
|
|
99
|
-
async () => json(ctx.getSpecOfType("color-palette"))
|
|
100
|
-
);
|
|
101
|
-
server.registerTool(
|
|
102
|
-
"get_config",
|
|
103
|
-
{ description: "Get the resolved Bamboo CSS configuration including paths, JSX settings, and output options" },
|
|
104
|
-
async () => json(ctx.config)
|
|
105
|
-
);
|
|
106
|
-
server.registerTool(
|
|
107
|
-
"get_usage_report",
|
|
108
|
-
{
|
|
109
|
-
description: "Get a usage report of design tokens and recipes across the codebase. Shows which tokens/recipes are used, unused, or missing. Useful for auditing, cleanup, and identifying dead code.",
|
|
110
|
-
inputSchema: {
|
|
111
|
-
scope: z.enum(["all", "token", "recipe"]).optional().describe("Analysis scope: token, recipe, or all (default)")
|
|
112
|
-
}
|
|
113
|
-
},
|
|
114
|
-
async ({ scope }) => {
|
|
115
|
-
const result = analyze(ctx);
|
|
116
|
-
const includeTokens = !scope || scope === "all" || scope === "token";
|
|
117
|
-
const includeRecipes = !scope || scope === "all" || scope === "recipe";
|
|
118
|
-
const report = {};
|
|
119
|
-
if (includeTokens && !ctx.tokens.isEmpty) {
|
|
120
|
-
const tokenReport = result.getTokenReport();
|
|
121
|
-
report.tokens = tokenReport.report.getSummary();
|
|
122
|
-
}
|
|
123
|
-
if (includeRecipes && !ctx.recipes.isEmpty()) {
|
|
124
|
-
const recipeReport = result.getRecipeReport();
|
|
125
|
-
report.recipes = recipeReport.report;
|
|
126
|
-
}
|
|
127
|
-
return json(report);
|
|
128
|
-
}
|
|
129
|
-
);
|
|
130
|
-
return server;
|
|
21
|
+
const { ctx } = options;
|
|
22
|
+
const server = new McpServer({
|
|
23
|
+
name: "@bamboocss/mcp",
|
|
24
|
+
version: "1.0.0"
|
|
25
|
+
});
|
|
26
|
+
const recipeNames = ctx.recipes.keys;
|
|
27
|
+
const patternNames = ctx.patterns.keys;
|
|
28
|
+
const recipeNameSchema = recipeNames.length ? z.enum(recipeNames).optional().describe("Filter by recipe name") : z.string().optional().describe("Filter by recipe name");
|
|
29
|
+
const patternNameSchema = patternNames.length ? z.enum(patternNames).optional().describe("Filter by pattern name") : z.string().optional().describe("Filter by pattern name");
|
|
30
|
+
server.registerTool("get_tokens", {
|
|
31
|
+
description: "Get all design tokens with their values, CSS variables, and usage examples",
|
|
32
|
+
inputSchema: { category: tokenCategorySchema }
|
|
33
|
+
}, async ({ category }) => {
|
|
34
|
+
const spec = ctx.getSpecOfType("tokens");
|
|
35
|
+
const data = category ? spec.data.filter((group) => group.type === category) : spec.data;
|
|
36
|
+
return json({
|
|
37
|
+
type: spec.type,
|
|
38
|
+
data
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
server.registerTool("get_semantic_tokens", {
|
|
42
|
+
description: "Get semantic tokens with their conditional values (responsive, color modes)",
|
|
43
|
+
inputSchema: { category: tokenCategorySchema }
|
|
44
|
+
}, async ({ category }) => {
|
|
45
|
+
const spec = ctx.getSpecOfType("semantic-tokens");
|
|
46
|
+
const data = category ? spec.data.filter((group) => group.type === category) : spec.data;
|
|
47
|
+
return json({
|
|
48
|
+
type: spec.type,
|
|
49
|
+
data
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
server.registerTool("get_recipes", {
|
|
53
|
+
description: "Get component recipes with their variants, default values, and usage examples",
|
|
54
|
+
inputSchema: { name: recipeNameSchema }
|
|
55
|
+
}, async ({ name }) => {
|
|
56
|
+
const spec = ctx.getSpecOfType("recipes");
|
|
57
|
+
const data = name ? spec.data.filter((item) => item.name === name) : spec.data;
|
|
58
|
+
return json({
|
|
59
|
+
type: spec.type,
|
|
60
|
+
data
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
server.registerTool("get_patterns", {
|
|
64
|
+
description: "Get layout patterns with their properties and usage examples",
|
|
65
|
+
inputSchema: { name: patternNameSchema }
|
|
66
|
+
}, async ({ name }) => {
|
|
67
|
+
const spec = ctx.getSpecOfType("patterns");
|
|
68
|
+
const data = name ? spec.data.filter((item) => item.name === name) : spec.data;
|
|
69
|
+
return json({
|
|
70
|
+
type: spec.type,
|
|
71
|
+
data
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
server.registerTool("get_conditions", { description: "Get all conditions (breakpoints, pseudo-classes, color modes) and their CSS values" }, async () => json(ctx.getSpecOfType("conditions")));
|
|
75
|
+
server.registerTool("get_keyframes", { description: "Get keyframe animations defined in the theme" }, async () => json(ctx.getSpecOfType("keyframes")));
|
|
76
|
+
server.registerTool("get_text_styles", { description: "Get text style compositions for typography" }, async () => json(ctx.getSpecOfType("text-styles")));
|
|
77
|
+
server.registerTool("get_layer_styles", { description: "Get layer style compositions for visual styling" }, async () => json(ctx.getSpecOfType("layer-styles")));
|
|
78
|
+
server.registerTool("get_animation_styles", { description: "Get animation style compositions" }, async () => json(ctx.getSpecOfType("animation-styles")));
|
|
79
|
+
server.registerTool("get_color_palette", { description: "Get the color palette with all color values" }, async () => json(ctx.getSpecOfType("color-palette")));
|
|
80
|
+
server.registerTool("get_config", { description: "Get the resolved Bamboo CSS configuration including paths, JSX settings, and output options" }, async () => json(ctx.config));
|
|
81
|
+
server.registerTool("get_usage_report", {
|
|
82
|
+
description: "Get a usage report of design tokens and recipes across the codebase. Shows which tokens/recipes are used, unused, or missing. Useful for auditing, cleanup, and identifying dead code.",
|
|
83
|
+
inputSchema: { scope: z.enum([
|
|
84
|
+
"all",
|
|
85
|
+
"token",
|
|
86
|
+
"recipe"
|
|
87
|
+
]).optional().describe("Analysis scope: token, recipe, or all (default)") }
|
|
88
|
+
}, async ({ scope }) => {
|
|
89
|
+
const result = analyze(ctx);
|
|
90
|
+
const includeTokens = !scope || scope === "all" || scope === "token";
|
|
91
|
+
const includeRecipes = !scope || scope === "all" || scope === "recipe";
|
|
92
|
+
const report = {};
|
|
93
|
+
if (includeTokens && !ctx.tokens.isEmpty) report.tokens = result.getTokenReport().report.getSummary();
|
|
94
|
+
if (includeRecipes && !ctx.recipes.isEmpty()) report.recipes = result.getRecipeReport().report;
|
|
95
|
+
return json(report);
|
|
96
|
+
});
|
|
97
|
+
return server;
|
|
131
98
|
}
|
|
99
|
+
/**
|
|
100
|
+
* Start the MCP server with the given options.
|
|
101
|
+
* By default, uses StdioServerTransport for CLI usage.
|
|
102
|
+
*/
|
|
132
103
|
async function startMcpServer(options = {}) {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
console.error(`Working directory: ${resolvedCwd}`);
|
|
148
|
-
if (resolvedConfigPath) {
|
|
149
|
-
console.error(`Config path: ${resolvedConfigPath}`);
|
|
150
|
-
}
|
|
151
|
-
return server;
|
|
104
|
+
const { cwd = process.cwd(), config: configPath, silent = false, transport } = options;
|
|
105
|
+
if (silent) logger.level = "silent";
|
|
106
|
+
const resolvedCwd = resolve(cwd);
|
|
107
|
+
const resolvedConfigPath = configPath ? resolve(configPath) : void 0;
|
|
108
|
+
const server = createMcpServer({ ctx: await loadConfigAndCreateContext({
|
|
109
|
+
cwd: resolvedCwd,
|
|
110
|
+
configPath: resolvedConfigPath
|
|
111
|
+
}) });
|
|
112
|
+
const serverTransport = transport ?? new StdioServerTransport();
|
|
113
|
+
await server.connect(serverTransport);
|
|
114
|
+
console.error("Bamboo CSS MCP server started");
|
|
115
|
+
console.error(`Working directory: ${resolvedCwd}`);
|
|
116
|
+
if (resolvedConfigPath) console.error(`Config path: ${resolvedConfigPath}`);
|
|
117
|
+
return server;
|
|
152
118
|
}
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
codex: {
|
|
187
|
-
name: "codex",
|
|
188
|
-
label: "Codex (.codex/mcp.json)",
|
|
189
|
-
configPath: ".codex/mcp.json",
|
|
190
|
-
configKey: "mcpServers"
|
|
191
|
-
}
|
|
119
|
+
//#endregion
|
|
120
|
+
//#region src/clients.ts
|
|
121
|
+
const MCP_CLIENTS = {
|
|
122
|
+
claude: {
|
|
123
|
+
name: "claude",
|
|
124
|
+
label: "Claude (.mcp.json)",
|
|
125
|
+
configPath: ".mcp.json",
|
|
126
|
+
configKey: "mcpServers"
|
|
127
|
+
},
|
|
128
|
+
cursor: {
|
|
129
|
+
name: "cursor",
|
|
130
|
+
label: "Cursor (.cursor/mcp.json)",
|
|
131
|
+
configPath: ".cursor/mcp.json",
|
|
132
|
+
configKey: "mcpServers"
|
|
133
|
+
},
|
|
134
|
+
vscode: {
|
|
135
|
+
name: "vscode",
|
|
136
|
+
label: "VS Code (.vscode/mcp.json)",
|
|
137
|
+
configPath: ".vscode/mcp.json",
|
|
138
|
+
configKey: "servers"
|
|
139
|
+
},
|
|
140
|
+
windsurf: {
|
|
141
|
+
name: "windsurf",
|
|
142
|
+
label: "Windsurf (.windsurf/mcp.json)",
|
|
143
|
+
configPath: ".windsurf/mcp.json",
|
|
144
|
+
configKey: "mcpServers"
|
|
145
|
+
},
|
|
146
|
+
codex: {
|
|
147
|
+
name: "codex",
|
|
148
|
+
label: "Codex (.codex/mcp.json)",
|
|
149
|
+
configPath: ".codex/mcp.json",
|
|
150
|
+
configKey: "mcpServers"
|
|
151
|
+
}
|
|
192
152
|
};
|
|
193
|
-
|
|
153
|
+
const CLIENT_NAMES = Object.keys(MCP_CLIENTS);
|
|
194
154
|
function isValidClient(client) {
|
|
195
|
-
|
|
155
|
+
return CLIENT_NAMES.includes(client);
|
|
196
156
|
}
|
|
197
157
|
function getClientConfig(client) {
|
|
198
|
-
|
|
158
|
+
return MCP_CLIENTS[client];
|
|
199
159
|
}
|
|
200
160
|
function generateMcpConfig(clientConfig) {
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
[clientConfig.configKey]: {
|
|
207
|
-
bamboo: serverConfig
|
|
208
|
-
}
|
|
209
|
-
};
|
|
161
|
+
const serverConfig = {
|
|
162
|
+
command: "npx",
|
|
163
|
+
args: ["bamboo", "mcp"]
|
|
164
|
+
};
|
|
165
|
+
return { [clientConfig.configKey]: { bamboo: serverConfig } };
|
|
210
166
|
}
|
|
211
|
-
|
|
212
|
-
|
|
167
|
+
//#endregion
|
|
168
|
+
//#region src/init.ts
|
|
213
169
|
async function initMcpConfig(options = {}) {
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
});
|
|
273
|
-
}
|
|
274
|
-
p.note(results.map((r) => `${r.client}: ${r.path}`).join("\n"), "Created MCP configurations");
|
|
275
|
-
p.outro("MCP setup complete! Your AI assistants can now use Bamboo CSS tools.");
|
|
276
|
-
return results;
|
|
170
|
+
const { cwd = process.cwd() } = options;
|
|
171
|
+
let { clients } = options;
|
|
172
|
+
p.intro("Bamboo MCP Setup");
|
|
173
|
+
if (!clients || clients.length === 0) {
|
|
174
|
+
const selected = await p.multiselect({
|
|
175
|
+
message: "Select AI clients to configure:",
|
|
176
|
+
options: CLIENT_NAMES.map((client) => ({
|
|
177
|
+
value: client,
|
|
178
|
+
label: MCP_CLIENTS[client].label
|
|
179
|
+
})),
|
|
180
|
+
required: true
|
|
181
|
+
});
|
|
182
|
+
if (p.isCancel(selected)) {
|
|
183
|
+
p.cancel("Setup cancelled.");
|
|
184
|
+
process.exit(0);
|
|
185
|
+
}
|
|
186
|
+
clients = selected;
|
|
187
|
+
}
|
|
188
|
+
const validClients = clients.filter((client) => {
|
|
189
|
+
if (!isValidClient(client)) {
|
|
190
|
+
logger.warn("mcp:init", `Unknown client: ${client}`);
|
|
191
|
+
return false;
|
|
192
|
+
}
|
|
193
|
+
return true;
|
|
194
|
+
});
|
|
195
|
+
if (validClients.length === 0) {
|
|
196
|
+
p.cancel("No valid clients selected.");
|
|
197
|
+
process.exit(1);
|
|
198
|
+
}
|
|
199
|
+
const results = [];
|
|
200
|
+
for (const client of validClients) {
|
|
201
|
+
const clientConfig = getClientConfig(client);
|
|
202
|
+
const configPath = resolve(cwd, clientConfig.configPath);
|
|
203
|
+
const configDir = dirname(configPath);
|
|
204
|
+
if (!existsSync(configDir)) mkdirSync(configDir, { recursive: true });
|
|
205
|
+
const newConfig = generateMcpConfig(clientConfig);
|
|
206
|
+
let finalConfig = newConfig;
|
|
207
|
+
if (existsSync(configPath)) try {
|
|
208
|
+
const existingContent = readFileSync(configPath, "utf-8");
|
|
209
|
+
const existingConfig = JSON.parse(existingContent);
|
|
210
|
+
finalConfig = {
|
|
211
|
+
...existingConfig,
|
|
212
|
+
[clientConfig.configKey]: {
|
|
213
|
+
...existingConfig[clientConfig.configKey],
|
|
214
|
+
...newConfig[clientConfig.configKey]
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
} catch {}
|
|
218
|
+
writeFileSync(configPath, JSON.stringify(finalConfig, null, 2));
|
|
219
|
+
results.push({
|
|
220
|
+
client,
|
|
221
|
+
path: clientConfig.configPath,
|
|
222
|
+
created: true
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
p.note(results.map((r) => `${r.client}: ${r.path}`).join("\n"), "Created MCP configurations");
|
|
226
|
+
p.outro("MCP setup complete! Your AI assistants can now use Bamboo CSS tools.");
|
|
227
|
+
return results;
|
|
277
228
|
}
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
createMcpServer,
|
|
281
|
-
initMcpConfig,
|
|
282
|
-
startMcpServer
|
|
283
|
-
};
|
|
229
|
+
//#endregion
|
|
230
|
+
export { MCP_CLIENTS, createMcpServer, initMcpConfig, startMcpServer };
|
package/package.json
CHANGED
|
@@ -1,27 +1,27 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bamboocss/mcp",
|
|
3
|
-
"version": "1.11.
|
|
3
|
+
"version": "1.11.2",
|
|
4
4
|
"description": "MCP server for Bamboo CSS AI assistants",
|
|
5
5
|
"homepage": "https://bamboo-css.com",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"author": "Segun Adebayo <joseshegs@gmail.com>",
|
|
8
8
|
"repository": {
|
|
9
9
|
"type": "git",
|
|
10
|
-
"url": "git+https://github.com/
|
|
10
|
+
"url": "git+https://github.com/bamboocss/bamboo.git",
|
|
11
11
|
"directory": "packages/mcp"
|
|
12
12
|
},
|
|
13
13
|
"files": [
|
|
14
14
|
"dist"
|
|
15
15
|
],
|
|
16
16
|
"sideEffects": false,
|
|
17
|
-
"main": "dist/index.
|
|
17
|
+
"main": "dist/index.cjs",
|
|
18
18
|
"module": "dist/index.mjs",
|
|
19
|
-
"types": "dist/index.d.
|
|
19
|
+
"types": "dist/index.d.cts",
|
|
20
20
|
"exports": {
|
|
21
21
|
".": {
|
|
22
22
|
"source": "./src/index.ts",
|
|
23
|
-
"types": "./dist/index.d.
|
|
24
|
-
"require": "./dist/index.
|
|
23
|
+
"types": "./dist/index.d.cts",
|
|
24
|
+
"require": "./dist/index.cjs",
|
|
25
25
|
"import": {
|
|
26
26
|
"types": "./dist/index.d.mts",
|
|
27
27
|
"default": "./dist/index.mjs"
|
|
@@ -36,14 +36,14 @@
|
|
|
36
36
|
"@clack/prompts": "0.11.0",
|
|
37
37
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
38
38
|
"zod": "^4.0.0",
|
|
39
|
-
"@bamboocss/logger": "1.11.
|
|
40
|
-
"@bamboocss/
|
|
41
|
-
"@bamboocss/
|
|
42
|
-
"@bamboocss/types": "1.11.
|
|
39
|
+
"@bamboocss/logger": "1.11.2",
|
|
40
|
+
"@bamboocss/node": "1.11.2",
|
|
41
|
+
"@bamboocss/token-dictionary": "1.11.2",
|
|
42
|
+
"@bamboocss/types": "1.11.2"
|
|
43
43
|
},
|
|
44
44
|
"scripts": {
|
|
45
|
-
"build": "
|
|
46
|
-
"build-fast": "
|
|
45
|
+
"build": "tsdown src/index.ts --format=esm,cjs",
|
|
46
|
+
"build-fast": "tsdown --dts=false src/index.ts --format=esm,cjs",
|
|
47
47
|
"dev": "pnpm build-fast --watch"
|
|
48
48
|
}
|
|
49
49
|
}
|
package/dist/index.js
DELETED
|
@@ -1,323 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __create = Object.create;
|
|
3
|
-
var __defProp = Object.defineProperty;
|
|
4
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
-
var __export = (target, all) => {
|
|
9
|
-
for (var name in all)
|
|
10
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
-
};
|
|
12
|
-
var __copyProps = (to, from, except, desc) => {
|
|
13
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
-
for (let key of __getOwnPropNames(from))
|
|
15
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
-
}
|
|
18
|
-
return to;
|
|
19
|
-
};
|
|
20
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
-
mod
|
|
27
|
-
));
|
|
28
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
-
|
|
30
|
-
// src/index.ts
|
|
31
|
-
var index_exports = {};
|
|
32
|
-
__export(index_exports, {
|
|
33
|
-
MCP_CLIENTS: () => MCP_CLIENTS,
|
|
34
|
-
createMcpServer: () => createMcpServer,
|
|
35
|
-
initMcpConfig: () => initMcpConfig,
|
|
36
|
-
startMcpServer: () => startMcpServer
|
|
37
|
-
});
|
|
38
|
-
module.exports = __toCommonJS(index_exports);
|
|
39
|
-
|
|
40
|
-
// src/server.ts
|
|
41
|
-
var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
42
|
-
var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
43
|
-
var import_logger = require("@bamboocss/logger");
|
|
44
|
-
var import_node = require("@bamboocss/node");
|
|
45
|
-
var import_token_dictionary = require("@bamboocss/token-dictionary");
|
|
46
|
-
var import_path = require("path");
|
|
47
|
-
var z = __toESM(require("zod/v4"));
|
|
48
|
-
var tokenCategorySchema = z.enum(import_token_dictionary.TOKEN_CATEGORIES).optional().describe("Filter by token category");
|
|
49
|
-
var json = (data) => ({
|
|
50
|
-
content: [{ type: "text", text: JSON.stringify(data) }]
|
|
51
|
-
});
|
|
52
|
-
function createMcpServer(options) {
|
|
53
|
-
const { ctx } = options;
|
|
54
|
-
const server = new import_mcp.McpServer({
|
|
55
|
-
name: "@bamboocss/mcp",
|
|
56
|
-
version: "1.0.0"
|
|
57
|
-
});
|
|
58
|
-
const recipeNames = ctx.recipes.keys;
|
|
59
|
-
const patternNames = ctx.patterns.keys;
|
|
60
|
-
const recipeNameSchema = recipeNames.length ? z.enum(recipeNames).optional().describe("Filter by recipe name") : z.string().optional().describe("Filter by recipe name");
|
|
61
|
-
const patternNameSchema = patternNames.length ? z.enum(patternNames).optional().describe("Filter by pattern name") : z.string().optional().describe("Filter by pattern name");
|
|
62
|
-
server.registerTool(
|
|
63
|
-
"get_tokens",
|
|
64
|
-
{
|
|
65
|
-
description: "Get all design tokens with their values, CSS variables, and usage examples",
|
|
66
|
-
inputSchema: { category: tokenCategorySchema }
|
|
67
|
-
},
|
|
68
|
-
async ({ category }) => {
|
|
69
|
-
const spec = ctx.getSpecOfType("tokens");
|
|
70
|
-
const data = category ? spec.data.filter((group) => group.type === category) : spec.data;
|
|
71
|
-
return json({ type: spec.type, data });
|
|
72
|
-
}
|
|
73
|
-
);
|
|
74
|
-
server.registerTool(
|
|
75
|
-
"get_semantic_tokens",
|
|
76
|
-
{
|
|
77
|
-
description: "Get semantic tokens with their conditional values (responsive, color modes)",
|
|
78
|
-
inputSchema: { category: tokenCategorySchema }
|
|
79
|
-
},
|
|
80
|
-
async ({ category }) => {
|
|
81
|
-
const spec = ctx.getSpecOfType("semantic-tokens");
|
|
82
|
-
const data = category ? spec.data.filter((group) => group.type === category) : spec.data;
|
|
83
|
-
return json({ type: spec.type, data });
|
|
84
|
-
}
|
|
85
|
-
);
|
|
86
|
-
server.registerTool(
|
|
87
|
-
"get_recipes",
|
|
88
|
-
{
|
|
89
|
-
description: "Get component recipes with their variants, default values, and usage examples",
|
|
90
|
-
inputSchema: { name: recipeNameSchema }
|
|
91
|
-
},
|
|
92
|
-
async ({ name }) => {
|
|
93
|
-
const spec = ctx.getSpecOfType("recipes");
|
|
94
|
-
const data = name ? spec.data.filter((item) => item.name === name) : spec.data;
|
|
95
|
-
return json({ type: spec.type, data });
|
|
96
|
-
}
|
|
97
|
-
);
|
|
98
|
-
server.registerTool(
|
|
99
|
-
"get_patterns",
|
|
100
|
-
{
|
|
101
|
-
description: "Get layout patterns with their properties and usage examples",
|
|
102
|
-
inputSchema: { name: patternNameSchema }
|
|
103
|
-
},
|
|
104
|
-
async ({ name }) => {
|
|
105
|
-
const spec = ctx.getSpecOfType("patterns");
|
|
106
|
-
const data = name ? spec.data.filter((item) => item.name === name) : spec.data;
|
|
107
|
-
return json({ type: spec.type, data });
|
|
108
|
-
}
|
|
109
|
-
);
|
|
110
|
-
server.registerTool(
|
|
111
|
-
"get_conditions",
|
|
112
|
-
{ description: "Get all conditions (breakpoints, pseudo-classes, color modes) and their CSS values" },
|
|
113
|
-
async () => json(ctx.getSpecOfType("conditions"))
|
|
114
|
-
);
|
|
115
|
-
server.registerTool(
|
|
116
|
-
"get_keyframes",
|
|
117
|
-
{ description: "Get keyframe animations defined in the theme" },
|
|
118
|
-
async () => json(ctx.getSpecOfType("keyframes"))
|
|
119
|
-
);
|
|
120
|
-
server.registerTool(
|
|
121
|
-
"get_text_styles",
|
|
122
|
-
{ description: "Get text style compositions for typography" },
|
|
123
|
-
async () => json(ctx.getSpecOfType("text-styles"))
|
|
124
|
-
);
|
|
125
|
-
server.registerTool(
|
|
126
|
-
"get_layer_styles",
|
|
127
|
-
{ description: "Get layer style compositions for visual styling" },
|
|
128
|
-
async () => json(ctx.getSpecOfType("layer-styles"))
|
|
129
|
-
);
|
|
130
|
-
server.registerTool(
|
|
131
|
-
"get_animation_styles",
|
|
132
|
-
{ description: "Get animation style compositions" },
|
|
133
|
-
async () => json(ctx.getSpecOfType("animation-styles"))
|
|
134
|
-
);
|
|
135
|
-
server.registerTool(
|
|
136
|
-
"get_color_palette",
|
|
137
|
-
{ description: "Get the color palette with all color values" },
|
|
138
|
-
async () => json(ctx.getSpecOfType("color-palette"))
|
|
139
|
-
);
|
|
140
|
-
server.registerTool(
|
|
141
|
-
"get_config",
|
|
142
|
-
{ description: "Get the resolved Bamboo CSS configuration including paths, JSX settings, and output options" },
|
|
143
|
-
async () => json(ctx.config)
|
|
144
|
-
);
|
|
145
|
-
server.registerTool(
|
|
146
|
-
"get_usage_report",
|
|
147
|
-
{
|
|
148
|
-
description: "Get a usage report of design tokens and recipes across the codebase. Shows which tokens/recipes are used, unused, or missing. Useful for auditing, cleanup, and identifying dead code.",
|
|
149
|
-
inputSchema: {
|
|
150
|
-
scope: z.enum(["all", "token", "recipe"]).optional().describe("Analysis scope: token, recipe, or all (default)")
|
|
151
|
-
}
|
|
152
|
-
},
|
|
153
|
-
async ({ scope }) => {
|
|
154
|
-
const result = (0, import_node.analyze)(ctx);
|
|
155
|
-
const includeTokens = !scope || scope === "all" || scope === "token";
|
|
156
|
-
const includeRecipes = !scope || scope === "all" || scope === "recipe";
|
|
157
|
-
const report = {};
|
|
158
|
-
if (includeTokens && !ctx.tokens.isEmpty) {
|
|
159
|
-
const tokenReport = result.getTokenReport();
|
|
160
|
-
report.tokens = tokenReport.report.getSummary();
|
|
161
|
-
}
|
|
162
|
-
if (includeRecipes && !ctx.recipes.isEmpty()) {
|
|
163
|
-
const recipeReport = result.getRecipeReport();
|
|
164
|
-
report.recipes = recipeReport.report;
|
|
165
|
-
}
|
|
166
|
-
return json(report);
|
|
167
|
-
}
|
|
168
|
-
);
|
|
169
|
-
return server;
|
|
170
|
-
}
|
|
171
|
-
async function startMcpServer(options = {}) {
|
|
172
|
-
const { cwd = process.cwd(), config: configPath, silent = false, transport } = options;
|
|
173
|
-
if (silent) {
|
|
174
|
-
import_logger.logger.level = "silent";
|
|
175
|
-
}
|
|
176
|
-
const resolvedCwd = (0, import_path.resolve)(cwd);
|
|
177
|
-
const resolvedConfigPath = configPath ? (0, import_path.resolve)(configPath) : void 0;
|
|
178
|
-
const ctx = await (0, import_node.loadConfigAndCreateContext)({
|
|
179
|
-
cwd: resolvedCwd,
|
|
180
|
-
configPath: resolvedConfigPath
|
|
181
|
-
});
|
|
182
|
-
const server = createMcpServer({ ctx });
|
|
183
|
-
const serverTransport = transport ?? new import_stdio.StdioServerTransport();
|
|
184
|
-
await server.connect(serverTransport);
|
|
185
|
-
console.error("Bamboo CSS MCP server started");
|
|
186
|
-
console.error(`Working directory: ${resolvedCwd}`);
|
|
187
|
-
if (resolvedConfigPath) {
|
|
188
|
-
console.error(`Config path: ${resolvedConfigPath}`);
|
|
189
|
-
}
|
|
190
|
-
return server;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
// src/init.ts
|
|
194
|
-
var p = __toESM(require("@clack/prompts"));
|
|
195
|
-
var import_logger2 = require("@bamboocss/logger");
|
|
196
|
-
var import_fs = require("fs");
|
|
197
|
-
var import_path2 = require("path");
|
|
198
|
-
|
|
199
|
-
// src/clients.ts
|
|
200
|
-
var MCP_CLIENTS = {
|
|
201
|
-
claude: {
|
|
202
|
-
name: "claude",
|
|
203
|
-
label: "Claude (.mcp.json)",
|
|
204
|
-
configPath: ".mcp.json",
|
|
205
|
-
configKey: "mcpServers"
|
|
206
|
-
},
|
|
207
|
-
cursor: {
|
|
208
|
-
name: "cursor",
|
|
209
|
-
label: "Cursor (.cursor/mcp.json)",
|
|
210
|
-
configPath: ".cursor/mcp.json",
|
|
211
|
-
configKey: "mcpServers"
|
|
212
|
-
},
|
|
213
|
-
vscode: {
|
|
214
|
-
name: "vscode",
|
|
215
|
-
label: "VS Code (.vscode/mcp.json)",
|
|
216
|
-
configPath: ".vscode/mcp.json",
|
|
217
|
-
configKey: "servers"
|
|
218
|
-
},
|
|
219
|
-
windsurf: {
|
|
220
|
-
name: "windsurf",
|
|
221
|
-
label: "Windsurf (.windsurf/mcp.json)",
|
|
222
|
-
configPath: ".windsurf/mcp.json",
|
|
223
|
-
configKey: "mcpServers"
|
|
224
|
-
},
|
|
225
|
-
codex: {
|
|
226
|
-
name: "codex",
|
|
227
|
-
label: "Codex (.codex/mcp.json)",
|
|
228
|
-
configPath: ".codex/mcp.json",
|
|
229
|
-
configKey: "mcpServers"
|
|
230
|
-
}
|
|
231
|
-
};
|
|
232
|
-
var CLIENT_NAMES = Object.keys(MCP_CLIENTS);
|
|
233
|
-
function isValidClient(client) {
|
|
234
|
-
return CLIENT_NAMES.includes(client);
|
|
235
|
-
}
|
|
236
|
-
function getClientConfig(client) {
|
|
237
|
-
return MCP_CLIENTS[client];
|
|
238
|
-
}
|
|
239
|
-
function generateMcpConfig(clientConfig) {
|
|
240
|
-
const serverConfig = {
|
|
241
|
-
command: "npx",
|
|
242
|
-
args: ["bamboo", "mcp"]
|
|
243
|
-
};
|
|
244
|
-
return {
|
|
245
|
-
[clientConfig.configKey]: {
|
|
246
|
-
bamboo: serverConfig
|
|
247
|
-
}
|
|
248
|
-
};
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
// src/init.ts
|
|
252
|
-
async function initMcpConfig(options = {}) {
|
|
253
|
-
const { cwd = process.cwd() } = options;
|
|
254
|
-
let { clients } = options;
|
|
255
|
-
p.intro("Bamboo MCP Setup");
|
|
256
|
-
if (!clients || clients.length === 0) {
|
|
257
|
-
const selected = await p.multiselect({
|
|
258
|
-
message: "Select AI clients to configure:",
|
|
259
|
-
options: CLIENT_NAMES.map((client) => ({
|
|
260
|
-
value: client,
|
|
261
|
-
label: MCP_CLIENTS[client].label
|
|
262
|
-
})),
|
|
263
|
-
required: true
|
|
264
|
-
});
|
|
265
|
-
if (p.isCancel(selected)) {
|
|
266
|
-
p.cancel("Setup cancelled.");
|
|
267
|
-
process.exit(0);
|
|
268
|
-
}
|
|
269
|
-
clients = selected;
|
|
270
|
-
}
|
|
271
|
-
const validClients = clients.filter((client) => {
|
|
272
|
-
if (!isValidClient(client)) {
|
|
273
|
-
import_logger2.logger.warn("mcp:init", `Unknown client: ${client}`);
|
|
274
|
-
return false;
|
|
275
|
-
}
|
|
276
|
-
return true;
|
|
277
|
-
});
|
|
278
|
-
if (validClients.length === 0) {
|
|
279
|
-
p.cancel("No valid clients selected.");
|
|
280
|
-
process.exit(1);
|
|
281
|
-
}
|
|
282
|
-
const results = [];
|
|
283
|
-
for (const client of validClients) {
|
|
284
|
-
const clientConfig = getClientConfig(client);
|
|
285
|
-
const configPath = (0, import_path2.resolve)(cwd, clientConfig.configPath);
|
|
286
|
-
const configDir = (0, import_path2.dirname)(configPath);
|
|
287
|
-
if (!(0, import_fs.existsSync)(configDir)) {
|
|
288
|
-
(0, import_fs.mkdirSync)(configDir, { recursive: true });
|
|
289
|
-
}
|
|
290
|
-
const newConfig = generateMcpConfig(clientConfig);
|
|
291
|
-
let finalConfig = newConfig;
|
|
292
|
-
if ((0, import_fs.existsSync)(configPath)) {
|
|
293
|
-
try {
|
|
294
|
-
const existingContent = (0, import_fs.readFileSync)(configPath, "utf-8");
|
|
295
|
-
const existingConfig = JSON.parse(existingContent);
|
|
296
|
-
finalConfig = {
|
|
297
|
-
...existingConfig,
|
|
298
|
-
[clientConfig.configKey]: {
|
|
299
|
-
...existingConfig[clientConfig.configKey],
|
|
300
|
-
...newConfig[clientConfig.configKey]
|
|
301
|
-
}
|
|
302
|
-
};
|
|
303
|
-
} catch {
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
(0, import_fs.writeFileSync)(configPath, JSON.stringify(finalConfig, null, 2));
|
|
307
|
-
results.push({
|
|
308
|
-
client,
|
|
309
|
-
path: clientConfig.configPath,
|
|
310
|
-
created: true
|
|
311
|
-
});
|
|
312
|
-
}
|
|
313
|
-
p.note(results.map((r) => `${r.client}: ${r.path}`).join("\n"), "Created MCP configurations");
|
|
314
|
-
p.outro("MCP setup complete! Your AI assistants can now use Bamboo CSS tools.");
|
|
315
|
-
return results;
|
|
316
|
-
}
|
|
317
|
-
// Annotate the CommonJS export names for ESM import in node:
|
|
318
|
-
0 && (module.exports = {
|
|
319
|
-
MCP_CLIENTS,
|
|
320
|
-
createMcpServer,
|
|
321
|
-
initMcpConfig,
|
|
322
|
-
startMcpServer
|
|
323
|
-
});
|