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 -versionreports 17). - Android Studio Ladybug (2024.2) or newer, with AGP 8.7.3+.
- An Android app module with
minSdk ≥ 24. - An
apiKeyandsiteKeypair from your MCPFeedback dashboard → Sites. - A terminal with
curlandshasum(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.
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.
# 1. Download the bundle and its checksum sidecar
curl -L -O https://mcpfeedback.com
/downloads/mcpfeedback-android-sdk-2.1.0-repo.zip
curl -L -O https://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-mcpfeedbackRegister 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
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
maven { url = uri("app/libs-mcpfeedback") }
}
}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
dependencies {
implementation("com.mcpfeedback:sdk:2.1.0")
}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.
<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>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.
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
)
}
}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://mcpfeedback.com under your site. After this, you should see your submission in the dashboard within seconds.
// 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.1Call from any button, menu item, settings row, or support link. Works from Activity or Fragment (pass requireActivity()).
✅Shake-to-invoke
v2.1Detects shake via SensorManager accelerometer. Opt-in at initialize() with shakeEnabled = true.
🔜Floating button
coming in v2.2Persistent WindowManager overlay button. Not available in v2.1.
🔜Screenshot-detected
coming in v2.2Auto-prompt after the user takes a system screenshot. Not available in v2.1.
🔜Menu-action helper
coming in v2.2Drop-in MenuItem that opens the feedback form. Not available in v2.1.
🔜Deep-link trigger
coming in v2.2Launch 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.
| Parameter | Type | Default | Description |
|---|---|---|---|
| apiKey | String | required | Your account-level API key from Dashboard > Settings > API Keys. |
| siteKey | String | required | The site identifier for the app/site this SDK instance reports to. |
| shakeEnabled | Boolean | true | When true, the SDK listens for a shake gesture and presents the feedback sheet automatically. |
| baseUrl | String? | null | Override 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.
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.
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:
- Explicit override — values passed via a future
themeColorssurface win. - Host theme attributes —
?attr/colorPrimary,?attr/colorSurface, and?attr/colorOnSurfaceon the launching Activity (Material 3, Material 2, and AppCompat all supported). - 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.
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.
| Axis | Supported |
|---|---|
| Android API | 24–35 (minSdk 24, compileSdk/targetSdk 35) |
| Kotlin | 2.0.21+ (2.0.x line) |
| AGP | 8.7.3+ (8.7.x line) |
| Compose BOM | 2024.10.00+ (your BOM wins — SDK ships compileOnly) |
| JDK toolchain | 17 |
| Java source/target | 11 |
| Hosts | Jetpack Compose, Views/XML, hybrid |
| Themes | Material 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://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.
Version history
v2.1.0 — 2026-04
Latestandroidx.startupinitializer — Context-lessMCPFeedback.initialize().- Coroutines-native API:
suspend fun submitFeedback()andFlow<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.
FeedbackErrorsealed class with typed subclasses.- 4 Gradle modules with frozen public API (Binary Compatibility Validator), single AAR artifact.
- PII redaction pipeline;
sendDefaultPii = falsedefault. - 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.