mirror of
https://github.com/thedotmack/claude-mem.git
synced 2026-09-20 04:23:02 +08:00
Merge branch 'pr3065' into mainline
# Conflicts: # plugin/scripts/mcp-server.cjs # plugin/scripts/server-service.cjs # plugin/scripts/worker-service.cjs
This commit is contained in:
@@ -38,6 +38,7 @@ import {
|
||||
type ServerRuntimeContext,
|
||||
} from '../services/hooks/runtime-selector.js';
|
||||
import { normalizePlatformSource } from '../shared/platform-source.js';
|
||||
import { getAdvertisedMcpToolsForRuntime } from './mcp-tool-visibility.js';
|
||||
|
||||
let mcpServerDirResolutionFailed = false;
|
||||
const mcpServerDir = (() => {
|
||||
@@ -867,8 +868,9 @@ const server = new Server(
|
||||
);
|
||||
|
||||
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
||||
const advertisedTools = getAdvertisedMcpToolsForRuntime(tools, selectRuntime());
|
||||
return {
|
||||
tools: tools.map(tool => ({
|
||||
tools: advertisedTools.map(tool => ({
|
||||
name: tool.name,
|
||||
description: tool.description,
|
||||
inputSchema: tool.inputSchema
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
import type { SelectedRuntime } from '../services/hooks/runtime-selector.js';
|
||||
import { logger } from '../utils/logger.js';
|
||||
|
||||
export const SERVER_BETA_ONLY_TOOL_NAMES = [
|
||||
'observation_add',
|
||||
'observation_record_event',
|
||||
'observation_search',
|
||||
'observation_context',
|
||||
'observation_generation_status',
|
||||
'memory_add',
|
||||
'memory_search',
|
||||
'memory_context',
|
||||
] as const;
|
||||
|
||||
const serverBetaOnlyToolNameSet = new Set<string>(SERVER_BETA_ONLY_TOOL_NAMES);
|
||||
|
||||
export function getAdvertisedMcpToolsForRuntime<T extends { name: string }>(
|
||||
allTools: readonly T[],
|
||||
runtime: SelectedRuntime
|
||||
): T[] {
|
||||
if (runtime === 'server') {
|
||||
return [...allTools];
|
||||
}
|
||||
logger.debug('SYSTEM', 'Filtering server-beta-only MCP tools from worker runtime advertisement', {
|
||||
runtime,
|
||||
hiddenToolCount: SERVER_BETA_ONLY_TOOL_NAMES.length,
|
||||
});
|
||||
return allTools.filter((tool) => !serverBetaOnlyToolNameSet.has(tool.name));
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
import { describe, it, expect } from 'bun:test';
|
||||
import { readFileSync } from 'node:fs';
|
||||
import { join } from 'node:path';
|
||||
import {
|
||||
getAdvertisedMcpToolsForRuntime,
|
||||
SERVER_BETA_ONLY_TOOL_NAMES,
|
||||
} from '../../src/servers/mcp-tool-visibility.js';
|
||||
|
||||
const allTools = [
|
||||
{ name: 'search', description: '', inputSchema: {} },
|
||||
{ name: 'timeline', description: '', inputSchema: {} },
|
||||
{ name: 'get_observations', description: '', inputSchema: {} },
|
||||
{ name: 'observation_add', description: '', inputSchema: {} },
|
||||
{ name: 'observation_record_event', description: '', inputSchema: {} },
|
||||
{ name: 'observation_search', description: '', inputSchema: {} },
|
||||
{ name: 'observation_context', description: '', inputSchema: {} },
|
||||
{ name: 'observation_generation_status', description: '', inputSchema: {} },
|
||||
{ name: 'memory_add', description: '', inputSchema: {} },
|
||||
{ name: 'memory_search', description: '', inputSchema: {} },
|
||||
{ name: 'memory_context', description: '', inputSchema: {} },
|
||||
{ name: 'smart_search', description: '', inputSchema: {} },
|
||||
];
|
||||
|
||||
describe('MCP runtime-aware tool visibility', () => {
|
||||
it('base-fails/head-passes: worker hides server-beta-only tool names', () => {
|
||||
const workerTools = getAdvertisedMcpToolsForRuntime(allTools, 'worker');
|
||||
const names = new Set(workerTools.map(tool => tool.name));
|
||||
|
||||
for (const toolName of SERVER_BETA_ONLY_TOOL_NAMES) {
|
||||
expect(names.has(toolName)).toBe(false);
|
||||
}
|
||||
});
|
||||
|
||||
it('base-fails/head-passes: server runtime keeps server-beta-only tool names', () => {
|
||||
const serverTools = getAdvertisedMcpToolsForRuntime(allTools, 'server');
|
||||
const names = new Set(serverTools.map(tool => tool.name));
|
||||
|
||||
for (const toolName of SERVER_BETA_ONLY_TOOL_NAMES) {
|
||||
expect(names.has(toolName)).toBe(true);
|
||||
}
|
||||
});
|
||||
|
||||
it('worker runtime still advertises core MCP worker tools', () => {
|
||||
const workerTools = getAdvertisedMcpToolsForRuntime(allTools, 'worker');
|
||||
const names = new Set(workerTools.map(tool => tool.name));
|
||||
|
||||
expect(names.has('search')).toBe(true);
|
||||
expect(names.has('timeline')).toBe(true);
|
||||
expect(names.has('get_observations')).toBe(true);
|
||||
expect(names.has('smart_search')).toBe(true);
|
||||
});
|
||||
|
||||
it('tools/list path references the helper so discovery is runtime-aware', () => {
|
||||
const mcpServerPath = join(import.meta.dir, '..', '..', 'src', 'servers', 'mcp-server.ts');
|
||||
const mcpServerSrc = readFileSync(mcpServerPath, 'utf-8');
|
||||
|
||||
expect(mcpServerSrc).toContain('getAdvertisedMcpToolsForRuntime(tools, selectRuntime())');
|
||||
expect(mcpServerSrc).not.toContain('tools.map(tool => ({');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user