소개: 대규모 MCP 프로젝트 구성
단일 MCP 서버를 개발할 때 프로젝트 구조는 간단합니다. package.json,
TypeScript 파일 몇 개만 있으면 준비가 완료됩니다. 하지만 서버 수가 늘어나면 복잡성도 늘어납니다.
조직이 폭발한다. npm에 게시하지 않고 공통 코드를 공유하는 방법은 무엇입니까? 모든 것을 보장하는 방법
서버 컴파일이 올바른 순서로 이루어지나요? 구조와 패턴의 일관성을 유지하는 방법은 무엇입니까?
이러한 질문에 대한 대답은 다음과 같습니다. 모노레포: 모든 서버를 포함하는 단일 저장소 그리고 공유 패키지. 이 기사에서는 프로젝트의 모노레포 아키텍처를 분석합니다. Tech-MCP, 기본 기술 선택(TypeScript, SQLite, STDIO/HTTP) 및 4레이어 패턴 각 서버는 일관성과 유지 관리 가능성을 보장하기 위해 이를 따릅니다.
이 기사에서 배울 내용
- MCP 단일 저장소를 구성하는 방법 pnpm 작업공간 e 터보레포
- 완전한 디렉토리 구조
packages/eservers/ - TypeScript, SQLite 및 STDIO/HTTP가 MCP 서버를 위한 최선의 선택인 이유
- 4계층 아키텍처 패턴:
index.ts,server.ts,tools/,services/ - 인터페이스
McpSuiteServer그리고 공장createMcpServer() - Turborepo 및 종속성 그래프를 사용한 빌드 파이프라인
MCP 서버용 Monorepo가 필요한 이유는 무엇입니까?
모노레포는 프로젝트의 모든 구성요소를 단일 Git 저장소로 수집합니다. MCP 서버 제품군의 경우, 장점은 중요합니다:
-
게시하지 않고 코드 공유: 패키지
packages/이용 가능 프로토콜을 통해 모든 서버에workspace:npm에 게시할 필요 없이 pnpm의 - 원자적이고 깔끔한 빌드: Turborepo는 종속성 그래프를 분석하고 패키지를 빌드합니다. 올바른 순서로, 가능한 경우 병렬화
- 통합 버전 관리: 모든 패키지와 서버가 함께 진화하여 문제를 제거합니다. 버전 간 호환성
-
우수한 개발자 경험: 싱글
pnpm install그리고 하나pnpm build전체 프로젝트에 대해 -
안전한 리팩토링: 인터페이스를 다음으로 변경합니다.
@mcp-suite/core하이라이트 업데이트가 필요한 모든 서버를 즉시
모노레포의 전체 구조
Tech-MCP 프로젝트는 구성 파일이 있는 루트,
packages/ 공유 라이브러리의 경우 e servers/ 독립형 MCP 서버용.
mcp-suite/
├── package.json # Root: script globali, engine constraints
├── pnpm-workspace.yaml # Definisce packages/* e servers/* come workspace
├── turbo.json # Pipeline di build con Turborepo
├── tsconfig.base.json # Configurazione TypeScript condivisa
│
├── packages/ # Librerie condivise (6 pacchetti)
│ ├── core/ # Factory server, config, logger, errori, tipi
│ ├── event-bus/ # EventBus tipizzato con 29 eventi
│ ├── database/ # Connessione SQLite + migrazioni
│ ├── testing/ # Harness di test + MockEventBus
│ ├── cli/ # CLI per gestire i server
│ └── client-manager/ # Pool di client MCP per comunicazione server-to-server
│
├── servers/ # 22 MCP server indipendenti
│ ├── scrum-board/ # Gestione sprint, storie, task
│ ├── standup-notes/ # Note per gli standup giornalieri
│ ├── time-tracking/ # Tracciamento tempo
│ ├── agile-metrics/ # Metriche agili (velocity, burndown)
│ ├── code-review/ # Analisi e review del codice
│ ├── test-generator/ # Generazione test automatici
│ ├── cicd-monitor/ # Monitoraggio pipeline CI/CD
│ ├── docker-compose/ # Gestione Docker Compose
│ ├── db-schema-explorer/ # Esplorazione schemi database
│ ├── dependency-manager/ # Gestione dipendenze progetto
│ ├── api-documentation/ # Documentazione API
│ ├── codebase-knowledge/ # Knowledge base del codice
│ ├── data-mock-generator/ # Generazione dati mock
│ ├── environment-manager/ # Gestione variabili d'ambiente
│ ├── http-client/ # Client HTTP per test API
│ ├── log-analyzer/ # Analisi log applicativi
│ ├── performance-profiler/ # Profilazione performance
│ ├── project-economics/ # Economia di progetto (budget, costi)
│ ├── project-scaffolding/ # Scaffolding nuovi progetti
│ ├── regex-builder/ # Costruzione espressioni regolari
│ ├── retrospective-manager/# Gestione retrospettive agili
│ └── snippet-manager/ # Libreria di snippet di codice
│
└── docs/ # Documentazione del progetto
이 구조는 원리를 실현합니다. 서버 독립성: 각 서버 및 폴더
그들만의 자율적인 package.json, tsconfig.json 그리고 소스 코드. 동시에,
는 선택적 협업 공유된 패키지에 의해 보장됩니다. packages/.
6가지 공유 패키지
패키지 packages/ 이는 모든 서버에 대한 공통 기반을 제공합니다.
공유 패키지와 그 책임
| 패키지 | 책임 | 중독 |
|---|---|---|
@mcp-suite/core |
공장 서버, 구성, 로거, 오류, 공유 유형 | 이벤트 버스 |
@mcp-suite/event-bus |
29개의 이벤트와 게시/구독 패턴으로 입력된 EventBus | 없음 |
@mcp-suite/database |
WAL 모드 및 마이그레이션 시스템과 SQLite 연결 | 핵심 |
@mcp-suite/testing |
단위 테스트를 위한 테스트 하네스 및 MockEventBus | 코어, 이벤트 버스 |
@mcp-suite/cli |
서버를 관리, 시작 및 모니터링하는 CLI | 코어, 이벤트 버스, 클라이언트 관리자 |
@mcp-suite/client-manager |
서버 간 통신을 위한 MCP 클라이언트 풀 | 핵심 |
디자인 결정: TypeScript, SQLite 및 STDIO를 선택해야 하는 이유
프로젝트의 기본 기술은 무작위로 선택되지 않았습니다. 모든 결정은 반응합니다 분산 MCP 시스템의 특정 요구 사항에 따라 달라집니다.
왜 TypeScript인가?
TypeScript는 다음과 같은 네 가지 근본적인 이유 때문에 MCP 서버에 이상적인 언어입니다.
-
End-to-End형 안전성: 다음에 정의된 유형
@mcp-suite/core그들은 공유된다 모든 서버 간에 컴파일 시간 일관성을 보장합니다. 인터페이스 변경 사항이 즉시 전파됩니다. 그것을 사용하는 모든 서버에서 오류로 -
네이티브 ESM: ES2022 대상
"module": "Node16"기본 호환성을 위해 추가 번들러나 트랜스파일러가 필요 없는 최신 Node.js 사용 -
선언 맵: 각 패키지가 생성됩니다.
.d.tse.d.ts.map, IDE에서 직접 전체 모노레포에 걸쳐 "정의로 이동"을 허용합니다. -
엄격한 패션:
"strict": trueintsconfig.base.json최대로 유형 안전성 및 런타임 오류 방지
왜 SQLite(better-sqlite3)를 사용하나요?
각 서버의 로컬 지속성을 위해서는 SQLite가 최적의 선택입니다.
-
제로 구성: 설치하거나 관리할 데이터베이스 서버가 없습니다. 파일
.db처음 실행 시 자동으로 생성됩니다. -
파일 기반: 각 서버에는 자체 데이터베이스 파일이 있습니다.
~/.mcp-suite/data/, 다른 서버와 완전히 독립적 -
동기식:
better-sqlite3작업에 이상적인 동기식 C++ 바인딩을 사용합니다. 로컬 I/O 작업을 위한 Promise의 복잡성이 없는 빠른 로컬 - 월 모드: 최적의 동시 읽기 성능을 위해 미리 쓰기 로깅이 활성화되었습니다. 여러 도구가 동시에 저장소에 액세스할 때 필수
- 가지고 다닐 수 있는: 파일을 복사하는 것만으로 데이터베이스가 이동하므로 백업 및 마이그레이션이 용이합니다.
전송: STDIO 및 HTTP
MCP Suite는 환경 변수를 통해 선택할 수 있는 두 가지 전송을 지원합니다. MCP_SUITE_TRANSPORT:
MCP 전송 비교
| 특성 | STDIO(기본값) | HTTP(스트리밍 가능한 HTTP) |
|---|---|---|
| 사용 사례 | Claude Desktop, Cursor, VS Code를 사용한 로컬 사용 | 원격 배포, 서버 간 통신 |
| 구성 | 포트 없음, 네트워크 충돌 없음 | 각 서버의 전용 포트 |
| 안전 | 로컬 통신, 노출 없음 | 세션 UUID가 있는 상태 저장 프로토콜 |
| 확장성 | 연결당 하나의 프로세스 | 컨테이너, 수평 확장 |
| 노선 | 표준 입력/표준 출력 | POST/GET/DELETE /mcp + GET /health |
STDIO는 로컬 개발에 이상적인 기본 전송입니다. 서버가 다음과 같은 경우 HTTP가 필요해집니다. 클라이언트 관리자를 통해 또는 원격 서버에 배포할 때 서로 통신해야 합니다.
모노레포 구성
루트 디렉터리에 있는 세 개의 파일은 모노레포의 구조를 정의합니다: pnpm 작업 공간,
Turborepo 파이프라인과 package.json 뿌리.
pnpm-workspace.yaml
이 파일은 모노레포 작업공간이 포함된 디렉터리를 선언합니다.
# pnpm-workspace.yaml
packages:
- "packages/*"
- "servers/*"
이 구성을 사용하면 pnpm은 다음의 모든 하위 폴더를 처리합니다. packages/ e servers/
독립적인 작업 공간으로 내부 종속성은 프로토콜을 통해 해결됩니다.
workspace:* npm에서 찾는 대신.
터보.json
Turborepo는 빌드 파이프라인을 관리하여 작업 간의 컴파일 순서와 종속성을 정의합니다.
{
"$schema": "https://turbo.build/schema.json",
"tasks": {
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**"]
},
"test": {
"dependsOn": ["build"],
"outputs": []
},
"lint": {
"outputs": []
},
"clean": {
"cache": false
}
}
}
핵심 지시어 e "dependsOn": ["^build"]. 상징 ^ 작업을 나타냅니다.
build 각 작업 공간은 다음에 따라 다릅니다. build 내부 종속성. 이
다음을 보장합니다 @mcp-suite/core 이를 사용하는 서버보다 먼저 컴파일됩니다.
내부 종속성이 있는 서버 package.json
각 서버는 외부(npm) 및 내부(작업 공간) 모두에 대한 자체 종속성을 선언합니다.
{
"name": "@mcp-suite/scrum-board",
"version": "0.1.0",
"type": "module",
"scripts": {
"build": "tsc -p tsconfig.json",
"start": "node dist/index.js",
"clean": "rm -rf dist"
},
"dependencies": {
"@mcp-suite/core": "workspace:*",
"@mcp-suite/event-bus": "workspace:*",
"@mcp-suite/database": "workspace:*",
"@modelcontextprotocol/sdk": "^1.0.0",
"better-sqlite3": "^11.0.0",
"zod": "^3.23.0"
},
"devDependencies": {
"@types/better-sqlite3": "^7.6.0",
"typescript": "^5.7.0"
}
}
구문 "workspace:*" pnpm에게 로컬 작업공간 종속성을 해결하도록 지시합니다.
npm에서 찾는 대신. 이는 공유 패키지에 대한 변경 사항이 즉시 적용됨을 의미합니다.
재컴파일 후 모든 서버에서 사용할 수 있습니다.
빌드 파이프라인
당신이 달릴 때 pnpm build Turborepo는 모노레포의 루트에서 다음 그래프를 분석합니다.
종속성을 확인하고 최적의 빌드를 계획합니다.
pnpm build
│
├── @mcp-suite/event-bus (nessuna dipendenza interna)
├── @mcp-suite/core (dipende da event-bus)
├── @mcp-suite/database (dipende da core)
├── @mcp-suite/testing (dipende da core, event-bus)
├── @mcp-suite/client-manager (dipende da core)
├── @mcp-suite/cli (dipende da core, event-bus, client-manager)
│
└── servers/* (tutti dipendono da core, event-bus, database)
├── scrum-board
├── standup-notes
├── time-tracking
└── ... (altri 19 server compilati in parallelo)
Turborepo가 먼저 컴파일됩니다. event-bus (종속성 없음) core (이벤트 버스에 따라 다름)
그럼 database 다른 패키지, 그리고 마지막으로 모든 서버를 병렬로 연결합니다. 통합 캐시
Turborepo는 변경되지 않은 패키지 재컴파일을 건너뛰어 빌드를 점진적으로 만듭니다.
매우 빠릅니다.
4레이어 패턴 서버
제품군의 각 MCP 서버는 다음을 따릅니다. 엄격한 4레이어 아키텍처 패턴. 이 패턴 22개 서버 전체에 걸쳐 균일성, 유지 관리 가능성 및 테스트 가능성을 보장합니다. 이것은 컨벤션이 아닙니다. 선택 사항이지만 아키텍처 계약에 따라 모든 새 서버는 이 구조를 준수해야 합니다.
servers/nome-server/
├── package.json # Dipendenze e script
├── tsconfig.json # Estende tsconfig.base.json
└── src/
├── index.ts # Strato 1: Entry point, bootstrap
├── server.ts # Strato 2: Factory, registrazione tool
├── tools/ # Strato 3: Un file per tool
│ ├── create-sprint.ts
│ ├── get-sprint.ts
│ └── ...
├── services/ # Strato 4: Store SQLite, logica di business
│ └── scrum-store.ts
└── collaboration.ts # Handler eventi cross-server (opzionale)
4개 계층과 그 책임
| Strato | 파일 | 책임 | 중독 |
|---|---|---|---|
| 1. 진입점 | index.ts |
부트스트랩: EventBus 생성, 팩토리 호출, 전송 시작 | @mcp-suite/core, @mcp-suite/event-bus |
| 2.공장 | server.ts |
만들다 McpSuiteServer, 인스턴스화 저장, 등록 도구 |
@mcp-suite/core, 서비스, 도구 |
| 3.도구 | tools/*.ts |
단일 도구 정의: Zod 스키마 + 비동기 처리기 | @modelcontextprotocol/sdk, 서비스 |
| 4. 서비스 | services/*.ts |
SQLite 지속성, 마이그레이션, 도메인 로직 | @mcp-suite/database |
레이어 1: 진입점(index.ts)
전체 서버에서 진입점이자 가장 간단한 파일입니다. 정확히 세 가지 책임이 있습니다.
인스턴스를 생성 LocalEventBus, 서버 팩토리를 호출하고 전송을 시작합니다.
#!/usr/bin/env node
import { startServer } from '@mcp-suite/core';
import { LocalEventBus } from '@mcp-suite/event-bus';
import { createScrumBoardServer } from './server.js';
const eventBus = new LocalEventBus();
const suite = createScrumBoardServer(eventBus);
startServer(suite).catch((error) => {
console.error('Failed to start scrum-board server:', error);
process.exit(1);
});
셔뱅 #!/usr/bin/env node 바이너리로 직접 실행이 가능합니다.
EventBus는 여기에서 생성되고 다음을 통해 서버에 주입됩니다. 의존성 주입.
기능 startServer() 자동으로 전송(STDIO 또는 HTTP) 기반을 선택합니다.
구성에. 치명적인 오류로 인해 프로세스가 종료됩니다. process.exit(1).
레이어 2: 팩토리(server.ts)
공장이자 서버의 심장입니다. 객체 생성 McpSuiteServer, 지속성 서비스를 인스턴스화합니다.
모든 도구를 등록하고 다른 서버와 협업을 설정하세요.
import { createMcpServer, type McpSuiteServer, type EventBus } from '@mcp-suite/core';
import { ScrumStore } from './services/scrum-store.js';
import { registerCreateSprint } from './tools/create-sprint.js';
import { registerGetSprint } from './tools/get-sprint.js';
import { registerCreateStory } from './tools/create-story.js';
import { registerCreateTask } from './tools/create-task.js';
import { registerUpdateTaskStatus } from './tools/update-task-status.js';
import { registerSprintBoard } from './tools/sprint-board.js';
import { registerGetBacklog } from './tools/get-backlog.js';
import { setupCollaborationHandlers } from './collaboration.js';
export function createScrumBoardServer(eventBus?: EventBus): McpSuiteServer {
const suite = createMcpServer({
name: 'scrum-board',
version: '0.1.0',
description: 'MCP server for managing sprints, user stories, tasks',
eventBus,
});
const store = new ScrumStore();
// Registra tutti i tool
registerCreateSprint(suite.server, store, suite.eventBus);
registerGetSprint(suite.server, store);
registerCreateStory(suite.server, store);
registerCreateTask(suite.server, store);
registerUpdateTaskStatus(suite.server, store, suite.eventBus);
registerSprintBoard(suite.server, store);
registerGetBacklog(suite.server, store);
// Collaborazione cross-server (solo se EventBus presente)
if (suite.eventBus) {
setupCollaborationHandlers(suite.eventBus, store);
}
suite.logger.info('All scrum-board tools registered');
return suite;
}
방법에 주목하세요 createMcpServer() 객체를 반환합니다 McpSuiteServer 이미 구성되었습니다.
스토어는 한 번만 생성되며 등록 기능을 통해 모든 도구에서 공유됩니다.
그만큼'eventBus 선택사항: 통과하지 못한 경우 서버는 독립형 모드로 작동합니다.
레이어 3: 도구 등록(tools/)
각 도구는 기능을 내보내는 별도의 파일입니다. registerXxx(). 이 함수는 수신
는 McpServer, 상점 및 선택적으로EventBus, 단일 도구를 등록합니다.
Zod 유효성 검사 체계와 비동기 처리기를 사용합니다.
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { z } from 'zod';
import type { EventBus } from '@mcp-suite/core';
import type { ScrumStore } from '../services/scrum-store.js';
export function registerCreateSprint(
server: McpServer,
store: ScrumStore,
eventBus?: EventBus,
): void {
server.tool(
'create-sprint', // Nome del tool
'Create a new sprint with a name, date range, and goals', // Descrizione per l'LLM
{ // Schema Zod
name: z.string().describe('Sprint name (e.g. "Sprint 12")'),
startDate: z.string().describe('Start date ISO (YYYY-MM-DD)'),
endDate: z.string().describe('End date ISO (YYYY-MM-DD)'),
goals: z.array(z.string()).describe('Sprint goals'),
},
async ({ name, startDate, endDate, goals }) => { // Handler
try {
const sprint = store.createSprint({ name, startDate, endDate, goals });
// Pubblicazione evento fire-and-forget
eventBus?.publish('scrum:sprint-started', {
sprintId: String(sprint.id),
name: sprint.name,
startDate: sprint.startDate,
endDate: sprint.endDate,
});
return {
content: [{ type: 'text' as const, text: JSON.stringify(sprint, null, 2) }],
};
} catch (error) {
return {
content: [{
type: 'text' as const,
text: `Failed to create sprint: ${error instanceof Error ? error.message : String(error)}`,
}],
isError: true,
};
}
},
);
}
녹음 패턴은 정확한 구조를 따릅니다. 이름 도구의 고유 코드,
설명 언제 사용하는지 이해하기 위해 LLM이 읽을 수 있으며, 조드 계획
입력 매개변수의 자동 검증을 위해 e 비동기 핸들러 오류 처리와 함께.
EventBus는 선택적 연결 연산자와 함께 사용됩니다. eventBus?.publish(...):
존재하지 않는 경우 호출은 아무 작업도 수행하지 않습니다.
계층 4: 서비스 및 저장소(services/)
서비스에는 비즈니스 논리와 지속성이 포함됩니다. Store와 그것이 관리하는 메인 클래스
마이그레이션 시스템을 사용하여 SQLite 데이터베이스에 대한 CRUD 작업 @mcp-suite/database.
import type Database from 'better-sqlite3';
import { createDatabase } from '@mcp-suite/database';
import { runMigrations, type Migration } from '@mcp-suite/database';
const migrations: Migration[] = [
{
version: 1,
description: 'Create sprints, stories, and tasks tables',
up: `
CREATE TABLE IF NOT EXISTS sprints (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
startDate TEXT NOT NULL,
endDate TEXT NOT NULL,
goals TEXT NOT NULL DEFAULT '[]',
status TEXT NOT NULL DEFAULT 'planning',
createdAt TEXT NOT NULL DEFAULT (datetime('now'))
);
`,
},
];
export class ScrumStore {
private db: Database.Database;
constructor(options?: { inMemory?: boolean; dataDir?: string }) {
this.db = createDatabase({
serverName: 'scrum-board',
inMemory: options?.inMemory,
dataDir: options?.dataDir,
});
runMigrations(this.db, migrations);
}
createSprint(input: {
name: string; startDate: string; endDate: string; goals: string[]
}): Sprint {
const stmt = this.db.prepare(
'INSERT INTO sprints (name, startDate, endDate, goals) VALUES (?, ?, ?, ?)',
);
const result = stmt.run(
input.name, input.startDate, input.endDate,
JSON.stringify(input.goals)
);
return this.getSprint(Number(result.lastInsertRowid))!;
}
// ... altri metodi CRUD ...
}
매장에서 사용하는 createDatabase() da @mcp-suite/database 데이터베이스를 생성하려면
SQLite with WAL mode enabled. 마이그레이션은 객체 배열로 정의됩니다. Migration
생성자에 자동으로 적용됩니다. 제조사에서 지원하는 inMemory: true 테스트를 위해,
파일 시스템을 건드리지 않고도 단위 테스트를 실행할 수 있습니다.
McpSuiteServer 인터페이스
아키텍처의 중심에는 인터페이스가 있습니다 McpSuiteServer, 각 서버가 체결하는 계약
존중해야 합니다. 이 인터페이스는 공장에서 생성됩니다. createMcpServer() 그리고 통과
모든 녹음 도구 기능에 적용됩니다.
export interface CreateServerOptions {
name: string;
version: string;
description?: string;
config?: Partial<ServerConfig>;
eventBus?: EventBus;
}
export interface McpSuiteServer {
server: McpServer; // Istanza del server MCP (SDK ufficiale)
config: ServerConfig; // Configurazione caricata e validata
logger: Logger; // Logger strutturato su stderr
eventBus?: EventBus; // EventBus opzionale per collaborazione
}
export function createMcpServer(options: CreateServerOptions): McpSuiteServer {
const config = loadConfig(options.name, options.config);
const logger = new Logger(options.name, config.logLevel);
logger.info(`Initializing ${options.name} v${options.version}`);
const server = new McpServer({
name: options.name,
version: options.version,
});
return { server, config, logger, eventBus: options.eventBus };
}
팩토리의 내부 흐름은 선형입니다. 즉, 환경 변수에서 구성을 로드합니다.
(loadConfig), 구성된 레벨로 로거를 생성하고 McpServer
공식 SDK에서 전체 번들을 반환합니다. 분야 eventBus e 선택 과목:
존재하는 경우 도구는 이벤트를 게시할 수 있습니다. 없는 경우 도구는 독립형 모드에서 작동합니다.
부작용 없이.
완전한 아키텍처 다이어그램
다음 다이어그램은 AI 클라이언트부터 모든 구성 요소가 서로 어떻게 연관되어 있는지 보여줍니다. 외부 종속성:
┌────────────────────────────────────────────────────────────────────┐
│ CLIENT (Claude Desktop, Cursor, VS Code) │
│ Comunica via STDIO o HTTP (JSON-RPC / Streamable) │
└──────────────┬─────────────────────────────────┬───────────────────┘
│ │
v v
┌──────────────────────┐ ┌──────────────────────┐
│ scrum-board │ │ time-tracking │
│ ┌──────────────┐ │ EventBus │ ┌──────────────┐ │
│ │ tools/ │ │<────────>│ │ tools/ │ │
│ │ services/ │ │(opzionale)│ │ services/ │ │
│ │ server.ts │ │ │ │ server.ts │ │
│ │ index.ts │ │ │ │ index.ts │ │
│ └──────────────┘ │ │ └──────────────┘ │
└──────────┬───────────┘ └──────────┬───────────┘
│ │
v v
┌────────────────────────────────────────────────────────────────────┐
│ PACKAGES (librerie condivise) │
│ │
│ ┌────────────┐ ┌────────────┐ ┌──────────┐ ┌────────────┐ │
│ │ @mcp-suite│ │ @mcp-suite│ │@mcp-suite│ │ @mcp-suite│ │
│ │ /core │ │ /event-bus │ │/database │ │ /testing │ │
│ └────────────┘ └────────────┘ └──────────┘ └────────────┘ │
└────────────────────────────────────────────────────────────────────┘
│
v
┌────────────────────────────────────────────────────────────────────┐
│ @modelcontextprotocol/sdk better-sqlite3 zod │
│ (protocollo MCP ufficiale) (database nativo) (validaz.) │
└────────────────────────────────────────────────────────────────────┘
EventBus 주입 흐름
패턴의 핵심 측면은 EventBus가 다양한 계층을 통해 주입되는 방식입니다.
디자인은 원칙을 따릅니다. 실행하고 잊어버리세요: EventBus가 존재하지 않는 경우 호출
eventBus?.publish(...) 그들은 아무것도 하지 않습니다. 존재하지만 듣는 사람이 없다면,
이벤트는 단순히 무시됩니다. 도구는 이벤트 응답을 기다리지 않습니다.
index.ts server.ts tools/xxx.ts
──────── ───────── ────────────
const eventBus = function createXxxServer( function registerXxx(
new LocalEventBus(); eventBus?: EventBus server, store,
) { eventBus?: EventBus
const suite = const suite = createMcpServer( ) {
createXxxServer( { eventBus } // uso:
eventBus ); eventBus?.publish(...)
); }
registerXxx(
suite.server,
store,
suite.eventBus // passato ai tool
);
}
이 종속성 주입 패턴은 각 구성 요소가 필요한 종속성만 받도록 보장합니다. EventBus는 항상 선택 사항이므로 협업을 추가하거나 제거하는 데 구조적 변경이 필요하지 않습니다. 서버에.
4레이어 패턴의 장점
- 책임의 분리: 각 레이어에는 잘 정의된 작업이 있어 코드를 쉽게 읽고 유지 관리할 수 있습니다.
- 테스트 가능성: 서비스는 메모리 내 데이터베이스로 테스트할 수 있고, 도구는 매장 모형으로 테스트할 수 있습니다.
- 확장성: 새 도구를 추가하려면 새 도구만 필요합니다.
tools/공장등록 및 공장등록 - 일률: 22개 서버 모두 동일한 구조를 따르므로 어떤 서버라도 쉽게 탐색하고 이해할 수 있습니다.
- 독립: 각 서버는 자체 종속성 및 데이터베이스를 사용하여 개별적으로 배포 가능
결론
pnpm 작업공간과 Turborepo를 갖춘 모노레포 아키텍처와 4레이어 서버 패턴이 결합되어, 확장 가능하고 유지 관리가 가능한 MCP 제품군을 위한 견고한 기반을 제공합니다. 기술적 선택 (유형 안전성을 위한 TypeScript, 로컬 지속성을 위한 SQLite, 전송을 위한 STDIO/HTTP)는 MCP 서버 생태계의 특정 요구에 의해 주도되었습니다.
인터페이스 McpSuiteServer 그리고 공장 createMcpServer() 그들은 표준화한다
새로운 서버를 생성하는 동시에 레이어(진입점, 공장, 도구, 서비스)로 분리
각 회원이 명확하고 제한된 책임을 갖도록 보장합니다.
다음 기사에서는 이론에서 실습으로 넘어갈 것입니다. 첫 번째 MCP 서버를 만들겠습니다. TypeScript에서 처음부터, 이 문서에 설명된 패턴을 따릅니다. 구성하는 방법을 살펴보겠습니다. 프로젝트를 작성하고, Zod로 도구를 정의하고, SQLite로 지속성을 구현하고, 서버를 테스트하세요. 클로드 데스크탑과 함께하세요.
모든 예제가 포함된 전체 코드는 저장소에서 사용할 수 있습니다. GitHub의 Tech-MCP.







