Skip to main content
Glama
AstroMined
by AstroMined

create_or_update_file

Create or update files in a GitHub repository with specified content, commit message, and branch. Manage file changes programmatically using the PyGithub MCP Server for efficient repository operations.

Instructions

Create or update a file in a GitHub repository.

Args: params: Dictionary with file parameters - owner: Repository owner (username or organization) - repo: Repository name - path: Path where to create/update the file - content: Content of the file - message: Commit message - branch: Branch to create/update the file in - sha: SHA of file being replaced (for updates, optional) Returns: MCP response with file creation/update result

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
paramsYes

Implementation Reference

  • MCP tool handler: validates params with schema and calls the core operation function.
    @tool() def create_or_update_file(params: Dict) -> Dict: """Create or update a file in a GitHub repository. Args: params: Dictionary with file parameters - owner: Repository owner (username or organization) - repo: Repository name - path: Path where to create/update the file - content: Content of the file - message: Commit message - branch: Branch to create/update the file in - sha: SHA of file being replaced (for updates, optional) Returns: MCP response with file creation/update result """ try: logger.debug(f"create_or_update_file called with params: {params}") # Convert dict to Pydantic model file_params = CreateOrUpdateFileParams(**params) # Call operation result = repositories.create_or_update_file(file_params) logger.debug(f"File created/updated: {file_params.path}") return { "content": [{"type": "text", "text": json.dumps(result, indent=2)}] } except ValidationError as e: logger.error(f"Validation error: {e}") return { "content": [{"type": "error", "text": f"Validation error: {str(e)}"}], "is_error": True } except GitHubError as e: logger.error(f"GitHub error: {e}") return { "content": [{"type": "error", "text": format_github_error(e)}], "is_error": True } except Exception as e: logger.error(f"Unexpected error: {e}") logger.error(traceback.format_exc()) error_msg = str(e) if str(e) else "An unexpected error occurred" return { "content": [{"type": "error", "text": f"Internal server error: {error_msg}"}], "is_error": True }
  • Pydantic input schema with validation for create_or_update_file tool parameters.
    class CreateOrUpdateFileParams(RepositoryRef): """Parameters for creating or updating a single file.""" model_config = ConfigDict(strict=True) path: str = Field(..., description="Path where to create/update the file") content: str = Field(..., description="Content of the file") message: str = Field(..., description="Commit message") branch: str = Field(..., description="Branch to create/update the file in") sha: Optional[str] = Field(None, description="SHA of file being replaced (for updates)") @field_validator('path') @classmethod def validate_path(cls, v): """Validate that path is not empty.""" if not v.strip(): raise ValueError("path cannot be empty") return v @field_validator('content') @classmethod def validate_content(cls, v): """Validate that content is not empty.""" if not v.strip(): raise ValueError("content cannot be empty") return v @field_validator('message') @classmethod def validate_message(cls, v): """Validate that message is not empty.""" if not v.strip(): raise ValueError("message cannot be empty") return v @field_validator('branch') @classmethod def validate_branch(cls, v): """Validate that branch is not empty.""" if not v.strip(): raise ValueError("branch cannot be empty") return v
  • Registration of the create_or_update_file tool via register_tools in the repositories module.
    def register(mcp: FastMCP) -> None: """Register all repository tools with the MCP server. Args: mcp: The MCP server instance """ from pygithub_mcp_server.tools import register_tools from .tools import ( get_repository, create_repository, fork_repository, search_repositories, get_file_contents, create_or_update_file, push_files, create_branch, list_commits ) # Register all repository tools register_tools(mcp, [ get_repository, create_repository, fork_repository, search_repositories, get_file_contents, create_or_update_file, push_files, create_branch, list_commits ])
  • Core helper function implementing GitHub API calls for file create/update using PyGitHub library.
    def create_or_update_file(params: CreateOrUpdateFileParams) -> Dict[str, Any]: """Create or update a file in a repository. Args: params: Parameters for creating or updating a file Returns: Result data including commit info Raises: GitHubError: If file creation/update fails """ logger.debug(f"Creating/updating file: {params.owner}/{params.repo}/{params.path}") try: client = GitHubClient.get_instance() repository = client.get_repo(f"{params.owner}/{params.repo}") # Build kwargs from Pydantic model kwargs = { "path": params.path, "message": params.message, "content": params.content, "branch": params.branch } # Determine whether to create or update based on sha presence if params.sha: # Update existing file result = repository.update_file(sha=params.sha, **kwargs) else: # Create new file result = repository.create_file(**kwargs) logger.debug(f"File created/updated successfully: {params.path}") # Log detailed information about the response structure for debugging logger.debug(f"Commit result type: {type(result['commit']).__name__}") if hasattr(result['commit'], 'commit'): logger.debug(f"Has nested commit: {result['commit'].commit is not None}") # Extract commit information safely with fallbacks commit_sha = None commit_message = None commit_url = None try: # Get commit SHA if hasattr(result["commit"], "sha"): commit_sha = result["commit"].sha # Get commit message with multiple fallbacks if hasattr(result["commit"], "commit") and result["commit"].commit is not None: if hasattr(result["commit"].commit, "message"): commit_message = result["commit"].commit.message if commit_message is None and hasattr(result["commit"], "message"): commit_message = result["commit"].message if commit_message is None: commit_message = params.message # Fall back to the provided commit message # Get commit URL if hasattr(result["commit"], "html_url"): commit_url = result["commit"].html_url except (AttributeError, KeyError) as e: logger.warning(f"Error extracting commit details: {e}") # Continue execution even if we can't get all commit details # Extract content information safely content_sha = None content_size = None content_url = None try: if hasattr(result["content"], "sha"): content_sha = result["content"].sha if hasattr(result["content"], "size"): content_size = result["content"].size if hasattr(result["content"], "html_url"): content_url = result["content"].html_url except (AttributeError, KeyError) as e: logger.warning(f"Error extracting content details: {e}") # Continue execution even if we can't get all content details return { "commit": { "sha": commit_sha, "message": commit_message, "html_url": commit_url }, "content": { "path": params.path, "sha": content_sha, "size": content_size, "html_url": content_url } } except GithubException as e: logger.error(f"GitHub exception when creating/updating file: {str(e)}") raise client._handle_github_exception(e, resource_hint="content_file")

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/AstroMined/pygithub-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server