thedotmack/claude-mem · error · ServerClientError
transport
transport
Error message
${toolName} requires CLAUDE_MEM_RUNTIME=server. Current runtime is "worker"; use the existing search/timeline/get_observations tools for worker-mode memory access. What it means
requireServerForObservationTool guards server-only observation tools (like observation_add) behind runtime resolution. If resolveServerToolContext() returns nothing — meaning CLAUDE_MEM_RUNTIME is 'worker' (the default) so no server context exists — it throws a ServerClientError with code 'transport' telling the caller the tool needs CLAUDE_MEM_RUNTIME=server and pointing them to the worker-mode tools (search, timeline, get_observations) instead. This is an intentional routing error: the capability exists only in server runtime.
Solutions
- Switch to server runtime: set CLAUDE_MEM_RUNTIME=server for the MCP server process and provide the required server config (API key, server URL).
- If you intend to stay in worker mode, use the worker-mode tools instead: search, timeline, get_observations.
- Verify the variable is exported in the environment where the MCP server itself launches (e.g. Claude Code MCP config env block), not just a shell.
- After changing the runtime, restart the MCP server so resolveServerToolContext() re-reads the environment.
Example fix
// before: calling server-only tool in worker mode
observation_add({ content: 'note' }) // ServerClientError: transport
// after: either set CLAUDE_MEM_RUNTIME=server in the MCP server env, or in worker mode use:
search({ query: 'note' }) Defensive patterns
Strategy: type-guard
Validate before calling
function canUseServerObservationTools(): boolean {
return (process.env.CLAUDE_MEM_RUNTIME ?? '').trim() === 'server';
}
// call only if canUseServerObservationTools(), else use search/timeline/get_observations Type guard
function isServerRuntime(env: NodeJS.ProcessEnv = process.env): boolean {
return (env.CLAUDE_MEM_RUNTIME ?? '').trim() === 'server';
} Try / catch
try {
ctx = requireServerForObservationTool('observation_add');
} catch (err) {
if (err instanceof ServerClientError && err.code === 'transport') {
// fall back to worker-mode tooling (search/timeline/get_observations)
}
throw err;
} Prevention
- Set CLAUDE_MEM_RUNTIME=server explicitly in the MCP server's launch config when using server-only tools.
- Advertise only runtime-appropriate tools (getAdvertisedMcpToolsForRuntime) so agents never see observation_add in worker mode.
- Document in agent prompts which tools require server runtime.
- After runtime changes, restart the MCP server so the env is re-read.
When it happens
Trigger: Invoking a server-only MCP tool (e.g. observation_add, handleSessionStartContext's ctx resolution) while the MCP server runs with CLAUDE_MEM_RUNTIME unset or = 'worker', so resolveServerToolContext() yields no server context.
Common situations: User configured claude-mem in default worker mode but an agent/workflow tries the newer server-only tools; docs or prompts referencing observation_add without mentioning the runtime requirement; env var typo'd or set only in the worker process and not the MCP server process.
Understand the failure class
Background: "environment variable is not set" and "Missing keys in environment" errors: what missing required env var messages mean and how to fix them — this error's family across 28 libraries.
Related errors
- missing_api_key
- observation_add: "content" is required
- `server ` is a server runtime command, but…
- Access denied: " " resolves outside the workspace ( ). MCP…
- Anthropic API rejected request with HTTP 400: this model…
AI-assisted analysis of thedotmack/claude-mem@d8bc9755e7 (2026-09-17).
Data as JSON: /api/errors/68c7930e49b855fb.
Report an issue: GitHub.
Appendix: source
Thrown at src/servers/mcp-server.ts:207
text: `Tool error: ${error instanceof Error ? error.message : String(error)}`,
}],
isError: true as const,
};
}
function formatJsonResult(payload: unknown): { content: Array<{ type: 'text'; text: string }> } {
return {
content: [{
type: 'text' as const,
text: JSON.stringify(payload, null, 2),
}],
};
}
function requireServerForObservationTool(toolName: string): ServerAvailable {
const resolution = resolveServerToolContext();
if (!resolution) {
throw new ServerClientError(
'transport',
`${toolName} requires CLAUDE_MEM_RUNTIME=server. Current runtime is "worker"; use the existing search/timeline/get_observations tools for worker-mode memory access.`,
);
}
if (!resolution.available) {
throw new ServerClientError('missing_api_key', `${toolName}: ${resolution.reason}`);
}
return resolution;
}
function wrapHandler<Args>(
toolName: string,
execute: (args: Args) => Promise<{ content: Array<{ type: 'text'; text: string }> }>,
): (args: Args) => Promise<{ content: Array<{ type: 'text'; text: string }>; isError?: boolean }> {
return async (args: Args) => {
try {
return await execute(args);
} catch (error) {View on GitHub (pinned to d8bc9755e7)