365center-mcp 1.2.1 → 1.2.2
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/dist/index.js +14 -14
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -41,7 +41,7 @@ server.tool("create_site", "Create a new SharePoint site. Template: 'communicati
|
|
|
41
41
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
42
42
|
});
|
|
43
43
|
// ============ DOCUMENTS ============
|
|
44
|
-
server.tool("list_document_libraries", "List all document libraries (drives) in a SharePoint site. Returns driveId for each library
|
|
44
|
+
server.tool("list_document_libraries", "List all document libraries (drives) in a SharePoint site. Returns driveId and listId for each library. Use driveId for file operations (upload, download, delete, list, versions). Use listId for metadata operations (list_columns, get/set_document_metadata, create columns). Call this first when working with documents — you need both IDs.", { siteId: z.string().describe("SharePoint site ID") }, async ({ siteId }) => {
|
|
45
45
|
const libraries = await listDocumentLibraries(siteId);
|
|
46
46
|
return { content: [{ type: "text", text: JSON.stringify(libraries, null, 2) }] };
|
|
47
47
|
});
|
|
@@ -53,7 +53,7 @@ server.tool("list_documents", "List documents in a document library folder. Retu
|
|
|
53
53
|
const docs = await listDocuments(siteId, driveId, folderId || "root");
|
|
54
54
|
return { content: [{ type: "text", text: JSON.stringify(docs, null, 2) }] };
|
|
55
55
|
});
|
|
56
|
-
server.tool("upload_document", "Upload a local file to a SharePoint document library.
|
|
56
|
+
server.tool("upload_document", "Upload a single local file to a SharePoint document library. Root folder by default, or specific folder via folderId. After upload, use set_document_metadata to tag it. Supports up to 250 GB (auto session upload for >4 MB). For multiple files, prefer upload_documents — up to 30 files per call with inline metadata and built-in rate limit protection. NOTE: If using Highlighted Content web parts, filename prefix determines filtering. The 'Title includes the words' filter is SUBSTRING-based — e.g. 'Report' will also match 'ReportQ1' or 'ReportAnnual'. Use non-overlapping prefixes.", {
|
|
57
57
|
siteId: z.string().describe("SharePoint site ID"),
|
|
58
58
|
driveId: z.string().describe("Document library (drive) ID"),
|
|
59
59
|
fileName: z.string().describe("Name for the file in SharePoint"),
|
|
@@ -72,7 +72,7 @@ server.tool("download_document", "Download a document from a SharePoint document
|
|
|
72
72
|
const result = await downloadDocument(siteId, driveId, itemId, localPath);
|
|
73
73
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
74
74
|
});
|
|
75
|
-
server.tool("upload_documents", "
|
|
75
|
+
server.tool("upload_documents", "Batch upload up to 30 files to SharePoint with optional inline metadata per file. Files >4 MB use resumable upload. Built-in 500ms delay between files prevents HTTP 429 from Microsoft. Returns per-file status for upload and metadata independently. When setting metadata, listId is required. Choice values must match predefined choices exactly (case-sensitive). For large batches, split into multiple calls of max 30 files each. Same substring warning as upload_document — if using Highlighted Content web parts, filename prefixes determine which section shows which documents.", {
|
|
76
76
|
siteId: z.string().describe("SharePoint site ID"),
|
|
77
77
|
driveId: z.string().describe("Document library (drive) ID"),
|
|
78
78
|
listId: z.string().optional().describe("List ID — required only if setting metadata via fields"),
|
|
@@ -89,7 +89,7 @@ server.tool("upload_documents", "Upload one or more files to SharePoint, optiona
|
|
|
89
89
|
const results = await uploadDocuments(siteId, driveId, listId, files, folderId || "root");
|
|
90
90
|
return { content: [{ type: "text", text: JSON.stringify(results, null, 2) }] };
|
|
91
91
|
});
|
|
92
|
-
server.tool("search_documents", "Search for documents in a SharePoint site", {
|
|
92
|
+
server.tool("search_documents", "Search for documents across all libraries in a SharePoint site by keyword. Search indexes may take a few minutes to reflect newly uploaded documents.", {
|
|
93
93
|
siteId: z.string().describe("SharePoint site ID"),
|
|
94
94
|
query: z.string().describe("Search query"),
|
|
95
95
|
}, async ({ siteId, query }) => {
|
|
@@ -122,7 +122,7 @@ server.tool("get_document_versions", "Get version history of a document (audit t
|
|
|
122
122
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
123
123
|
});
|
|
124
124
|
// ============ METADATA ============
|
|
125
|
-
server.tool("list_columns", "List
|
|
125
|
+
server.tool("list_columns", "List custom metadata columns in a SharePoint list/library. listId can be display name (e.g. 'Documents') or GUID. Returns internal name, display name, type, and choices. Call this before set_document_metadata — internal column names (used in API) often differ from display names (shown in UI). Using wrong name fails silently.", {
|
|
126
126
|
siteId: z.string().describe("SharePoint site ID"),
|
|
127
127
|
listId: z.string().describe("List or document library list ID"),
|
|
128
128
|
}, async ({ siteId, listId }) => {
|
|
@@ -149,7 +149,7 @@ server.tool("create_text_column", "Create a single-line text metadata column in
|
|
|
149
149
|
const result = await createTextColumn(siteId, listId, name, displayName);
|
|
150
150
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
151
151
|
});
|
|
152
|
-
server.tool("set_document_metadata", "Set metadata fields on a document.
|
|
152
|
+
server.tool("set_document_metadata", "Set metadata fields on a document. 'fields' is a JSON string of key-value pairs using column internal names. Choice values must match predefined choices exactly (case-sensitive). Multi-select: use array of strings. Columns must exist first — check with list_columns. Accepts drive item ID (requires driveId) or numeric list item ID. Only change fields the user asked for — leave others untouched. TIP: Changing a Status field (e.g. to 'Pending Approval') can trigger Power Automate flows with 'When item modified' trigger — no HTTP webhooks or extra tools needed.", {
|
|
153
153
|
siteId: z.string().describe("SharePoint site ID"),
|
|
154
154
|
listId: z.string().describe("List or document library list ID"),
|
|
155
155
|
itemId: z.string().describe("Document ID — either numeric list item ID or drive item ID"),
|
|
@@ -170,11 +170,11 @@ server.tool("get_document_metadata", "Get all metadata fields of a document incl
|
|
|
170
170
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
171
171
|
});
|
|
172
172
|
// ============ PAGES ============
|
|
173
|
-
server.tool("list_pages", "List all pages
|
|
173
|
+
server.tool("list_pages", "List all pages via Graph API. Returns page GUID, name, title, URL, and state. Use page GUID for publish_page, delete_page, add_quick_links. NOTE: Canvas tools (get/set_page_canvas_content) need NUMERIC item IDs from list_site_pages instead — GUIDs from this tool won't work there.", { siteId: z.string().describe("SharePoint site ID") }, async ({ siteId }) => {
|
|
174
174
|
const pages = await listPages(siteId);
|
|
175
175
|
return { content: [{ type: "text", text: JSON.stringify(pages, null, 2) }] };
|
|
176
176
|
});
|
|
177
|
-
server.tool("create_page", "Create a new empty
|
|
177
|
+
server.tool("create_page", "Create a new empty page in checkout/draft state. MUST call publish_page after to make it visible. 'name' becomes URL slug (e.g. 'my-page' → my-page.aspx). For pages with text sections, use create_page_with_content. For pages with web parts (Highlighted Content etc.), create empty page first, then set_page_canvas_content, then publish_page.", {
|
|
178
178
|
siteId: z.string().describe("SharePoint site ID"),
|
|
179
179
|
title: z.string().describe("Page title"),
|
|
180
180
|
name: z.string().describe("Page file name (without .aspx)"),
|
|
@@ -182,7 +182,7 @@ server.tool("create_page", "Create a new empty SharePoint page. Page is created
|
|
|
182
182
|
const result = await createPage(siteId, title, name);
|
|
183
183
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
184
184
|
});
|
|
185
|
-
server.tool("create_page_with_content", "Create a
|
|
185
|
+
server.tool("create_page_with_content", "Create a page with HTML text sections. Draft state — MUST call publish_page after. Sections is a JSON string array. Layouts: oneColumn (12), twoColumns (6+6), threeColumns (4+4+4), oneThirdLeftColumn (4+8), oneThirdRightColumn (8+4), fullWidth (12). Example: [{\"layout\":\"twoColumns\",\"columns\":[{\"width\":6,\"html\":\"<h2>Left</h2>\"},{\"width\":6,\"html\":\"<h2>Right</h2>\"}]}]. NOTE: Only supports text/HTML. For web parts like Highlighted Content, use create_page + set_page_canvas_content instead.", {
|
|
186
186
|
siteId: z.string().describe("SharePoint site ID"),
|
|
187
187
|
title: z.string().describe("Page title"),
|
|
188
188
|
name: z.string().describe("Page file name (without .aspx)"),
|
|
@@ -203,7 +203,7 @@ server.tool("add_quick_links", "Add a Quick Links web part to a SharePoint page
|
|
|
203
203
|
const result = await addQuickLinksWebPart(siteId, pageId, links);
|
|
204
204
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
205
205
|
});
|
|
206
|
-
server.tool("publish_page", "Publish a
|
|
206
|
+
server.tool("publish_page", "Publish a page to make it visible. MUST call after: create_page, create_page_with_content, or set_page_canvas_content — without publishing, the page appears EMPTY to users. This is the most commonly forgotten step.", {
|
|
207
207
|
siteId: z.string().describe("SharePoint site ID"),
|
|
208
208
|
pageId: z.string().describe("Page ID"),
|
|
209
209
|
}, async ({ siteId, pageId }) => {
|
|
@@ -224,7 +224,7 @@ server.tool("get_navigation", "Get the top navigation menu links of a SharePoint
|
|
|
224
224
|
const result = await getNavigation(siteUrl);
|
|
225
225
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
226
226
|
});
|
|
227
|
-
server.tool("add_navigation_link", "Add a link to
|
|
227
|
+
server.tool("add_navigation_link", "Add a link to top navigation. REST API, delegated auth. siteUrl must include https://. url = link target (internal or external). Check get_navigation first to avoid duplicates.", {
|
|
228
228
|
siteUrl: z.string().describe("Full SharePoint site URL"),
|
|
229
229
|
title: z.string().describe("Navigation link title"),
|
|
230
230
|
url: z.string().describe("Navigation link URL"),
|
|
@@ -268,14 +268,14 @@ server.tool("remove_user_from_group", "Remove a user from a SharePoint group. Us
|
|
|
268
268
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
269
269
|
});
|
|
270
270
|
// ============ REST API — CANVAS CONTENT ============
|
|
271
|
-
server.tool("get_page_canvas_content", "Read
|
|
271
|
+
server.tool("get_page_canvas_content", "Read raw CanvasContent1 of a page via REST API. Returns full HTML including all web parts. Use to inspect existing page structure before modifying. pageItemId = numeric ID from list_site_pages (NOT GUID from list_pages). Uses delegated auth. ALWAYS read before calling set_page_canvas_content — understand what's there before replacing it.", {
|
|
272
272
|
siteUrl: z.string().describe("Full SharePoint site URL (e.g. https://contoso.sharepoint.com/sites/MySite)"),
|
|
273
273
|
pageItemId: z.number().describe("Numeric item ID from Site Pages list (use list_site_pages to find it)"),
|
|
274
274
|
}, async ({ siteUrl, pageItemId }) => {
|
|
275
275
|
const result = await getPageCanvasContent(siteUrl, pageItemId);
|
|
276
276
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
277
277
|
});
|
|
278
|
-
server.tool("set_page_canvas_content", "
|
|
278
|
+
server.tool("set_page_canvas_content", "Replace entire page canvas via REST API. Overwrites ALL existing content. Uses delegated auth. pageItemId = numeric ID from list_site_pages. MUST call publish_page after — page reverts to draft and appears EMPTY without it. Canvas HTML rules: use pre-encoded entities directly ({ } : ") — never JSON.stringify then replace (double-escaping on file round-trips). Omit titleHTML property (causes escaping corruption) — titles render from searchablePlainTexts. Read current canvas with get_page_canvas_content first.", {
|
|
279
279
|
siteUrl: z.string().describe("Full SharePoint site URL"),
|
|
280
280
|
pageItemId: z.number().describe("Numeric item ID from Site Pages list"),
|
|
281
281
|
canvasContent: z.string().describe("Raw HTML/JSON canvas content string — get format from get_page_canvas_content on an existing page"),
|
|
@@ -291,7 +291,7 @@ server.tool("copy_page", "Copy an existing SharePoint page to create a new one.
|
|
|
291
291
|
const result = await copyPage(siteUrl, sourceFileName, targetFileName);
|
|
292
292
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
293
293
|
});
|
|
294
|
-
server.tool("list_site_pages", "List
|
|
294
|
+
server.tool("list_site_pages", "List pages via REST API. Returns NUMERIC item IDs needed for canvas tools (get/set_page_canvas_content). Also returns title and file name. Uses delegated auth. NOTE: This gives numeric IDs for canvas operations. For page GUIDs (needed by publish_page, delete_page), use list_pages instead.", {
|
|
295
295
|
siteUrl: z.string().describe("Full SharePoint site URL"),
|
|
296
296
|
}, async ({ siteUrl }) => {
|
|
297
297
|
const result = await listSitePages(siteUrl);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "365center-mcp",
|
|
3
|
-
"version": "1.2.
|
|
4
|
-
"description": "MCP server for Microsoft 365 / Office 365 SharePoint —
|
|
3
|
+
"version": "1.2.2",
|
|
4
|
+
"description": "MCP server for Microsoft 365 / Office 365 SharePoint — full read-write access to sites, documents, pages, metadata, navigation, and permissions",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"bin": {
|