Resolve human project names in MCP project_id args
Auto-resolve project_id values that look like human names to canonical project identifiers when there is a clear match. Return actionable guidance with candidate slugs when ambiguous, and cover the behavior with structure tests and docs updates.
This commit is contained in:
@@ -78,6 +78,8 @@ final class RedmineStructureTest
|
||||
$this->testMcpFindProjectRecommendsExactIdentifier();
|
||||
$this->testMcpFindProjectRecommendsExactName();
|
||||
$this->testMcpFindProjectLeavesAmbiguousMatchesUnrecommended();
|
||||
$this->testMcpGetProjectResolvesHumanProjectNameToIdentifier();
|
||||
$this->testMcpGetProjectShowsHelpfulErrorForAmbiguousHumanName();
|
||||
$this->testMcpSearchSanitizesNoisyTextFields();
|
||||
$this->testMcpSearchCanDisableTextSanitization();
|
||||
$this->testCreateRelationDefaultsToRelatesAndRequiresTarget();
|
||||
@@ -241,6 +243,45 @@ final class RedmineStructureTest
|
||||
$this->assertSame('quality-archive', $result['matches'][1]['identifier'], 'second ambiguous match is returned');
|
||||
}
|
||||
|
||||
private function testMcpGetProjectResolvesHumanProjectNameToIdentifier(): void
|
||||
{
|
||||
$http = new RecordingClient();
|
||||
$http->queueJson(['projects' => $this->projectFixtures()]);
|
||||
$http->queueJson(['project' => ['id' => 78, 'identifier' => 'quality-tracker', 'name' => 'Quality Tracker']]);
|
||||
$dispatcher = new McpDispatcher(new RedmineClient($http));
|
||||
|
||||
$result = $this->callToolJson($dispatcher, 'redmine_get_project', ['project_id' => 'Quality Tracker']);
|
||||
|
||||
$this->assertSame(78, $result['id'], 'human project name resolves to expected project');
|
||||
$this->assertSame('/projects/quality-tracker.json', $http->requests[1]['path'], 'resolved project lookup uses project identifier slug');
|
||||
}
|
||||
|
||||
private function testMcpGetProjectShowsHelpfulErrorForAmbiguousHumanName(): void
|
||||
{
|
||||
$http = new RecordingClient();
|
||||
$http->queueJson(['projects' => $this->projectFixtures()]);
|
||||
$dispatcher = new McpDispatcher(new RedmineClient($http));
|
||||
|
||||
$response = $dispatcher->handleMessage([
|
||||
'jsonrpc' => '2.0',
|
||||
'id' => 1,
|
||||
'method' => 'tools/call',
|
||||
'params' => [
|
||||
'name' => 'redmine_get_project',
|
||||
'arguments' => [
|
||||
'project_id' => 'Quality',
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
if (!is_array($response) || !isset($response['error']) || !is_array($response['error'])) {
|
||||
throw new RuntimeException('Expected ambiguous project name to produce an MCP error.');
|
||||
}
|
||||
$message = (string) ($response['error']['message'] ?? '');
|
||||
$this->assertStringContains('redmine_find_project', $message, 'ambiguous project error points to resolver tool');
|
||||
$this->assertStringContains('quality-tracker', $message, 'ambiguous project error provides possible identifier matches');
|
||||
}
|
||||
|
||||
private function testMcpSearchSanitizesNoisyTextFields(): void
|
||||
{
|
||||
$http = new RecordingClient();
|
||||
|
||||
Reference in New Issue
Block a user