Skip to content

feat: switch engines mid-session via MCP tools and /use-memory skill#62

Closed
gonzaloserrano wants to merge 1 commit intomainfrom
gsr/add-session-engine-mcp-tools
Closed

feat: switch engines mid-session via MCP tools and /use-memory skill#62
gonzaloserrano wants to merge 1 commit intomainfrom
gsr/add-session-engine-mcp-tools

Conversation

@gonzaloserrano
Copy link
Copy Markdown

The Claude Code plugin couldn't switch Memory Engines mid-session. The MCP server bound at startup to whichever engine owned --api-key, so touching a different engine meant quitting Claude Code, running me engine use <slug>, and reopening. Blocks anyone who wants to dip into a team engine briefly without losing their personal default.

Four new MCP tools and a /use-memory skill move engine selection from launch-time to runtime. me_engine_list enumerates engines via the session token (works in FRESH state). me_session_get_engine reads the current binding without exposing the API key. me_session_use_engine binds for the rest of the session, with an optional probe and a client cache so re-binds are free. me_session_provision_engine mints a key via accounts.engine.setupAccess, persists it under engines.<slug>.api_key, and binds; idempotent when the key already exists.

--api-key is now optional. When present, its slug seeds the session as already bound, so the existing plugin's .mcp.json keeps working unchanged. Without it the server starts FRESH and the agent must call me_session_use_engine before any me_memory_* succeeds.

Provisioning persists keys via a new addEngineApiKey helper that does not mutate active_engine. The existing storeApiKey does, because CLI callers expect it to. Two helpers keep session-scoped binding from leaking into whatever the next CLI process treats as default; running me memory get foo outside Claude Code after a provision call still hits the original active engine.

The skill ships from packages/claude-plugin/skills/use-memory/, not td-aiguide. It's generic to all Memory Engine users, and bundling it next to the MCP tools means one install gets both halves. Plugin version 0.1.0 → 0.2.0; "skills": "./skills/" added to plugin.json.

Manual smoke test against the live server (FRESH bootstrap, single-engine account): me_session_get_engine returns slug-only binding from bootstrap; me_engine_list returns the full org/engine tree; me_session_provision_engine default is idempotent (provisioned: false on retry); a bogus slug yields a resolver error pointing at me_engine_list; me_session_use_engine default reuses the cached client (validated: false) and backfills full metadata.

Auto-capture hooks (UserPromptSubmit/Stop) are unchanged. They still read CLAUDE_PLUGIN_OPTION_API_KEY from plugin userConfig, so in-session me_session_use_engine does not redirect them. Agent-driven writes follow the in-session bind; hook-driven captures follow scope-resolved userConfig. Multi-engine capture across sessions still requires the existing user/project scope split.

Resolver and credentials persistence have unit tests (packages/cli/mcp/engine-resolve.test.ts, additions in packages/cli/credentials.test.ts). End-to-end MCP behavior validated by the smoke test above; no harness for spawning the stdio server in a test exists yet.

@CLAassistant
Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

The Claude Code plugin couldn't switch Memory Engines mid-session. The
MCP server bound at startup to whichever engine owned --api-key, so
touching a different engine meant quitting Claude Code, running
`me engine use <slug>`, and reopening. Blocks anyone who wants to dip
into a team engine briefly without losing their personal default.

Four new MCP tools and a /use-memory skill move engine selection from
launch-time to runtime. me_engine_list enumerates engines via the
session token (works in FRESH state). me_session_get_engine reads the
current binding without exposing the API key. me_session_use_engine
binds for the rest of the session, with an optional probe and a client
cache so re-binds are free. me_session_provision_engine mints a key via
accounts.engine.setupAccess, persists it under engines.<slug>.api_key,
and binds; idempotent when the key already exists.

--api-key is now optional. When present, its slug seeds the session as
already bound, so the existing plugin's .mcp.json keeps working
unchanged. Without it the server starts FRESH and the agent must call
me_session_use_engine before any me_memory_* succeeds.

Provisioning persists keys via a new addEngineApiKey helper that does
not mutate active_engine. The existing storeApiKey does, because CLI
callers expect it to. Two helpers keep session-scoped binding from
leaking into whatever the next CLI process treats as default; running
`me memory get foo` outside Claude Code after a provision call still
hits the original active engine.

The skill ships from packages/claude-plugin/skills/use-memory/, not
td-aiguide. It's generic to all Memory Engine users, and bundling it
next to the MCP tools means one install gets both halves. Plugin
version 0.1.0 -> 0.2.0; "skills": "./skills/" added to plugin.json.

Resolver and credentials persistence have unit tests
(packages/cli/mcp/engine-resolve.test.ts, additions in
packages/cli/credentials.test.ts). End-to-end MCP behavior validated by
manual smoke test against the live server; no harness for spawning the
stdio server in a test exists yet.
@gonzaloserrano gonzaloserrano force-pushed the gsr/add-session-engine-mcp-tools branch from 465945f to 66efe02 Compare April 30, 2026 16:14
@jgpruitt
Copy link
Copy Markdown
Collaborator

jgpruitt commented May 1, 2026

Gonzalo, I fully appreciate the motivation for this change. We need an ergonomic way to support multi-engine setups.

There are a few issues here:

  1. The MCP server has to be able to operate in environments where there is no credentials.yaml file. We want it to work with humans' coding agents, but we also want it to work embedded in an application, in a Docker container, in a CI/CD workflow, etc., where there is no human identity to tie it to--the application IS the identity.

  2. This breaks our security model. In many cases, a human will allow an agent to act on their behalf by sharing a single api key with the agent. But we want to support models in which the human has a user with certain privileges and provisions a user for their agent with a subset of those privileges. The agent gets an api key tied to that more restricted user. This guarantees that the agent can ONLY perform the actions the human intends it to perform. This PR breaks that model. The agent can switch engines and adopt the human's api keys and thereby their privileges. Worse, the provisioning tool mints fresh keys against the human's OAuth session token, so even engines the agent has no key for today become reachable.

  3. This adds four new MCP tools to express "switch engines." Every tool adds tokens we pay for on every turn and increases the surface area the agent has to disambiguate. It's a project-wide principle for me — we won't add new MCP tools unless they are absolutely necessary.

We're actively working on designs to make the agent plugins work and enable this sort of team-based activity. I think we should close this PR and pick the problem back up under that design. Would you be willing to provide feedback on these plans? I have a vision doc — would you read it and push back?

@jgpruitt jgpruitt closed this May 1, 2026
@gonzaloserrano
Copy link
Copy Markdown
Author

gonzaloserrano commented May 4, 2026

Hey sorry about the noise. I did not want to open a PR but my AI companion did. I was just vibe-experimenting with the APIs and the whole problem without giving it mutch thought. Sorry about that again!

We're actively working on designs to make the agent plugins work and enable this sort of team-based activity. I think we should close this PR and pick the problem back up under that design. Would you be willing to provide feedback on these plans? I have a vision doc — would you read it and push back?

I will take a look for sure! I'm not sure if I will be able to push back though ;-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants