• Blog
  • Docs
  • Pricing
  • We’re hiring!
Log inSign up
drewmcdonald

drewmcdonald

inbox

Public
Like
inbox
Home
Code
13
mcp
2
server
5
.vtignore
CLAUDE.md
PROJECT.md
README.md
apiClient.ts
C
cleanupCron.ts
deno.json
E
emailHandler.ts
H
httpHandler.ts
localMcpServer.ts
onetimeSetup.ts
Branches
1
Pull requests
Remixes
History
Environment variables
2
Val Town is a collaborative website to build and scale JavaScript apps.
Deploy APIs, crons, & store data – all from the browser, and deployed in milliseconds.
Sign up now
Code
/
README.md
Code
/
README.md
Search
10/21/2025
Viewing readonly version of main branch: v325
View latest version
README.md

POP Inbox

An POP-like inbox for my note taking system. Rather than pushing things directly into my notes, I hold them here until I'm ready to thoughtfully engage with them. This separation allows me to capture freely in the moment, then process intentionally when I'm ready.

Ok, but why?

When I yeet raw information into my vault, I don't get any benefit from it. This POP-like approach forces me to engage with things before storing them more permanently.

Also, more technically, Obsidian doesn't have a push-friendly API - you can't just send data to your vault from anywhere. Instead, you have to pull data into the vault from a client. Doing so requires a unified receptacle, that's this val!

Quick Start

See CLAUDE.md for AI assistant guidelines and PROJECT.md for detailed architecture.

Setup

  1. Remix on Val.town

  2. Run one-time database setup

    Run the one-time setup script to create the database table in your val.town sqlite database

  3. Configure Environment Variables

    In val.town, set these secrets:

    • INBOX_API_TOKEN - Create a secure random token for API auth (via e.g. openssl rand -hex 32)
    • INCOMING_EMAIL_ALLOWLIST - Comma-separated email addresses allowed to send records to the inbox (e.g. name@gmail.com,name@work.org)
  4. Set up MCP Server (for Claude Desktop integration)

    Create ~/Library/Application Support/Claude/claude_desktop_config.json:

    { "mcpServers": { "inbox": { "command": "deno", "args": [ "run", "--allow-net", "--allow-env", "/path/to/inbox/localMcpServer.ts" ], "env": { "INBOX_API_URL": "https://your-username-httphandler.web.val.run", "INBOX_API_TOKEN": "your-api-token" } } } }

    Alternatively, use the published val URL:

    "command": "deno", "args": [ "run", "--allow-net", "--allow-env", "https://esm.town/v/your-username/inbox/localMcpServer.ts" ]

File Organization

obsidian-inbox/
├── server/            # Core http server logic
├── mcp/               # Model Context Protocol server
├── emailHandler.ts    # Val.town email trigger
├── httpHandler.ts     # Val.town HTTP endpoint
├── cleanupCron.ts     # Val.town cron job
├── localMcpServer.ts  # Entry point for local MCP
└── apiClient.ts       # HTTP client (used by MCP)

Usage

Sending Content to Inbox

Via Email: Send email to your Val.town email address from an allowlisted sender. The email body and attachments are automatically saved.

Via HTTP API:

curl -X POST https://your-val.web.val.run/api/record \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "raw": "Content to process later", "subject": "Meeting notes", "from": "manual-entry", "date": "2025-10-21T10:00:00Z", "attachmentBlobIds": [] }'

Processing Inbox Items

With Claude Desktop (MCP): In Claude Desktop, ask:

  • "What's in my inbox?"
  • "Download the attachments from inbox item XYZ"
  • "Mark inbox item ABC as processed"

With Custom Scripts:

# Get unprocessed items curl https://your-val.web.val.run/api/inbox \ -H "Authorization: Bearer YOUR_TOKEN" # Mark item as processed curl -X PATCH https://your-val.web.val.run/api/record/{id}/processed \ -H "Authorization: Bearer YOUR_TOKEN"

API Reference

All endpoints require Authorization: Bearer YOUR_TOKEN header.

Endpoints

MethodPathDescription
GET/Health check (no auth required)
GET/api/inboxRetrieve all unprocessed records
POST/api/recordCreate new inbox record
PATCH/api/record/:id/processedMark record as processed
GET/api/record/:recordId/attachmentsGet attachment metadata
GET/api/record/:recordId/attachments/:blobIdDownload attachment file

License

Go nuts, but know this was largely vibe-coded

FeaturesVersion controlCode intelligenceCLIMCP
Use cases
TeamsAI agentsSlackGTM
DocsShowcaseTemplatesNewestTrendingAPI examplesNPM packages
PricingNewsletterBlogAboutCareers
We’re hiring!
Brandhi@val.townStatus
X (Twitter)
Discord community
GitHub discussions
YouTube channel
Bluesky
Open Source Pledge
Terms of usePrivacy policyAbuse contact
© 2026 Val Town, Inc.