feat: add @tm/ai-tools package with Context7 MCP integration

Adds a new package @tm/ai-tools that provides AI SDK tool integrations
for Task Master. Starts with Context7 MCP support for documentation
lookup capabilities.

Package features:
- createContext7Tools() - Creates MCP client for Context7 documentation
- createMCPTools() - Auto-detects and combines available MCP tools
- isContext7Available() - Checks if CONTEXT7_API_KEY is configured
- getAvailableMCPTools() - Lists available MCP tool sources

Usage:
import { createContext7Tools } from '@tm/ai-tools/context7';
import { createMCPTools } from '@tm/ai-tools';

The package uses @ai-sdk/mcp for MCP client functionality.
This commit is contained in:
Claude
2025-11-25 14:27:36 +00:00
committed by Ralph Khreish
parent 9a6fa1bd2a
commit af20b4250b
9 changed files with 3737 additions and 8584 deletions

11943
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,37 @@
{
"name": "@tm/ai-tools",
"private": true,
"description": "AI SDK tools for Task Master - MCP integrations and AI utilities",
"type": "module",
"types": "./src/index.ts",
"main": "./dist/index.js",
"exports": {
".": "./src/index.ts",
"./context7": "./src/context7/index.ts"
},
"scripts": {
"test": "vitest run",
"test:watch": "vitest",
"test:coverage": "vitest run --coverage",
"lint": "biome check --write",
"lint:check": "biome check",
"lint:fix": "biome check --fix --unsafe",
"format": "biome format --write",
"format:check": "biome format",
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@ai-sdk/mcp": "^0.0.10",
"ai": "^5.0.0"
},
"devDependencies": {
"@types/node": "^22.10.5",
"@vitest/coverage-v8": "^4.0.10",
"typescript": "^5.9.2",
"vitest": "^4.0.10"
},
"files": ["src", "README.md", "CHANGELOG.md"],
"keywords": ["ai-sdk", "mcp", "context7", "task-master", "ai-tools"],
"author": "Task Master AI",
"version": ""
}

View File

@@ -0,0 +1,94 @@
import { experimental_createMCPClient } from '@ai-sdk/mcp';
import { Experimental_StdioMCPTransport } from '@ai-sdk/mcp/mcp-stdio';
import type {
Context7Config,
Context7ToolsOptions,
Context7ToolsResult
} from './types.js';
/**
* Error thrown when Context7 API key is not configured
*/
export class Context7ApiKeyError extends Error {
constructor() {
super(
'Context7 API key is required. Set CONTEXT7_API_KEY environment variable or pass apiKey in config.'
);
this.name = 'Context7ApiKeyError';
}
}
/**
* Get the Context7 API key from config or environment
*/
function getApiKey(config?: Context7Config): string {
const apiKey = config?.apiKey ?? process.env.CONTEXT7_API_KEY;
if (!apiKey) {
throw new Context7ApiKeyError();
}
return apiKey;
}
/**
* Creates a Context7 MCP client and returns tools for use with AI SDK.
*
* Context7 provides up-to-date documentation and code examples for libraries
* and frameworks, helping AI models give more accurate answers about APIs.
*
* @example
* ```typescript
* import { createContext7Tools } from '@tm/ai-tools/context7';
* import { generateText } from 'ai';
* import { openai } from '@ai-sdk/openai';
*
* const { tools, close } = await createContext7Tools();
*
* try {
* const result = await generateText({
* model: openai('gpt-4o'),
* tools,
* prompt: 'How do I use the latest React Query API?',
* });
* console.log(result.text);
* } finally {
* await close();
* }
* ```
*/
export async function createContext7Tools(
options?: Context7ToolsOptions
): Promise<Context7ToolsResult> {
const apiKey = getApiKey(options?.config);
const transport = new Experimental_StdioMCPTransport({
command: 'npx',
args: ['-y', '@upstash/context7-mcp', '--api-key', apiKey]
});
const client = await experimental_createMCPClient({
transport
});
options?.onReady?.();
const tools = await client.tools();
return {
tools,
close: async () => {
await client.close();
}
};
}
/**
* Check if Context7 is available (API key is configured)
*/
export function isContext7Available(config?: Context7Config): boolean {
try {
getApiKey(config);
return true;
} catch {
return false;
}
}

View File

@@ -0,0 +1,11 @@
export {
createContext7Tools,
isContext7Available,
Context7ApiKeyError
} from './client.js';
export type {
Context7Config,
Context7ToolsOptions,
Context7ToolsResult
} from './types.js';

View File

@@ -0,0 +1,45 @@
/**
* Configuration options for the Context7 MCP client
*/
export interface Context7Config {
/**
* The Context7 API key. If not provided, will attempt to read from
* CONTEXT7_API_KEY environment variable.
*/
apiKey?: string;
}
/**
* Options for creating Context7 tools
*/
export interface Context7ToolsOptions {
/**
* Configuration for the Context7 client
*/
config?: Context7Config;
/**
* Callback when the client is ready
*/
onReady?: () => void;
/**
* Callback when an error occurs
*/
onError?: (error: Error) => void;
}
/**
* Result from creating Context7 tools
*/
export interface Context7ToolsResult {
/**
* The tools object that can be passed to AI SDK's generateText/streamText
*/
tools: Record<string, unknown>;
/**
* Close the MCP client connection. Should be called when done using the tools.
*/
close: () => Promise<void>;
}

View File

@@ -0,0 +1,25 @@
/**
* @tm/ai-tools - AI SDK tools for Task Master
*
* This package provides AI SDK integrations for various MCP servers and tools.
*
* @example
* ```typescript
* // Import Context7 tools directly
* import { createContext7Tools } from '@tm/ai-tools/context7';
*
* // Or use the MCP tools manager for auto-detection
* import { createMCPTools } from '@tm/ai-tools';
* ```
*/
// MCP Tools Manager - auto-detects and combines available MCP tools
export {
createMCPTools,
getAvailableMCPTools,
type MCPToolsManagerConfig,
type MCPToolsResult
} from './mcp-tools-manager.js';
// Re-export context7 module for convenience
export * from './context7/index.js';

View File

@@ -0,0 +1,126 @@
import {
createContext7Tools,
isContext7Available,
type Context7Config
} from './context7/index.js';
/**
* Configuration for MCP tools manager
*/
export interface MCPToolsManagerConfig {
/**
* Enable Context7 tools for documentation lookup
*/
context7?: Context7Config | boolean;
}
/**
* Result from getting MCP tools
*/
export interface MCPToolsResult {
/**
* Combined tools from all enabled MCP servers
*/
tools: Record<string, unknown>;
/**
* Close all MCP client connections. Should be called when done.
*/
close: () => Promise<void>;
/**
* List of enabled MCP tool sources
*/
enabledSources: string[];
}
/**
* Creates and manages MCP tools from multiple sources.
*
* This utility automatically detects available MCP tools based on
* environment variables and configuration.
*
* @example
* ```typescript
* import { createMCPTools } from '@tm/ai-tools';
* import { generateText } from 'ai';
* import { openai } from '@ai-sdk/openai';
*
* // Auto-detect available tools from environment
* const { tools, close, enabledSources } = await createMCPTools();
*
* console.log('Enabled MCP tools:', enabledSources);
*
* try {
* const result = await generateText({
* model: openai('gpt-4o'),
* tools,
* prompt: 'How do I use React Query?',
* });
* console.log(result.text);
* } finally {
* await close();
* }
* ```
*
* @example
* ```typescript
* // With explicit configuration
* const { tools, close } = await createMCPTools({
* context7: { apiKey: 'my-api-key' },
* });
* ```
*/
export async function createMCPTools(
config?: MCPToolsManagerConfig
): Promise<MCPToolsResult> {
const tools: Record<string, unknown> = {};
const closeFunctions: (() => Promise<void>)[] = [];
const enabledSources: string[] = [];
// Context7 tools
const context7Config =
config?.context7 === true
? {}
: config?.context7 === false
? undefined
: config?.context7;
// Only create Context7 tools if explicitly enabled or auto-detect available
const shouldEnableContext7 =
config?.context7 !== false &&
(config?.context7 !== undefined || isContext7Available(context7Config));
if (shouldEnableContext7 && isContext7Available(context7Config)) {
try {
const context7 = await createContext7Tools({ config: context7Config });
Object.assign(tools, context7.tools);
closeFunctions.push(context7.close);
enabledSources.push('context7');
} catch (error) {
// Log but don't fail if Context7 connection fails
console.warn('Failed to connect to Context7 MCP server:', error);
}
}
return {
tools,
enabledSources,
close: async () => {
await Promise.all(closeFunctions.map((fn) => fn()));
}
};
}
/**
* Check which MCP tools are available based on environment
*/
export function getAvailableMCPTools(): string[] {
const available: string[] = [];
if (isContext7Available()) {
available.push('context7');
}
return available;
}

View File

@@ -0,0 +1,36 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"lib": ["ES2022"],
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"outDir": "./dist",
"baseUrl": ".",
"rootDir": "./src",
"strict": true,
"noImplicitAny": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"strictBindCallApply": true,
"strictPropertyInitialization": true,
"noImplicitThis": true,
"alwaysStrict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"moduleResolution": "NodeNext",
"moduleDetection": "force",
"types": ["node"],
"resolveJsonModule": true,
"isolatedModules": true,
"allowImportingTsExtensions": false
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist", "tests", "**/*.test.ts", "**/*.spec.ts"]
}

View File

@@ -29,7 +29,9 @@
"./packages/ai-sdk-provider-grok-cli/src/*"
],
"@tm/bridge": ["./packages/tm-bridge/src/index.ts"],
"@tm/bridge/*": ["./packages/tm-bridge/src/*"]
"@tm/bridge/*": ["./packages/tm-bridge/src/*"],
"@tm/ai-tools": ["./packages/ai-sdk-tools/src/index.ts"],
"@tm/ai-tools/*": ["./packages/ai-sdk-tools/src/*"]
}
},
"tsx": {