lazy-mcp 1.0.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 +63 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +117 -0
- package/dist/cli.js.map +1 -0
- package/dist/proxy.d.ts +10 -0
- package/dist/proxy.d.ts.map +1 -0
- package/dist/proxy.js +51 -0
- package/dist/proxy.js.map +1 -0
- package/dist/server.d.ts +9 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +141 -0
- package/dist/server.js.map +1 -0
- package/dist/types.d.ts +36 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/package.json +42 -0
package/README.md
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Lazy MCP Proxy
|
|
2
|
+
|
|
3
|
+
A proxy tool that converts normal MCP servers to use a lazy-loading pattern with three core tools, dramatically reducing initial context usage and enabling support for hundreds of commands.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
Instead of exposing all tools directly (which can consume many context tokens), this proxy exposes only three meta-tools:
|
|
8
|
+
|
|
9
|
+
- `list_commands` - Returns command names and brief descriptions
|
|
10
|
+
- `describe_commands` - Accepts `command_names: Array[String]`, returns full schemas
|
|
11
|
+
- `invoke_command` - Executes commands with `command_name: String, parameters: Object`
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install -g lazy-mcp
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Or use with npx:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npx lazy-mcp <server-command> [server-args...]
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Usage
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
# Run a Python MCP server through the lazy proxy
|
|
29
|
+
lazy-mcp python my_server.py
|
|
30
|
+
|
|
31
|
+
# Run a Node.js MCP server through the lazy proxy
|
|
32
|
+
lazy-mcp node my_server.js
|
|
33
|
+
|
|
34
|
+
# Pass additional arguments to the original server
|
|
35
|
+
lazy-mcp python my_server.py --config config.json
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Example
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
# Original server with many tools
|
|
42
|
+
python my_server.py
|
|
43
|
+
# Exposes: tool1, tool2, tool3, ..., tool100 (uses 100x context)
|
|
44
|
+
|
|
45
|
+
# Through lazy proxy
|
|
46
|
+
lazy-mcp python my_server.py
|
|
47
|
+
# Exposes: list_commands, describe_commands, invoke_command (uses 3x context)
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Development
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
npm install
|
|
54
|
+
npm run build
|
|
55
|
+
npm run dev -- python example_server.py
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Benefits
|
|
59
|
+
|
|
60
|
+
- **Dramatic reduction** in initial context usage
|
|
61
|
+
- **Progressive tool discovery** - only load schemas when needed
|
|
62
|
+
- **Scales to hundreds** of commands without context bloat
|
|
63
|
+
- **Clean separation** of concerns between discovery and execution
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
const child_process_1 = require("child_process");
|
|
5
|
+
const server_js_1 = require("./server.js");
|
|
6
|
+
class ExternalMCPServer {
|
|
7
|
+
constructor(serverCommand, serverArgs = []) {
|
|
8
|
+
this.serverCommand = serverCommand;
|
|
9
|
+
this.serverArgs = serverArgs;
|
|
10
|
+
}
|
|
11
|
+
async listTools() {
|
|
12
|
+
return new Promise((resolve, reject) => {
|
|
13
|
+
const process = (0, child_process_1.spawn)(this.serverCommand, this.serverArgs, {
|
|
14
|
+
stdio: ['pipe', 'pipe', 'inherit']
|
|
15
|
+
});
|
|
16
|
+
const request = {
|
|
17
|
+
jsonrpc: '2.0',
|
|
18
|
+
id: 1,
|
|
19
|
+
method: 'tools/list'
|
|
20
|
+
};
|
|
21
|
+
let responseData = '';
|
|
22
|
+
process.stdout.on('data', (data) => {
|
|
23
|
+
responseData += data.toString();
|
|
24
|
+
});
|
|
25
|
+
process.on('close', (code) => {
|
|
26
|
+
if (code !== 0) {
|
|
27
|
+
reject(new Error(`Server process exited with code ${code}`));
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
try {
|
|
31
|
+
const lines = responseData.trim().split('\n');
|
|
32
|
+
for (const line of lines) {
|
|
33
|
+
if (line.trim()) {
|
|
34
|
+
const response = JSON.parse(line);
|
|
35
|
+
if (response.id === 1 && response.result) {
|
|
36
|
+
resolve(response.result);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
reject(new Error('No valid response received'));
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
reject(new Error(`Failed to parse response: ${error}`));
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
process.stdin.write(JSON.stringify(request) + '\n');
|
|
48
|
+
process.stdin.end();
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
async callTool(name, arguments_) {
|
|
52
|
+
return new Promise((resolve, reject) => {
|
|
53
|
+
const process = (0, child_process_1.spawn)(this.serverCommand, this.serverArgs, {
|
|
54
|
+
stdio: ['pipe', 'pipe', 'inherit']
|
|
55
|
+
});
|
|
56
|
+
const request = {
|
|
57
|
+
jsonrpc: '2.0',
|
|
58
|
+
id: 2,
|
|
59
|
+
method: 'tools/call',
|
|
60
|
+
params: {
|
|
61
|
+
name,
|
|
62
|
+
arguments: arguments_
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
let responseData = '';
|
|
66
|
+
process.stdout.on('data', (data) => {
|
|
67
|
+
responseData += data.toString();
|
|
68
|
+
});
|
|
69
|
+
process.on('close', (code) => {
|
|
70
|
+
if (code !== 0) {
|
|
71
|
+
reject(new Error(`Server process exited with code ${code}`));
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
try {
|
|
75
|
+
const lines = responseData.trim().split('\n');
|
|
76
|
+
for (const line of lines) {
|
|
77
|
+
if (line.trim()) {
|
|
78
|
+
const response = JSON.parse(line);
|
|
79
|
+
if (response.id === 2 && response.result) {
|
|
80
|
+
resolve(response.result);
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
reject(new Error('No valid response received'));
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
reject(new Error(`Failed to parse response: ${error}`));
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
process.stdin.write(JSON.stringify(request) + '\n');
|
|
92
|
+
process.stdin.end();
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
async function main() {
|
|
97
|
+
const args = process.argv.slice(2);
|
|
98
|
+
if (args.length === 0) {
|
|
99
|
+
console.error('Usage: lazy-mcp <server-command> [server-args...]');
|
|
100
|
+
console.error('Example: lazy-mcp python my_server.py');
|
|
101
|
+
process.exit(1);
|
|
102
|
+
}
|
|
103
|
+
const [serverCommand, ...serverArgs] = args;
|
|
104
|
+
const originalServer = new ExternalMCPServer(serverCommand, serverArgs);
|
|
105
|
+
const lazyServer = new server_js_1.LazyMCPServer(originalServer);
|
|
106
|
+
try {
|
|
107
|
+
await lazyServer.run();
|
|
108
|
+
}
|
|
109
|
+
catch (error) {
|
|
110
|
+
console.error('Error starting lazy MCP server:', error);
|
|
111
|
+
process.exit(1);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
if (require.main === module) {
|
|
115
|
+
main().catch(console.error);
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/proxy.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { CommandInfo, CommandSchema, MCPServer, LazyMCPProxy } from './types.js';
|
|
2
|
+
export declare class LazyMCPProxyImpl implements LazyMCPProxy {
|
|
3
|
+
private mcpServer;
|
|
4
|
+
private toolsCache;
|
|
5
|
+
constructor(mcpServer: MCPServer);
|
|
6
|
+
listCommands(): Promise<CommandInfo[]>;
|
|
7
|
+
describeCommands(commandNames: string[]): Promise<CommandSchema[]>;
|
|
8
|
+
invokeCommand(commandName: string, parameters: Record<string, any>): Promise<any>;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=proxy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxy.d.ts","sourceRoot":"","sources":["../src/proxy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,SAAS,EAAE,YAAY,EAAW,MAAM,YAAY,CAAC;AAE1F,qBAAa,gBAAiB,YAAW,YAAY;IACnD,OAAO,CAAC,SAAS,CAAY;IAC7B,OAAO,CAAC,UAAU,CAA0B;gBAEhC,SAAS,EAAE,SAAS;IAI1B,YAAY,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;IAYtC,gBAAgB,CAAC,YAAY,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC;IAuBlE,aAAa,CAAC,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC;CAQxF"}
|
package/dist/proxy.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.LazyMCPProxyImpl = void 0;
|
|
4
|
+
class LazyMCPProxyImpl {
|
|
5
|
+
constructor(mcpServer) {
|
|
6
|
+
this.toolsCache = null;
|
|
7
|
+
this.mcpServer = mcpServer;
|
|
8
|
+
}
|
|
9
|
+
async listCommands() {
|
|
10
|
+
if (!this.toolsCache) {
|
|
11
|
+
const result = await this.mcpServer.listTools();
|
|
12
|
+
this.toolsCache = result.tools;
|
|
13
|
+
}
|
|
14
|
+
return this.toolsCache.map(tool => ({
|
|
15
|
+
name: tool.name,
|
|
16
|
+
description: tool.description
|
|
17
|
+
}));
|
|
18
|
+
}
|
|
19
|
+
async describeCommands(commandNames) {
|
|
20
|
+
if (!this.toolsCache) {
|
|
21
|
+
const result = await this.mcpServer.listTools();
|
|
22
|
+
this.toolsCache = result.tools;
|
|
23
|
+
}
|
|
24
|
+
const schemas = [];
|
|
25
|
+
for (const commandName of commandNames) {
|
|
26
|
+
const tool = this.toolsCache.find(t => t.name === commandName);
|
|
27
|
+
if (tool) {
|
|
28
|
+
schemas.push({
|
|
29
|
+
name: tool.name,
|
|
30
|
+
description: tool.description,
|
|
31
|
+
inputSchema: tool.inputSchema
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
throw new Error(`Command '${commandName}' not found`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return schemas;
|
|
39
|
+
}
|
|
40
|
+
async invokeCommand(commandName, parameters) {
|
|
41
|
+
try {
|
|
42
|
+
const result = await this.mcpServer.callTool(commandName, parameters);
|
|
43
|
+
return result.content;
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
throw new Error(`Failed to invoke command '${commandName}': ${error}`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
exports.LazyMCPProxyImpl = LazyMCPProxyImpl;
|
|
51
|
+
//# sourceMappingURL=proxy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxy.js","sourceRoot":"","sources":["../src/proxy.ts"],"names":[],"mappings":";;;AAEA,MAAa,gBAAgB;IAI3B,YAAY,SAAoB;QAFxB,eAAU,GAAqB,IAAI,CAAC;QAG1C,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;IAC7B,CAAC;IAED,KAAK,CAAC,YAAY;QAChB,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;YACrB,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,CAAC;YAChD,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC,KAAK,CAAC;QACjC,CAAC;QAED,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAClC,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,WAAW,EAAE,IAAI,CAAC,WAAW;SAC9B,CAAC,CAAC,CAAC;IACN,CAAC;IAED,KAAK,CAAC,gBAAgB,CAAC,YAAsB;QAC3C,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;YACrB,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,CAAC;YAChD,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC,KAAK,CAAC;QACjC,CAAC;QAED,MAAM,OAAO,GAAoB,EAAE,CAAC;QACpC,KAAK,MAAM,WAAW,IAAI,YAAY,EAAE,CAAC;YACvC,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,WAAW,CAAC,CAAC;YAC/D,IAAI,IAAI,EAAE,CAAC;gBACT,OAAO,CAAC,IAAI,CAAC;oBACX,IAAI,EAAE,IAAI,CAAC,IAAI;oBACf,WAAW,EAAE,IAAI,CAAC,WAAW;oBAC7B,WAAW,EAAE,IAAI,CAAC,WAAW;iBAC9B,CAAC,CAAC;YACL,CAAC;iBAAM,CAAC;gBACN,MAAM,IAAI,KAAK,CAAC,YAAY,WAAW,aAAa,CAAC,CAAC;YACxD,CAAC;QACH,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,WAAmB,EAAE,UAA+B;QACtE,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC;YACtE,OAAO,MAAM,CAAC,OAAO,CAAC;QACxB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CAAC,6BAA6B,WAAW,MAAM,KAAK,EAAE,CAAC,CAAC;QACzE,CAAC;IACH,CAAC;CACF;AAnDD,4CAmDC"}
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEvC,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,KAAK,CAAmB;gBAEpB,iBAAiB,EAAE,SAAS;IAiBxC,OAAO,CAAC,aAAa;IA0Hf,GAAG;CAIV"}
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.LazyMCPServer = void 0;
|
|
4
|
+
const index_js_1 = require("@modelcontextprotocol/sdk/server/index.js");
|
|
5
|
+
const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
6
|
+
const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
|
|
7
|
+
const proxy_js_1 = require("./proxy.js");
|
|
8
|
+
class LazyMCPServer {
|
|
9
|
+
constructor(originalMcpServer) {
|
|
10
|
+
this.proxy = new proxy_js_1.LazyMCPProxyImpl(originalMcpServer);
|
|
11
|
+
this.server = new index_js_1.Server({
|
|
12
|
+
name: 'lazy-mcp-proxy',
|
|
13
|
+
version: '1.0.0',
|
|
14
|
+
}, {
|
|
15
|
+
capabilities: {
|
|
16
|
+
tools: {},
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
this.setupHandlers();
|
|
20
|
+
}
|
|
21
|
+
setupHandlers() {
|
|
22
|
+
this.server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => {
|
|
23
|
+
return {
|
|
24
|
+
tools: [
|
|
25
|
+
{
|
|
26
|
+
name: 'list_commands',
|
|
27
|
+
description: 'List all available commands with brief descriptions',
|
|
28
|
+
inputSchema: {
|
|
29
|
+
type: 'object',
|
|
30
|
+
properties: {},
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
name: 'describe_commands',
|
|
35
|
+
description: 'Get detailed schemas for specified commands',
|
|
36
|
+
inputSchema: {
|
|
37
|
+
type: 'object',
|
|
38
|
+
properties: {
|
|
39
|
+
command_names: {
|
|
40
|
+
type: 'array',
|
|
41
|
+
items: { type: 'string' },
|
|
42
|
+
description: 'Array of command names to describe',
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
required: ['command_names'],
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
name: 'invoke_command',
|
|
50
|
+
description: 'Execute a command with given parameters',
|
|
51
|
+
inputSchema: {
|
|
52
|
+
type: 'object',
|
|
53
|
+
properties: {
|
|
54
|
+
command_name: {
|
|
55
|
+
type: 'string',
|
|
56
|
+
description: 'Name of the command to execute',
|
|
57
|
+
},
|
|
58
|
+
parameters: {
|
|
59
|
+
type: 'object',
|
|
60
|
+
description: 'Parameters to pass to the command',
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
required: ['command_name', 'parameters'],
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
],
|
|
67
|
+
};
|
|
68
|
+
});
|
|
69
|
+
this.server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
|
|
70
|
+
const { name, arguments: args } = request.params;
|
|
71
|
+
try {
|
|
72
|
+
switch (name) {
|
|
73
|
+
case 'list_commands': {
|
|
74
|
+
const commands = await this.proxy.listCommands();
|
|
75
|
+
return {
|
|
76
|
+
content: [
|
|
77
|
+
{
|
|
78
|
+
type: 'text',
|
|
79
|
+
text: JSON.stringify(commands, null, 2),
|
|
80
|
+
},
|
|
81
|
+
],
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
case 'describe_commands': {
|
|
85
|
+
const { command_names } = args;
|
|
86
|
+
if (!Array.isArray(command_names)) {
|
|
87
|
+
throw new Error('command_names must be an array');
|
|
88
|
+
}
|
|
89
|
+
const schemas = await this.proxy.describeCommands(command_names);
|
|
90
|
+
return {
|
|
91
|
+
content: [
|
|
92
|
+
{
|
|
93
|
+
type: 'text',
|
|
94
|
+
text: JSON.stringify(schemas, null, 2),
|
|
95
|
+
},
|
|
96
|
+
],
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
case 'invoke_command': {
|
|
100
|
+
const { command_name, parameters } = args;
|
|
101
|
+
if (typeof command_name !== 'string') {
|
|
102
|
+
throw new Error('command_name must be a string');
|
|
103
|
+
}
|
|
104
|
+
if (typeof parameters !== 'object' || parameters === null) {
|
|
105
|
+
throw new Error('parameters must be an object');
|
|
106
|
+
}
|
|
107
|
+
const result = await this.proxy.invokeCommand(command_name, parameters);
|
|
108
|
+
return {
|
|
109
|
+
content: [
|
|
110
|
+
{
|
|
111
|
+
type: 'text',
|
|
112
|
+
text: JSON.stringify(result, null, 2),
|
|
113
|
+
},
|
|
114
|
+
],
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
default:
|
|
118
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
catch (error) {
|
|
122
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
123
|
+
return {
|
|
124
|
+
content: [
|
|
125
|
+
{
|
|
126
|
+
type: 'text',
|
|
127
|
+
text: `Error: ${errorMessage}`,
|
|
128
|
+
},
|
|
129
|
+
],
|
|
130
|
+
isError: true,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
async run() {
|
|
136
|
+
const transport = new stdio_js_1.StdioServerTransport();
|
|
137
|
+
await this.server.connect(transport);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
exports.LazyMCPServer = LazyMCPServer;
|
|
141
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export interface CommandInfo {
|
|
2
|
+
name: string;
|
|
3
|
+
description: string;
|
|
4
|
+
}
|
|
5
|
+
export interface CommandSchema {
|
|
6
|
+
name: string;
|
|
7
|
+
description: string;
|
|
8
|
+
inputSchema: {
|
|
9
|
+
type: string;
|
|
10
|
+
properties: Record<string, any>;
|
|
11
|
+
required?: string[];
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
export interface MCPTool {
|
|
15
|
+
name: string;
|
|
16
|
+
description: string;
|
|
17
|
+
inputSchema: {
|
|
18
|
+
type: string;
|
|
19
|
+
properties: Record<string, any>;
|
|
20
|
+
required?: string[];
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
export interface MCPServer {
|
|
24
|
+
listTools(): Promise<{
|
|
25
|
+
tools: MCPTool[];
|
|
26
|
+
}>;
|
|
27
|
+
callTool(name: string, arguments_: Record<string, any>): Promise<{
|
|
28
|
+
content: any[];
|
|
29
|
+
}>;
|
|
30
|
+
}
|
|
31
|
+
export interface LazyMCPProxy {
|
|
32
|
+
listCommands(): Promise<CommandInfo[]>;
|
|
33
|
+
describeCommands(commandNames: string[]): Promise<CommandSchema[]>;
|
|
34
|
+
invokeCommand(commandName: string, parameters: Record<string, any>): Promise<any>;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE;QACX,IAAI,EAAE,MAAM,CAAC;QACb,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAChC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;KACrB,CAAC;CACH;AAED,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE;QACX,IAAI,EAAE,MAAM,CAAC;QACb,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAChC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;KACrB,CAAC;CACH;AAED,MAAM,WAAW,SAAS;IACxB,SAAS,IAAI,OAAO,CAAC;QAAE,KAAK,EAAE,OAAO,EAAE,CAAA;KAAE,CAAC,CAAC;IAC3C,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,GAAG,EAAE,CAAA;KAAE,CAAC,CAAC;CACtF;AAED,MAAM,WAAW,YAAY;IAC3B,YAAY,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IACvC,gBAAgB,CAAC,YAAY,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC,CAAC;IACnE,aAAa,CAAC,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;CACnF"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "lazy-mcp",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A proxy tool that converts normal MCP servers to use lazy-loading pattern with three core tools",
|
|
5
|
+
"main": "dist/server.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"lazy-mcp": "dist/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist/**/*",
|
|
11
|
+
"README.md"
|
|
12
|
+
],
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "git+https://gitlab.com/gitlab-org/search-team/experiments/lazy-mcp.git"
|
|
16
|
+
},
|
|
17
|
+
"homepage": "https://gitlab.com/gitlab-org/search-team/experiments/lazy-mcp#readme",
|
|
18
|
+
"bugs": {
|
|
19
|
+
"url": "https://gitlab.com/gitlab-org/search-team/experiments/lazy-mcp/-/issues"
|
|
20
|
+
},
|
|
21
|
+
"scripts": {
|
|
22
|
+
"build": "tsc",
|
|
23
|
+
"start": "node dist/cli.js",
|
|
24
|
+
"dev": "ts-node src/cli.ts"
|
|
25
|
+
},
|
|
26
|
+
"keywords": [
|
|
27
|
+
"mcp",
|
|
28
|
+
"model-context-protocol",
|
|
29
|
+
"proxy",
|
|
30
|
+
"lazy-loading"
|
|
31
|
+
],
|
|
32
|
+
"author": "",
|
|
33
|
+
"license": "MIT",
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"@types/node": "^20.0.0",
|
|
36
|
+
"typescript": "^5.0.0",
|
|
37
|
+
"ts-node": "^10.9.0"
|
|
38
|
+
},
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"@modelcontextprotocol/sdk": "^1.0.0"
|
|
41
|
+
}
|
|
42
|
+
}
|