create_or_update_file
Create a new file or update an existing one in a GitHub repository. Provide the file path, content, commit message, and branch; include the current SHA when updating.
Instructions
Create or update a single file in a GitHub repository. If updating an existing file, you must provide the current SHA of the file (the full 40-character SHA, not a shortened version).
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| owner | Yes | Repository owner (username or organization) | |
| repo | Yes | Repository name | |
| path | Yes | Path where to create/update the file | |
| content | Yes | Content of the file | |
| message | Yes | Commit message | |
| branch | Yes | Branch to create/update the file in | |
| sha | No | Full SHA of the current file blob (required for updates, must be the complete 40-character SHA) |
Implementation Reference
- src/tools/repositories.ts:407-408 (registration)Registration of the create_or_update_file tool via server.tool() within the registerRepositoryTools function
server.tool( "create_or_update_file", - src/tools/repositories.ts:410-423 (schema)Input schema for create_or_update_file: owner, repo, path, content, message, branch, and optional sha (40-character full SHA required for updates)
{ owner: z.string().describe("Repository owner (username or organization)"), repo: z.string().describe("Repository name"), path: z.string().describe("Path where to create/update the file"), content: z.string().describe("Content of the file"), message: z.string().describe("Commit message"), branch: z.string().describe("Branch to create/update the file in"), sha: z .string() .optional() .describe( "Full SHA of the current file blob (required for updates, must be the complete 40-character SHA)", ), }, - src/tools/repositories.ts:424-479 (handler)Handler function for create_or_update_file: validates SHA length (must be 40 chars), calls octokit.rest.repos.createOrUpdateFileContents with base64-encoded content, formats response as markdown with file and commit details, and provides helpful error messages for SHA mismatches
async ({ owner, repo, path, content, message, branch, sha }) => { try { // If SHA is provided, validate it's the full SHA if (sha && sha.length !== 40) { return { content: [ { type: "text", text: `Error: SHA must be the full 40-character blob SHA. Provided SHA "${sha}" is only ${sha.length} characters. Use get_file_contents to retrieve the full SHA.`, }, ], } } const response = await octokit.rest.repos.createOrUpdateFileContents({ owner, repo, path, message, content: Buffer.from(content).toString("base64"), branch, sha, }) // Format response as markdown let markdown = `# File ${response.data.commit.message}\n\n` markdown += `**Path:** ${response.data.content?.path || path}\n` markdown += `**SHA:** ${response.data.content?.sha || "N/A"}\n` markdown += `**Size:** ${response.data.content?.size || 0} bytes\n\n` markdown += `## Commit Details\n\n` markdown += `- **Commit SHA:** ${response.data.commit.sha}\n` markdown += `- **Author:** ${response.data.commit.author?.name} <${response.data.commit.author?.email}>\n` markdown += `- **Date:** ${response.data.commit.author?.date}\n` markdown += `- **URL:** ${response.data.commit.html_url}\n` return { content: [{ type: "text", text: markdown }], } } catch (e: any) { // Provide more helpful error messages if (e.message.includes("does not match")) { return { content: [ { type: "text", text: `Error: SHA mismatch. The provided SHA does not match the current file's SHA. This usually means the file has been modified since you last retrieved it. Use get_file_contents to get the current SHA, then retry the update.\n\nOriginal error: ${e.message}`, }, ], } } return { content: [{ type: "text", text: `Error: ${e.message}` }], } } }, )