import { z } from "zod";
import { getUserContext } from "../helpers/getUser.js";
import { squadClient } from "../lib/clients/squad.js";
import { logger } from "../lib/logger.js";
import {
formatWorkspaceSelectionError,
getUserId,
type OAuthServer,
toolError,
toolSuccess,
WorkspaceSelectionRequired,
} from "./helpers.js";
/**
* Register knowledge tools with the MCP server
*/
export function registerKnowledgeTools(server: OAuthServer) {
// Create Knowledge
server.tool(
{
name: "create_knowledge",
title: "Create Knowledge Document",
description:
"Create a new knowledge entry. Knowledge entries are text documents that can be used as references or information sources.",
schema: z.object({
title: z.string().describe("A short title for the knowledge"),
description: z
.string()
.describe("A short summary of the knowledge content"),
content: z.string().describe("The full content of the knowledge"),
}),
annotations: {
readOnlyHint: false,
destructiveHint: true,
},
},
async (params, ctx) => {
try {
const userContext = await getUserContext(
ctx.auth.accessToken,
getUserId(ctx.auth),
);
const { orgId, workspaceId } = userContext;
const result = await squadClient(userContext).createKnowledge({
orgId,
workspaceId,
createKnowledgePayload: {
title: params.title,
description: params.description,
content: params.content,
},
});
return toolSuccess({
id: result.data.id,
title: result.data.title,
message: "Knowledge entry created successfully",
});
} catch (error) {
if (error instanceof WorkspaceSelectionRequired) {
return toolError(formatWorkspaceSelectionError(error));
}
logger.debug(
{ err: error, tool: "create_knowledge_document" },
"Tool error",
);
const message =
error instanceof Error ? error.message : "Unknown error";
return toolError(`Unable to create knowledge: ${message}`);
}
},
);
// List Knowledge
server.tool(
{
name: "list_knowledge",
title: "List Knowledge Documents",
description:
"List all knowledge entries in the workspace. Knowledge entries are text documents that can be used as references or information sources. List only shows the available items and a short description for the actual knowledge use the get by id call.",
schema: z.object({}),
annotations: {
readOnlyHint: true,
destructiveHint: false,
},
},
async (_params, ctx) => {
try {
const userContext = await getUserContext(
ctx.auth.accessToken,
getUserId(ctx.auth),
);
const { orgId, workspaceId } = userContext;
const knowledge = await squadClient(userContext).listKnowledge({
orgId,
workspaceId,
});
if (knowledge.data.length === 0) {
return toolSuccess({ message: "No knowledge entries found." });
}
// Return summaries to reduce token usage - use get_knowledge for full details
return toolSuccess({
count: knowledge.data.length,
items: knowledge.data.map(k => ({
id: k.id,
title: k.title,
description: k.description,
})),
});
} catch (error) {
if (error instanceof WorkspaceSelectionRequired) {
return toolError(formatWorkspaceSelectionError(error));
}
logger.debug(
{ err: error, tool: "list_knowledge_documents" },
"Tool error",
);
const message =
error instanceof Error ? error.message : "Unknown error";
return toolError(`Unable to list knowledge: ${message}`);
}
},
);
// Get Knowledge
server.tool(
{
name: "get_knowledge",
title: "Get Knowledge Document",
description:
"Get details of a specific knowledge entry by ID. Knowledge entries are text documents that can be used as references or information sources.",
schema: z.object({
knowledgeId: z
.string()
.describe("The ID of the knowledge entry to retrieve"),
}),
annotations: {
readOnlyHint: true,
destructiveHint: false,
},
},
async (params, ctx) => {
try {
const userContext = await getUserContext(
ctx.auth.accessToken,
getUserId(ctx.auth),
);
const { orgId, workspaceId } = userContext;
const knowledge = await squadClient(userContext).getKnowledge({
orgId,
workspaceId,
knowledgeId: params.knowledgeId,
});
return toolSuccess(knowledge);
} catch (error) {
if (error instanceof WorkspaceSelectionRequired) {
return toolError(formatWorkspaceSelectionError(error));
}
logger.debug(
{ err: error, tool: "get_knowledge_document" },
"Tool error",
);
const message =
error instanceof Error ? error.message : "Unknown error";
return toolError(`Unable to get knowledge: ${message}`);
}
},
);
// Delete Knowledge
server.tool(
{
name: "delete_knowledge",
title: "Delete Knowledge Document",
description: "Delete a knowledge entry by ID.",
schema: z.object({
knowledgeId: z
.string()
.describe("The ID of the knowledge entry to delete"),
}),
annotations: {
readOnlyHint: false,
destructiveHint: true,
},
},
async (params, ctx) => {
try {
const userContext = await getUserContext(
ctx.auth.accessToken,
getUserId(ctx.auth),
);
const { orgId, workspaceId } = userContext;
const result = await squadClient(userContext).deleteKnowledge({
orgId,
workspaceId,
knowledgeId: params.knowledgeId,
});
return toolSuccess(result);
} catch (error) {
if (error instanceof WorkspaceSelectionRequired) {
return toolError(formatWorkspaceSelectionError(error));
}
logger.debug(
{ err: error, tool: "delete_knowledge_document" },
"Tool error",
);
const message =
error instanceof Error ? error.message : "Unknown error";
return toolError(`Unable to delete knowledge: ${message}`);
}
},
);
}