From 17724c8e2d56f2a7ccf3b9b84a20431de1d5dbaf Mon Sep 17 00:00:00 2001 From: Gab Date: Sun, 12 Apr 2026 14:21:33 +1000 Subject: [PATCH] Bump to 1.0.31: default ToothFairy MCP tools to stored credentials When api_key and workspace_id are not provided, ToothFairy MCP tools now default to credentials stored in ~/.tfcode/credentials.json (from tfcode validate). --- packages/tfcode/package.json | 2 +- packages/tfcode/src/mcp/index.ts | 29 ++++++++++++++++++++++++++++- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/packages/tfcode/package.json b/packages/tfcode/package.json index 4cb6f62ca..003504241 100644 --- a/packages/tfcode/package.json +++ b/packages/tfcode/package.json @@ -1,6 +1,6 @@ { "$schema": "https://json.schemastore.org/package.json", - "version": "1.0.30", + "version": "1.0.31", "name": "@toothfairyai/tfcode", "type": "module", "license": "MIT", diff --git a/packages/tfcode/src/mcp/index.ts b/packages/tfcode/src/mcp/index.ts index bf5a0d3ce..0692314cc 100644 --- a/packages/tfcode/src/mcp/index.ts +++ b/packages/tfcode/src/mcp/index.ts @@ -24,6 +24,8 @@ import { BusEvent } from "../bus/bus-event" import { Bus } from "@/bus" import { TuiEvent } from "@/cli/cmd/tui/event" import open from "open" +import path from "path" +import { Global } from "../global" export namespace MCP { const log = Log.create({ service: "mcp" }) @@ -117,6 +119,16 @@ export namespace MCP { }) } + async function loadTFCredentials(): Promise<{ api_key?: string; workspace_id?: string; region?: string }> { + try { + const credPath = path.join(Global.Path.data, ".tfcode", "credentials.json") + const content = await Bun.file(credPath).text() + return JSON.parse(content) + } catch { + return {} + } + } + // Convert MCP tool definition to AI SDK Tool type async function convertMcpTool(mcpTool: MCPToolDef, client: MCPClient, timeout?: number): Promise { const inputSchema = mcpTool.inputSchema @@ -129,14 +141,29 @@ export namespace MCP { additionalProperties: false, } + const isTFCredTool = (name: string) => + name.startsWith("toothfairy_") && (schema.properties?.api_key || schema.properties?.workspace_id) + return dynamicTool({ description: mcpTool.description ?? "", inputSchema: jsonSchema(schema), execute: async (args: unknown) => { + let finalArgs = (args || {}) as Record + + if (isTFCredTool(mcpTool.name)) { + const creds = await loadTFCredentials() + finalArgs = { + ...finalArgs, + api_key: finalArgs.api_key || creds.api_key, + workspace_id: finalArgs.workspace_id || creds.workspace_id, + region: finalArgs.region || creds.region || "au", + } + } + return client.callTool( { name: mcpTool.name, - arguments: (args || {}) as Record, + arguments: finalArgs, }, CallToolResultSchema, {