Skip to content

fix: support scoped template v1 paths#183

Draft
cursor[bot] wants to merge 5 commits into
mainfrom
cursor/mcp-v2-bug-resolution-cb5c
Draft

fix: support scoped template v1 paths#183
cursor[bot] wants to merge 5 commits into
mainfrom
cursor/mcp-v2-bug-resolution-cb5c

Conversation

@cursor
Copy link
Copy Markdown
Contributor

@cursor cursor Bot commented May 13, 2026

Description

Fixes template create/update/delete registry behavior for the v1 template API. Create/update now build account-, org-, or project-scoped v1 paths per operation, while preserving configured default org/project scoping for existing template list/get/delete reads. Template delete now sends version_label as the required path segment, and template update passes through optional v1 metadata fields.

Type of Change

  • Bug fix
  • New feature
  • Refactor
  • Documentation
  • Other

Checklist

  • Tests pass
  • Typecheck passes

Verification:

  • pnpm test tests/registry/registry.test.ts
  • pnpm test tests/registry/structural-validation.test.ts
  • pnpm typecheck
  • pnpm test
Open in Web View Automation 

cursoragent and others added 2 commits May 13, 2026 05:22
Co-authored-by: Rohan Gupta <thisrohangupta@users.noreply.github.com>
Co-authored-by: Rohan Gupta <thisrohangupta@users.noreply.github.com>
@CLAassistant
Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

Co-authored-by: Rohan Gupta <thisrohangupta@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale comment

Found 1 blocking issue.

  1. templateV1ScopePath still re-applies default project/org scope for v1 template writes, so explicit broader-scope create/update calls are not actually supported under the normal MCP configuration where HARNESS_ORG and HARNESS_PROJECT are set. I reproduced this on the built branch: registry.dispatch(..., 'template', 'update', { org_id: 'org-only', ... }) emitted PUT /v1/orgs/org-only/projects/test-project/templates/testTemplate/versions/v2 and carried projectIdentifier: "test-project" in both params and body. That means org/account-scoped writes only work when defaults are unset, which is narrower than the PR description claims.

Open question:

  • Should explicit org_id with omitted project_id suppress default project fallback for v1 writes, or do create/update need a per-operation way to opt out of the registry's project-scope param/body injection?

Verification:

  • pnpm test tests/registry/registry.test.ts
  • pnpm test tests/registry/structural-validation.test.ts
  • pnpm typecheck
  • pnpm build
Open in Web View Automation 

Sent by Cursor Automation: Sunil On Demand Architecture Review

Comment thread src/registry/toolsets/templates.ts Outdated
cursoragent and others added 2 commits May 13, 2026 05:59
Co-authored-by: Rohan Gupta <thisrohangupta@users.noreply.github.com>
Co-authored-by: Rohan Gupta <thisrohangupta@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale comment

Important:

  1. src/registry/toolsets/templates.ts, src/tools/harness-describe.ts, src/tools/harness-create.ts, src/tools/harness-update.ts, src/tools/harness-delete.ts, tasks/todo.md: runtime now supports account/org/project template writes via scopeOptional/scope_level, but the agent-facing contract still exposes template as scope: "project" and the generic write/delete tools do not advertise scope_level (or template version_label) as first-class inputs. With defaults configured, account-scoped writes only work if callers already know to tunnel params.scope_level="account" through the generic params bag, so the new task/review note overstates end-to-end support.
  2. tests/registry/registry.test.ts, tests/tools/tool-handlers.test.ts: the new regression coverage stops at registry.dispatch(). The shipped behavior goes through harness_create / harness_update / harness_delete, which still need to map resource_id -> template_id, default or forward version_label, and carry scope_level through params. Without at least one tool-handler regression on those public paths, this PR proves helper wiring, not the real agent-facing behavior.
Open in Web View Automation 

Sent by Cursor Automation: Sunil On Demand Architecture Review

Comment thread src/registry/toolsets/templates.ts
Comment thread tests/registry/registry.test.ts
Copy link
Copy Markdown
Contributor Author

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale comment

Reviewed against Sunil's architecture standards.

Findings:

  1. src/registry/toolsets/templates.ts now fixes the dispatcher/path behavior for account/org/project template operations, but the agent-facing contract is still incomplete. harness_describe(resource_type="template") still presents templates as scope: "project", while the shared write tools only expose a generic params bag. That means the new account/org create / update / delete paths, plus delete's required version_label, are still not discoverable in the structured metadata surface that this repo expects agents to use.
  2. tests/registry/registry.test.ts adds good dispatch-level regressions, but the public bug report was about generic template operations. There is still no tool-handler coverage proving harness_create / harness_update / harness_delete actually preserve params.scope_level and params.version_label through the shared tool layer.

Assumption:

  • I reviewed this as a user-facing generic-tool fix, not just an internal registry refactor, because the PR title/body claim scoped template support rather than a helper-only cleanup.

Change summary:

  • The earlier blocking issue where config defaults re-narrowed org/account-scoped v1 template writes looks fixed in the current branch.

Verification:

  • pnpm install --frozen-lockfile
  • pnpm test -- tests/registry/registry.test.ts tests/tools/tool-handlers.test.ts tests/registry/structural-validation.test.ts (52 files / 1202 tests passed)
  • pnpm typecheck
  • pnpm build
  • gh pr checks 183
Open in Web View Automation 

Sent by Cursor Automation: Sunil On Demand Architecture Review

Comment thread src/registry/toolsets/templates.ts
Comment thread tests/registry/registry.test.ts
Copy link
Copy Markdown
Contributor Author

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Found 3 findings in src/registry/toolsets/templates.ts.

  1. Important: global=true now widens template.list to account scope and drops the configured org/project filters.
  2. Important: invalid scope_level values silently fall back to configured defaults, which can mis-target writes instead of failing loudly.
  3. Warning: the new update schema advertises label as a version label, but the public harness_update path still routes missing version_label to /versions/v1.

Open questions / assumptions:

  • I'm assuming global=true on template.list is meant to include global templates alongside the active scope, matching the current description and the pre-PR behavior.
  • If template updates are still required to pass params.version_label, the updated body schema should say that explicitly instead of surfacing label as the version selector.

Change summary:

  • The earlier scoped-write blocker is fixed on the live head. I verified that org-scoped template updates now emit /v1/orgs/<org>/templates/... without projectIdentifier.

Verification:

  • pnpm test tests/registry/registry.test.ts tests/tools/tool-handlers.test.ts
  • pnpm typecheck
  • pnpm build
  • runtime probes against build/ for template.list(global=true), invalid scope_level, and harness_update version routing
Open in Web View Automation 

Sent by Cursor Automation: Sunil On Demand Architecture Review

const projectInput = nonEmptyString(input.project_id);
const isGlobalTemplate = input.global === true || input.global === "true" || input.account_id === "__GLOBAL_TEMPLATES_ACCOUNT_ID__";

if (explicitScope === "account" || (!explicitScope && isGlobalTemplate)) {
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Treating global=true as account scope for every template operation regresses template.list semantics. Because applyTemplateScope() clears org_id / project_id and the resource is now scopeOptional, a normal scoped list call like harness_list(resource_type="template", global=true) drops the configured orgIdentifier / projectIdentifier entirely instead of "including global templates" in the active scope.

I reproduced it on this head after pnpm build with registry.dispatch(..., "template", "list", { global: true }), which emitted:

{"path":"/template/api/templates/list-metadata","params":{"isGlobal":true}}

That is a behavior change from origin/main, where global=true only added isGlobal=true and preserved the default project/org scope.

};

function normalizeTemplateScopeLevel(value: unknown): TemplateScope["level"] | undefined {
if (value !== "account" && value !== "org" && value !== "project") {
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This helper silently ignores invalid scope_level values and falls back to configured defaults. Since scope_level reaches the registry through the generic tool params / filters records, a typo like "acount" on create / update / delete can route the write to the default project instead of failing locally.

Current-head reproduction after pnpm build:

{"path":"/template/api/templates/testTemplate/v2","params":{"orgIdentifier":"default","projectIdentifier":"test-project"}}

from registry.dispatch(..., "template", "delete", { scope_level: "acount", template_id: "testTemplate", version_label: "v2" }).

Given the repo's fail-loud guidance, I'd reject unknown scope selectors here instead of treating them as "use defaults".

{ name: "template_yaml", type: "yaml", required: true, description: "Full template YAML string with changes (name, identifier, etc. are derived from the YAML)" },
{ name: "identifier", type: "string", required: false, description: "Template identifier (derived from YAML if omitted)" },
{ name: "name", type: "string", required: false, description: "Display name (derived from YAML if omitted)" },
{ name: "label", type: "string", required: false, description: "Version label (derived from YAML if omitted)" },
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new update schema now surfaces label as the version label, but the public harness_update path still defaults missing version_label to v1 in src/tools/harness-update.ts. That creates a metadata/runtime contract mismatch for agents using harness_describe.

Current-head reproduction after pnpm build:

{"path":"/v1/orgs/default/projects/test-project/templates/testTemplate/versions/v1","body":{"label":"v2"}}

from harness_update(resource_type="template", resource_id="testTemplate", body={ template_yaml: ..., label: "v2" }).

If update calls still must provide params.version_label, I think this schema should say that explicitly instead of implying label drives version selection.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants