Improve tool descriptions for cross-model compatibility

Add concrete parameter examples, negative routing guidance, and
format conventions to tool descriptions. Helps Gemini with literal
tool selection and GPT with over-calling prevention.
This commit is contained in:
2026-03-01 18:49:46 +00:00
parent d58fa405a2
commit 518cef51bc

View File

@@ -20,7 +20,7 @@ const server = new McpServer({
server.tool(
"search_context",
"Semantic search across all homelab documentation. Returns the most relevant sections for a natural language query. Optionally filter by document type (device, infrastructure, network, automation, tool) or hostname.",
"Semantic search across all homelab documentation and projects. Returns the most relevant sections for a natural language query. Optionally filter by document type (device, infrastructure, network, automation, tool, project) or hostname. For projects, results include project name, slug, and status — use the returned slug with get_project for full details.",
searchContextSchema.shape,
async (input) => ({
content: [{ type: "text", text: await searchContext(searchContextSchema.parse(input)) }],
@@ -47,7 +47,7 @@ server.tool(
server.tool(
"search_issues",
"Search for operational notes, troubleshooting info, known issues, and incident reports across all homelab documentation.",
"Search for operational problems, troubleshooting notes, known issues, and incident history across all homelab documentation. Searches the same collection as search_context but filters results to operational/issue-related content. Use search_context instead for general documentation lookup or project searches.",
searchIssuesSchema.shape,
async (input) => ({
content: [{ type: "text", text: await searchIssues(searchIssuesSchema.parse(input)) }],
@@ -56,7 +56,7 @@ server.tool(
server.tool(
"upsert_context",
"Create or overwrite a homelab documentation chunk. Uses a deterministic ID based on source, section, and host so repeated upserts are idempotent.",
'Create or overwrite a homelab documentation chunk. Uses a deterministic ID based on source, section, and host so repeated upserts are idempotent. Example: {host: "proxmox", section: "GPU Passthrough", source: "devices/proxmox.md", type: "device", text: "...", tags: ["gpu", "nvidia"]}. source uses path-like format, host is the hostname, section is a human-readable heading.',
upsertContextSchema.shape,
async (input) => ({
content: [{ type: "text", text: await upsertContext(upsertContextSchema.parse(input)) }],
@@ -65,7 +65,7 @@ server.tool(
server.tool(
"update_context",
"Update metadata fields on existing homelab documentation chunk(s). Filter by host, source, section, or project. Optionally provide new text to trigger re-embedding.",
'Update metadata fields on existing homelab documentation chunk(s). Filter fields (host, source, section, project) select which chunks to update. new_* fields set the new values. At least one filter required. Example: {host: "proxmox", section: "GPU Passthrough", new_tags: ["gpu", "nvidia", "rtx8000"]}. Optionally provide text to trigger re-embedding.',
updateContextSchema._def.schema.shape,
async (input) => ({
content: [{ type: "text", text: await updateContext(updateContextSchema.parse(input)) }],
@@ -83,7 +83,7 @@ server.tool(
server.tool(
"list_projects",
"List all tracked projects. Filter by status (default: 'active', or 'all' for everything). Returns JSON array of project summaries.",
"List all tracked projects at a glance. Filter by status (default: 'active', or 'all' for everything). Returns JSON array of project summaries with slug, name, status, summary, tags, and updated. Use search_context with type: 'project' for semantic/topic search across projects instead.",
listProjectsSchema.shape,
async (input) => ({
content: [{ type: "text", text: await listProjects(listProjectsSchema.parse(input)) }],
@@ -101,7 +101,7 @@ server.tool(
server.tool(
"upsert_project",
"Create or update a project. On create, 'name' is required; other fields default to empty. On update, only provided fields are changed. Relationships merge at sub-key level (hosts, software, git_repos, local_dirs).",
'Use for initial project creation or full rewrites. Do NOT use for incremental changes like adding a single blocker or history entry — use update_project instead. On create, slug and name are required; other fields default to empty. On update, only provided fields are changed. Relationships merge at sub-key level (hosts, software, git_repos, local_dirs). Example creation: {slug: "led-dimming", name: "LED Dimming Controller", status: "planning", summary: "PWM-based LED dimming system", tags: ["hardware", "esphome"]}.',
upsertProjectSchema.shape,
async (input) => ({
content: [{ type: "text", text: await upsertProject(upsertProjectSchema.parse(input)) }],
@@ -110,7 +110,7 @@ server.tool(
server.tool(
"update_project",
"Apply granular mutations to an existing project. Supports scalar updates (status, summary, current_state) and array add/remove operations (blockers, tags, key_facts, history, decisions_pending, relationships).",
'Use for incremental mutations to existing projects. Supports adding/removing individual items without touching other fields. Do NOT use for initial creation — use upsert_project instead. Examples: add_blocker: "Waiting on PCB fab delivery", add_history: "2026-03-01: Deployed v1.0 to production", add_relationship: {category: "hosts", host: "proxmox", role: "compute node"}, add_relationship: {category: "git_repos", repo: "adamksmith/homelab-mcp", role: "source code"}, add_relationship: {category: "software", name: "ESPHome", role: "firmware framework", version: "2024.12"}, add_relationship: {category: "local_dirs", path: "/home/adam/projects/foo", role: "working directory"}, remove_relationship: {category: "hosts", host: "old-server"}.',
updateProjectSchema.shape,
async (input) => ({
content: [{ type: "text", text: await updateProject(updateProjectSchema.parse(input)) }],