// tools/create-spec/mcp-tool-contract.ts
// SPEC-016b: Generates Tool Contracts for MCP tools.
// Criterion 4: define_ui_contract generates "Tool Contract" for MCP servers.
import { isMcpServerProject } from '../../engine/detectors/mcp-server-detector.js';
// === Detection ===
export function isMcpToolContract(knowledge) {
    if (!knowledge) {
        return false;
    }
    return isMcpServerProject(knowledge);
}
// === Tool Contract builder ===
function buildErrorCodes(toolName, description) {
    const codes = ['InvalidParams', 'InternalError'];
    const lower = description.toLowerCase();
    if (lower.includes('not found') ||
        lower.includes('missing') ||
        lower.includes(toolName.toLowerCase())) {
        codes.push('MethodNotFound');
    }
    // Deduplicate
    return [...new Set(codes)];
}
function buildSideEffects(description) {
    const lower = description.toLowerCase();
    const effects = [];
    if (lower.includes('write') || lower.includes('create') || lower.includes('save')) {
        effects.push('filesystem-write');
    }
    if (lower.includes('delete') || lower.includes('remove')) {
        effects.push('filesystem-delete');
    }
    if (lower.includes('http') || lower.includes('fetch') || lower.includes('api')) {
        effects.push('network-call');
    }
    if (lower.includes('database') || lower.includes('db') || lower.includes('query')) {
        effects.push('database-read');
    }
    if (lower.includes('email') || lower.includes('notify') || lower.includes('send')) {
        effects.push('external-service-call');
    }
    return effects;
}
/**
 * Generate a ToolContract for an MCP tool.
 * Criterion 4: name, description, inputSchema (Zod), outputSchema, side effects, error codes, timeout.
 */
export function generateMcpToolContract(toolName, description, inputFields) {
    const inputSchema = {};
    for (const field of inputFields) {
        inputSchema[field] = {
            type: 'string',
            description: `The ${field} parameter`,
        };
    }
    return {
        name: toolName,
        description,
        inputSchema: {
            type: 'object',
            properties: inputSchema,
            required: inputFields.filter((f) => !f.startsWith('optional_')),
            additionalProperties: false,
        },
        outputSchema: {
            type: 'object',
            properties: {
                content: {
                    type: 'array',
                    items: {
                        type: 'object',
                        properties: {
                            type: { type: 'string', enum: ['text', 'image', 'embedded_resource'] },
                            text: { type: 'string' },
                        },
                    },
                },
                isError: { type: 'boolean' },
            },
            required: ['content'],
        },
        sideEffects: buildSideEffects(description),
        errorCodes: buildErrorCodes(toolName, description),
        timeoutMs: 30000,
    };
}
// === Formatted output for define_ui_contract ===
export function formatMcpToolContractAsMarkdown(tools, knowledge) {
    const lines = [
        '## MCP Tool Contracts',
        '',
        `> **Server stack**: ${knowledge.framework ?? 'MCP'} | **Language**: ${knowledge.language}`,
        '',
    ];
    for (const tool of tools) {
        const contract = generateMcpToolContract(tool.name, tool.description, tool.fields);
        lines.push(`### Tool: \`${contract.name}\``);
        lines.push('');
        lines.push(`**Description**: ${contract.description}`);
        lines.push('');
        lines.push('**Input Schema (Zod)**:');
        lines.push('```typescript');
        lines.push(`const ${tool.name}Schema = z.object({`);
        for (const field of Object.keys(contract.inputSchema.properties ?? {})) {
            const required = contract.inputSchema.required ?? [];
            const suffix = required.includes(field) ? '' : '.optional()';
            lines.push(`  ${field}: z.string()${suffix},`);
        }
        lines.push('});');
        lines.push('```');
        lines.push('');
        lines.push('**Output format**: MCP CallToolResult (content array + optional isError)');
        lines.push('');
        if (contract.sideEffects.length > 0) {
            lines.push(`**Side effects**: ${contract.sideEffects.join(', ')}`);
            lines.push('');
        }
        else {
            lines.push('**Side effects**: none (pure read)');
            lines.push('');
        }
        lines.push(`**Error codes**: ${contract.errorCodes.join(', ')}`);
        lines.push(`**Timeout**: ${contract.timeoutMs}ms (MCP client default)`);
        lines.push('');
        lines.push('**Error handling guidelines**:');
        lines.push('- Return `{ isError: true, content: [{ type: "text", text: "..." }] }` for tool errors');
        lines.push('- Throw `McpError(ErrorCode.InvalidParams, "...")` for schema validation failures');
        lines.push('- Throw `McpError(ErrorCode.InternalError, "...")` for unexpected server errors');
        lines.push('');
    }
    lines.push('### MCP Protocol Compliance Checklist');
    lines.push('');
    lines.push('- [ ] All tools have description (non-empty, max 1024 chars)');
    lines.push('- [ ] All inputSchemas use `type: "object"` at root');
    lines.push('- [ ] All inputSchemas have `additionalProperties: false`');
    lines.push('- [ ] All inputSchemas declare `required` array');
    lines.push('- [ ] No tool call blocks the event loop without `Promise.race` + timeout');
    lines.push('- [ ] All tools handle concurrent calls correctly (no shared mutable state)');
    return lines.join('\n');
}
//# sourceMappingURL=mcp-tool-contract.js.map