惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

人人都是产品经理
人人都是产品经理
美团技术团队
J
Java Code Geeks
T
The Exploit Database - CXSecurity.com
博客园 - 聂微东
T
Tor Project blog
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
P
Proofpoint News Feed
AWS News Blog
AWS News Blog
博客园_首页
S
Secure Thoughts
S
Schneier on Security
量子位
Simon Willison's Weblog
Simon Willison's Weblog
H
Help Net Security
Spread Privacy
Spread Privacy
Vercel News
Vercel News
Hugging Face - Blog
Hugging Face - Blog
M
Microsoft Research Blog - Microsoft Research
T
Tailwind CSS Blog
The Cloudflare Blog
V
V2EX - 技术
I
InfoQ
O
OpenAI News
有赞技术团队
有赞技术团队
F
Fortinet All Blogs
Google DeepMind News
Google DeepMind News
V
V2EX
Jina AI
Jina AI
Hacker News: Ask HN
Hacker News: Ask HN
F
Future of Privacy Forum
C
Comments on: Blog
Y
Y Combinator Blog
T
The Blog of Author Tim Ferriss
Blog — PlanetScale
Blog — PlanetScale
Cyberwarzone
Cyberwarzone
Project Zero
Project Zero
P
Privacy International News Feed
H
Hacker News: Front Page
Engineering at Meta
Engineering at Meta
Security Latest
Security Latest
P
Privacy & Cybersecurity Law Blog
Recent Announcements
Recent Announcements
小众软件
小众软件
The Hacker News
The Hacker News
Martin Fowler
Martin Fowler
T
Threatpost
P
Proofpoint News Feed
博客园 - 司徒正美
S
SegmentFault 最新的问题

Hacker News: Show HN

Architectural Metapatterns Show HN: VimRace Hodor — Instantly launch your prompts into any AI tool GitHub - javaid-codes/audit-supply-chain-agents Workplane — Share AI artifacts with humans and agents DEMON: Diffusion Engine for Musical Orchestrated Noise Show HN: Gochan – A library of channel architectures for Go, inspired by Rust Show HN: WatchPlane, my attempt to replace my monitoring tool stack GitHub - arifozgun/OpenGem: Free, Open-Source AI API Gateway with Gemini, OpenAI & Anthropic Compatibility Show HN: Biopetals – Run biology tuned Llama, BitTorrent-style Show HN: Bounty-Doctor – Diagnose a GitHub bounty before wasting hours on it Show HN: Approve Claude CLI prompts from the browser, phone, or tablet GridPath — Best way to build spreadsheets with AI Kibbutznik — a pulse-based direct democratic engine Show HN: CoreMCP – MCP Server for On-Prem DBs Zorilla — vibe code games with your crew Show HN: KittyHTML – Render HTML/CSS as an inline image in your terminal Show HN: Enigma – a walkthrough from Caesar ciphers to a working Enigma machine GitHub - bingud/filemat: Web-based file manager Show HN: TruthLens – Free multi-signal deepfake image detector GitHub - apexlocal-jz/claude-usage-tray: Windows system-tray app showing your Claude Code rate-limit usage at a glance. Zero deps, ~300 lines of PowerShell. Cross-IDE (works regardless of VS Code, Cursor, plain terminal). Show HN: I made an emergency page for my family. You should too Mneme HQ — Architectural Governance for AI-Assisted Development 2048 — Blitz Edition Release v0.1.2.1 · kouhxp/yapsnap GitHub - noopolis/moltnet: Self-hostable chat network for AI agents. Pre-built bridges for Claude Code, Codex, and the Claws. Rooms, DMs, history. No Slack bots, no Matrix, no glue code. Show HN: Disable Ugly Firefox Single Rounded Corner Show HN: Enju – humans, AI agents, and compute as peers on one workflow graph PolyCSS - CSS 3D Engine for the DOM Show HN: Continuity-auth – Respect-weighted rate limits for the open web GitHub - luml-ai/luml: LUML is an open-source MLOps/LLMOps platform, allowing to build and deploy AI/ML models in a matter of minutes. Show HN: Sitchy – Auto-setup any GitHub repo Show HN: Detect anti-bot, anti-agent defenses for any website InsiderTrack · Insider Trading Intelligence GitShare.ch - GitHub Repo Screenshots for Social Media Show HN: Game Boy pixel pipeline explorer 在地图上绘制 — 免费在线路线绘制和位置标记工具 Supapin - Automate your Pinterest. Grow your traffic. GitHub - mrdanielcasper/CoreTex: A UNIX-inspired, biomimetic, flat-file AI harness and knowledge engine. Show HN: Notmyfault.fyi – email alerts when GitHub, Stripe, or Vercel go down GitHub - clemg/pierre-github: Pierre's diffs.com and trees.software for Github GitHub - lyriks-io/unspaghettit: Behavior-driven AI development without prompt spaghetti. ADHD: Parallel Divergent Ideation for Coding Agents GitHub - sofumel/claude-handoff-revive: Resume Claude Code work after rate/usage/context limits without replaying the prior transcript. Auto-saves at 90%/95% usage. Plugin-installable, 10 languages. droast — Free Online Dockerfile Linter Billpal | AI bookkeeping assistant GitHub - dotexorg/erpc: Typed, end-to-end encrypted RPC over any bidirectional channel. GitHub - BeeZeeAgent/beezee: Agent harness orchestration Legato Next.js Boilerplate for Internal Tools · CoreUI Axion — Real amps in your browser Chat Hoarding: A permanent, private archive of your WhatsApp chats Show HN: I hand-write 5 daily word puzzles before work Show HN: Generate 54 social media assets in 1 click the shared workspace for human + agent teams Sotto — Your invisible interview co-pilot. GitHub - clark-labs-inc/clark-hash: Clark Hash, 32x smaller searchable sketches for embeddings TokenAdvisor — Free LLM token analyzer with savings advice GitHub - ZeroPointRepo/youtube-mcp: The fastest YouTube transcript + YouTube search MCP for AI agents. Try for free. Typing Mastery — climb toward 100+ WPM, deliberately GitHub - Andebugulin/Awareen Mirdel - Next-generation AI Workspace PikoCI — The CI/CD that grows with you Virtuoso Data Table GoPeek — open links in live mini browser windows without losing your flow. Show HN: I built a samurai-themed playable Résumé with React, Phaser, + Laravel Programming Language Job Demand Index — 2026 STAX IDE — a spatial terminal IDE for macOS Tasmap GitHub - craigmccaskill/posthorn: Self-hosted email gateway between your apps and a transactional mail provider (Postmark, Resend, Mailgun, AWS SES, or outbound-SMTP). Three ingress shapes (HTTP form, HTTP API, SMTP). One Docker container, one TOML config. Show HN: Windows 8 inspired transfer speed graph Show HN: Hyper, the self driving company brain GitHub - shubhamgoel27/artifold: 📚 A local-first library for the stuff you make with AI. Index, search, preview, share — and use your past work as the style guide for your next one. Show HN: I made a simple Keyword Research tool for app devs Mobile SSH - Android SSH client GitHub - punnerud/mpee: Offline routing, multi-vehicle VRP & street geocoding for one downloaded area — Rust engine, driven from Python or a CLI GitHub - fayzan123/claude-workflow-composer: Visual desktop app for composing multi-agent coding workflows. Drag agents, attach skills and MCPs, wire handoffs, export to .claude/ Show HN: I turned my personal website into a bash shell (with Vim) Show HN: I built a tool to auto-accept AI slop and bigtech devs loves it GitHub - Flowtriq/ftagent-lite: Lightweight open-source DDoS traffic monitor. Stdout output, no account required Permly — Notification Manager for Android GitHub - srijanpatel/arq-dashboard: A dashboard for ARQ built with FastAPI Show HN: CredWork – a simple project tracking and showcasing tool GitHub - clark-labs-inc/clark-agent: A small, typed, hookable agent loop. Provider-agnostic, sandbox-agnostic, tooling-agnostic. Battle tested on clarkchat.com GitHub - alebeck/rhymesum: Hash files into LLM-generated poems locally GitHub - bitcreed/gsd-meta-manager: TUI command center for managing multiple GSD projects from a single terminal GitHub - oeo/monkdev: A holy, minimalist CLI toolkit and MCP server designed exclusively for LLM coding agents. GitHub - xilioscient/troskji: Post-quantum multi-path tunnel — Hybrid KEM (X25519+Kyber-1024) · Shamir 3-of-5 SSS · BLAKE3 · XDP/eBPF cover traffic · Rust Introducing vtermux – M.C. Pantz Flow Simulator Show HN: Free DNS propagation checker – 40 resolvers, TTL and response times GitHub - hamsterbase/llm-translator SetupHub - Share Your IDE Setup with the World Show HN: Zt – Expose local services via Cloudflare Zero Trust in one command Mirror — Record your workflow. Generate docs in one click. GitHub - NikhilSKashyap/interviewsignal: AI-native broad-interviewing. Share a code, capture thought process, auto-grade on submit. pip install, zero setup cost, pure signal. Stumbleback - Chrome 应用商店 OACP — Open Agent Coordination Protocol GitHub - mplsllc/macsurf: A modern web browser for Classic Mac OS 9 PowerPC. Real CSS3, ES5 JavaScript, native HTTPS — built with CodeWarrior on the Carbon API. yavchn
GitHub - brooksmcmillin/mcp-authflow: OAuth 2.0 Authorization Server framework for MCP servers
bengal · 2026-05-28 · via Hacker News: Show HN

OAuth 2.0 Authorization Server framework for MCP servers. Issue and manage tokens that protect MCP tool access.

Pair with mcp-authflow-resource on the resource server side.

Features

  • Token storage with PostgreSQL and in-memory backends
  • RFC 6749 standardized OAuth error responses
  • RFC 7523 private_key_jwt client authentication with algorithm allowlist and JTI replay protection (Redis or in-memory)
  • RFC 7636 PKCE verification (S256 + plain) and input validation for the token endpoint
  • RFC 8628 Device Authorization Grant — sans-IO polling state machine and code generators
  • Sliding-window rate limiting for token endpoints
  • Input validation for client IDs and scopes
  • CORS helpers with origin allowlisting
  • Async-first design, built on Starlette

Installation

pip install mcp-authflow

# With PostgreSQL token storage (production)
pip install mcp-authflow[postgres]

Quick Start

Build an OAuth authorization server that issues tokens for MCP clients:

import secrets
import time
from contextlib import asynccontextmanager

from starlette.applications import Starlette
from starlette.requests import Request
from starlette.responses import JSONResponse
from starlette.routing import Route

from mcp_authflow.rate_limiting import SlidingWindowRateLimiter
from mcp_authflow.responses import invalid_request, rate_limit_exceeded
from mcp_authflow.storage import MemoryTokenStorage
from mcp_authflow.validation import parse_scope_field, validate_client_id

# --- Setup ---

storage = MemoryTokenStorage()  # Use PostgresTokenStorage for production
limiter = SlidingWindowRateLimiter(requests_per_window=60, window_seconds=3600)


# --- Token endpoint ---

async def token_endpoint(request: Request) -> JSONResponse:
    form = await request.form()
    client_id = str(form.get("client_id", ""))

    # Rate limit per client
    if not limiter.is_allowed(client_id):
        return rate_limit_exceeded(
            "Too many requests",
            retry_after=limiter.get_retry_after(client_id),
        )

    # Validate client
    if not validate_client_id(client_id):
        return invalid_request("Invalid client_id format")

    # Issue token
    token = secrets.token_urlsafe(32)
    scopes = parse_scope_field(form.get("scope"))
    expires_at = int(time.time()) + 3600

    await storage.store_token(
        token=token,
        client_id=client_id,
        scopes=scopes.split(),
        expires_at=expires_at,
        resource=str(form.get("resource", "")),
    )

    return JSONResponse({
        "access_token": token,
        "token_type": "bearer",
        "expires_in": 3600,
        "scope": scopes,
    })


# --- Introspection endpoint (called by resource servers) ---

async def introspect_endpoint(request: Request) -> JSONResponse:
    form = await request.form()
    token = str(form.get("token", ""))

    token_data = await storage.load_token(token)
    if not token_data or token_data["expires_at"] < time.time():
        return JSONResponse({"active": False})

    return JSONResponse({
        "active": True,
        "client_id": token_data["client_id"],
        "scope": " ".join(token_data["scopes"]),
        "exp": token_data["expires_at"],
        "aud": token_data.get("resource", ""),
    })


@asynccontextmanager
async def lifespan(app):
    await storage.initialize()
    yield
    await storage.close()


app = Starlette(
    routes=[
        Route("/token", token_endpoint, methods=["POST"]),
        Route("/introspect", introspect_endpoint, methods=["POST"]),
    ],
    lifespan=lifespan,
)

Run with: uvicorn myapp:app --port 8000

Architecture

                         MCP Client (Claude, etc.)
                                |
                  1. Authorization request
                                |
                                v
                    +---------------------+
                    |   Auth Server        |   <-- this package
                    |   (mcp-authflow)  |
                    |                     |
                    |  /token             |   2. Issues access token
                    |  /introspect        |   4. Validates token
                    +---------------------+
                                ^
                                |
                     4. Token introspection (RFC 7662)
                                |
                    +---------------------+
                    |   Resource Server    |   <-- mcp-authflow-resource
                    |   (MCP tools)       |
                    |                     |
                    |  3. Client calls    |
                    |     MCP tools with  |
                    |     Bearer token    |
                    +---------------------+
  1. MCP client authenticates with the auth server
  2. Auth server issues an access token (stored in PostgreSQL or memory)
  3. Client calls MCP tools on the resource server with the Bearer token
  4. Resource server validates the token by calling the auth server's /introspect endpoint

API Reference

Token Storage

Abstract base class with two implementations:

from mcp_authflow.storage import MemoryTokenStorage, PostgresTokenStorage

# In-memory (development/testing)
storage = MemoryTokenStorage()

# PostgreSQL (production) -- requires `postgres` extra
storage = PostgresTokenStorage(database_url="postgresql://user:pass@host/db")
# Or reads DATABASE_URL env var if no argument provided
storage = PostgresTokenStorage()

await storage.initialize()  # Open the connection pool (in-memory needs no setup)

PostgresTokenStorage does not create or migrate its schema — it expects the tables to already exist, so you stay in control of migrations. Apply this DDL (e.g. via your migration tool) before first use:

CREATE TABLE IF NOT EXISTS mcp_access_tokens (
    token       TEXT PRIMARY KEY,
    client_id   TEXT NOT NULL,
    scopes      TEXT NOT NULL DEFAULT '',
    resource    TEXT,
    expires_at  TIMESTAMPTZ NOT NULL,
    created_at  TIMESTAMPTZ NOT NULL DEFAULT now(),
    user_id     INTEGER
);

-- Only needed if you use the refresh-token methods.
CREATE TABLE IF NOT EXISTS mcp_refresh_tokens (
    token       TEXT PRIMARY KEY,
    client_id   TEXT NOT NULL,
    scopes      TEXT NOT NULL DEFAULT '',
    resource    TEXT,
    expires_at  TIMESTAMPTZ NOT NULL,
    created_at  TIMESTAMPTZ NOT NULL DEFAULT now(),
    user_id     INTEGER
);

Storage interface:

Method Description
store_token(token, client_id, scopes, expires_at, resource?, user_id?) Store an access token
load_token(token) -> dict | None Look up a token
delete_token(token) Revoke a token
cleanup_expired_tokens() -> int Purge expired tokens, returns count
get_token_count() -> int Count active tokens
store_refresh_token(...) Store a refresh token (same interface)
load_refresh_token(token) -> dict | None Look up a refresh token
delete_refresh_token(token) Revoke a refresh token
cleanup_expired_refresh_tokens() -> int Purge expired refresh tokens, returns count

Token data returned by load_token():

{
    "token": str,
    "client_id": str,
    "scopes": list[str],
    "resource": str | None,       # RFC 8707 resource binding
    "expires_at": int,            # Unix timestamp
    "created_at": int,            # Unix timestamp
    "user_id": int | None,
}

OAuth Error Responses

Standardized error helpers following RFC 6749:

from mcp_authflow.responses import (
    invalid_request,       # 400 - Missing/invalid parameters
    invalid_client,        # 401 - Authentication failure
    invalid_grant,         # 400 - Expired/invalid code or token
    invalid_scope,         # 400 - Scope violation
    slow_down,             # 400 - Device flow rate limiting
    rate_limit_exceeded,   # 429 - Too many requests
    server_error,          # 500 - Internal error
    backend_timeout,       # 504 - Upstream timeout
)

Each returns a Starlette JSONResponse with the appropriate status code and Cache-Control: no-store header.

Rate Limiting

from mcp_authflow.rate_limiting import SlidingWindowRateLimiter

limiter = SlidingWindowRateLimiter(
    requests_per_window=60,   # Max requests per window
    window_seconds=3600,      # Window duration (1 hour)
)

if not limiter.is_allowed(client_id):
    retry_after = limiter.get_retry_after(client_id)  # Seconds until next allowed request

Input Validation

from mcp_authflow.validation import validate_client_id, parse_scope_field

validate_client_id("my-client-123")  # True (alphanumeric + hyphens/underscores)
validate_client_id("")               # False

parse_scope_field("read write")      # "read write"
parse_scope_field(["read", "write"]) # "read write"
parse_scope_field(None)              # "read" (default)

CORS

from mcp_authflow.cors import parse_allowed_origins, build_cors_headers

# Reads ALLOWED_MCP_ORIGINS env var (comma-separated)
origins = parse_allowed_origins()

# Returns CORS headers if request origin is in allowlist
headers = build_cors_headers(request, origins)

Configuration

Env Variable Description Default
DATABASE_URL PostgreSQL connection string (for PostgresTokenStorage) Required for postgres
ALLOWED_MCP_ORIGINS Comma-separated allowed CORS origins Empty (no CORS)

License

MIT