Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitd22167a

Browse files
authored
Merge pull request#270 from savinmikhail/feature/multi-client-config-support
Multi-Client MCP Configuration Support
2 parentsc387607 +8db6a25 commitd22167a

File tree

11 files changed

+542
-71
lines changed

11 files changed

+542
-71
lines changed

‎README.md‎

Lines changed: 57 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -124,11 +124,11 @@ what contexts might be useful.
124124
ctx generate
125125
```
126126

127-
3. Use with your favorite AI:
128-
129-
-Copy the generated markdown files to your AI chat
130-
-Or use the built-in MCP server with Claude Desktop
131-
-Or process locally with open-source models
127+
3. Use with your favorite AI:
128+
129+
-Copy the generated markdown files to your AI chat
130+
-Or use the built-in MCP server withyour MCP client (e.g.,Claude Desktop, Cursor, Continue, Windsurf)
131+
-Or process locally with open-source models
132132

133133
## Real-World Use Cases
134134

@@ -220,58 +220,58 @@ Configuration → Sources → Filters → Modifiers → Output
220220
- **Modifiers**: How to transform content (extract signatures, remove comments)
221221
- **Output**: Structured markdown ready for AI consumption
222222

223-
## Connect toClaude Desktop (Optional)
224-
225-
For a more seamless experience, you can connectContext Generator directlytoClaude AIusing the MCP server.
226-
227-
```bash
228-
#Auto-detect OS andgenerate configuration
229-
ctx mcp:config
230-
```
231-
232-
This command:
233-
234-
-🔍**Auto-detects your OS** (Windows, Linux, macOS, WSL)
235-
-🎯 **Generates the right config** for your environment
236-
-📋 **Provides copy-paste ready** JSONforClaude Desktop
237-
-🧭 **Includes setup instructions** and troubleshooting tips
238-
239-
**Global Registry Mode** (recommended for multiple projects):
240-
241-
```json
242-
{
243-
"mcpServers":{
244-
"ctx": {
245-
"command":"ctx",
246-
"args":[
247-
"server"
248-
]
249-
}
250-
}
251-
}
252-
```
253-
254-
If you prefer manual setup, point the MCP client to the Context Generator server:
255-
256-
```json
257-
{
258-
"mcpServers":{
259-
"ctx": {
260-
"command":"ctx",
261-
"args":[
262-
"server",
263-
"-c",
264-
"/path/to/project"
265-
]
266-
}
267-
}
268-
}
269-
```
270-
271-
> **Note:** Read more about [MCP Server](https://docs.ctxgithub.com/mcp/#setting-up) for detailed setup
272-
> instructions and troubleshooting.
273-
274-
Now you canaskClaude questions about your codebase without manually uploading context files!
223+
## Connect toan MCP Client (Optional)
224+
225+
For a more seamless experience, you can connectCTXtoany MCP-compatible clientusing the built-in MCP server.
226+
227+
```bash
228+
#Interactive setup:detect OS andinstall config for your client
229+
ctx mcp:config -i
230+
```
231+
232+
This command:
233+
234+
-🔍 Auto-detects your OS (Windows, Linux, macOS, WSL)
235+
-🧩 Lets you choose your MCP client (e.g., Claude Desktop, Cursor, Continue, Windsurf)
236+
-🎯 Generates and optionally installs the correct configforyour environment
237+
-📋 Provides copy‑paste ready JSON if you prefer manual setup
238+
-🧭 Includes setup instructions and troubleshooting tips
239+
240+
**Global Registry Mode** (recommended for multiple projects/clients):
241+
242+
```json
243+
{
244+
"mcpServers": {
245+
"ctx":{
246+
"command":"ctx",
247+
"args": [
248+
"server"
249+
]
250+
}
251+
}
252+
}
253+
```
254+
255+
If you prefer manual setup, point your MCP client to the CTX server:
256+
257+
```json
258+
{
259+
"mcpServers": {
260+
"ctx":{
261+
"command":"ctx",
262+
"args": [
263+
"server",
264+
"-c",
265+
"/path/to/project"
266+
]
267+
}
268+
}
269+
}
270+
```
271+
272+
>Note: Read more about the [MCP server](https://docs.ctxgithub.com/mcp/#setting-up) for detailed setupinstructions and troubleshooting. Specific config file locations vary by client.
273+
274+
Now you canuse your preferred MCP client (includingClaudeDesktop) to askquestions about your codebase without manually uploading context files.
275275

276276
## Custom Tools
277277

‎src/McpServer/Console/McpConfigCommand.php‎

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
useButschster\ContextGenerator\McpServer\McpConfig\ConfigGeneratorInterface;
1010
useButschster\ContextGenerator\McpServer\McpConfig\Renderer\McpConfigRenderer;
1111
useButschster\ContextGenerator\McpServer\McpConfig\Service\OsDetectionService;
12+
useButschster\ContextGenerator\McpServer\McpConfig\Client\ClientStrategyRegistry;
1213
useSpiral\Console\Attribute\Option;
1314
useSymfony\Component\Console\Attribute\AsCommand;
1415
useSymfony\Component\Console\Command\Command;
@@ -43,7 +44,7 @@ final class McpConfigCommand extends BaseCommand
4344
#[Option(
4445
name:'client',
4546
shortcut:'c',
46-
description:'MCP client type (claude, generic)',
47+
description:'MCP client type (claude,codex, cursor,generic)',
4748
)]
4849
protectedstring$client ='generic';
4950

@@ -80,20 +81,22 @@ public function __invoke(
8081
// Determine configuration approach
8182
$options =$this->buildConfigOptions($dirs);
8283

83-
// Generate configuration
84+
// Resolve selected client strategy
85+
$registry =newClientStrategyRegistry();
86+
$strategy =$registry->getByKey($this->client) ??$registry->getDefault();
87+
88+
// Generate configuration via vendor generator (supports claude/generic)
8489
$config =$configGenerator->generate(
85-
client:$this->client,
90+
client:$strategy->getGeneratorClientKey(),
8691
osInfo:$osInfo,
8792
projectPath:$options['project_path'] ?? (string)$dirs->getRootPath(),
8893
options:$options,
8994
);
9095

91-
// Render the configuration
92-
$renderer->renderConfiguration($config,$osInfo,$options);
93-
94-
// Show explanations if requested
96+
// Render using strategy
97+
$strategy->renderConfiguration($renderer,$config,$osInfo,$options,$this->output);
9598
if ($this->explain) {
96-
$renderer->renderExplanation($config,$osInfo,$options);
99+
$strategy->renderExplanation($renderer,$config,$osInfo,$options,$this->output);
97100
}
98101

99102
return Command::SUCCESS;
@@ -108,12 +111,23 @@ private function runInteractiveMode(
108111
$renderer->renderInteractiveWelcome();
109112

110113
// Ask about client type
111-
$clientType =$this->output->choice(
114+
$registry =newClientStrategyRegistry();
115+
116+
// Build interactive choices. We pass human labels for display, but
117+
// also accept typed keys (e.g. "codex") as valid input.
118+
$choice =$this->output->choice(
112119
'Which MCP client are you configuring?',
113-
['claude' =>'Claude Desktop','generic' =>'Generic MCP Client'],
114-
'generic',
120+
$registry->getChoiceLabels(),
121+
$registry->getDefault()->getLabel(),
115122
);
116123

124+
// Resolve strategy by label first, then by key (case-insensitive).
125+
// This fixes a bug where typing a key like "codex" fell back to the
126+
// default (Claude) because we only matched by label.
127+
$strategy =$registry->getByLabel($choice)
128+
??$registry->getByKey(\strtolower(\trim((string)$choice)))
129+
??$registry->getDefault();
130+
117131
// Auto-detect OS
118132
$osInfo =$osDetection->detect();
119133
$renderer->renderDetectedEnvironment($osInfo);
@@ -174,14 +188,14 @@ private function runInteractiveMode(
174188

175189
// Generate and display configuration
176190
$config =$configGenerator->generate(
177-
client:$clientType,
191+
client:$strategy->getGeneratorClientKey(),
178192
osInfo:$osInfo,
179193
projectPath:$projectPath,
180194
options:$options,
181195
);
182196

183-
$renderer->renderConfiguration($config,$osInfo,$options);
184-
$renderer->renderExplanation($config,$osInfo,$options);
197+
$strategy->renderConfiguration($renderer,$config,$osInfo,$options,$this->output);
198+
$strategy->renderExplanation($renderer,$config,$osInfo,$options,$this->output);
185199

186200
return Command::SUCCESS;
187201
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespaceButschster\ContextGenerator\McpServer\McpConfig\Client;
6+
7+
useButschster\ContextGenerator\McpServer\McpConfig\Model\McpConfig;
8+
useButschster\ContextGenerator\McpServer\McpConfig\Model\OsInfo;
9+
useButschster\ContextGenerator\McpServer\McpConfig\Renderer\McpConfigRenderer;
10+
useSymfony\Component\Console\Style\SymfonyStyle;
11+
12+
abstractclass AbstractClientStrategyimplements ClientStrategyInterface
13+
{
14+
publicfunctionrenderConfiguration(
15+
McpConfigRenderer$renderer,
16+
McpConfig$config,
17+
OsInfo$osInfo,
18+
array$options,
19+
SymfonyStyle$output,
20+
):void {
21+
// Default rendering delegates to shared renderer
22+
$renderer->renderConfiguration($config,$osInfo,$options);
23+
}
24+
25+
publicfunctionrenderExplanation(
26+
McpConfigRenderer$renderer,
27+
McpConfig$config,
28+
OsInfo$osInfo,
29+
array$options,
30+
SymfonyStyle$output,
31+
):void {
32+
// Default explanation delegates to shared renderer
33+
$renderer->renderExplanation($config,$osInfo,$options);
34+
35+
$this->renderAdditionalNotes($output,$osInfo,$options);
36+
}
37+
38+
protectedfunctionrenderAdditionalNotes(SymfonyStyle$output,OsInfo$osInfo,array$options):void {}
39+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespaceButschster\ContextGenerator\McpServer\McpConfig\Client;
6+
7+
finalclass ClaudeDesktopClientStrategyextends AbstractClientStrategy
8+
{
9+
publicfunctiongetKey():string
10+
{
11+
return'claude';
12+
}
13+
14+
publicfunctiongetLabel():string
15+
{
16+
return'Claude Desktop';
17+
}
18+
19+
publicfunctiongetGeneratorClientKey():string
20+
{
21+
return'claude';
22+
}
23+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespaceButschster\ContextGenerator\McpServer\McpConfig\Client;
6+
7+
useButschster\ContextGenerator\McpServer\McpConfig\Model\McpConfig;
8+
useButschster\ContextGenerator\McpServer\McpConfig\Model\OsInfo;
9+
useButschster\ContextGenerator\McpServer\McpConfig\Renderer\McpConfigRenderer;
10+
useSymfony\Component\Console\Style\SymfonyStyle;
11+
12+
interface ClientStrategyInterface
13+
{
14+
publicfunctiongetKey():string;
15+
16+
publicfunctiongetLabel():string;
17+
18+
/**
19+
* Returns the client key supported by the underlying generator (e.g. "claude" or "generic").
20+
*/
21+
publicfunctiongetGeneratorClientKey():string;
22+
23+
publicfunctionrenderConfiguration(
24+
McpConfigRenderer$renderer,
25+
McpConfig$config,
26+
OsInfo$osInfo,
27+
array$options,
28+
SymfonyStyle$output,
29+
):void;
30+
31+
publicfunctionrenderExplanation(
32+
McpConfigRenderer$renderer,
33+
McpConfig$config,
34+
OsInfo$osInfo,
35+
array$options,
36+
SymfonyStyle$output,
37+
):void;
38+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespaceButschster\ContextGenerator\McpServer\McpConfig\Client;
6+
7+
finalclass ClientStrategyRegistry
8+
{
9+
/** @var array<string, ClientStrategyInterface> */
10+
privatearray$strategies;
11+
12+
publicfunction__construct()
13+
{
14+
$this->strategies = [];
15+
16+
$this->register(newClaudeDesktopClientStrategy());
17+
$this->register(newCodexClientStrategy());
18+
$this->register(newCursorClientStrategy());
19+
$this->register(newGenericClientStrategy());
20+
}
21+
22+
publicfunctionregister(ClientStrategyInterface$strategy):void
23+
{
24+
$this->strategies[$strategy->getKey()] =$strategy;
25+
}
26+
27+
publicfunctiongetByKey(string$key): ?ClientStrategyInterface
28+
{
29+
$key =\strtolower($key);
30+
return$this->strategies[$key] ??null;
31+
}
32+
33+
publicfunctiongetByLabel(string$label): ?ClientStrategyInterface
34+
{
35+
foreach ($this->strategiesas$strategy) {
36+
if ($strategy->getLabel() ===$label) {
37+
return$strategy;
38+
}
39+
}
40+
returnnull;
41+
}
42+
43+
/**
44+
* @return string[] Human-friendly labels for interactive choice
45+
*/
46+
publicfunctiongetChoiceLabels():array
47+
{
48+
return\array_map(staticfn(ClientStrategyInterface$s) =>$s->getLabel(),$this->strategies);
49+
}
50+
51+
publicfunctiongetDefault():ClientStrategyInterface
52+
{
53+
return$this->strategies['claude'];
54+
}
55+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp