MCPFeedback Android SDKv2.1.0

Embeddable Android feedback widget — drop it in, your users shake or tap to report, and feedback lands in your dashboard. Native Kotlin, Compose-first UI, a frozen public API, and a single AAR drop-in.

Requires Android 7.0+ (API 24+), Kotlin 2.0+, AGP 8.x, JDK 17.

Always verify the SHA-256 sidecar before extracting.

🔧 v2.1.1 hotfix AAR

Drop-in patch on top of v2.1.0 with two fixes:

  • Feedback form adds a Type picker (Bug / Feature / UX / Comment) alongside Severity.
  • 4xx errors now surface field-level detail — e.g. Invalid request body: reporter_email - valid reporter_email is required — instead of a generic message.

Replace app/libs-mcpfeedback/com/mcpfeedback/sdk/2.1.0/sdk-2.1.0.aar with this file (rename to sdk-2.1.0.aar) to patch an existing install without re-running the full bundle flow.

Prerequisites

  • JDK 17 installed and active (java -version reports 17).
  • Android Studio Ladybug (2024.2) or newer, with AGP 8.7.3+.
  • An Android app module with minSdk ≥ 24.
  • An apiKey and siteKey pair from your MCPFeedback dashboard → Sites.
  • A terminal with curl and shasum (or equivalent) for checksum verification.

Step-by-step integration

Six steps, roughly ten minutes end-to-end. Every snippet below is copy-pasteable and verified against the v2.1.0 BCV-frozen public API.

1

Download the SDK bundle

Fetch the signed local Maven repo zip, verify its SHA-256, and extract it into app/libs-mcpfeedback/. The extracted tree is a real Maven repository layout containing the umbrella com.mcpfeedback:sdk artifact plus its three module publications and POMs. After this, you should see app/libs-mcpfeedback/com/mcpfeedback/sdk/2.1.0/ in your project tree.

terminal
# 1. Download the bundle and its checksum sidecar
curl -L -O https://staging.mcpfeedback.com/downloads/mcpfeedback-android-sdk-2.1.0-repo.zip
curl -L -O https://staging.mcpfeedback.com/downloads/mcpfeedback-android-sdk-2.1.0-repo.zip.sha256

# 2. Verify the checksum (expect: "mcpfeedback-android-sdk-2.1.0-repo.zip: OK")
shasum -a 256 -c mcpfeedback-android-sdk-2.1.0-repo.zip.sha256

# 3. Extract into your app module
mkdir -p app/libs-mcpfeedback
unzip -q mcpfeedback-android-sdk-2.1.0-repo.zip -d app/libs-mcpfeedback
2

Register the local Maven repo

Point Gradle at the extracted directory as a local Maven repository. Transitive dependencies (androidx, compose, okhttp, etc.) resolve automatically via the included POMs — you do not list them explicitly. After this, a Gradle sync should resolve the repo without errors.

settings.gradle.kts
// settings.gradle.kts
dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
        maven { url = uri("app/libs-mcpfeedback") }
    }
}
3

Add the dependency

Declare a single dependency on the umbrella artifact. One AAR ships; the sdk-core, sdk-networking, and sdk-ui modules resolve transitively. After this, a Gradle sync should download and index com.mcpfeedback:sdk:2.1.0.

app/build.gradle.kts
// app/build.gradle.kts
dependencies {
    implementation("com.mcpfeedback:sdk:2.1.0")
}
4

Add manifest permissions

INTERNET is required to upload feedback. The two FOREGROUND_SERVICE permissions are optional — only needed if you plan to use MediaProjection-based screen recording for session replay (shipping in v2.2). After this, your app should build cleanly.

app/src/main/AndroidManifest.xml
<manifest>
    <uses-permission android:name="android.permission.INTERNET" />

    <!-- Optional  only for MediaProjection screen recording (v2.2) -->
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION" />

    <application ...>
        <!-- your activities -->
    </application>
</manifest>
5

Initialize — no Context required

v2.1 uses androidx.startup to capture the application Context automatically before your first line of code runs. Call MCPFeedback.initialize() from any Activity's onCreate or your Application.onCreate — you do NOT need an Application subclass. After this, logcat should show an SdkLogger line confirming initialization.

MainActivity.kt
import com.mcpfeedback.sdk.MCPFeedback

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        MCPFeedback.initialize(
            apiKey = "YOUR_API_KEY",
            siteKey = "YOUR_SITE_KEY",
            shakeEnabled = true,
            // baseUrl = null  // optional self-hosted override
        )
    }
}
6

Trigger feedback

Call MCPFeedback.show(activity) from a button, menu item, or support link — OR simply shake the device (enabled via shakeEnabled = true at init). Submit a test report and confirm it lands on your dashboard at https://staging.mcpfeedback.com under your site. After this, you should see your submission in the dashboard within seconds.

MainActivity.kt
// From an Activity:
helpButton.setOnClickListener {
    MCPFeedback.show(this@MainActivity)
}

// From a Fragment:
MCPFeedback.show(requireActivity())

Invocation methods

v2.1.0 ships two invocation entry points as real public API. Four additional methods appear in the sample app as placeholders marked [coming-soon v2.2] and will ship in the next minor release.

Programmatic — MCPFeedback.show(activity)

v2.1

Call from any button, menu item, settings row, or support link. Works from Activity or Fragment (pass requireActivity()).

Shake-to-invoke

v2.1

Detects shake via SensorManager accelerometer. Opt-in at initialize() with shakeEnabled = true.

🔜Floating button

coming in v2.2

Persistent WindowManager overlay button. Not available in v2.1.

🔜Screenshot-detected

coming in v2.2

Auto-prompt after the user takes a system screenshot. Not available in v2.1.

🔜Menu-action helper

coming in v2.2

Drop-in MenuItem that opens the feedback form. Not available in v2.1.

🔜Deep-link trigger

coming in v2.2

Launch feedback via an intent filter (mcpfeedback://open). Not available in v2.1.

Configuration reference

The v2.1.0 public API exposes four initialization parameters. The extended configuration surface (screenshot detection, floating button, session replay, network logging, privacy tiers) is deferred to v2.2.

ParameterTypeDefaultDescription
apiKeyStringrequiredYour account-level API key from Dashboard > Settings > API Keys.
siteKeyStringrequiredThe site identifier for the app/site this SDK instance reports to.
shakeEnabledBooleantrueWhen true, the SDK listens for a shake gesture and presents the feedback sheet automatically.
baseUrlString?nullOverride the API endpoint for self-hosted MCPFeedback deployments. Leave null for the production cloud.

Observing upload state

Collect MCPFeedback.observeUpload(uploadId) inside a lifecycle-aware coroutine scope to react to progress, success, or failure.

MainActivity.kt
import com.mcpfeedback.sdk.MCPFeedback
import com.mcpfeedback.sdk.repo.UploadState

lifecycleScope.launch {
    MCPFeedback.observeUpload(uploadId).collect { state ->
        when (state) {
            is UploadState.InProgress -> progress.isVisible = true
            is UploadState.Succeeded  -> toast("Feedback sent")
            is UploadState.Failed     -> toast("Failed: ${state.error.message}")
        }
    }
}

Suspend submission

Submit feedback without presenting the UI — useful for custom bug-report forms or programmatic error reporting. Every thrown error is mapped to a typed FeedbackError before crossing the SDK boundary.

MainActivity.kt
import com.mcpfeedback.sdk.MCPFeedback
import com.mcpfeedback.sdk.repo.FeedbackRequest

lifecycleScope.launch {
    val request = FeedbackRequest(
        message = "Tapping the cart icon in the XL layout dismisses the drawer.",
        metadata = mapOf("screen" to "checkout", "build" to BuildConfig.VERSION_NAME),
        screenshotPngBytes = null,
    )
    MCPFeedback.submitFeedback(request)
        .onSuccess { receipt -> /* receipt.id */ }
        .onFailure { err -> /* err: FeedbackError */ }
}

Theming

The SDK resolves your host theme at invocation time via a three-tier bridge — no configuration needed for the common case:

  1. Explicit override — values passed via a future themeColors surface win.
  2. Host theme attributes ?attr/colorPrimary, ?attr/colorSurface, and ?attr/colorOnSurface on the launching Activity (Material 3, Material 2, and AppCompat all supported).
  3. Neutral default — sensible hard-coded colors if no host theme is resolvable.

Auto dark mode is wired via Configuration.uiMode. See the sample app's M2 / M3 / AppCompat runtime toggle for a live demonstration.

Error handling

Every public API returns a typed FeedbackError sealed class — your app never catches a raw SDK exception. Each error carries code, message, and suggestedAction.

MainActivity.kt
import com.mcpfeedback.sdk.repo.FeedbackError

when (val err = result.exceptionOrNull() as? FeedbackError) {
    is FeedbackError.NetworkUnavailable   -> showOfflineBanner()
    is FeedbackError.PermissionDenied     -> promptForPermission(err.permission)
    is FeedbackError.InvalidConfiguration -> Log.e("App", err.suggestedAction)
    null                                  -> Unit
    else                                  -> Log.e("App", err.message)
}

Compatibility matrix

Tested in CI on API 30 / 33 / 34 / 35 with R8 enabled. Source: mcpfeedback-android/docs/COMPATIBILITY-MATRIX.md.

AxisSupported
Android API24–35 (minSdk 24, compileSdk/targetSdk 35)
Kotlin2.0.21+ (2.0.x line)
AGP8.7.3+ (8.7.x line)
Compose BOM2024.10.00+ (your BOM wins — SDK ships compileOnly)
JDK toolchain17
Java source/target11
HostsJetpack Compose, Views/XML, hybrid
ThemesMaterial 3, Material 2, AppCompat

Troubleshooting

Gradle: Could not find com.mcpfeedback:sdk:2.1.0

Confirm you extracted the zip into app/libs-mcpfeedback/ and that the settings.gradle.kts maven { url = uri("app/libs-mcpfeedback") } path is correct relative to the root project. The directory should contain com/mcpfeedback/sdk/2.1.0/sdk-2.1.0.aar.

shasum: SHA-256 mismatch on the downloaded zip

Re-download both the zip and the .sha256 sidecar from https://staging.mcpfeedback.com/downloads. A mismatch usually means a truncated download — delete and retry. Never proceed to extract a bundle that fails checksum verification.

No feedback appears in the dashboard after submission

Verify your apiKey and siteKey are the exact pair shown together under Sites in the dashboard — mixing keys from two different sites is the most common cause. Check logcat for an SdkLogger ERROR line. Confirm the device has network connectivity; the SDK queues submissions offline and retries, but will not surface without INTERNET permission.

Shake gesture does not trigger the feedback sheet

Ensure you passed shakeEnabled = true to MCPFeedback.initialize(). On emulators, use Extended Controls → Virtual sensors → "Move" to simulate a shake. If you previously called MCPFeedback.destroy(), re-initialize to re-register the sensor listener.

Sample app

A reference integration exercising the v2.1.0 invocation methods across Compose and XML hosts, with a runtime Material 3 / Material 2 / AppCompat theme toggle. Two product flavors: compose and xml.

Download sample app
# Compose host ./gradlew :sample-app:installComposeDebug # XML / Views host ./gradlew :sample-app:installXmlDebug

Version history

v2.1.0 — 2026-04

Latest
  • androidx.startup initializer — Context-less MCPFeedback.initialize().
  • Coroutines-native API: suspend fun submitFeedback() and Flow<UploadState>.
  • Three-tier theme bridge — M2 / M3 / AppCompat inheritance, auto dark mode.
  • Enriched payload — device, network, orientation, fragment back-stack, depth-10 crash cause chain.
  • FeedbackError sealed class with typed subclasses.
  • 4 Gradle modules with frozen public API (Binary Compatibility Validator), single AAR artifact.
  • PII redaction pipeline; sendDefaultPii = false default.
  • MediaProjection FGS lifecycle safety for API 34+.

View the full CHANGELOG.md (repository is private — internal access only).

API reference

Full Kotlin API reference (Dokka)

Auto-generated from KDoc comments on every @PublicApi symbol — always in sync with the BCV-frozen public surface.