///
/**
* MCP Adapter — Tool Definitions (RFC-0068)
*
* Exposes 4 core harness capabilities as MCP tools.
*/
import type { MCPTool, ToolCallResult } from "./types.js";
export const HARNESS_TOOLS: MCPTool[] = [
{
name: "analyze_workspace",
description:
"Analyze a codebase directory to detect framework, structure, and dependencies",
inputSchema: {
type: "object",
properties: {
path: {
type: "string",
description: "Absolute path to workspace directory",
},
framework: {
type: "string",
description: "Force specific framework detection",
},
},
required: ["path"],
},
},
{
name: "search_memory",
description:
"Search the harness persistent memory store for relevant knowledge",
inputSchema: {
type: "object",
properties: {
query: { type: "string", description: "Search query" },
limit: { type: "number", description: "Max results (default: 5)" },
},
required: ["query"],
},
},
{
name: "list_skills",
description:
"List all registered harness skills with their triggers and capabilities",
inputSchema: {
type: "object",
properties: {
capability: {
type: "string",
description: "Filter by capability type",
},
},
},
},
{
name: "invoke_skill",
description: "Invoke a named harness skill with a trigger",
inputSchema: {
type: "object",
properties: {
name: { type: "string", description: "Skill name to invoke" },
trigger: {
type: "object",
description: "Trigger object with type and value",
properties: {
type: { type: "string", enum: ["keyword", "intent", "pattern"] },
value: { type: "string" },
confidence: { type: "number" },
},
required: ["type", "value"],
},
context: { type: "object", description: "Optional context overrides" },
},
required: ["name", "trigger"],
},
},
];
/**
* Tool handler function — maps MCP tool name to harness capability
*/
export async function handleToolCall(
toolName: string,
args?: Record,
): Promise {
try {
switch (toolName) {
case "analyze_workspace":
return handleAnalyzeWorkspace(args as unknown as AnalyzeArgs);
case "search_memory":
return handleSearchMemory(args as unknown as SearchArgs);
case "list_skills":
return handleListSkills(args as unknown as ListSkillsArgs);
case "invoke_skill":
return handleInvokeSkill(args as unknown as InvokeSkillArgs);
default:
return {
content: [{ type: "text", text: `Unknown tool: ${toolName}` }],
isError: true,
};
}
} catch (err) {
const msg = err instanceof Error ? err.message : String(err);
return { content: [{ type: "text", text: msg }], isError: true };
}
}
interface AnalyzeArgs {
path: string;
framework?: string;
}
interface SearchArgs {
query: string;
limit?: number;
}
interface ListSkillsArgs {
capability?: string;
}
interface InvokeSkillArgs {
name: string;
trigger: { type: string; value: string; confidence?: number };
context?: Record;
}
async function handleAnalyzeWorkspace(
args: AnalyzeArgs,
): Promise {
const { path } = args;
const fs = await import("node:fs");
const pathModule = await import("node:path");
if (!fs.existsSync(path)) {
return {
content: [{ type: "text", text: `Path does not exist: ${path}` }],
isError: true,
};
}
// Basic framework detection from filesystem
const files = fs.readdirSync(path);
const frameworks: string[] = [];
if (files.includes("package.json")) frameworks.push("node");
if (files.includes("go.mod")) frameworks.push("go");
if (files.includes("Cargo.toml")) frameworks.push("rust");
if (files.includes("pyproject.toml") || files.includes("requirements.txt"))
frameworks.push("python");
if (files.includes("composer.json")) frameworks.push("php");
if (
files.includes("frappe-bench") ||
fs.existsSync(pathModule.join(path, "sites"))
) {
frameworks.push("frappe");
}
if (files.includes("next.config.js") || files.includes("next.config.ts"))
frameworks.push("nextjs");
if (files.includes("vite.config.ts")) frameworks.push("react-vite");
if (files.includes("manage.py")) frameworks.push("django");
const result = JSON.stringify(
{ path, frameworks, fileCount: files.length },
null,
2,
);
return { content: [{ type: "text", text: result }] };
}
async function handleSearchMemory(args: SearchArgs): Promise {
const { query, limit = 5 } = args;
return {
content: [
{
type: "text",
text: JSON.stringify({
query,
limit,
results: [],
note: "Memory search requires runtime integration",
}),
},
],
};
}
async function handleListSkills(args: ListSkillsArgs): Promise {
const { capability } = args;
return {
content: [
{
type: "text",
text: JSON.stringify({
capability,
skills: [],
note: "Skill registry requires runtime integration",
}),
},
],
};
}
async function handleInvokeSkill(
args: InvokeSkillArgs,
): Promise {
const { name, trigger, context } = args;
return {
content: [
{
type: "text",
text: JSON.stringify({
skill: name,
trigger,
context,
note: "Skill invocation requires runtime integration",
}),
},
],
};
}