Doramagic Project Pack · Human Manual

handoff-mcp

MCP server that gives AI coding agents persistent memory across sessions

Overview and System Architecture

Related topics: Core Tools and CLI API, Data Model and Storage Layer, Installation, Setup, and Operations

Section Related Pages

Continue reading this section for the full explanation and source context.

Related topics: Core Tools and CLI API, Data Model and Storage Layer, Installation, Setup, and Operations

Overview and System Architecture

handoff-mcp is a Model Context Protocol (MCP) server implemented in Rust. Its role is to expose MCP-compatible capabilities to clients (typically AI agents or tool-using LLMs) by accepting JSON-RPC requests, routing them to the correct handler, and returning protocol-conformant responses. The project is intentionally split between a thin executable entry point and a reusable library crate, so that the MCP core can be embedded into other Rust applications.

High-Level Component Layout

The source tree separates concerns into three layers: the binary entry point, the library façade, and the mcp module that contains all protocol-specific logic.

LayerFileResponsibility
Binarysrc/main.rsProcess startup, configuration loading, and dispatch into the library
Library façadesrc/lib.rsPublic re-exports and crate-level glue for handoff_mcp
MCP modulesrc/mcp/mod.rsWires protocol, router, and server state together
Protocolsrc/mcp/protocol.rsDefines message types, request/response shapes, and serialization
Routersrc/mcp/router.rsDispatches incoming requests to registered handlers

Source: src/main.rs:1-40 Source: src/lib.rs:1-30 Source: src/mcp/mod.rs:1-50

The binary in src/main.rs performs only orchestration: it parses command-line arguments, configures logging, constructs the MCP server via the library API, and waits for incoming traffic. Heavy lifting is delegated to src/lib.rs, which re-exports the relevant types and functions so external consumers can integrate the same MCP server without depending on the binary.

Execution Flow

The runtime flow begins when a client opens a transport connection (stdio or another transport enabled by configuration) and sends a JSON-RPC framed request. The server deserializes the payload using the protocol types, hands the resulting request to the router, executes the matching handler, and writes the response back onto the same transport.

flowchart LR
    A[Client] -->|JSON-RPC request| B[main.rs entry]
    B --> C[mcp::mod server loop]
    C --> D[protocol.rs decode]
    D --> E[router.rs dispatch]
    E --> F[Handler]
    F --> E
    E --> C
    C --> G[protocol.rs encode]
    G --> A

Source: src/mcp/protocol.rs:1-80 Source: src/mcp/router.rs:1-60 Source: src/mcp/mod.rs:20-90

The protocol layer (protocol.rs) is responsible for the wire format: it defines the JSON-RPC envelope, error codes, and the concrete request and response variants that the server understands. By centralizing serialization here, the rest of the codebase works with strongly typed Rust values instead of raw JSON, which reduces the risk of malformed responses.

Routing and Handler Dispatch

The router (src/mcp/router.rs) maintains a registry that maps method names (such as tools/list, tools/call, resources/read, or initialize) to handler implementations. When a request arrives, the router looks up the method, validates the parameters against the protocol's expected schema, invokes the handler, and converts any returned error into the correct JSON-RPC error object.

Key properties of the router design include:

  • Method-based dispatch: handlers are keyed by the JSON-RPC method string rather than by concrete Rust types, making it straightforward to add new capabilities.
  • Typed parameter extraction: the router relies on protocol.rs definitions to deserialize arguments into the handler's expected input type.
  • Uniform error mapping: domain-level Result types from handlers are translated into protocol-level error responses in one place.

Source: src/mcp/router.rs:20-120 Source: src/mcp/protocol.rs:60-160

Configuration, Startup, and Extensibility

Startup is driven by main.rs, which reads configuration (transport choice, bind address, logging level) and constructs a server instance through the library API exposed in lib.rs. Because lib.rs re-exports the public surface of the mcp module, embedding handoff-mcp into another Rust application follows the same construction path as the bundled binary.

The README describes handoff-mcp as a handoff-oriented MCP server: requests that arrive while a long-running operation is in progress are queued or forwarded rather than dropped, which keeps connected agents responsive. The router's dispatch path and the server loop in mcp/mod.rs together implement that semantics.

Source: README.md:1-80 Source: src/main.rs:30-70 Source: src/mcp/mod.rs:40-110

In summary, handoff-mcp is organized around a clear protocol boundary: main.rs starts the process, lib.rs exposes the reusable server API, and mcp/ contains the protocol definitions and router that together turn JSON-RPC requests into typed handler calls and back into well-formed responses. This layering keeps the protocol implementation testable and makes it straightforward to add new MCP capabilities by registering additional handlers with the router.

Source: https://github.com/alphaelements/handoff-mcp / Human Manual

Core Tools and CLI API

Related topics: Overview and System Architecture, Data Model and Storage Layer

Section Related Pages

Continue reading this section for the full explanation and source context.

Section Initialization (init.rs)

Continue reading this section for the full explanation and source context.

Section Loading Context (loadcontext.rs)

Continue reading this section for the full explanation and source context.

Section Saving Context (savecontext.rs)

Continue reading this section for the full explanation and source context.

Related topics: Overview and System Architecture, Data Model and Storage Layer

Core Tools and CLI API

The Core Tools and CLI API is the public contract of the handoff-mcp server. It registers the set of MCP tools that clients can invoke, defines the request/response types that flow over the wire, and dispatches each tool call to a dedicated handler module. Together, these components let an external agent persist, retrieve, and initialize conversational context that can be "handed off" between sessions or processes.

Tool Registry

src/mcp/tools.rs is the central registry of the server's capabilities. It enumerates the tool descriptors that the server advertises to MCP clients during capability negotiation. Each descriptor includes the tool's name, a human-readable description, and the JSON Schema for its inputs.

The registry wires three core tools into the dispatcher:

Tool namePurposeHandler module
initEstablishes a handoff session and returns server metadatahandlers/init.rs
load_contextRetrieves a previously saved context blobhandlers/load_context.rs
save_contextPersists the current context for later retrievalhandlers/save_context.rs

Source: src/mcp/tools.rs Source: src/mcp/handlers/mod.rs

Type System

src/mcp/types.rs defines the data structures shared between the registry, handlers, and the underlying transport. These types model the shape of tool arguments (e.g., a context identifier, a payload blob, optional metadata) and the standardized result envelope returned to the client. By centralizing the schema, the module ensures that every handler produces a response that the MCP client can deserialize consistently.

Source: src/mcp/types.rs

Handler Modules

The handlers/ submodule is organized so that each tool owns its own file, keeping cross-cutting state out of the request path. The dispatcher in handlers/mod.rs matches an incoming tools/call request by tool name and forwards the parsed arguments to the matching handler.

Initialization (`init.rs`)

The init handler runs during the first exchange with a client. It returns server identity information and prepares any in-memory state required by the session. Because the rest of the lifecycle (load and save) depends on this step completing successfully, init is the entry point for all subsequent tool invocations.

Source: src/mcp/handlers/init.rs

Loading Context (`load_context.rs`)

The load_context handler resolves a context identifier supplied by the client and returns the associated payload. The handler is responsible for validating the identifier, locating the stored context, and serializing it through the shared response type defined in types.rs.

Source: src/mcp/handlers/load_context.rs

Saving Context (`save_context.rs`)

The save_context handler accepts a context payload from the client, validates it against the schema declared in tools.rs, and writes it to the storage layer. On success it returns a confirmation that the calling agent can use as a receipt for the handoff.

Source: src/mcp/handlers/save_context.rs

Request Flow

The diagram below summarizes how a tool invocation traverses the layers of the server, from the initial MCP request to the handler-specific response.

sequenceDiagram
    participant Client as MCP Client
    participant Tools as tools.rs (registry)
    participant Dispatcher as handlers/mod.rs
    participant Handler as handlers/*.rs
    participant Types as types.rs

    Client->>Tools: list/capabilities
    Tools-->>Client: tool descriptors (init, load_context, save_context)
    Client->>Dispatcher: tools/call { name, args }
    Dispatcher->>Types: parse args via shared types
    Types-->>Dispatcher: validated request
    Dispatcher->>Handler: route to handler
    Handler-->>Dispatcher: result envelope
    Dispatcher-->>Client: tools/call response

This flow illustrates that tools.rs controls what the client can request, handlers/mod.rs controls how those requests are routed, and types.rs controls the shape of data that crosses every boundary. Individual handler files (init.rs, load_context.rs, save_context.rs) implement the tool-specific business logic without duplicating transport or schema concerns.

Scope and Boundaries

The Core Tools and CLI API is intentionally narrow: it does not implement the storage backend, the transport layer, or the host process. Its job is limited to:

  • Advertising the three tools defined in tools.rs.
  • Declaring the input and output schemas in types.rs.
  • Dispatching each call to a single, focused handler module.
  • Returning well-formed MCP responses.

Anything beyond that boundary — persistence, authentication, telemetry, process lifecycle — is handled by modules outside the mcp/ tree and is therefore out of scope for this page.

Source: https://github.com/alphaelements/handoff-mcp / Human Manual

Data Model and Storage Layer

Related topics: Overview and System Architecture, Core Tools and CLI API

Section Related Pages

Continue reading this section for the full explanation and source context.

Section Sessions

Continue reading this section for the full explanation and source context.

Section Tasks

Continue reading this section for the full explanation and source context.

Section Configuration

Continue reading this section for the full explanation and source context.

Related topics: Overview and System Architecture, Core Tools and CLI API

Data Model and Storage Layer

Purpose and Scope

The Data Model and Storage Layer is the persistent and in-memory substrate that backs every stateful operation of the handoff-mcp server. Its role is to own the canonical representation of sessions, tasks, and configuration, and to present a uniform trait-based interface to the rest of the system so that MCP tool handlers do not need to know whether a record lives in process memory, on a local filesystem, or inside a Git working tree.

The layer sits between the transport/tool surface above and the operating-system or VCS primitives below, and is the single point at which schema, validation, and concurrency rules are enforced. Source: src/storage/mod.rs:1-60.

Module Layout

Storage is organized as a single Rust module facade at storage/mod.rs that re-exports the backend trait and the concrete implementations. Domain entities each have a dedicated file, while the two storage backends (in-memory and Git-backed) live in their own submodules.

FileResponsibility
mod.rsTrait surface, re-exports, dispatch
sessions.rsSession records, identity, parent linking
tasks.rsTask records, state transitions
config.rsServer- and session-level configuration
git.rsGit-backed implementation of the storage trait
memory/mod.rsIn-memory implementation used for tests and ephemeral mode

Source: src/storage/mod.rs:5-40, src/storage/sessions.rs:1-30, src/storage/tasks.rs:1-30, src/storage/config.rs:1-30.

Core Entities and Relationships

Sessions

A Session describes a bounded execution or handoff context that may be passed between agents. Each session is keyed by an opaque ID, carries creation and last-modified timestamps, an owner, and an optional parent session ID used to express continuation chains when one agent hands work to another. Source: src/storage/sessions.rs:20-90.

Tasks

A Task represents a discrete unit of work scoped to a single session. Each task holds a status drawn from a fixed state machine (such as Pending, InProgress, Blocked, Done, Cancelled), assignees, and free-form payload. Task records are immutable in their history: state changes are recorded as ordered transition events rather than overwritten in place, allowing the audit trail to be reconstructed later. Source: src/storage/tasks.rs:10-110.

Configuration

config.rs persists server-wide and per-session configuration: paths, feature flags, limits, and behavioural toggles. Values are versioned and re-read lazily so that operators can change settings without restarting the process. Source: src/storage/config.rs:15-80.

Storage Backends

The trait defined at the top of the module has two production implementations.

In-Memory Backend

storage/memory/mod.rs provides a non-persistent backend built on concurrent collections guarded by interior synchronisation (typically Arc<RwLock<_>>). It is used for unit tests, for ephemeral single-process deployments, and as the default when no Git repository is configured. Source: src/storage/memory/mod.rs:1-70.

Git-Backed Backend

storage/git.rs treats a checked-out repository as the durable surface. Sessions, tasks, and config files are serialized under a conventional directory layout inside the working tree, and writes are committed so that every accepted transition becomes a reviewable, revertible change. This backend is the only one suitable for multi-host or long-lived deployments, because it provides an audit trail and rollback semantics for free. Source: src/storage/git.rs:30-150.

flowchart LR
  H[MCP Tool Handlers] --> F[storage::mod facade]
  F --> M[(memory/mod.rs)]
  F --> G[(git.rs)]
  G --> R[(Git working tree)]
  M --> S[sessions.rs]
  M --> T[tasks.rs]
  M --> C[config.rs]
  G --> S
  G --> T
  G --> C

Invariants and Concurrency

The layer follows a single-writer-multiple-reader discipline at backend granularity. The in-memory backend uses read/write locks for fine-grained access, while the Git backend serializes write paths through a mutex around the underlying git2 repository handle to keep the index from corrupting under contention. Domain entities are never mutated in place; callers invoke transition methods that return validated, new versions, and the storage layer is responsible for atomicity (in-memory swap, or staging-then-commit on disk). Source: src/storage/tasks.rs:90-160, src/storage/git.rs:120-200, src/storage/memory/mod.rs:60-110.

Cross-References

  • The session and task APIs are consumed by the MCP tool surface elsewhere in the crate; see src/storage/sessions.rs and src/storage/tasks.rs for the canonical method signatures exposed upward.
  • Configuration reload semantics and validation rules are documented at the source of config.rs.
  • The Git backend is the only backend that survives a process restart and is the recommended one for any multi-agent or production deployment; see src/storage/git.rs for the commit and rollback contract.

Source: https://github.com/alphaelements/handoff-mcp / Human Manual

Installation, Setup, and Operations

Related topics: Overview and System Architecture, Core Tools and CLI API

Section Related Pages

Continue reading this section for the full explanation and source context.

Section Memory Hook

Continue reading this section for the full explanation and source context.

Section Environment Sourcing

Continue reading this section for the full explanation and source context.

Section Runtime Launch

Continue reading this section for the full explanation and source context.

Related topics: Overview and System Architecture, Core Tools and CLI API

Installation, Setup, and Operations

Overview and Hybrid Build Model

handoff-mcp is distributed as a Node.js package that bundles a Rust binary implementing a Model Context Protocol (MCP) server. The hybrid model lets JavaScript tooling handle packaging, lifecycle, and hook orchestration while the native binary handles protocol-level message exchange. The Cargo manifest declares the Rust crate, its release profile (optimized for size with lto, codegen-units = 1, strip = "symbols"), and a [[bin]] target for the MCP executable. Source: Cargo.toml:1-40

The Node side acts as a thin client launcher: bin/handoff-mcp.js resolves the platform-specific native binary inside node_modules/@alphaelements/handoff-mcp/bin/ and spawns it as a child process, forwarding stdin/stdout so the MCP transport stays intact. Source: bin/handoff-mcp.js:1-40

Prerequisites

The project targets two toolchains that must be present before installation:

  • Rust toolchain (cargo, rustc) — required to compile the native binary referenced in Cargo.toml. The build uses standard Cargo conventions and does not pin a specific rust-version in the manifest, so any reasonably recent stable compiler is accepted. Source: Cargo.toml:1-40
  • Node.js / npm — required to install the package, run the launcher, and execute the post-install hook. The package.json bin field exposes the handoff-mcp command, and scripts.install delegates to the postinstall step. Source: package.json:1-60

A helper script scripts/cargo-env.sh exports environment variables (CARGO_HOME, RUSTUP_HOME, PATH updates for cargo/rustc) so the toolchain is discoverable inside CI shells, container images, or local sandboxes where defaults are absent. Source: scripts/cargo-env.sh:1-30

Installation Workflow

flowchart TD
    A[npm install handoff-mcp] --> B[scripts/postinstall.js runs]
    B --> C{cargo available?}
    C -- yes --> D[cargo build --release]
    D --> E[Native binary placed under bin/]
    C -- no --> F[Fail with toolchain error]
    E --> G[Package ready: bin/handoff-mcp.js + native bin]
    G --> H[User invokes handoff-mcp CLI]
    H --> I[bin/handoff-mcp.js spawns native child]
    I --> J[MCP server communicates via stdio]

The scripts.install hook in package.json invokes scripts/postinstall.js, which is responsible for compiling the Rust crate and placing the resulting binary in the package's bin/ directory. The Node launcher bin/handoff-mcp.js then locates that binary by platform (e.g. handoff-mcp-linux-x64, handoff-mcp-darwin-arm64) and exec it. Source: scripts/postinstall.js:1-80, bin/handoff-mcp.js:1-40

The package exposes the handoff-mcp binary through the bin field of package.json, so once installation completes the command is available on PATH for MCP-aware clients to call. Source: package.json:1-60

Operations and Runtime Hooks

Memory Hook

scripts/handoff-memory-hook.py is a Python entry point that lets the MCP server persist or recall conversation state. It is intended to be invoked by the native binary (or an MCP client wrapper) as a sidecar process when memory features are enabled. The script provides a CLI-style interface that can be wired into the MCP tools list to expose memory operations to the host model. Source: scripts/handoff-memory-hook.py:1-120

Environment Sourcing

For non-interactive shells, operators should source scripts/cargo-env.sh before running npm install so that cargo is reachable when the postinstall hook triggers. This is the recommended pattern in CI: load the env script, then run npm ci so the Rust build step has the toolchain it needs. Source: scripts/cargo-env.sh:1-30

Runtime Launch

When the user runs handoff-mcp, the Node shim in bin/handoff-mcp.js selects the correct prebuilt binary, sets any required environment variables, and hands the process over to the Rust implementation. The native server then speaks MCP framing over the inherited stdio file descriptors, which is the standard transport for local MCP integrations. Source: bin/handoff-mcp.js:1-40

Operational Checklist

StepActionSource
1Install Rust toolchain (rustup)scripts/cargo-env.sh:1-30
2npm install handoff-mcp (runs postinstall.jscargo build --release)package.json:1-60, scripts/postinstall.js:1-80
3Confirm binary present under node_modules/.../bin/bin/handoff-mcp.js:1-40
4Configure MCP client to call handoff-mcp as a stdio serverbin/handoff-mcp.js:1-40
5Optionally wire handoff-memory-hook.py as a memory toolscripts/handoff-memory-hook.py:1-120

Troubleshooting Notes

  • Postinstall fails on missing cargo: re-source scripts/cargo-env.sh or reinstall the Rust toolchain, then rerun npm install. Source: scripts/cargo-env.sh:1-30
  • handoff-mcp not found after install: verify node_modules/.bin is on PATH; the bin entry in package.json only registers the shim once npm links the package. Source: package.json:1-60
  • Native binary mismatch: the shim selects the binary by platform/arch; ensure the build emitted the expected artifact under bin/. Source: bin/handoff-mcp.js:1-40

This page covers the install-to-runtime path. For protocol-level details (tools, resources, message framing), consult the Rust crate source referenced from Cargo.toml. Source: Cargo.toml:1-40

Source: https://github.com/alphaelements/handoff-mcp / Human Manual

Doramagic Pitfall Log

Source-linked risks stay visible on the manual page so the preview does not read like a recommendation.

medium Configuration risk requires verification

May increase setup, validation, or first-run risk for the user.

medium Capability evidence risk requires verification

May increase setup, validation, or first-run risk for the user.

medium Maintenance risk requires verification

May increase setup, validation, or first-run risk for the user.

medium Security or permission risk requires verification

May increase setup, validation, or first-run risk for the user.

Doramagic Pitfall Log

Found 7 structured pitfall item(s), including 0 high/blocking item(s). Top priority: Configuration risk - Configuration risk requires verification.

1. Configuration risk: Configuration risk requires verification

  • Severity: medium
  • Finding: Project evidence flags a configuration risk. Review the linked source before relying on this workflow.
  • User impact: May increase setup, validation, or first-run risk for the user.
  • Recommended check: Reproduce the official install and quickstart path in an isolated environment.
  • Evidence: capability.host_targets | https://github.com/alphaelements/handoff-mcp

2. Capability evidence risk: Capability evidence risk requires verification

  • Severity: medium
  • Finding: README/documentation is current enough for a first validation pass.
  • User impact: May increase setup, validation, or first-run risk for the user.
  • Recommended check: Reproduce the official install and quickstart path in an isolated environment.
  • Evidence: capability.assumptions | https://github.com/alphaelements/handoff-mcp

3. Maintenance risk: Maintenance risk requires verification

  • Severity: medium
  • Finding: Project evidence flags a maintenance risk. Review the linked source before relying on this workflow.
  • User impact: May increase setup, validation, or first-run risk for the user.
  • Recommended check: Reproduce the official install and quickstart path in an isolated environment.
  • Evidence: evidence.maintainer_signals | https://github.com/alphaelements/handoff-mcp

4. Security or permission risk: Security or permission risk requires verification

  • Severity: medium
  • Finding: no_demo
  • User impact: May increase setup, validation, or first-run risk for the user.
  • Recommended check: Reproduce the official install and quickstart path in an isolated environment.
  • Evidence: downstream_validation.risk_items | https://github.com/alphaelements/handoff-mcp

5. Security or permission risk: Security or permission risk requires verification

  • Severity: medium
  • Finding: no_demo
  • User impact: May increase setup, validation, or first-run risk for the user.
  • Recommended check: Reproduce the official install and quickstart path in an isolated environment.
  • Evidence: risks.scoring_risks | https://github.com/alphaelements/handoff-mcp

6. Maintenance risk: Maintenance risk requires verification

  • Severity: low
  • Finding: issue_or_pr_quality=unknown。
  • User impact: May increase setup, validation, or first-run risk for the user.
  • Recommended check: Reproduce the official install and quickstart path in an isolated environment.
  • Evidence: evidence.maintainer_signals | https://github.com/alphaelements/handoff-mcp

7. Maintenance risk: Maintenance risk requires verification

  • Severity: low
  • Finding: release_recency=unknown。
  • User impact: May increase setup, validation, or first-run risk for the user.
  • Recommended check: Reproduce the official install and quickstart path in an isolated environment.
  • Evidence: evidence.maintainer_signals | https://github.com/alphaelements/handoff-mcp

Source: Doramagic discovery, validation, and Project Pack records

Community Discussion Evidence

These external discussion links are review inputs, not standalone proof that the project is production-ready.

Sources 1

Count of project-level external discussion links exposed on this manual page.

Use Review before install

Open the linked issues or discussions before treating the pack as ready for your environment.

Community Discussion Evidence

Doramagic exposes project-level community discussion separately from official documentation. Review these links before using handoff-mcp with real data or production workflows.

Source: Project Pack community evidence and pitfall evidence