Baton MCP Server
Provides an adapter for Discord, allowing the orchestrator to send and receive messages, and interact with Discord servers and channels.
Click on "Install 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., "@Baton MCP Serverlist my recent files in Downloads"
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.
Baton
A local-first orchestration platform for bounded agent work: a Swift macOS control daemon behind fail-closed permission gates, driven by a TypeScript orchestrator over MCP.
English · 한국어 · 日本語 · 简体中文 · 繁體中文 · Español · Deutsch · Français · Português (Brasil) · Русский · Italiano · Bahasa Indonesia · Türkçe
Quickstart · Architecture · Tool surface · ADR index · Limitations · Credits
Apache-2.0 covers source code only. Media files are governed by the tiers and records inCREDITS.md, which take precedence for those files. Media that is not listed there is unrecorded, not free to reuse.
What this is
Baton is a two-layer platform for giving an agent a bounded amount of authority over one macOS workstation. A Swift daemon exposes machine capabilities as MCP tools behind a policy engine, an approval broker, and an append-only audit log; a TypeScript orchestrator plans work, keeps durable state, and drives those tools without ever being able to grant itself new authority. This is a working system built and run by one author on one machine — a platform plus command-line surfaces, not a packaged product: there is no installer, no notarized release, and no hosted service here, and the daemon layer runs on macOS only. Workstation-derived evaluations, private operational packs, and local audit captures are deliberately excluded from the public source, so this snapshot is the engineering substrate rather than the author's live configuration.
Related MCP server: OmniCommanderMCP
Highlights
63 tools in the generated tool-surface ledger (
docs/TOOL_SURFACE.json) — a machine-checked public answer to "what can this thing actually do".Fail-closed approval broker (ADR-003): the approval fingerprint is
SHA-256(tool + "\n" + canonical JSON args), rows are inserted pending,pending → grantedis one atomic transition, consumption is fingerprint-bound and single-use, and grants are TTL-bounded. A row's existence does not imply a grant.234 JavaScript/TypeScript test and spec files; the persona-behaviour test alone carries 112 assertions.
16 TypeScript workspace packages and 90 Swift files across the daemon and a native menu-bar app (
swift-tools-version6.1 and 6.0, macOS 14+).15 architecture decision records, plus an ADR-index gate (
npm run audit:adr-index) that fails when a repo-local ADR is missing from the index.9 CI jobs, split so TypeScript work runs on Linux runners while the Swift daemon and menu-bar targets run on macOS runners.
332 PNG files, every one first-party: 33 runner packs × 10 frames, plus 2 contact sheets, all emitted by a single in-repo Pillow generator (
apps/menubar/tools/gen-runners-v2.py).54 ported-file provenance rows in
docs/PROVENANCE.md, each recording source path, source commit, date, and an explicit divergence note.A limitations document that is part of the design (
docs/LIMITATIONS.md) — for example, an unbundled daemon cannot hold a CoreLocation grant, so there is no location tool, permanently.
Screenshots
This snapshot tracks no UI captures: the menu-bar app, companion surface, and CLI are not photographed here, and inventing captures for a README would be worse than omitting them. What it does track is the contact sheet the sprite generator emits, which is the visual output that actually lives in the repository:
Each row is one runner pack: 10 frames on a 44×36 menu-bar sprite spec, with a per-character palette, an automatic dark contour so the sprite stays legible on light and dark menu bars, a ground shadow, an eye blink, and a distinct motion cycle. Nothing here was downloaded — see How this was built.
Use it
Baton is used from source. Three surfaces exist:
Surface | What it is | Requirement |
Control daemon | The Swift MCP daemon. Speaks MCP over stdio; every gated call passes policy → approval → audit. | macOS 14+, Swift 6.1 toolchain |
Orchestrator CLI | The TypeScript entry point for plans, missions, durable state, and adapters. | Node ≥ 22.13, pnpm |
Menu-bar app | Native macOS status and control surface. It discovers runner packs from disk, so adding a pack needs no Swift change. | macOS 14+, Swift 6.0 toolchain |
Configuration is environment-driven and documented in docs/CONFIG.md; .env.example enumerates the knobs across 162 lines. Do not put tokens or workstation paths in the repository. Mutating and outward-facing actions stay gated at the capability boundary — and read docs/LIMITATIONS.md before trusting a timeout.
Quickstart
Prerequisites: Node.js ≥ 22.13 and pnpm. package.json pins pnpm@10.33.0 for corepack; this snapshot's gate ran on Node.js v26.3.1 with pnpm 11.6.0. The Swift targets additionally need macOS 14+ and a Swift 6.1 toolchain.
git clone <your-fork-url> baton
cd baton
corepack enable
pnpm install --frozen-lockfile
pnpm -r build # TypeScript packages
pnpm -r test && npm run test:scripts # 234 test/spec files
npm run audit:adr-index # index must cover every repo-local ADRThose commands are exactly what the publication gate runs for this snapshot. The Swift targets are separate and are not exercised by that gate: npm run build:daemon, npm run build:menubar, and npm run checks each require the toolchain named above.
Architecture
Two layers, one boundary. Authority lives in Swift, planning lives in TypeScript, the only path between them is MCP, and the only way authority widens is an owner grant.
flowchart TB
subgraph TS["TypeScript orchestrator — 16 workspace packages"]
PL[Plans and missions] --> OC[Orchestrator core]
OC --> AD[Adapters: chat, web, editor, phone, voice]
OC --> DU[(Durable state / SQLite)]
OC --> PM[permission.ts — may request, never grant]
end
subgraph SW["Swift layer — 90 Swift files"]
GD[Gated dispatch watchdog] --> PE[Policy engine + recursive redaction]
PE --> AB[Approval broker: fingerprint, TTL, single-use]
AB --> TL[63 documented tools]
TL --> AU[(Append-only audit log)]
TL --> RD[Per-runner SIGTERM to SIGKILL deadline]
end
PM -->|MCP over stdio| GD
AB -->|grant required| OW([Owner: Touch ID / approval surface])Load-bearing properties:
Authority is not delegable.
orchestrator/packages/core/src/permission.tscan ask; only the Swift side decides. Orchestration cannot widen its own capability surface — which is why the tool ledger is generated rather than hand-maintained.Fingerprint canonicality is a correctness dependency. Approval fingerprints hash canonical JSON with sorted keys, so the Swift check harness pins the JSON encoder's key ordering. Without that pin, an encoding change would silently invalidate every stored fingerprint.
Two layered timeouts, deliberately. A per-runner deadline (default 30 s) is what actually reclaims a hung child process; the dispatch watchdog (default 180 s) is a backstop, because Swift cannot preempt a thread blocked on a child. The invariant
runner deadline < dispatch watchdogis what makes the design sound, and the residual leak — side effects that already happened before a timeout was recorded — is written down instead of hidden.Hermetic Swift. The daemon has zero external SwiftPM dependencies, and the menu-bar core target is pure Foundation so its models, REST client, and icon mapping are unit-testable without SwiftUI or AppKit.
Project layout
orchestrator/packages/ 16 TypeScript workspace packages
core/ orchestrator, agent loop, permission, memory, tools, security
cli/ mcp/ bus/ command surfaces, MCP wiring, event bus
durable/ sqlite/ durable state and storage
graph/ observe/ verify/ retrieval graph, telemetry, judge and verification
discord/ web/ phone/ voice-call/ companion/ env/ net-guard/ adapters and guards
daemon/ Swift MCP daemon: tools, safety stack, persistence, audit
apps/menubar/ native macOS menu-bar app + sprite generator and packs
apps/companion-extension/ browser companion surface
integrations/ editor integration and config sync
scripts/ build and install scripts, audit harness, CI helpers
docs/adr/ 15 architecture decision records + generated INDEX.md
docs/ TOOL_SURFACE.json, PROVENANCE.md, LIMITATIONS.md, runbooks
docs/i18n/ translated README set
profiles/ MCP and profile presets
eval/ prompt-evaluation configHow this was built
This repository is an AI-augmented build, and the interesting part is not that a model wrote code — it is where the model was allowed to be authoritative and where it was not.
Deterministic scanning first, model review second. scripts/audit/harness.sh runs typecheck, ESLint, Prettier, knip dead-code and unused-export detection, and madge circular-dependency analysis across all 16 packages — and says so in its own header: deterministic code does the mechanical scanning, the model only reviews the summary. It is report-only by default with a --strict mode for CI, so the ramp from advisory to blocking is an explicit decision rather than an accident.
A relay, not a single agent. Work was cut into bounded lanes: one agent implemented or audited a lane, a second cross-checked the behaviour and the evidence, and the author adjudicated. Handoff documents from those rounds ship in docs/, so the reasoning is auditable rather than folklore.
In-repo AI review that cannot merge anything. scripts/ci/ai-review.mjs reuses Baton's own primitives: a cross-encoder reranker picks the diff hunks most worth reviewing, a multi-axis judge pass runs over those hunks through a local model gateway, and the result is posted as a markdown review. It is advisory by construction — it never fails the build and never auto-merges.
Self-healing that stays a draft. scripts/ci/self-heal.mjs reacts to a red check by asking a local model for a strict unified diff, applying it on a scratch branch, re-running the failing command, and iterating up to a bounded number of attempts. Its default mode changes nothing at all; with --apply and a green result it opens a draft PR. It never pushes to main and never auto-merges. It also treats token thrift as a safety property: the model sees only the ~40 most error-relevant log lines plus the working-tree diff, never raw logs.
Mutation testing as the work generator. stryker.config.json scopes mutation to core/src, runs incrementally, and writes a JSON report. The loop is that a surviving mutant becomes the ticket, and a proposed killing test is accepted only once a runner proves it actually kills that mutant. Passing tests are not treated as evidence on their own.
Provenance gating on code, not just assets. Every file ported in from a sibling project carries a PORTED-FROM header and a row in docs/PROVENANCE.md — 54 rows recording source path, source commit, date, and a divergence note. Several of those notes are bugs found because the port forced a line-by-line comparison; one ancestor's integer accessor truncated 3.9 to 3, which had been letting "must be a non-negative integer" tool guards silently accept fractional input.
Self-generated media instead of downloads. All 332 PNGs come from apps/menubar/tools/gen-runners-v2.py, a supersampled Pillow renderer with one draw function per character, so a licence question about menu-bar art never arises. The generator ships alongside the packs, so a fork can regenerate rather than trust the binaries — and CREDITS.md records a tier and a digest for the shipped media regardless.
A fail-closed publication gate. This public snapshot is produced by an out-of-repo sanitizing pipeline that never writes to the private source. It archives a ref, applies exclusions, applies publication-only documentation, then refuses to commit unless every gate is green: secret scanning, credential-shaped-file detection, absolute-home-path and email-shape checks, a fixed-string employer/client wordlist expanded over delimiter variants, exclusion verification, build, tests — and a claims gate that re-runs the command behind each number in this README. A false README claim was the dominant defect class in the audit that produced this document, so these numbers are executable rather than aspirational.
Development
pnpm -r build # build all TypeScript packages
pnpm -r test # package test suites (Vitest)
npm run test:scripts # node:test suites for scripts/lib
npm run audit:adr-index # ADR index completeness gate
npm run typecheck # tsc -b across the workspace
npm run lint # eslint --max-warnings 0
npm run format:check # prettier --check
bash scripts/audit/harness.sh # full report-only audit
bash scripts/audit/harness.sh --strict # same, but any finding exits nonzeromacOS with a Swift toolchain additionally enables npm run build:daemon, npm run build:menubar, npm run checks (the Swift check harness), and npm run test:menubar.
When changing behaviour: add or extend a deterministic test, keep the ADR index in sync if you add an ADR, and update CREDITS.md if you add or replace any media file.
Localization
Credits
See CREDITS.md for the four-tier media register, the fail-closed rule for unlisted media, and the SHA-256 records. Its asset-specific terms take precedence over the code licence for any image or media file. Third-party software dependencies retain their upstream licences; the package manifests and pnpm-lock.yaml are the authoritative dependency inventory.
License
Source code is licensed under the Apache License 2.0; modification notices are recorded in NOTICE. Media files are not licensed by Apache-2.0 and remain governed by CREDITS.md.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- Alicense-qualityBmaintenanceA macOS computer-use MCP server that grants AI agents mouse, keyboard, and screen control with a robust security model including permission profiles, app deny-lists, and audit logging.Last updatedMIT
- AlicenseBqualityDmaintenanceEnables full local computer control from MCP clients, including terminal commands, file system operations, application management, screen capture, and input device automation across Windows, macOS, and Linux.Last updated27MIT
- Flicense-qualityBmaintenanceEnterprise-grade macOS MCP server that gives AI agents eyes, hands, and a terminal, enabling screen capture, mouse/keyboard control, shell commands, and file operations.Last updated
- Alicense-qualityBmaintenanceEnables AI agents to directly access native macOS services, media, system health, and administration tools through a local MCP server.Last updated25MIT
Related MCP Connectors
Remote MCP for Android CLI agent build gate, structured receipts, audit logs, and reviewer-ready evi
Control plane for autonomous software labor. Agents claim objectives over MCP with audit trail.
Remote MCP for Copilot CLI switch gate MCP, structured receipts, audit logs, and reviewer-ready evid
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/euuuuuuan/baton-public'
If you have feedback or need assistance with the MCP directory API, please join our Discord server