nostr-mcp-auth
A Nostr-based authentication gate for MCP servers that requires agents to sign HTTP requests with a Nostr key, verifying signatures offline to secure tool access.
README
nostr-mcp-auth
Lock MCP tools to a Nostr key
No proof, no tools. Agents sign every HTTP call with a Nostr secret. The server checks the signature offline. Wrong key, bad sig, stale event, or body swap: 401. Tool code never runs.
pip install -e .
nostr-mcp-auth quickstart
nostr-mcp-auth serve
# other terminal:
nostr-mcp-auth call --tool whoami
Crypto identity for agent tool access. No OAuth dance required for the lab or fleet path.
What is Nostr?
Nostr is a simple open protocol for signed messages. Each user (or agent) has:
| Piece | What it is |
|---|---|
| nsec | Private key. Signs. Keep offline / in a vault. |
| npub | Public key. Identity. Safe to put on an allowlist. |
Messages (events) are JSON objects with a BIP-340 Schnorr signature. Anyone can verify who signed without a central account server.
Common uses: social apps, relays, Lightning wallet connect. The part we care about for MCP is pure crypto identity: prove key possession.
You do not need Damus, a public relay, or a social profile for this package. Verification is local.
NIP-98 (HTTP auth)
NIP-98 defines how to authorize an HTTP request with a short-lived signed event:
- Kind 27235
- Tags bind the request: URL (
u), method (method), optional body hash (payload) - Header:
Authorization: Nostr <base64-encoded event>
That is the protocol. This repo turns it into a gate in front of MCP tools.
How we use Nostr for MCP
MCP (Model Context Protocol) is how agents call tools over stdio or HTTP. Network MCP needs auth. We put NIP-98 on POST /mcp.
| Step | What happens |
|---|---|
| 1 | Agent (or sidecar) builds a NIP-98 event for this exact URL, method, and body. |
| 2 | Signs with nsec. |
| 3 | Sends JSON-RPC (tools/list / tools/call) plus Authorization: Nostr …. |
| 4 | Server verifies: kind, signature, time window, URL/method match, body hash, allowlist, optional roles, replay. |
| 5 | Only then does the tool run. |
Agent / sidecar MCP server (this package)
| |
| POST /mcp |
| Authorization: Nostr <signed event> |
| tools/call { name, arguments } |
|----------------------------------------->|
| | verify NIP-98 (offline)
| | allowlist + roles
| | run tool OR 401/403
|<-----------------------------------------|
What we take from Nostr
- Keypair identity (
npub/nsec) - Event shape + Schnorr signatures
- NIP-98 request binding
What we do not need
- Public relays for auth
- Social graph, follows, or notes
- Publishing the auth event anywhere
What we add
- Fail-closed HTTP MCP surface (
tools/list,tools/call) - Allow / deny lists and optional tool roles
- Process-local replay defense
- Operator CLI:
quickstart,serve,call,doctor - Red-team tested gate (see
docs/)
Plug in
Install
git clone https://github.com/SamsonCyber/nostr-mcp-auth.git
cd nostr-mcp-auth
pip install -e .
Bootstrap
nostr-mcp-auth quickstart
| File | Purpose |
|---|---|
caller.nsec |
Agent secret (never commit) |
caller.npub |
Public identity |
mcp-auth.yaml |
Server config; npub already allowlisted |
Serve
nostr-mcp-auth serve
# http://127.0.0.1:8787/mcp
# http://127.0.0.1:8787/health (public)
serve refuses auth.open=true and auth.trust_proxy=true unless you pass
--force-open or --force-trust-proxy (lab / reverse-proxy only).
Call
nostr-mcp-auth call --tool whoami
nostr-mcp-auth call --tool protected_echo --arg text=hello
nostr-mcp-auth list-tools
nostr-mcp-auth doctor
Python
from nostr_mcp_auth.client import call_tool
print(call_tool("http://127.0.0.1:8787/mcp", "caller.nsec", "whoami"))
See examples/python_agent.py.
Agent UIs that cannot sign (Claude Desktop, etc.)
Most hosts do not implement NIP-98. Options:
- Local signing sidecar that holds
nsecand forwards signed HTTP. - Keep high-risk tools on this HTTP gate; use stdio only where local trust is enough.
Unsigned or plain Bearer clients get 401. That is the gate doing its job.
Endpoints and demo tools
| Path | Auth |
|---|---|
GET /health |
Public |
GET /ready |
Public |
POST /mcp |
Required |
| Tool | Access |
|---|---|
whoami |
Allowlisted identity |
protected_echo |
Allowlisted identity |
admin_ping |
Role tools:admin |
Wire real tools behind the same pattern, or terminate network MCP at this process.
Fail-closed checks
| Check | Result |
|---|---|
| Missing / wrong auth | 401, no tool side effects |
| Bad signature / wrong kind | 401 |
| Clock skew outside window | 401 |
| URL or method mismatch | 401 |
| Body hash mismatch | 401 |
| Empty allowlist | 401 for everyone |
| Deny list | Wins over allow |
| Replay (same event id) | 401 (process-local) |
| Missing tool role | 403 |
| Auth failure body | Generic unauthorized (no fine reason oracle) |
| MCP responses | Cache-Control: no-store (not shared-cacheable) |
Defaults: open: false, trust_proxy: false. Auth logs never print nsec or full
Authorization tokens. Multi-instance shared replay and stolen allowlisted nsec
remain residual (see residual risks).
More: SPEC · residual risks · red-team · wave 2
Config
auth:
open: false
allow_npubs:
- npub1...
roles:
npub1...: [tools:admin]
tools:
admin_ping:
roles: [tools:admin]
server:
host: 127.0.0.1
port: 8787
Add agents by generating keys and appending npubs. Example: examples/mcp-auth.example.yaml.
CLI
| Command | Job |
|---|---|
quickstart |
Identity + config |
serve |
Authenticated MCP HTTP (--force-open / --force-trust-proxy if needed) |
call / list-tools |
Signed client |
doctor |
Config + nsec + allowlist check |
gen-key / init |
Manual pieces |
Dev
pip install -e ".[dev]"
pytest -q
Python 3.10+. Uses coincurve for BIP-340.
License
MIT
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.