fix: simplified tool list. 10 removed, in favor of more unified tools

This commit is contained in:
ajspig 2026-03-20 16:23:54 -04:00
parent b05ed4e7c6
commit 4a5f4364cd
6 changed files with 100 additions and 342 deletions

View File

@ -1,5 +1,6 @@
{
"lockfileVersion": 1,
"configVersion": 0,
"workspaces": {
"": {
"name": "honcho-mcp-proxy",
@ -7,6 +8,7 @@
"@honcho-ai/sdk": "^2.0.0",
"@modelcontextprotocol/sdk": "^1.26.0",
"agents": "^0.4.0",
"nanoid": "^5.1.7",
"zod": "^4.3.6",
},
"devDependencies": {
@ -373,7 +375,7 @@
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
"nanoid": ["nanoid@5.1.6", "", { "bin": { "nanoid": "bin/nanoid.js" } }, "sha512-c7+7RQ+dMB5dPwwCp4ee1/iV/q2P6aK1mTZcfr1BTuVlyW9hJYiMPybJCcnBlQtuSmTIWNeazm/zqNoZSSElBg=="],
"nanoid": ["nanoid@5.1.7", "", { "bin": { "nanoid": "bin/nanoid.js" } }, "sha512-ua3NDgISf6jdwezAheMOk4mbE1LXjm1DfMUDMuJf4AqxLFK3ccGpgWizwa5YV7Yz9EpXwEaWoRXSb/BnV0t5dQ=="],
"negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="],
@ -507,10 +509,14 @@
"@honcho-ai/sdk/zod": ["zod@4.0.0", "", {}, "sha512-9diLdTPc/L7w/5jI4C3gHYNiGHDV9IZYxo1e5LSD8cabi65WVTWWb+g2BGPEpUUCOxR4D+6O5B0AzyMdUAXwrw=="],
"agents/nanoid": ["nanoid@5.1.6", "", { "bin": { "nanoid": "bin/nanoid.js" } }, "sha512-c7+7RQ+dMB5dPwwCp4ee1/iV/q2P6aK1mTZcfr1BTuVlyW9hJYiMPybJCcnBlQtuSmTIWNeazm/zqNoZSSElBg=="],
"mimetext/mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="],
"miniflare/zod": ["zod@3.22.3", "", {}, "sha512-EjIevzuJRiRPbVH4mGc8nApb/lVLKVpmUhAaR5R5doKGfAnGJ6Gr3CViAVjP+4FWSxCsybeWQdcgCtbX+7oZug=="],
"partyserver/nanoid": ["nanoid@5.1.6", "", { "bin": { "nanoid": "bin/nanoid.js" } }, "sha512-c7+7RQ+dMB5dPwwCp4ee1/iV/q2P6aK1mTZcfr1BTuVlyW9hJYiMPybJCcnBlQtuSmTIWNeazm/zqNoZSSElBg=="],
"router/path-to-regexp": ["path-to-regexp@8.3.0", "", {}, "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA=="],
"youch/cookie": ["cookie@1.0.2", "", {}, "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA=="],

View File

@ -39,9 +39,9 @@ export function parseConfig(request: Request): HonchoConfig {
baseUrl:
request.headers.get("X-Honcho-Base-URL")?.trim() ||
"https://api.honcho.dev",
workspaceId: request.headers.get("X-Honcho-Workspace-ID") || "default",
workspaceId: request.headers.get("X-Honcho-Workspace-ID")?.trim() || "default",
assistantName:
request.headers.get("X-Honcho-Assistant-Name") || "Assistant",
request.headers.get("X-Honcho-Assistant-Name")?.trim() || "Assistant",
};
}

View File

@ -12,7 +12,8 @@ export function register(server: McpServer, ctx: ToolContext) {
description: [
"Start a new conversation for the current user.",
"Call this once at the beginning of every new conversation.",
"Returns a session_id you must pass to add_turn and get_personalization_insights for the rest of this conversation.",
"Returns session_id, user_peer_id, and assistant_peer_id.",
"Use the peer IDs with add_messages_to_session to record turns.",
].join("\n"),
inputSchema: {},
},
@ -32,7 +33,11 @@ export function register(server: McpServer, ctx: ToolContext) {
[assistantPeer, { observeMe: null, observeOthers: false }],
]);
return textResult(sessionId);
return textResult({
session_id: sessionId,
user_peer_id: userPeer.id,
assistant_peer_id: assistantPeer.id,
});
} catch (e) {
return errorResult(
`Failed to start conversation: ${e instanceof Error ? e.message : String(e)}`,
@ -40,97 +45,4 @@ export function register(server: McpServer, ctx: ToolContext) {
}
},
);
// ── add_turn ────────────────────────────────────────────────────────
server.registerTool(
"add_turn",
{
description: [
"Record a userassistant exchange in the current conversation.",
"Call this after every assistant response so Honcho can learn from the conversation.",
"Pass the full messages array containing both the user's message and your response.",
].join("\n"),
inputSchema: {
session_id: z.string().describe("Session ID from start_conversation."),
messages: z
.array(
z.object({
role: z
.enum(["user", "assistant"])
.describe("Who sent the message."),
content: z.string().describe("Message text."),
metadata: z
.record(z.string(), z.unknown())
.optional()
.describe("Optional metadata."),
}),
)
.describe("Ordered list of messages in this turn."),
},
},
async ({ session_id, messages }) => {
try {
const session = await ctx.honcho.session(session_id);
const userPeer = await ctx.honcho.peer(ctx.config.userName);
const assistantPeer = await ctx.honcho.peer(ctx.config.assistantName);
const sessionMessages = messages.map((msg) => {
const peer = msg.role === "user" ? userPeer : assistantPeer;
return msg.metadata
? peer.message(msg.content, { metadata: msg.metadata })
: peer.message(msg.content);
});
await session.addMessages(sessionMessages);
return textResult("Turn added successfully");
} catch (e) {
return errorResult(
`Failed to add turn: ${e instanceof Error ? e.message : String(e)}`,
);
}
},
);
// ── get_personalization_insights ────────────────────────────────────
server.registerTool(
"get_personalization_insights",
{
description: [
"Ask Honcho a natural-language question about the user and get a personalized answer",
"grounded in everything Honcho has learned across all of the user's conversations.",
"Use this before responding when personalization would genuinely improve your response — it takes a few seconds.",
"Returns a natural-language answer.",
].join("\n"),
inputSchema: {
session_id: z
.string()
.describe("Session ID from start_conversation, for context."),
query: z
.string()
.describe(
"Natural-language question about the user (e.g. 'What communication style does this user prefer?').",
),
reasoning_level: z
.enum(["minimal", "low", "medium", "high", "max"])
.optional()
.describe(
"How much reasoning effort to use. Higher = more detailed but slower. Default: 'low'.",
),
},
},
async ({ session_id, query, reasoning_level }) => {
try {
const userPeer = await ctx.honcho.peer(ctx.config.userName);
const result = await userPeer.chat(query, {
session: session_id,
reasoningLevel: reasoning_level,
});
return textResult(result ?? "No personalization insights found.");
} catch (e) {
return errorResult(
`Failed to get insights: ${e instanceof Error ? e.message : String(e)}`,
);
}
},
);
}

View File

@ -1,7 +1,7 @@
import { z } from "zod";
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import type { ToolContext } from "../types.js";
import { textResult, errorResult, formatMessages } from "../types.js";
import { textResult, errorResult } from "../types.js";
export function register(server: McpServer, ctx: ToolContext) {
// ── create_peer ─────────────────────────────────────────────────────
@ -276,83 +276,4 @@ export function register(server: McpServer, ctx: ToolContext) {
}
},
);
// ── get_peer_metadata ───────────────────────────────────────────────
server.registerTool(
"get_peer_metadata",
{
description: [
"Get metadata for a peer.",
].join("\n"),
inputSchema: {
peer_id: z.string().describe("The peer to get metadata for."),
},
},
async ({ peer_id }) => {
try {
const peer = await ctx.honcho.peer(peer_id);
const metadata = await peer.getMetadata();
return textResult(metadata);
} catch (e) {
return errorResult(
`Failed to get peer metadata: ${e instanceof Error ? e.message : String(e)}`,
);
}
},
);
// ── set_peer_metadata ───────────────────────────────────────────────
server.registerTool(
"set_peer_metadata",
{
description: [
"Set metadata for a peer.",
"Overwrites existing metadata.",
].join("\n"),
inputSchema: {
peer_id: z.string().describe("The peer to set metadata for."),
metadata: z
.record(z.string(), z.unknown())
.describe("Key-value pairs to set."),
},
},
async ({ peer_id, metadata }) => {
try {
const peer = await ctx.honcho.peer(peer_id);
await peer.setMetadata(metadata);
return textResult("Peer metadata set successfully");
} catch (e) {
return errorResult(
`Failed to set peer metadata: ${e instanceof Error ? e.message : String(e)}`,
);
}
},
);
// ── search_peer_messages ────────────────────────────────────────────
server.registerTool(
"search_peer_messages",
{
description: [
"Semantic search across all messages authored by a specific peer.",
"Use this to find what a particular peer has said across all sessions.",
"Returns an array of matching messages.",
].join("\n"),
inputSchema: {
peer_id: z.string().describe("The peer whose messages to search."),
query: z.string().describe("Search query."),
},
},
async ({ peer_id, query }) => {
try {
const peer = await ctx.honcho.peer(peer_id);
const messages = await peer.search(query);
return textResult(formatMessages(messages));
} catch (e) {
return errorResult(
`Search failed: ${e instanceof Error ? e.message : String(e)}`,
);
}
},
);
}

View File

@ -270,8 +270,8 @@ export function register(server: McpServer, ctx: ToolContext) {
{
description: [
"Add messages to a session from specific peers.",
"Use this for multi-peer conversations where you need to attribute messages to specific peers.",
"For the simple user/assistant flow, use add_turn instead.",
"Use this to record conversation turns. Each message must specify the peer_id of the author.",
"For the bespoke flow, use start_conversation first to get the user_peer_id and assistant_peer_id.",
].join("\n"),
inputSchema: {
session_id: z.string().describe("The session to add messages to."),
@ -391,33 +391,6 @@ export function register(server: McpServer, ctx: ToolContext) {
},
);
// ── search_session_messages ─────────────────────────────────────────
server.registerTool(
"search_session_messages",
{
description: [
"Semantic search across messages in a specific session.",
"Use this to find relevant messages within a single conversation.",
"Returns an array of matching messages.",
].join("\n"),
inputSchema: {
session_id: z.string().describe("The session to search in."),
query: z.string().describe("Search query."),
},
},
async ({ session_id, query }) => {
try {
const session = await ctx.honcho.session(session_id);
const messages = await session.search(query);
return textResult(formatMessages(messages));
} catch (e) {
return errorResult(
`Search failed: ${e instanceof Error ? e.message : String(e)}`,
);
}
},
);
// ── get_session_context ─────────────────────────────────────────────
server.registerTool(
"get_session_context",
@ -456,119 +429,4 @@ export function register(server: McpServer, ctx: ToolContext) {
}
},
);
// ── get_session_summaries ───────────────────────────────────────────
server.registerTool(
"get_session_summaries",
{
description: [
"Get the short and long summaries available for a session.",
"Use this when you want Honcho's generated rollups of the conversation so far.",
"Returns the session ID plus short and long summary objects when available.",
].join("\n"),
inputSchema: {
session_id: z.string().describe("The session to get summaries for."),
},
},
async ({ session_id }) => {
try {
const session = await ctx.honcho.session(session_id);
const summaries = await session.summaries();
return textResult(formatSessionSummaries(summaries));
} catch (e) {
return errorResult(
`Failed to get session summaries: ${e instanceof Error ? e.message : String(e)}`,
);
}
},
);
// ── get_session_representation ──────────────────────────────────────
server.registerTool(
"get_session_representation",
{
description: [
"Get a peer's representation scoped to a specific session.",
"Use this to see what Honcho has learned about a peer from a single conversation.",
"Returns a formatted string of session-scoped conclusions.",
].join("\n"),
inputSchema: {
session_id: z.string().describe("The session to scope to."),
peer_id: z
.string()
.describe("The peer to get the representation for."),
target_peer_id: z
.string()
.optional()
.describe(
"Optional: get what peer_id knows about target_peer_id in this session.",
),
},
},
async ({ session_id, peer_id, target_peer_id }) => {
try {
const session = await ctx.honcho.session(session_id);
const rep = await session.representation(peer_id, {
target: target_peer_id,
});
return textResult(rep);
} catch (e) {
return errorResult(
`Failed to get representation: ${e instanceof Error ? e.message : String(e)}`,
);
}
},
);
// ── get_session_metadata ────────────────────────────────────────────
server.registerTool(
"get_session_metadata",
{
description: [
"Get metadata for a session.",
].join("\n"),
inputSchema: {
session_id: z.string().describe("The session to get metadata for."),
},
},
async ({ session_id }) => {
try {
const session = await ctx.honcho.session(session_id);
const metadata = await session.getMetadata();
return textResult(metadata);
} catch (e) {
return errorResult(
`Failed to get session metadata: ${e instanceof Error ? e.message : String(e)}`,
);
}
},
);
// ── set_session_metadata ────────────────────────────────────────────
server.registerTool(
"set_session_metadata",
{
description: [
"Set metadata for a session.",
"Overwrites existing metadata.",
].join("\n"),
inputSchema: {
session_id: z.string().describe("The session to set metadata for."),
metadata: z
.record(z.string(), z.unknown())
.describe("Key-value pairs to set."),
},
},
async ({ session_id, metadata }) => {
try {
const session = await ctx.honcho.session(session_id);
await session.setMetadata(metadata);
return textResult("Session metadata set successfully");
} catch (e) {
return errorResult(
`Failed to set session metadata: ${e instanceof Error ? e.message : String(e)}`,
);
}
},
);
}

View File

@ -69,22 +69,41 @@ export function register(server: McpServer, ctx: ToolContext) {
},
);
// ── search_workspace ────────────────────────────────────────────────
// ── search ────────────────────────────────────────────────────────
server.registerTool(
"search_workspace",
"search",
{
description: [
"Semantic search across all messages in the workspace.",
"Use this to find past conversations or messages from any peer/session.",
"Semantic search across messages. Scope is determined by which optional params are provided:",
"- No scope params: search all messages in the workspace.",
"- peer_id only: search messages authored by that peer across all sessions.",
"- session_id only: search messages within that session.",
"Returns an array of matching messages with their content, peer, and session info.",
].join("\n"),
inputSchema: {
query: z.string().describe("Search query."),
peer_id: z
.string()
.optional()
.describe("Optional: scope search to messages by this peer."),
session_id: z
.string()
.optional()
.describe("Optional: scope search to messages in this session."),
},
},
async ({ query }) => {
async ({ query, peer_id, session_id }) => {
try {
const messages = await ctx.honcho.search(query);
let messages;
if (session_id) {
const session = await ctx.honcho.session(session_id);
messages = await session.search(query);
} else if (peer_id) {
const peer = await ctx.honcho.peer(peer_id);
messages = await peer.search(query);
} else {
messages = await ctx.honcho.search(query);
}
return textResult(formatMessages(messages));
} catch (e) {
return errorResult(
@ -94,18 +113,39 @@ export function register(server: McpServer, ctx: ToolContext) {
},
);
// ── get_workspace_metadata ──────────────────────────────────────────
// ── get_metadata ──────────────────────────────────────────────────
server.registerTool(
"get_workspace_metadata",
"get_metadata",
{
description: [
"Get metadata for the current workspace.",
"Get metadata for a resource. Scope is determined by which optional params are provided:",
"- No scope params: get workspace metadata.",
"- peer_id only: get peer metadata.",
"- session_id only: get session metadata.",
].join("\n"),
inputSchema: {},
inputSchema: {
peer_id: z
.string()
.optional()
.describe("Optional: get metadata for this peer."),
session_id: z
.string()
.optional()
.describe("Optional: get metadata for this session."),
},
},
async () => {
async ({ peer_id, session_id }) => {
try {
const metadata = await ctx.honcho.getMetadata();
let metadata;
if (session_id) {
const session = await ctx.honcho.session(session_id);
metadata = await session.getMetadata();
} else if (peer_id) {
const peer = await ctx.honcho.peer(peer_id);
metadata = await peer.getMetadata();
} else {
metadata = await ctx.honcho.getMetadata();
}
return textResult(metadata);
} catch (e) {
return errorResult(
@ -115,24 +155,45 @@ export function register(server: McpServer, ctx: ToolContext) {
},
);
// ── set_workspace_metadata ──────────────────────────────────────────
// ── set_metadata ──────────────────────────────────────────────────
server.registerTool(
"set_workspace_metadata",
"set_metadata",
{
description: [
"Set metadata for the current workspace.",
"Overwrites existing metadata.",
"Set metadata for a resource. Overwrites existing metadata.",
"Scope is determined by which optional params are provided:",
"- No scope params: set workspace metadata.",
"- peer_id only: set peer metadata.",
"- session_id only: set session metadata.",
].join("\n"),
inputSchema: {
metadata: z
.record(z.string(), z.unknown())
.describe("Key-value pairs to set as workspace metadata."),
.describe("Key-value pairs to set as metadata."),
peer_id: z
.string()
.optional()
.describe("Optional: set metadata for this peer."),
session_id: z
.string()
.optional()
.describe("Optional: set metadata for this session."),
},
},
async ({ metadata }) => {
async ({ metadata, peer_id, session_id }) => {
try {
await ctx.honcho.setMetadata(metadata);
return textResult("Workspace metadata set successfully");
if (session_id) {
const session = await ctx.honcho.session(session_id);
await session.setMetadata(metadata);
return textResult("Session metadata set successfully");
} else if (peer_id) {
const peer = await ctx.honcho.peer(peer_id);
await peer.setMetadata(metadata);
return textResult("Peer metadata set successfully");
} else {
await ctx.honcho.setMetadata(metadata);
return textResult("Workspace metadata set successfully");
}
} catch (e) {
return errorResult(
`Failed to set metadata: ${e instanceof Error ? e.message : String(e)}`,