chore: initialize qiming workspace repository

This commit is contained in:
Codex
2026-05-29 14:22:48 +08:00
commit bfd67a0f2c
10750 changed files with 1885711 additions and 0 deletions

View File

@@ -0,0 +1,20 @@
/**
* Tool discovery utilities
*/
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import type { Tool } from '@modelcontextprotocol/sdk/types.js';
/**
* Discover all tools from a connected MCP client, handling pagination.
*/
export async function discoverTools(client: Client): Promise<Tool[]> {
const tools: Tool[] = [];
let cursor: string | undefined;
do {
const page = await client.listTools(cursor ? { cursor } : undefined);
tools.push(...page.tools);
cursor = page.nextCursor;
} while (cursor);
return tools;
}

View File

@@ -0,0 +1,13 @@
/**
* Shared helpers — deduplicated logic used across modes
*
* This module re-exports utilities from sub-modules:
* - discovery: Tool discovery from MCP clients
* - proxy-server: Tool proxy server creation
* - shutdown: Graceful shutdown handlers
*/
export { discoverTools } from './discovery.js';
export { createToolProxyServer } from './proxy-server.js';
export type { ToolResolver, ToolProxyServerOptions } from './proxy-server.js';
export { setupGracefulShutdown } from './shutdown.js';

View File

@@ -0,0 +1,80 @@
/**
* Tool proxy server creation
*/
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import {
ListToolsRequestSchema,
CallToolRequestSchema,
} from '@modelcontextprotocol/sdk/types.js';
import type { Tool } from '@modelcontextprotocol/sdk/types.js';
import { logError } from '../logger.js';
import { PKG_NAME, PKG_VERSION } from '../constants.js';
/**
* Callback that resolves a tool name to the client that owns it.
* Returns undefined if the tool is unknown or filtered.
*/
export type ToolResolver = (toolName: string) => Client | undefined;
export interface ToolProxyServerOptions {
/** Tools to expose via ListTools */
tools: Tool[];
/** Resolves a tool name to the upstream client */
resolveClient: ToolResolver;
/** Optional label for error logging (e.g. server name) */
errorLabel?: (toolName: string) => string;
}
/**
* Create a stdio MCP server that proxies tool calls to upstream clients.
*
* Sets up Server with ListTools + CallTool handlers, connects to a
* StdioServerTransport, and returns both for lifecycle management.
*/
export async function createToolProxyServer(
opts: ToolProxyServerOptions,
): Promise<{ server: Server; transport: StdioServerTransport }> {
const { tools, resolveClient, errorLabel } = opts;
const server = new Server(
{ name: PKG_NAME, version: PKG_VERSION },
{ capabilities: { tools: {} } },
);
server.setRequestHandler(ListToolsRequestSchema, async () => {
return { tools };
});
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: toolArgs } = request.params;
const client = resolveClient(name);
if (!client) {
return {
content: [{ type: 'text' as const, text: `Unknown tool: "${name}"` }],
isError: true,
};
}
try {
const result = await client.callTool({ name, arguments: toolArgs });
return result;
} catch (e) {
const label = errorLabel ? errorLabel(name) : `"${name}"`;
logError(`Tool ${label} call failed: ${e}`);
return {
content: [{ type: 'text' as const, text: `Tool call failed: ${e}` }],
isError: true,
};
}
});
const transport = new StdioServerTransport();
await server.connect(transport);
return { server, transport };
}

View File

@@ -0,0 +1,30 @@
/**
* Graceful shutdown utilities
*/
import { logInfo, logError } from '../logger.js';
/**
* Register SIGINT/SIGTERM handlers that run a cleanup function once,
* then exit. Guards against double-invocation.
*/
export function setupGracefulShutdown(cleanupFn: () => Promise<void>): void {
let isShuttingDown = false;
const shutdown = async (signal: string) => {
if (isShuttingDown) return;
isShuttingDown = true;
logInfo(`Received ${signal}, shutting down...`);
try {
await cleanupFn();
} catch (e) {
logError(`Shutdown cleanup error: ${e}`);
}
process.exit(0);
};
process.on('SIGINT', () => void shutdown('SIGINT'));
process.on('SIGTERM', () => void shutdown('SIGTERM'));
}