• 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: v322
View latest version
README.md

Inbox -

An inbox for my note taking system so that I can quickly flag things now and thoughtfully organize them later when I'm in the right headspace.

What is this?

This service is a buffer between raw sources (email, API, messages, etc) and my personal knowledge management system (an Obsidian vault).

Instead of directly processing incoming content into notes, this inbox:

  1. Receives raw information from multiple sources (email, API calls, AI chats)
  2. Stores unprocessed items temporarily with their attachments
  3. Provides a simple API for clients to retrieve and process items

This separation allows me to capture freely in the moment, then process intentionally when I'm ready. And it's client agnostic - it can all be done via MCP or http, and capture can additionally be done by email.

Ok but why?

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 setup

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

  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" ]

Architecture

Platform: Val.town Serverless

  • SQLite database via standard library
  • Blob storage for binary attachments
  • Email sending/receiving built-in
  • HTTP endpoints for API access
  • Cron scheduling for cleanup tasks

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

Making Changes

Schema Changes:

  1. Update inboxRecordSchema in server/InboxService.ts
  2. Increment table name in server/db.ts (e.g., inbox_records_2)
  3. Redeploy vals to Val.town

Adding Endpoints:

  1. Add route in server/app.ts
  2. Add auth middleware if needed
  3. Update this README

Adding MCP Tools:

  1. Create tool file in mcp/tools/
  2. Register in mcp/tools/index.ts
  3. Test with Claude Desktop

Design Philosophy

  1. Simple buffer - Not a full app, just a temporary holding area
  2. Client-side processing - Complex logic lives in clients, not here
  3. Stateless - Each record is independent
  4. Val.town native - Leverage platform features over external services
  5. Fail-fast - Let errors bubble with context

Common Workflows

Email → Claude Processing

  1. Send email with notes/attachments to Val.town address
  2. Email handler saves to inbox
  3. Ask Claude Desktop: "What's in my inbox?"
  4. Claude reads items, processes into Obsidian vault
  5. Claude marks items as processed
  6. Auto-deleted after 30 days

API → Custom Script

  1. POST content via HTTP API
  2. Poll /api/inbox endpoint
  3. Process items with your script
  4. PATCH to mark processed
  5. Auto-deleted after 30 days

License

Go nuts

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.