Sailfish Devel MCP
This MCP server provides host-side tools for Sailfish OS development, device control/debugging, builds, OBS workflows, repository/QML inspection, and detached job management.
Check host/device readiness, list configured devices, and optionally install missing device prerequisites.
Access devices over SSH: read journals, inspect topmost window PID and process maps, run short or detached commands, manage services, and copy/install RPMs.
Control the Sailfish UI/session: take Lipstick screenshots, discover touchscreens and inject taps/swipes, run session D-Bus calls, execute user-session commands, launch desktop apps, and launch/debug Sailfish Browser.
Build Sailfish RPMs with Docker/mb2 or an installed SDK: preflight, start, status, cancel, and refresh SDK metadata; also run remote Android/AppSupport builds.
Use OBS tools to read results/build logs, watch builds, and read/preview/apply guarded source-pin edits.
Inspect local repositories: git status/search, RPM spec summaries, QML translation searches, and QML ternary translation checks.
Manage detached build/device/Android jobs via status/log/cancel tools or the
sailfish-devel-jobsCLI waiter.Optionally deploy and manage a privileged device companion for journal/D-Bus capture and routed device operations, with SSH fallback.
Provides tools for Sailfish OS development workflows, including device access over SSH, D-Bus session calls, Lipstick screenshots, touch injection, process inspection, journal logs, RPM installation, service management, user-session command execution, app launch, browser debugging, and SDK/OBS build integration.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Sailfish Devel MCP take a screenshot from my Sailfish device"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Sailfish Devel MCP
Host-side Model Context Protocol server for Sailfish OS development workflows.
This first iteration is dependency-free: it implements MCP over stdio directly with Python's standard library and exposes typed tools around commands that are easy to get wrong during day-to-day Sailfish work.
Scope
The server currently exposes tools for:
Sailfish device access over SSH
device prerequisite checks and opt-in installation of missing optional tools
defaultuser session-bus calls
Lipstick screenshots
touchscreen discovery and tap/swipe injection
combined screenshot, touchscreen discovery, and touch injection workflows
topmost window PID lookup
process map inspection
journal log reads
RPM copy/install on a device
system and user service management
short and detached user-session command execution with the configured D-Bus environment
desktop-entry application launch as the configured session user
Sailfish Browser launch/debug helpers
preflighted Docker/mb2 RPM builds through the vendored
build-sailfishoshelpercancellable local and remote Android/AppSupport build jobs
installed SDK repository metadata refresh
OBS results, build logs, and guarded source-pin edits through
oscrepository status and search under the configured git root
RPM spec metadata summaries
QML translation search and Sailfish ternary translation checks
The committed configuration template defaults are deliberately generic.
Device tools default to the placeholder SSH target root@device, the Sailfish
user-session bus at /run/user/100000/dbus/user_bus_socket, ~/git as the
local source root, ~/OBS as the OBS checkout root, and the vendored build
helper at
src/sailfish_devel_mcp/vendor/build_sailfishos.py. Put a config file at
~/.config/sailfish-devel-mcp/config.json or pass --config to provide your
real device and OBS settings. Device entries can also carry the preferred user,
architecture, and configured release label. If an installed SDK is available,
set paths.local_sdk to its sdk-chroot path; builds will use it when it has a
target matching the requested release and architecture, otherwise they fall
back to a matching tag in the third-party coderus Docker mirror. Neither a
configured device label nor mirror tag availability independently establishes
the current official SailfishOS release or SDK target.
For a device attached over USB, pass usb as the device argument to use the
configured default device, or usb:<name> when the user supplies a device
name. The MCP keeps that device's user and session metadata but connects to
192.168.2.15 without checking or storing SSH host keys. It trusts the supplied
name and does not resolve it through DNS, so no separate validation connection
is made.
Generic Python configuration code is tracked and works in a clean checkout.
Keep all machine-specific values in ~/.config/sailfish-devel-mcp/config.json
or its environment overrides. No Python bootstrap copy is needed.
Related MCP server: micro-mcp
Host prerequisites
Use a Linux host with Python 3.10 or newer. The server has no third-party
Python runtime dependencies. Detached job supervision uses POSIX process groups
and Linux /proc. The following programs are needed only for the workflows
listed; installing every optional tool is unnecessary.
Workflow | Host requirements |
Run from the checkout |
|
Install the Python package |
|
Device commands and deployment | OpenSSH |
Repository inspection |
|
QML translation search |
|
RPM builds and SDK refresh | A running Docker engine accessible to your user, |
Installed SDK builds | A configured Sailfish Platform SDK |
OBS results, logs and source-pin edits | Required: |
Android/AppSupport builds |
|
Run the MCP tool sailfish_doctor to report local command availability, helper
provenance and installed SDK targets. It does not connect to devices, test Docker
daemon access, or install host packages. Install host tools through your Linux
distribution; the package names differ between distributions. Check RPM build
requirements in each project's spec file and Android requirements in its tree's
documentation.
The remote Android build host also needs sh, the selected bash or sh,
nohup, setsid, base64, date, mkdir, chmod, cat, sed, cut,
sort, tail, and sleep, plus Linux /proc. These support job bookkeeping
and cancellation; the build command may require additional tools.
Device prerequisites and optional setup
Enable Sailfish developer mode and SSH access before using device tools. SSH
authentication and root access must be configured by the device owner. Set the
device's username and session-bus address in the local configuration: older
devices can use nemo rather than defaultuser, and the user ID can differ.
Start the graphical user session before checking Lipstick or session-bus tools.
See the Sailfish developer-mode instructions
and D-Bus reference.
Feature passed to | Device requirements |
|
|
|
|
|
|
| Python >=3.6 with standard-library |
| Optional |
|
|
|
|
|
|
|
|
The prerequisite probe itself requires sh and id. dbus-send is supplied by
dbus, and gio
is supplied by glib2
in current Sailfish packaging. Base OS tools, missing applications, permissions,
and session configuration require manual repair. Command availability and a
session socket do not prove that every device API or touch input works.
Call sailfish_device_setup with install_missing omitted or false to check
a device without installing anything:
{"device": "phone", "features": ["touch", "app_launch"]}The result lists discovered executables, missing requirements, session issues,
and optional packages that could be installed. The default features are
commands, diagnostics, screenshot, touch, app_launch, install, and
services. Select input_trace or browser explicitly when needed.
To install supported missing optional tools, explicitly opt in:
{"device": "phone", "features": ["touch", "input_trace"], "install_missing": true}Setup requires a root SSH login and pkcon or zypper. It installs only missing
python3-base (for Python) and mce-tools (for evdev_trace) from the device's
existing repositories, then checks again. Package dependencies are resolved by
the device package manager. It does not add repositories, enable SSH, change
accounts or permissions, or repair base OS packages. Package availability can
vary with the configured Sailfish release. The mappings follow the
Python spec
and Sailfish touch documentation.
Installation returns a detached job by default. Check sailfish_build_status
or use sailfish-devel-jobs wait --kind build --job-id JOB_ID; the completed
status includes the final report under device_setup and its JSON result_path.
sailfish_build_cancel requests
cancellation, but interrupting SSH does not roll back a package transaction.
wait=true requests synchronous operation for controlled diagnostics.
Optional device companion
Development/test devices only. Do not install this companion on a personal or primary phone containing real accounts or sensitive data. It runs as root and can execute privileged development commands. Journal/D-Bus captures, screenshots and diagnostics can include private data returned to the host MCP client and model context. Present this warning before requesting first-install permission.
The host MCP remains the coordinator for builds, OBS, repository work and file transfers. The optional Python 3.6+ standard-library companion runs as a system service, with a root-only Unix socket reached over existing SSH access. It has no TCP listener. Session D-Bus calls, app launches and user-service operations run as the configured graphical user with that user's home and bus environment.
Use sailfish_device_setup for installation and updates:
{"device": "phone", "features": ["companion"], "companion": "check"}Always request permission before first installation on each device. Only after approval, deploy with:
{"device": "phone", "features": ["companion"], "companion": "deploy", "confirm_companion_install": true}Updates to recognized installations need no renewed permission; omit the confirmation flag. A recognized earlier user-service installation is migrated: setup verifies root-service readiness before stopping/removing the old user service. User-owned companion source is never executed as root during migration. Unknown files/symlinks are refused. The confirmation flag records the caller's assertion of approval, not an independent authentication mechanism.
Deployment requires root SSH and writes:
/opt/sailfish-devel-companion/{agent.py,owner,session.json}/etc/systemd/system/sailfish-devel-companion.serviceRuntime socket/lock in
/run/sailfish-devel-companion/, with a separate/run/sailfish-devel-companion.controllifecycle lock.Detached job state/logs under
/var/lib/sailfish-devel-companion/jobs/.
Code, configuration, socket and job directories are private to root. Setup starts or restarts the service and returns the deployed source SHA-256. It does not enable boot autostart or start capture. An installed companion starts on demand for routed device work or a new capture. It exits successfully after one hour of inactivity, so systemd does not restart it. Active requests and detached jobs prevent idle shutdown and reset the idle period. Capture output does not count as activity; each capture expires after one hour, even if clients keep polling. Restart capture explicitly for a longer session. Idle shutdown discards the in-memory event history; detached job records remain on disk.
Management stop pauses on-demand startup persistently; start or a deployment
update resumes it. Status inspection does not start a stopped service. A failed
on-demand start selects SSH fallback before any requested operation executes.
The system service is independent of the graphical
session; session-dependent tools still require that session to be available.
Optional Python installation still requires install_missing=true. Ordinary
setup defaults perform no installation. Setup, recovery and RPM transfer/install
retain their host implementations and do not depend on a working companion.
Existing device tools and fallback
Public host tool names and arguments are preserved. Journal reads, process maps, topmost PID, D-Bus calls, short commands, screenshots/touch, app/browser launch, service control and detached device commands prefer a compatible companion. Absent, incompatible or explicitly paused companions select the retained SSH implementation before execution. A protocol/transport error or failed operation after selecting the companion is reported, never retried over SSH. No automatic installation occurs. Root-only socket access does not elevate a non-root SSH account; it uses fallback.
Journal/process-map filtering runs on the device. Screenshot/touch workflows run under one device-local operation lock; file downloads remain host-side and happen after the device sequence. A download failure does not replay already-performed touch input. App launch adds observed foreground PID/verification where the desktop entry's executable can be identified; submission alone still does not prove visible rendering. Service calls include local state and bounded failure logs. Operations that start/stop the companion itself use SSH to avoid severing their own RPC.
Detached commands run under device-owned supervisors, survive host/SSH disconnects, and terminate their process groups on cancellation/timeout, including children whose leader has exited. Durable host receipts keep the existing job ID and status/cancel/CLI interface. Individual status reads contact the recorded device; listings show the last known snapshot. Jobs never switch backend after submission. Logs stay on the device and are retrieved in bounded pages/excerpts. Restart/reboot interruption is reported as a lost supervisor, not success. Managed stop, remove and update refuse while jobs are active; job submission and management share a lock. Completed job evidence is retained on companion removal.
Capture tools
All tools below have the prefix sailfish_device_companion_:
Suffix | Purpose |
| Inspect installation or start/stop/remove the service |
| Running version, API capabilities, UID, session user and capture state |
| One journal unit ( |
| Stop collection, retaining captured history |
| Read |
| Wait for |
Root journal capture reads system storage directly; user scope filters by the configured user's UID and user unit, so it works even without separate per-user journal files. Session D-Bus capture drops to the graphical user. Capture is off initially; a second capture is refused until the first is stopped. D-Bus output is raw text lines. Inspect status/events for command failures and policy denials.
History is capped at 512 records of at most 4096 characters each. It survives SSH
disconnects, but not companion restart/update or reboot. Save instance and
next_after; reset reports a new instance and dropped reports overflow. Pages
are also bounded to 64 KiB of record text. Synchronous command output is bounded
to 2 MiB per stream, with truncation reported; detached logs remain complete.
For a direct MCP client, execute /opt/sailfish-devel-companion/agent.py --stdio
as root over SSH. It bridges the five public companion MCP tools to the existing
service. Internal execution/job RPCs are private to the root socket and support
the existing host tools. Removal deletes only recognized installation files,
stops capture, and preserves unexpected files and completed job evidence.
Trust and privacy
This is local development tooling intended for a trusted MCP client running on your own workstation. It communicates over stdio and has no network listener. The client invokes tools using your host account, SSH credentials and OBS credentials. Tool annotations describe effects; they do not enforce permissions or provide an approval layer.
Device command tools can execute arbitrary programs. Their default identity is
the SSH login account, often root; setting the session environment does not
change that identity. Select run_as_user=true when execution should use the
configured Sailfish user. Android builds intentionally accept shell commands.
Configured aliases are convenient names, not a host allowlist: explicit
user@host targets are also supported. Target strings cannot contain SSH
options or whitespace.
RPM builds and SDK maintenance use privileged Docker containers. Installed SDK
builds mount the host user's home directory and the SDK read-write. Build only
trusted source and images, including the optional third-party SDK mirror.
Repository path checks constrain direct file operations; they do not sandbox
build scripts or arbitrary device commands. The explicit chmod permission
fallback broadens file permissions; prefer ACL support and the default error
behaviour when ACL tools are unavailable.
Non-USB SSH connections follow the configured SSH host-key policy. USB mode
connects to 192.168.2.15 and deliberately disables host-key checking and storage
to support changing devices at that address. Use it only for a device connection
you trust.
By default, SSH and SCP use ~/.ssh/config when it exists, or -F /dev/null
when it is absent. Both choices skip the system SSH configuration; OpenSSH's
built-in defaults, including normal non-USB host-key checks, still apply.
An explicit paths.ssh_config must name an existing file; a missing explicit
file remains an error. This policy applies to device and Android connections.
Tool output is returned to the MCP client and may enter a model's context. Effective configuration includes private hostnames, usernames, source paths and OBS mappings. Screenshots, journals, source matches and job logs can contain private data; commands can contain credentials supplied by callers. Keep real configuration, credentials, task notes, screenshots and runtime logs out of source releases and public bug reports. The server's request logs record argument names rather than tool argument values, but job logs and verbose results retain command/output details. Configure the client's tool approvals to suit your workflow.
Running
From a checkout:
/path/to/sailfish-devel-mcp/bin/sailfish-devel-mcpTo inspect the effective configuration:
/path/to/sailfish-devel-mcp/bin/sailfish-devel-mcp --dump-configExample MCP client configuration:
{
"mcpServers": {
"sailfish-devel": {
"command": "/path/to/sailfish-devel-mcp/bin/sailfish-devel-mcp"
}
}
}The wrapper writes startup, shutdown, MCP request, and tool-call logs to
~/.local/state/sailfish-devel-mcp/server.log by default. Override the log
directory with SAILFISH_DEVEL_MCP_LOG_DIR. If the MCP client uses a different
server label, set SAILFISH_DEVEL_MCP_SERVER_LABEL in the client environment so
the wrapper startup line includes the same label.
Configuration
Example:
{
"default_device": "phone",
"devices": {
"phone": {
"ssh_target": "root@phone",
"username": "defaultuser",
"architecture": "aarch64",
"release": "live",
"user_bus_runtime_dir": "/run/user/100000",
"user_bus_address": "unix:path=/run/user/100000/dbus/user_bus_socket"
}
},
"paths": {
"git_root": "~/git",
"obs_root": "~/OBS",
"ssh_config": "~/.ssh/config",
"local_sdk": "/srv/mer/sdks/sfossdk/sdk-chroot",
"osc_api_alias": "primary",
"obs_servers": {
"primary": "primary",
"community": "community"
}
},
"default_android_build_host": "android-builder",
"android_build_hosts": {
"android-builder": {
"ssh_target": "user@android-build-host"
}
}
}Tool Notes
The server keeps local paths scoped to the configured git root, OBS checkout
root, and /tmp for tools that read or write files. Device access still uses
SSH, so the usual SSH prompts, permissions, and command failures are surfaced
as tool results.
Mutating tools are annotated as non-read-only:
sailfish_device_setup(conservatively annotated because installation is optional)sailfish_device_lipstick_screenshotsailfish_device_touchsailfish_device_touch_workflowsailfish_device_user_bus_callsailfish_device_user_session_commandsailfish_device_command_startsailfish_device_command_cancelsailfish_device_install_rpmsailfish_device_restart_servicesailfish_device_app_launchsailfish_device_browser_launchsailfish_build_rpmsailfish_build_cancelsailfish_android_buildsailfish_android_build_cancelsailfish_sdk_refresh_metadatasailfish_obs_source_pin(apply)
sailfish_device_lipstick_screenshot defaults to
~/Pictures/Screenshots/lipstick-<timestamp>.png under /home/<username>,
where username comes from the device config. Lipstick rejects screenshot save
paths outside the home directory. When that directory is missing, the tool
derives ownership with stat -L, creates Pictures as that owner/group with
mode 775, and creates Pictures/Screenshots as that owner and the
privileged group with mode 755 when the group exists.
sailfish_device_touch supports discover, tap, and swipe. Discovery
prints /proc/bus/input/devices and can also run evdev_trace -i when
include_evdev_trace is true. Tap and swipe auto-select a likely touchscreen
input event device unless input_device is supplied. Coordinates are raw
input/display coordinates, so pair this tool with a current screenshot when
choosing points.
sailfish_device_touch_workflow wraps the common UI-debugging sequence:
capture a Lipstick screenshot, optionally list touch devices, inject a tap or
swipe, and optionally capture a second screenshot. It returns each step's
structured result separately.
sailfish_device_user_session_command runs an argv command with
XDG_RUNTIME_DIR and DBUS_SESSION_BUS_ADDRESS set from the configured device.
Set run_as_user when the command should execute as the configured Sailfish
username through runuser or su. Command tools return compact metadata and
bounded output by default; set verbose only when the full command, stdout, and
stderr are needed. This synchronous tool is limited to 15 seconds.
Use sailfish_device_command_start for GDB, tracing, or any command that might
run longer than 15 seconds. It starts a detached host-side SSH process and
returns a job id immediately, so the command survives the MCP request and stdio
server exiting. Use scheduled follow-ups for long jobs, or the CLI waiter below
when explicitly waiting. For occasional checks, use
sailfish_device_command_status with lines=0 and at most 15 wait_seconds. Terminal
failures include a bounded log excerpt automatically. Full logs remain under
the local MCP state directory in device-commands/<job-id>/command.log. Use
sailfish_device_command_cancel to ask the owning supervisor to terminate the
SSH process group.
sailfish_device_install_rpm accepts either rpm_path for one local RPM or
rpm_paths for a dependency set. With rpm_paths, the tool copies every RPM to
the remote remote_dir and runs one pkcon install-local or rpm -Uvh
command with all copied files, so dependencies can be resolved together.
sailfish_device_app_launch launches an installed desktop entry using gio,
as the configured device user from their passwd home directory. For example:
{"device": "my-device", "desktop_file": "sailfish-browser.desktop"}A basename resolves under /usr/share/applications; an absolute device path
ending in .desktop is also accepted. No URL is required. It does not kill
running apps, restart boosters, or change preferences. The process detaches
with stdin/stdout/stderr redirected, avoiding an SSH timeout when app children
retain the connection. wait_seconds (0–5, default 1) checks for immediate
launcher failure; timeout (up to 15 seconds) must exceed it.
The receipt includes submitted, the launch supervisor PID (not the app PID),
launch_exit_code if already available, and private remote_log/remote_status
paths under the user's ~/.cache/sailfish-devel-mcp/launch.* directory. Read those
paths with device commands for later failures and remove that specific directory
when its evidence is no longer needed. Submission or gio exit zero does not
prove foreground activation/rendering: check Lipstick's topmost PID and a
screenshot separately. This desktop-entry path was validated manually for Browser
on a Sailfish device; it does not claim to execute all of Lipstick's icon/switcher logic.
sailfish_device_browser_launch stops the browser booster service and stale
browser/firejail PIDs when requested, launches Sailfish Browser through
invoker with the display and user-session environment, then queries Lipstick
for the topmost PID and checks whether that process has libxul.so mapped.
sailfish_build_rpm can use a configured device's architecture and release
as defaults when the call includes device. If paths.local_sdk is set, the
build defaults to live and first checks the installed SDK targets. live uses
the unversioned local target for the requested architecture, for example
aarch64. A named production release is used only when passed explicitly
through the tool arguments, environment, or device config; it uses a matching
versioned local target when available, and otherwise falls back to a matching
tag in the third-party coderus/sailfishos-platform-sdk Docker mirror. Tags in
that mirror indicate image availability; they do not identify the current
official SailfishOS release or SDK target. The wrapper image defaults to
sailfish-sdk-build-engine:$USER and can be overridden with
SAILFISH_SDK_BUILD_ENGINE_IMAGE.
Use sailfish_build_preflight to validate backend, image/target selection,
architectures, local RPM inputs, pull policy, VCS behavior, and artifact paths
without pulling an image or changing the project. sailfish_build_rpm accepts
the same backend, local_sdk, target, pull_policy, no_vcs_apply, and
allow_untrusted_rpms controls. An explicitly selected local backend does
not silently fall back to Docker. Asynchronous jobs use confined UUID job
directories and expose helper metadata and RPM paths through
sailfish_build_status; use sailfish_build_cancel to terminate the tracked
process group. Successful builds run the helper in quiet mode while retaining
the complete job log. For occasional status checks, use lines=0 and
after_revision to suppress unchanged output. Scheduled progress checks need
bounded log evidence to choose the next interval; follow the long-job policy
below instead of repeatedly calling short status waits. A terminal failure
includes a bounded diagnostic excerpt; request more only when needed. Status waits are capped at
15 seconds so a monitoring request stays comfortably below the stdio
transport's observed lifetime limit.
Local SDK builds use the canonical helper. Ordinary builds share the base's
mb2-managed .default working snapshot; custom repositories, packages and local
RPMs use isolated originals. snapshot_key explicitly isolates a project even
without custom inputs. Supply it when your project or machine policy requires
per-project isolation. snapshot_repository and snapshot_package use the same
helper options; repeat these inputs on later builds so outdated snapshots can
be restored. Only original targets go to mb2; working .default children are
managed by mb2. Bases remain free of project dependencies.
sailfish_android_build starts a remote Android/AppSupport build on the
configured build host. Configure android_build_hosts.<host>.project_dir or
pass project_dir to point at the remote Android source tree. The tool writes
job state under the remote state_dir, atomically creates a per-job directory,
and starts its own process group with nohup and setsid, so the SSH session
used to launch the job can disconnect without killing the build. Set
build_timeout for a remote build lifetime limit. Poll with
sailfish_android_build_status; omit job_id to list recent jobs, or pass a
job id and wait_seconds to wait mechanically for a state change. Running jobs
omit their log by default, while failed jobs include a bounded diagnostic
excerpt. Request bounded lines during scheduled progress checks; use
verbose only when full command/job inspection is needed.
Individual status waits are capped at 15 seconds. Use
sailfish_android_build_cancel to terminate the identity-checked process group.
sailfish_sdk_refresh_metadata starts a detached job to refresh zypper metadata in the installed SDK
exact requested target using the same privileged Docker wrapper as local builds.
aarch64 refreshes the parent; aarch64.default or aarch64-project refreshes
that specific snapshot. No .default suffix is inferred. Use it when local SDK builds fail because a
package listed in repository metadata cannot be downloaded.
The OBS tools, including sailfish_obs_source_pin, accept a friendly server
name configured in paths.obs_servers; each value is an .oscrc alias or API
URL passed to osc -A. Omit server to use paths.osc_api_alias. The advanced
api_alias argument accepts any raw osc -A alias or API URL and cannot be
combined with server. Keep machine- or organization-specific server mappings
in the local config rather than in the repository.
sailfish_obs_results can wait mechanically in intervals of at most 15 seconds
until OBS no longer reports an active state. sailfish_obs_buildlog returns a
bounded tail by default; set verbose only when the complete response is
required.
sailfish_obs_buildlog defaults to osc api with nostream=1 so a build log
request does not become a long-running live stream. Set nostream to false
to use osc remotebuildlog.
Read-only tools include build preflight/status, the journal, topmost PID, process maps, OBS lookup, repo search, spec summary, and QML checks.
OBS source pins
sailfish_obs_source_pin edits an existing _service revision parameter and,
optionally, its existing branch parameter. It uses osc api and your configured
credentials. No local OBS checkout is needed. Install osc through your Linux
distribution; it is an external executable, not a Python package dependency.
action: "read"(default): return source pins and the file'ssha256.action: "preview": supplyrevisionand optionallybranch; return before/ after values, the originalsha256andnew_sha256, without a remote write.action: "apply": supply the same changes,expected_sha256copied from the read/preview, and an OBS commitcomment. If there are multiple source pins, supply the zero-basedservice_indexreturned by read.
For example, after reading home:example:feature/sample, preview with:
{"project":"home:example:feature","package":"sample","action":"preview","revision":"v1.2.3"}Apply with the returned original hash and a meaningful comment. The tool checks
the whole _service hash and rechecks immediately before uploading only that
file. Existing XML formatting, comments and unrelated parameters are preserved;
the tool does not change repository URLs or create missing parameters. It
refuses packages with staged OBS uploads to avoid committing another operation's
unfinished work. It does not resolve Git refs or check whether a commit has been
pushed. Follow the project's authorized OBS server, package and branch mapping.
The OBS file-write API
does not provide an atomic conditional update: another writer can still change
the package between the final check and upload. Coordinate concurrent writers.
Applying creates an OBS source revision and can trigger the configured remote
source services and builds; the tool does not wait for them. An unchanged pin
does not create a commit. Successful writes are verified at the returned OBS
revision. unknown or committed_unverified means inspect/read back before any
retry; never blindly repeat a write. The total operation timeout is at most
15 seconds. Because apply writes remotely, the tool is annotated as mutating
even though read and preview do not write.
Smoke Test
printf '%s\n' \
'{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"smoke","version":"0"}}}' \
'{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}' \
| /path/to/sailfish-devel-mcp/bin/sailfish-devel-mcpDevelopment
Run tests without installing the package:
PYTHONPATH=src python3 -m unittest discover -s testsThe canonical helper lives in the build-sailfishos skill. Update the exact
vendored copy with:
python3 scripts/update_build_helper.py /path/to/build-sailfishos/scripts/build_sailfishos.pyCompact jobs and diagnostics
RPM installation and SDK metadata refresh now return detached build-job receipts
by default. Wait for sailfish_build_status to finish successfully before dependent
actions; sailfish_build_cancel cancels these jobs. Explicit wait=true retains
legacy synchronous behavior. For a multi-RPM transaction, timeout bounds the whole
async job; cancellation of local SSH does not guarantee rollback of a remote RPM
transaction. Inspect package state before retrying an interrupted install.
sailfish_obs_watch runs osc results --watch --fail-on-error in a detached job,
using the selected OBS alias and package filter. It does not modify OBS sources.
For long jobs, confirm detached startup and arrange a quiet scheduled follow-up unless the user opts out, then return to the user. Each follow-up should inspect bounded progress evidence and notify once on completion or failure. If scheduling is unavailable, report that limitation. When the user explicitly requests waiting, use one CLI process without repeated model-driven status calls:
bin/sailfish-devel-jobs wait --kind build --job-id JOB_ID
bin/sailfish-devel-jobs wait --kind device --job-id JOB_ID
bin/sailfish-devel-jobs wait --kind android --host HOST --job-id JOB_ID
bin/sailfish-devel-jobs status --kind build --job-id JOB_ID
bin/sailfish-devel-jobs log --kind build --job-id JOB_ID --offset 0 --max-bytes 6000The waiter emits one JSON result at completion or failure. Exit codes are 0 for
success, 1 for failure/cancellation and 124 for wait expiration (which leaves the
job running). Installed packages expose sailfish-devel-jobs on PATH. Android
jobs accept an optional --state-dir matching their creation call.
Status results include a revision. Send after_revision on an occasional later
check to receive a minimal unchanged receipt when nothing changed. Explicit
lines, verbose, or log_offset requests still return their requested detail.
Build/device log pages are capped at 12,000 bytes and return next_offset and
eof. Tails are byte bounded too, including logs containing very long lines.
Verbose status retains full job metadata; compact completion exposes helper
version, backend, targets, duration, RPM paths, rpmlint and dependency diagnostics.
sailfish_doctor checks configured helper provenance, local executable availability,
SDK targets and configuration presence without contacting devices or OBS. It does
not prove Docker daemon access or network connectivity. The canonical helper also
provides --doctor and --refresh-metadata --target TARGET [--force-refresh].
The QML checker lexes strings/comments and multiline ternaries. It reports missing
branch-local //: and //% comments; it is a focused checker, not a full QML parser.
Maintaining the helper and skills
The vendored helper is pinned by vendor/build-helper.json with its version,
SHA-256 and available source revision/dirty state. Verify parity without editing:
python3 scripts/update_build_helper.py /path/to/build-sailfishos/scripts/build_sailfishos.py --checkThe version check, CLI-control tests and snapshot tests guard the interface. Update
the canonical skill first, vendor it, and run both test suites before release.
skills/sailfish-devel is a separate optional skill for deployment, debugging,
Android and OBS workflows. Install/symlink that directory in your skill directory;
the canonical RPM skill stays focused on building and packaging.
Detecting a stale host process
sailfish_doctor includes host_runtime: the PID, process start time (when
available), source-load time, and SHA-256 identities of package Python sources
at startup and currently on disk. restart_needed: true means the source tree
changed after startup; restart the MCP connection before relying on the updated
implementation. null means identity could not be checked. This is separate
from the existing canonical/vendored helper integrity check and does not restart
the server or interrupt jobs automatically.
Build input provenance
Use spec_path in build/preflight requests to choose a repository's RPM spec,
for example rpm/sensorfw-qt5.spec. Ambiguous selection reports candidates.
Managed snapshots track dependency inputs, including local RPM hashes. Use
reset_snapshot: true when deliberately resetting a project's snapshot to
reapply changed inputs; SDK bases remain untouched. Build results include
provenance and artifact_checksums for tracing RPMs back to source and inputs.
After interrupted preparation, resume_snapshot: true explicitly retries the
identical recorded inputs without resetting an existing snapshot. Missing or
different recipes remain rejected. A build failure after preparation retains
the completed recipe, so it does not by itself require a reset.
Available Tools
35 toolssailfish_android_buildStart Android BuildA
Start a remote Android/AppSupport build under nohup on the configured build host; project_dir must be configured for the host or supplied.
Inputs: shell_command (required), host, shell, job_id, +4 more.
sailfish_android_build_cancelCancel Android BuildC
Cancel a remote Android/AppSupport build after verifying its process identity.
Inputs: job_id (required), host, timeout, state_dir.
sailfish_android_build_hostsAndroid Build HostsBRead-onlyIdempotent
List configured remote Android/AppSupport build hosts.
Inputs: no named parameters.
sailfish_android_build_statusAndroid Build StatusARead-onlyIdempotent
List remote Android/AppSupport build jobs or read one job's status and recent log output.
Inputs: host, lines, job_id, timeout, +5 more.
sailfish_build_cancelCancel Sailfish BuildB
Request cancellation of a local asynchronous Sailfish RPM build job.
Inputs: job_id (required).
sailfish_build_preflightPreflight Sailfish BuildBRead-onlyIdempotent
Validate and return a structured Sailfish RPM build plan without mutating the project.
Inputs: project_path (required), arch, clean, debug, +17 more.
sailfish_build_rpmBuild Sailfish RPMB
Start an asynchronous RPM build. Ordinary local builds share mb2 snapshots; custom inputs or an explicit key use an isolated original target. paths.local_sdk defaults to the live installed SDK, with third-party coderus Docker-image fallback only for explicit named releases.
Inputs: project_path (required), arch, wait, clean, +18 more.
sailfish_build_statusBuild Job StatusARead-onlyIdempotent
Read status and recent log output for asynchronous Sailfish RPM build jobs.
Inputs: lines, job_id, verbose, max_bytes, +3 more.
sailfish_device_app_launchLaunch a Sailfish applicationA
Launch an installed .desktop entry using gio as the configured session user from their home. Detaches all streams and returns a launch receipt and remote log/status paths. Does not stop apps or boosters. Submission is not proof of foreground activation or rendering; verify separately.
Inputs: desktop_file (required), device, timeout, wait_seconds.
sailfish_device_browser_launchLaunch Sailfish BrowserB
Stop stale browser state, launch Sailfish Browser with display/session env, and report topmost PID details.
Inputs: url (required), device, timeout, stop_stale, +1 more.
sailfish_device_command_cancelCancel Device Command JobB
Request cancellation of a detached device command and its process group.
Inputs: job_id (required).
sailfish_device_command_startStart Device Command JobA
Start a detached SSH command with the configured Sailfish user-session environment and immediately return a job id. Use this for GDB, tracing, and any device command that may exceed 15 seconds.
Inputs: command (required), device, timeout, run_as_user.
sailfish_device_command_statusDevice Command Job StatusARead-onlyIdempotent
List detached device command jobs or read one job's status. A bounded failure excerpt is included automatically; running logs are omitted by default.
Inputs: lines, job_id, verbose, max_bytes, +3 more.
sailfish_device_install_rpmInstall Device RPMB
Start a detached RPM copy/install transaction; use sailfish_build_status/cancel.
Inputs: wait, device, timeout, rpm_path, +4 more.
sailfish_device_journalRead Device JournalCRead-onlyIdempotent
Read recent journalctl output from a Sailfish OS device.
Inputs: grep, unit, lines, since, +2 more.
sailfish_device_lipstick_screenshotLipstick ScreenshotB
Ask Lipstick to save a screenshot on the device, optionally pulling it locally.
Inputs: device, timeout, local_path, privileged, +1 more.
sailfish_device_proc_mapsRead Process MapsCRead-onlyIdempotent
Read or filter /proc//maps on a Sailfish OS device.
Inputs: pid (required), device, timeout, contains, +1 more.
sailfish_device_restart_serviceManage Device ServiceC
Run systemctl start/stop/restart/status for a system or user service.
Inputs: unit (required), mode, action, device, +1 more.
sailfish_devicesList Sailfish DevicesARead-onlyIdempotent
List configured Sailfish OS device aliases and SSH targets.
Inputs: no named parameters.
sailfish_device_setupCheck or Set Up Device PrerequisitesA
Check command availability and session configuration over SSH. By default this only reads device state. Explicit install_missing=true installs missing python3-base or mce-tools from existing repositories in a detached job; use sailfish_build_status/cancel. Missing base OS tools need manual repair.
Inputs: wait, device, timeout, features, +1 more.
sailfish_device_topmost_pidTopmost Window PIDBRead-onlyIdempotent
Query Lipstick for the current topmost window process id.
Inputs: device, timeout.
sailfish_device_touchDevice Touch InputC
Discover the touchscreen input device or inject tap/swipe events over SSH.
Inputs: action (required), x, y, end_x, +10 more.
sailfish_device_touch_workflowScreenshot And TouchC
Capture a Lipstick screenshot, optionally list touch inputs, then inject a tap or swipe.
Inputs: action (required), x, y, end_x, +19 more.
sailfish_device_user_bus_callUser Bus CallC
Run a typed dbus-send method call on the defaultuser session bus.
Inputs: path (required), member (required), interface (required), destination (required), +3 more.
sailfish_device_user_session_commandUser Session CommandA
Run a short command, limited to 15 seconds, with the configured Sailfish user-session D-Bus environment. Use sailfish_device_command_start for anything that may run longer.
Inputs: command (required), device, timeout, verbose, +1 more.
sailfish_doctorARead-onlyIdempotent
Check helper compatibility, local tools, SDK targets and configuration without contacting devices.
Inputs: no named parameters.
sailfish_obs_buildlogOBS Build LogCRead-onlyIdempotent
Fetch a build log from a configured OBS server or explicit API alias; defaults to the API nostream form.
Inputs: arch (required), package (required), project (required), repository (required), +6 more.
sailfish_obs_resultsOBS ResultsARead-onlyIdempotent
Read OBS results. Use wait_seconds for bounded mechanical monitoring instead of repeated model-driven status calls.
Inputs: project (required), server, package, timeout, +4 more.
sailfish_obs_watchB
Watch OBS until completion in a detached local job; use sailfish_build_status/cancel or the jobs CLI waiter.
Inputs: project (required), server, package, timeout, +1 more.
sailfish_qml_check_translator_ternariesCheck QML Ternary TranslationsCRead-onlyIdempotent
Flag QML ternary qsTrId expressions that need branch-local comments.
Inputs: path.
sailfish_qml_find_translationsFind QML TranslationsCRead-onlyIdempotent
Find qsTrId and translator comments in QML files.
Inputs: path, timeout.
sailfish_repo_findRepo FindCRead-onlyIdempotent
Search a repo or subtree under the configured git root.
Inputs: query (required), path, timeout, max_count, +1 more.
sailfish_repo_statusRepo StatusBRead-onlyIdempotent
Run git status --short --branch under the configured git root.
Inputs: path, timeout.
sailfish_sdk_refresh_metadataRefresh SDK MetadataB
Start a detached SDK metadata refresh; use sailfish_build_status/cancel.
Inputs: arch, wait, force, device, +4 more.
sailfish_spec_summaryRPM Spec SummaryCRead-onlyIdempotent
Parse high-level metadata from a Sailfish RPM spec file.
Inputs: repo_path, spec_path.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 35 tools
Tools are grouped by domain and most have clearly distinct purposes, such as local RPM build, Android build, OBS, device SSH commands, and QML translation checks. Some boundaries blur because sailfish_build_status/cancel are reused for multiple local async jobs despite the 'build' name, and device_user_session_command vs device_command_start require reading descriptions to distinguish short from long-running commands.
All tool names use snake_case with a consistent sailfish_ prefix, which makes the set predictable. However, the suffix pattern is not uniformly verb_noun: sailfish_devices, sailfish_doctor, sailfish_spec_summary, and sailfish_obs_watch mix noun/state and action forms, though deviations are minor.
35 tools is heavy for a single MCP server, even though the server spans several subdomains including device, build, Android, OBS, repo, SDK, spec, and QML. The breadth justifies many tools, but the surface is at the upper end and could likely be consolidated in places.
The tool set covers a wide lifecycle: build planning, local and Android builds, device inspection and command execution, OBS monitoring, SDK refresh, repo search, spec parsing, and QML translation checks. Minor gaps remain, such as RPM uninstall, explicit app stop/termination, git write operations, and signing/deployment workflows.
Maintenance
Related MCP Connectors
Build, test, publish, and run Kovca workflows from AI agents over remote MCP.
Generate a typed SDK, CLI, and MCP server from any OpenAPI or GraphQL spec, and keep them current.
MCP access to ELSHWORK agents, repositories, isolated runs, discovery and tasks.
MCP tools for TON Sites, TON DNS and TON Storage.
Related MCP Servers
- FlicenseDqualityBmaintenanceEnables HarmonyOS device discovery, app build and deployment, UI automation, E2E inspection, and log validation through MCP tools.1812-
- AlicenseAqualityFmaintenanceEnables building, verifying, previewing, deploying, diagnosing, updating, and rolling back full-stack Micro apps through typed local MCP tools backed by micro-cli.685 npmMIT
- FlicenseNot gradedqualityCmaintenanceEnables agents to connect to remote MCP servers once, access their tools through a compact MCP endpoint, pair a CLI inside sandboxes, and create watches that turn command or tool output into pollable structured events.2-
- FlicenseNot gradedqualityCmaintenanceEnables secure discovery and invocation of sandboxed filesystem, repository inspection, and utility tools through a unified MCP client with schema validation, timeouts, and execution traces.-