fix: load ejclaw mcp tools on claude first turn
This commit is contained in:
@@ -60,6 +60,7 @@ import {
|
||||
createSanitizeBashHook,
|
||||
} from './runner-hooks.js';
|
||||
import { buildClaudeSdkEnv } from './sdk-env.js';
|
||||
import { buildEjclawMcpServerConfig } from './mcp-config.js';
|
||||
|
||||
interface RunnerInput {
|
||||
prompt: string;
|
||||
@@ -299,23 +300,15 @@ async function runQuery(
|
||||
settingSources: ['project', 'user'],
|
||||
abortController: agentAbortController,
|
||||
mcpServers: {
|
||||
ejclaw: {
|
||||
command: 'node',
|
||||
args: [mcpServerPath],
|
||||
env: {
|
||||
EJCLAW_CHAT_JID: runnerInput.chatJid,
|
||||
EJCLAW_GROUP_FOLDER: runnerInput.groupFolder,
|
||||
EJCLAW_IS_MAIN: runnerInput.isMain ? '1' : '0',
|
||||
EJCLAW_AGENT_TYPE: process.env.EJCLAW_AGENT_TYPE || 'claude-code',
|
||||
EJCLAW_ROOM_ROLE: runnerInput.roomRoleContext?.role || '',
|
||||
...(process.env.EJCLAW_IPC_DIR && {
|
||||
EJCLAW_IPC_DIR: process.env.EJCLAW_IPC_DIR,
|
||||
}),
|
||||
...(process.env.EJCLAW_HOST_IPC_DIR && {
|
||||
EJCLAW_HOST_IPC_DIR: process.env.EJCLAW_HOST_IPC_DIR,
|
||||
}),
|
||||
},
|
||||
},
|
||||
ejclaw: buildEjclawMcpServerConfig(mcpServerPath, {
|
||||
chatJid: runnerInput.chatJid,
|
||||
groupFolder: runnerInput.groupFolder,
|
||||
isMain: runnerInput.isMain,
|
||||
agentType: process.env.EJCLAW_AGENT_TYPE || 'claude-code',
|
||||
roomRole: runnerInput.roomRoleContext?.role || '',
|
||||
ipcDir: process.env.EJCLAW_IPC_DIR,
|
||||
hostIpcDir: process.env.EJCLAW_HOST_IPC_DIR,
|
||||
}),
|
||||
},
|
||||
hooks: {
|
||||
PreCompact: [
|
||||
|
||||
35
runners/agent-runner/src/mcp-config.ts
Normal file
35
runners/agent-runner/src/mcp-config.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import type { McpStdioServerConfig } from '@anthropic-ai/claude-agent-sdk';
|
||||
|
||||
export interface EjclawMcpServerConfigInput {
|
||||
chatJid: string;
|
||||
groupFolder: string;
|
||||
isMain: boolean;
|
||||
agentType: string;
|
||||
roomRole: string;
|
||||
ipcDir?: string;
|
||||
hostIpcDir?: string;
|
||||
}
|
||||
|
||||
export function buildEjclawMcpServerConfig(
|
||||
mcpServerPath: string,
|
||||
input: EjclawMcpServerConfigInput,
|
||||
): McpStdioServerConfig {
|
||||
return {
|
||||
command: 'node',
|
||||
args: [mcpServerPath],
|
||||
alwaysLoad: true,
|
||||
env: {
|
||||
EJCLAW_CHAT_JID: input.chatJid,
|
||||
EJCLAW_GROUP_FOLDER: input.groupFolder,
|
||||
EJCLAW_IS_MAIN: input.isMain ? '1' : '0',
|
||||
EJCLAW_AGENT_TYPE: input.agentType,
|
||||
EJCLAW_ROOM_ROLE: input.roomRole,
|
||||
...(input.ipcDir && {
|
||||
EJCLAW_IPC_DIR: input.ipcDir,
|
||||
}),
|
||||
...(input.hostIpcDir && {
|
||||
EJCLAW_HOST_IPC_DIR: input.hostIpcDir,
|
||||
}),
|
||||
},
|
||||
};
|
||||
}
|
||||
32
runners/agent-runner/test/mcp-config.test.ts
Normal file
32
runners/agent-runner/test/mcp-config.test.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
import { buildEjclawMcpServerConfig } from '../src/mcp-config.js';
|
||||
|
||||
describe('ejclaw MCP config', () => {
|
||||
it('always loads EJClaw MCP tools on turn one and preserves runtime env', () => {
|
||||
expect(
|
||||
buildEjclawMcpServerConfig('/runner/dist/ipc-mcp-stdio.js', {
|
||||
chatJid: 'dc:room',
|
||||
groupFolder: 'ejclaw',
|
||||
isMain: true,
|
||||
agentType: 'claude-code',
|
||||
roomRole: 'reviewer',
|
||||
ipcDir: '/tmp/ipc/task',
|
||||
hostIpcDir: '/tmp/ipc/host',
|
||||
}),
|
||||
).toEqual({
|
||||
command: 'node',
|
||||
args: ['/runner/dist/ipc-mcp-stdio.js'],
|
||||
alwaysLoad: true,
|
||||
env: {
|
||||
EJCLAW_CHAT_JID: 'dc:room',
|
||||
EJCLAW_GROUP_FOLDER: 'ejclaw',
|
||||
EJCLAW_IS_MAIN: '1',
|
||||
EJCLAW_AGENT_TYPE: 'claude-code',
|
||||
EJCLAW_ROOM_ROLE: 'reviewer',
|
||||
EJCLAW_IPC_DIR: '/tmp/ipc/task',
|
||||
EJCLAW_HOST_IPC_DIR: '/tmp/ipc/host',
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -8,7 +8,7 @@
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./src/index.ts",
|
||||
"default": "./src/index.ts"
|
||||
"default": "./dist/index.js"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
|
||||
19
runners/shared/test/package-exports.test.ts
Normal file
19
runners/shared/test/package-exports.test.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
describe('runner shared package exports', () => {
|
||||
it('points runtime imports at built JavaScript for node-launched MCP servers', () => {
|
||||
const packageJson = JSON.parse(
|
||||
fs.readFileSync(
|
||||
path.resolve(import.meta.dirname, '../package.json'),
|
||||
'utf8',
|
||||
),
|
||||
) as { exports: { '.': { default: string; types: string } } };
|
||||
|
||||
expect(packageJson.exports['.']).toEqual({
|
||||
types: './src/index.ts',
|
||||
default: './dist/index.js',
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user