()
| 82 | let chatClient: AddieClaudeClient | null = null; |
| 83 | |
| 84 | function getChatClient(): AddieClaudeClient { |
| 85 | if (!chatClient) { |
| 86 | const apiKey = process.env.ADDIE_ANTHROPIC_API_KEY || process.env.ANTHROPIC_API_KEY; |
| 87 | if (!apiKey) { |
| 88 | throw new Error('Anthropic API key not configured'); |
| 89 | } |
| 90 | |
| 91 | chatClient = new AddieClaudeClient(apiKey, AddieModelConfig.chat); |
| 92 | |
| 93 | // Register knowledge + directory tools for MCP callers. |
| 94 | // MCP chat_with_addie keeps knowledge tools because MCP partners use Sonnet, |
| 95 | // unlike web chat anonymous users who get Haiku (see addie-chat.ts). |
| 96 | // |
| 97 | // MCP chat_with_addie is invoked without a per-call auth context, so all |
| 98 | // callers here are treated as anonymous — handlers are scoped to exclude |
| 99 | // user-bookmarked URLs and strip Addie-generated notes that could carry |
| 100 | // prompt-injection text from arbitrary fetched content. |
| 101 | const knowledgeHandlers = createKnowledgeToolHandlers(undefined, { anonymous: true }); |
| 102 | for (const tool of KNOWLEDGE_TOOLS) { |
| 103 | if (ANONYMOUS_SAFE_KNOWLEDGE_TOOLS.has(tool.name)) { |
| 104 | const handler = knowledgeHandlers.get(tool.name); |
| 105 | if (handler) { |
| 106 | chatClient.registerTool(tool, handler); |
| 107 | } |
| 108 | } |
| 109 | } |
| 110 | |
| 111 | // Register directory tools (public member/agent/publisher lookup - safe for anonymous) |
| 112 | const directoryHandlers = createDirectoryToolHandlers(); |
| 113 | for (const tool of DIRECTORY_TOOLS) { |
| 114 | const handler = directoryHandlers.get(tool.name); |
| 115 | if (handler) { |
| 116 | chatClient.registerTool(tool, handler); |
| 117 | } |
| 118 | } |
| 119 | |
| 120 | // Register search_members for rich card-based member search (null-safe for anonymous) |
| 121 | const anonMemberHandlers = createMemberToolHandlers(null); |
| 122 | const searchMembersTool = MEMBER_TOOLS.find(t => t.name === 'search_members'); |
| 123 | const searchMembersHandler = anonMemberHandlers.get('search_members'); |
| 124 | if (searchMembersTool && searchMembersHandler) { |
| 125 | chatClient.registerTool(searchMembersTool, searchMembersHandler); |
| 126 | } |
| 127 | |
| 128 | logger.info({ tools: chatClient.getRegisteredTools() }, 'MCP Chat: Client initialized'); |
| 129 | } |
| 130 | |
| 131 | return chatClient; |
| 132 | } |
| 133 | |
| 134 | /** |
| 135 | * The chat_with_addie tool definition |
no test coverage detected