🐺 Initial commit - Lupul Augmentat MCP Server

- MCP server cu stdio transport pentru performanță maximă
- Tool-uri pentru file operations, HTTP requests, system commands
- Suport NATS pentru comunicare inter-module
- Configurare nginx cu API key auth și SSL
- Arhitectură modulară și extensibilă

🤖 Generated with Claude Code
This commit is contained in:
Claude (Lupul Augmentat)
2025-10-09 06:24:58 +02:00
commit 475f89af74
59 changed files with 12827 additions and 0 deletions

View File

@@ -0,0 +1,23 @@
{
"name": "@mcp-server/module-sdk",
"version": "0.1.0",
"description": "TypeScript SDK for MCP Server modules",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
"build": "tsc",
"dev": "tsc --watch"
},
"dependencies": {
"nats": "^2.19.0",
"zod": "^3.22.4",
"pino": "^8.16.2"
},
"devDependencies": {
"@types/node": "^20.10.5",
"typescript": "^5.3.3"
},
"peerDependencies": {
"@mcp-server/types": "workspace:*"
}
}

View File

@@ -0,0 +1,161 @@
import { connect, NatsConnection, JSONCodec } from 'nats';
import { z } from 'zod';
import pino from 'pino';
import { ToolRequest, ToolResponse, ToolDefinition } from './types';
export interface ModuleConfig {
name: string;
natsUrl?: string;
token?: string;
logLevel?: 'debug' | 'info' | 'warn' | 'error';
}
export abstract class ModuleBase {
protected connection?: NatsConnection;
protected jsonCodec = JSONCodec();
protected logger: pino.Logger;
protected tools = new Map<string, ToolDefinition>();
constructor(protected config: ModuleConfig) {
this.logger = pino({
level: config.logLevel || 'info',
name: config.name,
});
}
async start(): Promise<void> {
try {
// Connect to NATS
await this.connectNats();
// Register tools
await this.registerTools();
// Announce tools
await this.announceTools();
// Setup handlers
this.setupHandlers();
// Mark as ready
await this.markReady();
this.logger.info('Module started successfully');
} catch (error) {
this.logger.error({ error }, 'Failed to start module');
throw error;
}
}
async stop(): Promise<void> {
if (this.connection) {
await this.connection.drain();
await this.connection.close();
}
this.logger.info('Module stopped');
}
protected abstract registerTools(): Promise<void>;
protected addTool(tool: ToolDefinition): void {
this.tools.set(tool.name, tool);
this.logger.info({ tool: tool.name }, 'Tool registered');
}
private async connectNats(): Promise<void> {
const url = this.config.natsUrl || process.env.NATS_URL || 'nats://localhost:4222';
const token = this.config.token || process.env.MODULE_TOKEN;
this.connection = await connect({
servers: url,
name: this.config.name,
token,
});
this.logger.info({ url }, 'Connected to NATS');
}
private async announceTools(): Promise<void> {
const tools = Array.from(this.tools.values()).map(tool => ({
name: tool.name,
description: tool.description,
inputSchema: tool.inputSchema,
module: this.config.name,
permissions: [],
}));
this.connection!.publish(
'tools.discovery',
this.jsonCodec.encode({
module: this.config.name,
tools,
}),
);
this.logger.info({ count: tools.length }, 'Tools announced');
}
private setupHandlers(): void {
for (const [name, tool] of this.tools) {
const subject = `tools.${this.config.name}.${name}.execute`;
const sub = this.connection!.subscribe(subject);
(async () => {
for await (const msg of sub) {
try {
const request = this.jsonCodec.decode(msg.data) as ToolRequest;
const startTime = Date.now();
this.logger.debug({ request }, 'Executing tool');
try {
const result = await tool.handler(request.params);
const response: ToolResponse = {
id: request.id,
status: 'success',
data: result,
duration: Date.now() - startTime,
};
msg.respond(this.jsonCodec.encode(response));
} catch (error) {
const response: ToolResponse = {
id: request.id,
status: 'error',
error: {
code: 'EXECUTION_ERROR',
message: error instanceof Error ? error.message : 'Unknown error',
details: error,
},
duration: Date.now() - startTime,
};
msg.respond(this.jsonCodec.encode(response));
}
} catch (error) {
this.logger.error({ error }, 'Failed to process request');
}
}
})().catch(err => this.logger.error({ error: err }, 'Subscription error'));
}
}
private async markReady(): Promise<void> {
// Signal to parent process that module is ready
if (process.send) {
process.send({ type: 'ready' });
}
}
protected createToolHandler<T>(
schema: z.ZodSchema<T>,
handler: (params: T) => Promise<unknown>,
): (params: unknown) => Promise<unknown> {
return async (params: unknown) => {
const validated = schema.parse(params);
return handler(validated);
};
}
}

View File

@@ -0,0 +1,2 @@
export * from './ModuleBase';
export * from './types';

View File

@@ -0,0 +1,36 @@
import { z } from 'zod';
export const ToolRequestSchema = z.object({
id: z.string(),
tool: z.string(),
method: z.enum(['execute', 'describe', 'validate']),
params: z.unknown(),
timeout: z.number(),
metadata: z.object({
user: z.string().optional(),
session: z.string().optional(),
timestamp: z.number(),
}),
});
export const ToolResponseSchema = z.object({
id: z.string(),
status: z.enum(['success', 'error']),
data: z.unknown().optional(),
error: z.object({
code: z.string(),
message: z.string(),
details: z.unknown().optional(),
}).optional(),
duration: z.number(),
});
export type ToolRequest = z.infer<typeof ToolRequestSchema>;
export type ToolResponse = z.infer<typeof ToolResponseSchema>;
export interface ToolDefinition {
name: string;
description: string;
inputSchema: Record<string, unknown>;
handler: (params: unknown) => Promise<unknown>;
}

View File

@@ -0,0 +1,9 @@
{
"extends": "../../../tsconfig.json",
"compilerOptions": {
"outDir": "./dist",
"rootDir": "./src"
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}