* 2.24.1 - Updated dependencies - MCP Server: better compatibility with Windows - MCP Server: allow using a custom root for better flexibility - Version Check: use package.json version instead of number of commits - Prettier: reformatted some files - Add SSH_AUTH_SOCK to dev passThroughEnv to solve SSH issues; handle execSync errors - Use GIT_SSH to fix SSH issues on Windows - Updated Stripe version - Updated application version from 2.24.0 to 2.24.1 in package.json. - Enhanced error handling in billing services to include error causes for better debugging.
140 lines
3.2 KiB
TypeScript
140 lines
3.2 KiB
TypeScript
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
import { access, readFile, stat } from 'node:fs/promises';
|
|
import { Socket } from 'node:net';
|
|
import { join } from 'node:path';
|
|
|
|
import { execFileAsync } from '../../lib/process-utils';
|
|
import {
|
|
type KitStatusDeps,
|
|
createKitStatusService,
|
|
} from './kit-status.service';
|
|
import { KitStatusInputSchema, KitStatusOutputSchema } from './schema';
|
|
|
|
export function registerKitStatusTool(server: McpServer, rootPath?: string) {
|
|
return server.registerTool(
|
|
'kit_status',
|
|
{
|
|
description: 'Project status with variant context',
|
|
inputSchema: KitStatusInputSchema,
|
|
outputSchema: KitStatusOutputSchema,
|
|
},
|
|
async (input) => {
|
|
const parsedInput = KitStatusInputSchema.parse(input);
|
|
|
|
try {
|
|
const service = createKitStatusService(createKitStatusDeps(rootPath));
|
|
const status = await service.getStatus(parsedInput);
|
|
|
|
return {
|
|
structuredContent: status,
|
|
content: [
|
|
{
|
|
type: 'text',
|
|
text: JSON.stringify(status),
|
|
},
|
|
],
|
|
};
|
|
} catch (error) {
|
|
const message = toErrorMessage(error);
|
|
|
|
return {
|
|
isError: true,
|
|
content: [
|
|
{
|
|
type: 'text',
|
|
text: `kit_status failed: ${message}`,
|
|
},
|
|
],
|
|
};
|
|
}
|
|
},
|
|
);
|
|
}
|
|
|
|
function createKitStatusDeps(rootPath = process.cwd()): KitStatusDeps {
|
|
return {
|
|
rootPath,
|
|
async readJsonFile(path: string): Promise<unknown> {
|
|
const filePath = join(rootPath, path);
|
|
const content = await readFile(filePath, 'utf8');
|
|
return JSON.parse(content) as unknown;
|
|
},
|
|
async pathExists(path: string) {
|
|
const fullPath = join(rootPath, path);
|
|
|
|
try {
|
|
await access(fullPath);
|
|
return true;
|
|
} catch {
|
|
return false;
|
|
}
|
|
},
|
|
async isDirectory(path: string) {
|
|
const fullPath = join(rootPath, path);
|
|
|
|
try {
|
|
const stats = await stat(fullPath);
|
|
return stats.isDirectory();
|
|
} catch {
|
|
return false;
|
|
}
|
|
},
|
|
async executeCommand(command: string, args: string[]) {
|
|
const result = await execFileAsync(command, args, {
|
|
cwd: rootPath,
|
|
});
|
|
|
|
return {
|
|
stdout: result.stdout,
|
|
stderr: result.stderr,
|
|
exitCode: 0,
|
|
};
|
|
},
|
|
async isPortOpen(port: number) {
|
|
return checkPort(port);
|
|
},
|
|
getNodeVersion() {
|
|
return process.version;
|
|
},
|
|
};
|
|
}
|
|
|
|
async function checkPort(port: number) {
|
|
return new Promise<boolean>((resolve) => {
|
|
const socket = new Socket();
|
|
|
|
socket.setTimeout(200);
|
|
|
|
socket.once('connect', () => {
|
|
socket.destroy();
|
|
resolve(true);
|
|
});
|
|
|
|
socket.once('timeout', () => {
|
|
socket.destroy();
|
|
resolve(false);
|
|
});
|
|
|
|
socket.once('error', () => {
|
|
socket.destroy();
|
|
resolve(false);
|
|
});
|
|
|
|
socket.connect(port, '127.0.0.1');
|
|
});
|
|
}
|
|
|
|
function toErrorMessage(error: unknown) {
|
|
if (error instanceof Error) {
|
|
return error.message;
|
|
}
|
|
|
|
return 'Unknown error';
|
|
}
|
|
|
|
export {
|
|
createKitStatusService,
|
|
type KitStatusDeps,
|
|
} from './kit-status.service';
|
|
export type { KitStatusOutput } from './schema';
|