@stackkedjohn/mcp-factory-cli 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +100 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +33 -0
- package/dist/commands/create.d.ts +4 -0
- package/dist/commands/create.js +56 -0
- package/dist/commands/install.d.ts +1 -0
- package/dist/commands/install.js +79 -0
- package/dist/commands/list.d.ts +1 -0
- package/dist/commands/list.js +24 -0
- package/dist/commands/validate.d.ts +1 -0
- package/dist/commands/validate.js +27 -0
- package/dist/generator/analyzer.d.ts +2 -0
- package/dist/generator/analyzer.js +14 -0
- package/dist/generator/engine.d.ts +10 -0
- package/dist/generator/engine.js +46 -0
- package/dist/parsers/ai-parser.d.ts +2 -0
- package/dist/parsers/ai-parser.js +7 -0
- package/dist/parsers/detector.d.ts +6 -0
- package/dist/parsers/detector.js +38 -0
- package/dist/parsers/openapi.d.ts +5 -0
- package/dist/parsers/openapi.js +205 -0
- package/dist/parsers/postman.d.ts +2 -0
- package/dist/parsers/postman.js +4 -0
- package/dist/registry/manager.d.ts +13 -0
- package/dist/registry/manager.js +43 -0
- package/dist/schema/api-schema.d.ts +77 -0
- package/dist/schema/api-schema.js +1 -0
- package/dist/utils/errors.d.ts +13 -0
- package/dist/utils/errors.js +26 -0
- package/dist/utils/logger.d.ts +7 -0
- package/dist/utils/logger.js +19 -0
- package/docs/plans/2026-02-02-mcp-factory-design.md +306 -0
- package/docs/plans/2026-02-02-mcp-factory-implementation.md +1866 -0
- package/package.json +48 -0
- package/src/cli.ts +41 -0
- package/src/commands/create.ts +65 -0
- package/src/commands/install.ts +92 -0
- package/src/commands/list.ts +28 -0
- package/src/commands/validate.ts +29 -0
- package/src/generator/analyzer.ts +20 -0
- package/src/generator/engine.ts +73 -0
- package/src/parsers/ai-parser.ts +10 -0
- package/src/parsers/detector.ts +49 -0
- package/src/parsers/openapi.ts +238 -0
- package/src/parsers/postman.ts +6 -0
- package/src/registry/manager.ts +62 -0
- package/src/schema/api-schema.ts +87 -0
- package/src/utils/errors.ts +27 -0
- package/src/utils/logger.ts +23 -0
- package/templates/README.md.hbs +40 -0
- package/templates/client.ts.hbs +45 -0
- package/templates/index.ts.hbs +36 -0
- package/templates/package.json.hbs +20 -0
- package/templates/test.ts.hbs +1 -0
- package/templates/tools.ts.hbs +38 -0
- package/templates/tsconfig.json.hbs +13 -0
- package/templates/types.ts.hbs +1 -0
- package/templates/validation.ts.hbs +1 -0
- package/test-fixtures/weather-api.json +49 -0
- package/tsconfig.json +17 -0
package/README.md
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# MCP Factory
|
|
2
|
+
|
|
3
|
+
Generate production-ready MCP servers from API documentation in one command.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g @mcp-factory/cli
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
# Generate MCP server from OpenAPI spec
|
|
15
|
+
mcp-factory create openapi.json
|
|
16
|
+
|
|
17
|
+
# Install to Claude Desktop/Code
|
|
18
|
+
cd my-api-mcp
|
|
19
|
+
npm install && npm run build
|
|
20
|
+
mcp-factory install my-api
|
|
21
|
+
|
|
22
|
+
# List generated servers
|
|
23
|
+
mcp-factory list
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Commands
|
|
27
|
+
|
|
28
|
+
### create
|
|
29
|
+
|
|
30
|
+
Generate an MCP server from API documentation:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
mcp-factory create <input> [options]
|
|
34
|
+
|
|
35
|
+
Options:
|
|
36
|
+
--ai-parse Use AI to parse unstructured documentation
|
|
37
|
+
-o, --output <dir> Output directory for generated server
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
**Supported input formats:**
|
|
41
|
+
- OpenAPI 3.x (JSON/YAML)
|
|
42
|
+
- Swagger 2.0 (JSON/YAML)
|
|
43
|
+
- Postman collections (coming soon)
|
|
44
|
+
- Unstructured docs with `--ai-parse` (coming soon)
|
|
45
|
+
|
|
46
|
+
### validate
|
|
47
|
+
|
|
48
|
+
Validate API specification without generating code:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
mcp-factory validate <input>
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### list
|
|
55
|
+
|
|
56
|
+
List all generated MCP servers:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
mcp-factory list
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### install
|
|
63
|
+
|
|
64
|
+
Install generated server to Claude Desktop/Code configuration:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
mcp-factory install <server-name>
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Generated Server Structure
|
|
71
|
+
|
|
72
|
+
```
|
|
73
|
+
my-api-mcp/
|
|
74
|
+
├── src/
|
|
75
|
+
│ ├── index.ts # MCP server entry point
|
|
76
|
+
│ ├── client.ts # HTTP client with auth
|
|
77
|
+
│ └── tools.ts # Tool implementations
|
|
78
|
+
├── package.json
|
|
79
|
+
├── tsconfig.json
|
|
80
|
+
└── README.md
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Development
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
# Clone and setup
|
|
87
|
+
git clone <repo>
|
|
88
|
+
cd mcp-factory
|
|
89
|
+
npm install
|
|
90
|
+
|
|
91
|
+
# Build
|
|
92
|
+
npm run build
|
|
93
|
+
|
|
94
|
+
# Test with sample
|
|
95
|
+
node dist/cli.js create test-fixtures/weather-api.json
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## License
|
|
99
|
+
|
|
100
|
+
MIT
|
package/dist/cli.d.ts
ADDED
package/dist/cli.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import { createCommand } from './commands/create.js';
|
|
4
|
+
import { validateCommand } from './commands/validate.js';
|
|
5
|
+
import { listCommand } from './commands/list.js';
|
|
6
|
+
import { installCommand } from './commands/install.js';
|
|
7
|
+
const program = new Command();
|
|
8
|
+
program
|
|
9
|
+
.name('mcp-factory')
|
|
10
|
+
.description('Generate production-ready MCP servers from API documentation')
|
|
11
|
+
.version('0.1.0');
|
|
12
|
+
program
|
|
13
|
+
.command('create')
|
|
14
|
+
.description('Generate MCP server from API documentation')
|
|
15
|
+
.argument('<input>', 'Path to API spec file or URL')
|
|
16
|
+
.option('--ai-parse', 'Use AI to parse unstructured documentation')
|
|
17
|
+
.option('-o, --output <dir>', 'Output directory for generated server')
|
|
18
|
+
.action(createCommand);
|
|
19
|
+
program
|
|
20
|
+
.command('validate')
|
|
21
|
+
.description('Validate API specification without generating code')
|
|
22
|
+
.argument('<input>', 'Path to API spec file')
|
|
23
|
+
.action(validateCommand);
|
|
24
|
+
program
|
|
25
|
+
.command('list')
|
|
26
|
+
.description('List all generated MCP servers')
|
|
27
|
+
.action(listCommand);
|
|
28
|
+
program
|
|
29
|
+
.command('install')
|
|
30
|
+
.description('Install MCP server to Claude Desktop/Code configuration')
|
|
31
|
+
.argument('<server-name>', 'Name of the server to install')
|
|
32
|
+
.action(installCommand);
|
|
33
|
+
program.parse();
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import * as path from 'path';
|
|
2
|
+
import { detectFormat } from '../parsers/detector.js';
|
|
3
|
+
import { parseOpenAPI } from '../parsers/openapi.js';
|
|
4
|
+
import { parsePostman } from '../parsers/postman.js';
|
|
5
|
+
import { parseWithAI } from '../parsers/ai-parser.js';
|
|
6
|
+
import { analyzePatterns } from '../generator/analyzer.js';
|
|
7
|
+
import { generateServer } from '../generator/engine.js';
|
|
8
|
+
import { addServer } from '../registry/manager.js';
|
|
9
|
+
import { logger } from '../utils/logger.js';
|
|
10
|
+
import { ParseError } from '../utils/errors.js';
|
|
11
|
+
export async function createCommand(input, options) {
|
|
12
|
+
try {
|
|
13
|
+
logger.info(`Detecting format for: ${input}`);
|
|
14
|
+
// Detect format
|
|
15
|
+
const detection = await detectFormat(input);
|
|
16
|
+
logger.info(`Detected format: ${detection.format}`);
|
|
17
|
+
// Parse to APISchema
|
|
18
|
+
let schema;
|
|
19
|
+
if (detection.format === 'openapi' || detection.format === 'swagger') {
|
|
20
|
+
schema = parseOpenAPI(detection.content);
|
|
21
|
+
}
|
|
22
|
+
else if (detection.format === 'postman') {
|
|
23
|
+
schema = parsePostman(detection.content);
|
|
24
|
+
}
|
|
25
|
+
else if (options.aiParse) {
|
|
26
|
+
logger.info('Using AI parser for unstructured docs...');
|
|
27
|
+
schema = await parseWithAI(JSON.stringify(detection.content));
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
throw new ParseError('Could not detect format. Use --ai-parse for unstructured docs.');
|
|
31
|
+
}
|
|
32
|
+
logger.success(`Parsed API: ${schema.name}`);
|
|
33
|
+
// Analyze patterns
|
|
34
|
+
const patterns = analyzePatterns(schema);
|
|
35
|
+
logger.info(`Detected patterns: auth=${patterns.authPattern}, pagination=${patterns.paginationStyle || 'none'}`);
|
|
36
|
+
// Generate server
|
|
37
|
+
const outputDir = options.output || path.join(process.cwd(), `${schema.name}-mcp`);
|
|
38
|
+
logger.info(`Generating server in: ${outputDir}`);
|
|
39
|
+
await generateServer(schema, patterns, outputDir);
|
|
40
|
+
// Add to registry
|
|
41
|
+
await addServer(schema.name, outputDir);
|
|
42
|
+
logger.success(`Generated MCP server: ${schema.name}`);
|
|
43
|
+
logger.info(`Next steps:`);
|
|
44
|
+
logger.info(` cd ${outputDir}`);
|
|
45
|
+
logger.info(` npm install`);
|
|
46
|
+
logger.info(` npm run build`);
|
|
47
|
+
logger.info(` npm test`);
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
if (error instanceof Error) {
|
|
51
|
+
logger.error(error.message);
|
|
52
|
+
process.exit(1);
|
|
53
|
+
}
|
|
54
|
+
throw error;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function installCommand(serverName: string): Promise<void>;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import * as fs from 'fs/promises';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import * as os from 'os';
|
|
4
|
+
import { getServer } from '../registry/manager.js';
|
|
5
|
+
import { logger } from '../utils/logger.js';
|
|
6
|
+
export async function installCommand(serverName) {
|
|
7
|
+
try {
|
|
8
|
+
// Get server from registry
|
|
9
|
+
const server = await getServer(serverName);
|
|
10
|
+
if (!server) {
|
|
11
|
+
logger.error(`Server not found: ${serverName}`);
|
|
12
|
+
logger.info('Run "mcp-factory list" to see available servers');
|
|
13
|
+
process.exit(1);
|
|
14
|
+
}
|
|
15
|
+
// Check if server build exists
|
|
16
|
+
const buildPath = path.join(server.path, 'build', 'index.js');
|
|
17
|
+
try {
|
|
18
|
+
await fs.access(buildPath);
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
logger.error(`Server not built yet. Run:`);
|
|
22
|
+
logger.info(` cd ${server.path}`);
|
|
23
|
+
logger.info(` npm install && npm run build`);
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
|
26
|
+
// Determine Claude config paths
|
|
27
|
+
const configPaths = [
|
|
28
|
+
path.join(os.homedir(), 'Library', 'Application Support', 'Claude', 'claude_desktop_config.json'),
|
|
29
|
+
path.join(os.homedir(), '.claude', 'config.json'),
|
|
30
|
+
];
|
|
31
|
+
let installed = false;
|
|
32
|
+
for (const configPath of configPaths) {
|
|
33
|
+
try {
|
|
34
|
+
await fs.access(configPath);
|
|
35
|
+
await installToConfig(configPath, serverName, buildPath);
|
|
36
|
+
installed = true;
|
|
37
|
+
const configName = configPath.includes('claude_desktop_config.json')
|
|
38
|
+
? 'Claude Desktop'
|
|
39
|
+
: 'Claude Code';
|
|
40
|
+
logger.success(`Installed ${serverName} to ${configName}`);
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
// Config file doesn't exist, skip
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
if (!installed) {
|
|
47
|
+
logger.warn('No Claude configuration files found');
|
|
48
|
+
logger.info('Expected locations:');
|
|
49
|
+
configPaths.forEach(p => logger.info(` ${p}`));
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
logger.info('\nNext steps:');
|
|
53
|
+
logger.info(' 1. Edit the config file and add your API credentials');
|
|
54
|
+
logger.info(' 2. Restart Claude Desktop/Code to load the server');
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
if (error instanceof Error) {
|
|
59
|
+
logger.error(error.message);
|
|
60
|
+
process.exit(1);
|
|
61
|
+
}
|
|
62
|
+
throw error;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
async function installToConfig(configPath, serverName, buildPath) {
|
|
66
|
+
const content = await fs.readFile(configPath, 'utf-8');
|
|
67
|
+
const config = JSON.parse(content);
|
|
68
|
+
if (!config.mcpServers) {
|
|
69
|
+
config.mcpServers = {};
|
|
70
|
+
}
|
|
71
|
+
config.mcpServers[serverName] = {
|
|
72
|
+
command: 'node',
|
|
73
|
+
args: [buildPath],
|
|
74
|
+
env: {
|
|
75
|
+
API_KEY: 'YOUR_API_KEY_HERE',
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
await fs.writeFile(configPath, JSON.stringify(config, null, 2));
|
|
79
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function listCommand(): Promise<void>;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { listServers } from '../registry/manager.js';
|
|
2
|
+
import { logger } from '../utils/logger.js';
|
|
3
|
+
export async function listCommand() {
|
|
4
|
+
try {
|
|
5
|
+
const servers = await listServers();
|
|
6
|
+
if (servers.length === 0) {
|
|
7
|
+
logger.info('No MCP servers generated yet');
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
logger.info(`Generated MCP servers (${servers.length}):\n`);
|
|
11
|
+
for (const server of servers) {
|
|
12
|
+
console.log(` ${server.name}`);
|
|
13
|
+
console.log(` Path: ${server.path}`);
|
|
14
|
+
console.log(` Created: ${new Date(server.createdAt).toLocaleString()}\n`);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
catch (error) {
|
|
18
|
+
if (error instanceof Error) {
|
|
19
|
+
logger.error(error.message);
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
22
|
+
throw error;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function validateCommand(input: string): Promise<void>;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { detectFormat } from '../parsers/detector.js';
|
|
2
|
+
import { parseOpenAPI } from '../parsers/openapi.js';
|
|
3
|
+
import { logger } from '../utils/logger.js';
|
|
4
|
+
export async function validateCommand(input) {
|
|
5
|
+
try {
|
|
6
|
+
logger.info(`Validating: ${input}`);
|
|
7
|
+
const detection = await detectFormat(input);
|
|
8
|
+
logger.success(`Format detected: ${detection.format}`);
|
|
9
|
+
if (detection.format === 'openapi' || detection.format === 'swagger') {
|
|
10
|
+
const schema = parseOpenAPI(detection.content);
|
|
11
|
+
logger.success(`Valid API specification: ${schema.name}`);
|
|
12
|
+
logger.info(`Base URL: ${schema.baseUrl}`);
|
|
13
|
+
logger.info(`Endpoints: ${schema.endpoints.length}`);
|
|
14
|
+
logger.info(`Auth type: ${schema.auth.type}`);
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
logger.warn('Format detected but parsing not implemented yet');
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
catch (error) {
|
|
21
|
+
if (error instanceof Error) {
|
|
22
|
+
logger.error(`Validation failed: ${error.message}`);
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
25
|
+
throw error;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export function analyzePatterns(schema) {
|
|
2
|
+
return {
|
|
3
|
+
authPattern: schema.auth.type,
|
|
4
|
+
paginationStyle: schema.pagination?.style,
|
|
5
|
+
rateLimitStrategy: schema.rateLimit?.strategy || 'none',
|
|
6
|
+
errorFormat: detectErrorFormat(schema),
|
|
7
|
+
hasWebhooks: false,
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
function detectErrorFormat(schema) {
|
|
11
|
+
// Check if any endpoint has custom error schemas
|
|
12
|
+
const hasCustomErrors = schema.endpoints.some(endpoint => endpoint.errors.length > 0 && endpoint.errors.some(e => e.schema));
|
|
13
|
+
return hasCustomErrors ? 'custom' : 'standard';
|
|
14
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { APISchema, DetectedPatterns } from '../schema/api-schema.js';
|
|
2
|
+
export interface GenerationContext {
|
|
3
|
+
name: string;
|
|
4
|
+
baseUrl: string;
|
|
5
|
+
auth: any;
|
|
6
|
+
endpoints: any[];
|
|
7
|
+
patterns: DetectedPatterns;
|
|
8
|
+
absolutePath?: string;
|
|
9
|
+
}
|
|
10
|
+
export declare function generateServer(schema: APISchema, patterns: DetectedPatterns, outputDir: string): Promise<void>;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import * as fs from 'fs/promises';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import Handlebars from 'handlebars';
|
|
4
|
+
import { GenerationError } from '../utils/errors.js';
|
|
5
|
+
import { fileURLToPath } from 'url';
|
|
6
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
7
|
+
const __dirname = path.dirname(__filename);
|
|
8
|
+
// Register Handlebars helper for equality check
|
|
9
|
+
Handlebars.registerHelper('eq', (a, b) => a === b);
|
|
10
|
+
export async function generateServer(schema, patterns, outputDir) {
|
|
11
|
+
const context = {
|
|
12
|
+
name: schema.name,
|
|
13
|
+
baseUrl: schema.baseUrl,
|
|
14
|
+
auth: schema.auth,
|
|
15
|
+
endpoints: schema.endpoints,
|
|
16
|
+
patterns,
|
|
17
|
+
absolutePath: path.resolve(outputDir),
|
|
18
|
+
};
|
|
19
|
+
// Create output directory structure
|
|
20
|
+
await fs.mkdir(path.join(outputDir, 'src'), { recursive: true });
|
|
21
|
+
// Get template directory
|
|
22
|
+
const templateDir = path.join(__dirname, '..', '..', 'templates');
|
|
23
|
+
// Generate files from templates
|
|
24
|
+
await generateFile(templateDir, outputDir, 'package.json.hbs', 'package.json', context);
|
|
25
|
+
await generateFile(templateDir, outputDir, 'tsconfig.json.hbs', 'tsconfig.json', context);
|
|
26
|
+
await generateFile(templateDir, outputDir, 'README.md.hbs', 'README.md', context);
|
|
27
|
+
await generateFile(templateDir, outputDir, 'index.ts.hbs', 'src/index.ts', context);
|
|
28
|
+
await generateFile(templateDir, outputDir, 'client.ts.hbs', 'src/client.ts', context);
|
|
29
|
+
await generateFile(templateDir, outputDir, 'tools.ts.hbs', 'src/tools.ts', context);
|
|
30
|
+
await generateFile(templateDir, outputDir, 'types.ts.hbs', 'src/types.ts', context);
|
|
31
|
+
await generateFile(templateDir, outputDir, 'validation.ts.hbs', 'src/validation.ts', context);
|
|
32
|
+
await generateFile(templateDir, outputDir, 'test.ts.hbs', 'test.ts', context);
|
|
33
|
+
}
|
|
34
|
+
async function generateFile(templateDir, outputDir, templateFile, outputFile, context) {
|
|
35
|
+
try {
|
|
36
|
+
const templatePath = path.join(templateDir, templateFile);
|
|
37
|
+
const templateContent = await fs.readFile(templatePath, 'utf-8');
|
|
38
|
+
const template = Handlebars.compile(templateContent);
|
|
39
|
+
const output = template(context);
|
|
40
|
+
const outputPath = path.join(outputDir, outputFile);
|
|
41
|
+
await fs.writeFile(outputPath, output, 'utf-8');
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
throw new GenerationError(`Failed to generate ${outputFile}: ${error}`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { ParseError } from '../utils/errors.js';
|
|
2
|
+
export async function parseWithAI(content) {
|
|
3
|
+
if (!process.env.ANTHROPIC_API_KEY) {
|
|
4
|
+
throw new ParseError('ANTHROPIC_API_KEY environment variable required for AI parsing');
|
|
5
|
+
}
|
|
6
|
+
throw new ParseError('AI-powered parsing not yet implemented');
|
|
7
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import * as fs from 'fs/promises';
|
|
2
|
+
import * as yaml from 'yaml';
|
|
3
|
+
import { ParseError } from '../utils/errors.js';
|
|
4
|
+
export async function detectFormat(input) {
|
|
5
|
+
let content;
|
|
6
|
+
// Check if input is a file path
|
|
7
|
+
try {
|
|
8
|
+
content = await fs.readFile(input, 'utf-8');
|
|
9
|
+
}
|
|
10
|
+
catch {
|
|
11
|
+
throw new ParseError(`Could not read file: ${input}`);
|
|
12
|
+
}
|
|
13
|
+
// Try parsing as JSON
|
|
14
|
+
let parsed;
|
|
15
|
+
try {
|
|
16
|
+
parsed = JSON.parse(content);
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
// Try parsing as YAML
|
|
20
|
+
try {
|
|
21
|
+
parsed = yaml.parse(content);
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
throw new ParseError('Could not parse input as JSON or YAML');
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
// Detect format from parsed content
|
|
28
|
+
if (parsed.openapi) {
|
|
29
|
+
return { format: 'openapi', content: parsed };
|
|
30
|
+
}
|
|
31
|
+
if (parsed.swagger) {
|
|
32
|
+
return { format: 'swagger', content: parsed };
|
|
33
|
+
}
|
|
34
|
+
if (parsed.info?.schema?.includes('postman')) {
|
|
35
|
+
return { format: 'postman', content: parsed };
|
|
36
|
+
}
|
|
37
|
+
return { format: 'unknown', content: parsed };
|
|
38
|
+
}
|