@hiai-gg/docsmint 0.9.4 → 1.0.1
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.
- package/README.md +12 -8
- package/dist/backend/index.js +1 -1
- package/dist/mcp-cli.js +361 -588
- package/dist/mcp-server.js +392 -627
- package/package.json +1 -1
- package/packages/cli/src/index.ts +1 -1
- package/server.json +3 -3
- package/skills/docsmint-document-manager/SKILL.md +9 -8
package/dist/mcp-cli.js
CHANGED
|
@@ -1,26 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
// @bun
|
|
3
|
-
var __defProp = Object.defineProperty;
|
|
4
|
-
var __returnValue = (v) => v;
|
|
5
|
-
function __exportSetter(name, newValue) {
|
|
6
|
-
this[name] = __returnValue.bind(null, newValue);
|
|
7
|
-
}
|
|
8
|
-
var __export = (target, all) => {
|
|
9
|
-
for (var name in all)
|
|
10
|
-
__defProp(target, name, {
|
|
11
|
-
get: all[name],
|
|
12
|
-
enumerable: true,
|
|
13
|
-
configurable: true,
|
|
14
|
-
set: __exportSetter.bind(all, name)
|
|
15
|
-
});
|
|
16
|
-
};
|
|
17
3
|
|
|
18
4
|
// ../mcp-server/src/index.ts
|
|
19
5
|
import { serveStdio } from "@modelcontextprotocol/server/stdio";
|
|
20
6
|
|
|
21
7
|
// ../mcp-server/src/server.ts
|
|
22
8
|
import { McpServer } from "@modelcontextprotocol/server";
|
|
23
|
-
import { z as z15 } from "zod";
|
|
24
9
|
|
|
25
10
|
// dist/client.js
|
|
26
11
|
var docsApiErrorBrand = Symbol.for("io.github.hiai-gg.docsmint.DocsApiError");
|
|
@@ -590,8 +575,8 @@ var RESOURCE_PERMISSIONS = new Set([
|
|
|
590
575
|
"edit",
|
|
591
576
|
"write"
|
|
592
577
|
]);
|
|
593
|
-
// ../mcp-server/src/
|
|
594
|
-
import { z as
|
|
578
|
+
// ../mcp-server/src/compact.ts
|
|
579
|
+
import { z as z3 } from "zod";
|
|
595
580
|
|
|
596
581
|
// ../mcp-server/src/output-schemas.ts
|
|
597
582
|
import { z } from "zod";
|
|
@@ -768,7 +753,7 @@ var deleteAcknowledgmentSchema = z.looseObject({
|
|
|
768
753
|
id: z.string().uuid(),
|
|
769
754
|
deleted: z.literal(true)
|
|
770
755
|
});
|
|
771
|
-
var
|
|
756
|
+
var operationOutputSchemas = {
|
|
772
757
|
search_documents: z.looseObject({
|
|
773
758
|
items: z.array(searchResultSchema),
|
|
774
759
|
total: z.number(),
|
|
@@ -820,314 +805,78 @@ var toolOutputSchemas = {
|
|
|
820
805
|
restore_trashed_document: z.looseObject({ success: z.literal(true) }),
|
|
821
806
|
permanently_delete_document: deleteAcknowledgmentSchema
|
|
822
807
|
};
|
|
808
|
+
var variant = (operation, result) => z.object({ operation: z.literal(operation), result });
|
|
809
|
+
var toolOutputSchemas = {
|
|
810
|
+
delete_document: operationOutputSchemas.delete_document,
|
|
811
|
+
delete_folder: operationOutputSchemas.delete_folder,
|
|
812
|
+
delete_category: operationOutputSchemas.delete_category,
|
|
813
|
+
delete_tag: operationOutputSchemas.delete_tag,
|
|
814
|
+
create_snapshot: operationOutputSchemas.create_snapshot,
|
|
815
|
+
restore_document_version: operationOutputSchemas.restore_document_version,
|
|
816
|
+
get_document_index_status: operationOutputSchemas.get_document_index_status,
|
|
817
|
+
refresh_document_index: operationOutputSchemas.refresh_document_index,
|
|
818
|
+
list_trash: operationOutputSchemas.list_trash,
|
|
819
|
+
restore_trashed_document: operationOutputSchemas.restore_trashed_document,
|
|
820
|
+
permanently_delete_document: operationOutputSchemas.permanently_delete_document,
|
|
821
|
+
find_documents: z.union([
|
|
822
|
+
variant("list", operationOutputSchemas.list_documents),
|
|
823
|
+
variant("search", operationOutputSchemas.search_documents)
|
|
824
|
+
]),
|
|
825
|
+
read_document: z.union([
|
|
826
|
+
variant("detail", operationOutputSchemas.get_document),
|
|
827
|
+
variant("markdown", operationOutputSchemas.export_document),
|
|
828
|
+
variant("versions", operationOutputSchemas.get_version_history)
|
|
829
|
+
]),
|
|
830
|
+
save_document: z.union([
|
|
831
|
+
variant("create", operationOutputSchemas.create_document),
|
|
832
|
+
variant("update", operationOutputSchemas.update_document)
|
|
833
|
+
]),
|
|
834
|
+
list_workspace_structure: z.union([
|
|
835
|
+
variant("folders", operationOutputSchemas.list_folders),
|
|
836
|
+
variant("categories", operationOutputSchemas.list_categories),
|
|
837
|
+
variant("tags", operationOutputSchemas.list_tags)
|
|
838
|
+
]),
|
|
839
|
+
save_folder: z.union([
|
|
840
|
+
variant("create", operationOutputSchemas.create_folder),
|
|
841
|
+
variant("update", operationOutputSchemas.update_folder)
|
|
842
|
+
]),
|
|
843
|
+
save_category: z.union([
|
|
844
|
+
variant("create", operationOutputSchemas.create_category),
|
|
845
|
+
variant("update", operationOutputSchemas.update_category)
|
|
846
|
+
]),
|
|
847
|
+
save_tag: z.union([
|
|
848
|
+
variant("create", operationOutputSchemas.create_tag),
|
|
849
|
+
variant("update", operationOutputSchemas.update_tag)
|
|
850
|
+
]),
|
|
851
|
+
set_document_tag: z.union([
|
|
852
|
+
variant("add", operationOutputSchemas.add_tag_to_document),
|
|
853
|
+
variant("remove", operationOutputSchemas.remove_tag_from_document)
|
|
854
|
+
]),
|
|
855
|
+
explore_graph: z.union([
|
|
856
|
+
variant("neighbors", operationOutputSchemas.get_related_documents),
|
|
857
|
+
variant("search", operationOutputSchemas.search_knowledge_graph)
|
|
858
|
+
]),
|
|
859
|
+
batch_documents: z.looseObject({
|
|
860
|
+
action: z.enum(["move", "set_category", "add_tag", "remove_tag", "trash", "restore", "refresh_index"]),
|
|
861
|
+
total: z.number().int().min(1).max(25),
|
|
862
|
+
succeeded: z.number().int().nonnegative(),
|
|
863
|
+
failed: z.number().int().nonnegative(),
|
|
864
|
+
aborted: z.boolean(),
|
|
865
|
+
results: z.array(z.union([
|
|
866
|
+
z.looseObject({ id: z.string().uuid(), status: z.literal("ok") }),
|
|
867
|
+
z.looseObject({ id: z.string().uuid(), status: z.literal("error"), error: z.looseObject({ status: z.number().int(), code: z.string(), message: z.string() }) }),
|
|
868
|
+
z.looseObject({ id: z.string().uuid(), status: z.literal("skipped") })
|
|
869
|
+
]))
|
|
870
|
+
}),
|
|
871
|
+
get_workspace_item: z.union([
|
|
872
|
+
variant("folder", folderSchema),
|
|
873
|
+
variant("category", categoryListItemSchema),
|
|
874
|
+
variant("tag", tagSchema)
|
|
875
|
+
])
|
|
876
|
+
};
|
|
823
877
|
|
|
824
|
-
// ../mcp-server/src/
|
|
825
|
-
|
|
826
|
-
throw new Error(`The injected legacy MCP client does not support ${name}; use a public DocsClient.`);
|
|
827
|
-
}
|
|
828
|
-
var annotations = { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: false };
|
|
829
|
-
function registerLifecycleCapabilities(server, client, wrap) {
|
|
830
|
-
const deletions = [
|
|
831
|
-
{
|
|
832
|
-
name: "delete_document",
|
|
833
|
-
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.",
|
|
834
|
-
action: (id) => client.deleteDocument ? client.deleteDocument(id) : unsupported("delete_document"),
|
|
835
|
-
idDescription: "UUID of the document to move to trash; obtain it from search_documents, list_documents, or get_document."
|
|
836
|
-
},
|
|
837
|
-
{
|
|
838
|
-
name: "delete_folder",
|
|
839
|
-
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}.",
|
|
840
|
-
action: (id) => client.deleteFolder ? client.deleteFolder(id) : unsupported("delete_folder"),
|
|
841
|
-
idDescription: "UUID of the folder to delete; obtain it from list_folders. This detaches, but does not delete, the documents inside it."
|
|
842
|
-
},
|
|
843
|
-
{
|
|
844
|
-
name: "delete_category",
|
|
845
|
-
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}.",
|
|
846
|
-
action: (id) => client.deleteCategory ? client.deleteCategory(id) : unsupported("delete_category"),
|
|
847
|
-
idDescription: "UUID of the category to delete; obtain it from list_categories using a workspace-scoped credential."
|
|
848
|
-
}
|
|
849
|
-
];
|
|
850
|
-
for (const tool of deletions) {
|
|
851
|
-
server.registerTool(tool.name, {
|
|
852
|
-
description: tool.description,
|
|
853
|
-
annotations,
|
|
854
|
-
inputSchema: z2.object({ id: z2.string().uuid().describe(tool.idDescription) }),
|
|
855
|
-
outputSchema: toolOutputSchemas[tool.name]
|
|
856
|
-
}, wrap(tool.name, async ({ id }) => {
|
|
857
|
-
await tool.action(id);
|
|
858
|
-
return { id, deleted: true };
|
|
859
|
-
}));
|
|
860
|
-
}
|
|
861
|
-
server.registerTool("restore_document_version", {
|
|
862
|
-
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.",
|
|
863
|
-
annotations,
|
|
864
|
-
inputSchema: z2.object({
|
|
865
|
-
documentId: z2.string().uuid().describe("UUID of the document whose content should be restored; it must be visible in the active workspace or category."),
|
|
866
|
-
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.")
|
|
867
|
-
}),
|
|
868
|
-
outputSchema: toolOutputSchemas.restore_document_version
|
|
869
|
-
}, wrap("restore_document_version", async ({ documentId, versionId }) => client.restoreDocumentVersion ? client.restoreDocumentVersion(documentId, versionId) : unsupported("restore_document_version")));
|
|
870
|
-
}
|
|
871
|
-
|
|
872
|
-
// ../mcp-server/src/management.ts
|
|
873
|
-
import { z as z3 } from "zod";
|
|
874
|
-
var uuid = z3.string().uuid().describe("UUID of the target object, obtained from the corresponding list tool.");
|
|
875
|
-
var write = { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false };
|
|
876
|
-
var update = { ...write, destructiveHint: true };
|
|
877
|
-
var read = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
|
|
878
|
-
var purge = { ...write, destructiveHint: true };
|
|
879
|
-
function unsupported2(name) {
|
|
880
|
-
throw new Error(`The injected legacy MCP client does not support ${name}; use a public DocsClient.`);
|
|
881
|
-
}
|
|
882
|
-
function registerManagementCapabilities(server, client, wrap) {
|
|
883
|
-
server.registerTool("create_tag", {
|
|
884
|
-
description: "Create a tag in the active workspace. Requires full workspace write access; category-scoped credentials cannot manage tags. Use add_tag_to_document to assign it.",
|
|
885
|
-
annotations: write,
|
|
886
|
-
inputSchema: z3.object({ name: z3.string().min(1).max(100).describe("New tag name, up to 100 characters."), color: z3.string().max(20).optional().describe("Optional display color for the new tag, up to 20 characters.") }),
|
|
887
|
-
outputSchema: toolOutputSchemas.create_tag
|
|
888
|
-
}, wrap("create_tag", async (input) => client.createTag ? client.createTag(input) : unsupported2("create_tag")));
|
|
889
|
-
server.registerTool("update_tag", {
|
|
890
|
-
description: "Rename or recolor an existing tag. Requires full workspace write access; category-scoped credentials cannot manage tags. Affected documents are reindexed by the API.",
|
|
891
|
-
annotations: update,
|
|
892
|
-
inputSchema: z3.object({ id: uuid, name: z3.string().min(1).max(100).optional().describe("Replacement tag name; omit to keep the current name."), color: z3.string().max(20).optional().describe("Replacement display color; omit to keep the current color.") }).refine((value) => value.name !== undefined || value.color !== undefined),
|
|
893
|
-
outputSchema: toolOutputSchemas.update_tag
|
|
894
|
-
}, wrap("update_tag", async ({ id, ...input }) => client.updateTag ? client.updateTag(id, input) : unsupported2("update_tag")));
|
|
895
|
-
server.registerTool("delete_tag", {
|
|
896
|
-
description: "Delete a tag in the active workspace and remove its document assignments. Requires full workspace write access; category-scoped credentials cannot manage tags.",
|
|
897
|
-
annotations: purge,
|
|
898
|
-
inputSchema: z3.object({ id: uuid }),
|
|
899
|
-
outputSchema: toolOutputSchemas.delete_tag
|
|
900
|
-
}, wrap("delete_tag", async ({ id }) => {
|
|
901
|
-
if (!client.deleteTag)
|
|
902
|
-
return unsupported2("delete_tag");
|
|
903
|
-
await client.deleteTag(id);
|
|
904
|
-
return { id, deleted: true };
|
|
905
|
-
}));
|
|
906
|
-
server.registerTool("add_tag_to_document", {
|
|
907
|
-
description: "Assign a tag from list_tags to an existing document. Requires edit access to the document and permission to use the tag.",
|
|
908
|
-
annotations: write,
|
|
909
|
-
inputSchema: z3.object({ documentId: uuid.describe("UUID of the document to tag."), tagId: uuid.describe("UUID of the tag returned by list_tags.") }),
|
|
910
|
-
outputSchema: toolOutputSchemas.add_tag_to_document
|
|
911
|
-
}, wrap("add_tag_to_document", async ({ documentId, tagId }) => {
|
|
912
|
-
if (!client.addTagToDocument)
|
|
913
|
-
return unsupported2("add_tag_to_document");
|
|
914
|
-
await client.addTagToDocument(documentId, tagId);
|
|
915
|
-
return { documentId, tagId, assigned: true };
|
|
916
|
-
}));
|
|
917
|
-
server.registerTool("remove_tag_from_document", {
|
|
918
|
-
description: "Remove a tag assignment from a document. Requires edit access; the tag itself is preserved.",
|
|
919
|
-
annotations: update,
|
|
920
|
-
inputSchema: z3.object({ documentId: uuid.describe("UUID of the document whose tag assignment changes."), tagId: uuid.describe("UUID of the assigned tag to remove.") }),
|
|
921
|
-
outputSchema: toolOutputSchemas.remove_tag_from_document
|
|
922
|
-
}, wrap("remove_tag_from_document", async ({ documentId, tagId }) => {
|
|
923
|
-
if (!client.removeTagFromDocument)
|
|
924
|
-
return unsupported2("remove_tag_from_document");
|
|
925
|
-
await client.removeTagFromDocument(documentId, tagId);
|
|
926
|
-
return { documentId, tagId, removed: true };
|
|
927
|
-
}));
|
|
928
|
-
server.registerTool("update_folder", {
|
|
929
|
-
description: "Rename or move a folder; changes to category or parent follow API scope rules and trigger reindexing. Requires write access.",
|
|
930
|
-
annotations: update,
|
|
931
|
-
inputSchema: z3.object({ id: uuid, name: z3.string().min(1).max(255).optional().describe("Replacement folder name; omit to preserve the name."), parentId: uuid.nullable().optional().describe("New parent folder UUID, or null for a root folder."), categoryId: uuid.nullable().optional().describe("New category UUID, or null to clear the category."), order: z3.number().int().nonnegative().optional().describe("New non-negative order within the containing folder.") }).refine((value) => value.name !== undefined || value.parentId !== undefined || value.categoryId !== undefined || value.order !== undefined),
|
|
932
|
-
outputSchema: toolOutputSchemas.update_folder
|
|
933
|
-
}, wrap("update_folder", async ({ id, ...input }) => client.updateFolder ? client.updateFolder(id, input) : unsupported2("update_folder")));
|
|
934
|
-
server.registerTool("update_category", {
|
|
935
|
-
description: "Rename or reorder a category. Requires full workspace write access; category-scoped credentials cannot modify categories.",
|
|
936
|
-
annotations: update,
|
|
937
|
-
inputSchema: z3.object({ id: uuid, name: z3.string().min(1).max(255).optional().describe("New category name, up to 255 characters."), order: z3.number().int().nonnegative().optional().describe("New non-negative category order.") }).refine((value) => value.name !== undefined || value.order !== undefined),
|
|
938
|
-
outputSchema: toolOutputSchemas.update_category
|
|
939
|
-
}, wrap("update_category", async ({ id, ...input }) => client.updateCategory ? client.updateCategory(id, input) : unsupported2("update_category")));
|
|
940
|
-
server.registerTool("list_trash", {
|
|
941
|
-
description: "List soft-deleted documents visible to the active workspace/category. Requires read access.",
|
|
942
|
-
annotations: read,
|
|
943
|
-
inputSchema: z3.object({}),
|
|
944
|
-
outputSchema: toolOutputSchemas.list_trash
|
|
945
|
-
}, wrap("list_trash", async () => client.listTrash ? client.listTrash() : unsupported2("list_trash")));
|
|
946
|
-
server.registerTool("restore_trashed_document", {
|
|
947
|
-
description: "Restore a soft-deleted document from list_trash. Requires write access. This is different from restoring a content version.",
|
|
948
|
-
annotations: write,
|
|
949
|
-
inputSchema: z3.object({ id: uuid }),
|
|
950
|
-
outputSchema: toolOutputSchemas.restore_trashed_document
|
|
951
|
-
}, wrap("restore_trashed_document", async ({ id }) => client.restoreTrashedDocument ? client.restoreTrashedDocument(id) : unsupported2("restore_trashed_document")));
|
|
952
|
-
server.registerTool("permanently_delete_document", {
|
|
953
|
-
description: "Irreversibly purge a document already in trash, including its content and version history. Requires write access. Use only on explicit user request after checking list_trash.",
|
|
954
|
-
annotations: purge,
|
|
955
|
-
inputSchema: z3.object({ id: uuid }),
|
|
956
|
-
outputSchema: toolOutputSchemas.permanently_delete_document
|
|
957
|
-
}, wrap("permanently_delete_document", async ({ id }) => {
|
|
958
|
-
if (!client.permanentlyDeleteDocument)
|
|
959
|
-
return unsupported2("permanently_delete_document");
|
|
960
|
-
await client.permanentlyDeleteDocument(id);
|
|
961
|
-
return { id, deleted: true };
|
|
962
|
-
}));
|
|
963
|
-
}
|
|
964
|
-
|
|
965
|
-
// ../mcp-server/src/capabilities.ts
|
|
966
|
-
import { z as z4 } from "zod";
|
|
967
|
-
function registerExtendedCapabilities(server, client, wrapHandler) {
|
|
968
|
-
server.registerTool("list_categories", {
|
|
969
|
-
annotations: {
|
|
970
|
-
readOnlyHint: true,
|
|
971
|
-
destructiveHint: false,
|
|
972
|
-
idempotentHint: true,
|
|
973
|
-
openWorldHint: false
|
|
974
|
-
},
|
|
975
|
-
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.",
|
|
976
|
-
inputSchema: z4.object({}),
|
|
977
|
-
outputSchema: toolOutputSchemas.list_categories
|
|
978
|
-
}, wrapHandler("list_categories", async () => client.listCategories()));
|
|
979
|
-
server.registerTool("create_category", {
|
|
980
|
-
annotations: {
|
|
981
|
-
readOnlyHint: false,
|
|
982
|
-
destructiveHint: false,
|
|
983
|
-
idempotentHint: false,
|
|
984
|
-
openWorldHint: false
|
|
985
|
-
},
|
|
986
|
-
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.",
|
|
987
|
-
inputSchema: z4.object({
|
|
988
|
-
name: z4.string().trim().min(1).max(255).describe("Non-empty display name, up to 255 characters, for example Project notes.")
|
|
989
|
-
}),
|
|
990
|
-
outputSchema: toolOutputSchemas.create_category
|
|
991
|
-
}, wrapHandler("create_category", async (input) => client.createCategory(input)));
|
|
992
|
-
server.registerTool("list_tags", {
|
|
993
|
-
annotations: {
|
|
994
|
-
readOnlyHint: true,
|
|
995
|
-
destructiveHint: false,
|
|
996
|
-
idempotentHint: true,
|
|
997
|
-
openWorldHint: false
|
|
998
|
-
},
|
|
999
|
-
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.",
|
|
1000
|
-
inputSchema: z4.object({}),
|
|
1001
|
-
outputSchema: toolOutputSchemas.list_tags
|
|
1002
|
-
}, wrapHandler("list_tags", async () => client.listTags()));
|
|
1003
|
-
server.registerTool("get_related_documents", {
|
|
1004
|
-
annotations: {
|
|
1005
|
-
readOnlyHint: true,
|
|
1006
|
-
destructiveHint: false,
|
|
1007
|
-
idempotentHint: true,
|
|
1008
|
-
openWorldHint: false
|
|
1009
|
-
},
|
|
1010
|
-
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.",
|
|
1011
|
-
inputSchema: z4.object({
|
|
1012
|
-
documentId: z4.string().min(1).describe("Document ID returned by search_documents or list_documents; it must be readable in the active scope."),
|
|
1013
|
-
limit: z4.number().int().min(1).max(100).optional().describe("Maximum related documents to return, from 1 to 100. Omit to use the server default.")
|
|
1014
|
-
}),
|
|
1015
|
-
outputSchema: toolOutputSchemas.get_related_documents
|
|
1016
|
-
}, wrapHandler("get_related_documents", async ({ documentId, limit }) => client.getRelatedDocuments(documentId, limit)));
|
|
1017
|
-
server.registerTool("search_knowledge_graph", {
|
|
1018
|
-
annotations: {
|
|
1019
|
-
readOnlyHint: true,
|
|
1020
|
-
destructiveHint: false,
|
|
1021
|
-
idempotentHint: true,
|
|
1022
|
-
openWorldHint: false
|
|
1023
|
-
},
|
|
1024
|
-
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.",
|
|
1025
|
-
inputSchema: z4.object({
|
|
1026
|
-
query: z4.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."),
|
|
1027
|
-
docIds: z4.array(z4.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."),
|
|
1028
|
-
limit: z4.number().int().min(1).max(100).optional().describe("Maximum related documents to return, from 1 to 100. Omit to use the server default.")
|
|
1029
|
-
}),
|
|
1030
|
-
outputSchema: toolOutputSchemas.search_knowledge_graph
|
|
1031
|
-
}, wrapHandler("search_knowledge_graph", async (input) => client.searchGraph(input)));
|
|
1032
|
-
server.registerTool("get_document_index_status", {
|
|
1033
|
-
annotations: {
|
|
1034
|
-
readOnlyHint: true,
|
|
1035
|
-
destructiveHint: false,
|
|
1036
|
-
idempotentHint: true,
|
|
1037
|
-
openWorldHint: false
|
|
1038
|
-
},
|
|
1039
|
-
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.",
|
|
1040
|
-
inputSchema: z4.object({
|
|
1041
|
-
documentId: z4.string().uuid().describe("UUID of a document returned by search_documents or list_documents; it must be readable in the active scope.")
|
|
1042
|
-
}),
|
|
1043
|
-
outputSchema: toolOutputSchemas.get_document_index_status
|
|
1044
|
-
}, wrapHandler("get_document_index_status", async ({ documentId }) => client.getDocumentIndexStatus(documentId)));
|
|
1045
|
-
server.registerTool("refresh_document_index", {
|
|
1046
|
-
annotations: {
|
|
1047
|
-
readOnlyHint: false,
|
|
1048
|
-
destructiveHint: false,
|
|
1049
|
-
idempotentHint: false,
|
|
1050
|
-
openWorldHint: false
|
|
1051
|
-
},
|
|
1052
|
-
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.",
|
|
1053
|
-
inputSchema: z4.object({
|
|
1054
|
-
documentId: z4.string().uuid().describe("UUID of the document to refresh, obtained from search_documents or list_documents and visible in the active scope.")
|
|
1055
|
-
}),
|
|
1056
|
-
outputSchema: toolOutputSchemas.refresh_document_index
|
|
1057
|
-
}, wrapHandler("refresh_document_index", async ({ documentId }) => client.refreshDocumentIndex(documentId)));
|
|
1058
|
-
server.registerPrompt("organize_workspace", {
|
|
1059
|
-
description: "Plan safe document organization using DocsMint categories and folders.",
|
|
1060
|
-
argsSchema: z4.object({
|
|
1061
|
-
objective: z4.string(),
|
|
1062
|
-
language: z4.string().optional()
|
|
1063
|
-
})
|
|
1064
|
-
}, ({ objective, language }) => ({
|
|
1065
|
-
messages: [
|
|
1066
|
-
{
|
|
1067
|
-
role: "user",
|
|
1068
|
-
content: {
|
|
1069
|
-
type: "text",
|
|
1070
|
-
text: `Organize this DocsMint workspace for: ${objective}. Work in ${language ?? "the document language"}. Inspect categories, folders, tags, and documents before proposing or applying changes. Preserve document content and obey the API key scope.`
|
|
1071
|
-
}
|
|
1072
|
-
}
|
|
1073
|
-
]
|
|
1074
|
-
}));
|
|
1075
|
-
server.registerPrompt("research_workspace", {
|
|
1076
|
-
description: "Research a question with hybrid search and GraphRAG while citing DocsMint document IDs.",
|
|
1077
|
-
argsSchema: z4.object({
|
|
1078
|
-
question: z4.string(),
|
|
1079
|
-
language: z4.string().optional()
|
|
1080
|
-
})
|
|
1081
|
-
}, ({ question, language }) => ({
|
|
1082
|
-
messages: [
|
|
1083
|
-
{
|
|
1084
|
-
role: "user",
|
|
1085
|
-
content: {
|
|
1086
|
-
type: "text",
|
|
1087
|
-
text: `Answer this question from DocsMint: ${question}. Respond in ${language ?? "the question language"}. Start with hybrid search, use graph traversal only from authorized result documents, and cite document IDs. Distinguish retrieved facts from inference.`
|
|
1088
|
-
}
|
|
1089
|
-
}
|
|
1090
|
-
]
|
|
1091
|
-
}));
|
|
1092
|
-
server.registerResource("editor-guide", "docsmint://guide/editor", {}, async (uri) => ({
|
|
1093
|
-
contents: [
|
|
1094
|
-
{
|
|
1095
|
-
uri: uri.href,
|
|
1096
|
-
mimeType: "text/markdown",
|
|
1097
|
-
text: `# DocsMint editing rules
|
|
1098
|
-
|
|
1099
|
-
Read a document before updating it. Preserve its language, title intent, TipTap/Markdown structure, category, folder, and tags unless the user explicitly requests a change. After content changes, verify index status and request refresh only when needed.`
|
|
1100
|
-
}
|
|
1101
|
-
]
|
|
1102
|
-
}));
|
|
1103
|
-
server.registerResource("search-guide", "docsmint://guide/search", {}, async (uri) => ({
|
|
1104
|
-
contents: [
|
|
1105
|
-
{
|
|
1106
|
-
uri: uri.href,
|
|
1107
|
-
mimeType: "text/markdown",
|
|
1108
|
-
text: `# DocsMint retrieval rules
|
|
1109
|
-
|
|
1110
|
-
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.`
|
|
1111
|
-
}
|
|
1112
|
-
]
|
|
1113
|
-
}));
|
|
1114
|
-
server.registerResource("workspace-catalog", "docsmint://workspace/catalog", {}, async (uri) => {
|
|
1115
|
-
const [categories, folders, tags] = await Promise.all([
|
|
1116
|
-
client.listCategories(),
|
|
1117
|
-
client.listFolders({}),
|
|
1118
|
-
client.listTags()
|
|
1119
|
-
]);
|
|
1120
|
-
return {
|
|
1121
|
-
contents: [
|
|
1122
|
-
{
|
|
1123
|
-
uri: uri.href,
|
|
1124
|
-
mimeType: "application/json",
|
|
1125
|
-
text: JSON.stringify({ categories, folders, tags }, null, 2)
|
|
1126
|
-
}
|
|
1127
|
-
]
|
|
1128
|
-
};
|
|
1129
|
-
});
|
|
1130
|
-
}
|
|
878
|
+
// ../mcp-server/src/batch-workspace.ts
|
|
879
|
+
import { z as z2 } from "zod";
|
|
1131
880
|
|
|
1132
881
|
// ../mcp-server/src/client.ts
|
|
1133
882
|
var DEFAULT_BASE_URL = "http://localhost:50700";
|
|
@@ -1167,6 +916,7 @@ function sanitizeMcpRequestContext(context) {
|
|
|
1167
916
|
function createMcpDocsClient(docsClient, requestContext) {
|
|
1168
917
|
const context = sanitizeMcpRequestContext(requestContext);
|
|
1169
918
|
return {
|
|
919
|
+
getFolder: (id) => docsClient.getFolder(id, context),
|
|
1170
920
|
createTag: (input) => docsClient.createTag(input, context),
|
|
1171
921
|
updateTag: (id, input) => docsClient.updateTag(id, input, context),
|
|
1172
922
|
deleteTag: (id) => docsClient.deleteTag(id, context),
|
|
@@ -1220,236 +970,298 @@ var client = new Proxy({}, {
|
|
|
1220
970
|
}
|
|
1221
971
|
});
|
|
1222
972
|
|
|
1223
|
-
// ../mcp-server/src/
|
|
1224
|
-
var
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
})
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
}
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
});
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
}
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
};
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
};
|
|
1309
|
-
var handler4 = createHandler4(client);
|
|
973
|
+
// ../mcp-server/src/batch-workspace.ts
|
|
974
|
+
var uuid = z2.string().uuid().describe("UUID of an item visible to the active API key.");
|
|
975
|
+
var documentIds = z2.array(uuid).min(1).max(25).refine((ids) => new Set(ids).size === ids.length, "Document IDs must be unique.").describe("One to 25 distinct document UUIDs, explicitly selected by the user; no search expansion.");
|
|
976
|
+
var base = { documentIds };
|
|
977
|
+
var batchInput = z2.discriminatedUnion("action", [
|
|
978
|
+
z2.strictObject({ ...base, action: z2.literal("move").describe("Move each document to the same folder."), folderId: uuid.nullable().describe("Destination folder UUID, or null for no folder.") }),
|
|
979
|
+
z2.strictObject({ ...base, action: z2.literal("set_category").describe("Set one explicit category on every document."), categoryId: uuid.nullable().describe("Category UUID, or null to clear explicit category.") }),
|
|
980
|
+
z2.strictObject({ ...base, action: z2.literal("add_tag").describe("Assign one existing tag to every document."), tagId: uuid.describe("Existing tag UUID to assign to each document.") }),
|
|
981
|
+
z2.strictObject({ ...base, action: z2.literal("remove_tag").describe("Remove one tag assignment from every document."), tagId: uuid.describe("Existing tag UUID to unassign from each document.") }),
|
|
982
|
+
z2.strictObject({ ...base, action: z2.literal("trash").describe("Move every document to trash without permanent deletion.") }),
|
|
983
|
+
z2.strictObject({ ...base, action: z2.literal("restore").describe("Restore every selected document from trash.") }),
|
|
984
|
+
z2.strictObject({ ...base, action: z2.literal("refresh_index").describe("Request explicit indexing retry for every document.") })
|
|
985
|
+
]);
|
|
986
|
+
function required(method, name) {
|
|
987
|
+
if (!method)
|
|
988
|
+
throw new Error(`The injected legacy MCP client does not support ${name}; use a public DocsClient.`);
|
|
989
|
+
return method;
|
|
990
|
+
}
|
|
991
|
+
function registerBatchAndWorkspaceCapabilities(server, client2, wrap) {
|
|
992
|
+
async function batch(input) {
|
|
993
|
+
const results = [];
|
|
994
|
+
let aborted = false;
|
|
995
|
+
for (const id of input.documentIds) {
|
|
996
|
+
if (aborted) {
|
|
997
|
+
results.push({ id, status: "skipped" });
|
|
998
|
+
continue;
|
|
999
|
+
}
|
|
1000
|
+
try {
|
|
1001
|
+
switch (input.action) {
|
|
1002
|
+
case "move":
|
|
1003
|
+
await client2.updateDocument(id, { folderId: input.folderId });
|
|
1004
|
+
break;
|
|
1005
|
+
case "set_category":
|
|
1006
|
+
await client2.updateDocument(id, { categoryId: input.categoryId });
|
|
1007
|
+
break;
|
|
1008
|
+
case "add_tag":
|
|
1009
|
+
await required(client2.addTagToDocument, "add_tag")(id, input.tagId);
|
|
1010
|
+
break;
|
|
1011
|
+
case "remove_tag":
|
|
1012
|
+
await required(client2.removeTagFromDocument, "remove_tag")(id, input.tagId);
|
|
1013
|
+
break;
|
|
1014
|
+
case "trash":
|
|
1015
|
+
await required(client2.deleteDocument, "trash")(id);
|
|
1016
|
+
break;
|
|
1017
|
+
case "restore":
|
|
1018
|
+
await required(client2.restoreTrashedDocument, "restore")(id);
|
|
1019
|
+
break;
|
|
1020
|
+
case "refresh_index":
|
|
1021
|
+
await client2.refreshDocumentIndex(id);
|
|
1022
|
+
break;
|
|
1023
|
+
}
|
|
1024
|
+
results.push({ id, status: "ok" });
|
|
1025
|
+
} catch (error) {
|
|
1026
|
+
const known = isDocsApiError(error) || error instanceof HiaiDocsError;
|
|
1027
|
+
const status = known ? error.status : 500;
|
|
1028
|
+
const code = known ? error.code : "INTERNAL_ERROR";
|
|
1029
|
+
results.push({ id, status: "error", error: { status, code, message: known ? error.message : "Document operation failed" } });
|
|
1030
|
+
if (status === 401 || status === 429)
|
|
1031
|
+
aborted = true;
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1034
|
+
const succeeded = results.filter((result) => result.status === "ok").length;
|
|
1035
|
+
return { action: input.action, total: input.documentIds.length, succeeded, failed: results.filter((result) => result.status === "error").length, aborted, results };
|
|
1036
|
+
}
|
|
1037
|
+
server.registerTool("batch_documents", {
|
|
1038
|
+
description: "Apply one action to 1\u201325 explicitly selected document IDs. Supports move, set_category, add_tag, remove_tag, trash, restore, or refresh_index. Processes sequentially through the existing API so each document keeps its own workspace and category permission check. Returns per-ID success or error; partial success is possible. Stops after authentication or rate-limit failure. Permanent purge and version restore are intentionally separate tools.",
|
|
1039
|
+
inputSchema: batchInput,
|
|
1040
|
+
outputSchema: toolOutputSchemas.batch_documents,
|
|
1041
|
+
annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: false }
|
|
1042
|
+
}, wrap("batch_documents", batch, toolOutputSchemas.batch_documents));
|
|
1043
|
+
server.registerTool("get_workspace_item", {
|
|
1044
|
+
description: "Read one visible folder, category, or tag by UUID. Folder uses its direct API getter; category and tag lookup uses the complete permission-filtered lists. An absent or out-of-scope ID is reported as not found. Use list_workspace_structure to discover IDs first.",
|
|
1045
|
+
inputSchema: z2.strictObject({ kind: z2.enum(["folder", "category", "tag"]).describe("The workspace resource type to read by ID."), id: uuid }),
|
|
1046
|
+
outputSchema: toolOutputSchemas.get_workspace_item,
|
|
1047
|
+
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false }
|
|
1048
|
+
}, wrap("get_workspace_item", async ({ kind, id }) => {
|
|
1049
|
+
if (kind === "folder")
|
|
1050
|
+
return { operation: kind, result: await required(client2.getFolder, "get_workspace_item(folder)")(id) };
|
|
1051
|
+
const listed = kind === "category" ? await client2.listCategories() : await client2.listTags();
|
|
1052
|
+
const result = Array.isArray(listed) ? listed.find((item) => item.id === id) : undefined;
|
|
1053
|
+
if (!result)
|
|
1054
|
+
throw new HiaiDocsError(`${kind} not found`, 404, null, "NOT_FOUND");
|
|
1055
|
+
return { operation: kind, result };
|
|
1056
|
+
}, toolOutputSchemas.get_workspace_item));
|
|
1057
|
+
}
|
|
1310
1058
|
|
|
1311
|
-
// ../mcp-server/src/
|
|
1312
|
-
var
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
}
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1059
|
+
// ../mcp-server/src/compact.ts
|
|
1060
|
+
var uuid2 = z3.string().uuid().describe("UUID returned by the corresponding list or read operation.");
|
|
1061
|
+
var text = z3.string().min(1).describe("Non-empty human-readable name or title.");
|
|
1062
|
+
var title = z3.string().min(1).max(500).describe("Document title, from 1 to 500 characters.");
|
|
1063
|
+
var content = z3.string().describe("Markdown document content; an empty string clears the content on update.");
|
|
1064
|
+
var read = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
|
|
1065
|
+
var write = { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false };
|
|
1066
|
+
var destructive = { ...write, destructiveHint: true };
|
|
1067
|
+
function required2(value, name) {
|
|
1068
|
+
if (!value)
|
|
1069
|
+
throw new Error(`The injected legacy MCP client does not support ${name}; use a public DocsClient.`);
|
|
1070
|
+
return value;
|
|
1071
|
+
}
|
|
1072
|
+
function registerCompactCapabilities(server, client2, wrap) {
|
|
1073
|
+
function register(name, description, inputSchema, annotations, handler) {
|
|
1074
|
+
server.registerTool(name, { description, inputSchema, outputSchema: toolOutputSchemas[name], annotations }, wrap(name, handler, toolOutputSchemas[name]));
|
|
1075
|
+
}
|
|
1076
|
+
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.", z3.discriminatedUnion("mode", [
|
|
1077
|
+
z3.strictObject({ mode: z3.literal("list").describe("Select the list operation explicitly."), folderId: uuid2.optional(), tag: uuid2.optional(), page: z3.number().int().min(1).optional().describe("One-based page number; defaults to the API first page."), limit: z3.number().int().min(1).max(1000).optional().describe("Maximum documents per page, up to 1000.") }),
|
|
1078
|
+
z3.strictObject({ mode: z3.literal("search").describe("Select the search operation explicitly."), query: text.describe("Text to search in the original language."), folder: z3.string().optional().describe("Optional folder UUID filter for search."), tags: z3.array(z3.string()).optional().describe("Optional tag names; all supplied names must match."), limit: z3.number().int().min(1).max(100).optional().describe("Maximum results to return, up to 100.") })
|
|
1079
|
+
]), read, async (input) => input.mode === "list" ? { operation: "list", result: await client2.listDocuments(input) } : { operation: "search", result: await client2.search(input) });
|
|
1080
|
+
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.", z3.discriminatedUnion("view", [
|
|
1081
|
+
z3.strictObject({ view: z3.literal("detail").describe("Select the detail operation explicitly."), id: uuid2 }),
|
|
1082
|
+
z3.strictObject({ view: z3.literal("markdown").describe("Select the markdown operation explicitly."), id: uuid2 }),
|
|
1083
|
+
z3.strictObject({ view: z3.literal("versions").describe("Select the versions operation explicitly."), id: uuid2, onlySnapshots: z3.boolean().optional().describe("When true, return only named snapshots.") })
|
|
1084
|
+
]), read, async (input) => {
|
|
1085
|
+
if (input.view === "detail")
|
|
1086
|
+
return { operation: "detail", result: await client2.getDocument(input.id) };
|
|
1087
|
+
if (input.view === "markdown")
|
|
1088
|
+
return { operation: "markdown", result: await client2.exportDocument(input.id) };
|
|
1089
|
+
return { operation: "versions", result: await client2.getVersionHistory(input.id, input.onlySnapshots) };
|
|
1090
|
+
});
|
|
1091
|
+
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.", z3.discriminatedUnion("action", [
|
|
1092
|
+
z3.strictObject({ action: z3.literal("create").describe("Select the create operation explicitly."), title: title.optional(), content: content.optional(), folderId: uuid2.optional(), categoryId: uuid2.nullable().optional().describe("Optional category UUID; null clears the explicit category.") }),
|
|
1093
|
+
z3.strictObject({ action: z3.literal("update").describe("Select the update operation explicitly."), id: uuid2, title: title.optional(), content: content.optional(), folderId: uuid2.nullable().optional().describe("Optional folder UUID; null clears the placement on update."), categoryId: uuid2.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)
|
|
1094
|
+
]), destructive, async (input) => {
|
|
1095
|
+
if (input.action === "create") {
|
|
1096
|
+
const { action: _action2, ...data2 } = input;
|
|
1097
|
+
return { operation: "create", result: await client2.createDocument(data2) };
|
|
1098
|
+
}
|
|
1099
|
+
const { action: _action, id, ...data } = input;
|
|
1100
|
+
return { operation: "update", result: await client2.updateDocument(id, data) };
|
|
1101
|
+
});
|
|
1102
|
+
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.", z3.strictObject({ id: uuid2 }), destructive, async ({ id }) => {
|
|
1103
|
+
await required2(client2.deleteDocument, "delete_document")(id);
|
|
1104
|
+
return { id, deleted: true };
|
|
1105
|
+
});
|
|
1106
|
+
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.", z3.discriminatedUnion("kind", [
|
|
1107
|
+
z3.strictObject({ kind: z3.literal("folders").describe("Select the folders operation explicitly."), parentId: uuid2.optional() }),
|
|
1108
|
+
z3.strictObject({ kind: z3.literal("categories").describe("Select the categories operation explicitly.") }),
|
|
1109
|
+
z3.strictObject({ kind: z3.literal("tags").describe("Select the tags operation explicitly.") })
|
|
1110
|
+
]), read, async (input) => {
|
|
1111
|
+
if (input.kind === "folders")
|
|
1112
|
+
return { operation: "folders", result: await client2.listFolders({ parentId: input.parentId }) };
|
|
1113
|
+
if (input.kind === "categories")
|
|
1114
|
+
return { operation: "categories", result: await client2.listCategories() };
|
|
1115
|
+
return { operation: "tags", result: await client2.listTags() };
|
|
1116
|
+
});
|
|
1117
|
+
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.", z3.discriminatedUnion("action", [
|
|
1118
|
+
z3.strictObject({ action: z3.literal("create").describe("Select the create operation explicitly."), name: text.max(255), parentId: uuid2.nullable().optional().describe("Optional parent folder UUID; null selects the root."), categoryId: uuid2.nullable().optional().describe("Optional category UUID; null clears the explicit category.") }),
|
|
1119
|
+
z3.strictObject({ action: z3.literal("update").describe("Select the update operation explicitly."), id: uuid2, name: text.max(255).optional(), parentId: uuid2.nullable().optional().describe("Optional parent folder UUID; null selects the root."), categoryId: uuid2.nullable().optional().describe("Optional category UUID; null clears the explicit category."), order: z3.number().int().nonnegative().optional().describe("New non-negative display order.") }).refine((value) => value.name !== undefined || value.parentId !== undefined || value.categoryId !== undefined || value.order !== undefined)
|
|
1120
|
+
]), destructive, async (input) => {
|
|
1121
|
+
if (input.action === "create") {
|
|
1122
|
+
const { action: _action2, ...data2 } = input;
|
|
1123
|
+
return { operation: "create", result: await client2.createFolder(data2) };
|
|
1124
|
+
}
|
|
1125
|
+
const { action: _action, id, ...data } = input;
|
|
1126
|
+
return { operation: "update", result: await required2(client2.updateFolder, "update_folder")(id, data) };
|
|
1127
|
+
});
|
|
1128
|
+
register("delete_folder", "Delete a folder while preserving its documents; child folders and documents are detached under the API rules. Requires write access.", z3.strictObject({ id: uuid2 }), destructive, async ({ id }) => {
|
|
1129
|
+
await required2(client2.deleteFolder, "delete_folder")(id);
|
|
1130
|
+
return { id, deleted: true };
|
|
1131
|
+
});
|
|
1132
|
+
register("save_category", "Create or update a workspace category. Full workspace write access is required; category-scoped credentials cannot manage categories.", z3.discriminatedUnion("action", [
|
|
1133
|
+
z3.strictObject({ action: z3.literal("create").describe("Select the create operation explicitly."), name: text.max(255) }),
|
|
1134
|
+
z3.strictObject({ action: z3.literal("update").describe("Select the update operation explicitly."), id: uuid2, name: text.max(255).optional(), order: z3.number().int().nonnegative().optional().describe("New non-negative display order.") }).refine((value) => value.name !== undefined || value.order !== undefined)
|
|
1135
|
+
]), destructive, async (input) => {
|
|
1136
|
+
if (input.action === "create")
|
|
1137
|
+
return { operation: "create", result: await client2.createCategory({ name: input.name }) };
|
|
1138
|
+
const { action: _action, id, ...data } = input;
|
|
1139
|
+
return { operation: "update", result: await required2(client2.updateCategory, "update_category")(id, data) };
|
|
1140
|
+
});
|
|
1141
|
+
register("delete_category", "Delete a workspace category and detach its documents without deleting them. Requires full workspace write access; category-scoped credentials are denied.", z3.strictObject({ id: uuid2 }), destructive, async ({ id }) => {
|
|
1142
|
+
await required2(client2.deleteCategory, "delete_category")(id);
|
|
1143
|
+
return { id, deleted: true };
|
|
1144
|
+
});
|
|
1145
|
+
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.", z3.discriminatedUnion("action", [
|
|
1146
|
+
z3.strictObject({ action: z3.literal("create").describe("Select the create operation explicitly."), name: text.max(100), color: z3.string().max(20).optional().describe("Optional tag color, at most 20 characters.") }),
|
|
1147
|
+
z3.strictObject({ action: z3.literal("update").describe("Select the update operation explicitly."), id: uuid2, name: text.max(100).optional(), color: z3.string().max(20).optional().describe("Optional tag color, at most 20 characters.") }).refine((value) => value.name !== undefined || value.color !== undefined)
|
|
1148
|
+
]), destructive, async (input) => {
|
|
1149
|
+
if (input.action === "create")
|
|
1150
|
+
return { operation: "create", result: await required2(client2.createTag, "create_tag")({ name: input.name, color: input.color }) };
|
|
1151
|
+
const { action: _action, id, ...data } = input;
|
|
1152
|
+
return { operation: "update", result: await required2(client2.updateTag, "update_tag")(id, data) };
|
|
1153
|
+
});
|
|
1154
|
+
register("delete_tag", "Delete a workspace tag and remove its document assignments. Full workspace write access is required; documents themselves remain.", z3.strictObject({ id: uuid2 }), destructive, async ({ id }) => {
|
|
1155
|
+
await required2(client2.deleteTag, "delete_tag")(id);
|
|
1156
|
+
return { id, deleted: true };
|
|
1157
|
+
});
|
|
1158
|
+
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.", z3.strictObject({ action: z3.enum(["add", "remove"]).describe("Add or remove exactly one tag assignment."), documentId: uuid2, tagId: uuid2 }), destructive, async ({ action, documentId, tagId }) => {
|
|
1159
|
+
if (action === "add") {
|
|
1160
|
+
await required2(client2.addTagToDocument, "add_tag_to_document")(documentId, tagId);
|
|
1161
|
+
return { operation: "add", result: { documentId, tagId, assigned: true } };
|
|
1162
|
+
}
|
|
1163
|
+
await required2(client2.removeTagFromDocument, "remove_tag_from_document")(documentId, tagId);
|
|
1164
|
+
return { operation: "remove", result: { documentId, tagId, removed: true } };
|
|
1165
|
+
});
|
|
1166
|
+
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.", z3.strictObject({ documentId: uuid2, label: text.max(200).describe("Snapshot label, from 1 to 200 characters."), description: z3.string().max(1000).optional().describe("Optional snapshot note, at most 1000 characters.") }), write, async ({ documentId, label, description }) => client2.createSnapshot(documentId, { label, description }));
|
|
1167
|
+
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.", z3.strictObject({ documentId: uuid2, versionId: uuid2 }), destructive, async ({ documentId, versionId }) => required2(client2.restoreDocumentVersion, "restore_document_version")(documentId, versionId));
|
|
1168
|
+
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.", z3.discriminatedUnion("mode", [
|
|
1169
|
+
z3.strictObject({ mode: z3.literal("neighbors").describe("Select the neighbors operation explicitly."), documentId: uuid2, limit: z3.number().int().min(1).max(100).optional().describe("Maximum results to return, up to 100.") }),
|
|
1170
|
+
z3.strictObject({ mode: z3.literal("search").describe("Select the search operation explicitly."), docIds: z3.array(uuid2).min(1).max(50).describe("One to 50 authorized seed document UUIDs."), query: z3.string().max(2000).optional().describe("Optional graph relevance query, at most 2000 characters."), limit: z3.number().int().min(1).max(100).optional().describe("Maximum results to return, up to 100.") })
|
|
1171
|
+
]), read, async (input) => input.mode === "neighbors" ? { operation: "neighbors", result: await client2.getRelatedDocuments(input.documentId, input.limit) } : { operation: "search", result: await client2.searchGraph(input) });
|
|
1172
|
+
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.", z3.strictObject({ documentId: uuid2 }), read, async ({ documentId }) => client2.getDocumentIndexStatus(documentId));
|
|
1173
|
+
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.", z3.strictObject({ documentId: uuid2 }), write, async ({ documentId }) => client2.refreshDocumentIndex(documentId));
|
|
1174
|
+
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.", z3.strictObject({}), read, async () => required2(client2.listTrash, "list_trash")());
|
|
1175
|
+
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.", z3.strictObject({ id: uuid2 }), write, async ({ id }) => required2(client2.restoreTrashedDocument, "restore_trashed_document")(id));
|
|
1176
|
+
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.", z3.strictObject({ id: uuid2 }), destructive, async ({ id }) => {
|
|
1177
|
+
await required2(client2.permanentlyDeleteDocument, "permanently_delete_document")(id);
|
|
1178
|
+
return { id, deleted: true };
|
|
1179
|
+
});
|
|
1180
|
+
registerBatchAndWorkspaceCapabilities(server, client2, wrap);
|
|
1181
|
+
}
|
|
1330
1182
|
|
|
1331
|
-
// ../mcp-server/src/
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
}
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1183
|
+
// ../mcp-server/src/prompts-resources.ts
|
|
1184
|
+
import { z as z4 } from "zod";
|
|
1185
|
+
function registerPromptsAndResources(server, client2) {
|
|
1186
|
+
server.registerPrompt("organize_workspace", {
|
|
1187
|
+
description: "Plan safe document organization using DocsMint categories and folders.",
|
|
1188
|
+
argsSchema: z4.object({
|
|
1189
|
+
objective: z4.string(),
|
|
1190
|
+
language: z4.string().optional()
|
|
1191
|
+
})
|
|
1192
|
+
}, ({ objective, language }) => ({
|
|
1193
|
+
messages: [
|
|
1194
|
+
{
|
|
1195
|
+
role: "user",
|
|
1196
|
+
content: {
|
|
1197
|
+
type: "text",
|
|
1198
|
+
text: `Organize this DocsMint workspace for: ${objective}. Work in ${language ?? "the document language"}. Inspect categories, folders, tags, and documents before proposing or applying changes. Preserve document content and obey the API key scope.`
|
|
1199
|
+
}
|
|
1200
|
+
}
|
|
1201
|
+
]
|
|
1202
|
+
}));
|
|
1203
|
+
server.registerPrompt("research_workspace", {
|
|
1204
|
+
description: "Research a question with hybrid search and GraphRAG while citing DocsMint document IDs.",
|
|
1205
|
+
argsSchema: z4.object({
|
|
1206
|
+
question: z4.string(),
|
|
1207
|
+
language: z4.string().optional()
|
|
1208
|
+
})
|
|
1209
|
+
}, ({ question, language }) => ({
|
|
1210
|
+
messages: [
|
|
1211
|
+
{
|
|
1212
|
+
role: "user",
|
|
1213
|
+
content: {
|
|
1214
|
+
type: "text",
|
|
1215
|
+
text: `Answer this question from DocsMint: ${question}. Respond in ${language ?? "the question language"}. Start with hybrid search, use graph traversal only from authorized result documents, and cite document IDs. Distinguish retrieved facts from inference.`
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
]
|
|
1219
|
+
}));
|
|
1220
|
+
server.registerResource("editor-guide", "docsmint://guide/editor", {}, async (uri) => ({
|
|
1221
|
+
contents: [
|
|
1222
|
+
{
|
|
1223
|
+
uri: uri.href,
|
|
1224
|
+
mimeType: "text/markdown",
|
|
1225
|
+
text: `# DocsMint editing rules
|
|
1353
1226
|
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
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.",
|
|
1365
|
-
inputSchema: {
|
|
1366
|
-
parentId: z11.string().uuid().optional().describe("Optional parent folder UUID from list_folders; omit to list root folders.")
|
|
1367
|
-
}
|
|
1368
|
-
};
|
|
1369
|
-
var createHandler7 = (api) => async function listFolders(args) {
|
|
1370
|
-
return await api.listFolders(args);
|
|
1371
|
-
};
|
|
1372
|
-
var handler7 = createHandler7(client);
|
|
1227
|
+
Read a document before updating it. Preserve its language, title intent, TipTap/Markdown structure, category, folder, and tags unless the user explicitly requests a change. After content changes, verify index status and request refresh only when needed.`
|
|
1228
|
+
}
|
|
1229
|
+
]
|
|
1230
|
+
}));
|
|
1231
|
+
server.registerResource("search-guide", "docsmint://guide/search", {}, async (uri) => ({
|
|
1232
|
+
contents: [
|
|
1233
|
+
{
|
|
1234
|
+
uri: uri.href,
|
|
1235
|
+
mimeType: "text/markdown",
|
|
1236
|
+
text: `# DocsMint retrieval rules
|
|
1373
1237
|
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
return await api.search({
|
|
1394
|
-
query: args.query,
|
|
1395
|
-
folder: args.folder,
|
|
1396
|
-
tags: args.tags,
|
|
1397
|
-
limit: args.limit
|
|
1238
|
+
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.`
|
|
1239
|
+
}
|
|
1240
|
+
]
|
|
1241
|
+
}));
|
|
1242
|
+
server.registerResource("workspace-catalog", "docsmint://workspace/catalog", {}, async (uri) => {
|
|
1243
|
+
const [categories, folders, tags] = await Promise.all([
|
|
1244
|
+
client2.listCategories(),
|
|
1245
|
+
client2.listFolders({}),
|
|
1246
|
+
client2.listTags()
|
|
1247
|
+
]);
|
|
1248
|
+
return {
|
|
1249
|
+
contents: [
|
|
1250
|
+
{
|
|
1251
|
+
uri: uri.href,
|
|
1252
|
+
mimeType: "application/json",
|
|
1253
|
+
text: JSON.stringify({ categories, folders, tags }, null, 2)
|
|
1254
|
+
}
|
|
1255
|
+
]
|
|
1256
|
+
};
|
|
1398
1257
|
});
|
|
1399
|
-
}
|
|
1400
|
-
var handler8 = createHandler8(client);
|
|
1401
|
-
|
|
1402
|
-
// ../mcp-server/src/tools/update-document.ts
|
|
1403
|
-
var exports_update_document = {};
|
|
1404
|
-
__export(exports_update_document, {
|
|
1405
|
-
createHandler: () => createHandler9,
|
|
1406
|
-
definition: () => definition9,
|
|
1407
|
-
handler: () => handler9
|
|
1408
|
-
});
|
|
1409
|
-
import { z as z13 } from "zod";
|
|
1410
|
-
var definition9 = {
|
|
1411
|
-
name: "update_document",
|
|
1412
|
-
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.",
|
|
1413
|
-
inputSchema: {
|
|
1414
|
-
id: z13.string().uuid().describe("UUID of the existing document, obtained from search_documents, list_documents, or get_document."),
|
|
1415
|
-
title: z13.string().min(1).max(500).optional().describe("Optional replacement title, 1 to 500 characters; omit to leave the current title unchanged."),
|
|
1416
|
-
content: z13.string().optional().describe("New markdown content for the document."),
|
|
1417
|
-
folderId: z13.string().uuid().nullable().optional().describe("Optional destination folder UUID from list_folders; omit to keep current placement or pass null to remove folder placement."),
|
|
1418
|
-
categoryId: z13.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.")
|
|
1419
|
-
}
|
|
1420
|
-
};
|
|
1421
|
-
var createHandler9 = (api) => async function updateDocument(args) {
|
|
1422
|
-
const { id, ...patch } = args;
|
|
1423
|
-
return await api.updateDocument(id, patch);
|
|
1424
|
-
};
|
|
1425
|
-
var handler9 = createHandler9(client);
|
|
1426
|
-
|
|
1427
|
-
// ../mcp-server/src/tools/version-history.ts
|
|
1428
|
-
var exports_version_history = {};
|
|
1429
|
-
__export(exports_version_history, {
|
|
1430
|
-
createHandler: () => createHandler10,
|
|
1431
|
-
definition: () => definition10,
|
|
1432
|
-
handler: () => handler10
|
|
1433
|
-
});
|
|
1434
|
-
import { z as z14 } from "zod";
|
|
1435
|
-
var definition10 = {
|
|
1436
|
-
name: "get_version_history",
|
|
1437
|
-
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.",
|
|
1438
|
-
inputSchema: {
|
|
1439
|
-
documentId: z14.string().uuid().describe("UUID of the readable document whose version history you need; obtain it from search_documents or list_documents."),
|
|
1440
|
-
onlySnapshots: z14.boolean().optional().describe("When true, return only named snapshots and omit auto-saved revisions; omit or use false for the full history.")
|
|
1441
|
-
}
|
|
1442
|
-
};
|
|
1443
|
-
var createHandler10 = (api) => async function getVersionHistory(args) {
|
|
1444
|
-
return await api.getVersionHistory(args.documentId, args.onlySnapshots);
|
|
1445
|
-
};
|
|
1446
|
-
var handler10 = createHandler10(client);
|
|
1258
|
+
}
|
|
1447
1259
|
|
|
1448
1260
|
// ../mcp-server/src/server.ts
|
|
1449
|
-
function wrapHandler(name,
|
|
1261
|
+
function wrapHandler(name, handler, outputSchema) {
|
|
1450
1262
|
return async (args) => {
|
|
1451
1263
|
try {
|
|
1452
|
-
const output = await
|
|
1264
|
+
const output = await handler(args);
|
|
1453
1265
|
const parsedOutput = outputSchema ? await outputSchema.safeParseAsync(output) : undefined;
|
|
1454
1266
|
if (parsedOutput && !parsedOutput.success) {
|
|
1455
1267
|
throw new Error(`Tool '${name}' returned a result outside its published output schema`);
|
|
@@ -1484,50 +1296,11 @@ function wrapHandler(name, handler11, outputSchema) {
|
|
|
1484
1296
|
};
|
|
1485
1297
|
}
|
|
1486
1298
|
function registerDocsmintMcpCapabilities(server, client2) {
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
description,
|
|
1490
|
-
inputSchema: z15.object(inputSchema),
|
|
1491
|
-
annotations: {
|
|
1492
|
-
readOnlyHint: ![
|
|
1493
|
-
"create_document",
|
|
1494
|
-
"update_document",
|
|
1495
|
-
"create_folder",
|
|
1496
|
-
"create_snapshot"
|
|
1497
|
-
].includes(name),
|
|
1498
|
-
destructiveHint: name === "update_document",
|
|
1499
|
-
idempotentHint: ![
|
|
1500
|
-
"create_document",
|
|
1501
|
-
"update_document",
|
|
1502
|
-
"create_folder",
|
|
1503
|
-
"create_snapshot"
|
|
1504
|
-
].includes(name),
|
|
1505
|
-
openWorldHint: false
|
|
1506
|
-
},
|
|
1507
|
-
outputSchema: toolOutputSchemas[name]
|
|
1508
|
-
}, wrapHandler(name, handler11, toolOutputSchemas[name]));
|
|
1509
|
-
};
|
|
1510
|
-
const tools = [
|
|
1511
|
-
exports_search,
|
|
1512
|
-
exports_get_document,
|
|
1513
|
-
exports_create_document,
|
|
1514
|
-
exports_update_document,
|
|
1515
|
-
exports_list_documents,
|
|
1516
|
-
exports_list_folders,
|
|
1517
|
-
exports_create_folder,
|
|
1518
|
-
exports_create_snapshot,
|
|
1519
|
-
exports_version_history,
|
|
1520
|
-
exports_export_document
|
|
1521
|
-
];
|
|
1522
|
-
for (const tool of tools) {
|
|
1523
|
-
register(tool.definition.name, tool.definition.description, tool.definition.inputSchema, tool.createHandler(client2));
|
|
1524
|
-
}
|
|
1525
|
-
registerExtendedCapabilities(server, client2, (name, handler11) => wrapHandler(name, handler11, toolOutputSchemas[name]));
|
|
1526
|
-
registerLifecycleCapabilities(server, client2, (name, handler11) => wrapHandler(name, handler11, toolOutputSchemas[name]));
|
|
1527
|
-
registerManagementCapabilities(server, client2, (name, handler11) => wrapHandler(name, handler11, toolOutputSchemas[name]));
|
|
1299
|
+
registerCompactCapabilities(server, client2, wrapHandler);
|
|
1300
|
+
registerPromptsAndResources(server, client2);
|
|
1528
1301
|
}
|
|
1529
1302
|
function createDocsmintMcpServer(options = {}) {
|
|
1530
|
-
const server = new McpServer({ name: "docsmint", version: "0.
|
|
1303
|
+
const server = new McpServer({ name: "docsmint", version: "1.0.1" });
|
|
1531
1304
|
const client2 = options.docsClient ? createMcpDocsClient(options.docsClient, options.requestContext) : options.client ?? createMcpDocsClient(createDefaultDocsClient(), options.requestContext);
|
|
1532
1305
|
registerDocsmintMcpCapabilities(server, client2);
|
|
1533
1306
|
return server;
|