Foto MCP Server
Enables migration of posts from an Instagram HTML data export into Foto, including stripping hashtags, mapping content to curated Foto tags, scrubbing GPS data, deduplicating against existing Foto posts, and supporting dry-run validation.
Click on "Deploy 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., "@Foto MCP Server inspect ~/Pictures/IMG_2042.jpg, suggest tags, and publish it to my Foto feed"
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.
Foto MCP Server (foto_mcp)
An official Model Context Protocol (MCP) server for Foto (fotoapp.co / the.fotoapp.co), the photography-first social platform.
This MCP server equips AI assistants (Claude Desktop, Cursor, Zed, Windsurf, and custom agent runtimes) to seamlessly inspect local photos, extract camera EXIF metadata, select from Foto's official curated taxonomy, and publish single frames, multi-image series, or Instagram migrations directly to your chronological Foto feed.
Architecture Overview
flowchart TD
Client["AI Assistant / MCP Client<br>(Claude Desktop, Cursor, Zed, Windsurf)"]
subgraph Foto_MCP ["Foto MCP Server (foto_mcp)"]
Tools["11 Native MCP Tools<br>& Resources / Prompts"]
Proc["Sharp & Exifr Media Pipeline<br>• Max 1820px Zero-Crop<br>• Strips GPS & Thumbnails<br>• Extracts Camera & Lens EXIF"]
Auth["Firebase REST Auth<br>• Local Token Cache (chmod 0600)<br>• Auto Token Refresh (60s buffer)"]
Sync["Instagram Migration Engine<br>• Cleans Hashtags<br>• Maps Curated Tags<br>• Deduplicates Posts"]
end
subgraph Foto_Cloud ["Foto Cloud Infrastructure (foto-d963e)"]
Storage["Firebase Storage<br>posts/{userId}/{imageId}_{ts}"]
Sightengine["Sightengine Moderation<br>nudity-2.1 Check"]
Firestore["Cloud Firestore<br>• posts/{postId}<br>• image-private-metadata/{id}<br>• user-profiles/{userId}<br>• tag_index/{tag}_{shard}"]
end
Client <-->|"Stdio Transport (JSON-RPC)"| Tools
Tools --> Proc
Tools --> Auth
Tools --> Sync
Proc --> Storage
Storage --> Sightengine
Sightengine --> FirestoreRelated MCP server: woof
Core Features & Platform Philosophy
Zero-Crop Resolution Normalization: Automatically scales high-resolution camera exports to Foto's 1820px longest-edge standard (JPEG quality 80) while preserving the creator's exact original aspect ratio (3:2, 4:3, 1:1, 6:7, 65:24 panoramic, or 16:9). No forced cropping.
Privacy by Design (GPS Scrubbing): Automatically strips embedded GPS coordinates and thumbnail IFDs from binary files before upload to prevent wildlife and location tracking.
Technical EXIF Preservation: Parses camera body, lens model, ISO, aperture ($f$-number), shutter speed, and focal length into Foto's
image-private-metadatasystem so technical details are preserved for photography enthusiasts.Curated 303 Tag Taxonomy: Strictly enforces Foto's platform rule of 1 to 3 tags selected exclusively from the official whitelist of 303 curated photographic tags. Completely eliminates hashtag spam.
Smart AI Tag Suggester: Analyzes narrative descriptions, gear notes, or film stocks (e.g.
Hasselblad 500C/M,Kodak Portra 400,Street) and recommends the best matching tags.Multi-Image Series (Stories): Authors and publishes sequential multi-photo stories (2 to 5 images per post).
Automated Content Moderation: Automatically validates uploads against platform community safety rules and Sightengine moderation (
sexual_activity <= 0.7,sexual_display <= 0.9).Dry-Run Validation: Test image geometry, EXIF extraction, and tag formatting locally without modifying your account or making live network calls (
dryRun: true).Instagram Migration Engine (
foto_sync_instagram): Seamlessly extracts posts from Instagram data exports, cleans out hashtag noise, strips GPS, suggests curated tags, and checks against already-published Foto posts.
Quick Start via npx (No Installation Required)
You can run foto_mcp directly without cloning or building locally:
npx -y github:thesven/foto_mcp#v1.0.0Client Configuration
Claude Desktop
Add this to your Claude Desktop configuration file:
macOS:
~/Library/Application Support/Claude/claude_desktop_config.jsonWindows:
%APPDATA%\Claude\claude_desktop_config.jsonLinux:
~/.config/Claude/claude_desktop_config.json
{
"mcpServers": {
"foto": {
"command": "npx",
"args": ["-y", "github:thesven/foto_mcp#v1.0.0"],
"env": {
"FOTO_EMAIL": "your_email@example.com",
"FOTO_PASSWORD": "your_password"
}
}
}
}Cursor
Add to .cursor/mcp.json or your Global Cursor MCP settings:
{
"mcpServers": {
"foto": {
"command": "npx",
"args": ["-y", "github:thesven/foto_mcp#v1.0.0"]
}
}
}Zed Editor
Add to ~/.config/zed/settings.json:
{
"experimental.model_context_protocol": {
"servers": {
"foto": {
"command": "npx",
"args": ["-y", "github:thesven/foto_mcp#v1.0.0"]
}
}
}
}Windsurf / Codeium
Add to ~/.codeium/windsurf/mcp_config.json:
{
"mcpServers": {
"foto": {
"command": "npx",
"args": ["-y", "github:thesven/foto_mcp#v1.0.0"]
}
}
}Authentication & Credentials Security
Foto MCP supports two flexible authentication mechanisms:
Option 1: In-Chat via foto_login (Recommended)
Prompt your AI assistant in chat:
"Log in to my Foto account with email
you@example.comand passwordyour_password."
The foto_login tool:
Connects directly to Google Identity Toolkit REST endpoints.
Securely caches session tokens locally in
~/.config/foto-mcp/credentials.jsonwith user-only permissions (0600).Automatically refreshes expired tokens in the background before subsequent tool calls.
Option 2: Environment Variables
For automated runtimes, provide credentials in your environment:
export FOTO_EMAIL="you@example.com"
export FOTO_PASSWORD="your_password"Complete MCP Tool Suite (11 Tools)
Tool | Purpose | Key Arguments |
| Inspects active session, local token validity, and remaining minutes. | None |
| In-chat authentication via email and password; caches tokens locally. |
|
| Clears local cached session tokens and in-memory credentials. | None |
| Inspects local image: returns dimensions, photographic aspect ratio (e.g. 3:2, 6:7), GPS status, and camera/lens EXIF. |
|
| Suggests 1 to 3 valid tags from the 303 curated tags list based on caption, gear notes, or keywords. |
|
| Searches the 303 curated tags whitelist by prefix or keyword. |
|
| Validates a post draft before publishing: checks tag whitelist, calculates downsampled dimensions, and reviews EXIF summary. |
|
| Normalizes image (1820px), scrubs GPS, uploads to Storage, passes Sightengine moderation, and creates public Firestore post. |
|
| Publishes a multi-image sequential Series (2 to 5 photos) under one post. |
|
| Retrieves current user's profile info, bio, and published post stats. | None |
| Migrates posts from an Instagram HTML export: strips hashtags, maps curated tags, scrubs GPS, and checks against published posts. |
|
MCP Resources & Prompts
Resources
foto://curated-tags: Exposes the complete JSON array of all 303 curated tags permitted on Foto. AI clients can read and cache this resource to ensure autocomplete and zero invalid tag errors.
Prompts
curate_foto_post: A structured prompt template guiding the model to inspect EXIF metadata, select canonical tags, formulate a caption focusing on narrative rather than hashtag spam, and preview drafts withfoto_draft_post.
Example Usage with an AI Agent
1. Inspecting a Photo
"Can you inspect the photo at
~/Photos/Redwoods.jpgand check its camera settings?"
{
"originalWidth": 4000,
"originalHeight": 2667,
"aspectRatioFormatted": "3:2 (Landscape)",
"hasGps": true,
"exif": {
"Make": "Hasselblad",
"Model": "500 C/M",
"LensModel": "Zeiss Planar 80mm f/2.8",
"ISO": 400,
"FNumber": 4,
"ExposureTime": "1/125s",
"FocalLength": 80
}
}2. Auto-Suggesting Foto Curated Tags
"What Foto tags would fit this redwood shot?"
{
"suggestedTags": ["Medium Format", "Analog", "Forest"],
"explanation": "Detected Medium Format context; Detected analog film gear; Detected forest environment"
}3. Publishing with Local Dry-Run Test
"Let's test publishing it with a dry run first."
Claude runs foto_publish_post with dryRun: true:
{
"success": true,
"dryRun": true,
"postId": "20261109161630-SIMULATED_USER-abc12345",
"dimensions": { "width": 1820, "height": 1213, "aspectRatio": 1.5 },
"hasStrippedGps": true,
"tags": ["Medium Format", "Analog", "Forest"],
"message": "[DRY RUN] Post successfully validated! Image prepared to 1820x1213px. GPS scrubbed: true. 0 API calls made."
}4. Publishing a Multi-Image Series
"Publish these 3 shots as a sequential series:
frame1.jpg,frame2.jpg,frame3.jpg"
Claude validates boundaries (2 to 5 images), extracts metadata for each, and publishes the multi-image post.
5. Instagram Data Export Migration
"Analyze my Instagram export at
~/Downloads/instagram_export/posts_1.htmland preview what can be migrated."
Claude runs foto_sync_instagram:
{
"dryRun": true,
"totalParsed": 15,
"readyToPublish": 12,
"alreadyPublishedCount": 3,
"candidates": [
{
"post": { "title": "Red Fox in Winter Snow", "hashtags": ["fox", "wildlife", "winter"] },
"suggestedTags": ["Wildlife", "Animals", "Winter"],
"gpsScrubbed": true,
"status": "READY"
}
]
}Build from Source & Developer Guide
Prerequisites
Node.js v18.0.0 or later
npm v9 or later
git clone https://github.com/thesven/foto_mcp.git
cd foto_mcp
npm install
npm run buildRunning Test Suite with >90% Coverage
The test suite includes end-to-end integration flows and modular unit test suites across all components.
# Run tests and verify >90% coverage
npm test
# Generate HTML coverage report
npm run test:coverageCurrent test coverage breakdown:
-----------------|---------|----------|---------|---------|
File | % Stmts | % Branch | % Funcs | % Lines |
-----------------|---------|----------|---------|---------|
All files | 97.71 | 84.55 | 96.07 | 97.71 |
src/config.ts | 100 | 100 | 100 | 100 |
src/foto-client | 100 | 92.3 | 100 | 100 |
src/tags.ts | 100 | 100 | 100 | 100 |
src/api/* | 98.24 | 86.62 | 100 | 98.24 |
src/media/* | 94.88 | 63.93 | 80 | 94.88 |
src/sync/* | 98.71 | 86.56 | 100 | 98.71 |
src/index.ts | 92.94 | 80.64 | 50 | 92.94 |
-----------------|---------|----------|---------|---------|Troubleshooting & FAQ
Session Expiration
If you see
"Stored credentials invalid"or"Authentication token expired", simply prompt the assistant: "Log in to my Foto account with email...and password..." or callfoto_login.To completely reset all local stored sessions, call
foto_logoutor delete~/.config/foto-mcp/credentials.json.
Content Moderation Rejection
Foto automatically evaluates photos using Sightengine (
nudity-2.1). If an image exceeds platform safety limits (sexual activity > 0.7 or sexual display > 0.9), it will be blocked to protect your account standing.
Image Format Support
Foto exclusively allows still photography (JPEG, PNG, WebP, TIFF, HEIC). Animated GIFs and video files are rejected by the media pipeline.
License
This project is licensed under the MIT License.
Available Tools
11 toolsfoto_auth_statusA
Check the current authentication status with Foto app (logged-in user, token validity).
Inputs: no named parameters.
foto_draft_postA
Preview and validate a post draft without publishing. Validates tag constraints (1-3 from whitelist), formats EXIF summary, and checks image parameters.
Inputs: tags (required), caption (required), filePath (required).
foto_get_user_profileA
Retrieve profile details and stats for the authenticated Foto user (username, bio, post count, following/followers).
Inputs: no named parameters.
foto_inspect_imageA
Inspect a local image file without uploading: extracts technical EXIF (camera, lens, ISO, shutter, aperture), dimensions, aspect ratio, and checks for GPS presence.
Inputs: filePath (required).
foto_loginA
Authenticate with Foto app using your account email and password. Securely stores credentials locally.
Inputs: email (required), password (required).
foto_logoutA
Log out of Foto app and delete stored credentials from local disk.
Inputs: no named parameters.
foto_publish_postA
Publish a single photo post to Foto. Automatically normalizes resolution (max 1820px, JPEG 80%), scrubs GPS for privacy, uploads to Storage, passes moderation, and creates the post. Use dryRun=true to test locally without publishing.
Inputs: tags (required), caption (required), filePath (required), dryRun.
foto_publish_seriesB
Publish a multi-image Series (2 to 5 photos) under a single post to Foto. Use dryRun=true to validate locally without uploading.
Inputs: tags (required), caption (required), filePaths (required), dryRun.
foto_search_tagsA
Search Foto's official 303 curated allowed tags whitelist by keyword or prefix.
Inputs: query (required), limit.
foto_suggest_tagsA
Suggest 1 to 3 valid tags from Foto's official 303 curated tags list based on caption, camera/film notes, or subject keywords.
Inputs: caption, keywords, cameraInfo.
foto_sync_instagramA
Synchronize posts from an Instagram data export (HTML/JSON) to Foto. Cleans hashtags, suggests 1-3 curated tags, normalizes dimensions, scrubs GPS, and checks against already-published Foto posts. Default dryRun=true validates everything without publishing.
Inputs: htmlFilePath (required), dryRun, maxPosts, mediaDir.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 11 tools
Each tool targets a fairly clear stage of the workflow (auth, inspect, tag, draft, publish, sync). Minor overlap exists between foto_draft_post and foto_publish_post with dryRun=true, and between foto_suggest_tags and foto_search_tags, but descriptions do enough to separate them.
All tools share a consistent foto_ prefix and mostly follow a verb_noun pattern (foto_inspect_image, foto_publish_post, foto_sync_instagram). Minor deviations: foto_auth_status is noun-phrase and foto_get_user_profile uniquely uses a get_ verb.
Eleven tools is well within a healthy scope and each maps to a distinct step: auth lifecycle (3), local inspection, tag discovery (2), draft, publishing (2), profile, and import sync.
Covers the full publish lifecycle from login and local validation through single/series publishing and Instagram import, plus read-only profile. The only notable gap is post management after publishing (edit/delete/list own posts), which agents can work around for now.
Maintenance
Related MCP Connectors
Search photos and video moments by visual meaning, people, dates, and folders across local libraries, Apple Photos, and OneDrive. Manage collections, groups, favorites, people, and duplicate review. Synced metadata remains searchable while the desktop is offline; local and Apple Photos media access needs the owning device online with remote access enabled. OneDrive media can be accessed directly from the cloud. OAuth or Bearer API keys. Paid Cloud Access required; hosted visual search uses prepaid credits. Text-in-image search is semantic matching, not guaranteed exact OCR. Setup: https://organizewith.ai/en/guides/connect-ai-assistants
Create, review, publish and schedule Instagram images, carousels and Reels with AI assistants.
YouTube and video analysis, C2PA marking for AI images, lossless EXIF/GPS removal. Pay per call.
AI-native digital asset management: semantic search, generative image edits, and CDN delivery.
Related MCP Servers
AlicenseNot gradedqualityDmaintenanceExposes a visual library with semantic search, tagging, editing, and management of photos as tools for AI agents like Claude Code.13 npm49MIT- AlicenseNot gradedqualityBmaintenanceEnables AI assistants to browse and search local photo galleries without uploading photos, using metadata-only indexing and local thumbnail serving.8MIT
- AlicenseNot gradedqualityDmaintenanceEnables AI assistants to access, tag, describe, and manage a Flickr photo library, including automated batch processing.61 npm1MIT
- AlicenseNot gradedqualityBmaintenanceEnables AI agents to search, list, preview, and export photos from Apple Photos, Google Photos Picker sessions, and local Google Takeout archives using native search and metadata inspection.10 npmMIT