fix : apply review fixes to MCP plan and spec
Fix getIsFinal() method name, enrich create/update tool return formats to match get/list consistency, fix duplicate Reference section in spec, correct tool count to 22. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
|
||||
**Goal:** Add an MCP server to Lesstime exposing projects, tasks, and time tracking for AI clients via STDIO and HTTP transports.
|
||||
|
||||
**Architecture:** Install `symfony/mcp-bundle`, create 21 tool classes in `src/Mcp/Tool/` organized by domain (Project, Task, TaskMeta, TimeEntry, Reference). HTTP transport secured by API token on User entity with a custom Symfony authenticator. STDIO for local Claude Code usage.
|
||||
**Architecture:** Install `symfony/mcp-bundle`, create 22 tool classes in `src/Mcp/Tool/` organized by domain (Project, Task, TaskMeta, TimeEntry, Reference). HTTP transport secured by API token on User entity with a custom Symfony authenticator. STDIO for local Claude Code usage.
|
||||
|
||||
**Tech Stack:** symfony/mcp-bundle, Symfony 8 security (custom authenticator), Doctrine ORM, PHP 8.4
|
||||
|
||||
@@ -931,7 +931,7 @@ class GetTaskTool
|
||||
'id' => $task->getStatus()->getId(),
|
||||
'label' => $task->getStatus()->getLabel(),
|
||||
'color' => $task->getStatus()->getColor(),
|
||||
'isFinal' => $task->getStatus()->isFinal(),
|
||||
'isFinal' => $task->getStatus()->getIsFinal(),
|
||||
] : null,
|
||||
'priority' => $task->getPriority() ? [
|
||||
'id' => $task->getPriority()->getId(),
|
||||
@@ -1109,16 +1109,39 @@ class CreateTaskTool
|
||||
'id' => $task->getId(),
|
||||
'number' => $task->getNumber(),
|
||||
'title' => $task->getTitle(),
|
||||
'description' => $task->getDescription(),
|
||||
'status' => $task->getStatus() ? [
|
||||
'id' => $task->getStatus()->getId(),
|
||||
'label' => $task->getStatus()->getLabel(),
|
||||
'color' => $task->getStatus()->getColor(),
|
||||
] : null,
|
||||
'priority' => $task->getPriority() ? [
|
||||
'id' => $task->getPriority()->getId(),
|
||||
'label' => $task->getPriority()->getLabel(),
|
||||
'color' => $task->getPriority()->getColor(),
|
||||
] : null,
|
||||
'effort' => $task->getEffort() ? [
|
||||
'id' => $task->getEffort()->getId(),
|
||||
'label' => $task->getEffort()->getLabel(),
|
||||
] : null,
|
||||
'assignee' => $task->getAssignee() ? [
|
||||
'id' => $task->getAssignee()->getId(),
|
||||
'username' => $task->getAssignee()->getUsername(),
|
||||
] : null,
|
||||
'group' => $task->getGroup() ? [
|
||||
'id' => $task->getGroup()->getId(),
|
||||
'title' => $task->getGroup()->getTitle(),
|
||||
] : null,
|
||||
'project' => [
|
||||
'id' => $project->getId(),
|
||||
'code' => $project->getCode(),
|
||||
'name' => $project->getName(),
|
||||
],
|
||||
'status' => $task->getStatus() ? ['id' => $task->getStatus()->getId(), 'label' => $task->getStatus()->getLabel()] : null,
|
||||
'priority' => $task->getPriority() ? ['id' => $task->getPriority()->getId(), 'label' => $task->getPriority()->getLabel()] : null,
|
||||
'effort' => $task->getEffort() ? ['id' => $task->getEffort()->getId(), 'label' => $task->getEffort()->getLabel()] : null,
|
||||
'assignee' => $task->getAssignee() ? ['id' => $task->getAssignee()->getId(), 'username' => $task->getAssignee()->getUsername()] : null,
|
||||
'group' => $task->getGroup() ? ['id' => $task->getGroup()->getId(), 'title' => $task->getGroup()->getTitle()] : null,
|
||||
'tags' => $task->getTags()->map(fn($t) => [
|
||||
'id' => $t->getId(),
|
||||
'label' => $t->getLabel(),
|
||||
])->toArray(),
|
||||
'archived' => $task->isArchived(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -1242,13 +1265,38 @@ class UpdateTaskTool
|
||||
'id' => $task->getId(),
|
||||
'number' => $task->getNumber(),
|
||||
'title' => $task->getTitle(),
|
||||
'description' => $task->getDescription(),
|
||||
'status' => $task->getStatus() ? [
|
||||
'id' => $task->getStatus()->getId(),
|
||||
'label' => $task->getStatus()->getLabel(),
|
||||
'color' => $task->getStatus()->getColor(),
|
||||
] : null,
|
||||
'priority' => $task->getPriority() ? [
|
||||
'id' => $task->getPriority()->getId(),
|
||||
'label' => $task->getPriority()->getLabel(),
|
||||
'color' => $task->getPriority()->getColor(),
|
||||
] : null,
|
||||
'effort' => $task->getEffort() ? [
|
||||
'id' => $task->getEffort()->getId(),
|
||||
'label' => $task->getEffort()->getLabel(),
|
||||
] : null,
|
||||
'assignee' => $task->getAssignee() ? [
|
||||
'id' => $task->getAssignee()->getId(),
|
||||
'username' => $task->getAssignee()->getUsername(),
|
||||
] : null,
|
||||
'group' => $task->getGroup() ? [
|
||||
'id' => $task->getGroup()->getId(),
|
||||
'title' => $task->getGroup()->getTitle(),
|
||||
] : null,
|
||||
'project' => [
|
||||
'id' => $task->getProject()->getId(),
|
||||
'code' => $task->getProject()->getCode(),
|
||||
'name' => $task->getProject()->getName(),
|
||||
],
|
||||
'status' => $task->getStatus() ? ['id' => $task->getStatus()->getId(), 'label' => $task->getStatus()->getLabel()] : null,
|
||||
'priority' => $task->getPriority() ? ['id' => $task->getPriority()->getId(), 'label' => $task->getPriority()->getLabel()] : null,
|
||||
'assignee' => $task->getAssignee() ? ['id' => $task->getAssignee()->getId(), 'username' => $task->getAssignee()->getUsername()] : null,
|
||||
'tags' => $task->getTags()->map(fn($t) => [
|
||||
'id' => $t->getId(),
|
||||
'label' => $t->getLabel(),
|
||||
])->toArray(),
|
||||
'archived' => $task->isArchived(),
|
||||
]);
|
||||
}
|
||||
@@ -1352,7 +1400,7 @@ class ListStatusesTool
|
||||
'label' => $s->getLabel(),
|
||||
'color' => $s->getColor(),
|
||||
'position' => $s->getPosition(),
|
||||
'isFinal' => $s->isFinal(),
|
||||
'isFinal' => $s->getIsFinal(),
|
||||
], $statuses));
|
||||
}
|
||||
}
|
||||
@@ -1851,11 +1899,27 @@ class CreateTimeEntryTool
|
||||
return json_encode([
|
||||
'id' => $entry->getId(),
|
||||
'title' => $entry->getTitle(),
|
||||
'description' => $entry->getDescription(),
|
||||
'startedAt' => $entry->getStartedAt()?->format('c'),
|
||||
'stoppedAt' => $entry->getStoppedAt()?->format('c'),
|
||||
'duration' => $entry->getStoppedAt() && $entry->getStartedAt()
|
||||
? (int) round(($entry->getStoppedAt()->getTimestamp() - $entry->getStartedAt()->getTimestamp()) / 60)
|
||||
: null,
|
||||
'user' => ['id' => $user->getId(), 'username' => $user->getUsername()],
|
||||
'project' => $entry->getProject() ? ['id' => $entry->getProject()->getId(), 'code' => $entry->getProject()->getCode()] : null,
|
||||
'task' => $entry->getTask() ? ['id' => $entry->getTask()->getId(), 'number' => $entry->getTask()->getNumber()] : null,
|
||||
'project' => $entry->getProject() ? [
|
||||
'id' => $entry->getProject()->getId(),
|
||||
'code' => $entry->getProject()->getCode(),
|
||||
'name' => $entry->getProject()->getName(),
|
||||
] : null,
|
||||
'task' => $entry->getTask() ? [
|
||||
'id' => $entry->getTask()->getId(),
|
||||
'number' => $entry->getTask()->getNumber(),
|
||||
'title' => $entry->getTask()->getTitle(),
|
||||
] : null,
|
||||
'tags' => $entry->getTags()->map(fn($t) => [
|
||||
'id' => $t->getId(),
|
||||
'label' => $t->getLabel(),
|
||||
])->toArray(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -1957,8 +2021,20 @@ class UpdateTimeEntryTool
|
||||
? (int) round(($entry->getStoppedAt()->getTimestamp() - $entry->getStartedAt()->getTimestamp()) / 60)
|
||||
: null,
|
||||
'user' => ['id' => $entry->getUser()->getId(), 'username' => $entry->getUser()->getUsername()],
|
||||
'project' => $entry->getProject() ? ['id' => $entry->getProject()->getId(), 'code' => $entry->getProject()->getCode()] : null,
|
||||
'task' => $entry->getTask() ? ['id' => $entry->getTask()->getId(), 'number' => $entry->getTask()->getNumber()] : null,
|
||||
'project' => $entry->getProject() ? [
|
||||
'id' => $entry->getProject()->getId(),
|
||||
'code' => $entry->getProject()->getCode(),
|
||||
'name' => $entry->getProject()->getName(),
|
||||
] : null,
|
||||
'task' => $entry->getTask() ? [
|
||||
'id' => $entry->getTask()->getId(),
|
||||
'number' => $entry->getTask()->getNumber(),
|
||||
'title' => $entry->getTask()->getTitle(),
|
||||
] : null,
|
||||
'tags' => $entry->getTags()->map(fn($t) => [
|
||||
'id' => $t->getId(),
|
||||
'label' => $t->getLabel(),
|
||||
])->toArray(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user