feat: MCP Server运行成功—stdio传输+7个Tool+Zod schema
- StdioServerTransport(stdin/stdout标准MCP协议) - Zod schema注册(file_list/read/write/move/exec/process_list/sysinfo) - pnpm install完成+SDK依赖解析 - 添加zod依赖
This commit is contained in:
@@ -1,84 +1,34 @@
|
||||
/**
|
||||
* C-001: MCP Server Framework
|
||||
*
|
||||
* Bootstrap the MCP server with SSE transport using @modelcontextprotocol/sdk.
|
||||
* Registers all 36 tools from @yuzu-gca/shared and exposes lifecycle hooks.
|
||||
* C-001: MCP Server Framework — stdio transport for Gateway compatibility.
|
||||
*/
|
||||
|
||||
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||
import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
|
||||
import { ALL_TOOL_DEFS, type ToolDef, type DeviceConfig } from "@yuzu-gca/shared";
|
||||
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
||||
import { z } from "zod";
|
||||
import * as tools from "./tools.js";
|
||||
|
||||
export interface ServerOptions {
|
||||
config: DeviceConfig;
|
||||
toolHandlers: Map<string, (args: any) => Promise<any>>;
|
||||
}
|
||||
export function createServer(): McpServer {
|
||||
const server = new McpServer({ name: "yuzu-gca-device", version: "0.1.0" });
|
||||
|
||||
/**
|
||||
* Creates and returns an MCP Server instance with all tools registered.
|
||||
* Call `server.connect(transport)` to start handling requests.
|
||||
*/
|
||||
export function createServer(opts: ServerOptions): McpServer {
|
||||
const server = new McpServer({
|
||||
name: "yuzu-gca-device",
|
||||
version: opts.config.identity.id,
|
||||
});
|
||||
|
||||
// Register every tool from the shared type definitions
|
||||
for (const toolDef of ALL_TOOL_DEFS) {
|
||||
const handler = opts.toolHandlers.get(toolDef.name);
|
||||
if (handler) {
|
||||
server.tool(
|
||||
toolDef.name,
|
||||
toolDef.description,
|
||||
toolDef.inputSchema.properties,
|
||||
async (args: any) => {
|
||||
const result = await handler(args);
|
||||
return {
|
||||
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
||||
};
|
||||
},
|
||||
);
|
||||
} else {
|
||||
// Register placeholder for unimplemented tools
|
||||
server.tool(
|
||||
toolDef.name,
|
||||
toolDef.description,
|
||||
{ ...toolDef.inputSchema.properties, _required: toolDef.inputSchema.required },
|
||||
async (args: any) => {
|
||||
content: [{ type: "text", text: JSON.stringify({ error: "Tool not yet implemented", tool: toolDef.name }) }],
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
server.tool("file_list", "List directory contents", { path: z.string(), recursive: z.boolean().optional() }, async a => ({ content: [{ type: "text" as const, text: JSON.stringify(await tools.file_list(a)) }] }));
|
||||
server.tool("file_read", "Read file content", { path: z.string(), encoding: z.string().optional(), offset: z.number().optional(), limit: z.number().optional() }, async a => ({ content: [{ type: "text" as const, text: (await tools.file_read(a)).content }] }));
|
||||
server.tool("file_write", "Write file content", { path: z.string(), content: z.string(), encoding: z.string().optional() }, async a => ({ content: [{ type: "text" as const, text: JSON.stringify(await tools.file_write(a)) }] }));
|
||||
server.tool("file_move", "Move/rename file", { from: z.string(), to: z.string() }, async a => ({ content: [{ type: "text" as const, text: JSON.stringify(await tools.file_move(a)) }] }));
|
||||
server.tool("exec", "Execute shell command", { command: z.string(), cwd: z.string().optional(), timeout: z.number().optional() }, async a => ({ content: [{ type: "text" as const, text: JSON.stringify(await tools.exec(a)) }] }));
|
||||
server.tool("process_list","List running processes", { filter: z.string().optional() }, async a => ({ content: [{ type: "text" as const, text: JSON.stringify(await tools.process_list(a)) }] }));
|
||||
server.tool("sysinfo", "System resource usage", {}, async () => ({ content: [{ type: "text" as const, text: JSON.stringify(await tools.sysinfo({})) }] }));
|
||||
|
||||
return server;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the server with SSE transport on a given port.
|
||||
*/
|
||||
export async function startServer(
|
||||
server: McpServer,
|
||||
port: number = 3001,
|
||||
): Promise<void> {
|
||||
const transport = new SSEServerTransport({
|
||||
port,
|
||||
endpoint: "/sse",
|
||||
});
|
||||
|
||||
export async function startServer(server: McpServer): Promise<void> {
|
||||
const transport = new StdioServerTransport();
|
||||
await server.connect(transport);
|
||||
console.log(`[Yuzu-GCA] MCP Server listening on :${port}/sse`);
|
||||
console.error("[Yuzu-GCA] MCP Server ready (stdio)");
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience — create + start in one call.
|
||||
*/
|
||||
export async function bootstrap(
|
||||
opts: ServerOptions,
|
||||
port?: number,
|
||||
): Promise<McpServer> {
|
||||
const server = createServer(opts);
|
||||
await startServer(server, port);
|
||||
export async function bootstrap(): Promise<McpServer> {
|
||||
const server = createServer();
|
||||
await startServer(server);
|
||||
return server;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user