@cgaspard/webappmcp
Version:
WebApp MCP - Model Context Protocol integration for web applications with server-side debugging tools
149 lines • 5.42 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.IntegratedMCPServer = void 0;
const index_js_1 = require("@modelcontextprotocol/sdk/server/index.js");
const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
const ws_1 = require("ws");
const index_js_2 = require("./tools/index.js");
class IntegratedMCPServer {
constructor(config) {
this.ws = null;
this.isConnected = false;
this.wsUrl = config.wsUrl;
this.authToken = config.authToken;
this.server = new index_js_1.Server({
name: 'webapp-mcp',
version: '0.1.0',
}, {
capabilities: {
tools: {},
},
});
this.setupHandlers();
}
setupHandlers() {
this.server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => {
return {
tools: (0, index_js_2.registerTools)(),
};
});
this.server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
if (!this.isConnected) {
throw new Error('Not connected to web application');
}
try {
const result = await this.executeToolOnClient(name, args);
return result;
}
catch (error) {
return {
content: [
{
type: 'text',
text: `Error executing tool: ${error instanceof Error ? error.message : 'Unknown error'}`,
},
],
};
}
});
}
async connectWebSocket() {
return new Promise((resolve, reject) => {
const headers = {};
if (this.authToken) {
headers['Authorization'] = `Bearer ${this.authToken}`;
}
this.ws = new ws_1.WebSocket(this.wsUrl, { headers });
this.ws.on('open', () => {
console.error('Connected to WebApp WebSocket');
this.isConnected = true;
this.ws.send(JSON.stringify({
type: 'init',
url: 'mcp-server',
}));
resolve();
});
this.ws.on('message', (data) => {
const message = JSON.parse(data.toString());
if (message.type === 'connected') {
console.error(`MCP Server registered with clientId: ${message.clientId}`);
}
});
this.ws.on('close', () => {
console.error('Disconnected from WebApp WebSocket');
this.isConnected = false;
this.scheduleReconnect();
});
this.ws.on('error', (error) => {
console.error('WebSocket error:', error);
reject(error);
});
});
}
scheduleReconnect() {
if (this.reconnectTimer)
return;
this.reconnectTimer = setTimeout(async () => {
this.reconnectTimer = null;
try {
await this.connectWebSocket();
}
catch (error) {
console.error('Reconnection failed:', error);
}
}, 5000);
}
async executeToolOnClient(toolName, args) {
return new Promise((resolve, reject) => {
const requestId = Math.random().toString(36).substring(7);
const timeout = setTimeout(() => {
reject(new Error('Tool execution timeout'));
}, 30000);
const messageHandler = (data) => {
const message = JSON.parse(data.toString());
if (message.requestId === requestId) {
clearTimeout(timeout);
this.ws.off('message', messageHandler);
if (message.error) {
reject(new Error(message.error));
}
else {
resolve({
content: [
{
type: 'text',
text: JSON.stringify(message.result, null, 2),
},
],
});
}
}
};
this.ws.on('message', messageHandler);
this.ws.send(JSON.stringify({
type: 'execute_tool',
requestId,
tool: toolName,
args,
}));
});
}
async start() {
try {
// Connect to WebSocket first
await this.connectWebSocket();
// Then start MCP server
const transport = new stdio_js_1.StdioServerTransport();
await this.server.connect(transport);
console.error('Integrated MCP Server started');
}
catch (error) {
console.error('Failed to start MCP server:', error);
process.exit(1);
}
}
}
exports.IntegratedMCPServer = IntegratedMCPServer;
//# sourceMappingURL=mcp-server.js.map