[PM-35353] feat: support custom fields, organizationId and collectionIds on items#177
Conversation
|
Thank you for your contribution! We've added this to our internal tracking system for review. Details on our contribution process can be found here: https://contributing.bitwarden.com/contributing/pull-requests/community-pr-process. |
- fix: use fileURLToPath + realpathSync for main module detection (PR bitwarden#168) - feat: support custom fields, organizationId and collectionIds on create/edit item (PR bitwarden#177) - docs: remove root CLAUDE.md (context moved to .claude/CLAUDE.md and memory)
- fix: use fileURLToPath + realpathSync for main module detection (PR bitwarden#168) - feat: support custom fields, organizationId and collectionIds on create/edit item (PR bitwarden#177) - docs: remove root CLAUDE.md (context moved to .claude/CLAUDE.md and memory)
The `create_item` and `edit_item` tools currently expose only name, type,
login/card/identity/secureNote and folderId. This forces MCP consumers to
drop down to the `bw` CLI directly whenever they need to:
- Create or update a vault item with custom fields
- Put an item inside an organization + collection
- Rename or migrate a custom field on an existing item
The underlying `bw` CLI already understands all three (fields are part of
the item JSON; organizationId/collectionIds live in the same object; the
CLI also needs --organizationid as a flag at create time), so this PR just
surfaces them through the MCP schema and threads them through the handler.
Changes
-------
- src/utils/types.ts: extend BitwardenItem with fields, organizationId,
collectionIds.
- src/schemas/cli.ts: new customFieldSchema (name + optional value + type
0..3) and extensions to createItemSchema/editItemSchema.
- src/handlers/cli.ts:
* handleCreateItem copies organizationId/collectionIds/fields into the
JSON item and appends `--organizationid <id>` when present.
* handleEditItem updates organizationId/collectionIds and replaces the
fields array on the existing item when one is supplied (callers that
want to merge should read the item first and merge client-side).
- src/tools/cli.ts: exposes the new parameters to MCP clients for both
create_item and edit_item.
Backward compatible: all new parameters are optional and existing calls
behave identically when they're omitted.
b816ee2 to
4672c77
Compare
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #177 +/- ##
==========================================
- Coverage 51.92% 51.02% -0.91%
==========================================
Files 12 12
Lines 909 929 +20
Branches 197 208 +11
==========================================
+ Hits 472 474 +2
- Misses 387 401 +14
- Partials 50 54 +4 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
withinfocus
left a comment
There was a problem hiding this comment.
Thanks for the contribution! One consistency suggestion and one correction for how orgs and collections work with edits.
| // Folder ID to assign the item to | ||
| folderId: z.string().optional(), | ||
| // Organization ID (required to create items shared with an organization) | ||
| organizationId: z.string().optional(), |
There was a problem hiding this comment.
❌ The new fields use z.string().optional() and z.array(z.string()).optional(), which permit empty strings. The rest of the codebase enforces non-empty strings on the same identifiers via .min(1, '...'):
editItemCollectionsSchema(line 469) --organizationId: z.string().min(1, ...)andcollectionIds: z.array(z.string().min(1, 'Collection ID cannot be empty'))moveSchema(line 479) -- same patterncreateOrgCollectionSchema(line 443) -- same pattern
With the current PR code, { organizationId: "" } validates successfully and then becomes the literal argument --organizationid "" passed to bw, producing a confusing CLI error rather than a clear validation message. Empty strings in collectionIds produce the same class of issue.
Suggested fix (apply to both createItemSchema and editItemSchema):
organizationId: z.string().min(1, 'Organization ID cannot be empty').optional(),
collectionIds: z
.array(z.string().min(1, 'Collection ID cannot be empty'))
.optional(),Same change at src/schemas/cli.ts:419 for editItemSchema.
| if (name !== undefined) existingItem.name = name; | ||
| if (notes !== undefined) existingItem.notes = notes; | ||
| if (folderId !== undefined) existingItem.folderId = folderId; | ||
| if (organizationId !== undefined) |
There was a problem hiding this comment.
❌ The mechanism for moving an item from a personal vault to an organization (or between organizations) is bw move <itemid> <organizationid> [encodedJson]. handleMove already exposes this. These organization and collection changes won't be applied.
- Drop
organizationIdfromeditItemSchemaentirely. IfcollectionIdsis meant to manage org-collection membership for an item, drop it too. - If
organizationId/collectionIdsneed to remain onedit_itemfor some validated use case (please share a CLI invocation that actually works), then at minimum mirrorhandleCreateItemand pass--organizationidthrough tobw edit item, and verify with the CLI that the change takes effect end-to-end.
Summary
The
create_itemandedit_itemtools currently expose onlyname,type,login/card/identity/secureNoteandfolderId. This forces MCP consumers to drop down to thebwCLI directly whenever they need to:The underlying
bwCLI already understands all three (fields are part of the item JSON;organizationId/collectionIdslive in the same object; the CLI also needs--organizationidas a flag at create time), so this PR just surfaces them through the MCP schema and threads them through the handler.Changes
src/utils/types.ts— extendBitwardenItemwithfields,organizationId,collectionIds.src/schemas/cli.ts— newcustomFieldSchema(name + optional value + type 0..3) and extensions tocreateItemSchema/editItemSchema.src/handlers/cli.ts—handleCreateItemcopiesorganizationId/collectionIds/fieldsinto the JSON item and appends--organizationid <id>when present.handleEditItemupdatesorganizationId/collectionIdsand replaces the fields array on the existing item when one is supplied (callers that want to merge should read the item first and merge client-side).src/tools/cli.ts— exposes the new parameters to MCP clients for bothcreate_itemandedit_item.Backward compatible: all new parameters are optional; existing calls behave identically when they're omitted.
Motivation
Encountered while using the MCP server from an assistant to populate Bitwarden with SSH credentials that need a
muxterm_init_path-style custom field (for a tool that reads the field and auto-cd's into that directory after login). Without this PR, the only way to create the items with the custom field is to shell out tobw edit item <id> <base64>directly or to wrap the MCP in a consumer-specific API.Test plan
npm run buildcompiles cleanly (no TypeScript errors)Initial_Pathfield lands in the correct collection, readable back viaget item)tests/cli-commands.spec.tshas pre-existing test timeouts in my environment (unrelated tests, no change in pass/fail counts from my diff). Happy to adjust if CI flags anything new.