Backend (Spring Boot 3.2 / Java 21 / PostgreSQL): - JWT auth with BCrypt password hashing - User profile + Mifflin-St Jeor BMR calculator - Food search + barcode via OpenFoodFacts API with local cache - Meal CRUD with user data isolation and ownership checks - AI photo analysis (OpenAI Vision) with confidence intervals - AI correction feedback loop for personalisation - Flyway DB migrations + RFC-7807 error responses Mobile (React Native / TypeScript): - Full navigation stack (Auth → Tabs → Home stack) - Design tokens (WCAG 2.2 AA colours, 8px grid, 48px touch targets) - 10 screens: Login, Register, Home, Search, Camera, AI Result, Edit Meal, Daily Details, History, Profile - Confidence-aware calorie display (kcal ± range) - Repeat last meal shortcut + macro tracking Docs: - docs/PLAN-AND-REQUIREMENTS.md - docs/traceability.csv (35 requirements, all Implemented)
625 lines
14 KiB
Markdown
625 lines
14 KiB
Markdown
All MCP tools use stdio transport. Every tool validates input with Zod before processing.
|
|
|
|
# MCP Standards - Layer 2
|
|
|
|
**Module**: MCP Standards
|
|
**Component**: Layer 2 (Model Context Protocol Server)
|
|
**Load**: When working on virsaitis-development/virsaitis-mcp/
|
|
**Version**: 3.0.0
|
|
**Updated**: 2026-04-20
|
|
|
|
---
|
|
|
|
## 🎯 Purpose
|
|
|
|
Defines TypeScript standards, MCP SDK usage, and development workflow for Virsaitis MCP Server (Layer 2 governance enforcement).
|
|
|
|
---
|
|
|
|
## 🤖 Machine Policy
|
|
|
|
```
|
|
[TECHNOLOGY_STACK]
|
|
LANGUAGE=TypeScript 5.0+
|
|
RUNTIME=Node.js 18+
|
|
FRAMEWORK=@modelcontextprotocol/sdk
|
|
BUILD=tsc + esbuild
|
|
TEST=vitest
|
|
LINT=eslint + prettier
|
|
|
|
[CODE_STANDARDS]
|
|
INDENTATION=2_spaces
|
|
LINE_LENGTH=100_chars
|
|
QUOTES=single
|
|
SEMICOLONS=required
|
|
TRAILING_COMMAS=required_multiline
|
|
|
|
[QUALITY_GATES]
|
|
BUILD=must_succeed
|
|
TESTS=must_pass
|
|
LINT=zero_errors
|
|
TYPE_CHECK=strict_mode
|
|
COVERAGE=70_percent_min
|
|
```
|
|
|
|
---
|
|
|
|
## 📐 TypeScript Standards (TIER-1)
|
|
|
|
### Indentation & Formatting
|
|
|
|
**REQUIRED**:
|
|
- **Indentation**: 2 spaces (not 4, not tabs)
|
|
- **Line length**: 100 characters maximum
|
|
- **Quotes**: Single quotes `'string'` for strings
|
|
- **Semicolons**: Required at end of statements
|
|
- **Trailing commas**: Required for multiline arrays/objects
|
|
|
|
✅ **GOOD**:
|
|
```typescript
|
|
const config = {
|
|
server: 'virsaitis-mcp',
|
|
port: 3000,
|
|
enabled: true,
|
|
};
|
|
```
|
|
|
|
❌ **BAD**:
|
|
```typescript
|
|
const config = {
|
|
server: "virsaitis-mcp",
|
|
port: 3000,
|
|
enabled: true
|
|
} // Missing trailing comma, 4 spaces, double quotes
|
|
```
|
|
|
|
### File Organization
|
|
|
|
**STANDARD ORDER**:
|
|
```typescript
|
|
// 1. External imports (Node.js, npm packages)
|
|
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
import * as fs from 'fs';
|
|
|
|
// 2. Internal imports (project files)
|
|
import { GovernanceValidator } from './governance/validator.js';
|
|
import { PolicyEngine } from './policy/engine.js';
|
|
|
|
// 3. Type definitions
|
|
interface ValidationResult {
|
|
allowed: boolean;
|
|
reason?: string;
|
|
}
|
|
|
|
// 4. Constants
|
|
const PROTECTED_PATTERNS = [
|
|
'.github/copilot-instructions.md',
|
|
'requirements/**',
|
|
];
|
|
|
|
// 5. Class/function implementations
|
|
export class VirsaitisMCPServer {
|
|
// Implementation
|
|
}
|
|
```
|
|
|
|
### Naming Conventions (TIER-1)
|
|
|
|
| Element | Convention | Example |
|
|
|---------|------------|---------|
|
|
| **Classes** | PascalCase | `GovernancePolicyValidator` |
|
|
| **Interfaces** | PascalCase | `PolicyResult` or `IPolicyResult` |
|
|
| **Types** | PascalCase | `OperationType` |
|
|
| **Functions** | camelCase | `validateFileOperation` |
|
|
| **Methods** | camelCase | `checkPermissions` |
|
|
| **Variables** | camelCase | `isValid`, `fileName` |
|
|
| **Constants** | UPPER_SNAKE_CASE | `MAX_RETRIES`, `PROTECTED_PATTERNS` |
|
|
| **Private members** | Leading underscore | `_config`, `_cache` |
|
|
| **Enums**| PascalCase | `TierLevel` |
|
|
| **Enum values** | PascalCase | `TierLevel.Critical` |
|
|
|
|
---
|
|
|
|
## 🔧 MCP Server Architecture
|
|
|
|
### Server Structure
|
|
|
|
```
|
|
virsaitis-development/virsaitis-mcp/
|
|
├── src/
|
|
│ ├── index.ts (server entry point)
|
|
│ ├── server.ts (MCP server class)
|
|
│ ├── governance/
|
|
│ │ ├── types.ts (TierLevel, GovernanceRule, ValidationResult)
|
|
│ │ ├── patterns.ts (glob pattern matching)
|
|
│ │ ├── cache.ts (in-memory governance cache)
|
|
│ │ ├── loader.ts (parse core-policies.md + agent files)
|
|
│ │ └── validator.ts (GovernanceValidator - TIER validation)
|
|
│ ├── config.ts (server configuration - REQ-MCP-010)
|
|
│ ├── tools/
|
|
│ │ ├── scan-secrets.ts (mcp_virsaitis_scan_secrets)
|
|
│ │ ├── validate-path.ts (mcp_virsaitis_validate_path)
|
|
│ │ ├── validate-command.ts (mcp_virsaitis_validate_command)
|
|
│ │ ├── audit-logger.ts (mcp_virsaitis_read_audit_log)
|
|
│ │ └── iteration-complete.ts (mcp_virsaitis_iteration_complete)
|
|
├── tests/
|
|
│ ├── unit/
|
|
│ ├── integration/
|
|
│ └── fixtures/
|
|
├── build/ (compiled output)
|
|
├── package.json
|
|
├── tsconfig.json
|
|
├── vitest.config.ts
|
|
└── README.md
|
|
```
|
|
|
|
### MCP Tools Implementation
|
|
|
|
**TOOL PATTERN**:
|
|
```typescript
|
|
// Tool definition
|
|
server.setRequestHandler(ToolsListRequestSchema, async () => {
|
|
return {
|
|
tools: [
|
|
{
|
|
name: 'mcp_virsaitis_validate_operation',
|
|
description: 'Validates if an operation is allowed by governance policy',
|
|
inputSchema: {
|
|
type: 'object',
|
|
properties: {
|
|
operation: {
|
|
type: 'string',
|
|
description: 'Operation type: read, write, delete, execute',
|
|
},
|
|
filePath: {
|
|
type: 'string',
|
|
description: 'Absolute file path',
|
|
},
|
|
},
|
|
required: ['operation', 'filePath'],
|
|
},
|
|
},
|
|
],
|
|
};
|
|
});
|
|
|
|
// Tool execution
|
|
server.setRequestHandler(ToolCallRequestSchema, async (request) => {
|
|
if (request.params.name === 'mcp_virsaitis_validate_operation') {
|
|
const { operation, filePath } = request.params.arguments;
|
|
|
|
// Validation logic
|
|
const result = await governanceValidator.validate(operation, filePath);
|
|
|
|
return {
|
|
content: [
|
|
{
|
|
type: 'text',
|
|
text: JSON.stringify(result, null, 2),
|
|
},
|
|
],
|
|
};
|
|
}
|
|
});
|
|
```
|
|
|
|
---
|
|
|
|
> ⚡ CHECKPOINT — Is this MCP tool using Zod input validation? Every tool parameter must have a schema.
|
|
|
|
## ✅ Type Safety (TIER-1)
|
|
|
|
### TypeScript Configuration
|
|
|
|
**tsconfig.json REQUIREMENTS**:
|
|
```json
|
|
{
|
|
"compilerOptions": {
|
|
"target": "ES2022",
|
|
"module": "ES2022",
|
|
"moduleResolution": "node",
|
|
"strict": true,
|
|
"esModuleInterop": true,
|
|
"skipLibCheck": false,
|
|
"forceConsistentCasingInFileNames": true,
|
|
"declaration": true,
|
|
"declarationMap": true,
|
|
"sourceMap": true,
|
|
"outDir": "./build",
|
|
"rootDir": "./src"
|
|
}
|
|
}
|
|
```
|
|
|
|
**STRICT MODE REQUIRED**:
|
|
- `strict: true` (enables all strict checks)
|
|
- `noImplicitAny: true` (no implicit any types)
|
|
- `strictNullChecks: true` (null/undefined handling)
|
|
- `strictFunctionTypes: true` (function type checking)
|
|
- `strictPropertyInitialization: true` (class property init)
|
|
|
|
### Explicit Type Annotations
|
|
|
|
**REQUIRED FOR**:
|
|
- Public function return types
|
|
- Public method return types
|
|
- Exported interfaces/types
|
|
- Complex function parameters
|
|
|
|
✅ **GOOD**:
|
|
```typescript
|
|
export function validateTier(tier: string): boolean {
|
|
return ['TIER-0', 'TIER-1', 'TIER-2', 'TIER-3'].includes(tier);
|
|
}
|
|
|
|
export interface PolicyResult {
|
|
allowed: boolean;
|
|
tier: string;
|
|
reason?: string;
|
|
consequences?: Consequence[];
|
|
}
|
|
```
|
|
|
|
❌ **BAD**:
|
|
```typescript
|
|
export function validateTier(tier) { // Missing parameter type
|
|
return ['TIER-0', 'TIER-1', 'TIER-2', 'TIER-3'].includes(tier);
|
|
} // Missing return type
|
|
|
|
export interface PolicyResult {
|
|
allowed; // Missing type
|
|
tier; // Missing type
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 🧪 Testing Standards (TIER-1)
|
|
|
|
### Test Framework
|
|
|
|
**USING**: Vitest (fast, TypeScript-native)
|
|
|
|
**vitest.config.ts**:
|
|
```typescript
|
|
import { defineConfig } from 'vitest/config';
|
|
|
|
export default defineConfig({
|
|
test: {
|
|
coverage: {
|
|
provider: 'v8',
|
|
reporter: ['text', 'html', 'lcov'],
|
|
lines: 70,
|
|
functions: 70,
|
|
branches: 70,
|
|
statements: 70,
|
|
},
|
|
},
|
|
});
|
|
```
|
|
|
|
### Test Structure
|
|
|
|
**PATTERN**:
|
|
```typescript
|
|
import { describe, it, expect, beforeEach } from 'vitest';
|
|
import { GovernanceValidator } from '../src/governance/validator';
|
|
|
|
describe('GovernanceValidator', () => {
|
|
let validator: GovernanceValidator;
|
|
|
|
beforeEach(() => {
|
|
validator = new GovernanceValidator();
|
|
});
|
|
|
|
describe('validateFileOperation', () => {
|
|
it('should block protected file modification', () => {
|
|
// Given
|
|
const operation = 'write';
|
|
const filePath = '.github/copilot-instructions.md';
|
|
|
|
// When
|
|
const result = validator.validateFileOperation(operation, filePath);
|
|
|
|
// Then
|
|
expect(result.allowed).toBe(false);
|
|
expect(result.tier).toBe('TIER-0');
|
|
expect(result.reason).toContain('protected file');
|
|
});
|
|
|
|
it('should allow non-protected file modification', () => {
|
|
// Given
|
|
const operation = 'write';
|
|
const filePath = 'src/my-file.ts';
|
|
|
|
// When
|
|
const result = validator.validateFileOperation(operation, filePath);
|
|
|
|
// Then
|
|
expect(result.allowed).toBe(true);
|
|
});
|
|
});
|
|
});
|
|
```
|
|
|
|
### Test Coverage Requirements
|
|
|
|
**MINIMUM COVERAGE**:
|
|
- Overall: 70%
|
|
- Security-critical code: 100%
|
|
- Governance validation: 100%
|
|
- Consequence evaluation: 100%
|
|
- Tool implementations: 90%
|
|
- Utilities: 70%
|
|
|
|
**MEASURE**:
|
|
```bash
|
|
npm run test:coverage
|
|
```
|
|
|
|
---
|
|
|
|
## 🔒 Security Standards
|
|
|
|
### Input Validation
|
|
|
|
**ALWAYS VALIDATE**:
|
|
```typescript
|
|
function validateFilePath(filePath: string): string {
|
|
// Check for null/undefined
|
|
if (!filePath) {
|
|
throw new Error('File path is required');
|
|
}
|
|
|
|
// Check for path traversal
|
|
if (filePath.includes('..')) {
|
|
throw new Error('Path traversal detected');
|
|
}
|
|
|
|
// Normalize path
|
|
const normalized = path.normalize(filePath);
|
|
|
|
// Ensure absolute path
|
|
if (!path.isAbsolute(normalized)) {
|
|
throw new Error('Absolute path required');
|
|
}
|
|
|
|
return normalized;
|
|
}
|
|
```\n\n> \u26a1 CHECKPOINT \u2014 MCP uses stdio transport only. If you see HTTP fetch or REST endpoints, that code is wrong.\n\n### Error Handling", "oldString": "```\n\n### Error Handling
|
|
- Internal file paths in error messages
|
|
- Sensitive configuration
|
|
- Stack traces to external systems
|
|
- Credentials or secrets
|
|
|
|
✅ **GOOD**:
|
|
```typescript
|
|
try {
|
|
await fs.promises.readFile(filePath);
|
|
} catch (error) {
|
|
// Log full error internally
|
|
logger.error('File read failed', { filePath, error });
|
|
|
|
// Return sanitized error to user
|
|
return {
|
|
success: false,
|
|
message: 'Unable to read file',
|
|
};
|
|
}
|
|
```
|
|
|
|
❌ **BAD**:
|
|
```typescript
|
|
try {
|
|
await fs.promises.readFile(filePath);
|
|
} catch (error) {
|
|
// Exposes internal path
|
|
return {
|
|
success: false,
|
|
message: `Failed to read ${filePath}: ${error.message}`,
|
|
};
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 🔄 Build & Development Workflow
|
|
|
|
### Development Commands
|
|
|
|
```bash
|
|
# Install dependencies
|
|
npm install
|
|
|
|
# Start development with file watching
|
|
npm run dev
|
|
|
|
# Build TypeScript
|
|
npm run build
|
|
|
|
# Run tests
|
|
npm test
|
|
|
|
# Run tests with coverage
|
|
npm run test:coverage
|
|
|
|
# Run linter
|
|
npm run lint
|
|
|
|
# Fix linting issues
|
|
npm run lint:fix
|
|
|
|
# TypeScript type checking
|
|
npm run type-check
|
|
|
|
# Format code
|
|
npm run format
|
|
```
|
|
|
|
### Before Commit Checklist (TIER-1)
|
|
|
|
**ALL MUST PASS**:
|
|
```bash
|
|
npm run build # ✅ Must succeed
|
|
npm test # ✅ Must pass (all tests)
|
|
npm run lint # ✅ Zero errors
|
|
npm run type-check # ✅ No type errors
|
|
npm run test:coverage # ✅ Coverage ≥70%
|
|
```
|
|
|
|
**IF ANY FAIL**: Fix before committing
|
|
|
|
---
|
|
|
|
## 📦 MCP Server Packaging
|
|
|
|
### Build Output
|
|
|
|
**COMPILED TO**: `build/` directory
|
|
|
|
**INCLUDES**:
|
|
- `build/index.js` (entry point)
|
|
- `build/**/*.js` (compiled TypeScript)
|
|
- `build/**/*.d.ts` (type definitions)
|
|
- `build/**/*.js.map` (source maps)
|
|
|
|
### NPM Package
|
|
|
|
**package.json ESSENTIALS**:
|
|
```json
|
|
{
|
|
"name": "@virsaitis/mcp-server",
|
|
"version": "2.0.0",
|
|
"type": "module",
|
|
"main": "./build/index.js",
|
|
"types": "./build/index.d.ts",
|
|
"bin": {
|
|
"virsaitis-mcp": "./build/index.js"
|
|
},
|
|
"engines": {
|
|
|
|
---
|
|
|
|
## Key Rules From This Module
|
|
|
|
- stdio transport only. No HTTP REST endpoints for MCP communication.
|
|
- Every tool input validated with Zod schemas before processing.
|
|
- TypeScript strict mode. No `any` types without documented justification.
|
|
- All dependencies must be in DEPENDENCY-REGISTER.md before use.
|
|
- Definitions: `.github/virsaitis-definition-library.md`
|
|
|
|
Return to hub: `.github/copilot-instructions.md`
|
|
"node": ">=18.0.0"
|
|
},
|
|
"scripts": {
|
|
"build": "tsc && esbuild",
|
|
"test": "vitest run",
|
|
"test:coverage": "vitest run --coverage",
|
|
"lint": "eslint src/",
|
|
"type-check": "tsc --noEmit"
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
> ⚡ CHECKPOINT — All dependencies approved? Check virsaitis-mcp/DEPENDENCY-REGISTER.md before adding packages.
|
|
|
|
## 🔗 Integration with Agent & Extension
|
|
|
|
### Agent → MCP Communication
|
|
|
|
**Agent calls MCP tools**:
|
|
```markdown
|
|
[Agent.md instruction]
|
|
Before editing protected file, call mcp_virsaitis_validate_operation tool.
|
|
Tool returns whether operation allowed.
|
|
If not allowed, respond with TIER-0 VIOLATION PREVENTED.
|
|
```
|
|
|
|
**MCP response format**:
|
|
```typescript
|
|
interface ValidationResponse {
|
|
allowed: boolean;
|
|
tier: 'TIER-0' | 'TIER-1' | 'TIER-2' | 'TIER-3';
|
|
reason?: string;
|
|
consequences?: {
|
|
operation: string;
|
|
userImpact: string;
|
|
technicalImpact: string;
|
|
businessImpact: string;
|
|
remediation: string;
|
|
};
|
|
}
|
|
```
|
|
|
|
### MCP ← Extension Communication
|
|
|
|
**Extension queries MCP**:
|
|
- User tries to edit file
|
|
- Extension calls mcp_virsaitis_validate_operation
|
|
- MCP validates against governance
|
|
- Extension shows 🛡️ shield if protected
|
|
- Extension blocks action if TIER-0
|
|
|
|
---
|
|
|
|
## 💡 Best Practices
|
|
|
|
### Code Organization
|
|
|
|
**ONE CONCERN PER FILE**:
|
|
- Each file handles one specific responsibility
|
|
- Validators in `governance/`
|
|
- Tools in `tools/`
|
|
- Utilities in `utils/`
|
|
|
|
**SMALL FUNCTIONS**:
|
|
- Keep functions <50 lines
|
|
- Single responsibility
|
|
- Testable in isolation
|
|
|
|
**AVOID GOD CLASSES**:
|
|
- Break large classes into smaller components
|
|
- Use composition over inheritance
|
|
- Inject dependencies
|
|
|
|
### Performance
|
|
|
|
**CACHING**:
|
|
```typescript
|
|
class GovernanceCache {
|
|
private _rulesCache: Map<string, Rule[]> = new Map();
|
|
private _cacheExpiry = 5 * 60 * 1000; // 5 minutes
|
|
|
|
async getRules(category: string): Promise<Rule[]> {
|
|
const cached = this._rulesCache.get(category);
|
|
if (cached && !this.isExpired(cached)) {
|
|
return cached;
|
|
}
|
|
|
|
const rules = await this.loadRules(category);
|
|
this._rulesCache.set(category, rules);
|
|
return rules;
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 📚 Quick Reference
|
|
|
|
| Aspect | Standard | Command |
|
|
|--------|----------|---------|
|
|
| **Indentation** | 2 spaces | ESLint enforces |
|
|
| **Build** | `tsc` + `esbuild` | `npm run build` |
|
|
| **Test** | Vitest | `npm test` |
|
|
| **Coverage** | ≥70% | `npm run test:coverage` |
|
|
| **Lint** | ESLint + Prettier | `npm run lint` |
|
|
| **Type Check** | TypeScript strict | `npm run type-check` |
|
|
|
|
---
|
|
|
|
*MCP Standards Module v3.0.0*
|
|
*TypeScript governance enforcement server*
|