feat: add native-only FME environment get, create, update, and delete - #833
Conversation
List was already dual-mode after harness#806. Remaining CRUD follows v4 EnvironmentResource: isProduction on the wire, merge-patch update, UUID environment_id, and skipScopeBodyInjection on POST. Item get is native-only because Split v2 has no GET-by-id. Co-authored-by: Cursor <cursoragent@cursor.com>
|
|
Co-authored-by: Cursor <cursoragent@cursor.com> harness#806 only dual-moded environment list. MCP never had a workspace_id contract for the other ops, so do not invent legacy v2 create/update/delete paths.
Java EnvironmentListResponse is paginated; passthrough dropped totalCount. Product docs should not cite internal PR history.
| const mode = resolveFmeDualMode(input, "fme_environment"); | ||
| if (mode.mode === "legacy") { | ||
| throw new Error( | ||
| `fme_environment.${operation}: Harness-native (org_id/project_id) only — MCP never supported workspace_id for this operation (list remains dual-mode).`, |
There was a problem hiding this comment.
MCP never supported workspace_id
We should talk about design in the description of the tools/resources.
We should explain the intent and that's it. Not go into details what the previous was prev supported or working.
Please revamp all the descriptions added/changed in this PR.
…scription Co-authored-by: Rohan Gupta <thisrohangupta@users.noreply.github.com>
| ], | ||
| }; | ||
|
|
||
| const fmeEnvironmentUpdateSchema: BodySchema = { |
There was a problem hiding this comment.
Why do we have both isProduction and production? can we align on one for MCP? We should avoid adding such things for newer resources.
| description: | ||
| "Feature Management environment. Supports list. Dual-mode scoping: pass either org_id+project_id " + | ||
| "(Harness-native, preferred — no workspace lookup needed) or the deprecated workspace_id.", | ||
| "Feature Management environment. Dual-mode list (workspace_id or org_id+project_id). get/create/update/delete are Harness-native only. Native create/update use isProduction (production accepted as an alias). Native PATCH is JSON Merge Patch; name and isProduction are not clearable. Name max 15 characters. Delete returns 400 hasDependents while SDK API keys (always created with a new env), flags, or segments remain.", |
There was a problem hiding this comment.
Simplified the resource-level description to focus on scope and supported operations only. Removed API paths, merge-patch semantics, field constraints, and error-code details — those remain in the per-operation descriptions and body schemas where agents need them.
| "Create an FME environment (Harness-native org_id+project_id only). name is required (max 15 characters). isProduction is optional (default false). production is accepted as an alias for isProduction.", | ||
| fields: [ | ||
| { name: "name", type: "string", required: true, description: "Environment name (unique in the project; max 15 characters)" }, | ||
| { name: "isProduction", type: "boolean", required: false, description: "Whether this is a production environment. Optional; defaults to false on the backend if omitted." }, |
There was a problem hiding this comment.
Agreed — aligned on isProduction only.
Removed the production alias from the create/update body schemas, the body builder helper, and the alias-mapping tests. MCP now exposes only isProduction, matching the Harness API field (CreateEnvironmentRequest.isProduction). README updated accordingly.
|
@cursor can you review the PR? |
PR Review SummaryI've completed a comprehensive review of PR #833. The PR adds native-only FME environment operations (get, create, update, delete) as a follow-up to #806. Here's my assessment: ✅ Overall Status: APPROVED - Ready to MergeTest Results
Implementation QualityStrengths:
Test Coverage: // Native get routes correctly
// workspace_id properly rejected on get/create/update/delete
// Native create uses isProduction without NG body injection
// Native delete routes by environment_idCode Implementation: const fmeEnvironmentCreateSchema: BodySchema = {
description:
"Create an FME environment in a project. Requires org_id+project_id. name is required (max 15 characters). isProduction is optional (default false).",
fields: [
{ name: "name", type: "string", required: true, description: "Environment name (unique in the project; max 15 characters)" },
{ name: "isProduction", type: "boolean", required: false, description: "Whether this is a production environment. Optional; defaults to false on the backend if omitted." },
],
};Review Comments AddressedAll feedback from @puthrayaharness has been addressed:
DocumentationREADME accurately documents the native-only pattern: - **`fme_environment`** — `list` is dual-mode (`workspace_id` or `org_id`+`project_id`). `get`/`create`/`update`/`delete` require `org_id`+`project_id` and call `/fme/api/v4/environments`. List pagination: optional `offset`/`limit` (max 100; `harness_list` `size` maps to `limit`); response envelope `{data, limit, offset, totalCount}` is promoted to `items`/`total`. Create/update accept `isProduction`. Update is JSON Merge Patch; `name` and `isProduction` are not clearable. Name max 15 characters.RecommendationThis PR is ready to merge. The implementation is clean, well-tested, follows all architectural patterns, and all review feedback has been addressed. The native-only constraint for get/create/update/delete operations is clearly documented and consistently enforced. |


Description
Follow-up to #806 for remaining FME environment ops.
#806 dual-moded list only (
workspace_idororg_id+project_id). MCP never had get/create/update/delete onworkspace_id, so those four ops are Harness-native only. This PR does not invent a legacy Split v2 MCP contract (those Admin APIs exist; we are not exposing them).Dual-mode routing — this PR only
workspace_id)org_id+project_id)fme_environmentNative contracts
fmeV4PaginatedListExtract(data→items,totalCount→total) withoffset/limit(harness_listsizemaps tolimit).GET /fme/api/v4/environments/{environment_id}(UUID from list, not the env name).POST /fme/api/v4/environmentsbody{ name, isProduction? }(CreateEnvironmentRequest). Name max 15 characters.productionis accepted as an alias forisProduction.skipScopeBodyInjectionso NGorgIdentifier/projectIdentifierare not injected.PATCHJSON Merge Patch{ name?, isProduction? }. Neither field is clearable (omit to keep).DELETE /fme/api/v4/environments/{id}. Backend returns 400hasDependentswhile SDK API keys (always created byEnvironmentStarterKit), flags, or segments remain. MCP has no v4 token resource and does not auto-delete keys.workspace_idon get/create/update/delete throws: Harness-native (org_id/project_id) only — MCP never supportedworkspace_idfor this operation (list remains dual-mode).Key implementation changes
src/registry/toolsets/feature-flags.tsplus tests/README.src/registry/extractors.ts—fmeV4PaginatedListExtractused by native environment list (same helper as traffic type / rollout status lists).resolveNativeOnlyEnvironmentRoutefor the four new ops. List still usesresolveFmeDualMode.fme_environmentget/create/update/delete. Native list envelope/pagination documented without citing other PR numbers.registry/index.ts,types.ts, or prompt changes.Type of Change
Checklist
tests/registry/fme-environment-native-only.test.ts+tests/registry/feature-flags.test.tspnpm docs:check(README matrix matches registry)Coding Standards (registry-driven MCP model)
server.registerTool()calls — existingfeature-flagstoolset extendedoperationPolicyon every new/changed endpointsrc/registry/extractors.tsidentifierFieldsandscopedeclaredconsole.log()insrc/Test plan
workspace_idrejected on get/create/update/deletehasDependentsuntil starter-kit SDK keys are removed (no MCP token API)