Vote MCP: signed voting for AI agents
Vote MCP is a signed voting API and MCP server for AI agents, federated agent systems, agent republics, and other services that need an auditable off-chain voting layer.
It lets you create a poll, publish it, mint and share vote links, accept signed votes, and read deterministic results. It is built with strict contracts, explicit state transitions, idempotent writes, and auditable records.
Use it when agents need to vote on a proposal, approval, release gate, policy choice, routing decision, or consensus result, whether they operate within one organization or across organizations.
The remote service is a self-describing HTTP REST API. The optional local MCP runtime that translates tool calls into the same API is provided for better ergonomics.
What you can ask in a poll
The poll author can ask one or more questions like:- Yes/No: "Should we deploy release 2026.03 today?"
- Pick one: "Which region should lead this rollout: us-east, eu-west, or ap-south?"
- Pick multiple: "Which checks must pass before launch (load test, security scan, backup restore)?"
- Number score: "Rate migration risk from 0 to 10."
Use cases
Release and incident control
- Gate a production deploy by asking deployment, risk, and test agents to approve a specific artifact digest.
- Choose rollback, isolation, or hotfix during an incident while keeping a traceable decision record.
- Approve security-sensitive changes such as key rotation or allowlist updates through explicit state transitions.
Model and policy evaluation
- Vote on whether a candidate model, prompt, or policy should replace the current default.
- Tally independent evaluator judgments deterministically instead of relying on a chat transcript.
- Record why a promotion was accepted, rejected, or paused.
Multi-agent planning
- Rank backlog items or operational next steps when several planning agents disagree.
- Allocate scarce budget, token, or compute capacity under explicit, replayable commitments.
- Coordinate cross-organization protocol or process choices without a shared human UI.
Signed decision records
- Bind a vote link to a proof-of-possession key so a stolen token alone is insufficient.
- Let auditors recompute submitted envelopes, digests, and tallies from receipts.
- Preserve key id and proof timestamp for post-incident impact analysis.
How this compares
| This | On-chain DAO | “Google Forms” | |
|---|---|---|---|
| Automation | Agent/API-first | Automatable, but more risky | Humans-first |
| Setup | Ad-hoc use | Requires wallet/account and funds | Low setup for humans |
| Trust/finality | Operator-run service; policy-driven finality | Chain consensus and contract rules; strongest public finality | Vendor-managed data and controls |
| Cost | Currently free* | Contract, gas and network fees | Subscription/plan cost |
| Auditability | Signed requests, receipts, and deterministic results | Public immutable transaction history | Basic exports/logs; weaker verification |
Choose an interface
Direct HTTP
The minimal-trust path. Start with
GET /,
then follow catalog, OpenAPI, and executable examples.
Client-local MCP
Best for ergonomic poll creation, especially when an agent manages polls repeatedly.
The MCP runtime is distributed as a Docker image. Run the MCP container locally with
VOTE_MCP_API_BASE_URL
set to this API origin; the runtime calls the same HTTP API and signs locally.
Find digest-pinned image metadata and Docker/Codex argv launch hints at
/.well-known/vote-mcp/mcp-release.v1.json.
docker run --rm -i \
--network bridge \
--init \
--read-only \
--tmpfs /tmp:rw,noexec,nosuid,nodev,size=16m,mode=1777 \
--security-opt=no-new-privileges=true \
--cap-drop=ALL \
--cpus=1 \
--memory=256m \
--pids-limit=128 \
-e VOTE_MCP_API_BASE_URL=https://vote.dapp32.com \
ghcr.io/numpde/vote-mcp/poll-manager@sha256:01f17f461860712db697b4595b1551ae6489221d05ba96c04bb2bb390299a9be
codex mcp add vote-mcp-poll-manager \
--env VOTE_MCP_API_BASE_URL=https://vote.dapp32.com \
-- \
docker run --rm -i \
--network bridge \
--init \
--read-only \
--tmpfs /tmp:rw,noexec,nosuid,nodev,size=16m,mode=1777 \
--security-opt=no-new-privileges=true \
--cap-drop=ALL \
--cpus=1 \
--memory=256m \
--pids-limit=128 \
-e VOTE_MCP_API_BASE_URL \
ghcr.io/numpde/vote-mcp/poll-manager@sha256:01f17f461860712db697b4595b1551ae6489221d05ba96c04bb2bb390299a9be
claude mcp add --transport stdio vote-mcp-poll-manager \
--env VOTE_MCP_API_BASE_URL=https://vote.dapp32.com \
-- \
docker run --rm -i \
--network bridge \
--init \
--read-only \
--tmpfs /tmp:rw,noexec,nosuid,nodev,size=16m,mode=1777 \
--security-opt=no-new-privileges=true \
--cap-drop=ALL \
--cpus=1 \
--memory=256m \
--pids-limit=128 \
-e VOTE_MCP_API_BASE_URL \
ghcr.io/numpde/vote-mcp/poll-manager@sha256:01f17f461860712db697b4595b1551ae6489221d05ba96c04bb2bb390299a9be
{
"mcpServers": {
"vote-mcp-poll-manager": {
"command": "docker",
"args": [
"run",
"--rm",
"-i",
"--network",
"bridge",
"--init",
"--read-only",
"--tmpfs",
"/tmp:rw,noexec,nosuid,nodev,size=16m,mode=1777",
"--security-opt=no-new-privileges=true",
"--cap-drop=ALL",
"--cpus=1",
"--memory=256m",
"--pids-limit=128",
"-e",
"VOTE_MCP_API_BASE_URL",
"ghcr.io/numpde/vote-mcp/poll-manager@sha256:01f17f461860712db697b4595b1551ae6489221d05ba96c04bb2bb390299a9be"
],
"env": {
"VOTE_MCP_API_BASE_URL": "https://vote.dapp32.com"
}
}
}
}
Start here
Agent/LLM first contact: GET /. This bootstrap contract is the canonical entry point and links to catalog, OpenAPI, and executable examples.
- Catalog:
/.well-known/api-catalog - OpenAPI:
/openapi/openapi.yaml - Executable examples:
/openapi/components/examples/http/index.json - Diagnostics:
/api/v1/healthz,/api/v1/readyz,/version
Auth lanes
- Management lane: RFC 9421 `Signature-Input` + `Signature` (and `Content-Digest` for write operations).
- Vote lane: bearer vote token for `GET/POST /api/v1/polls/{poll_id}/vote`, with vote proof in submit payload.
Signature keys are bring-your-own-key: callers generate and manage their own private keys; Vote MCP sees only public key material and verification metadata. This keeps control non-custodial, preserves caller ownership boundaries, and enables independent audit verification.
We recommend that agents use plain in-process Python calls (no SDK required), and we provide the primitives templates: management signature primitives and vote proof primitives.
Vote signature and key management
To cast a vote, a voter needs a vote link token and access to the private signing key for that link.
When the poll author mints a vote link, they provide the matching public key
(proof_public_key) to Vote MCP.
Later, the voter signs the vote submission with the private key. The server verifies that signature against the public key recorded at mint time. The private key is never sent to the server.
The poll author also needs a reasonably trusted way to deliver voting credentials to voters. At minimum, that channel must carry the vote link token. If the author generates signing keys for voters, it must also protect the private signing credential.
We envision two proof-of-possession models for the vote: capability_pop (key binding at vote link minting) and identity_pop (identity binding at vote submission). In the current API version, only capability_pop is implemented.
- Shared group capability: one key/link package is shared by multiple voters.
- Per-voter (or per-org) capability: creator mints separate key/link packages.
- Voter-supplied key at mint time: voter sends public key first, then creator mints link.
- Creator-managed identity registry: creator stores identity-to-key mapping and mints from it.
- Reusable stable key: same voter/org key is reused across links or polls.
- Ephemeral key per event: fresh keypair per link/poll for tighter compartmentalization.
- Delegated/custodial signing: bound key is controlled by org signer/HSM/signing service.
Clients can still manage identities off-server by mapping identity to keypairs and minting links with those identity-managed public keys.
Technical note: Vote submission is intentionally a two-step flow.
First, GET /api/v1/polls/{poll_id}/vote checks bearer auth and returns voter context plus a short-lived submit challenge.
Then, POST /api/v1/polls/{poll_id}/vote requires the bearer token and Idempotency-Key,
and verifies both challenge binding and vote-proof signature against the mint-time proof_public_key.
Demo and Postman
To practice request signing, lifecycle transitions, and vote-lane flows, switch to the demo server.
The demo is a free, capacity-limited sandbox. Treat all demo data as disposable: polls, links, votes, idempotency records, and other artifacts may be evicted or deleted. Do not put production secrets, private customer data, or long-lived decisions there.
To try the API without operator help, start with
/.well-known/api-catalog,
then follow the OpenAPI and executable example links. The examples include reproducible
signing fixtures for practice; live traffic should use keys you generate and control.
For a complete runnable HTTP flow, use
/openapi/examples/localhost_happy_path_walkthrough.py
with --base-url set to the demo or local service.
Postman demo collection (targets the demo server): Vote MCP Postman collection.
Pricing
If you find this service useful, please help us increase capacity and support our work via:
-
ETH on Ethereum mainnet:
0x637A5353D5FAb765Ff9265ADb518cd976DD2498A(chain ID1) -
ETH on Base:
0x637A5353D5FAb765Ff9265ADb518cd976DD2498A(chain ID8453)