Skip to content

Commit e51390c

Browse files
committed
feat: add MCP project management tools
1 parent a8b34a2 commit e51390c

11 files changed

+461
-0
lines changed

src/McpServer/McpConfig.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ final class McpConfig extends InjectableConfig
3737
'git_operations' => [
3838
'enable' => true,
3939
],
40+
'project_operations' => [
41+
'enable' => true,
42+
],
4043
];
4144

4245
public function getDocumentNameFormat(string $path, string $description, string $tags): string
@@ -97,4 +100,9 @@ public function isGitOperationsEnabled(): bool
97100
{
98101
return $this->config['git_operations']['enable'] ?? true;
99102
}
103+
104+
public function isProjectOperationsEnabled(): bool
105+
{
106+
return $this->config['project_operations']['enable'] ?? true;
107+
}
100108
}

src/McpServer/McpServerBootloader.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232
use Butschster\ContextGenerator\McpServer\Action\Tools\Prompts\GetPromptToolAction;
3333
use Butschster\ContextGenerator\McpServer\Action\Tools\Prompts\ListPromptsToolAction;
3434
use Butschster\ContextGenerator\McpServer\Console\MCPServerCommand;
35+
use Butschster\ContextGenerator\McpServer\Projects\Actions\ProjectsListToolAction;
36+
use Butschster\ContextGenerator\McpServer\Projects\Actions\ProjectSwitchToolAction;
3537
use Butschster\ContextGenerator\McpServer\Projects\McpProjectsBootloader;
3638
use Butschster\ContextGenerator\McpServer\ProjectService\ProjectServiceInterface;
3739
use Butschster\ContextGenerator\McpServer\Prompt\McpPromptBootloader;
@@ -98,6 +100,9 @@ public function init(EnvironmentInterface $env): void
98100
'git_operations' => [
99101
'enable' => (bool) $env->get('MCP_GIT_OPERATIONS', !$isCommonProject),
100102
],
103+
'project_operations' => [
104+
'enable' => (bool) $env->get('MCP_PROJECT_OPERATIONS', true),
105+
],
101106
],
102107
);
103108
}
@@ -189,6 +194,7 @@ private function actions(McpConfig $config): array
189194
FetchLibraryDocsAction::class,
190195
];
191196
}
197+
192198
if ($config->isFileOperationsEnabled()) {
193199
$actions = [
194200
...$actions,
@@ -209,6 +215,14 @@ private function actions(McpConfig $config): array
209215
}
210216
}
211217

218+
if ($config->isProjectOperationsEnabled()) {
219+
$actions = [
220+
...$actions,
221+
ProjectsListToolAction::class,
222+
ProjectSwitchToolAction::class,
223+
];
224+
}
225+
212226
if ($config->isGitOperationsEnabled()) {
213227
$actions[] = GitStatusAction::class;
214228
$actions[] = GitAddAction::class;
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Butschster\ContextGenerator\McpServer\Projects\Actions\Dto;
6+
7+
/**
8+
* Response when alias resolution occurs
9+
*/
10+
final readonly class AliasResolutionResponse implements \JsonSerializable
11+
{
12+
public function __construct(
13+
public string $originalAlias,
14+
public string $resolvedPath,
15+
) {}
16+
17+
public function jsonSerialize(): array
18+
{
19+
return [
20+
'original_alias' => $this->originalAlias,
21+
'resolved_path' => $this->resolvedPath,
22+
];
23+
}
24+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Butschster\ContextGenerator\McpServer\Projects\Actions\Dto;
6+
7+
/**
8+
* Represents current project information in response
9+
*/
10+
final readonly class CurrentProjectResponse implements \JsonSerializable
11+
{
12+
/**
13+
* @param string[] $aliases
14+
*/
15+
public function __construct(
16+
public string $path,
17+
public ?string $configFile,
18+
public ?string $envFile,
19+
public array $aliases,
20+
) {}
21+
22+
public function jsonSerialize(): array
23+
{
24+
return [
25+
'path' => $this->path,
26+
'config_file' => $this->configFile,
27+
'env_file' => $this->envFile,
28+
'aliases' => $this->aliases,
29+
];
30+
}
31+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Butschster\ContextGenerator\McpServer\Projects\Actions\Dto;
6+
7+
/**
8+
* Represents a single project in the response
9+
*/
10+
final readonly class ProjectInfoResponse implements \JsonSerializable
11+
{
12+
/**
13+
* @param string[] $aliases
14+
*/
15+
public function __construct(
16+
public string $path,
17+
public ?string $configFile,
18+
public ?string $envFile,
19+
public string $addedAt,
20+
public array $aliases,
21+
public bool $isCurrent,
22+
) {}
23+
24+
public function jsonSerialize(): array
25+
{
26+
return [
27+
'path' => $this->path,
28+
'config_file' => $this->configFile,
29+
'env_file' => $this->envFile,
30+
'added_at' => $this->addedAt,
31+
'aliases' => $this->aliases,
32+
'is_current' => $this->isCurrent,
33+
];
34+
}
35+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Butschster\ContextGenerator\McpServer\Projects\Actions\Dto;
6+
7+
final readonly class ProjectListRequest
8+
{
9+
public function __construct(
10+
// No parameters needed for listing projects
11+
) {}
12+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Butschster\ContextGenerator\McpServer\Projects\Actions\Dto;
6+
7+
use Spiral\JsonSchemaGenerator\Attribute\Field;
8+
9+
final readonly class ProjectSwitchRequest
10+
{
11+
public function __construct(
12+
#[Field(
13+
description: 'Alias to the project to switch to. Should be project alias.',
14+
)]
15+
public string $alias,
16+
) {}
17+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Butschster\ContextGenerator\McpServer\Projects\Actions\Dto;
6+
7+
/**
8+
* Response for project switch tool
9+
*/
10+
final readonly class ProjectSwitchResponse implements \JsonSerializable
11+
{
12+
public function __construct(
13+
public bool $success,
14+
public string $message,
15+
public ?CurrentProjectResponse $currentProject = null,
16+
public ?AliasResolutionResponse $resolvedFromAlias = null,
17+
) {}
18+
19+
public function jsonSerialize(): array
20+
{
21+
return \array_filter([
22+
'success' => $this->success,
23+
'message' => $this->message,
24+
'current_project' => $this->currentProject,
25+
'resolved_from_alias' => $this->resolvedFromAlias,
26+
], static fn($value) => $value !== null);
27+
}
28+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Butschster\ContextGenerator\McpServer\Projects\Actions\Dto;
6+
7+
/**
8+
* Response for projects list tool
9+
*/
10+
final readonly class ProjectsListResponse implements \JsonSerializable
11+
{
12+
/**
13+
* @param ProjectInfoResponse[] $projects
14+
*/
15+
public function __construct(
16+
public array $projects,
17+
public ?CurrentProjectResponse $currentProject,
18+
public int $totalProjects,
19+
public ?string $message = null,
20+
) {}
21+
22+
public function jsonSerialize(): array
23+
{
24+
return [
25+
'projects' => $this->projects,
26+
'current_project' => $this->currentProject,
27+
'total_projects' => $this->totalProjects,
28+
'message' => $this->message,
29+
];
30+
}
31+
}

0 commit comments

Comments
 (0)