Pluk turns the services you already use — databases, Linear, and more — into local MCP endpoints, so AI tools can use them safely from your own machine. Nothing leaves your laptop: the server runs on localhost, integrations are stored locally, and a per-integration policy engine keeps agents in bounds.
Each service is a pluggable adapter. Pluk ships with database adapters (Postgres / MySQL / SQLite) and a Linear adapter; adding another is one module — no changes to the app, server, or UI.
It ships as a macOS menu bar app with an embedded server. You add an integration in the UI, copy its MCP URL, and paste it into your AI client.
Pluk has two parts that the Makefile builds and bundles together:
swift/— a native macOS menu bar app (SwiftUI, macOS 14+). It manages integrations, shows activity logs, and supervises the server process. The add/edit form renders itself from the server's adapter catalog, so new adapters appear automatically.pluk/— a Bun + TypeScript server. It speaks MCP over streamable HTTP onhttp://localhost:4242, resolves each integration to its adapter (databases over SSH/SSL, Linear over its GraphQL API, …), and enforces that integration's policy.
The app launches the server, which exposes each saved integration at http://localhost:4242/mcp/<token>.
Concept docs live in docs/:
- Integrations — what an integration is, its lifecycle, policy, and MCP URL.
- Integration types — every service type and the tools it exposes.
- Groups — bundle several integrations behind one URL.
- macOS 14 or later
- Bun —
curl -fsSL https://bun.sh/install | bash - Swift toolchain — install Xcode or the Command Line Tools (
xcode-select --install) - Make (ships with the Command Line Tools)
Clone, build, and install the app to /Applications in one step:
git clone git@github.com:yondifon/pluk.git
cd pluk
make installmake install compiles the Bun server into a standalone binary, builds the Swift app in release mode, assembles Pluk.app, copies it to /Applications, and launches it. Pluk then lives in your menu bar.
To iterate on the Swift app with the server running from source:
make devThis runs swift run from swift/, which starts the app and the bundled server.
To run just the server (useful for working on the TypeScript / MCP side):
cd pluk
bun install
bun run serverThe server listens on http://localhost:4242. Health check: curl http://localhost:4242/health.
| Target | What it does |
|---|---|
make dev |
Run the app from source (swift run) |
make server |
Compile the Bun server to dist/pluk-server |
make swift-build |
Build the Swift app in release mode |
make bundle |
Assemble dist/Pluk.app (server + app + Info.plist) |
make install |
Build, install to /Applications, and launch |
make zip |
Bundle and zip the app for distribution |
make clean |
Remove dist/ and clean the Swift package |
Set APPLE_IDENTITY to code-sign the bundle: make bundle APPLE_IDENTITY="Developer ID Application: …".
-
Open Pluk from the menu bar and add an integration. Pick a type — a database (host, port, credentials, optional SSH and read-only flag) or Linear (API key) — and the form shows just that adapter's settings.
-
Test the integration from the detail view.
-
Copy its MCP URL — one URL per integration, so each agent only sees what you intend.
-
Add it to your MCP client. Example (
opencode.jsonc):
Every integration carries its own policy, and all access is recorded in a local activity log.
- Databases — a SQL policy engine classifies each statement. Treat production as read-heavy: prefer
SELECT, add explicitLIMITs, avoid broad scans and writes. Enable read-only mode and Pluk blocks write statements; Postgres also uses short connect/query timeouts so failed tunnels don't hang the UI. - Linear (and other API adapters) — a coarse read/write policy. Read-only blocks mutating actions (create issue, comment); read & write allows them.
Pluk reads ~/.ssh/config. Hosts with a ProxyCommand use the system ssh client for forwarding, which supports Cloudflare Access and your existing SSH agent / keychain setup:
Host app4-ssh-infra.example.com
ProxyCommand /opt/homebrew/bin/cloudflared access ssh --hostname %h
IdentityAgent "~/Library/Group Containers/2BUA8C4S2C.com.1password/t/agent.sock"Contributions are welcome. The fastest loop:
-
Fork and clone:
git clone git@github.com:yondifon/pluk.git cd pluk -
Install server dependencies and run the test suite:
cd pluk bun install bun test
-
Hack on the relevant side:
- Adapters (add a new service) →
pluk/src/adapters/— implement theAdaptercontract (types.ts) and register it inadapters/index.ts. The DB family lives inadapters/sql/, Linear inadapters/linear/. DeclaringconfigFieldsis enough for the macOS form to render it; nothing else needs editing. - Server / MCP / policy →
pluk/src/(SQL policy inmcp/policy.ts, action policy inmcp/actionPolicy.ts, drivers inpluk/src/db/) - App / UI →
swift/Sources/
- Adapters (add a new service) →
-
Verify your change end to end with
make dev. -
Open a pull request against
mainwith a clear description of the change and why it matters.
Conventions:
- Use Bun, not
npm/yarn/pnpm(bun install,bun test,bun run). - Keep changes surgical and match the surrounding style.
- Add tests for policy and driver behavior — these guard what agents are allowed to run.
Copyright © 2025 Pluk. See the repository for license details.
{ "$schema": "https://opencode.ai/config.json", "mcp": { "my-prod-db": { "type": "remote", "enabled": true, "url": "http://localhost:4242/mcp/<token>", "oauth": false } } }