Repository navigation
v0.6.0
Breaking change: scoped JWT and introspection tokens
This release fixes MCP permission widening when tokens contain mixed scopes, list-valued scopes,
or the scp claim. A token such as "scope": "openid read" now stays read-only.
A nonempty scope claim containing no recognised Forgetful permission now denies all MCP tools.
For example, a token containing only api:read api:write may still authenticate, but discovery
returns no tools and tool calls are denied.
Before upgrading an affected deployment:
- Keep the IdP scopes required by
FASTMCP_SERVER_AUTH_*_REQUIRED_SCOPES. - Configure the issuer or introspection response to include the intended Forgetful permissions:
- Read-only tools:
"scope": "api:read api:write read". - Read/write tools:
"scope": "api:read api:write read write". - Narrower permissions can use category labels such as
write:memories.
- Read-only tools:
- Obtain replacement tokens after changing issued claims, then check discovery and an allowed
operation. ChangingREQUIRED_SCOPESalone does not change an existing token.
REQUIRED_SCOPES controls admission. FORGETFUL_SCOPES sets the server's tool limit, and
recognised scopes in the token narrow its MCP access. Use * only when it should receive all tools
allowed by the server. Scope settings use commas; token scope strings use spaces. There is no new
forgetful_scopes field.
Absent or empty scope claims retain the existing server-permission fallback after authentication.
Normal built-in GitHub/Google OAuth logins and local no-auth usage do not need the token change
above. See the configuration guide for provider differences and examples.
Security fixes
- Scope PostgreSQL activity listing, history, counts and expired-event cleanup to the requesting
user, without relying on database row-level security (#105). - Check ownership of both memories before creating links on SQLite and PostgreSQL
(#103). - Validate project ownership before attaching documents, code artifacts, files, skills or plans.
Reject missing and foreign project references consistently. Check SQLite source-memory ownership
before using its embedding for similarity searches (#113). - Preserve recognised token restrictions alongside unrelated IdP scopes, and support list-valued
scopeandscpclaims (#107). - Update PyJWT 2.13.0 to 2.15.1, urllib3 2.7.0 to 2.8.0, and fsspec 2026.2.0 to 2026.9.0
(#102). Require those versions in published package metadata too, so normal pip
upgrades cannot silently retain the older versions (#165).
The ownership fixes prevent new invalid relationships. They do not remove cross-user links or
project references that an earlier version may already have stored.
Memory Plugin
Add an optional administrator-configured MemoryPlugin registration with handlers for create,
update, obsolete and restore operations (#97, #164):
- Before-save handlers can allow, warn or reject. Enforce mode blocks rejected writes; warn mode
continues with warnings. - After-save handlers can return advisory warnings. Create handlers receive existing similarity
results and resulting links; no extra similarity searches are added to other operations. - MCP, REST and CLI responses expose warnings while preserving successful response shapes.
After-save failures cannot veto or roll back a completed write.
The plugin is disabled by default and runs trusted administrator Python with server privileges.
Configure MEMORY_WRITE_PLUGIN to reference a module:object containing a MemoryPlugin.
See the plugin contract and examples.
This is the first published version of the plugin. Users who tested the earlier unreleased
single-function contract on main must update their registration; ordinary 0.5.5 installations
have no plugin contract to migrate. Timeouts remain cooperative, and handlers have no durable
retry or delivery guarantee. After a cancelled request or lost response, check stored state
before retrying a write.
Other changes
- Add
unobsolete_memoryto restore a memory mistakenly marked obsolete (#88). - Run FastEmbed work off the event loop with a bounded worker pool. The new
EMBEDDING_MAX_CONCURRENCYsetting defaults to1; increasing it is optional. DirectML requires
1. This limits active work per process, not the waiting queue (#101). - Add public
GET /.well-knowncapability discovery for planning, skills, files and activity
streaming. It reports enabled features without creating a user (#99). - Treat explicit
nullfields in memory updates as unchanged; empty relationship lists still
clear associations (#100). - Fix Windows OAuth token-cache paths (#93) and recovery after failed embedding rebuilds
(6d0199e). - Improve MCP project-ID validation, project name-lookup guidance and concurrent user-creation
recovery. - Add architecture-boundary checks and broader backup, recovery, plugin and Windows test coverage.
Upgrade and known limitations
- No new database migration or embedding rebuild is required when upgrading from 0.5.5.
- Python remains 3.12 or newer. PyJWT, urllib3 and fsspec now have explicit fixed-version
requirements; other existing runtime requirements are unchanged. Two development-only
architecture-check packages were also added. - Upgrade PyPI installations with
python -m pip install --upgrade forgetful-ai==0.6.0in the
intended environment, then runpython -m pip check. Normal dependency resolution upgrades
these three dependencies or reports a conflict. Do not use--no-depsto bypass the requirements.
Locked source installations can useuv sync --locked; Docker users can select the0.6.0image. - The MCP scope changes do not enforce scope restrictions on REST endpoints. REST authorization is
tracked separately in #155; do not rely on MCP tool restrictions to protect REST. - The separate empty-instance-permission-set fallback is unchanged. Do not use an empty resolved
tool set as a deny-all configuration; see the configuration guide.
Contributors
Thanks to @bertheto, @leninworld and @giovannimanzoni for contributions included in this release.