128 lines
4.4 KiB
JavaScript
128 lines
4.4 KiB
JavaScript
#!/usr/bin/env node
|
|
|
|
import process from "node:process";
|
|
import { startHttpToolServer } from "./mcp-http.js";
|
|
import { startToolServer } from "./mcp-stdio.js";
|
|
import { parseServerArgs } from "./root-args.js";
|
|
import { TOOL_DEFINITIONS } from "./tool-definitions.js";
|
|
import { COMMAND_TOOL_DEFINITIONS } from "./command-tool-definitions.js";
|
|
import { WorkspaceService } from "./workspace-service.js";
|
|
import { CommandService } from "./command-service.js";
|
|
import { AuditLog } from "./audit-log.js";
|
|
|
|
const SERVER_NAME = "coding-agent-mcp";
|
|
const SERVER_VERSION = "1.0.0";
|
|
function parseApiKeys() {
|
|
const rawValue = process.env.CODING_AGENT_MCP_API_KEYS ?? process.env.MCP_API_KEYS ?? "";
|
|
return rawValue
|
|
.split(",")
|
|
.map((value) => value.trim())
|
|
.filter(Boolean);
|
|
}
|
|
|
|
function parseCorsOrigins() {
|
|
return (process.env.CODING_AGENT_MCP_CORS_ORIGINS ?? "")
|
|
.split(",")
|
|
.map((value) => value.trim())
|
|
.filter(Boolean);
|
|
}
|
|
|
|
function resolveExecutionBackend(transport) {
|
|
const configured = process.env.CODING_AGENT_MCP_EXECUTION_BACKEND;
|
|
if (configured) return configured;
|
|
return transport === "stdio" ? "local" : "disabled";
|
|
}
|
|
|
|
async function main() {
|
|
const options = parseServerArgs(process.argv.slice(2), {
|
|
binaryName: SERVER_NAME,
|
|
envVarName: "CODING_AGENT_MCP_ROOTS"
|
|
});
|
|
const workspaceService = new WorkspaceService({ roots: options.roots });
|
|
const auditLog = new AuditLog(process.env.CODING_AGENT_MCP_AUDIT_LOG);
|
|
const executionBackend = resolveExecutionBackend(options.transport);
|
|
const commandService = new CommandService({
|
|
roots: options.roots,
|
|
executionBackend
|
|
});
|
|
// Do not advertise a command tool that this deployment intentionally cannot execute. An agent
|
|
// cannot recover from that failure, and seeing it in tools/list makes it waste a turn trying.
|
|
const tools = executionBackend === "local"
|
|
? [...TOOL_DEFINITIONS, ...COMMAND_TOOL_DEFINITIONS]
|
|
: TOOL_DEFINITIONS;
|
|
|
|
const callTool = async (toolName, toolArguments, context) => {
|
|
switch (toolName) {
|
|
case "list_files":
|
|
return workspaceService.listFiles(toolArguments, context);
|
|
case "read_file":
|
|
return workspaceService.readFile(toolArguments, context);
|
|
case "read_files":
|
|
return workspaceService.readFiles(toolArguments, context);
|
|
case "search_text":
|
|
return workspaceService.searchText(toolArguments, context);
|
|
case "write_file":
|
|
return workspaceService.writeFile(toolArguments, context);
|
|
case "read_binary_file":
|
|
return workspaceService.readBinaryFile(toolArguments, context);
|
|
case "write_binary_file":
|
|
return workspaceService.writeBinaryFile(toolArguments, context);
|
|
case "apply_patch":
|
|
return workspaceService.applyPatch(toolArguments, context);
|
|
case "make_directory":
|
|
return workspaceService.makeDirectory(toolArguments, context);
|
|
case "delete_path":
|
|
return workspaceService.deletePath(toolArguments, context);
|
|
case "move_path":
|
|
return workspaceService.movePath(toolArguments, context);
|
|
case "rename_path":
|
|
return workspaceService.renamePath(toolArguments, context);
|
|
case "file_info":
|
|
return workspaceService.fileInfo(toolArguments, context);
|
|
case "run_task":
|
|
return commandService.runTask({
|
|
...toolArguments,
|
|
onEvent: context?.emitEvent,
|
|
sessionId: context?.sessionId ?? null,
|
|
workspaceSubpath: context?.workspaceSubpath ?? null
|
|
});
|
|
default:
|
|
throw new Error(`Unknown tool: ${toolName}`);
|
|
}
|
|
};
|
|
|
|
if (options.transport === "stdio" || options.transport === "both") {
|
|
startToolServer({
|
|
serverName: SERVER_NAME,
|
|
serverVersion: SERVER_VERSION,
|
|
tools,
|
|
callTool,
|
|
auditLog
|
|
});
|
|
}
|
|
|
|
if (options.transport === "http" || options.transport === "both") {
|
|
const listener = await startHttpToolServer({
|
|
serverName: SERVER_NAME,
|
|
serverVersion: SERVER_VERSION,
|
|
tools,
|
|
callTool,
|
|
onSessionInitialize: (context) => workspaceService.ensureWorkspace(context),
|
|
auditLog,
|
|
host: options.host,
|
|
port: options.port,
|
|
apiKeys: parseApiKeys(),
|
|
corsOrigins: parseCorsOrigins(),
|
|
requireAuth: true
|
|
});
|
|
process.stderr.write(
|
|
`${SERVER_NAME} HTTP listening on http://${listener.host}:${listener.port}\n`
|
|
);
|
|
}
|
|
}
|
|
|
|
main().catch((error) => {
|
|
process.stderr.write(`${error instanceof Error ? error.stack : String(error)}\n`);
|
|
process.exit(1);
|
|
});
|