@rui.branco/1password-mcp 0.1.4 → 0.1.5

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 (2) hide show
  1. package/index.js +113 -36
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -522,22 +522,22 @@ const TOOL_DEFINITIONS = [
522
522
  {
523
523
  name: "op_update_item",
524
524
  description:
525
- "Update an existing item. Patch fields by title — e.g. to change the password on 'GitHub', pass fields: [{title: 'password', value: 'new-pwd'}]. To add a new field, include its type. Omitting fields leaves them untouched. Can also rename the item (title) or replace its tags.",
525
+ "Update any part of an existing item — title, category, fields, tags, websites, sections, or notes. Omitted parameters are preserved. Fields are patched by title (existing fields match case-insensitively; new fields require `type`). Tags, websites, and sections are REPLACED when passed.",
526
526
  inputSchema: {
527
527
  type: "object",
528
528
  properties: {
529
529
  vault: { type: "string", description: "Vault id or title." },
530
530
  item: { type: "string", description: "Item id or title to update." },
531
531
  title: { type: "string", description: "New title (optional)." },
532
- tags: {
533
- type: "array",
534
- items: { type: "string" },
535
- description: "Replace the item's tag list (optional).",
532
+ category: {
533
+ type: "string",
534
+ description:
535
+ "New category (rare). One of Login, SecureNote, Password, ApiCredentials, Database, Server, Email, Identity, CreditCard, etc.",
536
536
  },
537
537
  fields: {
538
538
  type: "array",
539
539
  description:
540
- "Field patches: [{title, value, type?, sectionId?}]. Existing fields are matched by title (case-insensitive) and their values replaced. New fields require `type`.",
540
+ "Field patches: [{title, value, type?, sectionId?}]. Existing fields matched by title have their values replaced. New fields require `type` (Text | Concealed | Totp | Email | Url | Phone).",
541
541
  items: {
542
542
  type: "object",
543
543
  properties: {
@@ -549,6 +549,46 @@ const TOOL_DEFINITIONS = [
549
549
  required: ["title", "value"],
550
550
  },
551
551
  },
552
+ tags: {
553
+ type: "array",
554
+ items: { type: "string" },
555
+ description:
556
+ "Replace the tag list. Omit to preserve existing tags; pass [] to clear.",
557
+ },
558
+ websites: {
559
+ type: "array",
560
+ description:
561
+ "Replace the website list. Each website is {url, label?, autofillBehavior?}. Omit to preserve existing websites.",
562
+ items: {
563
+ type: "object",
564
+ properties: {
565
+ url: { type: "string" },
566
+ label: { type: "string" },
567
+ autofillBehavior: {
568
+ type: "string",
569
+ description: "'AnywhereOnWebsite' (default) or 'Never'.",
570
+ },
571
+ },
572
+ required: ["url"],
573
+ },
574
+ },
575
+ sections: {
576
+ type: "array",
577
+ description: "Replace the section list. Each section is {title, id?}.",
578
+ items: {
579
+ type: "object",
580
+ properties: {
581
+ title: { type: "string" },
582
+ id: { type: "string" },
583
+ },
584
+ required: ["title"],
585
+ },
586
+ },
587
+ notes: {
588
+ type: "string",
589
+ description:
590
+ "Replace the notesPlain field. Omit to preserve existing notes.",
591
+ },
552
592
  instance: {
553
593
  type: "string",
554
594
  description: "Instance name. Uses default if omitted.",
@@ -952,44 +992,81 @@ async function updateItemHandler(args) {
952
992
  const current = await client.items.get(vault.id, itemRef.id);
953
993
  const updated = { ...current };
954
994
 
995
+ // --- title (rename) ---
955
996
  if (args.title) updated.title = args.title;
997
+
998
+ // --- category (rarely changed, but the SDK allows it) ---
999
+ if (args.category) {
1000
+ const cat = sdk.ItemCategory[args.category];
1001
+ if (!cat) throw new Error(`Unknown category "${args.category}".`);
1002
+ updated.category = cat;
1003
+ }
1004
+
1005
+ // --- tags (replace when passed; preserved when omitted) ---
956
1006
  if (args.tags) updated.tags = args.tags;
957
1007
 
958
- if (Array.isArray(args.fields) && args.fields.length > 0) {
959
- const existing = current.fields || [];
960
- const patchesByTitle = new Map(
961
- args.fields.map((p) => [p.title.toLowerCase(), p]),
962
- );
1008
+ // --- websites (replace when passed; preserved when omitted) ---
1009
+ if (Array.isArray(args.websites)) {
1010
+ updated.websites = args.websites.map((w) => ({
1011
+ url: w.url,
1012
+ label: w.label || "website",
1013
+ autofillBehavior:
1014
+ w.autofillBehavior === "Never"
1015
+ ? sdk.AutofillBehavior.Never
1016
+ : sdk.AutofillBehavior.AnywhereOnWebsite,
1017
+ }));
1018
+ }
963
1019
 
964
- // Patch existing fields in place, preserving id/type/sectionId
965
- const patchedExisting = existing.map((f) => {
966
- const patch = patchesByTitle.get((f.title || "").toLowerCase());
967
- if (!patch) return f;
968
- patchesByTitle.delete((f.title || "").toLowerCase());
969
- return { ...f, value: patch.value };
970
- });
1020
+ // --- sections (replace when passed; preserved when omitted) ---
1021
+ if (Array.isArray(args.sections)) {
1022
+ updated.sections = args.sections.map((s) => ({
1023
+ id: s.id || s.title.toLowerCase().replace(/\s+/g, "_"),
1024
+ title: s.title,
1025
+ }));
1026
+ }
971
1027
 
972
- // Remaining patches = new fields to add (must specify type)
973
- const additions = [];
974
- for (const patch of patchesByTitle.values()) {
975
- if (!patch.type) {
976
- throw new Error(
977
- `Field "${patch.title}" doesn't exist on the item — pass a 'type' to add it as a new field.`,
978
- );
979
- }
980
- const ft = sdk.ItemFieldType[patch.type];
981
- if (!ft) throw new Error(`Unknown field type "${patch.type}".`);
982
- additions.push({
983
- id: patch.title.toLowerCase().replace(/\s+/g, "_"),
984
- title: patch.title,
985
- fieldType: ft,
986
- value: patch.value,
987
- sectionId: patch.sectionId,
988
- });
1028
+ // --- fields (patch by title, add new ones with explicit type) ---
1029
+ const nextFields = [...(current.fields || [])];
1030
+ const fieldIndexByTitle = new Map(
1031
+ nextFields.map((f, idx) => [(f.title || "").toLowerCase(), idx]),
1032
+ );
1033
+
1034
+ function upsertField({ title, value, type, sectionId }) {
1035
+ const key = title.toLowerCase();
1036
+ const existingIdx = fieldIndexByTitle.get(key);
1037
+ if (existingIdx !== undefined) {
1038
+ nextFields[existingIdx] = { ...nextFields[existingIdx], value };
1039
+ return;
1040
+ }
1041
+ if (!type) {
1042
+ throw new Error(
1043
+ `Field "${title}" doesn't exist on the item — pass a 'type' to add it as a new field.`,
1044
+ );
989
1045
  }
990
- updated.fields = [...patchedExisting, ...additions];
1046
+ const ft = sdk.ItemFieldType[type];
1047
+ if (!ft) throw new Error(`Unknown field type "${type}".`);
1048
+ const added = {
1049
+ id: title.toLowerCase().replace(/\s+/g, "_"),
1050
+ title,
1051
+ fieldType: ft,
1052
+ value,
1053
+ };
1054
+ if (sectionId) added.sectionId = sectionId;
1055
+ fieldIndexByTitle.set(key, nextFields.length);
1056
+ nextFields.push(added);
1057
+ }
1058
+
1059
+ if (Array.isArray(args.fields)) {
1060
+ for (const patch of args.fields) upsertField(patch);
991
1061
  }
992
1062
 
1063
+ // --- notes: stored as a 'notesPlain' Text field, so patch it the same way ---
1064
+ if (args.notes !== undefined) {
1065
+ upsertField({ title: "notesPlain", value: args.notes, type: "Text" });
1066
+ }
1067
+
1068
+ updated.fields = nextFields;
1069
+
993
1070
  const result = await client.items.put(updated);
994
1071
  return `Updated item "${result.title}" (id: ${result.id}) in vault "${vault.title}".`;
995
1072
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rui.branco/1password-mcp",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "1Password MCP server for Claude Code - list vaults and items, get secrets, generate passwords, manage items via service accounts. Multi-instance like jira-mcp.",
5
5
  "main": "index.js",
6
6
  "bin": {