Stash
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Stashsearch my bookmarks for MCP"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Stash
Stash is a Next.js App Router application with first-party email/password authentication, stateless Auth.js sessions, Prisma/PostgreSQL persistence, transactional email through Resend, and authenticated bookmark tools over Model Context Protocol (MCP).
Local setup
Install dependencies with
pnpm install.Copy
.env.exampleto.envand replace every placeholder. Never commit.env.Generate
AUTH_SECRETwithpnpm exec auth secret(or another cryptographically secure generator).Set
APP_URLto the trusted public origin, normallyhttp://localhost:3000locally. Production must use HTTPS.Configure
EMAIL_FROMwith a sender on a domain verified in Resend.Set
MCP_AUTH_ISSUERto the exact trusted OAuth authorization-server issuer. Local development may use loopback HTTP; production issuers must use HTTPS and may not contain a query or fragment.Apply migrations with
pnpm prisma migrate dev. The committed migrations create the authentication and bookmark tables.Create a Vercel AI Gateway key, set
AI_GATEWAY_API_KEY, and setAI_MODELto a Gateway model that supports tool calls (the example usesopenai/gpt-5.4-mini).Start the application with
pnpm dev.
The server validates DATABASE_URL, RESEND_API_KEY, AUTH_SECRET, APP_URL, MCP_AUTH_ISSUER, EMAIL_FROM, AI_GATEWAY_API_KEY, and AI_MODEL at their first relevant use and reports invalid variable names without printing their values.
Related MCP server: bookmark-mcp
Authentication behavior
/signupcreates a credentials user, sends a best-effort welcome email, and signs the user in./logincreates a seven-day encrypted, HTTP-only Auth.js cookie session./forgot-passwordalways returns an account-enumeration-resistant response for valid email syntax./reset-passwordconsumes a SHA-256-hashed, 60-minute, single-use token and revokes older sessions by incrementing the user's session version./authorizes against the current database record through the DAL before rendering.
lib/rate-limit.ts is the extension point for a future shared IP/email limiter. The database-backed 60-second per-account cooldown is not a complete production abuse-control system by itself.
Bookmarks MCP
The MCP endpoint is stateless Streamable HTTP at POST /api/mcp. It serves the current protocol and the SDK's stateless 2025 compatibility handshake for desktop clients; it does not expose the legacy two-endpoint SSE transport. Its canonical RFC 8707 resource identifier and access-token audience are always ${APP_URL}/api/mcp. Public RFC 9728 discovery is available at /.well-known/oauth-protected-resource/api/mcp; Stash does not serve authorization, token, registration, revocation, or JWKS endpoints.
The endpoint exposes exactly four tools:
add_bookmarkanddelete_bookmarkrequirebookmarks:write.list_bookmarksandsearch_bookmarksrequirebookmarks:read.
Same-origin Stash clients may use their Auth.js cookie and receive both capabilities. Remote native, desktop, and server clients send a bearer access token on every request. Browser cross-origin MCP calls are intentionally unsupported. A 401 challenge points clients to the protected-resource document; a 403 insufficient_scope challenge identifies the exact scope needed for bounded OAuth step-up.
Stash is only an OAuth 2.1 protected resource. The separately operated authorization server must support authorization code with PKCE S256, Resource Indicators for the exact canonical MCP URI, and authorization-response issuer identification. It must publish validated RFC 8414 or OpenID discovery metadata, a jwks_uri, and access_token_signing_alg_values_supported containing an allowed asymmetric algorithm (RS256 or ES256).
Access tokens must be short-lived JWT access tokens with protected-header typ: at+jwt and a kid. Required claims are exact iss, exact single-resource aud, local Stash user ID in sub, exp, iat, space-delimited scope, client_id (or azp), and integer stash_session_version. The authorization server must mint that version from the current Stash user row and keep token lifetime at or below 60 minutes. It must never put email addresses in sub or expect Stash to provision users from tokens.
For local remote-client testing, configure a loopback authorization server, set MCP_AUTH_ISSUER to its issuer, pre-register the client (or use a Client ID Metadata Document), request the exact ${APP_URL}/api/mcp resource plus the least bookmark scopes, and send only the resulting access token to Stash. Refresh tokens go only to the authorization server.
Local authorization server for AI clients
Stash includes a development-only loopback authorization server. It signs short-lived access tokens, authenticates against the existing Stash users table, binds tokens to the user's current session_version, and keeps authorization codes and refresh tokens only in memory. Its signing key and all grants are discarded when the process stops.
Use the local values from
.env.example:APP_URL=http://localhost:3000,MCP_AUTH_ISSUER=http://localhost:4000, and the identicalLOCAL_AUTH_ISSUER=http://localhost:4000. Keep the issuer string exactly identical, including any trailing slash.Apply the database migrations and create a Stash account through
/signupif you do not already have one.In one terminal, run Stash with
pnpm dev. In a second terminal, run the authorization server withpnpm dev:auth.Configure the AI client with the MCP server URL
http://localhost:3000/api/mcp. A conforming client follows Stash's 401 challenge and discovers the authorization server automatically.At the local consent page, sign in with the same Stash email and password and approve the requested scopes.
Ask for bookmarks:read when the client only needs to list or search. Add bookmarks:write only when it needs to add or delete. The authorization and token requests must both contain the exact resource=http://localhost:3000/api/mcp; the local server rejects missing, altered, or additional resource values.
Public clients can be pre-registered in .env as JSON (there is no client secret):
LOCAL_AUTH_CLIENTS_JSON='[{"client_id":"my-ai-client","client_name":"My AI client","redirect_uris":["http://127.0.0.1:8765/oauth/callback"],"token_endpoint_auth_method":"none"}]'The server also accepts an HTTPS (or loopback HTTP) Client ID Metadata Document URL as client_id. Pre-registration and metadata documents are the default. For a legacy client that still requires dynamic client registration, set LOCAL_AUTH_ALLOW_DCR=true to advertise a local /register compatibility endpoint. Restarting the server clears dynamically registered clients, so reconnect or clear that client's cached OAuth registration after a restart.
The token endpoint supports authorization code with PKCE S256 and rotating refresh tokens. AI clients send access tokens only to http://localhost:3000/api/mcp; they send authorization codes and refresh tokens only to http://localhost:4000/token. The local server is intentionally bound to 127.0.0.1, uses ephemeral keys and in-memory grants, and must not be deployed or exposed to a network. For a client running in a VM or container, use a deliberate host bridge and TLS-capable development authorization server instead of changing this server to listen publicly.
AI chat
The authenticated home page is an ephemeral, streaming chat powered by Vercel AI SDK and AI Gateway. The browser sends AI SDK UI messages to POST /api/chat; that server route authenticates the user, opens a request-scoped Streamable HTTP connection to the canonical ${APP_URL}/api/mcp endpoint, and loads only the four schema-bound bookmark tools.
The assistant can add, list, search, and delete bookmarks. Delete calls use signed AI SDK approval requests and never reach MCP until the user explicitly approves the exact operation. The model is limited to six tool/model steps and the route enforces same-origin checks, a 256 KiB body limit, message/text bounds, safe public errors, no-store responses, and content-free operational logs.
Conversation messages are kept only in browser memory. Refreshing or choosing New chat clears the conversation but does not undo bookmark changes. Stop cancels the active provider request; stream resumption is intentionally disabled. checkChatRateLimit() in lib/rate-limit.ts is the extension point for a production shared request, concurrency, and token limiter.
Normal automated tests mock the model and MCP client and do not spend Gateway tokens. A manual live smoke test requires a non-production Gateway key and isolated user data: sign in, list bookmarks, add one, request deletion, confirm it remains before approval, then approve or deny the operation.
Email development
Automated tests mock Resend and never call its API. To preview templates without sending mail, render the exported React components in emails/ with a local React email preview tool or a private development-only harness. Do not add a public /api/send endpoint. For end-to-end email tests, use a separate Resend test key/sender and inbox; never use production recipients.
Verification
pnpm prisma format
pnpm prisma validate
pnpm prisma generate
pnpm lint
pnpm test
pnpm buildDatabase integration tests require an isolated TEST_DATABASE_URL. Browser tests require isolated test configuration and run with pnpm test:e2e. Never point either suite at a developer or production database, and never reset a database without explicit approval.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.
No tool schema history has been recorded yet.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Search, label, and manage your X (Twitter) bookmarks from any MCP client via Tweetsmash
Search and save to your Purl read-it-later knowledge base from any MCP client.
Create, list, and complete todo items through MCP.
Create, schedule, and publish social posts, manage accounts, and read analytics as MCP tools.
Related MCP Servers
- AlicenseNot gradedqualityBmaintenanceManage Safari bookmarks through an MCP server, providing tools to list, search, add, remove, and organize bookmarks and folders.Apache 2.0
- FlicenseAqualityDmaintenanceA bookmark management MCP server that enables saving, searching, and managing bookmarks with tags and read/unread status, providing tools, resources, and prompts for integration.4-
- AlicenseAqualityAmaintenanceManages Chrome's synced bookmarks through an MCP server and Chrome extension, enabling operations like listing, searching, adding, moving, and deduplicating bookmarks.17MIT
- AlicenseBqualityCmaintenanceEnables management of Raindrop.io bookmarks, collections, tags, and highlights via MCP tools, with support for search, bulk editing, and library auditing.17MIT
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/roguebot13/stash'
If you have feedback or need assistance with the MCP directory API, please join our Discord server