Add AttachmentService_CreateAttachment to the curated MCP allowlist so
agents can upload files (inline base64 content) alongside memos, closing
the gap where the MCP server could list/get/delete attachments but not
create them.
Closes#6057
Make the OpenAPI-driven MCP surface more usable by agents, following the
mcp-builder guidance.
- Enrich proto descriptions (single source of truth, flows to OpenAPI + MCP
tool descriptions): document the memo `filter` CEL grammar with fields and
examples (replacing the dangling "Refer to Shortcut.filter"), clarify the
created_ts/updated_ts vs create_time/update_time naming, the visibility
enum, the declarative replace semantics of Set* ops, and steer tag filters
to `"x" in tags` (not the unsupported `tag == "x"`).
- Mark SetMemoAttachments / SetMemoRelations idempotent via a per-operation
override the HTTP-method heuristic can't express.
- Curate two read-only orientation tools: shortcut_list_shortcuts (surfaces
reusable CEL filters) and auth_get_current_user (the single allowed
auth/identity op, for resolving the current user); guard test updated to
keep the rest of the auth/user surface excluded.
- Add a task-level evaluation suite (server/router/mcp/evals) with 10
verified questions, pinned to the deterministic demo seed.
The go-sdk Streamable HTTP handler enables DNS-rebinding protection that
rejects any request whose Host header is non-loopback while the server is
bound to a loopback address. memos is commonly run bound to loopback behind a
reverse proxy (e.g. the public demo), so every /mcp request was rejected with
"403 Forbidden: invalid Host header" before authentication ran.
Disable the SDK's localhost protection and rely on memos' own Origin/Host
allowlist (isAllowedMCPOrigin) for CSRF / DNS-rebinding protection. Add a
regression test covering the proxied shape and confirming disallowed origins
are still rejected.
Reject non-standard truthy numeric expressions in filters and document the parser as a supported subset of standard CEL syntax.
- remove legacy filter rewrites
- support standard equality in tag exists predicates
- add regression coverage for accepted and rejected expressions
- Replace PAT-only auth with optional auth supporting both PAT and JWT
via auth.Authenticator.Authenticate(); unauthenticated requests see
only public memos, matching REST API visibility semantics
- Inline auth middleware into mcp.go following fileserver pattern;
remove auth_middleware.go
- Introduce memoJSON response type that correctly serialises store.Memo
(including Payload.Tags and Payload.Property) without proto marshalling
- Add tools: list_memo_comments, create_memo_comment, list_tags
- Extend list_memos with state (NORMAL/ARCHIVED), order_by_pinned, and
page parameters
- Extend update_memo with pinned and state parameters
- Extract #tags from content on create/update via regex to pre-populate
Payload.Tags without requiring a full markdown service rebuild
- Add MCP Resources: memo://memos/{uid} template returns memo as
Markdown with YAML frontmatter, allowing clients to read memos by URI
- Add MCP Prompts: capture (save a thought) and review (search + summarise)
Add ApplyToContext and AuthenticateToUser helpers to the auth package,
then remove the duplicated auth code spread across the MCP middleware,
file server, Connect interceptor, and gRPC-Gateway middleware.
- auth.ApplyToContext: single place to set claims/user into context after Authenticate()
- auth.AuthenticateToUser: resolves any credential (bearer token or refresh cookie) to a *store.User
- MCP middleware: replaced manual PAT DB lookup + expiry check with Authenticator.AuthenticateByPAT
- File server: replaced authenticateByBearerToken/authenticateByRefreshToken with AuthenticateToUser
- Connect interceptor + Gateway middleware: replaced duplicated context-setting block with ApplyToContext
- MCPService now accepts secret to construct its own Authenticator
Embeds a Model Context Protocol (MCP) server into the Memos HTTP
process, exposing memo operations as MCP tools at POST/GET /mcp using
Streamable HTTP transport.
Authentication is PAT-only — requests without a valid personal access
token receive HTTP 401. Six tools are exposed: list_memos, get_memo,
create_memo, update_memo, delete_memo, and search_memos, all scoped to the authenticated user.