imogen
imogen 是一个面向家庭实验室的自托管照片和视频库。它把你的照片保存在你掌控的硬件上,并向你想构建的任何东西开放:Web 界面、REST API、用于移动应用的 TypeScript SDK,以及一个 MCP 端点,让你的 AI 助手也能搜索这个照片库。
对齐时间线 —— 照片保持拍摄时的宽高比,按天分组
相机产出的一切 —— HEIC、RAW、JPEG、视频、Live Photos
可安装 —— Web 界面是一个 PWA,可离线工作
两种登录方式 —— 本地账户,或通过 Authentik、Keycloak、Google 或其他任何支持 OIDC 的服务进行单点登录
为扩展而生 —— OpenAPI、SDK 和 OAuth 2.1 服务器,让第三方应用成为头等公民,而不是事后补充
人物 —— 可选的人脸分组,完全运行在你自己的服务器上
保险库 —— 需要口令才能查看的照片,对其他一切隐藏
共享 —— 将相册或单张照片发布为链接,可选密码、过期日期,以及下载开关
管理 —— 邀请用户、冻结账户、查看处理队列、断开应用连接,并查看当前所有公开内容
智能体就绪 —— 用一个 URL 将 Claude 或 Grok 连接到你的照片库
运行
curl -O https://raw.githubusercontent.com/ergofobe/imogen-server/main/docker-compose.yml
docker compose up -d打开 http://localhost:3000。你创建的第一个账户将成为管理员。
这就是全部安装过程。imogen 需要 Postgres,compose 文件会启动一个;没有消息代理,没有缓存,也没有需要运行的 sidecar。
配置
所有内容都是环境变量,并在启动时校验——服务器在配置错误时会拒绝启动,而不是在负载下才失败。
变量 | 默认值 | 作用 |
|
| 人们访问 imogen 所用的 URL。OAuth 和共享链接都由它生成,因此在反向代理后面必须设置正确。 |
| — | Postgres 连接字符串。必填。 |
|
| 照片存放的位置。请备份此目录。 |
| generated | 用于会话签名。如果未设置,将在首次运行时生成并持久化保存。 |
|
| 是否允许任何人创建账户。第一个账户始终允许。这只是一个起始值——管理员可以在应用中更改,并以其设置的为准。 |
|
| 已删除照片可被恢复的时间。这也是管理员可以更改的起始值。 |
|
| 同时处理的照片数量。在有空闲核心的机器上可以调高。 |
管理
创建的第一个账户将成为管理员。它的设置页面有一个指向 /admin 的链接,账户、邀请、处理队列、已连接应用、存储和共享链接都在那里管理。
该区域不只是对其他人关闭——它返回一个普通的 404,与服务器对未知路径返回的完全相同,因此无法通过查找来发现它。任何扫描管理面板的请求都不会得到任何信息。
要把某人加入已关闭的服务器,请创建邀请并发送链接。链接只显示一次,且仅以哈希形式存储,所以如果丢失了,就撤销它并重新创建一个。
单点登录
将 imogen 指向任何 OIDC 提供商。在你的提供商中将重定向 URI 设置为 https://photos.example.com/api/v1/auth/oidc/callback。
IMOGEN_OIDC_ISSUER: https://auth.example.com/application/o/imogen/
IMOGEN_OIDC_CLIENT_ID: ...
IMOGEN_OIDC_CLIENT_SECRET: ...
IMOGEN_OIDC_LABEL: Sign in with Authentik
IMOGEN_OIDC_ADMIN_VALUE: imogen-admins # members of this group become administrators
IMOGEN_OIDC_ACCOUNT_URL: '' # optional; guessed for Authentik and Keycloak现有本地账户通过已验证的电子邮件地址进行关联,因此启用 SSO 不会让任何人无法访问。
提供商拥有其管理的账户的姓名和电子邮件:imogen 在每次登录时重新读取它们,在设置中只读显示,并提供跳转到提供商自己账户页面的链接。如果该链接需要指向默认推断以外的地址,请设置 IMOGEN_OIDC_ACCOUNT_URL。
当你设置 IMOGEN_OIDC_ADMIN_VALUE 时,管理员状态跟随该值——包括在某人离开组时移除管理员状态。如果保持未设置,imogen 从不改动角色,因此在本地被提升为管理员的人会一直是管理员。
在反向代理后面
imogen 提供纯 HTTP 服务,并预期位于终止 TLS 的代理之后。透传 X-Forwarded-For,以便会话记录合理的地址;允许较大的请求体以支持视频上传;并将 IMOGEN_PUBLIC_URL 设置为外部 URL。
photos.example.com {
reverse_proxy localhost:3000
request_body { max_size 8GB }
}Related MCP server: immich-mcp
人物
imogen 可以识别人脸,并按每个人出现的照片进行分组,这样你只需命名一次,就可以浏览包含该人的所有照片。检测和识别都在你的服务器上运行;不会将任何照片发送到任何地方。
默认情况下,它是关闭的,直到你打开它——在“人物”页面开启。启用时需要下载约 190 MB 的识别模型,并在后台扫描你现有的照片库。
保险库中的照片永远不会被扫描,将照片移入保险库会忘记其中已找到的人脸。
在你命名之前,没有人有名字。未命名的分组会显示出来,以便你为它们命名;而且无论是分组还是人,都可以隐藏。
分组时宁愿将同一个人拆到两个组,也不愿将两个人合并到一个组。选择多个组并告诉它这些是同一个人。
关于模型的说明。 imogen 使用 InsightFace 的 SCRFD 和 ArcFace,它们的许可证允许非商业研究用途。imogen 不附带任何模型:你的服务器在启用该功能时下载它们,因此是否接受该许可由你自己决定。如果这不适合你的情况,请关闭该功能。
保险库
有些照片不应该在一次不小心的滚动中就被看到。将它们移入保险库,它们就完全离开照片库:不在时间线中,不在搜索中,不在你的相册中,不在共享链接中,也不在任何 AI 助手能看到的内容中。
打开它需要口令,即使你已经登录,也要再次输入。
有几个设计决策值得了解:
口令不是你的账户密码。 单点登录账户没有本地密码,更重要的是,一个已经登录的会话不应该足够——发现你的笔记本电脑开着,不应该也能打开这个。
只有浏览器会话可以打开它。 API 令牌或 MCP 连接器可以持有完全有效的凭据,但仍然无法进入。这是有意设计的,不是疏漏。
它会自动关闭,十五分钟之后,或在你要求时立即关闭。
没有人能为你重置它。 没有恢复途径,这正是关键所在。
将照片移入保险库也会将其从所有相册中移除,因为相册是可共享的。
连接 AI 助手
imogen 支持 MCP,因此助手可以搜索你的照片库、查看照片、管理相册——只需你的授权,此外别无所需。
Claude.ai 或 Grok: 添加一个指向 https://photos.example.com/mcp 的连接器。没有需要手动粘贴的内容:客户端发现 imogen、自行注册,并将你带到同意屏幕,屏幕上会明确列出它请求的权限。可随时在设置中撤销。
本地智能体(Claude Code,或任何通过 stdio 支持 MCP 的智能体):
bun add -g @imogen/mcp
imogen-mcp login --server https://photos.example.com{ "mcpServers": { "imogen": { "command": "imogen-mcp" } } }助手可以做什么
工具 | 权限 |
|
|
|
|
|
|
|
|
每个工具都限定在已连接的账户范围内。没有任何工具可以删除内容,保险库中的任何内容对它们都不可见。只有你已命名的人才能被找到——未命名的分组和已隐藏的人则不能。
在此基础上构建
API 文档位于 /api/v1/docs,OpenAPI 3.1 描述位于 /api/v1/openapi.json。
imogen-sdk 提供了五种语言的客户端——TypeScript、Rust、Python、Swift 和 Kotlin。在 TypeScript 中:
bun add @imogen/sdkimport { ImogenClient } from '@imogen/sdk'
const imogen = new ImogenClient({ baseUrl: 'https://photos.example.com', token })
const page = await imogen.assets.list({ q: 'harbour', limit: 50 })
for await (const asset of imogen.assets.iterate()) console.log(asset.originalFilename)
// Picks its protocol by size: one request for photos, a resumable session for video.
await imogen.assets.uploadMany(files, {
onFileComplete: (outcome, done, total) => console.log(`${done}/${total}`),
})编写移动应用
每个 SDK 都带有原生应用所需的 OAuth 客户端——Swift 和 Kotlin 的客户端正是为此而设。没有硬编码:应用会自行注册,因此它可以与用户指向的任何 imogen 服务器配合工作。
import { OAuthClient } from '@imogen/sdk'
const oauth = new OAuthClient('https://photos.example.com')
const client = await oauth.register('My Photo App', ['myapp://oauth'])
const pending = await oauth.beginAuthorization(client.client_id, 'myapp://oauth')
// Open pending.authorizationUrl in the system browser, then on the callback:
const tokens = await oauth.completeAuthorization(pending, callbackUrl)上传按内容幂等:重新发送服务器已拥有的照片会返回现有资源,而不是存储第二份副本,因此同步循环可以简单且仍然正确。传入 deviceAssetId,客户端无需保留自己的记录即可知道已发送的内容。
配对,而不是输入主机名
上述流程仍然需要应用知道要连接哪台服务器,而自托管的照片库位于其所有者选择的任何地址。在手机键盘上输入这个地址是安装这类应用时最糟糕的时刻,因此改为由浏览器来完成。
设置 → 设备 → 配对设备 会生成一次性票据,并将其呈现为二维码,二维码中同时包含服务器 URL 和代码。应用读取该二维码并完成其余操作:
val invitation = parsePairingUri(scanned) ?: return
val oauth = OAuthClient(invitation.serverUrl)
val paired = oauth.pair(invitation.code, "imogen for Android", "imogen://oauth", Build.MODEL)摄像头读到的是票据,而不是令牌。它一次性有效,有效期五分钟,并且只换取一个授权码——该授权码绑定到一个从未离开设备的 PKCE 挑战,因此拍下某人屏幕的照片是不够的。最终获得的授权是普通授权,并像其他任何授权一样出现在已连接应用中。
同一个页面还会将票据以链接形式提供,供已经在使用 Web 界面的手机使用:点按该链接会直接打开应用。
开发
git clone https://github.com/ergofobe/imogen-server
cd imogen-server
bun install
docker compose -f docker/compose.dev.yml up -d # Postgres
export DATABASE_URL='postgres://imogen:imogen@localhost:5432/imogen'
bun run db:migrate
bun run dev # API on :3000
bun run dev:web # web on :5173, proxying to the APIbun test # needs the dev Postgres running
bun run typecheck
bun run lint测试针对真实的 Postgres 和真实的 HTTP 服务器运行,而不是使用 mock。那些值得做对的部分——OAuth 流程、游标分页、媒体处理管道——恰恰是使用 mock 时会让你做错的部分。
项目结构
包 | 作用 |
| Hono 应用:路由、认证、媒体处理管道、任务 worker。 |
| React PWA。它像任何第三方客户端一样使用 |
| 面向本地智能体的 stdio 桥接。 |
客户端库位于它们自己的仓库中:imogen-sdk —— TypeScript、Rust、Python、Swift 和 Kotlin,均依据一套共用的契约测试夹具进行校验。@imogen/shared,即本服务器用来校验并据此生成 OpenAPI 文档的 Zod 模式,也存放在那里:它就是 API 契约,而契约应当与那些必须遵守它的客户端放在一起。
packages/server/src/api/sdk-contract.test.ts 是这一安排中服务器一侧的体现。它会启动一个真实的应用程序,并通过已发布的 TypeScript 客户端来驱动它——这是唯一能证明两半彼此吻合的地方。
设计文档位于 docs/superpowers/specs。
尚未实现
语义搜索——通过描述来查找照片——尚未实现。模式在资产上预留了一个向量列,搜索索引也已就位,因此该功能无需迁移即可实现;但目前搜索覆盖的是文件名、描述、地点、相机元数据,以及你已命名的人。
同样缺失的还有:反向地理编码(坐标仅以坐标形式显示)、视频转码和 S3 存储。存储驱动是一个接口,因此当有人需要时,加入 S3 是一个范围可控的改动。
人脸分组功能可用,但有一些值得了解的粗糙之处。它能很好地识别正面的、光线适当的人脸;侧面、墨镜、运动模糊和幼儿——其面部变化速度快于存储的平均面容所能追踪的速度——则是它会让你失望的地方。它宁可把同一个人拆到两个组里,也不愿把两个人合并,理由是前者只需点击一下即可修复,而后者会把某人的照片归档到另一个人的名下。
许可证
AGPL-3.0-or-later。如果你将修改后的 imogen 作为服务运行,请分享这些修改。
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
Holiday photo MCP server: list and fetch personal holiday photos inline in Claude chat.
Persistent memory for AI assistants — one shared, OAuth-secured vault for every MCP client.
Automate 1,000+ services from any MCP-compatible AI agent: build Applets, run actions and queries.
AI-powered image processing via GPU. Remove backgrounds and upscale images (2x/4x) directly from any MCP client. OAuth 2.1 authenticated, returns processed images inline with download links. Free credits on signup at maskr.io.
Related MCP Servers
- FlicenseNot gradedqualityCmaintenanceEnables AI assistants to search, browse, and retrieve metadata and images from your Google Photos library. It supports content-based filtering, album listing, and location extraction via STDIO and HTTP transports.39
- FlicenseAqualityBmaintenanceAn MCP server for Immich self-hosted photo management that provides AI-accessible tools for browsing, searching, organizing, and managing photo libraries with duplicate detection and safe deletion workflows.431

CoreViz MCPofficial
AlicenseNot gradedqualityDmaintenanceExposes a visual library with semantic search, tagging, editing, and management of photos as tools for AI agents like Claude Code.3048MIT- FlicenseNot gradedqualityCmaintenanceAn MCP server that integrates AI assistants with the Flickr API, enabling management of photos, albums, groups, and contacts via natural language commands.1
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/ergofobe/imogen-server'
If you have feedback or need assistance with the MCP directory API, please join our Discord server