loopctl-mcp-server 2.114.0 → 2.115.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +1 -0
  2. package/index.js +26 -1
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -200,6 +200,7 @@ tool parameter.
200
200
  | `resolve_project` | Resolve a repo to its `project_id` in one cheap call — provide any of `slug`, `repo_url` (`git@github.com:owner/repo.git`, `https://github.com/owner/repo`, and bare `owner/repo` all match), or `name`. Precedence `slug > repo_url > name`, first match wins. Use the returned `id` to scope captures/recall (`memory_*`, `recall_context`). `404` `not_found` if nothing matches, `422` `no_identifier` if none supplied, `409` if a fuzzy identifier matches more than one active project. |
201
201
  | `create_project` | Create a new **work** project (epics/stories/custody). Requires orchestrator+ **and** a `human_anchored` tenant; an agent-rooted tenant gets `403 custody_tier_required` and should use `create_kb_scope`. |
202
202
  | `delete_project` | **Needs a user-role key:** `LOOPCTL_USER_KEY` verbatim when set, else the default key (orchestrator role is 403 `insufficient_role`). Archives the project (status `archived`); no rows are removed and its slug stays taken. |
203
+ | `restore_project` | Restore an archived `kind: work` project, the reverse of `delete_project`; audited as `unarchived`. Orchestrator role or higher on a human-anchored tenant. Rejected (422) at the tenant's `max_projects` cap and for a kb scope (use `restore_kb_scope`). The only way to change a project's status back: PATCH refuses `status` with 422. |
203
204
  | `get_progress` | Get progress summary for a project, including story counts by status. Pass `include_cost=true` for cost data. |
204
205
  | `import_stories` | Import stories into a project from a structured payload (Epic 12 import format). Pass `merge: true` to add stories to epics that already exist (otherwise duplicates return 409). For large payloads, use `payload_path` to read JSON from disk instead of passing it inline. With `merge: true`, `report_orphans: true` adds `stories_orphaned` (the project's stories the payload does not mention; nothing is detached) — a signal only on a FULL round-trip of an export; without it the key is absent (#880). |
205
206
 
package/index.js CHANGED
@@ -959,6 +959,13 @@ async function deleteProject({ project_id }) {
959
959
  return toContent(result);
960
960
  }
961
961
 
962
+ // The reverse of deleteProject for a kind: work project. Default key: the route is
963
+ // orchestrator+ (a user key passes too), so no role pin is needed.
964
+ async function restoreProject({ project_id }) {
965
+ const result = await apiCall("POST", `/api/v1/projects/${project_id}/restore`, {});
966
+ return toContent(result);
967
+ }
968
+
962
969
  async function getProgress({ project_id, include_cost }) {
963
970
  const params = new URLSearchParams();
964
971
  if (include_cost) params.set("include_cost", "true");
@@ -4242,7 +4249,7 @@ const TOOLS = [
4242
4249
  {
4243
4250
  name: "delete_project",
4244
4251
  description:
4245
- "ARCHIVE a project (DELETE /api/v1/projects/:id sets status to archived; it removes no rows). Its epics, stories and audit entries stay, and an already-archived project is a no-op. The SLUG stays taken: slugs are unique per tenant across archived projects too, resolve_project by that slug still returns the archived project, create_project with it is refused 422, and no API call changes or releases a slug, so a new project needs a different one. The way back: restore_kb_scope for a kb scope; a work project is restored by PATCH /api/v1/projects/:id with status active, which no MCP tool reaches yet. Sent with LOOPCTL_USER_KEY verbatim when it is set (a global LOOPCTL_API_KEY does not displace it), else with the default key. Refusals: 403 insufficient_role below user role, 403 custody_tier_required on an agent-rooted tenant (the human-anchor gate), 404 for an id not in your tenant.",
4252
+ "ARCHIVE a project (DELETE /api/v1/projects/:id sets status to archived; it removes no rows). Its epics, stories and audit entries stay, and an already-archived project is a no-op. The SLUG stays taken: slugs are unique per tenant across archived projects too, resolve_project by that slug still returns the archived project, create_project with it is refused 422, and no API call changes or releases a slug, so a new project needs a different one. The way back: restore_project for a work project, restore_kb_scope for a kb scope. Sent with LOOPCTL_USER_KEY verbatim when it is set (a global LOOPCTL_API_KEY does not displace it), else with the default key. Refusals: 403 insufficient_role below user role, 403 custody_tier_required on an agent-rooted tenant (the human-anchor gate), 404 for an id not in your tenant.",
4246
4253
  inputSchema: {
4247
4254
  type: "object",
4248
4255
  properties: {
@@ -4254,6 +4261,21 @@ const TOOLS = [
4254
4261
  required: ["project_id"],
4255
4262
  },
4256
4263
  },
4264
+ {
4265
+ name: "restore_project",
4266
+ description:
4267
+ "RESTORE an archived kind: work project (POST /api/v1/projects/:id/restore, the reverse of delete_project). Audited as unarchived; an already-active project comes back unchanged. Status cannot be changed any other way: PATCH /api/v1/projects/:id refuses a body carrying status with 422. Sent with the default key; the route needs orchestrator role or higher. Refusals: 422 when the tenant is at its max_projects cap (re-activating takes an active slot), 422 for a kind: kb scope (use restore_kb_scope), 403 insufficient_role below orchestrator role, 403 custody_tier_required on an agent-rooted tenant (the human-anchor gate), 404 for an id not in your tenant.",
4268
+ inputSchema: {
4269
+ type: "object",
4270
+ properties: {
4271
+ project_id: {
4272
+ type: "string",
4273
+ description: "The UUID of the archived work project to restore.",
4274
+ },
4275
+ },
4276
+ required: ["project_id"],
4277
+ },
4278
+ },
4257
4279
  {
4258
4280
  name: "get_progress",
4259
4281
  description: "Get progress summary for a project, including story counts by status. Pass include_cost=true to include cost data when available.",
@@ -10018,6 +10040,9 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
10018
10040
  case "delete_project":
10019
10041
  return await deleteProject(args);
10020
10042
 
10043
+ case "restore_project":
10044
+ return await restoreProject(args);
10045
+
10021
10046
  case "get_progress":
10022
10047
  return await getProgress(args);
10023
10048
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "loopctl-mcp-server",
3
- "version": "2.114.0",
3
+ "version": "2.115.0",
4
4
  "description": "MCP server for loopctl — structural trust for AI development loops",
5
5
  "type": "module",
6
6
  "main": "index.js",