@hiai-gg/docsmint 0.9.2 → 0.10.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.
@@ -1,22 +1,6 @@
1
1
  // @bun
2
- var __defProp = Object.defineProperty;
3
- var __returnValue = (v) => v;
4
- function __exportSetter(name, newValue) {
5
- this[name] = __returnValue.bind(null, newValue);
6
- }
7
- var __export = (target, all) => {
8
- for (var name in all)
9
- __defProp(target, name, {
10
- get: all[name],
11
- enumerable: true,
12
- configurable: true,
13
- set: __exportSetter.bind(all, name)
14
- });
15
- };
16
-
17
2
  // ../mcp-server/src/server.ts
18
3
  import { McpServer } from "@modelcontextprotocol/server";
19
- import { z as z14 } from "zod";
20
4
 
21
5
  // dist/client.js
22
6
  var docsApiErrorBrand = Symbol.for("io.github.hiai-gg.docsmint.DocsApiError");
@@ -195,6 +179,15 @@ class DocsClient {
195
179
  async deleteTag(id, context) {
196
180
  await this.request("DELETE", `/api/tags/${encodeURIComponent(id)}`, undefined, context);
197
181
  }
182
+ async listTrash(context) {
183
+ return this.request("GET", "/api/trash", undefined, context);
184
+ }
185
+ async restoreTrashedDocument(id, context) {
186
+ return this.request("POST", `/api/trash/documents/${encodeURIComponent(id)}/restore`, undefined, context);
187
+ }
188
+ async permanentlyDeleteDocument(id, context) {
189
+ return this.request("DELETE", `/api/trash/documents/${encodeURIComponent(id)}`, undefined, context);
190
+ }
198
191
  async addTagToDoc(documentId, tagId, context) {
199
192
  await this.request("POST", `/api/documents/${encodeURIComponent(documentId)}/tags`, { json: { tagId } }, context);
200
193
  }
@@ -577,7 +570,7 @@ var RESOURCE_PERMISSIONS = new Set([
577
570
  "edit",
578
571
  "write"
579
572
  ]);
580
- // ../mcp-server/src/lifecycle.ts
573
+ // ../mcp-server/src/compact.ts
581
574
  import { z as z2 } from "zod";
582
575
 
583
576
  // ../mcp-server/src/output-schemas.ts
@@ -755,7 +748,7 @@ var deleteAcknowledgmentSchema = z.looseObject({
755
748
  id: z.string().uuid(),
756
749
  deleted: z.literal(true)
757
750
  });
758
- var toolOutputSchemas = {
751
+ var operationOutputSchemas = {
759
752
  search_documents: z.looseObject({
760
753
  items: z.array(searchResultSchema),
761
754
  total: z.number(),
@@ -795,181 +788,197 @@ var toolOutputSchemas = {
795
788
  delete_document: deleteAcknowledgmentSchema,
796
789
  delete_folder: deleteAcknowledgmentSchema,
797
790
  delete_category: deleteAcknowledgmentSchema,
798
- restore_document_version: documentSchema
791
+ restore_document_version: documentSchema,
792
+ create_tag: tagSchema,
793
+ update_tag: tagSchema,
794
+ delete_tag: deleteAcknowledgmentSchema,
795
+ add_tag_to_document: z.looseObject({ documentId: z.string().uuid(), tagId: z.string().uuid(), assigned: z.literal(true) }),
796
+ remove_tag_from_document: z.looseObject({ documentId: z.string().uuid(), tagId: z.string().uuid(), removed: z.literal(true) }),
797
+ update_folder: folderSchema,
798
+ update_category: categorySchema,
799
+ list_trash: z.looseObject({ documents: z.array(z.looseObject({ id: z.string().uuid(), title: z.string(), deletedAt: z.string(), purgeAfter: z.string().nullable() })), folders: z.array(z.unknown()) }),
800
+ restore_trashed_document: z.looseObject({ success: z.literal(true) }),
801
+ permanently_delete_document: deleteAcknowledgmentSchema
802
+ };
803
+ var variant = (operation, result) => z.object({ operation: z.literal(operation), result });
804
+ var toolOutputSchemas = {
805
+ delete_document: operationOutputSchemas.delete_document,
806
+ delete_folder: operationOutputSchemas.delete_folder,
807
+ delete_category: operationOutputSchemas.delete_category,
808
+ delete_tag: operationOutputSchemas.delete_tag,
809
+ create_snapshot: operationOutputSchemas.create_snapshot,
810
+ restore_document_version: operationOutputSchemas.restore_document_version,
811
+ get_document_index_status: operationOutputSchemas.get_document_index_status,
812
+ refresh_document_index: operationOutputSchemas.refresh_document_index,
813
+ list_trash: operationOutputSchemas.list_trash,
814
+ restore_trashed_document: operationOutputSchemas.restore_trashed_document,
815
+ permanently_delete_document: operationOutputSchemas.permanently_delete_document,
816
+ find_documents: z.union([
817
+ variant("list", operationOutputSchemas.list_documents),
818
+ variant("search", operationOutputSchemas.search_documents)
819
+ ]),
820
+ read_document: z.union([
821
+ variant("detail", operationOutputSchemas.get_document),
822
+ variant("markdown", operationOutputSchemas.export_document),
823
+ variant("versions", operationOutputSchemas.get_version_history)
824
+ ]),
825
+ save_document: z.union([
826
+ variant("create", operationOutputSchemas.create_document),
827
+ variant("update", operationOutputSchemas.update_document)
828
+ ]),
829
+ list_workspace_structure: z.union([
830
+ variant("folders", operationOutputSchemas.list_folders),
831
+ variant("categories", operationOutputSchemas.list_categories),
832
+ variant("tags", operationOutputSchemas.list_tags)
833
+ ]),
834
+ save_folder: z.union([
835
+ variant("create", operationOutputSchemas.create_folder),
836
+ variant("update", operationOutputSchemas.update_folder)
837
+ ]),
838
+ save_category: z.union([
839
+ variant("create", operationOutputSchemas.create_category),
840
+ variant("update", operationOutputSchemas.update_category)
841
+ ]),
842
+ save_tag: z.union([
843
+ variant("create", operationOutputSchemas.create_tag),
844
+ variant("update", operationOutputSchemas.update_tag)
845
+ ]),
846
+ set_document_tag: z.union([
847
+ variant("add", operationOutputSchemas.add_tag_to_document),
848
+ variant("remove", operationOutputSchemas.remove_tag_from_document)
849
+ ]),
850
+ explore_graph: z.union([
851
+ variant("neighbors", operationOutputSchemas.get_related_documents),
852
+ variant("search", operationOutputSchemas.search_knowledge_graph)
853
+ ])
799
854
  };
800
855
 
801
- // ../mcp-server/src/lifecycle.ts
802
- function unsupported(name) {
803
- throw new Error(`The injected legacy MCP client does not support ${name}; use a public DocsClient.`);
856
+ // ../mcp-server/src/compact.ts
857
+ var uuid = z2.string().uuid().describe("UUID returned by the corresponding list or read operation.");
858
+ var text = z2.string().min(1).describe("Non-empty human-readable name or title.");
859
+ var title = z2.string().min(1).max(500).describe("Document title, from 1 to 500 characters.");
860
+ var content = z2.string().describe("Markdown document content; an empty string clears the content on update.");
861
+ var read = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
862
+ var write = { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false };
863
+ var destructive = { ...write, destructiveHint: true };
864
+ function required(value, name) {
865
+ if (!value)
866
+ throw new Error(`The injected legacy MCP client does not support ${name}; use a public DocsClient.`);
867
+ return value;
804
868
  }
805
- var annotations = { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: false };
806
- function registerLifecycleCapabilities(server, client, wrap) {
807
- const deletions = [
808
- {
809
- name: "delete_document",
810
- description: "Move an existing document to trash; this is a soft delete and does not permanently purge its content or version history. Requires write access in the active workspace/category. Returns {id, deleted:true}. Use only when the user intends to delete it.",
811
- action: (id) => client.deleteDocument ? client.deleteDocument(id) : unsupported("delete_document"),
812
- idDescription: "UUID of the document to move to trash; obtain it from search_documents, list_documents, or get_document."
813
- },
814
- {
815
- name: "delete_folder",
816
- description: "Delete a folder while preserving its documents. Direct child folders and documents are detached according to the server folder rules, and reindexing is queued for affected documents. Requires write access in the active workspace/category. Returns {id, deleted:true}.",
817
- action: (id) => client.deleteFolder ? client.deleteFolder(id) : unsupported("delete_folder"),
818
- idDescription: "UUID of the folder to delete; obtain it from list_folders. This detaches, but does not delete, the documents inside it."
819
- },
820
- {
821
- name: "delete_category",
822
- description: "Delete a category and detach its folders and documents without deleting their content. Requires full workspace write access; category-scoped credentials cannot delete any category, including their configured one. Returns {id, deleted:true}.",
823
- action: (id) => client.deleteCategory ? client.deleteCategory(id) : unsupported("delete_category"),
824
- idDescription: "UUID of the category to delete; obtain it from list_categories using a workspace-scoped credential."
869
+ function registerCompactCapabilities(server, client, wrap) {
870
+ function register(name, description, inputSchema, annotations, handler) {
871
+ server.registerTool(name, { description, inputSchema, outputSchema: toolOutputSchemas[name], annotations }, wrap(name, handler, toolOutputSchemas[name]));
872
+ }
873
+ register("find_documents", "Find readable documents in the active scope. Use mode=list for paginated browsing by folder or tag UUID; use mode=search for hybrid text and semantic retrieval with tag names.", z2.discriminatedUnion("mode", [
874
+ z2.strictObject({ mode: z2.literal("list").describe("Select the list operation explicitly."), folderId: uuid.optional(), tag: uuid.optional(), page: z2.number().int().min(1).optional().describe("One-based page number; defaults to the API first page."), limit: z2.number().int().min(1).max(1000).optional().describe("Maximum documents per page, up to 1000.") }),
875
+ z2.strictObject({ mode: z2.literal("search").describe("Select the search operation explicitly."), query: text.describe("Text to search in the original language."), folder: z2.string().optional().describe("Optional folder UUID filter for search."), tags: z2.array(z2.string()).optional().describe("Optional tag names; all supplied names must match."), limit: z2.number().int().min(1).max(100).optional().describe("Maximum results to return, up to 100.") })
876
+ ]), read, async (input) => input.mode === "list" ? { operation: "list", result: await client.listDocuments(input) } : { operation: "search", result: await client.search(input) });
877
+ register("read_document", "Read one document by UUID. Choose detail for content and metadata, markdown for portable export, or versions for saved revisions and snapshots. All views are read-only.", z2.discriminatedUnion("view", [
878
+ z2.strictObject({ view: z2.literal("detail").describe("Select the detail operation explicitly."), id: uuid }),
879
+ z2.strictObject({ view: z2.literal("markdown").describe("Select the markdown operation explicitly."), id: uuid }),
880
+ z2.strictObject({ view: z2.literal("versions").describe("Select the versions operation explicitly."), id: uuid, onlySnapshots: z2.boolean().optional().describe("When true, return only named snapshots.") })
881
+ ]), read, async (input) => {
882
+ if (input.view === "detail")
883
+ return { operation: "detail", result: await client.getDocument(input.id) };
884
+ if (input.view === "markdown")
885
+ return { operation: "markdown", result: await client.exportDocument(input.id) };
886
+ return { operation: "versions", result: await client.getVersionHistory(input.id, input.onlySnapshots) };
887
+ });
888
+ register("save_document", "Create a new document or update an existing document. action=create requires write access; action=update requires edit access for content, and placement changes may require write access. Content or placement changes queue normal indexing.", z2.discriminatedUnion("action", [
889
+ z2.strictObject({ action: z2.literal("create").describe("Select the create operation explicitly."), title: title.optional(), content: content.optional(), folderId: uuid.optional(), categoryId: uuid.nullable().optional().describe("Optional category UUID; null clears the explicit category.") }),
890
+ z2.strictObject({ action: z2.literal("update").describe("Select the update operation explicitly."), id: uuid, title: title.optional(), content: content.optional(), folderId: uuid.nullable().optional().describe("Optional folder UUID; null clears the placement on update."), categoryId: uuid.nullable().optional().describe("Optional category UUID; null clears the explicit category.") }).refine((value) => value.title !== undefined || value.content !== undefined || value.folderId !== undefined || value.categoryId !== undefined)
891
+ ]), destructive, async (input) => {
892
+ if (input.action === "create") {
893
+ const { action: _action2, ...data2 } = input;
894
+ return { operation: "create", result: await client.createDocument(data2) };
825
895
  }
826
- ];
827
- for (const tool of deletions) {
828
- server.registerTool(tool.name, {
829
- description: tool.description,
830
- annotations,
831
- inputSchema: z2.object({ id: z2.string().uuid().describe(tool.idDescription) }),
832
- outputSchema: toolOutputSchemas[tool.name]
833
- }, wrap(tool.name, async ({ id }) => {
834
- await tool.action(id);
835
- return { id, deleted: true };
836
- }));
837
- }
838
- server.registerTool("restore_document_version", {
839
- description: "Restore content for an existing document from a version or named snapshot returned by get_version_history. Requires edit access. The server saves current content in history, records the restoration, and queues indexing. Returns the updated document; it does not recover a trashed document or change folder/category placement.",
840
- annotations,
841
- inputSchema: z2.object({
842
- documentId: z2.string().uuid().describe("UUID of the document whose content should be restored; it must be visible in the active workspace or category."),
843
- versionId: z2.string().uuid().describe("UUID of a version belonging to this document, from get_version_history. Use the version ID, not a snapshot label.")
844
- }),
845
- outputSchema: toolOutputSchemas.restore_document_version
846
- }, wrap("restore_document_version", async ({ documentId, versionId }) => client.restoreDocumentVersion ? client.restoreDocumentVersion(documentId, versionId) : unsupported("restore_document_version")));
896
+ const { action: _action, id, ...data } = input;
897
+ return { operation: "update", result: await client.updateDocument(id, data) };
898
+ });
899
+ register("delete_document", "Move a writable document to trash without purging content or versions. Use only on an explicit delete request; permanently_delete_document is a separate irreversible action.", z2.strictObject({ id: uuid }), destructive, async ({ id }) => {
900
+ await required(client.deleteDocument, "delete_document")(id);
901
+ return { id, deleted: true };
902
+ });
903
+ register("list_workspace_structure", "List visible folders, categories, or tags in the active workspace or category scope. Set kind=folders to inspect root folders or children of parentId.", z2.discriminatedUnion("kind", [
904
+ z2.strictObject({ kind: z2.literal("folders").describe("Select the folders operation explicitly."), parentId: uuid.optional() }),
905
+ z2.strictObject({ kind: z2.literal("categories").describe("Select the categories operation explicitly.") }),
906
+ z2.strictObject({ kind: z2.literal("tags").describe("Select the tags operation explicitly.") })
907
+ ]), read, async (input) => {
908
+ if (input.kind === "folders")
909
+ return { operation: "folders", result: await client.listFolders({ parentId: input.parentId }) };
910
+ if (input.kind === "categories")
911
+ return { operation: "categories", result: await client.listCategories() };
912
+ return { operation: "tags", result: await client.listTags() };
913
+ });
914
+ register("save_folder", "Create or update a folder. action=update can rename or move an existing folder; the API enforces category boundaries and queues affected documents for reindexing.", z2.discriminatedUnion("action", [
915
+ z2.strictObject({ action: z2.literal("create").describe("Select the create operation explicitly."), name: text.max(255), parentId: uuid.nullable().optional().describe("Optional parent folder UUID; null selects the root."), categoryId: uuid.nullable().optional().describe("Optional category UUID; null clears the explicit category.") }),
916
+ z2.strictObject({ action: z2.literal("update").describe("Select the update operation explicitly."), id: uuid, name: text.max(255).optional(), parentId: uuid.nullable().optional().describe("Optional parent folder UUID; null selects the root."), categoryId: uuid.nullable().optional().describe("Optional category UUID; null clears the explicit category."), order: z2.number().int().nonnegative().optional().describe("New non-negative display order.") }).refine((value) => value.name !== undefined || value.parentId !== undefined || value.categoryId !== undefined || value.order !== undefined)
917
+ ]), destructive, async (input) => {
918
+ if (input.action === "create") {
919
+ const { action: _action2, ...data2 } = input;
920
+ return { operation: "create", result: await client.createFolder(data2) };
921
+ }
922
+ const { action: _action, id, ...data } = input;
923
+ return { operation: "update", result: await required(client.updateFolder, "update_folder")(id, data) };
924
+ });
925
+ register("delete_folder", "Delete a folder while preserving its documents; child folders and documents are detached under the API rules. Requires write access.", z2.strictObject({ id: uuid }), destructive, async ({ id }) => {
926
+ await required(client.deleteFolder, "delete_folder")(id);
927
+ return { id, deleted: true };
928
+ });
929
+ register("save_category", "Create or update a workspace category. Full workspace write access is required; category-scoped credentials cannot manage categories.", z2.discriminatedUnion("action", [
930
+ z2.strictObject({ action: z2.literal("create").describe("Select the create operation explicitly."), name: text.max(255) }),
931
+ z2.strictObject({ action: z2.literal("update").describe("Select the update operation explicitly."), id: uuid, name: text.max(255).optional(), order: z2.number().int().nonnegative().optional().describe("New non-negative display order.") }).refine((value) => value.name !== undefined || value.order !== undefined)
932
+ ]), destructive, async (input) => {
933
+ if (input.action === "create")
934
+ return { operation: "create", result: await client.createCategory({ name: input.name }) };
935
+ const { action: _action, id, ...data } = input;
936
+ return { operation: "update", result: await required(client.updateCategory, "update_category")(id, data) };
937
+ });
938
+ register("delete_category", "Delete a workspace category and detach its documents without deleting them. Requires full workspace write access; category-scoped credentials are denied.", z2.strictObject({ id: uuid }), destructive, async ({ id }) => {
939
+ await required(client.deleteCategory, "delete_category")(id);
940
+ return { id, deleted: true };
941
+ });
942
+ register("save_tag", "Create or update a workspace tag. Full workspace write access is required; renaming or recoloring a tag causes affected documents to be reindexed.", z2.discriminatedUnion("action", [
943
+ z2.strictObject({ action: z2.literal("create").describe("Select the create operation explicitly."), name: text.max(100), color: z2.string().max(20).optional().describe("Optional tag color, at most 20 characters.") }),
944
+ z2.strictObject({ action: z2.literal("update").describe("Select the update operation explicitly."), id: uuid, name: text.max(100).optional(), color: z2.string().max(20).optional().describe("Optional tag color, at most 20 characters.") }).refine((value) => value.name !== undefined || value.color !== undefined)
945
+ ]), destructive, async (input) => {
946
+ if (input.action === "create")
947
+ return { operation: "create", result: await required(client.createTag, "create_tag")({ name: input.name, color: input.color }) };
948
+ const { action: _action, id, ...data } = input;
949
+ return { operation: "update", result: await required(client.updateTag, "update_tag")(id, data) };
950
+ });
951
+ register("delete_tag", "Delete a workspace tag and remove its document assignments. Full workspace write access is required; documents themselves remain.", z2.strictObject({ id: uuid }), destructive, async ({ id }) => {
952
+ await required(client.deleteTag, "delete_tag")(id);
953
+ return { id, deleted: true };
954
+ });
955
+ register("set_document_tag", "Add or remove one existing tag assignment on a readable document. Requires edit access to that document; action=remove preserves the tag itself.", z2.strictObject({ action: z2.enum(["add", "remove"]).describe("Add or remove exactly one tag assignment."), documentId: uuid, tagId: uuid }), destructive, async ({ action, documentId, tagId }) => {
956
+ if (action === "add") {
957
+ await required(client.addTagToDocument, "add_tag_to_document")(documentId, tagId);
958
+ return { operation: "add", result: { documentId, tagId, assigned: true } };
959
+ }
960
+ await required(client.removeTagFromDocument, "remove_tag_from_document")(documentId, tagId);
961
+ return { operation: "remove", result: { documentId, tagId, removed: true } };
962
+ });
963
+ register("create_snapshot", "Save a named snapshot of an existing document before a planned change. The snapshot can later be restored with restore_document_version.", z2.strictObject({ documentId: uuid, label: text.max(200).describe("Snapshot label, from 1 to 200 characters."), description: z2.string().max(1000).optional().describe("Optional snapshot note, at most 1000 characters.") }), write, async ({ documentId, label, description }) => client.createSnapshot(documentId, { label, description }));
964
+ register("restore_document_version", "Restore content from a version or snapshot listed by read_document(view=versions). This changes current content and queues indexing; it does not restore a trashed document.", z2.strictObject({ documentId: uuid, versionId: uuid }), destructive, async ({ documentId, versionId }) => required(client.restoreDocumentVersion, "restore_document_version")(documentId, versionId));
965
+ register("explore_graph", "Explore graph relations from readable seed documents. mode=neighbors traverses one document without a query; mode=search ranks relations from one or more seed IDs with optional query text.", z2.discriminatedUnion("mode", [
966
+ z2.strictObject({ mode: z2.literal("neighbors").describe("Select the neighbors operation explicitly."), documentId: uuid, limit: z2.number().int().min(1).max(100).optional().describe("Maximum results to return, up to 100.") }),
967
+ z2.strictObject({ mode: z2.literal("search").describe("Select the search operation explicitly."), docIds: z2.array(uuid).min(1).max(50).describe("One to 50 authorized seed document UUIDs."), query: z2.string().max(2000).optional().describe("Optional graph relevance query, at most 2000 characters."), limit: z2.number().int().min(1).max(100).optional().describe("Maximum results to return, up to 100.") })
968
+ ]), read, async (input) => input.mode === "neighbors" ? { operation: "neighbors", result: await client.getRelatedDocuments(input.documentId, input.limit) } : { operation: "search", result: await client.searchGraph(input) });
969
+ register("get_document_index_status", "Read current indexing and pipeline status for one document without starting work. Use refresh_document_index only when an explicit retry is intended.", z2.strictObject({ documentId: uuid }), read, async ({ documentId }) => client.getDocumentIndexStatus(documentId));
970
+ register("refresh_document_index", "Queue an explicit asynchronous reindex for one document. Routine content and placement changes already schedule indexing; check get_document_index_status first.", z2.strictObject({ documentId: uuid }), write, async ({ documentId }) => client.refreshDocumentIndex(documentId));
971
+ register("list_trash", "List soft-deleted documents visible to the active workspace or category scope. Requires read access and does not restore or purge anything.", z2.strictObject({}), read, async () => required(client.listTrash, "list_trash")());
972
+ register("restore_trashed_document", "Return one soft-deleted document to the active library. This restores the document itself, unlike restore_document_version which changes content.", z2.strictObject({ id: uuid }), write, async ({ id }) => required(client.restoreTrashedDocument, "restore_trashed_document")(id));
973
+ register("permanently_delete_document", "Irreversibly purge a document already in trash, including its version history. Use only on an explicit user request after checking list_trash.", z2.strictObject({ id: uuid }), destructive, async ({ id }) => {
974
+ await required(client.permanentlyDeleteDocument, "permanently_delete_document")(id);
975
+ return { id, deleted: true };
976
+ });
847
977
  }
848
978
 
849
- // ../mcp-server/src/capabilities.ts
979
+ // ../mcp-server/src/prompts-resources.ts
850
980
  import { z as z3 } from "zod";
851
- var capabilityCatalog = {
852
- tools: [
853
- "search_documents",
854
- "get_document",
855
- "create_document",
856
- "update_document",
857
- "list_documents",
858
- "list_folders",
859
- "create_folder",
860
- "create_snapshot",
861
- "get_version_history",
862
- "export_document",
863
- "list_categories",
864
- "create_category",
865
- "list_tags",
866
- "get_related_documents",
867
- "search_knowledge_graph",
868
- "get_document_index_status",
869
- "refresh_document_index",
870
- "delete_document",
871
- "delete_folder",
872
- "delete_category",
873
- "restore_document_version"
874
- ],
875
- prompts: ["organize_workspace", "research_workspace"],
876
- resources: [
877
- "docsmint://guide/editor",
878
- "docsmint://guide/search",
879
- "docsmint://workspace/catalog"
880
- ]
881
- };
882
- function registerExtendedCapabilities(server, client, wrapHandler) {
883
- server.registerTool("list_categories", {
884
- annotations: {
885
- readOnlyHint: true,
886
- destructiveHint: false,
887
- idempotentHint: true,
888
- openWorldHint: false
889
- },
890
- description: "List categories visible in the active workspace or category scope. Requires read access; a category-scoped credential sees only its configured category. Use this before create_document or create_folder when you need an existing category ID.",
891
- inputSchema: z3.object({}),
892
- outputSchema: toolOutputSchemas.list_categories
893
- }, wrapHandler("list_categories", async () => client.listCategories()));
894
- server.registerTool("create_category", {
895
- annotations: {
896
- readOnlyHint: false,
897
- destructiveHint: false,
898
- idempotentHint: false,
899
- openWorldHint: false
900
- },
901
- description: "Create a new category for the active workspace. Requires workspace-level write access; category-scoped credentials cannot create categories. Returns the created category. Use list_categories to inspect existing categories.",
902
- inputSchema: z3.object({
903
- name: z3.string().trim().min(1).max(255).describe("Non-empty display name, up to 255 characters, for example Project notes.")
904
- }),
905
- outputSchema: toolOutputSchemas.create_category
906
- }, wrapHandler("create_category", async (input) => client.createCategory(input)));
907
- server.registerTool("list_tags", {
908
- annotations: {
909
- readOnlyHint: true,
910
- destructiveHint: false,
911
- idempotentHint: true,
912
- openWorldHint: false
913
- },
914
- description: "List tags visible in the active workspace or configured category scope. Requires read access; use returned tag IDs to filter list_documents and returned tag names to filter search_documents.",
915
- inputSchema: z3.object({}),
916
- outputSchema: toolOutputSchemas.list_tags
917
- }, wrapHandler("list_tags", async () => client.listTags()));
918
- server.registerTool("get_related_documents", {
919
- annotations: {
920
- readOnlyHint: true,
921
- destructiveHint: false,
922
- idempotentHint: true,
923
- openWorldHint: false
924
- },
925
- description: "Traverse graph relations from one readable document without a text query. Requires read access and returns related document IDs plus relation metadata. Use search_knowledge_graph to rank graph neighbors with query text, or search_documents for normal hybrid retrieval. Results stay in the active scope and may be empty when graph data is unavailable.",
926
- inputSchema: z3.object({
927
- documentId: z3.string().min(1).describe("Document ID returned by search_documents or list_documents; it must be readable in the active scope."),
928
- limit: z3.number().int().min(1).max(100).optional().describe("Maximum related documents to return, from 1 to 100. Omit to use the server default.")
929
- }),
930
- outputSchema: toolOutputSchemas.get_related_documents
931
- }, wrapHandler("get_related_documents", async ({ documentId, limit }) => client.getRelatedDocuments(documentId, limit)));
932
- server.registerTool("search_knowledge_graph", {
933
- annotations: {
934
- readOnlyHint: true,
935
- destructiveHint: false,
936
- idempotentHint: true,
937
- openWorldHint: false
938
- },
939
- description: "Search graph relations from one or more readable seed documents, optionally using query text to filter and rank related documents. Requires read access and returns seed entities plus relatedDocs. Use search_documents first to obtain authorized seed IDs; use get_related_documents for one-seed neighbors without graph search. Results stay in the active scope and graph data may be empty when unavailable.",
940
- inputSchema: z3.object({
941
- query: z3.string().max(2000).optional().describe("Optional search text up to 2,000 characters to filter and rank graph-related documents; omit it to inspect relations without query filtering."),
942
- docIds: z3.array(z3.string().min(1)).min(1).max(50).describe("Between 1 and 50 document IDs returned by search_documents or list_documents; each seed must be readable in the active scope."),
943
- limit: z3.number().int().min(1).max(100).optional().describe("Maximum related documents to return, from 1 to 100. Omit to use the server default.")
944
- }),
945
- outputSchema: toolOutputSchemas.search_knowledge_graph
946
- }, wrapHandler("search_knowledge_graph", async (input) => client.searchGraph(input)));
947
- server.registerTool("get_document_index_status", {
948
- annotations: {
949
- readOnlyHint: true,
950
- destructiveHint: false,
951
- idempotentHint: true,
952
- openWorldHint: false
953
- },
954
- description: "Read indexing and knowledge-pipeline status for an existing document without starting work. Requires read access. Use after a save or refresh_document_index to check progress or failures.",
955
- inputSchema: z3.object({
956
- documentId: z3.string().uuid().describe("UUID of a document returned by search_documents or list_documents; it must be readable in the active scope.")
957
- }),
958
- outputSchema: toolOutputSchemas.get_document_index_status
959
- }, wrapHandler("get_document_index_status", async ({ documentId }) => client.getDocumentIndexStatus(documentId)));
960
- server.registerTool("refresh_document_index", {
961
- annotations: {
962
- readOnlyHint: false,
963
- destructiveHint: false,
964
- idempotentHint: false,
965
- openWorldHint: false
966
- },
967
- description: "Queue an explicit reindex for an existing document; processing is asynchronous and the response acknowledges the generation. Requires write access. Normal content and placement changes schedule indexing when needed, so use get_document_index_status first and refresh only when a retry is intended.",
968
- inputSchema: z3.object({
969
- documentId: z3.string().uuid().describe("UUID of the document to refresh, obtained from search_documents or list_documents and visible in the active scope.")
970
- }),
971
- outputSchema: toolOutputSchemas.refresh_document_index
972
- }, wrapHandler("refresh_document_index", async ({ documentId }) => client.refreshDocumentIndex(documentId)));
981
+ function registerPromptsAndResources(server, client) {
973
982
  server.registerPrompt("organize_workspace", {
974
983
  description: "Plan safe document organization using DocsMint categories and folders.",
975
984
  argsSchema: z3.object({
@@ -1022,7 +1031,7 @@ Read a document before updating it. Preserve its language, title intent, TipTap/
1022
1031
  mimeType: "text/markdown",
1023
1032
  text: `# DocsMint retrieval rules
1024
1033
 
1025
- Use search_documents for normal retrieval. Use get_related_documents or search_knowledge_graph only with document IDs already authorized by the active API key. Keep multilingual queries in their original language and cite document IDs in answers.`
1034
+ Use find_documents(mode=search) for normal retrieval. Use explore_graph only with document IDs already authorized by the active API key. Keep multilingual queries in their original language and cite document IDs in answers.`
1026
1035
  }
1027
1036
  ]
1028
1037
  }));
@@ -1082,6 +1091,16 @@ function sanitizeMcpRequestContext(context) {
1082
1091
  function createMcpDocsClient(docsClient, requestContext) {
1083
1092
  const context = sanitizeMcpRequestContext(requestContext);
1084
1093
  return {
1094
+ createTag: (input) => docsClient.createTag(input, context),
1095
+ updateTag: (id, input) => docsClient.updateTag(id, input, context),
1096
+ deleteTag: (id) => docsClient.deleteTag(id, context),
1097
+ addTagToDocument: (documentId, tagId) => docsClient.addTagToDoc(documentId, tagId, context),
1098
+ removeTagFromDocument: (documentId, tagId) => docsClient.removeTagFromDoc(documentId, tagId, context),
1099
+ updateFolder: (id, input) => docsClient.updateFolder(id, input, context),
1100
+ updateCategory: (id, input) => docsClient.updateCategory(id, input, context),
1101
+ listTrash: () => docsClient.listTrash(context),
1102
+ restoreTrashedDocument: (id) => docsClient.restoreTrashedDocument(id, context),
1103
+ permanentlyDeleteDocument: (id) => docsClient.permanentlyDeleteDocument(id, context),
1085
1104
  deleteDocument: (id) => docsClient.deleteDoc(id, context),
1086
1105
  deleteFolder: (id) => docsClient.deleteFolder(id, context),
1087
1106
  deleteCategory: (id) => docsClient.deleteCategory(id, context),
@@ -1125,236 +1144,43 @@ var client = new Proxy({}, {
1125
1144
  }
1126
1145
  });
1127
1146
 
1128
- // ../mcp-server/src/tools/create-document.ts
1129
- var exports_create_document = {};
1130
- __export(exports_create_document, {
1131
- createHandler: () => createHandler,
1132
- definition: () => definition,
1133
- handler: () => handler
1134
- });
1135
- import { z as z4 } from "zod";
1136
- var definition = {
1137
- name: "create_document",
1138
- description: "Create a new DocsMint document when no existing document should be modified. Optionally set a title, initial Markdown content, and folder or category placement; an omitted title defaults to \u201CUntitled\u201D. Requires write access in the target scope. A category-scoped credential must create inside its configured category, by selecting that category or a folder within it. Normal creation schedules indexing asynchronously and returns the created document. Use update_document for an existing document.",
1139
- inputSchema: {
1140
- title: z4.string().min(1).max(500).optional().describe("Optional title from 1 to 500 characters; omit to use the API default \u201CUntitled\u201D."),
1141
- content: z4.string().optional().describe("Optional initial Markdown content; omit to create an empty document."),
1142
- folderId: z4.string().uuid().optional().describe("Optional folder UUID from list_folders; the folder must be writable in the active workspace or category."),
1143
- categoryId: z4.string().uuid().nullable().optional().describe("Optional category UUID from list_categories; omit or pass null to leave the explicit category unset. A categorized folder still supplies the document\u2019s effective category; without one the document remains uncategorized. Category-scoped credentials stay bound to their configured category.")
1144
- }
1145
- };
1146
- var createHandler = (api) => async function createDocument(args) {
1147
- return await api.createDocument(args);
1148
- };
1149
- var handler = createHandler(client);
1150
-
1151
- // ../mcp-server/src/tools/create-folder.ts
1152
- var exports_create_folder = {};
1153
- __export(exports_create_folder, {
1154
- createHandler: () => createHandler2,
1155
- definition: () => definition2,
1156
- handler: () => handler2
1157
- });
1158
- import { z as z5 } from "zod";
1159
- var definition2 = {
1160
- name: "create_folder",
1161
- description: "Create a new folder in the active workspace or category scope. Requires write access and returns the created folder. A nested folder inherits its parent category; for a root folder, pass categoryId when using a category-scoped credential. Category-scoped credentials cannot create outside their configured category.",
1162
- inputSchema: {
1163
- name: z5.string().min(1).max(255).describe("Non-empty folder name up to 255 characters."),
1164
- parentId: z5.string().uuid().nullable().optional().describe("Optional parent folder UUID from list_folders; omit or pass null to create a root-level folder."),
1165
- categoryId: z5.string().uuid().nullable().optional().describe("Optional category UUID from list_categories for a root-level folder. A nested folder inherits its parent category; category-scoped credentials cannot escape their configured category.")
1166
- }
1167
- };
1168
- var createHandler2 = (api) => async function createFolder(args) {
1169
- return await api.createFolder(args);
1170
- };
1171
- var handler2 = createHandler2(client);
1172
-
1173
- // ../mcp-server/src/tools/create-snapshot.ts
1174
- var exports_create_snapshot = {};
1175
- __export(exports_create_snapshot, {
1176
- createHandler: () => createHandler3,
1177
- definition: () => definition3,
1178
- handler: () => handler3
1179
- });
1180
- import { z as z6 } from "zod";
1181
- var definition3 = {
1182
- name: "create_snapshot",
1183
- description: "Save a named, retained snapshot of an existing document\u2019s current content before a planned change. Requires edit access and adds an entry to get_version_history without changing the document itself. Use restore_document_version with the returned version ID to restore its content later.",
1184
- inputSchema: {
1185
- documentId: z6.string().uuid().describe("UUID of the existing document, obtained from search_documents or list_documents and visible in the active scope."),
1186
- label: z6.string().min(1).max(200).describe("Non-empty snapshot label up to 200 characters, for example 'v1.0-release'."),
1187
- description: z6.string().max(1000).optional().describe("Optional snapshot note up to 1,000 characters; omit if not needed.")
1188
- }
1189
- };
1190
- var createHandler3 = (api) => async function createSnapshot(args) {
1191
- const { documentId, ...input } = args;
1192
- return await api.createSnapshot(documentId, input);
1193
- };
1194
- var handler3 = createHandler3(client);
1195
-
1196
- // ../mcp-server/src/tools/export-document.ts
1197
- var exports_export_document = {};
1198
- __export(exports_export_document, {
1199
- createHandler: () => createHandler4,
1200
- definition: () => definition4,
1201
- handler: () => handler4
1202
- });
1203
- import { z as z7 } from "zod";
1204
- var definition4 = {
1205
- name: "export_document",
1206
- description: "Render one readable document as portable Markdown and return a markdown string in the response object. Does not modify the document or include its complete metadata; use get_document to inspect the editable document.",
1207
- inputSchema: {
1208
- id: z7.string().uuid().describe("UUID of the readable document to export, obtained from search_documents or list_documents.")
1209
- }
1210
- };
1211
- var createHandler4 = (api) => async function exportDocument(args) {
1212
- return await api.exportDocument(args.id);
1213
- };
1214
- var handler4 = createHandler4(client);
1215
-
1216
- // ../mcp-server/src/tools/get-document.ts
1217
- var exports_get_document = {};
1218
- __export(exports_get_document, {
1219
- createHandler: () => createHandler5,
1220
- definition: () => definition5,
1221
- handler: () => handler5
1222
- });
1223
- import { z as z8 } from "zod";
1224
- var definition5 = {
1225
- name: "get_document",
1226
- description: "Read an existing document by UUID with its content, metadata, and tags before editing or citing it. Requires read access in the active workspace/category. Use export_document when you only need the portable Markdown body.",
1227
- inputSchema: {
1228
- id: z8.string().uuid().describe("UUID of the document, obtained from search_documents or list_documents, and visible in the active scope.")
1229
- }
1230
- };
1231
- var createHandler5 = (api) => async function getDocument(args) {
1232
- return await api.getDocument(args.id);
1233
- };
1234
- var handler5 = createHandler5(client);
1235
-
1236
- // ../mcp-server/src/tools/list-documents.ts
1237
- var exports_list_documents = {};
1238
- __export(exports_list_documents, {
1239
- createHandler: () => createHandler6,
1240
- definition: () => definition6,
1241
- handler: () => handler6
1242
- });
1243
- import { z as z9 } from "zod";
1244
- var definition6 = {
1245
- name: "list_documents",
1246
- description: "List readable documents in the active workspace or category with page-based results. Optionally filter by folder or tag; page defaults to 1 and limit to 20 (maximum 1,000). Use search_documents for text or semantic retrieval.",
1247
- inputSchema: {
1248
- folderId: z9.string().uuid().optional().describe("Optional folder UUID from list_folders to limit the listing."),
1249
- tag: z9.string().uuid().optional().describe("Optional tag UUID from list_tags to filter the documents."),
1250
- page: z9.number().int().min(1).optional().describe("1-indexed result page; defaults to 1."),
1251
- limit: z9.number().int().min(1).max(1000).optional().describe("Number of documents per page, from 1 to 1,000; defaults to 20.")
1252
- }
1253
- };
1254
- var createHandler6 = (api) => async function listDocuments(args) {
1255
- return await api.listDocuments(args);
1256
- };
1257
- var handler6 = createHandler6(client);
1258
-
1259
- // ../mcp-server/src/tools/list-folders.ts
1260
- var exports_list_folders = {};
1261
- __export(exports_list_folders, {
1262
- createHandler: () => createHandler7,
1263
- definition: () => definition7,
1264
- handler: () => handler7
1265
- });
1266
- import { z as z10 } from "zod";
1267
- var definition7 = {
1268
- name: "list_folders",
1269
- description: "List folders readable in the active workspace/category. Omit parentId to list root folders, or supply a parent UUID to list its immediate children as a flat list. Use create_folder to add a folder.",
1270
- inputSchema: {
1271
- parentId: z10.string().uuid().optional().describe("Optional parent folder UUID from list_folders; omit to list root folders.")
1272
- }
1273
- };
1274
- var createHandler7 = (api) => async function listFolders(args) {
1275
- return await api.listFolders(args);
1276
- };
1277
- var handler7 = createHandler7(client);
1278
-
1279
- // ../mcp-server/src/tools/search.ts
1280
- var exports_search = {};
1281
- __export(exports_search, {
1282
- createHandler: () => createHandler8,
1283
- definition: () => definition8,
1284
- handler: () => handler8
1285
- });
1286
- import { z as z11 } from "zod";
1287
- var definition8 = {
1288
- name: "search_documents",
1289
- description: "Search readable DocsMint documents with hybrid full-text and semantic retrieval, optionally filtered by folder and tag names. Requires read access and stays within the active workspace/category. Use search_knowledge_graph for graph relations from seed documents or get_related_documents for neighbors without a text query.",
1290
- inputSchema: {
1291
- query: z11.string().describe("Text to search for; preserve the language and terms relevant to the user request."),
1292
- folder: z11.string().optional().describe("Optional folder UUID from list_folders to scope retrieval."),
1293
- tags: z11.array(z11.string()).optional().describe("Optional tag names as shown by list_tags; documents match when they have any supplied tag name."),
1294
- limit: z11.number().int().positive().max(100).optional().describe("Maximum result count, from 1 to 100; defaults to 20.")
1295
- }
1296
- };
1297
- var createHandler8 = (api) => async function searchDocuments(args) {
1298
- return await api.search({
1299
- query: args.query,
1300
- folder: args.folder,
1301
- tags: args.tags,
1302
- limit: args.limit
1303
- });
1304
- };
1305
- var handler8 = createHandler8(client);
1306
-
1307
- // ../mcp-server/src/tools/update-document.ts
1308
- var exports_update_document = {};
1309
- __export(exports_update_document, {
1310
- createHandler: () => createHandler9,
1311
- definition: () => definition9,
1312
- handler: () => handler9
1313
- });
1314
- import { z as z12 } from "zod";
1315
- var definition9 = {
1316
- name: "update_document",
1317
- description: "Modify an existing document by UUID after reading its current state. Omitted fields remain unchanged; null folderId removes folder placement and null categoryId clears the explicit category, while a categorized folder can still supply the effective category. Changing title or Markdown content requires edit access, while moving placement requires write access in the active workspace/category. The server stores the prior content in version history and queues indexing when content or placement changes. Returns the updated document. Use create_document for new content.",
1318
- inputSchema: {
1319
- id: z12.string().uuid().describe("UUID of the existing document, obtained from search_documents, list_documents, or get_document."),
1320
- title: z12.string().min(1).max(500).optional().describe("Optional replacement title, 1 to 500 characters; omit to leave the current title unchanged."),
1321
- content: z12.string().optional().describe("New markdown content for the document."),
1322
- folderId: z12.string().uuid().nullable().optional().describe("Optional destination folder UUID from list_folders; omit to keep current placement or pass null to remove folder placement."),
1323
- categoryId: z12.string().uuid().nullable().optional().describe("Optional destination category UUID from list_categories; omit to keep the explicit category or pass null to clear it. A categorized folder may still supply the effective category. Category-scoped credentials cannot move outside their configured category.")
1324
- }
1325
- };
1326
- var createHandler9 = (api) => async function updateDocument(args) {
1327
- const { id, ...patch } = args;
1328
- return await api.updateDocument(id, patch);
1329
- };
1330
- var handler9 = createHandler9(client);
1331
-
1332
- // ../mcp-server/src/tools/version-history.ts
1333
- var exports_version_history = {};
1334
- __export(exports_version_history, {
1335
- createHandler: () => createHandler10,
1336
- definition: () => definition10,
1337
- handler: () => handler10
1338
- });
1339
- import { z as z13 } from "zod";
1340
- var definition10 = {
1341
- name: "get_version_history",
1342
- description: "Read versions for an existing document, including saved snapshots. Requires read access and returns version IDs with content and timestamps; pass a version ID to restore_document_version when the user asks to restore content. This is read-only and does not change the document.",
1343
- inputSchema: {
1344
- documentId: z13.string().uuid().describe("UUID of the readable document whose version history you need; obtain it from search_documents or list_documents."),
1345
- onlySnapshots: z13.boolean().optional().describe("When true, return only named snapshots and omit auto-saved revisions; omit or use false for the full history.")
1346
- }
1347
- };
1348
- var createHandler10 = (api) => async function getVersionHistory(args) {
1349
- return await api.getVersionHistory(args.documentId, args.onlySnapshots);
1147
+ // ../mcp-server/src/capabilities.ts
1148
+ var capabilityCatalog = {
1149
+ tools: [
1150
+ "find_documents",
1151
+ "read_document",
1152
+ "save_document",
1153
+ "delete_document",
1154
+ "list_workspace_structure",
1155
+ "save_folder",
1156
+ "delete_folder",
1157
+ "save_category",
1158
+ "delete_category",
1159
+ "save_tag",
1160
+ "delete_tag",
1161
+ "set_document_tag",
1162
+ "create_snapshot",
1163
+ "restore_document_version",
1164
+ "explore_graph",
1165
+ "get_document_index_status",
1166
+ "refresh_document_index",
1167
+ "list_trash",
1168
+ "restore_trashed_document",
1169
+ "permanently_delete_document"
1170
+ ],
1171
+ prompts: ["organize_workspace", "research_workspace"],
1172
+ resources: [
1173
+ "docsmint://guide/editor",
1174
+ "docsmint://guide/search",
1175
+ "docsmint://workspace/catalog"
1176
+ ]
1350
1177
  };
1351
- var handler10 = createHandler10(client);
1352
1178
 
1353
1179
  // ../mcp-server/src/server.ts
1354
- function wrapHandler(name, handler11, outputSchema) {
1180
+ function wrapHandler(name, handler, outputSchema) {
1355
1181
  return async (args) => {
1356
1182
  try {
1357
- const output = await handler11(args);
1183
+ const output = await handler(args);
1358
1184
  const parsedOutput = outputSchema ? await outputSchema.safeParseAsync(output) : undefined;
1359
1185
  if (parsedOutput && !parsedOutput.success) {
1360
1186
  throw new Error(`Tool '${name}' returned a result outside its published output schema`);
@@ -1389,49 +1215,11 @@ function wrapHandler(name, handler11, outputSchema) {
1389
1215
  };
1390
1216
  }
1391
1217
  function registerDocsmintMcpCapabilities(server, client2) {
1392
- const register = (name, description, inputSchema, handler11) => {
1393
- server.registerTool(name, {
1394
- description,
1395
- inputSchema: z14.object(inputSchema),
1396
- annotations: {
1397
- readOnlyHint: ![
1398
- "create_document",
1399
- "update_document",
1400
- "create_folder",
1401
- "create_snapshot"
1402
- ].includes(name),
1403
- destructiveHint: name === "update_document",
1404
- idempotentHint: ![
1405
- "create_document",
1406
- "update_document",
1407
- "create_folder",
1408
- "create_snapshot"
1409
- ].includes(name),
1410
- openWorldHint: false
1411
- },
1412
- outputSchema: toolOutputSchemas[name]
1413
- }, wrapHandler(name, handler11, toolOutputSchemas[name]));
1414
- };
1415
- const tools = [
1416
- exports_search,
1417
- exports_get_document,
1418
- exports_create_document,
1419
- exports_update_document,
1420
- exports_list_documents,
1421
- exports_list_folders,
1422
- exports_create_folder,
1423
- exports_create_snapshot,
1424
- exports_version_history,
1425
- exports_export_document
1426
- ];
1427
- for (const tool of tools) {
1428
- register(tool.definition.name, tool.definition.description, tool.definition.inputSchema, tool.createHandler(client2));
1429
- }
1430
- registerExtendedCapabilities(server, client2, (name, handler11) => wrapHandler(name, handler11, toolOutputSchemas[name]));
1431
- registerLifecycleCapabilities(server, client2, (name, handler11) => wrapHandler(name, handler11, toolOutputSchemas[name]));
1218
+ registerCompactCapabilities(server, client2, wrapHandler);
1219
+ registerPromptsAndResources(server, client2);
1432
1220
  }
1433
1221
  function createDocsmintMcpServer(options = {}) {
1434
- const server = new McpServer({ name: "docsmint", version: "0.9.2" });
1222
+ const server = new McpServer({ name: "docsmint", version: "0.10.0" });
1435
1223
  const client2 = options.docsClient ? createMcpDocsClient(options.docsClient, options.requestContext) : options.client ?? createMcpDocsClient(createDefaultDocsClient(), options.requestContext);
1436
1224
  registerDocsmintMcpCapabilities(server, client2);
1437
1225
  return server;