@aiready/mcp-server 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/.turbo/turbo-build.log +17 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +102 -0
- package/package.json +43 -0
- package/src/__tests__/server.test.ts +106 -0
- package/src/index.ts +122 -0
- package/test-mcp.ts +84 -0
- package/tsconfig.json +8 -0
- package/tsup.config.ts +26 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
> @aiready/mcp-server@0.1.0 build /Users/pengcao/projects/aiready/packages/mcp-server
|
|
4
|
+
> tsup src/index.ts --format esm --clean --dts
|
|
5
|
+
|
|
6
|
+
[34mCLI[39m Building entry: src/index.ts
|
|
7
|
+
[34mCLI[39m Using tsconfig: tsconfig.json
|
|
8
|
+
[34mCLI[39m tsup v8.5.1
|
|
9
|
+
[34mCLI[39m Using tsup config: /Users/pengcao/projects/aiready/packages/mcp-server/tsup.config.ts
|
|
10
|
+
[34mCLI[39m Target: node20
|
|
11
|
+
[34mCLI[39m Cleaning output folder
|
|
12
|
+
[34mESM[39m Build start
|
|
13
|
+
[32mESM[39m [1mdist/index.js [22m[32m2.74 KB[39m
|
|
14
|
+
[32mESM[39m ⚡️ Build success in 29ms
|
|
15
|
+
DTS Build start
|
|
16
|
+
DTS ⚡️ Build success in 2555ms
|
|
17
|
+
DTS dist/index.d.ts 202.00 B
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/index.ts
|
|
4
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
5
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
6
|
+
import {
|
|
7
|
+
CallToolRequestSchema,
|
|
8
|
+
ListToolsRequestSchema
|
|
9
|
+
} from "@modelcontextprotocol/sdk/types.js";
|
|
10
|
+
import { ToolRegistry } from "@aiready/core";
|
|
11
|
+
import chalk from "chalk";
|
|
12
|
+
import "@aiready/pattern-detect";
|
|
13
|
+
import "@aiready/context-analyzer";
|
|
14
|
+
import "@aiready/consistency";
|
|
15
|
+
var AIReadyMcpServer = class {
|
|
16
|
+
constructor() {
|
|
17
|
+
this.server = new Server(
|
|
18
|
+
{
|
|
19
|
+
name: "aiready-server",
|
|
20
|
+
version: "0.1.0"
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
capabilities: {
|
|
24
|
+
tools: {}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
);
|
|
28
|
+
this.setupHandlers();
|
|
29
|
+
this.server.onerror = (error) => {
|
|
30
|
+
console.error(chalk.red("[MCP Error]"), error);
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
setupHandlers() {
|
|
34
|
+
this.server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
35
|
+
const providers = ToolRegistry.getAll();
|
|
36
|
+
return {
|
|
37
|
+
tools: providers.map((p) => ({
|
|
38
|
+
name: p.id,
|
|
39
|
+
description: `AIReady analysis tool: ${p.id}`,
|
|
40
|
+
inputSchema: {
|
|
41
|
+
type: "object",
|
|
42
|
+
properties: {
|
|
43
|
+
path: {
|
|
44
|
+
type: "string",
|
|
45
|
+
description: "Path to the directory to analyze"
|
|
46
|
+
}
|
|
47
|
+
// Future: expose tool-specific options
|
|
48
|
+
},
|
|
49
|
+
required: ["path"]
|
|
50
|
+
}
|
|
51
|
+
}))
|
|
52
|
+
};
|
|
53
|
+
});
|
|
54
|
+
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
55
|
+
const { name, arguments: args } = request.params;
|
|
56
|
+
try {
|
|
57
|
+
const provider = ToolRegistry.find(name);
|
|
58
|
+
if (!provider) {
|
|
59
|
+
throw new Error(`Tool ${name} not found`);
|
|
60
|
+
}
|
|
61
|
+
if (!args || typeof args.path !== "string") {
|
|
62
|
+
throw new Error("Missing required argument: path");
|
|
63
|
+
}
|
|
64
|
+
console.error(chalk.blue(`[MCP] Executing ${name} on ${args.path}`));
|
|
65
|
+
const results = await provider.analyze({
|
|
66
|
+
rootDir: args.path
|
|
67
|
+
});
|
|
68
|
+
return {
|
|
69
|
+
content: [
|
|
70
|
+
{
|
|
71
|
+
type: "text",
|
|
72
|
+
text: JSON.stringify(results, null, 2)
|
|
73
|
+
}
|
|
74
|
+
]
|
|
75
|
+
};
|
|
76
|
+
} catch (error) {
|
|
77
|
+
return {
|
|
78
|
+
content: [
|
|
79
|
+
{
|
|
80
|
+
type: "text",
|
|
81
|
+
text: `Error: ${error.message}`
|
|
82
|
+
}
|
|
83
|
+
],
|
|
84
|
+
isError: true
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
async run() {
|
|
90
|
+
const transport = new StdioServerTransport();
|
|
91
|
+
await this.server.connect(transport);
|
|
92
|
+
console.error(chalk.green("AIReady MCP Server started"));
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
var server = new AIReadyMcpServer();
|
|
96
|
+
server.run().catch((error) => {
|
|
97
|
+
console.error(chalk.red("Fatal error starting AIReady MCP Server:"), error);
|
|
98
|
+
process.exit(1);
|
|
99
|
+
});
|
|
100
|
+
export {
|
|
101
|
+
AIReadyMcpServer
|
|
102
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@aiready/mcp-server",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "AIReady Model Context Protocol (MCP) Server",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"module": "./dist/index.mjs",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"type": "module",
|
|
9
|
+
"bin": {
|
|
10
|
+
"aiready-mcp": "./dist/index.js"
|
|
11
|
+
},
|
|
12
|
+
"dependencies": {
|
|
13
|
+
"@modelcontextprotocol/sdk": "^0.6.0",
|
|
14
|
+
"chalk": "^5.3.0",
|
|
15
|
+
"zod": "^4.3.6",
|
|
16
|
+
"@aiready/core": "0.23.2",
|
|
17
|
+
"@aiready/context-analyzer": "0.21.6",
|
|
18
|
+
"@aiready/consistency": "0.20.2",
|
|
19
|
+
"@aiready/pattern-detect": "0.16.2"
|
|
20
|
+
},
|
|
21
|
+
"devDependencies": {
|
|
22
|
+
"@types/node": "^24.0.0",
|
|
23
|
+
"tsup": "^8.3.5",
|
|
24
|
+
"typescript": "^5.9.3",
|
|
25
|
+
"vitest": "^2.1.0"
|
|
26
|
+
},
|
|
27
|
+
"keywords": [
|
|
28
|
+
"aiready",
|
|
29
|
+
"mcp",
|
|
30
|
+
"model-context-protocol",
|
|
31
|
+
"ai-readiness",
|
|
32
|
+
"code-analysis"
|
|
33
|
+
],
|
|
34
|
+
"license": "MIT",
|
|
35
|
+
"scripts": {
|
|
36
|
+
"build": "tsup src/index.ts --format esm --clean --dts",
|
|
37
|
+
"dev": "tsup src/index.ts --format esm --watch",
|
|
38
|
+
"test": "vitest run",
|
|
39
|
+
"lint": "eslint src",
|
|
40
|
+
"clean": "rm -rf dist",
|
|
41
|
+
"start": "node dist/index.js"
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
|
|
2
|
+
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
3
|
+
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
|
|
4
|
+
import {
|
|
5
|
+
ListToolsRequestSchema,
|
|
6
|
+
CallToolRequestSchema,
|
|
7
|
+
} from '@modelcontextprotocol/sdk/types.js';
|
|
8
|
+
import path from 'path';
|
|
9
|
+
import { fileURLToPath } from 'url';
|
|
10
|
+
|
|
11
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
12
|
+
// Point to the built JS to ensure we are testing the actual distribution
|
|
13
|
+
const serverPath = path.resolve(__dirname, '../../dist/index.js');
|
|
14
|
+
|
|
15
|
+
describe('AIReady MCP Server Integration', () => {
|
|
16
|
+
let client: Client;
|
|
17
|
+
let transport: StdioClientTransport;
|
|
18
|
+
|
|
19
|
+
beforeAll(async () => {
|
|
20
|
+
transport = new StdioClientTransport({
|
|
21
|
+
command: 'node',
|
|
22
|
+
args: [serverPath],
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
client = new Client(
|
|
26
|
+
{ name: 'test-client', version: '1.0.0' },
|
|
27
|
+
{ capabilities: {} }
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
await client.connect(transport);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
afterAll(async () => {
|
|
34
|
+
// StdioClientTransport doesn't have an explicit close, but we should clear references
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('should list available tools', async () => {
|
|
38
|
+
const result = await client.listTools();
|
|
39
|
+
|
|
40
|
+
expect(result.tools).toBeDefined();
|
|
41
|
+
expect(result.tools.length).toBeGreaterThan(0);
|
|
42
|
+
|
|
43
|
+
const toolNames = result.tools.map((t) => t.name);
|
|
44
|
+
expect(toolNames).toContain('pattern-detect');
|
|
45
|
+
expect(toolNames).toContain('context-analyzer');
|
|
46
|
+
expect(toolNames).toContain('naming-consistency');
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('should expose correct input schema for tools', async () => {
|
|
50
|
+
const result = await client.listTools();
|
|
51
|
+
|
|
52
|
+
const patternDetect = result.tools.find((t) => t.name === 'pattern-detect');
|
|
53
|
+
expect(patternDetect?.inputSchema).toMatchObject({
|
|
54
|
+
type: 'object',
|
|
55
|
+
properties: {
|
|
56
|
+
path: { type: 'string' },
|
|
57
|
+
},
|
|
58
|
+
required: ['path'],
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('should execute pattern-detect and return results', async () => {
|
|
63
|
+
const result = await client.callTool({
|
|
64
|
+
name: 'pattern-detect',
|
|
65
|
+
arguments: {
|
|
66
|
+
path: path.resolve(__dirname, '../../../core'), // Test on core package
|
|
67
|
+
},
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
// Check if result has content
|
|
71
|
+
expect(result.content).toBeDefined();
|
|
72
|
+
|
|
73
|
+
const firstContent = result.content[0];
|
|
74
|
+
expect(firstContent.type).toBe('text');
|
|
75
|
+
|
|
76
|
+
const data = JSON.parse((firstContent as any).text);
|
|
77
|
+
expect(data).toHaveProperty('results');
|
|
78
|
+
expect(data).toHaveProperty('summary');
|
|
79
|
+
}, 20000); // Higher timeout for analysis
|
|
80
|
+
|
|
81
|
+
it('should return error for unknown tool', async () => {
|
|
82
|
+
const result = await client.callTool({
|
|
83
|
+
name: 'non-existent-tool',
|
|
84
|
+
arguments: { path: '.' },
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
expect(result.isError).toBe(true);
|
|
88
|
+
expect((result.content[0] as any).text).toContain(
|
|
89
|
+
'Tool non-existent-tool not found'
|
|
90
|
+
);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('should return error for missing arguments', async () => {
|
|
94
|
+
// Note: The server handles missing arguments and returns isError: true
|
|
95
|
+
const result = await client.callTool({
|
|
96
|
+
name: 'pattern-detect',
|
|
97
|
+
arguments: {},
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
expect(result.isError).toBe(true);
|
|
101
|
+
expect(result.content[0].type).toBe('text');
|
|
102
|
+
expect((result.content[0] as any).text).toContain(
|
|
103
|
+
'Missing required argument: path'
|
|
104
|
+
);
|
|
105
|
+
});
|
|
106
|
+
});
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
2
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
3
|
+
import {
|
|
4
|
+
CallToolRequestSchema,
|
|
5
|
+
ListToolsRequestSchema,
|
|
6
|
+
} from '@modelcontextprotocol/sdk/types.js';
|
|
7
|
+
import { ToolRegistry, ToolName } from '@aiready/core';
|
|
8
|
+
import chalk from 'chalk';
|
|
9
|
+
|
|
10
|
+
// Pre-load essential tools (following CLI pattern)
|
|
11
|
+
// In a real implementation, we would want to dynamically load these
|
|
12
|
+
// or have them as peer dependencies.
|
|
13
|
+
import '@aiready/pattern-detect';
|
|
14
|
+
import '@aiready/context-analyzer';
|
|
15
|
+
import '@aiready/consistency';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* AIReady MCP Server Implementation
|
|
19
|
+
*/
|
|
20
|
+
export class AIReadyMcpServer {
|
|
21
|
+
private server: Server;
|
|
22
|
+
|
|
23
|
+
constructor() {
|
|
24
|
+
this.server = new Server(
|
|
25
|
+
{
|
|
26
|
+
name: 'aiready-server',
|
|
27
|
+
version: '0.1.0',
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
capabilities: {
|
|
31
|
+
tools: {},
|
|
32
|
+
},
|
|
33
|
+
}
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
this.setupHandlers();
|
|
37
|
+
|
|
38
|
+
this.server.onerror = (error) => {
|
|
39
|
+
console.error(chalk.red('[MCP Error]'), error);
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
private setupHandlers() {
|
|
44
|
+
// List available tools
|
|
45
|
+
this.server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
46
|
+
const providers = ToolRegistry.getAll();
|
|
47
|
+
|
|
48
|
+
return {
|
|
49
|
+
tools: providers.map((p) => ({
|
|
50
|
+
name: p.id,
|
|
51
|
+
description: `AIReady analysis tool: ${p.id}`,
|
|
52
|
+
inputSchema: {
|
|
53
|
+
type: 'object',
|
|
54
|
+
properties: {
|
|
55
|
+
path: {
|
|
56
|
+
type: 'string',
|
|
57
|
+
description: 'Path to the directory to analyze',
|
|
58
|
+
},
|
|
59
|
+
// Future: expose tool-specific options
|
|
60
|
+
},
|
|
61
|
+
required: ['path'],
|
|
62
|
+
},
|
|
63
|
+
})),
|
|
64
|
+
};
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
// Handle tool execution
|
|
68
|
+
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
69
|
+
const { name, arguments: args } = request.params;
|
|
70
|
+
|
|
71
|
+
try {
|
|
72
|
+
const provider = ToolRegistry.find(name);
|
|
73
|
+
if (!provider) {
|
|
74
|
+
throw new Error(`Tool ${name} not found`);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (!args || typeof args.path !== 'string') {
|
|
78
|
+
throw new Error('Missing required argument: path');
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
console.error(chalk.blue(`[MCP] Executing ${name} on ${args.path}`));
|
|
82
|
+
|
|
83
|
+
const results = await provider.analyze({
|
|
84
|
+
rootDir: args.path,
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
// Format results for the agent
|
|
88
|
+
return {
|
|
89
|
+
content: [
|
|
90
|
+
{
|
|
91
|
+
type: 'text',
|
|
92
|
+
text: JSON.stringify(results, null, 2),
|
|
93
|
+
},
|
|
94
|
+
],
|
|
95
|
+
};
|
|
96
|
+
} catch (error: any) {
|
|
97
|
+
return {
|
|
98
|
+
content: [
|
|
99
|
+
{
|
|
100
|
+
type: 'text',
|
|
101
|
+
text: `Error: ${error.message}`,
|
|
102
|
+
},
|
|
103
|
+
],
|
|
104
|
+
isError: true,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
async run() {
|
|
111
|
+
const transport = new StdioServerTransport();
|
|
112
|
+
await this.server.connect(transport);
|
|
113
|
+
console.error(chalk.green('AIReady MCP Server started'));
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Bootstrap the server
|
|
118
|
+
const server = new AIReadyMcpServer();
|
|
119
|
+
server.run().catch((error) => {
|
|
120
|
+
console.error(chalk.red('Fatal error starting AIReady MCP Server:'), error);
|
|
121
|
+
process.exit(1);
|
|
122
|
+
});
|
package/test-mcp.ts
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
2
|
+
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
|
|
3
|
+
import {
|
|
4
|
+
ListToolsRequestSchema,
|
|
5
|
+
CallToolRequestSchema,
|
|
6
|
+
} from '@modelcontextprotocol/sdk/types.js';
|
|
7
|
+
import path from 'path';
|
|
8
|
+
import { fileURLToPath } from 'url';
|
|
9
|
+
|
|
10
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
11
|
+
const serverPath = path.join(__dirname, 'dist', 'index.js');
|
|
12
|
+
|
|
13
|
+
async function testServer() {
|
|
14
|
+
console.log('🚀 Starting MCP Server verification test...');
|
|
15
|
+
|
|
16
|
+
const transport = new StdioClientTransport({
|
|
17
|
+
command: 'node',
|
|
18
|
+
args: [serverPath],
|
|
19
|
+
env: {
|
|
20
|
+
...process.env,
|
|
21
|
+
NODE_ENV: 'test',
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
const client = new Client(
|
|
26
|
+
{
|
|
27
|
+
name: 'test-client',
|
|
28
|
+
version: '1.0.0',
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
capabilities: {},
|
|
32
|
+
}
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
try {
|
|
36
|
+
await client.connect(transport);
|
|
37
|
+
console.log('✅ Connected to MCP Server');
|
|
38
|
+
|
|
39
|
+
// Test ListTools
|
|
40
|
+
const tools = await client.request(
|
|
41
|
+
{ method: 'tools/list' },
|
|
42
|
+
ListToolsRequestSchema
|
|
43
|
+
);
|
|
44
|
+
console.log(
|
|
45
|
+
'📋 Available Tools:',
|
|
46
|
+
tools.tools.map((t) => t.name).join(', ')
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
if (tools.tools.length === 0) {
|
|
50
|
+
throw new Error('No tools listed!');
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Test CallTool (pattern-detect)
|
|
54
|
+
console.log("🔍 Testing 'pattern-detect'...");
|
|
55
|
+
const rootDir = '/Users/pengcao/projects/aiready'; // Test on current repo
|
|
56
|
+
const result = await client.request(
|
|
57
|
+
{
|
|
58
|
+
method: 'tools/call',
|
|
59
|
+
params: {
|
|
60
|
+
name: 'pattern-detect',
|
|
61
|
+
arguments: { path: rootDir },
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
CallToolRequestSchema
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
if (result.isError) {
|
|
68
|
+
console.error('❌ Tool execution failed:', result.content[0].text);
|
|
69
|
+
} else {
|
|
70
|
+
console.log('✅ Tool execution success!');
|
|
71
|
+
const data = JSON.parse(result.content[0].text);
|
|
72
|
+
console.log(
|
|
73
|
+
`📊 Found ${data.duplicates?.length || 0} duplicate patterns.`
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
} catch (error) {
|
|
77
|
+
console.error('💥 Test failed:', error);
|
|
78
|
+
} finally {
|
|
79
|
+
console.log('🏁 Verification test complete.');
|
|
80
|
+
process.exit(0);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
testServer();
|
package/tsconfig.json
ADDED
package/tsup.config.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { defineConfig } from 'tsup';
|
|
2
|
+
|
|
3
|
+
export default defineConfig({
|
|
4
|
+
entry: ['src/index.ts'],
|
|
5
|
+
format: ['esm'],
|
|
6
|
+
dts: true,
|
|
7
|
+
clean: true,
|
|
8
|
+
shims: true,
|
|
9
|
+
// Treat these as external to avoid bundling them (they will be resolved at runtime)
|
|
10
|
+
external: [
|
|
11
|
+
'@aiready/core',
|
|
12
|
+
'@aiready/pattern-detect',
|
|
13
|
+
'@aiready/context-analyzer',
|
|
14
|
+
'@aiready/consistency',
|
|
15
|
+
'@modelcontextprotocol/sdk',
|
|
16
|
+
'path',
|
|
17
|
+
'url',
|
|
18
|
+
'fs',
|
|
19
|
+
],
|
|
20
|
+
// Ensure we are targeting a modern node version
|
|
21
|
+
target: 'node20',
|
|
22
|
+
// Build to be executable
|
|
23
|
+
banner: {
|
|
24
|
+
js: '#!/usr/bin/env node',
|
|
25
|
+
},
|
|
26
|
+
});
|