wiki_create_or_update_page
Create or update wiki pages in Azure DevOps with markdown content. Specify wiki identifier, path, and content for precise documentation management using PAT authentication.
Instructions
Create or update a wiki page with content.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| content | Yes | The content of the wiki page in markdown format. | |
| etag | No | ETag for editing existing pages (optional, will be fetched if not provided). | |
| path | Yes | The path of the wiki page (e.g., '/Home' or '/Documentation/Setup'). | |
| project | No | The project name or ID where the wiki is located. If not provided, the default project will be used. | |
| wikiIdentifier | Yes | The unique identifier or name of the wiki. |
Implementation Reference
- src/tools/wiki.ts:156-271 (handler)The core handler implementation for the wiki_create_or_update_page tool. It handles creating new wiki pages or updating existing ones via direct REST API calls to Azure DevOps, managing ETags for updates.server.tool( WIKI_TOOLS.create_or_update_page, "Create or update a wiki page with content.", { wikiIdentifier: z.string().describe("The unique identifier or name of the wiki."), path: z.string().describe("The path of the wiki page (e.g., '/Home' or '/Documentation/Setup')."), content: z.string().describe("The content of the wiki page in markdown format."), project: z.string().optional().describe("The project name or ID where the wiki is located. If not provided, the default project will be used."), etag: z.string().optional().describe("ETag for editing existing pages (optional, will be fetched if not provided)."), }, async ({ wikiIdentifier, path, content, project, etag }) => { try { const connection = await connectionProvider(); const accessToken = await tokenProvider(); // Normalize the path const normalizedPath = path.startsWith("/") ? path : `/${path}`; const encodedPath = encodeURIComponent(normalizedPath); // Build the URL for the wiki page API const baseUrl = connection.serverUrl; const projectParam = project || ""; const url = `${baseUrl}/${projectParam}/_apis/wiki/wikis/${wikiIdentifier}/pages?path=${encodedPath}&api-version=7.1`; // First, try to create a new page (PUT without ETag) try { const createResponse = await fetch(url, { method: "PUT", headers: { "Authorization": `Bearer ${accessToken.token}`, "Content-Type": "application/json", }, body: JSON.stringify({ content: content }), }); if (createResponse.ok) { const result = await createResponse.json(); return { content: [ { type: "text", text: `Successfully created wiki page at path: ${normalizedPath}. Response: ${JSON.stringify(result, null, 2)}`, }, ], }; } // If creation failed with 409 (Conflict) or 500 (Page exists), try to update it if (createResponse.status === 409 || createResponse.status === 500) { // Page exists, we need to get the ETag and update it let currentEtag = etag; if (!currentEtag) { // Fetch current page to get ETag const getResponse = await fetch(url, { method: "GET", headers: { Authorization: `Bearer ${accessToken.token}`, }, }); if (getResponse.ok) { currentEtag = getResponse.headers.get("etag") || getResponse.headers.get("ETag") || undefined; if (!currentEtag) { const pageData = await getResponse.json(); currentEtag = pageData.eTag; } } if (!currentEtag) { throw new Error("Could not retrieve ETag for existing page"); } } // Now update the existing page with ETag const updateResponse = await fetch(url, { method: "PUT", headers: { "Authorization": `Bearer ${accessToken.token}`, "Content-Type": "application/json", "If-Match": currentEtag, }, body: JSON.stringify({ content: content }), }); if (updateResponse.ok) { const result = await updateResponse.json(); return { content: [ { type: "text", text: `Successfully updated wiki page at path: ${normalizedPath}. Response: ${JSON.stringify(result, null, 2)}`, }, ], }; } else { const errorText = await updateResponse.text(); throw new Error(`Failed to update page (${updateResponse.status}): ${errorText}`); } } else { const errorText = await createResponse.text(); throw new Error(`Failed to create page (${createResponse.status}): ${errorText}`); } } catch (fetchError) { throw fetchError; } } catch (error) { const errorMessage = error instanceof Error ? error.message : "Unknown error occurred"; return { content: [{ type: "text", text: `Error creating/updating wiki page: ${errorMessage}` }], isError: true, }; } } );
- src/tools/wiki.ts:159-165 (schema)Input schema using Zod for validating tool parameters: wikiIdentifier, path, content, project (optional), etag (optional).{ wikiIdentifier: z.string().describe("The unique identifier or name of the wiki."), path: z.string().describe("The path of the wiki page (e.g., '/Home' or '/Documentation/Setup')."), content: z.string().describe("The content of the wiki page in markdown format."), project: z.string().optional().describe("The project name or ID where the wiki is located. If not provided, the default project will be used."), etag: z.string().optional().describe("ETag for editing existing pages (optional, will be fetched if not provided)."), },
- src/tools.ts:15-26 (registration)The wiki tools, including wiki_create_or_update_page, are registered by calling configureWikiTools(server, tokenProvider, connectionProvider). This function uses server.tool() internally to register the tool.import { configureWikiTools } from "./tools/wiki.js"; import { configureWorkTools } from "./tools/work.js"; import { configureWorkItemTools } from "./tools/workitems.js"; function configureAllTools(server: McpServer, tokenProvider: () => Promise<AccessToken>, connectionProvider: () => Promise<WebApi>, userAgentProvider: () => string) { configureCoreTools(server, tokenProvider, connectionProvider, userAgentProvider); configureWorkTools(server, tokenProvider, connectionProvider); configureBuildTools(server, tokenProvider, connectionProvider, userAgentProvider); configureRepoTools(server, tokenProvider, connectionProvider, userAgentProvider); configureWorkItemTools(server, tokenProvider, connectionProvider, userAgentProvider); configureReleaseTools(server, tokenProvider, connectionProvider); configureWikiTools(server, tokenProvider, connectionProvider);
- src/tools/wiki.ts:10-16 (helper)Constant object mapping internal names to tool names, defining 'create_or_update_page' as 'wiki_create_or_update_page'.const WIKI_TOOLS = { list_wikis: "wiki_list_wikis", get_wiki: "wiki_get_wiki", list_wiki_pages: "wiki_list_pages", get_wiki_page_content: "wiki_get_page_content", create_or_update_page: "wiki_create_or_update_page", };
- src/microsoft-exact-tools.ts:186-308 (handler)Duplicate handler implementation in microsoft-exact-tools.ts, likely for an alternative tool registration mechanism.{ name: "wiki_create_or_update_page", description: "Create or update a wiki page with content.", inputSchema: { type: "object", properties: { wikiIdentifier: { type: "string", description: "The unique identifier or name of the wiki." }, path: { type: "string", description: "The path of the wiki page (e.g., '/Home' or '/Documentation/Setup')." }, content: { type: "string", description: "The content of the wiki page in markdown format." }, project: { type: "string", description: "The project name or ID where the wiki is located. If not provided, the default project will be used." }, etag: { type: "string", description: "ETag for editing existing pages (optional, will be fetched if not provided)." } }, required: ["wikiIdentifier", "path", "content"] }, handler: async (args, connection, tokenProvider) => { try { if (!tokenProvider) { throw new Error("Token provider is required for wiki page creation/update"); } const accessToken = await tokenProvider(); // Normalize the path const normalizedPath = args.path.startsWith("/") ? args.path : `/${args.path}`; const encodedPath = encodeURIComponent(normalizedPath); // Build the URL for the wiki page API const baseUrl = connection.serverUrl; const projectParam = args.project || ""; const url = `${baseUrl}/${projectParam}/_apis/wiki/wikis/${args.wikiIdentifier}/pages?path=${encodedPath}&api-version=7.1`; // First, try to create a new page (PUT without ETag) try { const createResponse = await fetch(url, { method: "PUT", headers: { "Authorization": `Bearer ${accessToken.token}`, "Content-Type": "application/json", }, body: JSON.stringify({ content: args.content }), }); if (createResponse.ok) { const result = await createResponse.json(); return { content: [ { type: "text", text: `Successfully created wiki page at path: ${normalizedPath}. Response: ${JSON.stringify(result, null, 2)}`, }, ], }; } // If creation failed with 409 (Conflict) or 500 (Page exists), try to update it if (createResponse.status === 409 || createResponse.status === 500) { // Page exists, we need to get the ETag and update it let currentEtag = args.etag; if (!currentEtag) { // Fetch current page to get ETag const getResponse = await fetch(url, { method: "GET", headers: { Authorization: `Bearer ${accessToken.token}`, }, }); if (getResponse.ok) { currentEtag = getResponse.headers.get("etag") || getResponse.headers.get("ETag") || undefined; if (!currentEtag) { const pageData = await getResponse.json(); currentEtag = pageData.eTag; } } if (!currentEtag) { throw new Error("Could not retrieve ETag for existing page"); } } // Now update the existing page with ETag const updateResponse = await fetch(url, { method: "PUT", headers: { "Authorization": `Bearer ${accessToken.token}`, "Content-Type": "application/json", "If-Match": currentEtag, }, body: JSON.stringify({ content: args.content }), }); if (updateResponse.ok) { const result = await updateResponse.json(); return { content: [ { type: "text", text: `Successfully updated wiki page at path: ${normalizedPath}. Response: ${JSON.stringify(result, null, 2)}`, }, ], }; } else { const errorText = await updateResponse.text(); throw new Error(`Failed to update page (${updateResponse.status}): ${errorText}`); } } else { const errorText = await createResponse.text(); throw new Error(`Failed to create page (${createResponse.status}): ${errorText}`); } } catch (fetchError) { throw fetchError; } } catch (error) { const errorMessage = error instanceof Error ? error.message : "Unknown error occurred"; return { content: [{ type: "text", text: `Error creating/updating wiki page: ${errorMessage}` }], isError: true, }; } } }