feat: add change_title MCP tool support to OpenCode

This commit is contained in:
weishu
2026-01-29 10:53:15 +08:00
parent 70b5c22c8f
commit 7e0b139d24
5 changed files with 138 additions and 1 deletions
+81
View File
@@ -0,0 +1,81 @@
/**
* OpenCode configuration file generator.
*
* Generates opencode.json with MCP server configuration and instructions
* for the hapi change_title tool.
*/
import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
import { join } from 'node:path';
const CONFIG_FILENAME = 'opencode.json';
const INSTRUCTIONS_FILENAME = 'hapi-instructions.md';
interface McpServerEntry {
command: string;
args: string[];
}
interface OpencodeConfig {
$schema: string;
mcp: Record<string, {
type: string;
command: string[];
enabled: boolean;
}>;
instructions: string[];
}
/**
* Ensures the opencode.json config file exists with MCP server and instructions.
*
* @param rootPath - The OPENCODE_CONFIG_DIR path
* @param mcpServer - The hapi MCP server command configuration
* @param instructions - The instruction text to write to the instructions file
*/
export function ensureOpencodeConfig(
rootPath: string,
mcpServer: McpServerEntry,
instructions: string
): { configPath: string; instructionsPath: string } {
mkdirSync(rootPath, { recursive: true });
// Write instructions file
const instructionsPath = join(rootPath, INSTRUCTIONS_FILENAME);
writeFileSafe(instructionsPath, instructions);
// Build opencode.json config
// Use absolute path for instructions since OpenCode resolves paths relative to project root
const config: OpencodeConfig = {
$schema: 'https://opencode.ai/config.json',
mcp: {
hapi: {
type: 'local',
command: [mcpServer.command, ...mcpServer.args],
enabled: true
}
},
instructions: [instructionsPath]
};
const configPath = join(rootPath, CONFIG_FILENAME);
const configJson = JSON.stringify(config, null, 2);
writeFileSafe(configPath, configJson);
return { configPath, instructionsPath };
}
/**
* Write file only if content has changed.
*/
function writeFileSafe(filePath: string, content: string): void {
try {
const current = readFileSync(filePath, 'utf-8');
if (current === content) {
return;
}
} catch {
// Ignore missing or unreadable file
}
writeFileSync(filePath, content, 'utf-8');
}
+20
View File
@@ -0,0 +1,20 @@
/**
* OpenCode-specific system prompt for change_title tool.
*
* OpenCode exposes MCP tools with the naming pattern: <server-name>_<tool-name>
* The hapi MCP server exposes `change_title`, so it's called as `hapi_change_title`.
*/
import { trimIdent } from '@/utils/trimIdent';
/**
* Title instruction for OpenCode to call the hapi MCP tool.
*/
export const TITLE_INSTRUCTION = trimIdent(`
ALWAYS when you start a new chat - you must call the tool "hapi_change_title" to set a chat title. When you think chat title is not relevant anymore - call the tool again to change it. When chat name is too generic and you have a chance to make it more specific - call the tool again to change it. This title is needed to easily find the chat in the future. Help human.
`);
/**
* The system prompt to inject for OpenCode sessions.
*/
export const opencodeSystemPrompt = TITLE_INSTRUCTION;