Skip to main content

AFFiNE Desktop MCP

A Rust stdio MCP server for AFFiNE Desktop offline/local-only workspaces. It reads the desktop application's local SQLite/Yjs storage, creates normal pages and Edgeless canvases, and creates/edits native editable diagrams with shapes, rich-text labels, bound connectors, pen strokes, frames, link cards, free-floating curves, images and file attachments.

No AFFiNE Cloud, Docker/self-hosted AFFiNE server, GraphQL API, cloud login, or network listener is used. Docker is used only as an optional Linux test runner during development, not by the application.

Connect your AI assistant to your local AFFiNE notes and editable canvases. Download a standalone binary, add it to your MCP client, and ask the assistant to list, search or read your workspaces. Creating pages and diagrams is an explicit, offline-only opt-in.

The Cargo, npm and Python packages are all affine-desktop-mcp. The npm and Python launcher command is also affine-desktop-mcp. The standalone executable (including Cargo installs) remains affine-local-mcp (affine-local-mcp.exe on Windows). Registry packages are prepared here but have not yet been published; registry install commands below apply after release.

Contents

Quick start

  1. Install AFFiNE Desktop and create/open a local-only workspace. This bridge does not expose AFFiNE Cloud workspaces. The tested storage version is 0.27.4.

  2. Download and extract the binary for your OS and CPU. Prebuilt binaries need no Rust, Node.js, Python, Docker or cloud API key.

  3. Run the binary with --version, then --check to discover workspace IDs:

    /absolute/path/affine-local-mcp --version
    /absolute/path/affine-local-mcp --check
    

    Windows PowerShell:

    & 'C:\tools\affine-local-mcp.exe' --version
    & 'C:\tools\affine-local-mcp.exe' --check
    
  4. Configure your client with the binary's absolute path. Keep writes disabled initially. Add a workspace allowlist after discovering the IDs you want to expose.

  5. Restart/reconnect the client's MCP server and ask: “Use the AFFiNE tools to list my local workspaces, then list their documents.”

The client launches the server for you. Do not launch a separate background server, enter a URL, or include --check in its MCP launch arguments.

Important boundary

  • Reads can run while AFFiNE Desktop is open, but see only persisted content.
  • Writes are disabled by default. Enable them explicitly and quit AFFiNE Desktop completely before creating or editing documents. Reopen AFFiNE after changes.
  • This is a storage bridge, not a live IPC connection to the running editor. AFFiNE's own write path emits in-process update events that an external process cannot deliver. The bridge refuses writes when an AFFiNE process is detected. Keep the application closed for the entire write operation; do not open it concurrently. Renamed/custom-packaged executables may evade name detection.
  • Writes append Yjs updates; they do not overwrite existing snapshots or replace entire workspace metadata. Canvas editing preserves unrelated surface elements and note blocks; general page-body editing is not implemented.
  • Tested against AFFiNE Desktop 0.27.4. Storage is an internal AFFiNE contract, not a stable public API. Other versions are not guaranteed; missing required schema fields and incomplete Yjs updates fail rather than silently returning partial documents.

Install a release

Open the latest release or the v0.1.0 release. Download one archive matching the machine where the MCP client runs, plus SHA256SUMS if you want to verify its integrity.

Machine v0.1.0 archive
macOS, Apple Silicon (M1/M2/M3/M4 and other arm64 Macs) affine-local-mcp-0.1.0-macos-arm64.tar.gz
macOS, Intel affine-local-mcp-0.1.0-macos-amd64.tar.gz
Linux, x86_64 / amd64 affine-local-mcp-0.1.0-linux-amd64.tar.gz
Linux, aarch64 / arm64 affine-local-mcp-0.1.0-linux-arm64.tar.gz
Windows, Intel/AMD x64 affine-local-mcp-0.1.0-windows-amd64.zip
Windows, ARM64 affine-local-mcp-0.1.0-windows-arm64.zip

Linux downloads require glibc 2.35 or later; they are not musl/Alpine binaries. Each archive includes the executable, README and Apache 2.0 license.

macOS and Linux

For example, on an Apple Silicon Mac, run these commands in a download folder:

curl -fLO https://github.com/sauravniraula/affine-desktop-mcp/releases/download/v0.1.0/affine-local-mcp-0.1.0-macos-arm64.tar.gz
curl -fLO https://github.com/sauravniraula/affine-desktop-mcp/releases/download/v0.1.0/SHA256SUMS
shasum -a 256 affine-local-mcp-0.1.0-macos-arm64.tar.gz

Compare the printed hash with the line for that archive in SHA256SUMS before extracting it. On Linux you can use sha256sum instead of shasum -a 256. For another OS/CPU, substitute the filename from the table in both the URL and the commands.

mkdir -p affine-desktop-mcp-0.1.0
tar -xzf affine-local-mcp-0.1.0-macos-arm64.tar.gz -C affine-desktop-mcp-0.1.0
mkdir -p "$HOME/.local/bin"
install -m 755 affine-desktop-mcp-0.1.0/affine-local-mcp "$HOME/.local/bin/affine-local-mcp"
"$HOME/.local/bin/affine-local-mcp" --version
"$HOME/.local/bin/affine-local-mcp" --check

Use the expanded absolute path (for example, /Users/alice/.local/bin/affine-local-mcp) in client configuration. Adding ~/.local/bin to PATH is optional when you use an absolute path. If macOS blocks the executable, review its source and checksum, then use the system's Privacy & Security approval flow; do not disable Gatekeeper globally.

Windows PowerShell

For example, on an x64 Windows PC, run in a download folder:

Invoke-WebRequest 'https://github.com/sauravniraula/affine-desktop-mcp/releases/download/v0.1.0/affine-local-mcp-0.1.0-windows-amd64.zip' -OutFile 'affine-local-mcp-0.1.0-windows-amd64.zip'
Invoke-WebRequest 'https://github.com/sauravniraula/affine-desktop-mcp/releases/download/v0.1.0/SHA256SUMS' -OutFile 'SHA256SUMS'
Get-FileHash '.\affine-local-mcp-0.1.0-windows-amd64.zip' -Algorithm SHA256
Get-Content '.\SHA256SUMS'

Compare the hash against the matching filename (hash letter case is irrelevant), then extract the archive to a permanent directory you own:

Expand-Archive '.\affine-local-mcp-0.1.0-windows-amd64.zip' -DestinationPath "$env:USERPROFILE\tools\affine-desktop-mcp-0.1.0"
& "$env:USERPROFILE\tools\affine-desktop-mcp-0.1.0\affine-local-mcp.exe" --version
& "$env:USERPROFILE\tools\affine-desktop-mcp-0.1.0\affine-local-mcp.exe" --check

For Windows ARM64, substitute windows-arm64 in the download and extraction commands. In JSON, use an expanded path such as "C:\\Users\\alice\\tools\\affine-desktop-mcp-0.1.0\\affine-local-mcp.exe".

Upgrading

Stop the server in your MCP client before replacing its executable, verify the new archive, then reconnect. Keep your data-directory and workspace-allowlist settings. Upgrading the bridge does not migrate AFFiNE's database. Review release notes and AFFiNE version compatibility before enabling writes again.

Install with npm or pip

These packages have not yet been published. The following registry commands will work after publication. Both packages bundle the same native Rust server; they do not reimplement it or enable writes. Installation uses the package registry, but the installed server runs offline and never downloads a binary at startup. macOS, glibc Linux and Windows are supported on x64 and arm64.

npm / npx

Requires Node.js 18 or later. npm automatically installs the matching native optional dependency; do not use --omit=optional.

npm install -g affine-desktop-mcp
affine-desktop-mcp --version
affine-desktop-mcp --check

Or run without a global installation:

npx --yes affine-desktop-mcp --check

For a stdio MCP client, use "command": "npx" and "args": ["--yes", "affine-desktop-mcp"]. On Windows use npx.cmd if your client requires the command shim. For reproducibility, pin the package in args to a published version, for example affine-desktop-mcp@0.2.2. GUI clients may need the absolute path to npx or the installed launcher.

pip / pipx / uvx

Requires Python 3.11 or later. Use a virtual environment with pip, or use pipx/uvx for an isolated CLI installation. Supported-platform wheels require no Rust compiler; a source installation needs the Rust/C build tools. Linux release wheels require glibc 2.35 or later (not Alpine/musl).

python -m venv .venv
# macOS/Linux: source .venv/bin/activate
# Windows PowerShell: .venv\Scripts\Activate.ps1
python -m pip install affine-desktop-mcp
affine-desktop-mcp --version
affine-desktop-mcp --check

Alternatively:

pipx install affine-desktop-mcp
# Or run without a persistent installation:
uvx affine-desktop-mcp --check

Use the installed launcher's absolute path as your MCP client's command, with empty args, or use "command": "uvx", "args": ["affine-desktop-mcp"]. Pin a published version with affine-desktop-mcp==0.2.2 in uvx's args. python -m affine_desktop_mcp is also supported. Do not put diagnostic flags such as --check into the client's launch arguments. The configuration variables, allowlists and offline-write safety rules below apply to both launchers unchanged.

Local packages before publication

From a checkout, build a source installation with python -m pip install . in a virtual environment (Rust and a C compiler required). To build installable release artifacts for the current machine:

python -m pip install build
cargo build --release --locked
# Apple Silicon example; use linux/windows and amd64/arm64 for your machine.
# On Windows the binary ends in .exe.
python .github/scripts/package_registries.py --binary target/release/affine-local-mcp --platform macos --arch arm64
python .github/scripts/package_registries.py --shared
python .github/scripts/smoke_packages.py --platform macos --arch arm64

Artifacts are written to dist/. The smoke test installs the main npm tarball and its matching native tarball together, installs the wheel in a fresh virtual environment, and exercises actual MCP stdio calls against an isolated empty data directory. It does not read or write your real notes. Installing just the wheel needs no compiler; add --source to the smoke command to also verify a source-archive installation using Rust. Installing just the npm wrapper from this unpublished checkout cannot fetch unpublished native dependencies. Local Linux wheels have a linux_* tag; the release workflow audits and repairs them to manylinux_* before they can be uploaded to PyPI.

Build from source

Install Rust 1.95 or later and a C compiler (SQLite is bundled):

  • macOS: Xcode Command Line Tools.
  • Windows: Rust's MSVC toolchain and Visual Studio Build Tools with Desktop development with C++.
  • Linux: a C toolchain such as build-essential on Debian/Ubuntu.
git clone https://github.com/sauravniraula/affine-desktop-mcp.git
cd affine-desktop-mcp
cargo build --release --locked
cargo test --locked
cargo clippy --locked --all-targets -- -D warnings

macOS/Linux:

./target/release/affine-local-mcp --check
./target/release/affine-local-mcp

Windows PowerShell:

.\target\release\affine-local-mcp.exe --check
.\target\release\affine-local-mcp.exe

The normal invocation waits for MCP requests on stdin. Stdout is reserved for MCP JSON messages. --check, --help and --version are standalone diagnostics.

Alternatively, install the binary to your Cargo bin directory:

cargo install --path . --locked

Releases

The tag-triggered release workflow builds native amd64 (x86_64) and arm64 (aarch64) binaries for Windows, macOS and Linux. Windows downloads are ZIP archives; macOS and Linux downloads are .tar.gz archives. Each archive includes the executable, this README and the Apache 2.0 license. The release also includes SHA256SUMS for verifying downloads. Linux binaries are built on Ubuntu 22.04 and require glibc 2.35 or later.

To release, set [package].version in Cargo.toml, update Cargo.lock with cargo check, and set the same version in package.json and all six of its optionalDependencies. Python metadata derives its version from Cargo (Python prerelease spelling is normalized by setuptools). Commit the changes, then push a matching new tag such as v0.2.0; existing releases are not replaced. Only pushes of tags matching v* trigger the release workflow; unprefixed tags such as 0.1.0 do not. The version after v must match the manifest exactly, including any prerelease/build suffix.

Before any build, the workflow skips publication if the tag does not match the manifest or a release already exists for that version (with or without the v prefix, including drafts and prereleases). GitHub API errors fail the check rather than being treated as permission to release. Publication runs only after all six builds and tests succeed, and checks for an existing release again before uploading. Prerelease versions are marked as GitHub prereleases.

The workflow also builds/tests six native npm tarballs and six platform-specific Python wheels, plus the main npm tarball and Python source distribution. Linux wheels are checked/repaired with auditwheel for manylinux/glibc compatibility. These artifacts and SHA256SUMS are attached to the GitHub release; the workflow then automatically publishes to crates.io, npm and PyPI using GitHub Actions secrets. A dry-run-verified Cargo .crate archive is also attached to the release. Registry jobs download these exact assets and verify SHA256SUMS before uploading.

Required GitHub Actions secrets

In this repository, open Settings → Secrets and variables → Actions → New repository secret and add these exact names. The workflow checks that all three exist before starting a new release build. Never paste tokens into issues, chat, workflow YAML, or committed configuration files.

Secret Value and permissions
CARGO_REGISTRY_TOKEN A crates.io API token scoped to affine-desktop-mcp, with Publish new crates (publish-new) for the first release and Publish updates to existing crates (publish-update) for later versions. No owner-management or yank permissions are needed. Verify the account's email address and ensure you own/can create the crate name.
NPM_TOKEN An npm granular access token with Read and write (publish and stage) permissions and Bypass two-factor authentication enabled for unattended publishing. For the initial creation of the seven unscoped packages, use a token allowed to create them (typically All Packages); afterward restrict it to the seven package names listed below. Do not use a read-only, stage-only or legacy token. Package settings must permit token publishing.
PYPI_API_TOKEN A production PyPI API token, including its pypi- prefix. For the first release, use an account-wide token so it can create affine-desktop-mcp. After creation, replace it with a token scoped only to that project. Verify your email and complete PyPI's account/2FA requirements. A TestPyPI token will not work. The workflow supplies username __token__ automatically.

The npm token must cover all of:

  • affine-desktop-mcp
  • affine-desktop-mcp-darwin-x64
  • affine-desktop-mcp-darwin-arm64
  • affine-desktop-mcp-linux-x64
  • affine-desktop-mcp-linux-arm64
  • affine-desktop-mcp-win32-x64
  • affine-desktop-mcp-win32-arm64

All package names must be available to or owned by your registry accounts. Creating local manifests does not reserve names. Choose short-lived tokens and rotate/update the corresponding GitHub secret before expiration. Standard GitHub hosted runners do not have fixed outbound IPs; do not apply an incompatible token IP allowlist.

No custom GitHub PAT, SSH key, signing key, or registry username secret is required. GitHub supplies GITHUB_TOKEN automatically; the GitHub-release job declares contents: write, while registry jobs use read-only GitHub permissions. Allow Actions to run in repository settings and ensure organization policies do not block that permission. The standalone binaries remain unsigned; Apple notarization and Windows Authenticode signing are not part of this workflow.

Publication and recovery

After committing the packaging/workflow changes, set a new matching version in Cargo and npm metadata and push its v... tag. Existing GitHub releases are not overwritten or automatically backfilled. Monitor Actions → Release:

  1. Validate the tag/manifests and required secrets.
  2. Build/test all six native targets, install/test their packages and audit Linux wheels.
  3. Dry-run the Cargo publication, create the GitHub release and verify its assets.
  4. Independently publish affine-desktop-mcp to crates.io, all seven npm packages, and all six Python wheels plus the source distribution to PyPI.

Stable npm versions use latest; prereleases use next on all seven packages. Python prerelease versions use normalized PEP 440 spelling. Registry jobs read back public registry metadata and compare uploaded checksums. Existing identical files are safely skipped; conflicting or yanked files fail rather than being overwritten. Native npm dependencies are published and verified before the main launcher. Tokens are passed only to secret preflight and the corresponding publication step, not to build/test jobs.

Publication across independent registries is not atomic: the GitHub release or some registry packages may remain if another registry fails. Fix the cause (for example an expired token) and select Re-run failed jobs, not all jobs. Alternatively, use Actions → Release → Run workflow, select the default branch containing this workflow, and supply the existing release tag in the tag field. This recovery mode checks out that exact tag, downloads its original release assets, verifies checksums and resumes registry publication without rebuilding binaries or replacing the GitHub release. It requires an existing published release produced by this workflow, not an old binary-only release or a draft.

Once publication succeeds, check fresh registry installs with cargo install affine-desktop-mcp --locked, npx --yes affine-desktop-mcp --version and uvx affine-desktop-mcp --version. No registry credentials have been added to this repository, and editing this workflow alone does not publish anything.

License

Licensed under the Apache License, Version 2.0.

Desktop data directories

OS Default application data directory
macOS ~/Library/Application Support/AFFiNE
Windows %APPDATA%\AFFiNE (fallback: %USERPROFILE%\AppData\Roaming\AFFiNE)
Linux $XDG_CONFIG_HOME/AFFiNE (fallback: ~/.config/AFFiNE)

Only workspaces/local/<workspace-id>/storage.db beneath this directory is considered. Cloud caches, userspaces, trashed documents and unregistered leftover documents are excluded. Symlinked workspace directories and database paths escaping the configured root are not exposed.

For Flatpak, portable, beta, renamed, or custom installations, set AFFINE_DATA_DIR to the directory containing workspaces, not to a database file. You can also pass --data-dir PATH.

For example, if your database is at /home/alice/.config/AFFiNE/workspaces/local/abc123/storage.db, set AFFINE_DATA_DIR to /home/alice/.config/AFFiNE and use abc123 as the workspace ID. This same rule applies to custom locations on macOS and Windows.

Configuration options

The bridge has no separate config file. Configure environment variables and/or launch arguments in your MCP client. Use literal, expanded absolute paths; the binary does not expand ~, $HOME or %APPDATA% in supplied paths. Your shell may expand them when you run a diagnostic command, but JSON clients have different interpolation rules.

Environment variables

Variable Default Behavior
AFFINE_DATA_DIR OS-specific directory Directory containing workspaces, not storage.db or the workspace directory itself.
AFFINE_WORKSPACE_IDS Unset: all discovered local workspaces Comma-separated allowlist of workspace IDs. Whitespace is trimmed. An explicitly empty string exposes no workspaces. IDs must contain 1–128 ASCII letters, digits, underscores or hyphens. Discover actual IDs with --check; names/titles are not IDs.
AFFINE_ENABLE_WRITES Disabled Only the exact string "1" enables writes; "0", "true" and other values do not. AFFiNE must still be completely closed.

Default discovery also uses APPDATA on Windows and XDG_CONFIG_HOME on Linux. If your client filters environment variables, explicitly set AFFINE_DATA_DIR instead of relying on inherited shell settings.

Command-line options

Option Behavior
--data-dir PATH Overrides AFFINE_DATA_DIR / automatic discovery for this process. Pass the flag and path as separate elements in args.
--enable-writes Enables writes, even when AFFINE_ENABLE_WRITES is "0". Omit this flag for read-only operation. There is no --disable-writes flag.
--check Prints detected workspaces, warnings and writesEnabled as JSON, then exits. Diagnostic only.
--version Prints the package version, then exits. Diagnostic only.
--help, -h Prints usage, then exits. Diagnostic only.
No diagnostic option Starts the stdio MCP server and waits for requests from its client.

For a custom data directory, the launch arguments can be:

["--data-dir", "/absolute/path/to/AFFiNE"]

Neither the bridge nor a desktop client necessarily reads your shell profile or an .env file. Set values in the client's server configuration explicitly. There is no port, URL, API token, cloud login or HTTP/SSE mode to configure.

Here is a restricted, custom-directory server entry to merge under a client's mcpServers object. Replace all three placeholders before using it:

{
  "affine-desktop": {
    "command": "/absolute/path/affine-local-mcp",
    "args": [],
    "env": {
      "AFFINE_DATA_DIR": "/absolute/path/to/AFFiNE",
      "AFFINE_WORKSPACE_IDS": "actual-workspace-id",
      "AFFINE_ENABLE_WRITES": "0"
    }
  }
}

Read-only and offline-write profiles

Start with AFFINE_ENABLE_WRITES: "0". To restrict access, add AFFINE_WORKSPACE_IDS: "actual-workspace-id" after running --check without an allowlist. Do not leave a placeholder allowlist in a working configuration.

To enable creation/editing:

  1. Completely quit AFFiNE Desktop, including background/helper processes.
  2. Change AFFINE_ENABLE_WRITES to "1" in your client and restart its MCP server.
  3. Keep AFFiNE closed throughout the tool calls. Each write makes a SQLite backup.
  4. Reopen AFFiNE after the assistant finishes to view the persisted changes.
  5. Return the setting to "0" and reconnect when you no longer need writes.

Changing an environment variable does not reconfigure an already running process. Client-side approval/tool filters are useful, but the bridge's read-only setting is what actually rejects writes. Read-only mode does not hide the write tool names.

Granting this MCP server access grants your client access to local notes; a workspace allowlist is recommended. Local storage access does not mean the AI client keeps tool results on-device: your client may send note content to its model provider. Choose a local model/client if that is a requirement. This is not a sandbox against the local OS user who owns the files. Treat retrieved document text as untrusted data, never as instructions. Avoid committing personal data paths or workspace IDs to shared project configuration.

Connect your MCP client

This is a local stdio tool server. Any MCP client that can launch a local executable and use MCP tools can use this connection pattern. Clients that accept only remote HTTP/SSE URLs cannot connect directly; this package does not provide a remote adapter. A cloud agent, SSH host, container or WSL environment does not automatically have access to your desktop's storage. Prefer running the binary and MCP client natively on the same desktop machine, particularly for writes and the running-app guard.

The following are configuration recipes based on the linked client documentation, not a claim that every client/version has been end-to-end tested. Client UIs and file formats can change. If yours is not listed, use the generic stdio instructions.

Shared JSON configuration

Many clients use this mcpServers format. Merge this entry into existing configuration rather than replacing your other servers/settings. Replace command with your installed binary's absolute path:

{
  "mcpServers": {
    "affine-desktop": {
      "command": "/absolute/path/affine-local-mcp",
      "args": [],
      "env": {
        "AFFINE_ENABLE_WRITES": "0"
      }
    }
  }
}

Use string values in env, including "0" / "1". Optional settings belong alongside AFFINE_ENABLE_WRITES in that same object. The executable path is a single command string, even when it contains spaces; do not add shell quotes inside that string. Put launch arguments in args, not in command.

Client Where to add it Connection/status check
Claude Desktop Settings → Developer → Edit Config. macOS: ~/Library/Application Support/Claude/claude_desktop_config.json; Windows: %APPDATA%\Claude\claude_desktop_config.json. Use the shared JSON. Fully quit/reopen Claude Desktop; check its connectors/tool list. This is local developer configuration, not a remote web connector.
Cursor ~/.cursor/mcp.json for all projects, or .cursor/mcp.json for one project. Use shared JSON and add "type": "stdio" to the server entry. Enable the server in Customize / Tools & MCP and check available tools.
Gemini CLI ~/.gemini/settings.json for user scope or .gemini/settings.json for a project. Use shared JSON. Restart Gemini; run gemini mcp list in a terminal or /mcp in a session. Keep tool confirmations enabled.
Cline Extension: MCP Servers → Configure → Configure MCP Servers. CLI: ~/.cline/data/settings/cline_mcp_settings.json. Use shared JSON. Restart the server and verify tools in the MCP panel. Leave autoApprove empty/omit it until you review the tools.
Roo Code MCP settings → Edit Global MCP, or .roo/mcp.json for a project. Use shared JSON. Enable/restart the server in the MCP panel; do not blanket-allow mutating tools.
LM Studio Program → Install → Edit mcp.json. Merge the shared JSON server entry. Enable the server for the conversation and use a model that supports tool calling.
Windsurf / Cascade Open the MCP config from the agent's MCP settings and merge shared JSON. Legacy Windsurf uses ~/.codeium/windsurf/mcp_config.json. Newer Devin Desktop/Cascade docs use ~/.config/devin/mcp_config.json (Windows: %APPDATA%\devin\mcp_config.json). Use the file opened by your installed version's UI, not an assumed legacy path; enable/restart the server. Devin Local uses the Devin CLI configuration.

The clients below have different configuration shapes; do not paste mcpServers unchanged into their native configuration.

Claude Code

Register the server for your user (all projects):

claude mcp add --transport stdio --scope user --env AFFINE_ENABLE_WRITES=0 affine-desktop -- /absolute/path/affine-local-mcp
claude mcp list

Use /mcp inside Claude Code to inspect the connection. To keep it project-scoped, use --scope local; to deliberately share configuration, use --scope project. Add other variables with additional --env NAME=value options before --. Server arguments go after the binary, for example -- /absolute/path/affine-local-mcp --data-dir /absolute/path/to/AFFiNE. See Claude Code MCP documentation.

Codex CLI, IDE extension and desktop clients

Add this TOML to ~/.codex/config.toml, or .codex/config.toml in a trusted project:

[mcp_servers.affine-desktop]
command = "/absolute/path/affine-local-mcp"
args = []

[mcp_servers.affine-desktop.env]
AFFINE_ENABLE_WRITES = "0"

For a Windows path, TOML literal strings avoid backslash escaping: command = 'C:\tools\affine-local-mcp.exe'. Reconnect/restart the client and inspect its MCP server list. Codex clients on the same host share this configuration; a hosted web-only connector is not a local stdio process. See Codex MCP documentation.

VS Code / GitHub Copilot

For current versions, create a project-root .mcp.json using the shared JSON, or use MCP: Add Server → Command (stdio) and choose a local/user destination. The portable user configuration is ~/.copilot/mcp-config.json (or under COPILOT_HOME when set).

For VS Code's .vscode/mcp.json format, the top-level key is servers:

{
  "servers": {
    "affine-desktop": {
      "type": "stdio",
      "command": "/absolute/path/affine-local-mcp",
      "args": [],
      "env": { "AFFINE_ENABLE_WRITES": "0" }
    }
  }
}

Use MCP: List Servers to start the server/view logs, then enable its tools in an agent chat. With SSH/Dev Containers, choose configuration that runs locally on the desktop host, not in a remote environment without AFFiNE's files. See VS Code MCP documentation.

Zed

Use Settings → AI → MCP Servers → Add Server → Add Local Server, or merge this into the settings file opened by zed: open settings file:

{
  "context_servers": {
    "affine-desktop": {
      "command": "/absolute/path/affine-local-mcp",
      "args": [],
      "env": { "AFFINE_ENABLE_WRITES": "0" }
    }
  }
}

Check the server status in MCP settings and use its tools in Zed Agent. External agents/terminal threads may read their own native client configuration instead. See Zed MCP documentation.

OpenCode

Merge into opencode.json in your project or ~/.config/opencode/opencode.json for user-wide access:

{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "affine-desktop": {
      "type": "local",
      "command": ["/absolute/path/affine-local-mcp"],
      "environment": { "AFFINE_ENABLE_WRITES": "0" },
      "enabled": true
    }
  }
}

Unlike the other JSON formats, command is an array containing the executable and any launch arguments, and variables go in environment, not env. Run opencode mcp list to check the connection. See OpenCode MCP documentation.

Hermes Agent

Use Hermes' config command to add the server without hand-editing YAML:

hermes config set mcp_servers.affine-desktop '{"command":"/absolute/path/affine-local-mcp","args":[],"env":{"AFFINE_ENABLE_WRITES":"0"}}'

Use the active profile's configuration (HERMES_HOME / hermes --profile NAME), not another profile's config. Restart/reconnect Hermes; tool names may be prefixed with the server name. Put custom data-directory and allowlist settings in this entry's env, since the client's inherited environment may be filtered. The command above uses POSIX shell quoting; on Windows, use an appropriate shell or the client's MCP configuration UI. See Hermes MCP documentation.

Any other stdio MCP client

Use the client's Add local MCP server / Command / stdio workflow:

Field Value
Name affine-desktop (a label; you may choose another)
Transport stdio / local process
Command / executable Absolute path to affine-local-mcp or affine-local-mcp.exe
Arguments Empty initially; optional --data-dir and its path as separate arguments
Environment AFFINE_ENABLE_WRITES=0; optionally AFFINE_DATA_DIR and AFFINE_WORKSPACE_IDS
URL / headers / OAuth Not applicable; leave unset

Save, reconnect, approve the server if prompted, and verify that affine_list_workspaces appears. For standalone downloads, the extracted executable is the command, not a GitHub URL. After registry publication, you can also use the npm/uvx launcher recipes. The client must support MCP tool calling, not just resources/prompts or remote connectors.

First conversation

  1. Discover: “Call affine_list_workspaces and show me the workspace IDs.”
  2. Browse: “List the documents in workspace <id> using the AFFiNE tools.”
  3. Read/search: “Search that workspace for ‘project plan’, then read the matching document. Follow pagination until you have the full text.”
  4. Optional write: Quit AFFiNE, enable writes and reconnect, then ask: “Create a page titled ‘Meeting notes’ in workspace <id> with this content. Use document ID meeting-notes-mcp and report the backup path.”
  5. Native diagram: “Use affine_create_diagram to create an editable Start → Review → Done flowchart. Do not put ASCII or Mermaid into a text note.”

Replace <id> with a discovered ID. Review the client's tool arguments and approvals. Tool discovery/connection alone does not prove storage access; a successful workspace listing and document read are the useful first checks.

Tools

Tool Parameters / behavior
affine_list_workspaces Lists local workspace IDs, names and active document counts
affine_list_documents workspaceId, optional offset/limit; active documents and primary page/edgeless mode
affine_read_document workspaceId, documentId, optional offset/maxChars; best-effort Markdown, warnings and continuation
affine_search_documents workspaceId, query, optional offset/limit; literal case-insensitive title/body search
affine_create_document workspaceId, title, content, optional mode (page or edgeless) and documentId; offline-only creation
affine_create_diagram workspaceId, title, nodes, optional edges, documentId, direction (TB or LR); native shapes/connectors, not a note
affine_read_canvas workspaceId, documentId; native primitives in elements, native frame/link/media blocks in blocks, with IDs/properties
affine_edit_canvas workspaceId, documentId, optional nodes, edges, strokes, curves, frames, links, media, deleteIds, confirmDelete; atomic native-object upsert/delete
affine_draw_pen workspaceId, documentId, strokes; create/replace editable native freehand strokes
affine_erase_canvas workspaceId, documentId, strokeIds and/or swept path, optional radius, required confirm: true; whole-stroke erasing
affine_import_media workspaceId, documentId, media; import local raster images or file attachments into the canvas and native blob store

Offsets for reading are Unicode scalar characters, not bytes or UTF-16 units. List/search pagination uses zero-based result offsets. Follow hasMore and nextOffset. Search reports partial and warnings if a document cannot be read; its total counts matches among successfully read documents.

Text extraction includes paragraphs, lists, code, simple tables, note text and canvas text. It is not a lossless export: inline formatting may be flattened, images/attachments have labels only, database properties are incomplete, embeds are references, and canvas layout is not reproduced. No OCR, semantic search or external link fetching is performed.

Create a page

Quit AFFiNE, enable writes in your MCP client's configuration, and call:

{
  "workspaceId": "<id-from-affine_list_workspaces>",
  "documentId": "my-stable-mcp-page-id",
  "title": "Created through MCP",
  "content": "This text was written by the MCP creation tool.",
  "mode": "page"
}

Create an Edgeless canvas

Call the same tool with a new ID and "mode": "edgeless". Nonempty content creates an editable note positioned at [100,100,800,300]; empty content creates a blank canvas without a note. primaryMode is persisted in AFFiNE's db$docProperties document, so it opens in Edgeless mode. Content is plain text inside a rich-text paragraph, not parsed Markdown.

Use a stable documentId for retries. Repeating the same ID/title/content/mode returns alreadyExists: true; a conflicting document is rejected, never replaced. Omitting the ID generates a new UUID on each successful invocation.

Create a real diagram

Use affine_create_diagram, not affine_create_document with ASCII arrows, Markdown or Mermaid text. Those are plain text and are not converted to shapes. The complete example is examples/native-flowchart.json. Replace its workspaceId placeholder with a discovered local workspace ID and send that JSON as the tool's arguments while AFFiNE is closed.

{
  "workspaceId": "<local-workspace-id>",
  "documentId": "my-native-diagram",
  "title": "Native flowchart",
  "direction": "TB",
  "nodes": [
    {"id": "start", "text": "Start", "shape": "ellipse"},
    {"id": "check", "text": "Valid?", "shape": "diamond"},
    {"id": "save", "text": "Save changes", "shape": "roundedRect"}
  ],
  "edges": [
    {"id": "e1", "source": "start", "target": "check"},
    {"id": "e2", "source": "check", "target": "save", "text": "Yes"}
  ]
}
  • Shapes: rect, roundedRect, ellipse, diamond, triangle.
  • Each node has an editable label and optional position: [x,y], size: [width,height], style: "general" | "scribbled", fontSize, fillColor, strokeColor, and textColor.
  • Colors are hex strings or { "light": "#ffffff", "dark": "#222222" } objects.
  • DAGs use layered TB or LR layout. Custom/cyclic diagrams must explicitly position every node; use newlines and larger sizes for long labels.
  • Connectors use routing: "straight" | "orthogonal" | "curve", optional labels, sourceAnchor/targetAnchor (top, right, bottom, left) and startEndpoint/endEndpoint (none, arrow, circle, diamond, triangle). The default is an orthogonal line with a target arrow. Endpoints reference native shape IDs, so AFFiNE can re-route them when shapes move.
  • Limits: 200 nodes, 500 edges, 2000 UTF-8 bytes per label, 100000 bytes of labels per call. Element IDs must be unique across nodes and edges.
  • A stable document ID can be retried against the same persisted diagram. Modified diagrams are rejected rather than overwritten; use the edit tool.

Edit an existing canvas

Inspect IDs and native properties with affine_read_canvas, then send nodes or edges with the same IDs to affine_edit_canvas. New nodes require explicit positions. Existing nodes retain omitted position/size, but label/appearance defaults are applied; this is a complete supported-element upsert, not an arbitrary property patch. Existing Y.Map/Y.Text identities and unrelated elements/note blocks are preserved.

Deleting supported primitive/frame/link/media IDs requires deleteIds and confirmDelete: true. Incident connectors are also removed to avoid dangling bindings. Repeating a delete is safe. Native self-locked elements and locked frame ancestors are protected. Editing grouped canvases is deliberately unsupported; ungroup in AFFiNE first. Groups, mindmaps and note/page/surface deletion are not supported. Removing a frame preserves its contents; removing a media block does not delete its shared binary blob. Remaining frame references are cleaned up.

Pen and eraser

affine_draw_pen takes strokes, each with a stable id, absolute points ([[x,y], ...] or [[x,y,pressure], ...]), optional lineWidth (0.5..64, default 4), and optional hex/theme color. Pressure must be 0..1 and is retained in the native brush data; AFFiNE's renderer determines its visual use. A stroke can be a single dot. These are native brush elements, not raster images or shapes styled as scribbled. Limits: 5000 points/stroke, 50000 points/call.

affine_erase_canvas accepts explicit strokeIds or a swept absolute path with optional radius (0..1000, default 8 canvas units). confirm: true is mandatory. Sweeps account for brush position, rotation and line width, skip locked strokes and return skippedLockedIds. Explicitly targeting a locked stroke fails atomically. The eraser removes whole intersecting strokes, not pixels or partial stroke segments, matching AFFiNE's object-erasing model. Use a shorter path or explicit IDs if a sweep exceeds the geometry work limit.

Use the corresponding arrays in affine_edit_canvas:

  • frames: id, title, bounds: [x,y,width,height], optional childIds, background and presentationIndex. Titles remain editable Y.Text. Omit childIds to retain existing membership; [] explicitly empties it. Children must exist on the canvas. Nested frames are supported; cycles, self-membership and multiple frame owners are rejected. To move children between frames, explicitly update both frames' memberships in the same call. Frame bounds edits change the boundary, not the children's coordinates.
  • links: id, position, optional size, title and description, plus target: {"kind":"external","url":"https://..."} or target: {"kind":"document","documentId":"..."}. External links become native bookmarks; document links become native same-workspace linked-doc cards. Targets must be active registered documents. External URLs must use HTTP(S) and may not contain credentials. The bridge does not fetch previews; the desktop app may fetch them when opened.
  • curves: id, absolute source: [x,y] and target: [x,y], optional label, startArrow, endArrow, stroke, strokeWidth and labelColor. These are free-floating native curved connectors, with editable labels and endpoints; AFFiNE computes their curve. They are not arbitrary cubic Bézier paths. For curves attached to shapes, use edges with routing: "curve" instead.

Import media

The bridge only reads files deliberately placed in <AFFINE_DATA_DIR>/mcp-imports, never arbitrary filesystem paths or URLs. Create that staging folder and copy the files you want exposed into it. The folder and file paths must remain inside the data directory/import root; escaping symlinks and traversal are rejected. Once imported, the bytes are stored in AFFiNE's native SQLite blobs table, so the original staging file is no longer required to display/download the stored media.

Call affine_import_media with media items containing id, filePath, position, optional size: [width,height], caption and kind: "auto" | "image" | "attachment" (default auto). Paths can be import-folder-relative or absolute paths inside that folder.

  • PNG/JPEG/GIF/WebP files become native image blocks. Natural dimensions are retained; default display geometry fits within 640x480 without upscaling.
  • PDFs, video, audio and other files become native downloadable attachment cards. Dedicated audio/video players are not implemented. Other image formats such as SVG can be attached as files, but not imported as image blocks.
  • Limits: nonempty files, 20 MiB/file, 20 files and 100 MiB/batch; images must have supported headers/dimensions. Canvas display size may be overridden.
  • Identical file bytes reuse content-addressed blob IDs. Repeating the same media block ID updates it without duplicating the block or blob. Existing IDs of another block/element type are rejected, not silently converted.
  • Blob bytes, block references, document clocks and registry changes share one backed-up transaction. Blob bytes/MIME/size and the complete saved block map are read back before commit. Deleting a block never deletes a shared blob; orphan-blob cleanup is left to AFFiNE rather than risking other documents.

The combined example examples/native-canvas-features.json adds a pen stroke, curve, link, image, attachment and enclosing frame atomically. Replace its workspace/document placeholders, create a blank Edgeless document with affine_create_document if needed, copy tests/fixtures/sample-media.png and tests/fixtures/sample-attachment.txt into the staging folder, then send the example to affine_edit_canvas with AFFiNE closed.

Write safety and backups

Before each write the bridge makes a consistent SQLite online backup, including WAL content, under:

<application-data-directory>/mcp-backups/<workspace-id>-<uuid>.db

Backup paths are returned by the tool. Backups contain private workspace data; retain them securely. They are not automatically deleted, including backups from failed or repeated create attempts.

An immediate SQLite transaction atomically appends:

  1. The new BlockSuite/Yjs page, surface, note and paragraph.
  2. A Yjs update to the active meta.pages registry.
  3. A Yjs update setting primaryMode in db$docProperties.
  4. Matching document clock updates.

The document is reconstructed and checked before commit. Failure rolls back all dependent updates and clocks. Reads reconstruct snapshots plus unmerged updates from one SQLite transaction. The implementation never runs AFFiNE migrations or changes the storage schema.

Canvas edits atomically append native primitive/block and registry updatedDate updates with their clocks and imported blob rows, and reconstruct the complete stored canvas before commit. A failed validation or dependent write leaves the database unchanged (a backup may remain). Native shape/connector layouts follow the shape model and connector model.

The verified upstream contract is AFFiNE v0.27.4 nbstore push_update, AFFiNE document registry, and desktop mode properties.

To restore a backup, quit AFFiNE and stop the MCP server first. Preserve the current database and its WAL/SHM files before any replacement. Do not restore by copying a database over a running application.

Troubleshooting

Symptom What to check
Client says “command not found” / ENOENT Extract the archive first and use the absolute executable path, not the archive, directory, GitHub URL or Cargo package name. GUI clients may have a different PATH from your shell. On Windows include .exe and escape JSON backslashes.
“Permission denied” or macOS blocks launch Ensure the file is executable (chmod +x /absolute/path/affine-local-mcp on macOS/Linux). Review macOS Privacy & Security prompts and the download checksum. Do not bypass security globally.
“Exec format error” / wrong architecture / missing glibc Choose the OS/CPU archive from the installation table. Linux binaries need glibc 2.35+; build from source for other supported environments.
Running the binary appears to hang Without a diagnostic flag it is waiting for MCP requests on stdin. This is normal; let your client launch it. Use --check for a standalone diagnostic.
Server exits immediately or tools never appear Remove --check, --help and --version from MCP args. Confirm stdio transport, the correct client config shape, and that the client enabled/trusted the server. Read its MCP stderr logs.
“No local workspaces” Open/create a local-only workspace in AFFiNE and let it persist. Run --check. For a custom install, point AFFINE_DATA_DIR / --data-dir at the directory containing workspaces. Cloud caches are deliberately excluded.
Workspace missing or “Unknown or disallowed local workspace” Check AFFINE_WORKSPACE_IDS. An empty value exposes none; a name instead of an ID will not match. Discover IDs without an allowlist, then reconnect with the intended IDs.
Listing succeeds but documents have warnings Check persisted data, schema compatibility and AFFiNE version. Inspect warnings / partial; do not treat partial search results as a complete export.
“Writes disabled” Keep read-only mode unless you need a mutation. For writes, quit AFFiNE, set AFFINE_ENABLE_WRITES to the string "1" and restart the client's server.
“Quit AFFiNE Desktop before writing” Closing its window may not quit background processes. Completely quit it and keep it closed throughout the operation. Do not defeat the process guard.
Edits are not visible in AFFiNE Finish all offline writes, then reopen AFFiNE. There is no live editor synchronization; readers also see only persisted content.
“Unsupported storage schema” / “Incomplete Yjs data” Do not edit SQLite manually or force a migration. Let AFFiNE finish persisting, check the tested 0.27.4 contract, and report the exact error without sharing private notes/databases.
Media path rejected Copy the file into <AFFINE_DATA_DIR>/mcp-imports. Arbitrary filesystem paths, URL imports, escaping symlinks and files above the documented limits are not accepted.

For a custom location, diagnose with the same path and environment used by the client. Example (macOS/Linux):

AFFINE_ENABLE_WRITES=0 /absolute/path/affine-local-mcp --data-dir /absolute/path/to/AFFiNE --check

Windows PowerShell:

$env:AFFINE_ENABLE_WRITES = '0'
& 'C:\tools\affine-local-mcp.exe' --data-dir 'C:\Users\alice\AppData\Roaming\AFFiNE' --check

Restart/reconnect the client after any config change. If a command works in your terminal but not in the client, compare executable paths, environment variables, permissions and whether the client runs locally or remotely. Consult the client's MCP logs, not stdout logging wrappers: stdout must contain only MCP messages. When reporting an issue, include OS/architecture, bridge --version, AFFiNE version, client/version and a redacted error/config. Do not upload workspace databases or private tool results.

Verification

cargo test's write integration test uses the production running-app guard; quit AFFiNE Desktop completely before running the suite locally. The test only writes to an isolated temporary workspace, never your real notes.

cargo test includes independently generated JavaScript Yjs fixtures (not only Rust-to-Rust roundtrips) and a real child-process MCP stdio journey. Tests cover creation in both modes, readback, search, pagination, retries/conflicts, concurrent stable-ID creation, rollback after an injected dependent-write failure, read-only defaults, running-app refusal, deleted/orphan exclusion, corrupt/incomplete updates, allowlisting and path containment. Native-canvas tests cover editable Y.Text labels, native element types/bindings, all supported shape/routing variants, DAG layout, explicit cycles, editing, confirmed/cascading deletion, preservation of unrelated notes/shapes, invalid endpoints, read-only denial, and rollback after a dependent canvas-write failure. Drawing/media tests cover independent JavaScript brush/frame/link/media fixtures, pressure/relative geometry, swept erasure including rotations and dots, inherited frame locks, retained frame titles/membership, cycle/duplicate-owner rejection, external/local link validation, actual media-byte persistence, deduplication, shared-blob preservation, import-root/symlink containment, and combined canvas/blob rollback through actual MCP stdio calls. These are storage/MCP tests, not a desktop screenshot or visual-rendering test.

The GitHub Actions matrix runs tests, formatting, Clippy and release builds on macOS, Windows and Linux. The release workflow additionally tests/builds all six OS/architecture targets before publishing. Client-specific configuration recipes above are documentation, not an end-to-end certification of every client UI or model. Release archives contain the README from their tagged commit; this repository's default branch contains the latest setup guidance.

Metadata

Release files for affine-desktop-mcp 0.2.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for affine-desktop-mcp 0.2.2
File Size Uploaded
affine_desktop_mcp-0.2.2.tar.gz 109.3 kB Details

Built distributions (wheels)

Table of built distributions (wheels) for affine-desktop-mcp 0.2.2
File
affine_desktop_mcp-0.2.2-py3-none-win_arm64.whl Python 3 none Windows ARM64 Details
affine_desktop_mcp-0.2.2-py3-none-win_amd64.whl Python 3 none Windows x86-64 Details
affine_desktop_mcp-0.2.2-py3-none-manylinux_2_34_x86_64.manylinux_2_35_x86_64.whl Python 3 none Linux glibc 2.34+ x86-64, Linux glibc 2.35+ x86-64 Details
affine_desktop_mcp-0.2.2-py3-none-manylinux_2_34_aarch64.manylinux_2_35_aarch64.whl Python 3 none Linux glibc 2.34+ ARM64, Linux glibc 2.35+ ARM64 Details
affine_desktop_mcp-0.2.2-py3-none-macosx_11_0_x86_64.whl Python 3 none macOS 11.0+ x86-64 Details
affine_desktop_mcp-0.2.2-py3-none-macosx_11_0_arm64.whl Python 3 none macOS 11.0+ ARM64 Details

Total release size: 18.0 MB

Release files / affine_desktop_mcp-0.2.2.tar.gz

Download URL affine_desktop_mcp-0.2.2.tar.gz
Size 109.3 kB
Tags Source
SHA-256 checksum
How to use checksums
7f349c901a3420586a4c4235c0cea6110f30f1ba3b4b2652ddd620e7d4568360
BLAKE2b-256 checksum
How to use checksums
0aa32c9168110682e90155b5fa9be5f2a0242084fd88ea204179459414cf879d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.16

Release files / affine_desktop_mcp-0.2.2-py3-none-win_arm64.whl

Download URL affine_desktop_mcp-0.2.2-py3-none-win_arm64.whl
Size 2.8 MB
Tags Python 3 Windows ARM64
SHA-256 checksum
How to use checksums
15f3b01d88fc32895ba82588e1b068330555288bfe90faea75feb2e6a9768a74
BLAKE2b-256 checksum
How to use checksums
f7637c5e6e25f8ef5ce3206c8581b5533232e128aa44f1086537c14d71684896
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.16

Release files / affine_desktop_mcp-0.2.2-py3-none-win_amd64.whl

Download URL affine_desktop_mcp-0.2.2-py3-none-win_amd64.whl
Size 3.0 MB
Tags Python 3 Windows x86-64
SHA-256 checksum
How to use checksums
5bafec12a6af679e6f7b734df13cf29e1e7d1a0d7fbc1554141ead74a906ee22
BLAKE2b-256 checksum
How to use checksums
65fda149f64e60f23b39616534851a2224b68d9b4805156147271e1ba42d9b38
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.16

Release files / affine_desktop_mcp-0.2.2-py3-none-manylinux_2_34_x86_64.manylinux_2_35_x86_64.whl

Download URL affine_desktop_mcp-0.2.2-py3-none-manylinux_2_34_x86_64.manylinux_2_35_x86_64.whl
Size 3.2 MB
Tags Linux glibc 2.34+ x86-64 Linux glibc 2.35+ x86-64 Python 3
SHA-256 checksum
How to use checksums
e9d6412c5aaed3b55103fdcedb23e5a619acc1afb2e3ca3393c199d93d67411e
BLAKE2b-256 checksum
How to use checksums
87edda182b518dd26703d6b90fd67c107d3e77317a116c09b8d6bee7cd51eeed
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.16

Release files / affine_desktop_mcp-0.2.2-py3-none-manylinux_2_34_aarch64.manylinux_2_35_aarch64.whl

Download URL affine_desktop_mcp-0.2.2-py3-none-manylinux_2_34_aarch64.manylinux_2_35_aarch64.whl
Size 3.0 MB
Tags Linux glibc 2.34+ ARM64 Linux glibc 2.35+ ARM64 Python 3
SHA-256 checksum
How to use checksums
1968d0bd843087af9a9aec5a90e15e65f1496eeddc330ac0ce2a8d0cc5605cd8
BLAKE2b-256 checksum
How to use checksums
de7593ccfa3a625e9948339444bb14918dfd0bf58d1ed2e7edbff147f3ca6a7a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.16

Release files / affine_desktop_mcp-0.2.2-py3-none-macosx_11_0_x86_64.whl

Download URL affine_desktop_mcp-0.2.2-py3-none-macosx_11_0_x86_64.whl
Size 3.0 MB
Tags Python 3 macOS 11.0+ x86-64
SHA-256 checksum
How to use checksums
cc3ab910d94c299b7557832575609eee25fcee7293a19ac0056b0429987d928b
BLAKE2b-256 checksum
How to use checksums
f26d3c0cc1726f76a44626badfe9eeafa4c86d6b14aff9a6afc370fe7a733d45
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.16

Release files / affine_desktop_mcp-0.2.2-py3-none-macosx_11_0_arm64.whl

Download URL affine_desktop_mcp-0.2.2-py3-none-macosx_11_0_arm64.whl
Size 2.8 MB
Tags Python 3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
dd75759983213270fc88865105c8004e93a9e0c35841865f5dae20717fc9f286
BLAKE2b-256 checksum
How to use checksums
780d221b72bed78476b1faad2bc538567a1eba8c9e5be27838f9eb0afbd7c621
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.16

Release history Release notifications | RSS feed

This release

0.2.2 This release

7 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page