{
  "markdown": "# Grantd\n\nOAuth-for-agents: a dead-simple, MCP-native OAuth token broker that lets AI agents securely\nact on a user's behalf across third-party APIs (Gmail, Slack, GitHub, Notion…). Tokens are\nvaulted server-side and never touch the LLM.\n\nStack: TypeScript · Hono · Postgres · generic OAuth2 driven by a declarative provider registry ·\nenvelope encryption (AES-256-GCM, key-versioned) · Postgres advisory locks for refresh concurrency\n(no Redis). Security model and how to report issues: [SECURITY.md](SECURITY.md).\n\n## Security at a glance\n\nGrantd vaults users' OAuth tokens, so security is the product, not a feature. The fundamentals:\n\n- **Tokens encrypted at rest** — AES-256-GCM envelope encryption, fresh IV per record, key-versioned,\n  and **fail-closed** (a missing key refuses to write; it never silently stores plaintext).\n- **Tokens never reach the LLM or the caller.** The proxy injects the access token at the network\n  boundary and returns only the provider's response — the raw token is never serialized back.\n- **API keys hashed at rest** (pbkdf2-sha256, peppered); the raw `sk_` key is shown once.\n- **No SQL injection** — every query is a parameterized `postgres.js` tagged template.\n- **Tenant isolation** on every query by environment id; **Row-Level Security** enabled on all tables\n  so a Postgres REST layer (e.g. Supabase/PostgREST) can't read the vault.\n- **256-bit random** OAuth `state` + session tokens; **PKCE (S256)** where the provider supports it.\n- **Durable, Postgres-backed rate limiting** — per secret key on auth routes, per IP on public routes.\n\nThis is open-source infrastructure **you run yourself**. Self-hosting responsibilities (key custody,\nTLS, an edge/WAF for volumetric DoS) and known limitations are documented honestly in\n[SECURITY.md](SECURITY.md). If you intend to run a hosted, multi-tenant deployment that holds other\npeople's tokens, work through [HOSTED-CHECKLIST.md](HOSTED-CHECKLIST.md) first.\n\n## Providers\n\n| Provider | Status |\n|---|---|\n| Google (Gmail, Calendar, …) | ✅ Verified end-to-end, including token refresh |\n| GitHub | ✅ Verified end-to-end |\n| Slack | 🧪 Experimental — config present, not yet verified against live OAuth |\n| Notion | 🧪 Experimental — config present, not yet verified against live OAuth |\n\nAdding a provider is data, not code (see `src/providers.ts`). Help verifying Slack/Notion is welcome.\n\n## Quick start (dev)\n\n```bash\nnpm install\nnpm run keygen            # prints an ENCRYPTION_KEYRING + API_KEY_SALT\ncp .env.example .env      # then paste keygen output + your DATABASE_URL\nnpm run migrate           # apply SQL migrations\nnpm run dev               # start the broker on :8787\n```\n\n## MCP server\n\nExposes the broker to an AI agent (Claude Code / Cursor / Claude Desktop) as tools:\n`list_providers`, `check_connection`, `create_connect_link`, and `call_provider`. The\nauth-gating wedge: if the agent calls `call_provider` for a user who isn't connected, it\nreturns an `authorization_required` result with a connect link instead of failing.\n\nThe MCP server is published to npm as [`grantd-mcp`](https://www.npmjs.com/package/grantd-mcp), so\nyou don't need to clone this repo to use it — just point an MCP client at it (you do need a running\nbroker and a secret key). For local development: `npm run mcp` (needs the broker running); smoke\ntest: `npm run mcp:test`.\n\nAdd to Claude Code:\n\n```bash\nclaude mcp add grantd \\\n  --env GRANTD_API_KEY=sk_... \\\n  --env GRANTD_BASE_URL=https://your-broker.example.com \\\n  --env GRANTD_END_USER=user-123 \\\n  -- npx -y grantd-mcp\n```\n\nOr in a Cursor / Claude Desktop `mcpServers` config:\n\n```json\n{\n  \"mcpServers\": {\n    \"grantd\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"grantd-mcp\"],\n      \"env\": {\n        \"GRANTD_API_KEY\": \"sk_...\",\n        \"GRANTD_BASE_URL\": \"https://your-broker.example.com\",\n        \"GRANTD_END_USER\": \"user-123\"\n      }\n    }\n  }\n}\n```\n\n## Layout\n\n```\nmigrations/   SQL schema (Supabase/Postgres compatible)\nscripts/      keygen + migrate helpers\nsrc/\n  config.ts   env loading + validation + keyring parse\n  crypto.ts   envelope encryption + API-key hashing\n  db.ts       postgres.js client\n  providers.ts declarative provider registry (Google, GitHub, Slack, Notion)\n  oauth.ts    generic OAuth2 client (authorize / exchange / refresh) driven by the registry\n  server.ts   Hono app + routes (WIP)\n```\n",
  "bytes": 4365,
  "sha": "20715497bb09cda3ce163febca1dc588d8b21f2acd7c6159f500bbddd49c1b9c",
  "repo_slug": "rafavecchi/grantd",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_rafavecchi_grantd_27df9849/readme"
}