Skip to main content
Glama

upload_artifact

Upload APK or AAB files to create releases on Google Play Console tracks, enabling controlled app distribution to internal, alpha, beta, or production users.

Instructions

Upload an APK or AAB and create a release on the given track.

File type auto-detected from extension (.apk/.aab). Upload and track assignment are atomic.

Args: package_name: Package name, e.g. com.example.myapp file_path: Absolute local path to the APK or AAB. track: "internal" (default), "alpha", "beta", or "production". status: "draft" (default), "inProgress", or "completed". rollout_percentage: Rollout % when status is "inProgress". Default 10%. release_name: Optional human-readable name. release_notes: Optional {lang: text} dict, e.g. {"en-US": "Initial release"}.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
package_nameYes
file_pathYes
trackNointernal
statusNodraft
rollout_percentageNo
release_nameNo
release_notesNo

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
resultYes

Implementation Reference

  • MCP tool registration and wrapper for upload_artifact, which delegates to the underlying publisher client.
    @mcp.tool()
    def upload_artifact(
        package_name: str,
        file_path: str,
        track: str = "internal",
        status: str = "draft",
        rollout_percentage: float = 10.0,
        release_name: str = "",
        release_notes: Optional[dict] = None,
    ) -> str:
        """Upload an APK or AAB and create a release on the given track.
    
        File type auto-detected from extension (.apk/.aab). Upload and track
        assignment are atomic.
    
        Args:
            package_name: Package name, e.g. com.example.myapp
            file_path: Absolute local path to the APK or AAB.
            track: "internal" (default), "alpha", "beta", or "production".
            status: "draft" (default), "inProgress", or "completed".
            rollout_percentage: Rollout % when status is "inProgress". Default 10%.
            release_name: Optional human-readable name.
            release_notes: Optional {lang: text} dict, e.g. {"en-US": "Initial release"}.
        """
        try:
            notes = _notes_from_dict(release_notes)
            result = _publisher().upload_artifact(
                package_name=package_name,
                file_path=file_path,
                track=track,
                rollout_percentage=rollout_percentage if status == "inProgress" else None,
                release_name=release_name or None,
                release_notes=notes,
                status=status,
            )
  • Actual implementation of the upload_artifact logic, handling the file upload and track assignment process.
    def upload_artifact(
        self,
        package_name: str,
        file_path: str,
        track: str,
        rollout_percentage: Optional[float] = None,
        release_name: Optional[str] = None,
        release_notes: Optional[List[Dict[str, str]]] = None,
        status: str = "draft",
    ) -> Dict[str, Any]:
        """Upload an APK or AAB and create a release on the given track.
    
        File type is inferred from the extension (.apk or .aab).
        Everything (upload + track assignment) happens in a single edit.
        """
        ext = os.path.splitext(file_path)[1].lower()
        if ext == ".apk":
            mime = APK_MIME
            artifact_type = "apk"
        elif ext == ".aab":
            mime = BUNDLE_MIME
            artifact_type = "bundle"
        else:
            raise ValueError(f"Unrecognized file extension '{ext}'. Use .apk or .aab.")
    
        media = MediaFileUpload(file_path, mimetype=mime, resumable=True)
        edit_id = self._create_edit(package_name)
        try:
            if artifact_type == "apk":
                artifact = self.service.edits().apks().upload(
                    packageName=package_name, editId=edit_id, media_body=media
                ).execute()
            else:
                artifact = self.service.edits().bundles().upload(
                    packageName=package_name, editId=edit_id, media_body=media
                ).execute()
    
            version_code = artifact["versionCode"]
            release: Dict[str, Any] = {
                "versionCodes": [str(version_code)],
                "status": status,
            }
            if status == "inProgress" and rollout_percentage is not None:
                if rollout_percentage >= 100:
                    release["status"] = "completed"
                else:
                    release["userFraction"] = round(rollout_percentage / 100.0, 4)
            if release_name:
                release["name"] = release_name
            if release_notes:
                release["releaseNotes"] = release_notes
    
            updated_track = self._update_track(
                package_name, edit_id, track, {"track": track, "releases": [release]}
            )
            commit = self._commit_edit(package_name, edit_id)
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of behavioral disclosure. It adds valuable operational context (file auto-detection from extension, atomic upload/assignment transaction) but lacks explicit safety warnings or side-effect disclosure for this mutation-heavy operation (uploading and creating releases). It does not mention idempotency, error behavior on duplicate uploads, or revertibility.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured with a clear purpose statement upfront, followed by behavioral notes, then the Args section. Given 0% schema coverage, the detailed Args block is necessary rather than verbose. Sentences earn their place: first establishes purpose, second confirms atomicity, Args section provides essential parameter documentation otherwise missing from schema.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description adequately covers all 7 parameters through the Args section and mentions domain-specific context (APK/AAB, tracks, rollout percentages). Since an output schema exists, omitting return value explanation is acceptable. However, given this is a complex mutation tool with no annotations, it could better clarify the relationship to sibling `create_release` (file upload vs. metadata-only) and `upload_to_internal_sharing` (track release vs. internal sharing).

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With schema description coverage at 0%, the Args section fully compensates by providing semantic meaning for every parameter: valid enum values for track/status, format examples for package_name and release_notes, and dependency constraints (rollout_percentage only applies when status is 'inProgress'). This exceeds baseline expectations for high-coverage schemas.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the action ('Upload an APK or AAB and create a release') and target resource ('on the given track'). It implicitly distinguishes from `list_artifacts` (read vs. write) and `upload_to_internal_sharing` (track-based vs. internal sharing via the 'track' focus), though it could explicitly clarify when to use this versus `create_release` (which may not involve file upload).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides implied usage guidance through parameter defaults (internal track, draft status) and notes atomicity, but lacks explicit when-to-use/when-not-to-use guidance regarding siblings. It does not state prerequisites (e.g., package must exist) or contrast with `create_release` (which might create releases from existing artifacts) or `promote_release` (which moves existing releases between tracks).

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

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/AgiMaulana/GooglePlayConsoleMcp'

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