mcp server
unionize.software
Open-source, privacy-first organizing tools and field guides for software and game workers.
Set up
Runs on your computer. Pick your agent and operating system.
This project does not publish an install method we can turn into a config. Follow the README instead.
README
synced Oct 23, 2026unionize.software
Privacy-first public resource and decision-routing site for U.S. private-sector software and game workers.
Principles
- The public site is content-first.
- The
Start Herewizard stores nothing on the server. - Organizer intake is encrypted in the browser before submission.
- No analytics, session replay, ad pixels, or behavioral tracking.
Stack
- Next.js App Router
- React + TypeScript
- Tailwind CSS
- shadcn/ui-style components with Radix primitives
- Local MDX content with Zod frontmatter validation
- unionize-software CLI + local MCP server for agent access
- Supabase Postgres + Drizzle ORM
- Playwright tests
Local Development
- Use Node
22.xthrough24.xandpnpm. The current workspace has been validated on Node22.21.0. - Copy
.env.exampleto.env.local. - Fill in the public intake key and Supabase credentials.
- Publish the intake key ID, SHA-256 fingerprint, and rotation date together.
- Install dependencies with
pnpm install. - Start the app with
pnpm dev.
The Next config uses a development-only build directory, so pnpm dev does not collide with production build output.
With pnpm, CLI flags can be passed directly. For example:
pnpm dev --hostname 127.0.0.1 --port 3001
CLI And MCP
The repo now ships a small CLI and a local MCP server so agents and automation can consume the public guide corpus without scraping rendered pages.
Examples:
pnpm unionize guides list
pnpm unionize guides search "retaliation" --tag retaliation
pnpm unionize start schema --json
pnpm unionize start recommend --answers '{"inUnitedStates":"yes","privateSectorEmployer":"yes","workerStatus":"employee","supervisoryAuthority":"no","workplaceType":"startup","workArrangement":"hybrid","roleFamily":"full-stack/frontend/backend","topIssue":"AI surveillance","trustedCoworkers":"1-3 trusted coworkers","retaliationRisk":"no","organizerContact":"no"}'
pnpm mcp:serve
The MCP server exposes:
unionize://catalogunionize://pathfinder/schemaunionize://guides/<slug>- prompts for triage and first-conversation planning
- tools for guide search, project links, and pathfinder routing
See /tooling in the deployed site or app/tooling/page.tsx in the repo.
OpenClaw
OpenClaw can load workspace skills from skills/ and register MCP servers with openclaw mcp set.
This repo includes a starter skill at skills/unionize-organizing/SKILL.md.
Local MCP registration example:
openclaw mcp set unionize "{\"command\":\"node\",\"args\":[\"./bin/unionize-software.mjs\",\"mcp\",\"serve\"],\"cwd\":\"/absolute/path/to/unionize.software\"}"
Public source repository:
https://github.com/unionize-software/unionize.software
Testing
pnpm testruns Playwright against a static build (out/) served locally (next startdoes not supportoutput: "export").- Four tests POST to the deployed intake API (
https://api.unionize.software/intakeby default). They auto-skip when that host is unreachable (no DNS / not deployed). To skip them without probing, setPLAYWRIGHT_SKIP_LIVE_INTAKE=1. Override the URL withPLAYWRIGHT_INTAKE_URL.
Local Intake Dashboard (organizers only)
The CLI can run a localhost-only dashboard that reads the local intake cache at ~/.unionize/intakes.sqlite.
Workflow:
- Sync from AWS into the local DB:
AWS_REGION=us-east-1 INTAKE_TABLE_NAME="..." CIPHERTEXT_BUCKET_NAME="..." node bin/unionize-software.mjs intake sync
- Start the local dashboard:
node bin/unionize-software.mjs intake dashboard --port 4317
If you want the dashboard to support decrypt on demand, pass the private key path:
node bin/unionize-software.mjs intake dashboard --port 4317 --private-key ./keys/organizer-private.key
The private key is never stored in the database; it stays on the organizer machine.
Self-host (Docker Compose)
For non-AWS self-hosting (single box), docker-compose.yml runs:
site: serves the static export inout/athttp://localhost:3000intake_api: accepts encrypted POSTs athttp://localhost:3010/intakeand stores to./data/selfhost/
Steps:
pnpm build
docker compose up --build
Then set the site build-time env:
NEXT_PUBLIC_INTAKE_API_URL="http://localhost:3010/intake"
If you also want the organizer dashboard to read self-hosted intakes, import them into the same local cache:
node bin/unionize-software.mjs intake import-selfhost --data-dir ./data/selfhost
node bin/unionize-software.mjs intake dashboard --port 4317
AWS Amplify
The repo includes amplify.yml for Amplify Hosting.
It assumes:
pnpminstalled during the AmplifypreBuildphasepnpm build(Next.js withoutput: "export") as the build commandoutas the artifactbaseDirectory(static HTML/CSS/JS)
Before deploying, set branch environment variables, especially:
NEXT_PUBLIC_INTAKE_API_URL(full URL, e.g.https://api.unionize.software/intake)- public intake key fields (
NEXT_PUBLIC_INTAKE_PUBLIC_KEY_*) - any Supabase client credentials the app still needs at build/runtime
CSP: headers() in next.config.ts are not applied for static export; enforce CSP in production via CloudFront response headers policy (or equivalent) if you need the same guarantees as the dev server.
Local Intake Decryption
The repository never contains organizer private keys.
Use the local script after you export ciphertext from storage:
pnpm decrypt-intake --ciphertext "<base64-or-raw-ciphertext>" --private-key ./keys/organizer-private.key
The private key must remain on an organizer-controlled machine and must never be uploaded to Supabase, Vercel, GitHub, or any browser-accessible environment.
Intake Operations
pnpm print-intake-key-fingerprint --public-key "<base64>"prints the public key fingerprint for operator verification.pnpm purge-expired-intakes --dry-runpreviews expired ciphertext cleanup.pnpm purge-expired-intakessoft-deletes expired ciphertext and hard-deletes rows past the purge grace window.- See
docs/KEY_MANAGEMENT.mdfor rotation, revocation, and backup handling.
By default, encrypted intake rows are marked to expire after 30 days and should be purged 7 days after soft-delete.
Licensing
- Source code outside
content/is licensed under AGPL-3.0-or-later. See LICENSE. - Original written material in
content/is licensed under CC BY-SA 4.0. See CONTENT_LICENSE.md. - Third-party dependencies, fonts, and referenced source material retain their own licenses and attribution requirements.
Contributions are accepted under the license that applies to the part of the repository being changed.