Files
Lupul-Augmentat/docs/api-reference.md
Claude (Lupul Augmentat) 475f89af74 🐺 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
2025-10-09 06:24:58 +02:00

443 lines
10 KiB
Markdown

# MCP Server API Reference
## Tool Handler Base Class
All tools extend the `ToolHandler` abstract class which provides lifecycle management, validation, and error handling.
### Class Definition
```typescript
abstract class ToolHandler<TInput = any, TOutput = any> {
constructor(
config: ToolConfig,
inputSchema: z.ZodSchema<TInput>,
outputSchema: z.ZodSchema<TOutput>
);
// Main execution method
async execute(input: unknown, context: ToolContext): Promise<TOutput>;
// Lifecycle hooks (override in subclass)
protected async initialize(): Promise<void>;
protected async validate(input: TInput): Promise<TInput>;
protected abstract handle(input: TInput, context: ToolContext): Promise<TOutput>;
protected async cleanup(): Promise<void>;
protected async checkPermissions(context: ToolContext): Promise<void>;
}
```
### Tool Configuration
```typescript
interface ToolConfig {
name: string; // Unique tool identifier
description: string; // Human-readable description
timeout?: number; // Execution timeout in ms (default: 30000)
permissions?: string[]; // Required permissions
}
```
### Tool Context
```typescript
interface ToolContext {
requestId: string; // Unique request identifier
permissions: string[]; // Granted permissions
userId?: string; // Optional user identifier
metadata?: Record<string, any>; // Additional context
}
```
## Creating a Custom Tool
### Basic Example
```typescript
import { z } from 'zod';
import { ToolHandler, ToolContext } from '@mcp/tools';
// Define schemas
const InputSchema = z.object({
message: z.string(),
uppercase: z.boolean().optional(),
});
const OutputSchema = z.object({
result: z.string(),
length: z.number(),
});
type Input = z.infer<typeof InputSchema>;
type Output = z.infer<typeof OutputSchema>;
// Implement tool
export class EchoTool extends ToolHandler<Input, Output> {
constructor() {
super(
{
name: 'echo',
description: 'Echo a message with transformations',
timeout: 5000,
},
InputSchema,
OutputSchema
);
}
protected async handle(input: Input, context: ToolContext): Promise<Output> {
let result = input.message;
if (input.uppercase) {
result = result.toUpperCase();
}
this.logger.info({ message: result }, 'Echoing message');
return {
result,
length: result.length,
};
}
}
```
### Advanced Example with Permissions
```typescript
export class DatabaseQueryTool extends ToolHandler<QueryInput, QueryOutput> {
private db: Database;
constructor() {
super(
{
name: 'db_query',
description: 'Execute database queries',
timeout: 60000,
permissions: ['database:read', 'database:write'],
},
QueryInputSchema,
QueryOutputSchema
);
}
protected async initialize(): Promise<void> {
// Connect to database
this.db = await Database.connect(process.env.DATABASE_URL);
}
protected async checkPermissions(context: ToolContext): Promise<void> {
const isWrite = this.isWriteQuery(this.currentInput.query);
if (isWrite && !context.permissions.includes('database:write')) {
throw new Error('Permission denied: database:write required');
}
if (!context.permissions.includes('database:read')) {
throw new Error('Permission denied: database:read required');
}
}
protected async validate(input: QueryInput): Promise<QueryInput> {
// Additional validation beyond schema
if (this.containsSqlInjection(input.query)) {
throw new Error('Invalid query: potential SQL injection');
}
return input;
}
protected async handle(input: QueryInput, context: ToolContext): Promise<QueryOutput> {
const startTime = Date.now();
try {
const results = await this.db.query(input.query, input.params);
return {
rows: results.rows,
rowCount: results.rowCount,
duration: Date.now() - startTime,
};
} catch (error) {
this.logger.error({ error, query: input.query }, 'Query failed');
throw new Error(`Database query failed: ${error.message}`);
}
}
protected async cleanup(): Promise<void> {
// Close database connection
if (this.db) {
await this.db.close();
}
}
}
```
## Tool Registration
### Registering Built-in Tools
```typescript
import { ToolRegistry } from '@mcp/registry';
import { FileReadTool, FileWriteTool } from './tools';
const registry = new ToolRegistry(natsClient);
// Built-in tools are registered automatically
// But you can also register manually
registry.registerBuiltinTool('file_read', new FileReadTool());
registry.registerBuiltinTool('file_write', new FileWriteTool());
```
### Registering External Module Tools
```typescript
// External tools are discovered via NATS
// Modules announce their tools on startup
natsClient.publish('tools.discovery', {
module: 'my-module',
tools: [
{
name: 'my_tool',
description: 'Custom tool from module',
inputSchema: { /* ... */ },
permissions: ['custom:permission'],
}
]
});
```
## Error Handling
### Error Types
```typescript
// Base error class
export class ToolError extends Error {
constructor(
message: string,
public code: string,
public details?: any
) {
super(message);
this.name = 'ToolError';
}
}
// Specific error types
export class ValidationError extends ToolError {
constructor(message: string, details?: any) {
super(message, 'VALIDATION_ERROR', details);
}
}
export class PermissionError extends ToolError {
constructor(message: string, required: string[]) {
super(message, 'PERMISSION_ERROR', { required });
}
}
export class TimeoutError extends ToolError {
constructor(timeout: number) {
super(`Operation timed out after ${timeout}ms`, 'TIMEOUT_ERROR');
}
}
```
### Error Handling in Tools
```typescript
protected async handle(input: Input, context: ToolContext): Promise<Output> {
try {
// Tool logic
} catch (error) {
if (error.code === 'ENOENT') {
throw new ToolError('File not found', 'FILE_NOT_FOUND', { path: input.path });
}
// Re-throw unknown errors
throw error;
}
}
```
## Testing Tools
### Unit Testing
```typescript
import { MyTool } from './MyTool';
import { ToolContext } from '@mcp/tools';
describe('MyTool', () => {
let tool: MyTool;
beforeEach(() => {
tool = new MyTool();
});
const createContext = (permissions: string[] = []): ToolContext => ({
requestId: 'test-request',
permissions,
});
it('should execute successfully', async () => {
const result = await tool.execute(
{ input: 'test' },
createContext(['required:permission'])
);
expect(result).toEqual({ output: 'expected' });
});
it('should require permissions', async () => {
await expect(
tool.execute({ input: 'test' }, createContext())
).rejects.toThrow('Permission denied');
});
});
```
### Integration Testing
```typescript
import { ToolRegistry } from '@mcp/registry';
import { NatsClient } from '@mcp/nats';
describe('Tool Integration', () => {
let registry: ToolRegistry;
let nats: NatsClient;
beforeAll(async () => {
nats = new NatsClient();
await nats.connect();
registry = new ToolRegistry(nats);
});
afterAll(async () => {
await nats.close();
});
it('should execute tool via registry', async () => {
const result = await registry.executeTool(
'my_tool',
{ input: 'test' }
);
expect(result).toBeDefined();
});
});
```
## Performance Considerations
### Timeout Management
```typescript
protected async handle(input: Input, context: ToolContext): Promise<Output> {
// Use AbortController for cancellable operations
const controller = new AbortController();
const timeoutId = setTimeout(
() => controller.abort(),
this.config.timeout || 30000
);
try {
const result = await fetch(input.url, {
signal: controller.signal,
});
return processResult(result);
} finally {
clearTimeout(timeoutId);
}
}
```
### Resource Management
```typescript
export class ResourceIntensiveTool extends ToolHandler {
private pool: ResourcePool;
protected async initialize(): Promise<void> {
// Initialize resource pool
this.pool = new ResourcePool({ max: 10 });
}
protected async handle(input: Input, context: ToolContext): Promise<Output> {
// Acquire resource from pool
const resource = await this.pool.acquire();
try {
return await this.processWithResource(resource, input);
} finally {
// Always release resource
this.pool.release(resource);
}
}
protected async cleanup(): Promise<void> {
// Drain pool on cleanup
await this.pool.drain();
}
}
```
## Security Best Practices
1. **Always validate input** - Use Zod schemas and additional validation
2. **Check permissions** - Implement checkPermissions for sensitive operations
3. **Sanitize paths** - Prevent directory traversal attacks
4. **Limit resource usage** - Implement timeouts and size limits
5. **Log security events** - Track permission denials and suspicious activity
6. **Use prepared statements** - Prevent SQL injection in database tools
7. **Validate URLs** - Block internal/private IP ranges in HTTP tools
## Debugging Tools
### Logging
```typescript
protected async handle(input: Input, context: ToolContext): Promise<Output> {
this.logger.debug({ input }, 'Processing request');
try {
const result = await this.process(input);
this.logger.info({ result }, 'Request successful');
return result;
} catch (error) {
this.logger.error({ error, input }, 'Request failed');
throw error;
}
}
```
### Metrics
```typescript
protected async handle(input: Input, context: ToolContext): Promise<Output> {
const timer = this.metrics.startTimer('tool_execution_duration', {
tool: this.config.name,
});
try {
const result = await this.process(input);
this.metrics.increment('tool_execution_success', {
tool: this.config.name,
});
return result;
} catch (error) {
this.metrics.increment('tool_execution_error', {
tool: this.config.name,
error: error.code,
});
throw error;
} finally {
timer.end();
}
}
```