# Base64 Encoder Source: https://spec.conveniencepro.cc/examples/base64-encoder Reference implementation of a bidirectional CTP tool # Base64 Encoder/Decoder A bidirectional CTP tool demonstrating mode selection and conditional parameters. ## Overview | Property | Value | | ------------------ | ---------------- | | **ID** | `base64-encoder` | | **Category** | `encoders` | | **Execution Mode** | `client` | | **Method** | `POST` | ## Parameters | Name | Type | Required | Default | Description | | --------- | ---------- | -------- | -------- | ------------------------------- | | `input` | `textarea` | Yes | - | Text or Base64 string | | `mode` | `select` | No | `encode` | Operation mode | | `urlSafe` | `boolean` | No | `false` | URL-safe encoding (encode only) | ### Mode Options | Value | Description | | -------- | --------------------- | | `encode` | Convert text → Base64 | | `decode` | Convert Base64 → text | ### URL-Safe Mode When enabled (encode only): * `+` becomes `-` * `/` becomes `_` * Padding `=` is removed ## Example **Encode:** ```json theme={null} { "input": "Hello, World!", "mode": "encode" } ``` **Output:** ```json theme={null} { "success": true, "data": { "output": "SGVsbG8sIFdvcmxkIQ==", "mode": "encode", "inputLength": 13, "outputLength": 20 } } ``` **Decode:** ```json theme={null} { "input": "SGVsbG8sIFdvcmxkIQ==", "mode": "decode" } ``` **Output:** ```json theme={null} { "success": true, "data": { "output": "Hello, World!", "mode": "decode", "inputLength": 20, "outputLength": 13 } } ``` ## Implementation ```typescript theme={null} import type { ToolDefinition, ToolFunction } from '@conveniencepro/ctp-core'; interface Base64Result { output: string; mode: 'encode' | 'decode'; inputLength: number; outputLength: number; } export const base64EncoderDefinition: ToolDefinition = { id: 'base64-encoder', name: 'Base64 Encoder/Decoder', description: 'Encode text to Base64 or decode Base64 back to text.', category: 'encoders', tags: ['base64', 'encode', 'decode', 'text'], method: 'POST', parameters: [ { name: 'input', type: 'textarea', label: 'Input', description: 'Text to encode or Base64 to decode', required: true, }, { name: 'mode', type: 'select', label: 'Mode', description: 'Operation mode', required: false, defaultValue: 'encode', options: [ { value: 'encode', label: 'Encode' }, { value: 'decode', label: 'Decode' }, ], }, { name: 'urlSafe', type: 'boolean', label: 'URL Safe', description: 'Use URL-safe Base64 variant', required: false, defaultValue: false, // Only show when mode is 'encode' dependsOn: [{ field: 'mode', condition: 'equals', value: 'encode' }], }, ], outputDescription: 'Encoded or decoded string', example: { input: { input: 'Hello', mode: 'encode' }, output: { output: 'SGVsbG8=', mode: 'encode', inputLength: 5, outputLength: 8 }, }, executionMode: 'client', }; function encodeBase64(str: string, urlSafe: boolean): string { // Convert string to UTF-8 bytes const bytes = new TextEncoder().encode(str); let binary = ''; bytes.forEach(byte => { binary += String.fromCharCode(byte); }); // Encode to Base64 let result = btoa(binary); // Apply URL-safe transformation if (urlSafe) { result = result .replace(/\+/g, '-') .replace(/\//g, '_') .replace(/=/g, ''); } return result; } function decodeBase64(str: string): string { // Handle URL-safe variant let input = str.replace(/-/g, '+').replace(/_/g, '/'); // Add padding if needed while (input.length % 4) { input += '='; } // Decode from Base64 const binary = atob(input); const bytes = new Uint8Array(binary.length); for (let i = 0; i < binary.length; i++) { bytes[i] = binary.charCodeAt(i); } // Convert UTF-8 bytes to string return new TextDecoder().decode(bytes); } export const base64EncoderFn: ToolFunction = (params) => { const input = params.input as string; const mode = (params.mode as 'encode' | 'decode') || 'encode'; const urlSafe = params.urlSafe === true || params.urlSafe === 'true'; // Validation if (!input) { return { success: false, error: 'Input is required', errorCode: 'MISSING_REQUIRED', }; } try { const output = mode === 'encode' ? encodeBase64(input, urlSafe) : decodeBase64(input); return { success: true, data: { output, mode, inputLength: input.length, outputLength: output.length, }, }; } catch (e) { return { success: false, error: mode === 'decode' ? `Invalid Base64: ${(e as Error).message}` : `Encoding failed: ${(e as Error).message}`, errorCode: 'INVALID_INPUT', }; } }; export default { definition: base64EncoderDefinition, fn: base64EncoderFn }; ``` ## Key Patterns ### Bidirectional Operations Handle two opposite operations in one tool: ```typescript theme={null} const output = mode === 'encode' ? encodeBase64(input, urlSafe) : decodeBase64(input); ``` ### Conditional Parameters Show `urlSafe` only when encoding: ```typescript theme={null} { name: 'urlSafe', type: 'boolean', dependsOn: [{ field: 'mode', condition: 'equals', value: 'encode' }], } ``` ### UTF-8 Support Properly handle international characters: ```typescript theme={null} // Encode: Convert string to UTF-8 bytes first const bytes = new TextEncoder().encode(str); // Decode: Convert bytes back to string return new TextDecoder().decode(bytes); ``` ### URL-Safe Variant Transform standard Base64 for URL safety: ```typescript theme={null} if (urlSafe) { result = result .replace(/\+/g, '-') // + → - .replace(/\//g, '_') // / → _ .replace(/=/g, ''); // Remove padding } ``` ## Error Handling | Error Code | Cause | | ------------------ | ----------------------------------- | | `MISSING_REQUIRED` | `input` not provided | | `INVALID_INPUT` | Invalid Base64 string (decode mode) | # Hash Generator Source: https://spec.conveniencepro.cc/examples/hash-generator Reference implementation of an async CTP tool # Hash Generator An asynchronous CTP tool demonstrating Web Crypto API usage and conditional warnings. ## Overview | Property | Value | | ------------------ | ---------------- | | **ID** | `hash-generator` | | **Category** | `generators` | | **Execution Mode** | `client` | | **Method** | `POST` | ## Parameters | Name | Type | Required | Default | Description | | ----------- | ---------- | -------- | --------- | -------------- | | `input` | `textarea` | Yes | - | Text to hash | | `algorithm` | `select` | No | `SHA-256` | Hash algorithm | | `format` | `select` | No | `hex` | Output format | ### Algorithm Options | Value | Bits | Security | | --------- | ---- | ----------- | | `SHA-1` | 160 | Deprecated | | `SHA-256` | 256 | Recommended | | `SHA-384` | 384 | Strong | | `SHA-512` | 512 | Strongest | ### Format Options | Value | Description | Example | | -------- | --------------------- | ------------- | | `hex` | Lowercase hexadecimal | `b94d27b9...` | | `base64` | Base64 encoded | `uU0nuZ...` | ## Example **Input:** ```json theme={null} { "input": "hello world", "algorithm": "SHA-256", "format": "hex" } ``` **Output:** ```json theme={null} { "success": true, "data": { "hash": "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9", "algorithm": "SHA-256", "format": "hex", "inputLength": 11 }, "metadata": { "executionTime": 1.2, "warnings": null } } ``` **With SHA-1 (warning):** ```json theme={null} { "success": true, "data": { "hash": "2aae6c35c94fcfb415dbe95f408b9ce91ee846ed", "algorithm": "SHA-1", "format": "hex", "inputLength": 11 }, "metadata": { "warnings": ["SHA-1 is deprecated for security purposes"] } } ``` ## Implementation ```typescript theme={null} import type { ToolDefinition, ToolFunction } from '@conveniencepro/ctp-core'; interface HashGeneratorResult { hash: string; algorithm: string; format: string; inputLength: number; } type HashAlgorithm = 'SHA-1' | 'SHA-256' | 'SHA-384' | 'SHA-512'; type OutputFormat = 'hex' | 'base64'; export const hashGeneratorDefinition: ToolDefinition = { id: 'hash-generator', name: 'Hash Generator', description: 'Generate cryptographic hashes using SHA algorithms.', category: 'generators', tags: ['hash', 'sha256', 'sha512', 'checksum', 'crypto'], method: 'POST', parameters: [ { name: 'input', type: 'textarea', label: 'Input Text', description: 'Text to hash', required: true, }, { name: 'algorithm', type: 'select', label: 'Algorithm', description: 'Hash algorithm', required: false, defaultValue: 'SHA-256', options: [ { value: 'SHA-1', label: 'SHA-1', description: 'Legacy (not secure)' }, { value: 'SHA-256', label: 'SHA-256', description: 'Recommended' }, { value: 'SHA-384', label: 'SHA-384' }, { value: 'SHA-512', label: 'SHA-512', description: 'Strongest' }, ], aiHint: 'Use SHA-256 unless user specifies otherwise', }, { name: 'format', type: 'select', label: 'Output Format', description: 'Hash output format', required: false, defaultValue: 'hex', options: [ { value: 'hex', label: 'Hexadecimal' }, { value: 'base64', label: 'Base64' }, ], }, ], outputDescription: 'Cryptographic hash of the input', example: { input: { input: 'hello', algorithm: 'SHA-256', format: 'hex' }, output: { hash: '2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824', algorithm: 'SHA-256', format: 'hex', inputLength: 5, }, }, executionMode: 'client', aiInstructions: 'Use SHA-256 by default. Warn if user requests SHA-1.', }; // ASYNC function - uses Web Crypto API export const hashGeneratorFn: ToolFunction = async (params) => { const startTime = performance.now(); const input = params.input as string; const algorithm = (params.algorithm as HashAlgorithm) || 'SHA-256'; const format = (params.format as OutputFormat) || 'hex'; // Validation if (!input) { return { success: false, error: 'Input text is required', errorCode: 'MISSING_REQUIRED', }; } try { // Encode input as UTF-8 const encoder = new TextEncoder(); const data = encoder.encode(input); // Generate hash using Web Crypto API const hashBuffer = await crypto.subtle.digest(algorithm, data); const hashArray = new Uint8Array(hashBuffer); // Format output let hash: string; if (format === 'base64') { let binary = ''; hashArray.forEach(byte => { binary += String.fromCharCode(byte); }); hash = btoa(binary); } else { hash = Array.from(hashArray) .map(b => b.toString(16).padStart(2, '0')) .join(''); } return { success: true, data: { hash, algorithm, format, inputLength: input.length, }, metadata: { executionTime: performance.now() - startTime, // Include warning for deprecated algorithm warnings: algorithm === 'SHA-1' ? ['SHA-1 is deprecated for security purposes'] : undefined, }, }; } catch (e) { return { success: false, error: `Hash generation failed: ${(e as Error).message}`, errorCode: 'EXECUTION_ERROR', }; } }; export default { definition: hashGeneratorDefinition, fn: hashGeneratorFn }; ``` ## Key Patterns ### Async Tool Function Uses `async/await` for Web Crypto API: ```typescript theme={null} export const hashGeneratorFn: ToolFunction = async (params) => { const hashBuffer = await crypto.subtle.digest(algorithm, data); // ... }; ``` ### Web Crypto API Browser-native cryptographic functions: ```typescript theme={null} // Encode string to bytes const data = new TextEncoder().encode(input); // Generate hash const hashBuffer = await crypto.subtle.digest('SHA-256', data); ``` ### Conditional Warnings Include warnings without failing: ```typescript theme={null} metadata: { warnings: algorithm === 'SHA-1' ? ['SHA-1 is deprecated for security purposes'] : undefined, } ``` ### AI Hints Guide AI model behavior: ```typescript theme={null} { name: 'algorithm', aiHint: 'Use SHA-256 unless user specifies otherwise', } ``` ### AI Instructions Tool-level AI guidance: ```typescript theme={null} { aiInstructions: 'Use SHA-256 by default. Warn if user requests SHA-1.', } ``` ## Web Crypto Support Available in all modern browsers: | Algorithm | Bits | Support | | --------- | ---- | ------------ | | SHA-1 | 160 | All browsers | | SHA-256 | 256 | All browsers | | SHA-384 | 384 | All browsers | | SHA-512 | 512 | All browsers | **Note:** MD5 is NOT available in Web Crypto. Use a library if needed. ## Error Handling | Error Code | Cause | | ------------------ | -------------------- | | `MISSING_REQUIRED` | `input` not provided | | `EXECUTION_ERROR` | Web Crypto failure | # JSON Formatter Source: https://spec.conveniencepro.cc/examples/json-formatter Reference implementation of a sync CTP tool # JSON Formatter A synchronous CTP tool demonstrating multiple parameters and validation. ## Overview | Property | Value | | ------------------ | ---------------- | | **ID** | `json-formatter` | | **Category** | `formatters` | | **Execution Mode** | `client` | | **Method** | `POST` | ## Parameters | Name | Type | Required | Default | Description | | ---------- | ---------- | -------- | ------- | --------------------- | | `json` | `textarea` | Yes | - | JSON string to format | | `indent` | `select` | No | `2` | Indentation style | | `sortKeys` | `boolean` | No | `false` | Sort object keys | ### Indent Options | Value | Label | | ----- | -------- | | `0` | Minified | | `2` | 2 spaces | | `4` | 4 spaces | | `tab` | Tab | ## Example **Input:** ```json theme={null} { "json": "{\"b\":2,\"a\":1}", "indent": "2", "sortKeys": true } ``` **Output:** ```json theme={null} { "success": true, "data": { "formatted": "{\n \"a\": 1,\n \"b\": 2\n}", "valid": true, "lineCount": 4, "characterCount": 24 }, "metadata": { "executionTime": 0.5, "inputSize": 15, "outputSize": 24 } } ``` ## Implementation ```typescript theme={null} import type { ToolDefinition, ToolFunction } from '@conveniencepro/ctp-core'; interface JsonFormatterResult { formatted: string; valid: boolean; lineCount: number; characterCount: number; } export const jsonFormatterDefinition: ToolDefinition = { id: 'json-formatter', name: 'JSON Formatter', description: 'Format, validate, and beautify JSON data with customizable indentation.', category: 'formatters', tags: ['json', 'format', 'beautify', 'validate', 'minify'], method: 'POST', parameters: [ { name: 'json', type: 'textarea', label: 'JSON Input', description: 'The JSON string to format', required: true, placeholder: '{"name": "example"}', validation: { minLength: 1, maxLength: 1000000 }, }, { name: 'indent', type: 'select', label: 'Indentation', description: 'Number of spaces for indentation', required: false, defaultValue: '2', options: [ { value: '0', label: 'Minified' }, { value: '2', label: '2 spaces' }, { value: '4', label: '4 spaces' }, { value: 'tab', label: 'Tab' }, ], }, { name: 'sortKeys', type: 'boolean', label: 'Sort Keys', description: 'Sort object keys alphabetically', required: false, defaultValue: false, }, ], outputDescription: 'Formatted JSON string', example: { input: { json: '{"a":1}', indent: '2' }, output: { formatted: '{\n "a": 1\n}', valid: true, lineCount: 3, characterCount: 14 }, }, version: '1.0.0', icon: '📋', executionMode: 'client', }; function sortObjectKeys(obj: unknown): unknown { if (Array.isArray(obj)) return obj.map(sortObjectKeys); if (obj !== null && typeof obj === 'object') { const sorted: Record = {}; Object.keys(obj as Record).sort().forEach(key => { sorted[key] = sortObjectKeys((obj as Record)[key]); }); return sorted; } return obj; } export const jsonFormatterFn: ToolFunction = (params) => { const startTime = performance.now(); const jsonInput = params.json as string; const indentOption = (params.indent as string) || '2'; const sortKeys = params.sortKeys === true || params.sortKeys === 'true'; // Validation if (!jsonInput) { return { success: false, error: 'JSON input is required', errorCode: 'MISSING_REQUIRED', }; } // Parse JSON let parsed: unknown; try { parsed = JSON.parse(jsonInput); } catch (e) { return { success: false, error: `Invalid JSON: ${(e as Error).message}`, errorCode: 'INVALID_INPUT', suggestion: 'Check for missing quotes, commas, or brackets', }; } // Sort keys if requested if (sortKeys) { parsed = sortObjectKeys(parsed); } // Format with selected indentation const indent = indentOption === 'tab' ? '\t' : parseInt(indentOption) || 2; const formatted = JSON.stringify(parsed, null, indent); return { success: true, data: { formatted, valid: true, lineCount: formatted.split('\n').length, characterCount: formatted.length, }, metadata: { executionTime: performance.now() - startTime, inputSize: jsonInput.length, outputSize: formatted.length, }, }; }; export default { definition: jsonFormatterDefinition, fn: jsonFormatterFn }; ``` ## Key Patterns ### Performance Metadata Track execution metrics: ```typescript theme={null} const startTime = performance.now(); // ... processing ... metadata: { executionTime: performance.now() - startTime, } ``` ### Deep Object Sorting Recursively sort nested object keys: ```typescript theme={null} function sortObjectKeys(obj: unknown): unknown { if (Array.isArray(obj)) return obj.map(sortObjectKeys); if (obj !== null && typeof obj === 'object') { const sorted: Record = {}; Object.keys(obj).sort().forEach(key => { sorted[key] = sortObjectKeys(obj[key]); }); return sorted; } return obj; } ``` ### Error Suggestions Provide actionable error messages: ```typescript theme={null} return { success: false, error: `Invalid JSON: ${(e as Error).message}`, errorCode: 'INVALID_INPUT', suggestion: 'Check for missing quotes, commas, or brackets', }; ``` ## Error Handling | Error Code | Cause | | ------------------ | ----------------------------- | | `MISSING_REQUIRED` | `json` parameter not provided | | `INVALID_INPUT` | JSON parse error | # Examples Overview Source: https://spec.conveniencepro.cc/examples/overview Reference implementations of CTP-compliant tools # Example Tools Complete reference implementations demonstrating CTP patterns. ## Available Examples Format and beautify JSON with customizable indentation Bidirectional Base64 encoding and decoding Cryptographic hashing with Web Crypto API ## Pattern Summary | Example | Pattern | Key Concept | | -------------- | ------------- | ---------------------------------- | | JSON Formatter | Sync tool | Multiple parameters, validation | | Base64 Encoder | Bidirectional | Mode selection, conditional params | | Hash Generator | Async tool | Web Crypto, warnings in metadata | ## Quick Reference ### Sync Tool (JSON Formatter) ```typescript theme={null} export const jsonFormatterFn: ToolFunction = (params) => { // Synchronous processing const formatted = JSON.stringify(parsed, null, indent); return { success: true, data: { formatted } }; }; ``` ### Async Tool (Hash Generator) ```typescript theme={null} export const hashGeneratorFn: ToolFunction = async (params) => { // Asynchronous - uses Web Crypto const hash = await crypto.subtle.digest('SHA-256', data); return { success: true, data: { hash } }; }; ``` ### Bidirectional Tool (Base64) ```typescript theme={null} export const base64Fn: ToolFunction = (params) => { const mode = params.mode as 'encode' | 'decode'; const output = mode === 'encode' ? encode(input) : decode(input); return { success: true, data: { output, mode } }; }; ``` ## Running Examples ### Clone Repository ```bash theme={null} git clone https://github.com/titan-alpha/convenience-pro cd convenience-pro/packages/ctp-examples npm install ``` ### Run Tests ```bash theme={null} npm test ``` ### Try Interactively ```bash theme={null} npm run dev # Opens interactive tool runner ``` ## Creating Your Own Use examples as templates: ```typescript theme={null} // Copy a similar example cp src/tools/json-formatter.ts src/tools/my-tool.ts // Modify definition and function // Register in src/registry.ts // Add tests in src/__tests__/ ``` # Creating Tools Source: https://spec.conveniencepro.cc/implementation/creating-tools Patterns and best practices for building CTP tools # Creating Tools Learn the patterns and best practices for building CTP-compliant tools. ## Tool Structure Every CTP tool consists of two parts: 1. **Definition** - Metadata describing the tool 2. **Function** - Implementation that processes inputs ```typescript theme={null} import type { ToolDefinition, ToolFunction } from '@conveniencepro/ctp-core'; // 1. Define result type interface MyToolResult { // ... result properties } // 2. Create definition export const myToolDefinition: ToolDefinition = { // ... metadata }; // 3. Implement function export const myToolFn: ToolFunction = (params) => { // ... implementation }; // 4. Export together export default { definition: myToolDefinition, fn: myToolFn }; ``` ## Definition Patterns ### Minimal Definition ```typescript theme={null} export const minimalDefinition: ToolDefinition = { id: 'minimal-tool', name: 'Minimal Tool', description: 'A minimal example tool.', category: 'utilities', tags: ['example'], method: 'POST', parameters: [ { name: 'input', type: 'text', label: 'Input', description: 'Input value', required: true, }, ], outputDescription: 'Processed result', example: { input: { input: 'test' }, output: { result: 'processed' }, }, }; ``` ### Full-Featured Definition ```typescript theme={null} export const fullDefinition: ToolDefinition = { // Required id: 'advanced-tool', name: 'Advanced Tool', description: 'A fully-featured example with all options.', category: 'formatters', tags: ['advanced', 'example', 'featured'], method: 'POST', parameters: [/* ... */], outputDescription: 'Formatted output with metadata', example: { input: { /* ... */ }, output: { /* ... */ }, }, // Optional metadata version: '1.0.0', icon: '🔧', keywords: ['full', 'complete'], relatedTools: ['simple-tool', 'other-tool'], // AI guidance aiInstructions: 'Use default settings unless user specifies otherwise.', // Execution executionMode: 'client', requiresAuth: false, // Rate limiting rateLimit: { requests: 100, window: 60, }, }; ``` ## Implementation Patterns ### Synchronous Tool ```typescript theme={null} export const syncFn: ToolFunction = (params) => { const input = params.input as string; // Validation if (!input) { return { success: false, error: 'Input is required', errorCode: 'MISSING_REQUIRED', }; } // Processing const result = processSync(input); // Return success return { success: true, data: result, }; }; ``` ### Asynchronous Tool ```typescript theme={null} export const asyncFn: ToolFunction = async (params) => { const input = params.input as string; try { // Async operation (e.g., Web Crypto) const hash = await crypto.subtle.digest( 'SHA-256', new TextEncoder().encode(input) ); return { success: true, data: { hash: arrayToHex(hash) }, }; } catch (error) { return { success: false, error: (error as Error).message, errorCode: 'EXECUTION_ERROR', }; } }; ``` ### With Metadata ```typescript theme={null} export const metadataFn: ToolFunction = (params) => { const startTime = performance.now(); const input = params.input as string; const result = process(input); return { success: true, data: result, metadata: { executionTime: performance.now() - startTime, inputSize: input.length, outputSize: JSON.stringify(result).length, }, }; }; ``` ### With Warnings ```typescript theme={null} export const warningFn: ToolFunction = (params) => { const algorithm = params.algorithm as string; const warnings: string[] = []; if (algorithm === 'SHA-1') { warnings.push('SHA-1 is deprecated for security purposes'); } if (algorithm === 'MD5') { warnings.push('MD5 is cryptographically broken'); } const result = compute(params); return { success: true, data: result, metadata: { warnings: warnings.length > 0 ? warnings : undefined, }, }; }; ``` ## Parameter Patterns ### Select with Descriptions ```typescript theme={null} { name: 'format', type: 'select', label: 'Output Format', description: 'Choose the output format', required: false, defaultValue: 'json', options: [ { value: 'json', label: 'JSON', description: 'JavaScript Object Notation' }, { value: 'yaml', label: 'YAML', description: 'Human-readable format' }, { value: 'xml', label: 'XML', description: 'Extensible Markup Language' }, ], } ``` ### Conditional Parameters ```typescript theme={null} parameters: [ { name: 'mode', type: 'select', label: 'Mode', required: true, options: [ { value: 'simple', label: 'Simple' }, { value: 'advanced', label: 'Advanced' }, ], }, { name: 'advancedOption', type: 'text', label: 'Advanced Option', description: 'Only shown in advanced mode', required: false, dependsOn: [{ field: 'mode', condition: 'equals', value: 'advanced' }], }, ] ``` ### Grouped Parameters ```typescript theme={null} parameters: [ // Input group { name: 'input', type: 'textarea', group: 'input', order: 1, /* ... */ }, // Options group { name: 'format', type: 'select', group: 'options', order: 1, /* ... */ }, { name: 'indent', type: 'number', group: 'options', order: 2, /* ... */ }, // Advanced group { name: 'strict', type: 'boolean', group: 'advanced', order: 1, /* ... */ }, ] ``` ## Bidirectional Tools Handle encode/decode or similar operations: ```typescript theme={null} export const bidirectionalDefinition: ToolDefinition = { id: 'base64-encoder', name: 'Base64 Encoder/Decoder', // ... parameters: [ { name: 'input', type: 'textarea', label: 'Input', description: 'Text to encode or Base64 to decode', required: true, }, { name: 'mode', type: 'select', label: 'Mode', required: false, defaultValue: 'encode', options: [ { value: 'encode', label: 'Encode' }, { value: 'decode', label: 'Decode' }, ], }, ], }; export const bidirectionalFn: ToolFunction = (params) => { const input = params.input as string; const mode = (params.mode as 'encode' | 'decode') || 'encode'; const output = mode === 'encode' ? btoa(input) : atob(input); return { success: true, data: { output, mode }, }; }; ``` ## Error Handling ### Validation Errors ```typescript theme={null} if (!input) { return { success: false, error: 'Input is required', errorCode: 'MISSING_REQUIRED', }; } if (typeof input !== 'string') { return { success: false, error: 'Input must be a string', errorCode: 'TYPE_ERROR', }; } if (input.length > 100000) { return { success: false, error: 'Input exceeds maximum length', errorCode: 'CONSTRAINT_VIOLATION', }; } ``` ### Execution Errors ```typescript theme={null} try { const parsed = JSON.parse(input); return { success: true, data: { parsed } }; } catch (e) { return { success: false, error: `Invalid JSON: ${(e as Error).message}`, errorCode: 'INVALID_INPUT', suggestion: 'Check for missing quotes or trailing commas', }; } ``` ## Testing Tools ```typescript theme={null} import { describe, it, expect } from 'vitest'; import myTool from './my-tool'; describe('my-tool', () => { it('returns success for valid input', () => { const result = myTool.fn({ input: 'test' }); expect(result.success).toBe(true); expect(result.data).toBeDefined(); }); it('returns error for missing input', () => { const result = myTool.fn({}); expect(result.success).toBe(false); expect(result.errorCode).toBe('MISSING_REQUIRED'); }); }); ``` # Discovery Documents Source: https://spec.conveniencepro.cc/implementation/discovery-docs Generate OpenAPI, MCP, and llms.txt from your tools # Discovery Documents Generate discovery documents to make your tools discoverable. ## Installation ```bash theme={null} npm install @conveniencepro/ctp-discovery ``` ## OpenAPI Specification Generate OpenAPI 3.1 documentation: ```typescript theme={null} import { generateOpenAPISpec } from '@conveniencepro/ctp-discovery'; const tools = [jsonFormatter, base64Encoder, hashGenerator]; const spec = generateOpenAPISpec(tools, { info: { title: 'My Tools API', version: '1.0.0', description: 'A collection of developer tools', contact: { name: 'API Support', email: 'support@example.com', }, }, servers: [ { url: 'https://api.example.com/v1', description: 'Production' }, { url: 'http://localhost:3000/v1', description: 'Development' }, ], }); ``` ### Serve OpenAPI ```typescript theme={null} // Express.js app.get('/openapi.json', (req, res) => { res.json(generateOpenAPISpec(registry.getDefinitions())); }); // Static file import { writeFileSync } from 'fs'; writeFileSync('public/openapi.json', JSON.stringify(spec, null, 2)); ``` ### Use with Swagger UI ```html theme={null}
``` ## MCP Manifest Generate Model Context Protocol manifests: ```typescript theme={null} import { generateMCPManifest } from '@conveniencepro/ctp-discovery'; const manifest = generateMCPManifest(tools, { name: 'my-tools', version: '1.0.0', description: 'Developer tools for everyday tasks', }); ``` ### Serve MCP Manifest Standard location is `/.well-known/mcp.json`: ```typescript theme={null} app.get('/.well-known/mcp.json', (req, res) => { res.json(generateMCPManifest(registry.getDefinitions(), { name: 'my-tools', version: '1.0.0', })); }); ``` ### Claude Desktop Integration Add to Claude Desktop config: ```json theme={null} { "mcpServers": { "my-tools": { "command": "node", "args": ["path/to/mcp-server.js"] } } } ``` ## llms.txt Generate context documents for LLMs: ```typescript theme={null} import { generateLlmsTxt } from '@conveniencepro/ctp-discovery'; const llmsTxt = generateLlmsTxt(tools, { name: 'My Tools', baseUrl: 'https://example.com', includeExamples: true, }); ``` ### Serve llms.txt ```typescript theme={null} app.get('/llms.txt', (req, res) => { res.type('text/plain').send( generateLlmsTxt(registry.getDefinitions()) ); }); ``` ## CTP Manifest Native CTP discovery format: ```typescript theme={null} import { generateCTPManifest } from '@conveniencepro/ctp-discovery'; const manifest = generateCTPManifest(tools, { name: 'my-tools', version: '1.0.0', baseUrl: 'https://api.example.com', homepage: 'https://example.com', }); ``` ### Structure ```json theme={null} { "$schema": "https://conveniencepro.cc/schemas/ctp-manifest.schema.json", "version": "1.0.0", "name": "my-tools", "baseUrl": "https://api.example.com", "tools": [ { "id": "json-formatter", "path": "/tools/json-formatter", "definition": { /* ... */ } } ], "categories": ["formatters", "encoders"], "generatedAt": "2024-01-15T12:00:00Z" } ``` ## ChatGPT Plugin Generate ChatGPT plugin manifest: ```typescript theme={null} import { generateChatGPTPlugin } from '@conveniencepro/ctp-discovery'; const plugin = generateChatGPTPlugin(tools, { nameForHuman: 'My Developer Tools', nameForModel: 'my_tools', descriptionForHuman: 'A collection of developer utilities', descriptionForModel: 'Tools for formatting, encoding, and generating data', auth: { type: 'none' }, contactEmail: 'support@example.com', legalInfoUrl: 'https://example.com/legal', }); ``` ### Serve Plugin Manifest ```typescript theme={null} app.get('/.well-known/ai-plugin.json', (req, res) => { res.json(generateChatGPTPlugin(tools, config)); }); ``` ## Build-Time Generation Generate all documents at build time: ```typescript theme={null} // scripts/generate-discovery.ts import { writeFileSync, mkdirSync } from 'fs'; import { generateOpenAPISpec, generateMCPManifest, generateLlmsTxt, generateCTPManifest, } from '@conveniencepro/ctp-discovery'; import { registry } from '../src/registry'; const tools = registry.getDefinitions(); const outDir = 'public/.well-known'; mkdirSync(outDir, { recursive: true }); // Generate all formats writeFileSync( 'public/openapi.json', JSON.stringify(generateOpenAPISpec(tools), null, 2) ); writeFileSync( `${outDir}/mcp.json`, JSON.stringify(generateMCPManifest(tools, { name: 'my-tools' }), null, 2) ); writeFileSync( 'public/llms.txt', generateLlmsTxt(tools) ); writeFileSync( `${outDir}/ctp.json`, JSON.stringify(generateCTPManifest(tools, { name: 'my-tools' }), null, 2) ); console.log('Discovery documents generated!'); ``` Add to `package.json`: ```json theme={null} { "scripts": { "generate:discovery": "ts-node scripts/generate-discovery.ts", "build": "npm run generate:discovery && vite build" } } ``` ## Recommended URLs | Path | Format | Purpose | | ----------------------------- | ----------- | ----------------- | | `/openapi.json` | OpenAPI 3.1 | API documentation | | `/.well-known/mcp.json` | MCP | AI tool discovery | | `/.well-known/ctp.json` | CTP | Native discovery | | `/.well-known/ai-plugin.json` | ChatGPT | Plugin manifest | | `/llms.txt` | Text | LLM context | # Embedding Source: https://spec.conveniencepro.cc/implementation/embedding Embed CTP tools in any web page # Embedding Tools Use the CTP SDK to embed tools in any website. ## SDK Installation ### CDN ```html theme={null} ``` ### npm ```bash theme={null} npm install @conveniencepro/ctp-sdk ``` ```typescript theme={null} import { CTP } from '@conveniencepro/ctp-sdk'; ``` ## Quick Start ### Declarative Embedding ```html theme={null}
``` ### Programmatic Embedding ```typescript theme={null} import { CTP } from '@conveniencepro/ctp-sdk'; CTP.init(); const tool = CTP.render('json-formatter', document.getElementById('container'), { defaults: { indent: '4' }, theme: 'dark', onResult: (result) => console.log(result), }); ``` ## Configuration ### Data Attributes ```html theme={null}
``` ### Programmatic Options ```typescript theme={null} CTP.render('json-formatter', container, { // Default parameter values defaults: { indent: '4', sortKeys: true, }, // Hide parameters from UI hide: ['sortKeys'], // Appearance theme: 'light', // 'light' | 'dark' | 'auto' compact: false, showHeader: true, showFooter: false, // Behavior autoSubmit: false, debounce: 300, // Callbacks onResult: (result) => { /* ... */ }, onError: (error) => { /* ... */ }, onChange: (params) => { /* ... */ }, }); ``` ## Theming ### Auto Theme ```typescript theme={null} CTP.init({ theme: 'auto', // Uses system preference }); ``` ### CSS Variables ```css theme={null} :root { --ctp-primary: #6366f1; --ctp-background: #ffffff; --ctp-surface: #f9fafb; --ctp-text: #1f2937; --ctp-border: #e5e7eb; --ctp-radius: 0.5rem; } [data-ctp-theme="dark"] { --ctp-background: #1f2937; --ctp-surface: #374151; --ctp-text: #f9fafb; --ctp-border: #4b5563; } ``` ### Framework Autosense The SDK automatically detects CSS frameworks: ```typescript theme={null} CTP.init({ autosense: true, // Auto-detect Tailwind, Bootstrap, etc. }); ``` Supported frameworks: * Tailwind CSS * Bootstrap * Chakra UI * Material UI * shadcn/ui ## Events and API ### Tool Instance ```typescript theme={null} const tool = CTP.create('json-formatter', { onResult: (result) => { if (result.success) { console.log('Output:', result.data); } }, }); // Mount to DOM document.getElementById('container').appendChild(tool.element); // Execute programmatically const result = await tool.execute({ json: '{"a":1}' }); // Get current parameter values const params = tool.getParams(); // Set parameter values tool.setParams({ indent: '4' }); // Reset to defaults tool.reset(); // Destroy instance tool.destroy(); ``` ### Global Events ```typescript theme={null} CTP.on('result', (event) => { console.log('Tool:', event.toolId); console.log('Result:', event.result); }); CTP.on('error', (event) => { console.error('Tool:', event.toolId); console.error('Error:', event.error); }); ``` ## Iframe Embedding For complete isolation: ```html theme={null} ``` ### PostMessage Communication ```typescript theme={null} const iframe = document.querySelector('iframe'); // Send parameters iframe.contentWindow.postMessage({ type: 'ctp:setParams', params: { json: '{"test":true}' }, }, '*'); // Execute tool iframe.contentWindow.postMessage({ type: 'ctp:execute', }, '*'); // Receive results window.addEventListener('message', (event) => { if (event.data.type === 'ctp:result') { console.log('Result:', event.data.result); } }); ``` ## React Integration ```tsx theme={null} import { useEffect, useRef } from 'react'; import { CTP } from '@conveniencepro/ctp-sdk'; function JsonFormatter() { const containerRef = useRef(null); const toolRef = useRef(null); useEffect(() => { if (containerRef.current) { toolRef.current = CTP.render('json-formatter', containerRef.current, { onResult: (result) => console.log(result), }); } return () => { toolRef.current?.destroy(); }; }, []); return
; } ``` ## Vue Integration ```vue theme={null} ``` ## Responsive Behavior ```typescript theme={null} CTP.init({ responsive: { compact: 640, // Compact mode below 640px stack: 480, // Stack layout below 480px }, }); ``` # Getting Started Source: https://spec.conveniencepro.cc/implementation/getting-started Set up your development environment for CTP tools # Getting Started This guide walks you through setting up a CTP tool development environment. ## Prerequisites * Node.js 18+ or 20+ * npm, pnpm, or yarn * TypeScript 5.0+ ## Project Setup ### 1. Create a New Project ```bash theme={null} mkdir my-ctp-tools cd my-ctp-tools npm init -y ``` ### 2. Install Dependencies ```bash npm theme={null} npm install @conveniencepro/ctp-core @conveniencepro/ctp-runtime npm install -D typescript @types/node ``` ```bash pnpm theme={null} pnpm add @conveniencepro/ctp-core @conveniencepro/ctp-runtime pnpm add -D typescript @types/node ``` ### 3. Configure TypeScript Create `tsconfig.json`: ```json theme={null} { "compilerOptions": { "target": "ES2022", "module": "ESNext", "moduleResolution": "bundler", "strict": true, "esModuleInterop": true, "skipLibCheck": true, "declaration": true, "outDir": "dist", "rootDir": "src" }, "include": ["src/**/*"] } ``` ### 4. Project Structure ``` my-ctp-tools/ ├── src/ │ ├── tools/ │ │ ├── my-tool.ts │ │ └── another-tool.ts │ ├── registry.ts │ └── index.ts ├── package.json └── tsconfig.json ``` ## Create Your First Tool Create `src/tools/text-reverser.ts`: ```typescript theme={null} import type { ToolDefinition, ToolFunction } from '@conveniencepro/ctp-core'; // Define the result type interface TextReverserResult { reversed: string; originalLength: number; isPalindrome: boolean; } // Tool definition export const textReverserDefinition: ToolDefinition = { id: 'text-reverser', name: 'Text Reverser', description: 'Reverse any text string and check if it is a palindrome.', category: 'editors', tags: ['text', 'reverse', 'palindrome', 'string'], method: 'POST', parameters: [ { name: 'text', type: 'textarea', label: 'Input Text', description: 'Text to reverse', required: true, placeholder: 'Enter text to reverse...', }, { name: 'ignoreSpaces', type: 'boolean', label: 'Ignore Spaces', description: 'Ignore spaces when checking for palindrome', required: false, defaultValue: false, }, ], outputDescription: 'Reversed text with palindrome detection', example: { input: { text: 'hello', ignoreSpaces: false }, output: { reversed: 'olleh', originalLength: 5, isPalindrome: false }, }, executionMode: 'client', }; // Tool implementation export const textReverserFn: ToolFunction = (params) => { const text = params.text as string; const ignoreSpaces = params.ignoreSpaces === true; if (!text) { return { success: false, error: 'Text is required', errorCode: 'MISSING_REQUIRED', }; } const reversed = text.split('').reverse().join(''); // Check palindrome const normalizedOriginal = ignoreSpaces ? text.toLowerCase().replace(/\s/g, '') : text.toLowerCase(); const normalizedReversed = ignoreSpaces ? reversed.toLowerCase().replace(/\s/g, '') : reversed.toLowerCase(); return { success: true, data: { reversed, originalLength: text.length, isPalindrome: normalizedOriginal === normalizedReversed, }, }; }; export default { definition: textReverserDefinition, fn: textReverserFn, }; ``` ## Register Tools Create `src/registry.ts`: ```typescript theme={null} import { ToolRegistry } from '@conveniencepro/ctp-runtime'; import textReverser from './tools/text-reverser'; // Create registry export const registry = new ToolRegistry(); // Register tools registry.register(textReverser.definition, textReverser.fn); // Export for use export default registry; ``` ## Test Your Tool Create `src/index.ts`: ```typescript theme={null} import { createRuntime } from '@conveniencepro/ctp-runtime'; import registry from './registry'; // Create runtime const runtime = createRuntime(registry); // Test execution async function main() { const result = await runtime.execute('text-reverser', { text: 'race car', ignoreSpaces: true, }); console.log('Result:', JSON.stringify(result, null, 2)); } main(); ``` Run with: ```bash theme={null} npx ts-node src/index.ts ``` Expected output: ```json theme={null} { "success": true, "data": { "reversed": "rac ecar", "originalLength": 8, "isPalindrome": true } } ``` ## Next Steps Learn tool creation patterns Input and output validation Generate OpenAPI and MCP manifests Reference implementations # Runtime Source: https://spec.conveniencepro.cc/implementation/runtime Tool execution runtime and registry # Runtime The CTP runtime provides tool registration, execution, and lifecycle management. ## Tool Registry The registry maintains a collection of registered tools: ```typescript theme={null} import { ToolRegistry } from '@conveniencepro/ctp-runtime'; const registry = new ToolRegistry(); ``` ### Register Tools ```typescript theme={null} import jsonFormatter from './tools/json-formatter'; import base64Encoder from './tools/base64-encoder'; // Register individual tool registry.register(jsonFormatter.definition, jsonFormatter.fn); // Register multiple tools registry.registerAll([ { definition: jsonFormatter.definition, fn: jsonFormatter.fn }, { definition: base64Encoder.definition, fn: base64Encoder.fn }, ]); ``` ### Query Registry ```typescript theme={null} // Get specific tool const tool = registry.get('json-formatter'); // { definition: {...}, fn: (...) => {...} } // Check if tool exists registry.has('json-formatter'); // true // List all tool IDs registry.list(); // ['json-formatter', 'base64-encoder'] // Get all definitions registry.getDefinitions(); // [definition1, definition2] // Find by category registry.findByCategory('formatters'); // [definition] // Find by tag registry.findByTag('json'); // [definition] ``` ### Unregister Tools ```typescript theme={null} // Remove a tool registry.unregister('json-formatter'); // Clear all tools registry.clear(); ``` ## Execution Runtime Create a runtime for executing tools: ```typescript theme={null} import { createRuntime } from '@conveniencepro/ctp-runtime'; const runtime = createRuntime(registry, { timeout: 30000, // Default 30s timeout validateInput: true, // Validate inputs validateOutput: true, // Validate outputs }); ``` ### Execute Tools ```typescript theme={null} // Basic execution const result = await runtime.execute('json-formatter', { json: '{"a":1}', indent: '2', }); // With options const result = await runtime.execute('json-formatter', params, { timeout: 5000, context: { userId: 'user-123', requestId: 'req-456', }, }); ``` ### Execution Context ```typescript theme={null} interface ExecutionContext { toolId: string; userId?: string; requestId?: string; timeout?: number; abortSignal?: AbortSignal; metadata?: Record; } // Context is passed to tool function export const myFn: ToolFunction = (params, context) => { console.log('Executing for user:', context?.userId); // ... }; ``` ## Timeout Handling ```typescript theme={null} const runtime = createRuntime(registry, { timeout: 10000, // 10 second default }); // Override per-execution const result = await runtime.execute('slow-tool', params, { timeout: 60000, // 60 seconds }); // Handle timeout if (!result.success && result.errorCode === 'TIMEOUT') { console.error('Execution timed out'); } ``` ## Abort Support Cancel long-running operations: ```typescript theme={null} const controller = new AbortController(); // Start execution const promise = runtime.execute('tool-id', params, { abortSignal: controller.signal, }); // Abort after 5 seconds setTimeout(() => controller.abort(), 5000); try { const result = await promise; } catch (error) { if (error.name === 'AbortError') { console.log('Execution was aborted'); } } ``` ## Parallel Execution ```typescript theme={null} // Execute multiple tools in parallel const results = await Promise.all([ runtime.execute('tool-1', params1), runtime.execute('tool-2', params2), runtime.execute('tool-3', params3), ]); // Process results results.forEach((result, index) => { if (result.success) { console.log(`Tool ${index + 1} succeeded:`, result.data); } else { console.error(`Tool ${index + 1} failed:`, result.error); } }); ``` ## Batch Execution ```typescript theme={null} // Execute same tool with multiple inputs const inputs = [ { json: '{"a":1}' }, { json: '{"b":2}' }, { json: '{"c":3}' }, ]; const results = await Promise.all( inputs.map(input => runtime.execute('json-formatter', input)) ); ``` ## Event Hooks ```typescript theme={null} const runtime = createRuntime(registry, { hooks: { beforeExecute: async (toolId, params, context) => { console.log(`Starting ${toolId}`); // Return modified params or throw to abort return params; }, afterExecute: async (toolId, params, result, context) => { console.log(`Finished ${toolId}:`, result.success); // Return modified result return result; }, onError: async (toolId, error, context) => { console.error(`Error in ${toolId}:`, error); // Log, report, etc. }, }, }); ``` ## Runtime Configuration ```typescript theme={null} interface RuntimeConfig { // Timeouts timeout?: number; // Default execution timeout maxConcurrent?: number; // Max parallel executions // Validation validateInput?: boolean; // Validate inputs validateOutput?: boolean; // Validate outputs strictMode?: boolean; // Strict validation // Error handling throwOnError?: boolean; // Throw instead of return error retries?: number; // Auto-retry failed executions retryDelay?: number; // Delay between retries // Logging logger?: Logger; // Custom logger logLevel?: 'debug' | 'info' | 'warn' | 'error'; // Hooks hooks?: RuntimeHooks; } ``` ## Express.js Integration ```typescript theme={null} import express from 'express'; import { createRuntime, ToolRegistry } from '@conveniencepro/ctp-runtime'; const app = express(); const registry = new ToolRegistry(); const runtime = createRuntime(registry); // Register tools... app.post('/api/tools/:toolId', express.json(), async (req, res) => { const { toolId } = req.params; if (!registry.has(toolId)) { return res.status(404).json({ success: false, error: 'Tool not found', errorCode: 'NOT_FOUND', }); } const result = await runtime.execute(toolId, req.body); const status = result.success ? 200 : 400; res.status(status).json(result); }); app.listen(3000); ``` # Validation Source: https://spec.conveniencepro.cc/implementation/validation Input and output validation for CTP tools # Validation CTP provides built-in validation for tool definitions, inputs, and outputs. ## Definition Validation Validate tool definitions against the CTP schema: ```typescript theme={null} import { validateToolDefinition } from '@conveniencepro/ctp-core'; const result = validateToolDefinition(myDefinition); if (!result.valid) { result.errors.forEach(error => { console.error(`${error.path}: ${error.message}`); }); } ``` ### Validation Result ```typescript theme={null} interface ValidationResult { valid: boolean; errors: ValidationError[]; } interface ValidationError { path: string; // JSON path to error (e.g., "parameters[0].name") message: string; // Human-readable error message code: string; // Error code (e.g., "MISSING_REQUIRED") } ``` ### Common Validation Errors | Code | Message | Fix | | --------------------- | ------------------------------------- | ----------------------------- | | `MISSING_REQUIRED` | Required field missing | Add the required field | | `INVALID_ID` | ID must be lowercase hyphen-separated | Use format `my-tool-name` | | `INVALID_CATEGORY` | Unknown category | Use one of 8 valid categories | | `DUPLICATE_PARAMETER` | Parameter name already used | Use unique parameter names | ## Input Validation Validate parameters before execution: ```typescript theme={null} import { validateParameters } from '@conveniencepro/ctp-core'; const result = validateParameters(myDefinition.parameters, userInput); if (!result.valid) { return { success: false, error: result.errors[0].message, errorCode: 'INVALID_INPUT', }; } ``` ### Automatic Runtime Validation The runtime can validate automatically: ```typescript theme={null} import { createRuntime } from '@conveniencepro/ctp-runtime'; const runtime = createRuntime(registry, { validateInput: true, // Validate before execution validateOutput: true, // Validate after execution }); // Validation errors returned automatically const result = await runtime.execute('my-tool', { /* invalid params */ }); // result.errorCode === 'INVALID_INPUT' ``` ## Parameter Constraints ### String Validation ```typescript theme={null} { name: 'username', type: 'text', validation: { minLength: 3, maxLength: 20, pattern: '^[a-z0-9_]+$', }, } ``` ### Number Validation ```typescript theme={null} { name: 'quantity', type: 'number', validation: { min: 1, max: 100, step: 1, }, } ``` ### File Validation ```typescript theme={null} { name: 'document', type: 'file', validation: { accept: ['.json', '.txt', 'application/json'], maxSize: 5242880, // 5MB }, } ``` ## Manual Validation in Tools Implement validation in your tool function: ```typescript theme={null} export const myFn: ToolFunction = (params) => { const input = params.input; // 1. Required check if (input === undefined || input === null || input === '') { return { success: false, error: 'Input is required', errorCode: 'MISSING_REQUIRED', }; } // 2. Type check if (typeof input !== 'string') { return { success: false, error: 'Input must be a string', errorCode: 'TYPE_ERROR', }; } // 3. Length check if (input.length < 1) { return { success: false, error: 'Input must not be empty', errorCode: 'CONSTRAINT_VIOLATION', }; } if (input.length > 100000) { return { success: false, error: 'Input exceeds maximum length of 100,000 characters', errorCode: 'CONSTRAINT_VIOLATION', }; } // 4. Pattern check if (!/^[\s\S]*$/.test(input)) { return { success: false, error: 'Input contains invalid characters', errorCode: 'INVALID_INPUT', }; } // Validation passed, proceed with processing return { success: true, data: process(input), }; }; ``` ## Result Validation Validate tool output: ```typescript theme={null} import { validateToolResult } from '@conveniencepro/ctp-core'; const result = myFn(params); const validation = validateToolResult(result); if (!validation.valid) { console.error('Tool returned invalid result:', validation.errors); } ``` ### Result Requirements ```typescript theme={null} // ✅ Valid success result { success: true, data: { /* ... */ } } // ✅ Valid error result { success: false, error: 'message', errorCode: 'INVALID_INPUT' } // ❌ Invalid: missing success { data: { /* ... */ } } // ❌ Invalid: success true but no data { success: true } // ❌ Invalid: success false but no error { success: false } ``` ## Validation Helper Functions ```typescript theme={null} import { isValidToolId, isValidCategory, isValidParameterType, } from '@conveniencepro/ctp-core'; // Check ID format isValidToolId('my-tool'); // true isValidToolId('My Tool'); // false isValidToolId('my_tool'); // false // Check category isValidCategory('formatters'); // true isValidCategory('custom'); // false // Check parameter type isValidParameterType('text'); // true isValidParameterType('string'); // false ``` ## Schema Validation Use JSON Schema for advanced validation: ```typescript theme={null} import Ajv from 'ajv'; import toolDefinitionSchema from '@conveniencepro/ctp-spec/schemas/tool-definition.schema.json'; const ajv = new Ajv(); const validate = ajv.compile(toolDefinitionSchema); const valid = validate(myDefinition); if (!valid) { console.error(validate.errors); } ``` ## Best Practices Check required parameters and basic types before doing any processing. Error messages should tell users exactly what's wrong and how to fix it. Include `suggestion` in error results to help users fix issues. ```typescript theme={null} { success: false, error: 'Invalid JSON syntax', errorCode: 'INVALID_INPUT', suggestion: 'Check for missing commas or unquoted keys', } ``` Enforce min/max lengths, ranges, and patterns to prevent edge cases. # ConveniencePro Tool Protocol Source: https://spec.conveniencepro.cc/index Open specification for browser-native developer tools with MCP compatibility # ConveniencePro Tool Protocol (CTP) **Version 1.0.0** | [GitHub](https://github.com/titan-alpha/ctp) CTP is an open specification for building browser-native developer tools that are inherently compatible with the [Model Context Protocol (MCP)](https://modelcontextprotocol.io). It enables developers to create tools that work seamlessly in web browsers while maintaining full interoperability with AI-powered development environments. ## Why CTP? Tools execute directly in the browser using Web APIs, ensuring privacy and eliminating server dependencies. Automatic conversion to MCP format enables integration with Claude, Cursor, and other AI tools. Full TypeScript support with comprehensive schemas and validation. Built-in AI hints and instructions help LLMs use your tools effectively. ## Quick Example ```typescript theme={null} import type { ToolDefinition, ToolFunction } from '@conveniencepro/ctp-core'; export const myToolDefinition: ToolDefinition = { id: 'hello-world', name: 'Hello World', description: 'A simple greeting tool', category: 'utilities', tags: ['hello', 'greeting', 'demo'], method: 'POST', parameters: [ { name: 'name', type: 'text', label: 'Your Name', description: 'Name to greet', required: true, }, ], outputDescription: 'Greeting message', example: { input: { name: 'World' }, output: { message: 'Hello, World!' }, }, executionMode: 'client', }; export const myToolFn: ToolFunction<{ message: string }> = (params) => { return { success: true, data: { message: `Hello, ${params.name}!` }, }; }; ``` ## Architecture ```mermaid theme={null} %%{init: {'theme':'base', 'themeVariables': { 'primaryColor':'#ffffff','primaryTextColor':'#0f172a','primaryBorderColor':'#6366f1','lineColor':'#475569','secondaryColor':'#f8fafc','tertiaryColor':'#fefce8','clusterBkg':'#ffffff','clusterBorder':'#cbd5e1','fontSize':'15px','fontFamily':'ui-sans-serif, system-ui, -apple-system, sans-serif'}}}%% flowchart TB subgraph core[" 
Core Packages
 "] direction LR A["@conveniencepro/ctp-core
Types & Validation"] B["@conveniencepro/ctp-runtime
Execution Engine"] C["@conveniencepro/ctp-discovery
OpenAPI & Manifests"] end A --> B --> C SPACER1[" "] subgraph sdk[" 
Embeddable SDK
 "] D["@conveniencepro/ctp-sdk
Widget with Autosense"] end C --> SPACER1 SPACER1 --> D SPACER2[" "] subgraph output[" 
Discovery Formats
 "] direction LR E["OpenAPI 3.1"] F["MCP Manifest"] G["llms.txt"] end D --> SPACER2 SPACER2 --> E SPACER2 --> F SPACER2 --> G classDef coreStyle fill:#ffffff,stroke:#6366f1,stroke-width:3px,color:#0f172a,rx:12,ry:12 classDef sdkStyle fill:#ffffff,stroke:#3b82f6,stroke-width:3px,color:#0f172a,rx:12,ry:12 classDef outputStyle fill:#ffffff,stroke:#10b981,stroke-width:3px,color:#0f172a,rx:12,ry:12 classDef spacerStyle fill:none,stroke:none,color:transparent class A,B,C coreStyle class D sdkStyle class E,F,G outputStyle class SPACER1,SPACER2 spacerStyle style core fill:#fefce8,stroke:#ca8a04,stroke-width:4px,stroke-dasharray:0,rx:16,ry:16,color:#422006 style sdk fill:#eff6ff,stroke:#2563eb,stroke-width:4px,stroke-dasharray:0,rx:16,ry:16,color:#1e3a8a style output fill:#f0fdf4,stroke:#059669,stroke-width:4px,stroke-dasharray:0,rx:16,ry:16,color:#14532d linkStyle default stroke:#475569,stroke-width:3px ``` ## npm Packages | Package | Description | | -------------------------------------------------------------------------------------------- | ----------------------------------------- | | [`@conveniencepro/ctp-core`](https://npmjs.com/package/@conveniencepro/ctp-core) | Core types and validation | | [`@conveniencepro/ctp-runtime`](https://npmjs.com/package/@conveniencepro/ctp-runtime) | Tool execution engine | | [`@conveniencepro/ctp-discovery`](https://npmjs.com/package/@conveniencepro/ctp-discovery) | Discovery document generators | | [`@conveniencepro/ctp-sdk`](https://npmjs.com/package/@conveniencepro/ctp-sdk) | Embeddable SDK | | [`@conveniencepro/ctp-spec`](https://npmjs.com/package/@conveniencepro/ctp-spec) | Specification constants | | [`@conveniencepro/ctp-examples`](https://npmjs.com/package/@conveniencepro/ctp-examples) | Example tool implementations | | [`@conveniencepro/ctp-mcp-server`](https://npmjs.com/package/@conveniencepro/ctp-mcp-server) | MCP server for AI-powered tool generation | ## Get Started Understand the complete CTP protocol Step-by-step guide to creating tools Reference implementations Have AI generate tools for you AI-powered tool generation via Model Context Protocol # LLM Integration Source: https://spec.conveniencepro.cc/llm-prompts/overview Documents for AI-powered tool generation # LLM Integration CTP provides specialized documents that enable AI models to generate compliant tools. ## Available Documents Complete prompt for generating CTP tools Compact schema for quick AI lookups ## How It Works 1. **Copy the prompt** from the Tool Generator page 2. **Paste into your AI** conversation (Claude, GPT-4, etc.) 3. **Describe the tool** you want to create 4. **Receive compliant code** that follows CTP standards ## Example Workflow ### Step 1: Provide the Prompt Copy the entire [Tool Generator](/llm-prompts/tool-generator) document and paste it into your AI conversation. ### Step 2: Request a Tool ``` Create a URL encoder/decoder tool that: - Encodes text for use in URLs - Decodes URL-encoded strings back to text - Supports encoding all characters or just special ones ``` ### Step 3: Receive Complete Implementation The AI will generate: * TypeScript type definitions * Complete tool definition * Tool function implementation * Export statement ## Quick Reference For quick AI lookups during development, the [Schema Reference](/llm-prompts/schema-reference) provides: * Field types and descriptions * Parameter type options * Error codes * Category list * Common patterns ## Supported AI Models These documents are designed to work with: | Model | Provider | Notes | | ----------------- | --------- | -------------- | | Claude 3 | Anthropic | Best results | | Claude 3.5 Sonnet | Anthropic | Fast, accurate | | GPT-4 | OpenAI | Good results | | GPT-4 Turbo | OpenAI | Good results | | Gemini Pro | Google | Compatible | ## Best Practices ### Be Specific ``` ❌ "Make a text tool" ✅ "Create a tool that counts words, characters, and sentences in text" ``` ### Include Features ``` ❌ "Make a hash tool" ✅ "Create a hash generator that supports SHA-256 and SHA-512, with hex and base64 output options" ``` ### Mention Edge Cases ``` ❌ "Make a JSON formatter" ✅ "Create a JSON formatter with options for indentation, that handles invalid JSON gracefully with helpful error messages" ``` ## Integration Options ### Manual Copy-Paste 1. Copy the Tool Generator prompt 2. Paste into AI chat 3. Request your tool 4. Copy generated code to your project ### API Integration ```typescript theme={null} import Anthropic from '@anthropic-ai/sdk'; import { TOOL_GENERATOR_PROMPT } from './prompts'; const client = new Anthropic(); async function generateTool(description: string) { const response = await client.messages.create({ model: 'claude-3-5-sonnet-20241022', max_tokens: 4096, system: TOOL_GENERATOR_PROMPT, messages: [ { role: 'user', content: `Create a CTP tool: ${description}`, }, ], }); return response.content[0].text; } ``` ### MCP Integration CTP tools can be exposed as MCP tools for direct AI access: ```typescript theme={null} import { generateMCPManifest } from '@conveniencepro/ctp-discovery'; // Expose your tools to AI assistants const manifest = generateMCPManifest(myTools); ``` # Schema Reference Source: https://spec.conveniencepro.cc/llm-prompts/schema-reference Compact schema reference for AI lookups # Schema Quick Reference Compact reference for CTP schemas, designed for quick AI lookups. ## Tool Definition ```typescript theme={null} interface ToolDefinition { // Required id: string; // lowercase-hyphen-separated name: string; // Display name (max 50) description: string; // What it does (max 500) category: Category; // See categories below tags: string[]; // Search tags (min 1) method: 'GET' | 'POST'; // HTTP method parameters: Parameter[]; // Input params outputDescription: string; // Output description example: { input: object; output: object }; // Optional version?: string; // Semver "1.0.0" icon?: string; // Emoji or icon ID aiInstructions?: string; // AI guidance executionMode?: 'client' | 'server' | 'hybrid'; requiresAuth?: boolean; rateLimit?: { requests: number; window: number }; } ``` ## Parameter Types | Type | Input | Use Case | | ---------- | ------------ | --------------- | | `text` | Single line | Short strings | | `textarea` | Multi-line | Long text, code | | `number` | Numeric | Counts, sizes | | `boolean` | Toggle | Flags, options | | `select` | Dropdown | Fixed choices | | `json` | JSON editor | Structured data | | `file` | File picker | Uploads | | `color` | Color picker | Colors | | `date` | Date picker | Dates | | `datetime` | DateTime | Timestamps | | `url` | URL input | Links | | `email` | Email input | Addresses | ## Parameter Schema ```typescript theme={null} interface Parameter { name: string; // camelCase type: ParameterType; // See types above label: string; // Display label description: string; // Help text required: boolean; // Optional defaultValue?: any; placeholder?: string; options?: Option[]; // For select validation?: Validation; dependsOn?: Dependency[]; aiHint?: string; group?: string; order?: number; hidden?: boolean; } ``` ## Categories | Category | Purpose | | ------------ | ------------------------------- | | `formatters` | Format data (JSON, SQL, XML) | | `encoders` | Encode/decode (Base64, URL) | | `generators` | Generate (UUID, hash, password) | | `converters` | Convert formats (units, colors) | | `validators` | Validate (JSON, email, URL) | | `analyzers` | Analyze (diff, regex) | | `editors` | Transform (case, replace) | | `utilities` | General utilities | ## Error Codes | Code | HTTP | Cause | | ---------------------- | ---- | ---------------------- | | `INVALID_INPUT` | 400 | Bad input format | | `MISSING_REQUIRED` | 400 | Required param missing | | `TYPE_ERROR` | 400 | Wrong type | | `CONSTRAINT_VIOLATION` | 400 | Out of range | | `EXECUTION_ERROR` | 500 | Runtime error | | `TIMEOUT` | 504 | Too slow | | `RATE_LIMITED` | 429 | Too many requests | | `UNAUTHORIZED` | 401 | Auth required | ## Result Format ```typescript theme={null} // Success { success: true, data: { /* result */ }, metadata?: { executionTime?: number; warnings?: string[] } } // Error { success: false, error: "Message", errorCode: "ERROR_CODE", suggestion?: "How to fix" } ``` ## Validation Constraints ```typescript theme={null} interface Validation { minLength?: number; // String min maxLength?: number; // String max pattern?: string; // Regex pattern min?: number; // Number min max?: number; // Number max step?: number; // Number step accept?: string[]; // File types maxSize?: number; // File bytes } ``` ## Conditional Display ```typescript theme={null} dependsOn: [ { field: 'mode', condition: 'equals', value: 'advanced' } ] ``` Conditions: `equals`, `notEquals`, `contains`, `exists` ## Select Options ```typescript theme={null} options: [ { value: 'opt1', label: 'Option 1' }, { value: 'opt2', label: 'Option 2', description: 'With description' }, { value: 'opt3', label: 'Option 3', disabled: true } ] ``` ## Execution Modes | Mode | Where | Use Case | | -------- | ------- | ------------------- | | `client` | Browser | Most tools, privacy | | `server` | Node.js | File system, DB | | `hybrid` | Both | Flexible deployment | ## Common Patterns ### Sync Tool ```typescript theme={null} const fn: ToolFunction = (params) => { return { success: true, data: result }; }; ``` ### Async Tool ```typescript theme={null} const fn: ToolFunction = async (params) => { const result = await asyncOp(); return { success: true, data: result }; }; ``` ### With Validation ```typescript theme={null} if (!params.input) { return { success: false, error: 'Required', errorCode: 'MISSING_REQUIRED' }; } ``` ### With Metadata ```typescript theme={null} return { success: true, data: result, metadata: { executionTime: Date.now() - start } }; ``` # Tool Generator Prompt Source: https://spec.conveniencepro.cc/llm-prompts/tool-generator Complete prompt for AI-powered CTP tool generation # Tool Generator Prompt Copy this entire document and paste it into an AI conversation to enable CTP tool generation. Copy everything in the code block below and paste it as the first message in your AI conversation. ````markdown theme={null} # CTP Tool Generator You are an expert at creating CTP (ConveniencePro Tool Protocol) compliant developer tools. Generate complete, production-ready tool implementations following these specifications. ## Tool Structure Every tool consists of: 1. Result interface (TypeScript) 2. Tool definition (ToolDefinition) 3. Tool function (ToolFunction) 4. Default export ## Required Fields (ToolDefinition) | Field | Type | Description | |-------|------|-------------| | `id` | string | Lowercase, hyphen-separated (e.g., "json-formatter") | | `name` | string | Human-readable name (max 50 chars) | | `description` | string | What the tool does (max 500 chars) | | `category` | string | One of: formatters, encoders, generators, converters, validators, analyzers, editors, utilities | | `tags` | string[] | Searchable keywords (min 1) | | `method` | "GET" \| "POST" | HTTP method (usually POST) | | `parameters` | Parameter[] | Input parameters | | `outputDescription` | string | What the tool returns | | `example` | { input, output } | Example usage | ## Parameter Schema ```typescript { name: string; // camelCase identifier type: "text" | "textarea" | "number" | "boolean" | "select" | "json" | "file" | "color" | "date" | "datetime" | "url" | "email"; label: string; // Display label description: string; // Help text required: boolean; // Is required? defaultValue?: any; // Default if not provided options?: { value: string; label: string; description?: string }[]; // For select type validation?: { minLength?: number; maxLength?: number; min?: number; max?: number; pattern?: string }; dependsOn?: { field: string; condition: "equals" | "notEquals"; value: any }[]; // Conditional display aiHint?: string; // Guidance for AI models } ```` ## Result Format ```typescript theme={null} interface ToolResult { success: boolean; data?: T; // On success error?: string; // On failure errorCode?: "INVALID_INPUT" | "MISSING_REQUIRED" | "TYPE_ERROR" | "CONSTRAINT_VIOLATION" | "EXECUTION_ERROR" | "TIMEOUT"; suggestion?: string; // Help fix the error metadata?: { executionTime?: number; warnings?: string[]; }; } ``` ## Template ```typescript theme={null} import type { ToolDefinition, ToolFunction } from '@conveniencepro/ctp-core'; interface [ToolName]Result { // Define result properties } export const [toolName]Definition: ToolDefinition = { id: '[tool-id]', name: '[Tool Name]', description: '[What the tool does]', category: '[category]', tags: ['tag1', 'tag2'], method: 'POST', parameters: [ { name: '[paramName]', type: '[type]', label: '[Label]', description: '[Description]', required: true, }, ], outputDescription: '[What is returned]', example: { input: { /* example input */ }, output: { /* example output */ }, }, executionMode: 'client', }; export const [toolName]Fn: ToolFunction<[ToolName]Result> = (params) => { // 1. Extract and validate parameters const input = params.[paramName] as string; if (!input) { return { success: false, error: '[Parameter] is required', errorCode: 'MISSING_REQUIRED', }; } // 2. Process try { const result = /* processing logic */; return { success: true, data: result, }; } catch (e) { return { success: false, error: (e as Error).message, errorCode: 'EXECUTION_ERROR', }; } }; export default { definition: [toolName]Definition, fn: [toolName]Fn }; ``` ## Rules 1. Always validate required parameters first 2. Use try-catch for operations that can fail 3. Return helpful error messages with suggestions 4. Include metadata for performance tracking 5. Use appropriate parameter types 6. Add aiHint for parameters where AI guidance helps 7. Tools with executionMode: 'client' must not make network requests ## Categories * `formatters`: Format/beautify data (JSON, SQL, XML) * `encoders`: Encode/decode data (Base64, URL, HTML) * `generators`: Generate data (UUID, hash, password) * `converters`: Convert between formats (units, colors) * `validators`: Validate data (JSON, email, URL) * `analyzers`: Analyze data (diff, regex test) * `editors`: Edit/transform data (case, replace) * `utilities`: General utilities (timestamp) When asked to create a tool, generate complete, working code following this specification. ``` ## Using This Prompt After pasting the prompt above, you can ask the AI to create tools: **Example requests:** - "Create a UUID generator tool with options for v4 and v7" - "Make a URL encoder that handles all special characters" - "Build a word counter that also shows reading time" - "Create a color converter between hex, RGB, and HSL" The AI will generate complete, CTP-compliant implementations. ``` # Quickstart Source: https://spec.conveniencepro.cc/quickstart Create your first CTP-compliant tool in 5 minutes # Quickstart This guide will walk you through creating a CTP-compliant tool from scratch. ## Installation ```bash npm theme={null} npm install @conveniencepro/ctp-core @conveniencepro/ctp-runtime ``` ```bash pnpm theme={null} pnpm add @conveniencepro/ctp-core @conveniencepro/ctp-runtime ``` ```bash yarn theme={null} yarn add @conveniencepro/ctp-core @conveniencepro/ctp-runtime ``` ## Create a Tool Create a new file `my-tool.ts`: ```typescript theme={null} import type { ToolDefinition, ToolFunction } from '@conveniencepro/ctp-core'; // 1. Define the tool's result type interface UppercaseResult { result: string; originalLength: number; } // 2. Create the tool definition export const uppercaseDefinition: ToolDefinition = { id: 'uppercase-converter', name: 'Uppercase Converter', description: 'Convert text to uppercase.', category: 'converters', tags: ['uppercase', 'text', 'convert'], method: 'POST', parameters: [ { name: 'text', type: 'textarea', label: 'Input Text', description: 'Text to convert to uppercase', required: true, }, ], outputDescription: 'Uppercase version of the input text', example: { input: { text: 'hello world' }, output: { result: 'HELLO WORLD', originalLength: 11 }, }, executionMode: 'client', }; // 3. Implement the tool function export const uppercaseFn: ToolFunction = (params) => { const text = params.text as string; if (!text) { return { success: false, error: 'Text is required', errorCode: 'MISSING_REQUIRED', }; } return { success: true, data: { result: text.toUpperCase(), originalLength: text.length, }, }; }; export default { definition: uppercaseDefinition, fn: uppercaseFn }; ``` ## Register and Execute ```typescript theme={null} import { ToolRegistry, createRuntime } from '@conveniencepro/ctp-runtime'; import uppercaseTool from './my-tool'; // Create registry and register the tool const registry = new ToolRegistry(); registry.register(uppercaseTool.definition, uppercaseTool.fn); // Create runtime const runtime = createRuntime(registry); // Execute the tool const result = await runtime.execute('uppercase-converter', { text: 'hello world', }); console.log(result); // { // success: true, // data: { result: 'HELLO WORLD', originalLength: 11 } // } ``` ## Validate Your Tool ```typescript theme={null} import { validateToolDefinition } from '@conveniencepro/ctp-core'; const validation = validateToolDefinition(uppercaseTool.definition); if (!validation.valid) { console.error('Validation errors:', validation.errors); } else { console.log('Tool is CTP-compliant!'); } ``` ## Generate Discovery Documents ```typescript theme={null} import { generateOpenAPISpec, generateMCPManifest } from '@conveniencepro/ctp-discovery'; // Generate OpenAPI 3.1 specification const openapi = generateOpenAPISpec([uppercaseTool.definition]); // Generate MCP-compatible manifest const mcpManifest = generateMCPManifest([uppercaseTool.definition]); ``` ## Next Steps Learn all available definition options Explore all 12 parameter types Understand MCP compatibility See complete tool implementations # Discovery Source: https://spec.conveniencepro.cc/specification/discovery OpenAPI, MCP manifest, and llms.txt generation # Discovery Documents CTP tools are discoverable through multiple standardized formats. ## Supported Formats | Format | Purpose | Consumers | | -------------- | -------------------- | ----------------------------- | | OpenAPI 3.1 | API documentation | Swagger, Postman, API clients | | MCP Manifest | AI tool integration | Claude, Cursor, AI assistants | | llms.txt | LLM context | LLM-based applications | | CTP Manifest | Native CTP discovery | ConveniencePro ecosystem | | ChatGPT Plugin | ChatGPT integration | OpenAI plugins | ## OpenAPI 3.1 Specification ```typescript theme={null} import { generateOpenAPISpec } from '@conveniencepro/ctp-discovery'; const spec = generateOpenAPISpec(tools, { info: { title: 'My Tools API', version: '1.0.0', description: 'Collection of developer tools', }, servers: [ { url: 'https://api.example.com/v1' }, ], }); ``` ### Generated Structure ```yaml theme={null} openapi: "3.1.0" info: title: "My Tools API" version: "1.0.0" paths: /tools/json-formatter: post: operationId: "json-formatter" summary: "JSON Formatter" description: "Format, validate, and beautify JSON data" requestBody: content: application/json: schema: type: object required: ["json"] properties: json: type: string description: "JSON string to format" indent: type: string enum: ["0", "2", "4", "tab"] default: "2" responses: "200": description: "Success" content: application/json: schema: $ref: "#/components/schemas/ToolResult" ``` ## MCP Manifest Generate Model Context Protocol compatible manifests: ```typescript theme={null} import { generateMCPManifest } from '@conveniencepro/ctp-discovery'; const manifest = generateMCPManifest(tools, { name: 'my-tools', version: '1.0.0', description: 'Developer tool collection', }); ``` ### Generated Structure ```json theme={null} { "name": "my-tools", "version": "1.0.0", "description": "Developer tool collection", "tools": [ { "name": "json-formatter", "title": "JSON Formatter", "description": "Format, validate, and beautify JSON data", "inputSchema": { "type": "object", "required": ["json"], "properties": { "json": { "type": "string", "description": "JSON string to format" }, "indent": { "type": "string", "enum": ["0", "2", "4", "tab"], "default": "2" } } } } ] } ``` ## llms.txt Generate context documents for LLMs: ```typescript theme={null} import { generateLlmsTxt } from '@conveniencepro/ctp-discovery'; const llmsTxt = generateLlmsTxt(tools, { baseUrl: 'https://conveniencepro.cc', name: 'ConveniencePro Tools', }); ``` ### Generated Structure ```markdown theme={null} # ConveniencePro Tools > Developer tools for formatting, encoding, and generating data. ## Available Tools ### json-formatter Format, validate, and beautify JSON data with customizable indentation. **Parameters:** - `json` (required): JSON string to format - `indent`: Indentation style (0, 2, 4, tab). Default: 2 - `sortKeys`: Sort object keys alphabetically **Example:** Input: {"b":2,"a":1} Output: { "a": 1, "b": 2 } --- ### base64-encoder Encode text to Base64 or decode Base64 back to text. ... ``` ## CTP Manifest Native CTP discovery format: ```typescript theme={null} import { generateCTPManifest } from '@conveniencepro/ctp-discovery'; const manifest = generateCTPManifest(tools, { name: 'my-tools', version: '1.0.0', baseUrl: 'https://api.example.com', }); ``` ### Structure ```json theme={null} { "$schema": "https://conveniencepro.cc/schemas/ctp-manifest.schema.json", "version": "1.0.0", "name": "my-tools", "description": "Developer tool collection", "baseUrl": "https://api.example.com", "tools": [ { "id": "json-formatter", "path": "/tools/json-formatter", "definition": { /* full tool definition */ } } ], "categories": ["formatters", "encoders", "generators"], "generatedAt": "2024-01-15T12:00:00Z" } ``` ## Serving Discovery Documents ### Express.js Example ```typescript theme={null} import express from 'express'; import { generateOpenAPISpec, generateMCPManifest, generateLlmsTxt, } from '@conveniencepro/ctp-discovery'; const app = express(); // OpenAPI spec app.get('/openapi.json', (req, res) => { res.json(generateOpenAPISpec(tools)); }); // MCP manifest app.get('/.well-known/mcp.json', (req, res) => { res.json(generateMCPManifest(tools)); }); // llms.txt app.get('/llms.txt', (req, res) => { res.type('text/plain').send(generateLlmsTxt(tools)); }); ``` ### Static Generation ```typescript theme={null} import { writeFileSync } from 'fs'; // Generate at build time writeFileSync('public/openapi.json', JSON.stringify(generateOpenAPISpec(tools))); writeFileSync('public/.well-known/mcp.json', JSON.stringify(generateMCPManifest(tools))); writeFileSync('public/llms.txt', generateLlmsTxt(tools)); ``` ## Well-Known URLs CTP recommends these standard paths: | Path | Format | Purpose | | ----------------------------- | ----------- | ----------------- | | `/openapi.json` | OpenAPI 3.1 | API documentation | | `/.well-known/mcp.json` | MCP | AI tool discovery | | `/llms.txt` | Text | LLM context | | `/.well-known/ctp.json` | CTP | Native discovery | | `/.well-known/ai-plugin.json` | ChatGPT | Plugin manifest | # Embedding Source: https://spec.conveniencepro.cc/specification/embedding Widget embedding and autosense styling # Embedding Tools CTP tools can be embedded in any web page using the SDK. ## Quick Start ```html theme={null}
``` ## SDK Installation ### CDN ```html theme={null} ``` ### npm ```bash theme={null} npm install @conveniencepro/ctp-sdk ``` ```typescript theme={null} import { CTP } from '@conveniencepro/ctp-sdk'; CTP.init({ autosense: true }); ``` ## Embedding Methods ### Declarative (Data Attributes) ```html theme={null}
``` ### Programmatic ```typescript theme={null} import { CTP } from '@conveniencepro/ctp-sdk'; // Render to container CTP.render('json-formatter', document.getElementById('container'), { defaults: { indent: '4', sortKeys: true }, hide: ['sortKeys'], theme: 'dark', }); // Create standalone instance const tool = CTP.create('json-formatter', { onResult: (result) => console.log(result), onError: (error) => console.error(error), }); document.getElementById('container').appendChild(tool.element); ``` ## Configuration Options ```typescript theme={null} interface EmbedConfig { // Tool configuration toolId: string; defaults?: Record; hide?: string[]; // Parameters to hide // Appearance theme?: 'light' | 'dark' | 'auto' | 'inherit'; compact?: boolean; // Compact mode showHeader?: boolean; // Show tool header showFooter?: boolean; // Show footer/branding // Behavior autoSubmit?: boolean; // Submit on input change debounce?: number; // Debounce delay (ms) validateOnChange?: boolean; // Callbacks onResult?: (result: ToolResult) => void; onError?: (error: Error) => void; onChange?: (params: Record) => void; } ``` ## Autosense Autosense automatically detects and matches the host page's styling framework. ### Supported Frameworks | Framework | Detection | Styling | | ------------ | -------------- | ----------------------- | | Tailwind CSS | Class patterns | Native Tailwind classes | | Bootstrap | CSS variables | Bootstrap utilities | | Chakra UI | CSS variables | Chakra tokens | | Material UI | Theme provider | MUI styling | | shadcn/ui | CSS variables | shadcn components | | None | Fallback | Built-in neutral theme | ### How It Works ```typescript theme={null} CTP.init({ autosense: true, // Enable automatic detection }); ``` The SDK: 1. Scans the page for framework indicators 2. Detects CSS variables and class patterns 3. Applies matching styling tokens 4. Falls back to neutral theme if undetected ### Manual Override ```typescript theme={null} CTP.init({ autosense: false, theme: { framework: 'tailwind', colors: { primary: '#6366f1', background: '#ffffff', text: '#1f2937', }, borderRadius: '0.5rem', }, }); ``` ## Theme Configuration ### Using CSS Variables ```css theme={null} :root { --ctp-primary: #6366f1; --ctp-primary-hover: #4f46e5; --ctp-background: #ffffff; --ctp-surface: #f9fafb; --ctp-text: #1f2937; --ctp-text-muted: #6b7280; --ctp-border: #e5e7eb; --ctp-radius: 0.5rem; --ctp-font-family: system-ui, sans-serif; --ctp-font-mono: ui-monospace, monospace; } ``` ### Dark Mode ```typescript theme={null} CTP.init({ theme: 'dark', // or 'auto' for system preference }); ``` ```css theme={null} [data-ctp-theme="dark"] { --ctp-background: #1f2937; --ctp-surface: #374151; --ctp-text: #f9fafb; --ctp-border: #4b5563; } ``` ## Event Handling ```typescript theme={null} const tool = CTP.create('json-formatter', { onResult: (result) => { if (result.success) { console.log('Formatted:', result.data.formatted); } else { console.error('Error:', result.error); } }, onChange: (params) => { console.log('Parameters changed:', params); }, }); // Programmatic execution tool.execute({ json: '{"test":true}' }); // Get current values const currentParams = tool.getParams(); // Reset to defaults tool.reset(); // Destroy instance tool.destroy(); ``` ## Iframe Embedding For complete isolation: ```html theme={null} ``` ### PostMessage Communication ```typescript theme={null} // Parent page const iframe = document.querySelector('iframe'); // Send parameters iframe.contentWindow.postMessage({ type: 'ctp:setParams', params: { json: '{"test":true}' }, }, 'https://conveniencepro.cc'); // Receive results window.addEventListener('message', (event) => { if (event.origin !== 'https://conveniencepro.cc') return; if (event.data.type === 'ctp:result') { console.log('Result:', event.data.result); } }); ``` ## Responsive Behavior The SDK automatically adjusts for different viewport sizes: ```css theme={null} /* Compact mode on small screens */ @media (max-width: 640px) { [data-ctp-embed] { --ctp-compact: true; } } ``` ```typescript theme={null} CTP.init({ responsive: { compact: 640, // Compact mode below 640px stack: 480, // Stack layout below 480px }, }); ``` # Execution Source: https://spec.conveniencepro.cc/specification/execution Tool execution modes and runtime behavior # Tool Execution CTP defines three execution modes that determine where and how tools run. ## Execution Modes ### Client Mode (Default) Tools execute entirely in the browser using Web APIs. ```typescript theme={null} export const myDefinition: ToolDefinition = { // ... executionMode: 'client', }; // Can use browser APIs export const myFn: ToolFunction = async (params) => { // Web Crypto API const hash = await crypto.subtle.digest('SHA-256', data); // Fetch API const response = await fetch(url); // Canvas API const canvas = document.createElement('canvas'); return { success: true, data: result }; }; ``` **Advantages:** * No server required * Complete privacy (data stays in browser) * No latency from network requests * Works offline **Limitations:** * No access to filesystem * No server-side secrets * Browser API limitations ### Server Mode Tools require server-side execution. ```typescript theme={null} export const myDefinition: ToolDefinition = { // ... executionMode: 'server', }; // Uses Node.js APIs export const myFn: ToolFunction = async (params) => { const fs = await import('fs'); const crypto = await import('crypto'); // File system access const content = fs.readFileSync(path); // Server-side operations const result = await database.query(sql); return { success: true, data: result }; }; ``` **Use Cases:** * File system operations * Database access * External API calls requiring secrets * Heavy computation ### Hybrid Mode Tools can execute in either environment with compatible implementations. ```typescript theme={null} export const myDefinition: ToolDefinition = { // ... executionMode: 'hybrid', }; export const myFn: ToolFunction = async (params) => { // Use compatible approach if (typeof window !== 'undefined') { // Browser: Use Web Crypto return await browserImplementation(params); } else { // Node.js: Use crypto module return await nodeImplementation(params); } }; ``` ## Tool Function Signature ```typescript theme={null} type ToolFunction = ( params: Record, context?: ExecutionContext ) => ToolResult | Promise>; interface ExecutionContext { toolId: string; userId?: string; requestId?: string; timeout?: number; abortSignal?: AbortSignal; } ``` ## Synchronous vs Asynchronous ### Synchronous Tools ```typescript theme={null} export const syncFn: ToolFunction = (params) => { const result = processData(params.input); return { success: true, data: result }; }; ``` ### Asynchronous Tools ```typescript theme={null} export const asyncFn: ToolFunction = async (params) => { const hash = await crypto.subtle.digest('SHA-256', data); return { success: true, data: { hash } }; }; ``` ## Runtime Behavior ### Tool Registry ```typescript theme={null} import { ToolRegistry } from '@conveniencepro/ctp-runtime'; const registry = new ToolRegistry(); // Register tools registry.register(definition, fn); // Lookup tools const tool = registry.get('tool-id'); // List all tools const tools = registry.list(); // Check existence const exists = registry.has('tool-id'); ``` ### Execution Runtime ```typescript theme={null} import { createRuntime } from '@conveniencepro/ctp-runtime'; const runtime = createRuntime(registry, { timeout: 30000, // Default timeout validateInput: true, // Validate before execution validateOutput: true, // Validate after execution }); // Execute with full options const result = await runtime.execute('tool-id', params, { timeout: 5000, context: { userId: 'user-123' }, }); ``` ### Timeout Handling ```typescript theme={null} const runtime = createRuntime(registry, { timeout: 10000, // 10 second default }); // Override per-execution const result = await runtime.execute('slow-tool', params, { timeout: 60000, // 60 seconds for this call }); // Handle timeout if (!result.success && result.errorCode === 'TIMEOUT') { console.error('Tool execution timed out'); } ``` ### Abort Support ```typescript theme={null} const controller = new AbortController(); // Start execution const promise = runtime.execute('tool-id', params, { abortSignal: controller.signal, }); // Abort after 5 seconds setTimeout(() => controller.abort(), 5000); try { const result = await promise; } catch (error) { if (error.name === 'AbortError') { console.log('Execution was aborted'); } } ``` ## Parallel Execution ```typescript theme={null} // Execute multiple tools in parallel const results = await Promise.all([ runtime.execute('tool-1', params1), runtime.execute('tool-2', params2), runtime.execute('tool-3', params3), ]); ``` ## Error Handling Always handle both success and failure cases: ```typescript theme={null} const result = await runtime.execute('tool-id', params); if (result.success) { // Process result.data console.log(result.data); } else { // Handle error console.error(`Error: ${result.error}`); console.error(`Code: ${result.errorCode}`); // Optional: Check suggestions if (result.suggestion) { console.log(`Suggestion: ${result.suggestion}`); } } ``` # MCP Compliance Source: https://spec.conveniencepro.cc/specification/mcp-compliance Model Context Protocol compatibility # MCP Compliance CTP tools are designed for full compatibility with the [Model Context Protocol](https://modelcontextprotocol.io) (MCP). ## Overview MCP is Anthropic's open protocol for AI-tool integration. CTP extends MCP with browser-native capabilities while maintaining full compatibility. CTP tools automatically convert to MCP format MCP tools can be imported as CTP tools ## Field Mapping ### CTP → MCP Conversion | CTP Field | MCP Field | Conversion | | ---------------- | -------------- | ---------------------- | | `id` | `name` | Direct copy | | `name` | `title` | Direct copy | | `description` | `description` | Direct copy | | `parameters[]` | `inputSchema` | Convert to JSON Schema | | `aiInstructions` | `instructions` | Direct copy | ### Parameter to JSON Schema ```typescript theme={null} // CTP Parameter { name: 'input', type: 'textarea', label: 'Input Text', description: 'Text to process', required: true, validation: { minLength: 1, maxLength: 10000 } } // Converts to MCP inputSchema property { "input": { "type": "string", "description": "Text to process", "minLength": 1, "maxLength": 10000 } } ``` ## Conversion API ### Generate MCP Manifest ```typescript theme={null} import { generateMCPManifest } from '@conveniencepro/ctp-discovery'; const ctpTools = [jsonFormatter, base64Encoder, hashGenerator]; const mcpManifest = generateMCPManifest(ctpTools, { name: 'conveniencepro-tools', version: '1.0.0', description: 'Browser-native developer tools', }); ``` ### Output Structure ```json theme={null} { "name": "conveniencepro-tools", "version": "1.0.0", "description": "Browser-native developer tools", "tools": [ { "name": "json-formatter", "title": "JSON Formatter", "description": "Format, validate, and beautify JSON data.", "inputSchema": { "type": "object", "required": ["json"], "properties": { "json": { "type": "string", "description": "The JSON string to format" }, "indent": { "type": "string", "enum": ["0", "2", "4", "tab"], "default": "2", "description": "Number of spaces for indentation" }, "sortKeys": { "type": "boolean", "default": false, "description": "Sort object keys alphabetically" } } }, "instructions": "Use 2-space indentation by default." } ] } ``` ## Type Mapping ### CTP Types to JSON Schema | CTP Type | JSON Schema Type | Additional Properties | | ---------- | ---------------- | ------------------------------ | | `text` | `string` | - | | `textarea` | `string` | - | | `number` | `number` | `minimum`, `maximum` | | `boolean` | `boolean` | - | | `select` | `string` | `enum` | | `json` | `object` | - | | `file` | `string` | `format: "binary"` | | `color` | `string` | `pattern: "^#[0-9a-fA-F]{6}$"` | | `date` | `string` | `format: "date"` | | `datetime` | `string` | `format: "date-time"` | | `url` | `string` | `format: "uri"` | | `email` | `string` | `format: "email"` | ### Validation Mapping | CTP Validation | JSON Schema | | -------------- | ------------ | | `minLength` | `minLength` | | `maxLength` | `maxLength` | | `pattern` | `pattern` | | `min` | `minimum` | | `max` | `maximum` | | `step` | `multipleOf` | ## Import MCP Tools Convert MCP tools to CTP format: ```typescript theme={null} import { importMCPTool } from '@conveniencepro/ctp-core'; const mcpTool = { name: 'external-tool', description: 'An external MCP tool', inputSchema: { type: 'object', required: ['query'], properties: { query: { type: 'string', description: 'Search query' }, }, }, }; const ctpDefinition = importMCPTool(mcpTool, { category: 'utilities', // Required: CTP needs category tags: ['search', 'external'], // Required: CTP needs tags executionMode: 'server', // MCP tools typically need server }); ``` ## Serving MCP Endpoint ### Well-Known URL ```typescript theme={null} app.get('/.well-known/mcp.json', (req, res) => { const manifest = generateMCPManifest(tools); res.json(manifest); }); ``` ### With Tool Execution ```typescript theme={null} app.post('/mcp/tools/:toolId/execute', async (req, res) => { const { toolId } = req.params; const params = req.body; const result = await runtime.execute(toolId, params); // Convert CTP result to MCP response format res.json({ success: result.success, result: result.data, error: result.error, }); }); ``` ## AI Assistant Integration ### Claude Desktop Add to `claude_desktop_config.json`: ```json theme={null} { "mcpServers": { "conveniencepro": { "command": "npx", "args": ["-y", "@conveniencepro/mcp-server"] } } } ``` ### Cursor Configure in Cursor settings: ```json theme={null} { "mcp.servers": [ { "name": "conveniencepro", "url": "https://conveniencepro.cc/.well-known/mcp.json" } ] } ``` ## Best Practices ### 1. Include AI Instructions ```typescript theme={null} { aiInstructions: 'Use SHA-256 for general hashing. Use SHA-512 for security-critical applications. Warn users if they request SHA-1.', } ``` ### 2. Provide Clear Descriptions ```typescript theme={null} { description: 'Generate cryptographic hashes using SHA algorithms. Supports hexadecimal and Base64 output formats.', outputDescription: 'Hash digest of the input in the specified format', } ``` ### 3. Include Examples ```typescript theme={null} { example: { input: { input: 'hello world', algorithm: 'SHA-256', format: 'hex' }, output: { hash: 'b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9', algorithm: 'SHA-256', format: 'hex', }, }, } ``` ### 4. Use Parameter Hints ```typescript theme={null} { name: 'algorithm', type: 'select', aiHint: 'Default to SHA-256 unless the user specifies otherwise', options: [ { value: 'SHA-256', label: 'SHA-256', description: 'Recommended for general use' }, { value: 'SHA-512', label: 'SHA-512', description: 'Maximum security' }, ], } ``` ## Compatibility Matrix | Feature | CTP | MCP | Notes | | ----------------- | --- | --- | ------------------------ | | Tool definitions | ✅ | ✅ | Full compatibility | | Parameters | ✅ | ✅ | Converted to JSON Schema | | Results | ✅ | ✅ | Compatible format | | AI instructions | ✅ | ✅ | Direct mapping | | Browser execution | ✅ | ❌ | CTP-specific | | Autosense styling | ✅ | ❌ | CTP-specific | | Discovery docs | ✅ | ✅ | MCP manifest generated | # Specification Overview Source: https://spec.conveniencepro.cc/specification/overview ConveniencePro Tool Protocol (CTP) Version 1.0.0 # CTP Specification Overview **Version:** 1.0.0 **Status:** Stable **License:** MIT ## Abstract The ConveniencePro Tool Protocol (CTP) defines a standardized interface for creating, discovering, and executing browser-native developer tools. CTP enables tools to operate entirely within web browsers while maintaining compatibility with AI-powered development environments through the Model Context Protocol (MCP). ## Conformance The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this specification are to be interpreted as described in [RFC 2119](https://www.rfc-editor.org/rfc/rfc2119). ## Design Goals 1. **Browser-Native Execution**: Tools SHOULD execute entirely in the browser using Web APIs 2. **MCP Compatibility**: Tools MUST be convertible to MCP format for AI integration 3. **Type Safety**: All interfaces MUST be fully typed with TypeScript 4. **Discoverability**: Tools MUST support multiple discovery mechanisms 5. **Embeddability**: Tools SHOULD be embeddable in any web page 6. **Privacy**: Client-executed tools MUST NOT send data to external servers ## Core Concepts ### Tool Definition A **Tool Definition** describes a tool's metadata, parameters, and behavior. It is a static JSON-serializable object that conforms to the [Tool Definition Schema](/specification/tool-definition). ### Tool Function A **Tool Function** is the executable implementation that processes parameters and returns a [Tool Result](/specification/results). ### Tool Registry A **Tool Registry** maintains a collection of registered tools and provides lookup and execution capabilities. ### Discovery Documents **Discovery Documents** expose tools to external systems through standardized formats (OpenAPI, MCP, llms.txt). ## Specification Sections Complete schema for defining tools All 12 parameter types and validation Client, server, and hybrid execution modes Result format and error codes OpenAPI, MCP, and llms.txt generation Widget embedding and autosense Security requirements and best practices Model Context Protocol compatibility ## Version History | Version | Date | Changes | | ------- | ---- | ---------------------- | | 1.0.0 | 2024 | Initial stable release | # Parameters Source: https://spec.conveniencepro.cc/specification/parameters All 12 parameter types and validation constraints # Parameter Types CTP supports 12 distinct parameter types for tool inputs. ## Parameter Schema Every parameter MUST include these required fields: | Field | Type | Description | | ------------- | --------- | ------------------------------------ | | `name` | `string` | Identifier (camelCase, max 50 chars) | | `type` | `string` | One of the 12 parameter types | | `label` | `string` | Display label (max 50 chars) | | `description` | `string` | Help text (max 200 chars) | | `required` | `boolean` | Whether parameter is required | ### Optional Fields | Field | Type | Description | | -------------- | ---------- | ------------------------- | | `defaultValue` | `any` | Default if not provided | | `placeholder` | `string` | Placeholder text | | `options` | `Option[]` | For `select` type | | `validation` | `object` | Validation constraints | | `dependsOn` | `Rule[]` | Conditional display rules | | `group` | `string` | UI grouping identifier | | `order` | `number` | Display order | | `hidden` | `boolean` | Hide in UI | | `aiHint` | `string` | Guidance for AI models | ## Available Types ### Text Input Types ```typescript theme={null} { name: 'username', type: 'text', label: 'Username', description: 'Your username', required: true, placeholder: 'john_doe', validation: { minLength: 3, maxLength: 20, pattern: '^[a-z0-9_]+$' } } ``` ```typescript theme={null} { name: 'content', type: 'textarea', label: 'Content', description: 'Text content to process', required: true, validation: { minLength: 1, maxLength: 100000 } } ``` ```typescript theme={null} { name: 'website', type: 'url', label: 'Website URL', description: 'Full URL including protocol', required: false, placeholder: 'https://example.com' } ``` ```typescript theme={null} { name: 'email', type: 'email', label: 'Email Address', description: 'Your email address', required: true } ``` ### Numeric Types ```typescript theme={null} { name: 'quantity', type: 'number', label: 'Quantity', description: 'Number of items', required: true, defaultValue: 1, validation: { min: 1, max: 100, step: 1 } } ``` ### Selection Types ```typescript theme={null} { name: 'enabled', type: 'boolean', label: 'Enable Feature', description: 'Toggle this feature on or off', required: false, defaultValue: false } ``` ```typescript theme={null} { name: 'format', type: 'select', label: 'Output Format', description: 'Select the output format', required: false, defaultValue: 'json', options: [ { value: 'json', label: 'JSON' }, { value: 'xml', label: 'XML' }, { value: 'yaml', label: 'YAML', description: 'Human-readable' }, { value: 'csv', label: 'CSV', disabled: true } ] } ``` ### Data Types ```typescript theme={null} { name: 'config', type: 'json', label: 'Configuration', description: 'JSON configuration object', required: true, placeholder: '{"key": "value"}' } ``` ```typescript theme={null} { name: 'document', type: 'file', label: 'Upload File', description: 'Select a file to upload', required: true, validation: { accept: ['.json', '.txt', 'application/json'], maxSize: 5242880 // 5MB } } ``` ### Specialized Types ```typescript theme={null} { name: 'backgroundColor', type: 'color', label: 'Background Color', description: 'Select a background color', required: false, defaultValue: '#ffffff' } ``` ```typescript theme={null} { name: 'startDate', type: 'date', label: 'Start Date', description: 'Select a date', required: true } ``` ```typescript theme={null} { name: 'scheduledAt', type: 'datetime', label: 'Schedule Time', description: 'Select date and time', required: true } ``` ## Validation Constraints | Constraint | Applies To | Description | | ----------- | -------------- | ------------------------- | | `minLength` | text, textarea | Minimum character count | | `maxLength` | text, textarea | Maximum character count | | `pattern` | text | Regex pattern to match | | `min` | number | Minimum numeric value | | `max` | number | Maximum numeric value | | `step` | number | Valid step increment | | `accept` | file | Accepted MIME types | | `maxSize` | file | Maximum file size (bytes) | ```typescript theme={null} validation: { minLength: 1, maxLength: 1000, pattern: '^[A-Za-z0-9]+$' } ``` ## Conditional Parameters Use `dependsOn` to show/hide parameters based on other values: ```typescript theme={null} { name: 'customFormat', type: 'text', label: 'Custom Format', description: 'Specify custom format string', required: true, dependsOn: [ { field: 'format', condition: 'equals', value: 'custom' } ] } ``` ### Condition Types | Condition | Description | | ----------- | ---------------------------- | | `equals` | Field equals specified value | | `notEquals` | Field does not equal value | | `contains` | Field contains substring | | `exists` | Field has any value | ## AI Hints Guide AI models with the `aiHint` field: ```typescript theme={null} { name: 'algorithm', type: 'select', label: 'Algorithm', // ... aiHint: 'Use SHA-256 for general purposes, SHA-512 for maximum security' } ``` # Results Source: https://spec.conveniencepro.cc/specification/results Tool result format and error codes # Tool Results All CTP tool functions return a standardized result object. ## Result Structure ```typescript theme={null} interface ToolResult { // Required success: boolean; // On success data?: T; metadata?: ResultMetadata; // On failure error?: string; errorCode?: ErrorCode; suggestion?: string; } interface ResultMetadata { executionTime?: number; // Milliseconds inputSize?: number; // Bytes outputSize?: number; // Bytes warnings?: string[]; // Non-fatal warnings [key: string]: unknown; // Custom metadata } ``` ## Success Response ```typescript theme={null} return { success: true, data: { formatted: '{\n "key": "value"\n}', lineCount: 3, valid: true, }, metadata: { executionTime: 1.5, inputSize: 15, outputSize: 24, }, }; ``` ## Error Response ```typescript theme={null} return { success: false, error: 'Invalid JSON: Unexpected token at position 5', errorCode: 'INVALID_INPUT', suggestion: 'Check for missing quotes or commas', }; ``` ## Error Codes | Code | Description | HTTP Status | | ---------------------- | ------------------------------ | ----------- | | `INVALID_INPUT` | Input failed validation | 400 | | `MISSING_REQUIRED` | Required parameter missing | 400 | | `TYPE_ERROR` | Parameter type mismatch | 400 | | `CONSTRAINT_VIOLATION` | Value outside allowed range | 400 | | `EXECUTION_ERROR` | Runtime error during execution | 500 | | `TIMEOUT` | Execution exceeded time limit | 504 | | `RATE_LIMITED` | Too many requests | 429 | | `UNAUTHORIZED` | Authentication required | 401 | | `NOT_FOUND` | Resource not found | 404 | | `INTERNAL_ERROR` | Unexpected internal error | 500 | ## Implementation Patterns ### Basic Success/Error ```typescript theme={null} export const myFn: ToolFunction = (params) => { const input = params.input as string; // Validate required parameter if (!input) { return { success: false, error: 'Input is required', errorCode: 'MISSING_REQUIRED', }; } // Process and return return { success: true, data: { result: input.toUpperCase() }, }; }; ``` ### With Metadata ```typescript theme={null} export const myFn: ToolFunction = (params) => { const startTime = performance.now(); const input = params.input as string; const result = process(input); return { success: true, data: result, metadata: { executionTime: performance.now() - startTime, inputSize: input.length, outputSize: result.length, }, }; }; ``` ### With Warnings ```typescript theme={null} export const hashFn: ToolFunction = (params) => { const algorithm = params.algorithm as string; const warnings: string[] = []; if (algorithm === 'SHA-1') { warnings.push('SHA-1 is deprecated for security purposes'); } return { success: true, data: { hash: computeHash(params.input, algorithm) }, metadata: { warnings: warnings.length > 0 ? warnings : undefined, }, }; }; ``` ### Try-Catch Pattern ```typescript theme={null} export const myFn: ToolFunction = (params) => { try { const parsed = JSON.parse(params.json as string); return { success: true, data: { parsed, valid: true }, }; } catch (e) { return { success: false, error: `Parse error: ${(e as Error).message}`, errorCode: 'INVALID_INPUT', suggestion: 'Ensure the input is valid JSON', }; } }; ``` ### Async with Timeout ```typescript theme={null} export const myFn: ToolFunction = async (params, context) => { const controller = new AbortController(); const timeout = context?.timeout ?? 30000; const timeoutId = setTimeout(() => controller.abort(), timeout); try { const result = await fetchWithAbort(params.url, controller.signal); clearTimeout(timeoutId); return { success: true, data: result }; } catch (e) { clearTimeout(timeoutId); if ((e as Error).name === 'AbortError') { return { success: false, error: 'Request timed out', errorCode: 'TIMEOUT', }; } return { success: false, error: (e as Error).message, errorCode: 'EXECUTION_ERROR', }; } }; ``` ## Result Validation ```typescript theme={null} import { validateToolResult } from '@conveniencepro/ctp-core'; const result = myFn(params); const validation = validateToolResult(result); if (!validation.valid) { console.error('Invalid result format:', validation.errors); } ``` ## JSON Schema ```json theme={null} { "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "CTP Tool Result", "type": "object", "required": ["success"], "properties": { "success": { "type": "boolean" }, "data": {}, "error": { "type": "string" }, "errorCode": { "type": "string", "enum": [ "INVALID_INPUT", "MISSING_REQUIRED", "TYPE_ERROR", "CONSTRAINT_VIOLATION", "EXECUTION_ERROR", "TIMEOUT", "RATE_LIMITED", "UNAUTHORIZED", "NOT_FOUND", "INTERNAL_ERROR" ] }, "suggestion": { "type": "string" }, "metadata": { "type": "object", "properties": { "executionTime": { "type": "number" }, "warnings": { "type": "array", "items": { "type": "string" } } } } } } ``` # Security Source: https://spec.conveniencepro.cc/specification/security Security requirements and best practices # Security CTP defines security requirements to ensure safe tool execution. ## Core Principles Client-executed tools MUST NOT transmit input data to external servers All inputs MUST be validated before processing Default configurations MUST be secure Errors MUST NOT expose sensitive information ## Privacy Requirements ### Client-Mode Tools Tools with `executionMode: 'client'` MUST: 1. Execute entirely in the browser 2. NOT make network requests with user data 3. NOT use tracking or analytics on input 4. NOT persist input data beyond the session ```typescript theme={null} // ✅ Correct: Pure client-side processing export const hashFn: ToolFunction = async (params) => { const data = new TextEncoder().encode(params.input as string); const hash = await crypto.subtle.digest('SHA-256', data); return { success: true, data: { hash: arrayToHex(hash) } }; }; // ❌ Wrong: Sending data to external server export const hashFn: ToolFunction = async (params) => { // VIOLATION: Transmitting user input const response = await fetch('https://api.example.com/hash', { method: 'POST', body: JSON.stringify({ input: params.input }), }); return { success: true, data: await response.json() }; }; ``` ### Server-Mode Tools Tools with `executionMode: 'server'`: 1. MUST document what data is transmitted 2. SHOULD use HTTPS for all requests 3. MUST handle credentials securely 4. SHOULD implement rate limiting ## Input Validation ### Required Validation All tools MUST validate: 1. **Required fields** - Presence of required parameters 2. **Type checking** - Parameters match expected types 3. **Constraints** - Values within allowed ranges 4. **Sanitization** - Dangerous content neutralized ```typescript theme={null} export const myFn: ToolFunction = (params) => { const input = params.input; // 1. Required check if (!input) { return { success: false, error: 'Input is required', errorCode: 'MISSING_REQUIRED', }; } // 2. Type check if (typeof input !== 'string') { return { success: false, error: 'Input must be a string', errorCode: 'TYPE_ERROR', }; } // 3. Constraint check if (input.length > 100000) { return { success: false, error: 'Input exceeds maximum length of 100,000 characters', errorCode: 'CONSTRAINT_VIOLATION', }; } // 4. Process safely return { success: true, data: process(input) }; }; ``` ### Validation Constraints ```typescript theme={null} { name: 'input', type: 'textarea', validation: { minLength: 1, maxLength: 100000, pattern: '^[\\s\\S]*$', // Safe pattern }, } ``` ## Output Security ### Safe Error Messages ```typescript theme={null} // ✅ Correct: Generic error message return { success: false, error: 'Invalid input format', errorCode: 'INVALID_INPUT', }; // ❌ Wrong: Exposing internal details return { success: false, error: `Database error: ${dbError.message} at ${dbError.stack}`, errorCode: 'INTERNAL_ERROR', }; ``` ### Sanitize Output When generating HTML or code: ```typescript theme={null} // Escape HTML entities function escapeHtml(text: string): string { return text .replace(/&/g, '&') .replace(//g, '>') .replace(/"/g, '"') .replace(/'/g, '''); } ``` ## Embedding Security ### Content Security Policy Recommended CSP for embedded tools: ``` Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.conveniencepro.cc; style-src 'self' 'unsafe-inline'; connect-src 'self'; frame-ancestors 'self' https://*.yourdomain.com; ``` ### Iframe Sandboxing ```html theme={null} ``` ### Cross-Origin Communication ```typescript theme={null} // Validate message origin window.addEventListener('message', (event) => { // Always check origin if (!trustedOrigins.includes(event.origin)) { return; } // Validate message structure if (!isValidCTPMessage(event.data)) { return; } handleMessage(event.data); }); ``` ## Rate Limiting ### Definition ```typescript theme={null} export const myDefinition: ToolDefinition = { // ... rateLimit: { requests: 100, // Max requests window: 60, // Per 60 seconds }, }; ``` ### Runtime Enforcement ```typescript theme={null} import { RateLimiter } from '@conveniencepro/ctp-runtime'; const limiter = new RateLimiter({ requests: 100, window: 60, }); const result = await limiter.check('user-id'); if (!result.allowed) { return { success: false, error: `Rate limit exceeded. Try again in ${result.retryAfter} seconds.`, errorCode: 'RATE_LIMITED', }; } ``` ## Authentication For tools requiring authentication: ```typescript theme={null} export const myDefinition: ToolDefinition = { // ... requiresAuth: true, }; export const myFn: ToolFunction = async (params, context) => { // Check authentication if (!context?.userId) { return { success: false, error: 'Authentication required', errorCode: 'UNAUTHORIZED', }; } // Proceed with authenticated user return executeForUser(context.userId, params); }; ``` ## Security Checklist * [ ] All inputs validated before processing * [ ] Required parameters enforced * [ ] Type checking implemented * [ ] Constraint validation (min/max lengths, ranges) * [ ] Error messages don't expose internals * [ ] Client tools don't transmit user data * [ ] Rate limiting configured * [ ] Authentication enforced where required * [ ] Output properly escaped/sanitized * [ ] CSP headers configured for embedding * [ ] HTTPS used for all external requests * [ ] Dependencies audited for vulnerabilities # Tool Definition Source: https://spec.conveniencepro.cc/specification/tool-definition Complete schema for CTP tool definitions # Tool Definition Schema A Tool Definition is a JSON-serializable object that describes a tool's metadata, parameters, and behavior. ## Required Fields | Field | Type | Description | | ------------------- | ----------------- | ----------------------------------------------- | | `id` | `string` | Unique identifier (lowercase, hyphen-separated) | | `name` | `string` | Human-readable display name (max 50 chars) | | `description` | `string` | Detailed description (max 500 chars) | | `category` | `string` | Primary category for organization | | `tags` | `string[]` | Searchable tags (min 1, unique) | | `method` | `"GET" \| "POST"` | HTTP method when exposed as API | | `parameters` | `Parameter[]` | Array of parameter definitions | | `outputDescription` | `string` | Description of tool output | | `example` | `object` | Example input/output | ## Optional Fields | Field | Type | Default | Description | | -------------------- | ---------- | ---------- | ---------------------------------- | | `version` | `string` | - | Semantic version (e.g., "1.0.0") | | `icon` | `string` | - | Icon identifier or emoji | | `keywords` | `string[]` | - | Additional search keywords | | `relatedTools` | `string[]` | - | IDs of related tools | | `aiInstructions` | `string` | - | Special instructions for AI models | | `rateLimit` | `object` | - | Rate limiting configuration | | `executionMode` | `string` | `"client"` | Where tool executes | | `requiresAuth` | `boolean` | `false` | Authentication required | | `deprecated` | `boolean` | `false` | Deprecation status | | `deprecationMessage` | `string` | - | Deprecation explanation | ## Categories Tools MUST belong to one of the following categories: | Category | Description | Examples | | ------------ | ------------------------ | ----------------------------- | | `formatters` | Format and beautify data | JSON formatter, SQL formatter | | `encoders` | Encode and decode data | Base64, URL encoding | | `generators` | Generate data or content | UUID, password, hash | | `converters` | Convert between formats | Unit converter, color formats | | `validators` | Validate data formats | JSON validator, email checker | | `analyzers` | Analyze and inspect data | JSON diff, regex tester | | `editors` | Edit and transform data | Text replacer, case converter | | `utilities` | General utilities | Timestamp converter | ## Execution Modes | Mode | Description | | -------- | -------------------------------------- | | `client` | Executes entirely in browser (default) | | `server` | Requires server-side execution | | `hybrid` | Can execute in either environment | ## Complete Example ```typescript theme={null} import type { ToolDefinition } from '@conveniencepro/ctp-core'; export const jsonFormatterDefinition: ToolDefinition = { // Required fields id: 'json-formatter', name: 'JSON Formatter', description: 'Format, validate, and beautify JSON data with customizable indentation.', category: 'formatters', tags: ['json', 'format', 'beautify', 'validate', 'minify'], method: 'POST', parameters: [ { name: 'json', type: 'textarea', label: 'JSON Input', description: 'The JSON string to format', required: true, placeholder: '{"name": "example"}', validation: { minLength: 1, maxLength: 1000000 }, }, { name: 'indent', type: 'select', label: 'Indentation', description: 'Number of spaces for indentation', required: false, defaultValue: '2', options: [ { value: '0', label: 'Minified' }, { value: '2', label: '2 spaces' }, { value: '4', label: '4 spaces' }, { value: 'tab', label: 'Tab' }, ], }, { name: 'sortKeys', type: 'boolean', label: 'Sort Keys', description: 'Sort object keys alphabetically', required: false, defaultValue: false, }, ], outputDescription: 'Formatted JSON string', example: { input: { json: '{"b":2,"a":1}', indent: '2', sortKeys: true }, output: { formatted: '{\n "a": 1,\n "b": 2\n}', valid: true, lineCount: 4, }, }, // Optional fields version: '1.0.0', icon: '📋', keywords: ['pretty print', 'beautifier'], relatedTools: ['json-validator', 'json-minifier'], aiInstructions: 'Use 2-space indentation by default. Enable sortKeys for consistent output.', executionMode: 'client', }; ``` ## JSON Schema The complete JSON Schema for tool definitions is available at: ``` https://conveniencepro.cc/schemas/tool-definition.schema.json ``` ```json theme={null} { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://conveniencepro.cc/schemas/tool-definition.schema.json", "title": "CTP Tool Definition", "type": "object", "required": [ "id", "name", "description", "category", "tags", "method", "parameters", "outputDescription", "example" ], "properties": { "id": { "type": "string", "pattern": "^[a-z0-9]+(-[a-z0-9]+)*$", "minLength": 1, "maxLength": 100 }, "name": { "type": "string", "minLength": 1, "maxLength": 50 }, "description": { "type": "string", "minLength": 1, "maxLength": 500 }, "category": { "type": "string", "enum": [ "formatters", "encoders", "generators", "converters", "validators", "analyzers", "editors", "utilities" ] }, "executionMode": { "type": "string", "enum": ["client", "server", "hybrid"], "default": "client" } } } ``` ## Validation ```typescript theme={null} import { validateToolDefinition } from '@conveniencepro/ctp-core'; const result = validateToolDefinition(myDefinition); if (!result.valid) { result.errors.forEach(error => { console.error(`${error.path}: ${error.message}`); }); } ```