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

Obsidian Inbox

A temporary inbox for raw information before it's processed into an Obsidian vault.

What is this?

This service acts as a buffer between various information sources (email, HTTP) and your Obsidian vault. Instead of directly processing incoming content into notes, this inbox:

  1. Receives raw information from multiple sources (email, API calls)
  2. Stores unprocessed items temporarily with their attachments
  3. Provides a simple API for clients to retrieve and process items
  4. Manages the lifecycle: unprocessed → processed → auto-deleted after 30 days

This separation allows for flexible processing workflows using different clients (Claude Desktop via MCP, custom scripts, etc.).

Quick Start

Prerequisites

  • A Val.town account (free tier works)
  • Deno runtime installed locally (for MCP server)

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
    • INCOMING_EMAIL_ALLOWLIST - Comma-separated email addresses allowed to send
  4. Set up MCP Server (for Claude Desktop integration)

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

    { "mcpServers": { "obsidian-inbox": { "command": "deno", "args": [ "run", "--allow-net", "--allow-env", "/path/to/obsidian-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

This project runs on Val.town, a Deno-based serverless platform that provides:

  • 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

Components

┌─────────────────┐
│  Email Sources  │
└────────┬────────┘
         │
         v
    ┌────────────────┐
    │ emailHandler   │──┐
    └────────────────┘  │
                        │
┌─────────────────┐     │    ┌──────────────────┐
│  HTTP/API       │────>├───>│  InboxService    │
│  Sources        │     │    │  (SQLite)        │
└─────────────────┘     │    └──────────────────┘
                        │
    ┌────────────────┐  │    ┌──────────────────┐
    │ httpHandler    │──┘    │ AttachmentService│
    │ (Hono API)     │<──────│ (Blob Storage)   │
    └────────┬───────┘       └──────────────────┘
             │
             v
    ┌────────────────┐
    │  MCP Server    │───> Claude Desktop
    │  (Local)       │
    └────────────────┘
    ┌────────────────┐
    │ Custom Clients │───> Your Scripts
    └────────────────┘

File Organization

obsidian-inbox/
├── server/                    # Core server logic
│   ├── app.ts                # Hono HTTP app with routes
│   ├── InboxService.ts       # SQLite persistence layer
│   ├── AttachmentService.ts  # Blob storage for files
│   ├── auth.ts               # Bearer token & email allowlist
│   └── db.ts                 # Drizzle ORM schema
│
├── mcp/                      # Model Context Protocol server
│   ├── server.ts             # MCP server setup
│   └── tools/                # MCP tool implementations
│       ├── readInbox.ts
│       ├── addRecord.ts
│       ├── markRecordProcessed.ts
│       ├── getRecordAttachments.ts
│       └── downloadRecordAttachment.ts
│
├── 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 (except GET /).

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

Data Schema

InboxRecord:

{ raw: string, // Full text content summary?: string, // Optional summary from?: string, // Source (email address, etc.) subject?: string, // Subject/title date?: Date, // When received attachmentBlobIds: string[] // Blob storage keys }

Stored with metadata:

  • id - UUID primary key
  • created_at - Timestamp when saved
  • processed_at - Null until marked processed

Development

Local Testing

The MCP server can run locally and connect to your deployed Val.town service:

# Set environment variables export INBOX_API_URL="https://your-val.web.val.run" export INBOX_API_TOKEN="your-token" # Run MCP server deno run --allow-net --allow-env localMcpServer.ts

Val.town Development

Edit vals directly in the Val.town web interface. Key points:

  • No test suite - test manually via web interface
  • No migrations - change table names instead (inbox_records → inbox_records_2)
  • Deno imports - use https://esm.sh/package for npm packages
  • Platform stdlib - use https://esm.town/v/std/ for Val.town features

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

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

Troubleshooting

Emails not appearing:

  • Check sender is in INCOMING_EMAIL_ALLOWLIST
  • Verify email was sent to correct Val.town address
  • Check Val.town logs for errors

MCP connection fails:

  • Verify INBOX_API_URL and INBOX_API_TOKEN in config
  • Check Deno is installed and in PATH
  • Restart Claude Desktop after config changes

401 Unauthorized:

  • Check Authorization: Bearer TOKEN header is set
  • Verify token matches INBOX_API_TOKEN in Val.town secrets

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.