Skip to content

Commit b924bb4

Browse files
claudemrsimpson
authored andcommitted
fix: correct mcp.json format and Claude Code agent config generation
- Fix getDefaultMcpConfig() in both config-generator.ts and skill-generator.ts to use separate command/args fields instead of a single command array, which Claude Code requires (resolves issue #235) - Change ClaudeConfigGenerator to generate .claude/agents/vibe.md (proper Claude Code agent config with YAML frontmatter) instead of root CLAUDE.md - Move Claude Code settings from root settings.json to .claude/settings.json - Update tests to reflect the corrected output format and file locations https://claude.ai/code/session_01GHdfjCzUWKxo1CTQibFQ3i
1 parent 57fbed9 commit b924bb4

4 files changed

Lines changed: 61 additions & 25 deletions

File tree

packages/cli/src/config-generator.ts

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -130,11 +130,19 @@ abstract class ConfigGenerator {
130130
protected getDefaultMcpConfig(): object {
131131
const isWindows = process.platform.startsWith('win');
132132

133+
if (isWindows) {
134+
return {
135+
workflows: {
136+
command: 'cmd',
137+
args: ['/c', 'npx', '@codemcp/workflows-server@latest'],
138+
},
139+
};
140+
}
141+
133142
return {
134143
workflows: {
135-
command: isWindows
136-
? ['cmd', '/c', 'npx', '@codemcp/workflows-server@latest']
137-
: ['npx', '@codemcp/workflows-server@latest'],
144+
command: 'npx',
145+
args: ['@codemcp/workflows-server@latest'],
138146
},
139147
};
140148
}
@@ -215,17 +223,26 @@ class AmazonQConfigGenerator extends ConfigGenerator {
215223

216224
/**
217225
* Claude Code Configuration Generator
218-
* Generates multiple files: CLAUDE.md, .mcp.json, settings.json
226+
* Generates multiple files: .claude/agents/vibe.md, .mcp.json, .claude/settings.json
219227
* Merges with existing configuration instead of overwriting
220228
*/
221229
class ClaudeConfigGenerator extends ConfigGenerator {
222230
async generate(outputDir: string): Promise<void> {
223231
const systemPrompt = this.getSystemPrompt();
224232
const mcpServers = this.getDefaultMcpConfig();
225233

226-
// Generate CLAUDE.md (system prompt) - always overwrite as it's generated content
227-
const claudeMdPath = join(outputDir, 'CLAUDE.md');
228-
await this.writeFile(claudeMdPath, systemPrompt);
234+
// Generate .claude/agents/vibe.md (agent configuration) - always overwrite as it's generated content
235+
const claudeDir = join(outputDir, '.claude');
236+
const agentsDir = join(claudeDir, 'agents');
237+
await mkdir(agentsDir, { recursive: true });
238+
const agentContent = `---
239+
name: Responsible Vibe
240+
description: AI assistant that helps users develop software features using structured development workflows.
241+
---
242+
243+
${systemPrompt}`;
244+
const agentPath = join(agentsDir, 'vibe.md');
245+
await this.writeFile(agentPath, agentContent);
229246

230247
// Generate .mcp.json (MCP server configuration) - merge with existing
231248
const mcpConfig: Record<string, unknown> = {
@@ -238,7 +255,7 @@ class ClaudeConfigGenerator extends ConfigGenerator {
238255
);
239256
await this.writeFile(mcpJsonPath, JSON.stringify(finalMcpConfig, null, 2));
240257

241-
// Generate settings.json (permissions and security) - merge with existing
258+
// Generate .claude/settings.json (permissions and security) - merge with existing
242259
const settings: Record<string, unknown> = {
243260
permissions: {
244261
allow: [
@@ -254,7 +271,7 @@ class ClaudeConfigGenerator extends ConfigGenerator {
254271
deny: ['Read(./.env)', 'Read(./.env.*)', 'Read(./secrets/**)'],
255272
},
256273
};
257-
const settingsPath = join(outputDir, 'settings.json');
274+
const settingsPath = join(claudeDir, 'settings.json');
258275
const finalSettings = await this.mergeWithExistingConfig(
259276
settingsPath,
260277
settings

packages/cli/src/skill-generator.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,11 +78,19 @@ export abstract class SkillGenerator {
7878
protected getDefaultMcpConfig(): object {
7979
const isWindows = process.platform.startsWith('win');
8080

81+
if (isWindows) {
82+
return {
83+
workflows: {
84+
command: 'cmd',
85+
args: ['/c', 'npx', '@codemcp/workflows-server@latest'],
86+
},
87+
};
88+
}
89+
8190
return {
8291
workflows: {
83-
command: isWindows
84-
? ['cmd', '/c', 'npx', '@codemcp/workflows-server@latest']
85-
: ['npx', '@codemcp/workflows-server@latest'],
92+
command: 'npx',
93+
args: ['@codemcp/workflows-server@latest'],
8694
},
8795
};
8896
}

packages/cli/test/config-generator.test.ts

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -46,20 +46,27 @@ describe('Config Generator', () => {
4646
it('should generate Claude configuration files', async () => {
4747
await generateConfig('claude', tempDir);
4848

49-
// Check CLAUDE.md
50-
const claudeMdPath = join(tempDir, 'CLAUDE.md');
51-
expect(existsSync(claudeMdPath)).toBe(true);
52-
const claudeContent = readFileSync(claudeMdPath, 'utf-8');
53-
expect(claudeContent).toContain('whats_next');
49+
// Check .claude/agents/vibe.md (agent config)
50+
const agentPath = join(tempDir, '.claude', 'agents', 'vibe.md');
51+
expect(existsSync(agentPath)).toBe(true);
52+
const agentContent = readFileSync(agentPath, 'utf-8');
53+
expect(agentContent).toContain('---');
54+
expect(agentContent).toContain('name: Responsible Vibe');
55+
expect(agentContent).toContain('description:');
56+
expect(agentContent).toContain('whats_next');
5457

5558
// Check .mcp.json
5659
const mcpJsonPath = join(tempDir, '.mcp.json');
5760
expect(existsSync(mcpJsonPath)).toBe(true);
5861
const mcpConfig = JSON.parse(readFileSync(mcpJsonPath, 'utf-8'));
5962
expect(mcpConfig.mcpServers).toBeDefined();
63+
expect(mcpConfig.mcpServers['workflows'].command).toBe('npx');
64+
expect(mcpConfig.mcpServers['workflows'].args).toContain(
65+
'@codemcp/workflows-server@latest'
66+
);
6067

61-
// Check settings.json
62-
const settingsPath = join(tempDir, 'settings.json');
68+
// Check .claude/settings.json
69+
const settingsPath = join(tempDir, '.claude', 'settings.json');
6370
expect(existsSync(settingsPath)).toBe(true);
6471
const settings = JSON.parse(readFileSync(settingsPath, 'utf-8'));
6572
expect(settings.permissions.allow).toContain('MCP(workflows:whats_next)');
@@ -246,8 +253,10 @@ describe('Config Generator', () => {
246253
expect(mcpConfig.mcpServers['workflows']).toBeDefined();
247254
});
248255

249-
it('should merge settings.json with existing permissions', async () => {
250-
const settingsPath = join(tempDir, 'settings.json');
256+
it('should merge .claude/settings.json with existing permissions', async () => {
257+
const claudeDir = join(tempDir, '.claude');
258+
mkdirSync(claudeDir, { recursive: true });
259+
const settingsPath = join(claudeDir, 'settings.json');
251260

252261
// Create existing settings
253262
const existingSettings = {

packages/cli/test/skill-generator.test.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -94,9 +94,11 @@ describe('Skill Generator', () => {
9494

9595
expect(config.mcpServers).toBeDefined();
9696
expect(config.mcpServers['workflows']).toBeDefined();
97-
// command should be an array
98-
expect(Array.isArray(config.mcpServers['workflows'].command)).toBe(true);
99-
expect(config.mcpServers['workflows'].command).toContain('npx');
97+
// command should be a string, args should be an array
98+
expect(config.mcpServers['workflows'].command).toBe('npx');
99+
expect(config.mcpServers['workflows'].args).toContain(
100+
'@codemcp/workflows-server@latest'
101+
);
100102
});
101103
});
102104

@@ -146,7 +148,7 @@ describe('Skill Generator', () => {
146148
expect(config.mcp).toBeDefined();
147149
expect(config.mcp['workflows']).toBeDefined();
148150
expect(config.mcp['workflows'].type).toBe('local');
149-
// command should be an array
151+
// OpenCode uses command as array
150152
expect(Array.isArray(config.mcp['workflows'].command)).toBe(true);
151153
expect(config.mcp['workflows'].command).toContain('npx');
152154
expect(config.mcp['workflows'].command).toContain(

0 commit comments

Comments
 (0)