Problem
When an AI agent (e.g. Bob) connects to gbrain's HTTP MCP server using a plain bearer token (created via gbrain auth create), every write operation lands in the default source. The token has no way to carry a sourceId — it's hardcoded to 'default' in http-transport.ts:196:
OAuth tokens (from oauth_clients) can carry a source_id via migration v60, but the older access_tokens transport has no equivalent field.
Impact
- Bob's
opencode.json points to gbrain MCP with a bearer token — all add_timeline_entry, put_page, put_raw_data etc. go to source=default
- Bob's own pages already live in the
bob source (federated, 246 pages)
- Any AI agent using a plain API key can't target a specific source
- Workaround: run separate gbrain MCP servers per source with
GBRAIN_SOURCE env var, but that doesn't scale
Requested
Add a source_id column to access_tokens (analogous to oauth_clients.source_id), so bearer tokens can be scoped to a source at creation time:
gbrain auth create bob-token --source bob
Then in http-transport.ts:validateToken(), read sourceId from the token row instead of hardcoding 'default'.
Problem
When an AI agent (e.g. Bob) connects to gbrain's HTTP MCP server using a plain bearer token (created via
gbrain auth create), every write operation lands in thedefaultsource. The token has no way to carry asourceId— it's hardcoded to'default'inhttp-transport.ts:196:OAuth tokens (from
oauth_clients) can carry asource_idvia migration v60, but the olderaccess_tokenstransport has no equivalent field.Impact
opencode.jsonpoints to gbrain MCP with a bearer token — alladd_timeline_entry,put_page,put_raw_dataetc. go tosource=defaultbobsource (federated, 246 pages)GBRAIN_SOURCEenv var, but that doesn't scaleRequested
Add a
source_idcolumn toaccess_tokens(analogous tooauth_clients.source_id), so bearer tokens can be scoped to a source at creation time:Then in
http-transport.ts:validateToken(), readsourceIdfrom the token row instead of hardcoding'default'.