> 작성 및 명령어 확인 기준: 2026년 7월 26일
> 예제 환경: Windows, Node.js, TypeScript, Claude Code, Codex CLI
최근 개발자 채용공고를 보다 보면 MCP 서버 개발 경험을 우대한다는 문구가 종종 보인다.
Claude Code나 Codex 같은 AI 코딩 도구를 사용하면서도 MCP라는 이름은 계속 접하게 된다.
처음에는 AI가 외부 API를 호출하게 만드는 방식과 크게 다르지 않은 것처럼 보였다.
어차피 서버에 요청을 보내고 결과를 받는 구조라면, 기존 REST API를 연결하는 것과 무엇이 다른지 궁금했다.
그래서 이번 글에서는 외부 API 키가 필요 없는 간단한 MCP 서버를 직접 만들어보고, 같은 서버를 Claude Code와 Codex에 각각 연결해보는 흐름으로 정리해보려고 한다.
결론부터 말하면 MCP는 API를 대체하는 기술이 아니다.
API가 서비스의 기능과 데이터를 외부에 제공하는 통로라면, MCP는 AI가 그런 기능을 발견하고 일정한 형식으로 사용할 수 있게 만드는 연결 규격에 가깝다.
쉽게 말하면 API가 실제 기능을 제공하는 엔진이라면, MCP는 AI가 그 엔진의 사용법을 이해하고 작동시킬 수 있도록 만들어주는 공통 어댑터라고 보면 된다.
---
1. MCP란 무엇인가
MCP는 Model Context Protocol의 약자다.
AI 애플리케이션이 외부 데이터, 도구, 업무 흐름과 연결될 수 있도록 만든 공개 표준이다.
예를 들어 Claude Code나 Codex가 다음과 같은 일을 해야 한다고 생각해보자.
1) 사내 데이터베이스에서 주문 정보를 조회한다.
2) GitHub 이슈를 검색한다.
3) 로컬에 저장된 문서를 읽는다.
4) 브라우저를 열어 화면을 확인한다.
5) 특정 API를 호출해 결과를 가져온다.
AI 모델 자체는 이런 시스템에 마음대로 접근할 수 없다.
외부 기능을 사용하려면 어떤 기능이 있는지, 어떤 값을 넘겨야 하는지, 결과는 어떤 형식으로 돌아오는지를 알아야 한다.
MCP 서버는 이런 정보를 AI 도구에 일정한 규격으로 제공한다.
MCP 서버가 제공하는 대표 기능은 다음 세 가지다.
1) Tools
AI가 실행할 수 있는 기능이다.
예를 들어 프로젝트 검색, 데이터베이스 조회, 파일 생성, 배포 실행 같은 기능을 Tool로 만들 수 있다.
2) Resources
AI가 읽을 수 있는 데이터다.
파일 내용, 문서, 데이터베이스 결과, API 응답 같은 정보를 Resource로 제공할 수 있다.
3) Prompts
반복해서 사용할 수 있는 작업 지침이나 프롬프트 템플릿이다.
이번 글에서는 가장 이해하기 쉬운 Tools를 사용한다.
---
2. MCP와 API는 무엇이 다른가
MCP를 처음 보면 가장 먼저 드는 생각은 이것이다.
“이것도 결국 서버에 요청해서 결과를 받는 것 아닌가?”
맞다.
MCP 서버 내부에서도 기존 REST API를 호출할 수 있고, 데이터베이스를 조회할 수도 있다.
다만 API와 MCP는 담당하는 역할이 조금 다르다.
1) API는 애플리케이션을 위한 인터페이스다
일반적인 REST API는 개발자가 정해진 URL과 요청 형식을 알고 직접 호출한다.
예를 들어 프로젝트를 검색하는 API가 다음과 같다고 해보자.
```http
GET /api/projects?keyword=flutter
```
이 API를 사용하는 클라이언트는 미리 다음 내용을 알고 있어야 한다.
- 호출할 주소
- HTTP 메서드
- 전달할 파라미터
- 인증 방식
- 응답 데이터 구조
프론트엔드나 모바일 앱에서는 개발자가 이 규격에 맞춰 호출 코드를 작성한다.
2) MCP는 AI 도구를 위한 연결 규격이다
MCP 서버는 AI에게 사용할 수 있는 Tool의 이름, 설명, 입력값 구조를 알려준다.
예를 들어 다음과 같은 Tool이 있다고 해보자.
```text
도구명: search_projects
설명: 기술 스택, 프로젝트 이름, 설명에서 프로젝트를 검색한다.
입력값: keyword 문자열
```
Claude Code나 Codex는 이 설명을 보고 사용자의 요청에 필요한 Tool인지 판단한다.
사용자가 다음처럼 자연어로 질문할 수 있다.
```text
Flutter와 AWS를 같이 사용한 프로젝트를 찾아줘.
```
AI는 등록된 Tool 가운데 `search_projects`가 적절하다고 판단하면 필요한 검색어를 만들어 MCP 서버를 호출한다.
개발자가 매번 AI에게 API 주소와 JSON 형식을 설명하지 않아도 된다.
3) MCP 서버 안에서 기존 API를 그대로 사용할 수 있다
이 부분이 생각보다 중요했다.
MCP와 API는 서로 경쟁하는 구조가 아니다.
실제 운영 환경에서는 다음과 같이 연결되는 경우가 많다.
```text
Claude Code 또는 Codex
↓
MCP 서버
↓
기존 REST API 또는 데이터베이스
```
기존 서비스에 이미 REST API가 있다면 그것을 없애고 MCP로 다시 만드는 것이 아니다.
기존 API를 호출하는 MCP Tool을 추가해서 AI 도구가 사용할 수 있도록 연결하면 된다.
개인적으로는 MCP를 “AI용 API”라고만 설명하는 것보다 “기존 API와 시스템을 AI가 사용할 수 있게 만드는 표준 어댑터”라고 설명하는 편이 더 정확하게 느껴졌다.
---
3. 이번에 만들 MCP 서버의 구조
이번 예제에서는 개발자의 프로젝트 목록을 검색하는 간단한 MCP 서버를 만든다.
외부 API나 데이터베이스는 연결하지 않는다.
프로젝트 배열을 서버 코드 안에 넣고, AI가 검색어를 전달하면 일치하는 프로젝트를 반환하는 방식이다.
등록할 Tool은 두 개다.
1) `search_projects`
프로젝트 이름, 설명, 기술 스택에서 키워드를 검색한다.
2) `get_project_detail`
정확한 프로젝트 이름을 전달하면 해당 프로젝트의 상세 정보를 반환한다.
전체 구조는 다음과 같다.
```text
사용자
↓ 자연어 질문
Claude Code 또는 Codex
↓ Tool 선택 및 입력값 생성
project-search MCP 서버
↓ 프로젝트 데이터 검색
검색 결과 반환
↓
Claude Code 또는 Codex가 자연어로 정리
```
이 정도만 만들어도 MCP의 전체 흐름을 확인하기에는 충분하다.
---
4. 프로젝트 생성하기
먼저 PowerShell에서 프로젝트 폴더를 만든다.
```powershell
mkdir project-search-mcp
cd project-search-mcp
npm init -y
npm install @modelcontextprotocol/sdk zod@3
npm install -D typescript @types/node
mkdir src
New-Item src/index.ts
New-Item tsconfig.json
```
Node.js는 현재 설치 가능한 LTS 버전을 사용하는 것이 좋다.
설치 여부는 다음 명령으로 확인할 수 있다.
```powershell
node --version
npm --version
```
프로젝트 구조는 다음처럼 만들어진다.
```text
project-search-mcp
├─ src
│ └─ index.ts
├─ package.json
└─ tsconfig.json
```
---
5. package.json 설정하기
`package.json`을 다음처럼 정리한다.
```json
{
"name": "project-search-mcp",
"version": "1.0.0",
"description": "개발 프로젝트를 검색하는 간단한 MCP 서버",
"type": "module",
"scripts": {
"build": "tsc",
"start": "node build/index.js"
},
"dependencies": {
"@modelcontextprotocol/sdk": "^1.0.0",
"zod": "^3.0.0"
},
"devDependencies": {
"@types/node": "^22.0.0",
"typescript": "^5.0.0"
}
}
```
여기서 버전 번호는 예시다.
실제로 `npm install`을 실행하면 설치 시점에 맞는 버전이 `package.json`에 기록된다.
따라서 직접 설치한 뒤 생성된 버전을 그대로 사용하는 편이 안전하다.
`"type": "module"`은 ES Module 방식의 `import` 문을 사용하기 위한 설정이다.
`npm run build`를 실행하면 TypeScript 파일이 `build/index.js`로 컴파일된다.
---
6. tsconfig.json 설정하기
`tsconfig.json`은 다음처럼 작성한다.
```json
{
"compilerOptions": {
"target": "ES2022",
"module": "Node16",
"moduleResolution": "Node16",
"outDir": "./build",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
},
"include": ["src/**/*"],
"exclude": ["node_modules"]
}
```
복잡한 설정은 아니다.
`src` 안의 TypeScript 파일을 읽어서 `build` 폴더에 JavaScript 파일을 생성하는 설정이라고 보면 된다.
---
7. MCP 서버 코드 작성하기
`src/index.ts`에 다음 코드를 넣는다.
```typescript
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
type Project = {
name: string;
description: string;
stacks: string[];
role: string;
};
const projects: Project[] = [
{
name: "Super App",
description: "사용자 인증과 상품 조회 기능을 포함한 Flutter 모바일 앱",
stacks: ["Flutter", "Dart", "REST API", "AWS"],
role: "모바일 앱과 서버 연동 개발",
},
{
name: "Market Service",
description: "상품 등록과 주문 관리를 제공하는 웹 서비스",
stacks: ["Next.js", "Node.js", "PostgreSQL", "AWS"],
role: "웹 프론트엔드와 백엔드 개발",
},
{
name: "Booking Service",
description: "예약 일정과 관리자 기능을 제공하는 서비스",
stacks: ["React", "Express", "MySQL"],
role: "예약 API와 관리자 화면 개발",
},
{
name: "Document Translator",
description: "문서를 업로드하고 AI로 번역하는 웹 서비스",
stacks: ["Next.js", "Supabase", "OpenAI API", "Vercel"],
role: "전체 서비스 설계와 구현",
},
];
const server = new McpServer({
name: "project-search",
version: "1.0.0",
});
server.registerTool(
"search_projects",
{
description:
"프로젝트 이름, 설명, 역할, 기술 스택에서 입력한 키워드와 관련된 프로젝트를 검색합니다.",
inputSchema: {
keyword: z
.string()
.min(1)
.describe("검색할 기술명이나 프로젝트 관련 키워드"),
},
},
async ({ keyword }) => {
const normalizedKeyword = keyword.toLowerCase();
const matchedProjects = projects.filter((project) => {
const searchableText = [
project.name,
project.description,
project.role,
...project.stacks,
]
.join(" ")
.toLowerCase();
return searchableText.includes(normalizedKeyword);
});
if (matchedProjects.length === 0) {
return {
content: [
{
type: "text",
text: `"${keyword}"와 관련된 프로젝트를 찾지 못했습니다.`,
},
],
};
}
const result = matchedProjects
.map(
(project) =>
[
`프로젝트명: ${project.name}`,
`설명: ${project.description}`,
`기술 스택: ${project.stacks.join(", ")}`,
`담당 역할: ${project.role}`,
].join("\n"),
)
.join("\n\n---\n\n");
return {
content: [
{
type: "text",
text: result,
},
],
};
},
);
server.registerTool(
"get_project_detail",
{
description: "정확한 프로젝트 이름을 기준으로 상세 정보를 조회합니다.",
inputSchema: {
name: z.string().min(1).describe("조회할 프로젝트 이름"),
},
},
async ({ name }) => {
const project = projects.find(
(item) => item.name.toLowerCase() === name.toLowerCase(),
);
if (!project) {
return {
content: [
{
type: "text",
text: `"${name}" 프로젝트를 찾지 못했습니다.`,
},
],
};
}
return {
content: [
{
type: "text",
text: [
`프로젝트명: ${project.name}`,
`설명: ${project.description}`,
`기술 스택: ${project.stacks.join(", ")}`,
`담당 역할: ${project.role}`,
].join("\n"),
},
],
};
},
);
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("project-search MCP 서버가 stdio 방식으로 실행되었습니다.");
}
main().catch((error) => {
console.error("MCP 서버 실행 중 오류가 발생했습니다.", error);
process.exit(1);
});
```
코드를 보면 일반적인 Node.js 서버와 조금 다른 점이 있다.
Express처럼 포트를 열거나 URL을 등록하지 않았다.
대신 `McpServer`를 만들고 `registerTool`로 AI가 사용할 기능을 등록했다.
마지막에는 `StdioServerTransport`를 사용해 표준 입출력 방식으로 클라이언트와 통신한다.
---
8. 코드에서 중요한 부분 살펴보기
1) Tool의 설명이 중요하다
다음 부분은 단순한 주석이 아니다.
```typescript
description:
"프로젝트 이름, 설명, 역할, 기술 스택에서 입력한 키워드와 관련된 프로젝트를 검색합니다."
```
Claude Code나 Codex는 이 설명을 보고 어떤 상황에서 Tool을 사용할지 판단한다.
설명이 너무 짧거나 애매하면 AI가 Tool을 사용하지 않거나 엉뚱한 상황에서 호출할 수 있다.
MCP에서는 함수 이름만큼 설명과 입력값 정의가 중요하다.
2) inputSchema가 호출 규격이 된다
다음 부분은 Tool이 어떤 값을 받아야 하는지 정의한다.
```typescript
inputSchema: {
keyword: z
.string()
.min(1)
.describe("검색할 기술명이나 프로젝트 관련 키워드"),
}
```
기존 REST API의 요청 파라미터나 JSON 스키마와 비슷한 역할이다.
AI는 이 스키마에 맞춰 `keyword` 값을 만들어 전달한다.
3) 결과는 content 형식으로 반환한다
Tool 실행 결과는 다음 형태로 반환한다.
```typescript
return {
content: [
{
type: "text",
text: result,
},
],
};
```
MCP 서버는 결과를 사용자 화면에 직접 출력하는 것이 아니다.
결과를 AI 클라이언트에 전달하고, Claude Code나 Codex가 이를 다시 자연어로 정리한다.
4) stdio에서는 console.log를 사용하면 안 된다
이번 서버는 표준 입출력으로 MCP 메시지를 주고받는다.
이 상태에서 `console.log()`를 사용하면 MCP 통신에 사용하는 표준 출력에 일반 문자열이 섞일 수 있다.
그 결과 JSON-RPC 메시지가 깨지고 서버 연결이 실패할 수 있다.
로그가 필요하면 다음처럼 `console.error()`를 사용하는 편이 안전하다.
```typescript
console.error("서버 로그");
```
직접 만들어볼 때 이 부분이 생각보다 중요하다.
일반 Node.js 프로그램에서는 `console.log()`가 너무 자연스럽기 때문에 무심코 넣기 쉽다.
---
9. TypeScript 빌드하기
코드 작성이 끝났으면 빌드한다.
```powershell
npm run build
```
빌드가 성공하면 다음 파일이 생성된다.
```text
build/index.js
```
MCP 클라이언트는 TypeScript 원본이 아니라 이 JavaScript 파일을 Node.js로 실행한다.
코드를 수정한 뒤 빌드를 다시 하지 않으면 이전 코드가 실행된다.
MCP Tool을 수정했는데 결과가 바뀌지 않는다면 먼저 `npm run build`를 다시 실행했는지 확인하는 것이 좋다.
---
10. Claude Code에 MCP 서버 연결하기
Claude Code는 `claude mcp add` 명령으로 로컬 stdio MCP 서버를 추가할 수 있다.
먼저 `build/index.js`의 절대 경로를 확인한다.
예를 들어 프로젝트 위치가 다음과 같다고 해보자.
```text
C:\dev\project-search-mcp
```
Windows에서도 설정 경로에는 역슬래시보다 슬래시를 사용하면 따옴표와 이스케이프 문제를 줄일 수 있다.
```text
C:/dev/project-search-mcp/build/index.js
```
1) 사용자 범위로 연결하기
모든 프로젝트에서 사용하려면 다음처럼 등록한다.
```powershell
claude mcp add --transport stdio --scope user project-search -- node "C:/dev/project-search-mcp/build/index.js"
```
명령어 중간의 `--`는 Claude Code 자체 옵션과 실제 MCP 서버 실행 명령을 구분한다.
쉽게 말하면 `--` 뒤의 내용은 Claude Code 옵션이 아니라 서버를 실행하기 위한 명령이다.
위 설정은 내부적으로 다음 명령을 실행한다.
```powershell
node "C:/dev/project-search-mcp/build/index.js"
```
2) 현재 프로젝트에서만 사용하기
팀과 공유하거나 특정 프로젝트에서만 사용하려면 `project` 범위를 사용할 수 있다.
```powershell
claude mcp add --transport stdio --scope project project-search -- node "C:/dev/project-search-mcp/build/index.js"
```
이 경우 프로젝트 루트에 `.mcp.json` 설정이 만들어진다.
프로젝트 범위 MCP 서버는 보안상 처음 연결할 때 사용 승인을 요구할 수 있다.
개인적으로는 처음 테스트할 때는 `user` 범위로 연결하고, 실제 프로젝트에 필요한 서버만 `project` 범위로 관리하는 편이 이해하기 쉬웠다.
3) 연결 상태 확인하기
다음 명령으로 등록된 MCP 서버를 확인한다.
```powershell
claude mcp list
```
특정 서버의 상세 설정을 확인하려면 다음 명령을 사용한다.
```powershell
claude mcp get project-search
```
Claude Code를 실행한 상태에서는 다음 명령으로 연결 상태를 확인할 수 있다.
```text
/mcp
```
서버가 정상적으로 연결되면 `project-search`가 목록에 표시된다.
---
11. Claude Code에서 Tool 호출해보기
Claude Code를 실행한다.
```powershell
claude
```
다음과 같이 질문해본다.
```text
등록된 프로젝트 중 Flutter를 사용한 프로젝트를 찾아줘.
```
Claude Code가 MCP Tool을 사용하도록 조금 더 명확하게 요청할 수도 있다.
```text
project-search MCP 도구를 사용해서 Flutter 관련 프로젝트를 찾아줘.
```
정상적으로 연결됐다면 Claude Code는 `search_projects` Tool을 선택하고, 다음과 비슷한 입력값을 전달한다.
```json
{
"keyword": "Flutter"
}
```
서버는 검색 결과를 반환하고, Claude Code는 결과를 읽기 쉬운 문장으로 정리한다.
다음 요청도 테스트해볼 수 있다.
```text
Super App 프로젝트의 상세 정보를 MCP 도구로 조회해줘.
```
이 경우에는 `get_project_detail` Tool이 호출될 가능성이 높다.
---
12. Codex에 MCP 서버 연결하기
같은 MCP 서버를 Codex에도 연결할 수 있다.
MCP의 장점은 한 번 만든 서버를 특정 AI 도구에만 묶어두지 않고, MCP를 지원하는 여러 클라이언트에서 재사용할 수 있다는 점이다.
1) Codex CLI 명령으로 추가하기
다음 명령을 실행한다.
```powershell
codex mcp add project-search -- node "C:/dev/project-search-mcp/build/index.js"
```
Claude Code와 마찬가지로 `--` 뒤에는 MCP 서버를 실행할 실제 명령이 들어간다.
등록 결과는 다음 명령으로 확인한다.
```powershell
codex mcp list
```
Codex의 MCP 관련 명령을 모두 보고 싶다면 다음 명령을 사용한다.
```powershell
codex mcp --help
```
2) config.toml에 직접 설정하기
Codex는 기본적으로 다음 파일에 설정을 저장한다.
```text
~/.codex/config.toml
```
Windows에서는 보통 사용자 홈 폴더 아래의 `.codex/config.toml`이다.
다음 내용을 직접 추가할 수도 있다.
```toml
[mcp_servers.project-search]
command = "node"
args = ["C:/dev/project-search-mcp/build/index.js"]
```
특정 프로젝트에서만 사용하려면 프로젝트 안에 다음 파일을 만들 수 있다.
```text
.codex/config.toml
```
프로젝트 범위 설정은 신뢰된 프로젝트에서만 적용되는 점에 주의가 필요하다.
3) Codex에서 연결 상태 확인하기
Codex를 실행한다.
```powershell
codex
```
Codex 터미널 화면에서 다음 명령을 입력한다.
```text
/mcp
```
`project-search` 서버와 제공되는 Tool이 표시되면 연결된 것이다.
---
13. Codex에서 Tool 호출해보기
Codex에서 다음처럼 요청한다.
```text
project-search MCP 서버를 사용해서 AWS 관련 프로젝트를 찾아줘.
```
또는 자연스럽게 질문해도 된다.
```text
내 프로젝트 데이터 중 AWS를 사용한 프로젝트가 무엇인지 확인해줘.
```
Codex가 Tool 설명을 보고 MCP 서버 호출이 필요하다고 판단하면 `search_projects`를 실행한다.
다음 질문도 가능하다.
```text
Document Translator 프로젝트의 상세 정보를 조회하고 사용 기술을 정리해줘.
```
Claude Code와 Codex는 서로 다른 AI 코딩 도구지만, MCP 서버 입장에서는 같은 규격으로 요청을 처리한다.
이것이 MCP를 사용하는 가장 큰 이유 가운데 하나다.
---
14. 실제 호출 과정은 어떻게 진행되는가
사용자가 다음과 같이 질문했다고 해보자.
```text
Flutter를 사용한 프로젝트를 찾아줘.
```
내부 흐름은 대략 다음과 같다.
1) Claude Code나 Codex가 사용자의 문장을 분석한다.
2) 현재 연결된 MCP 서버의 Tool 목록과 설명을 확인한다.
3) `search_projects` Tool이 적절하다고 판단한다.
4) 입력 스키마에 맞춰 `keyword: "Flutter"`를 만든다.
5) MCP 서버에 Tool 실행을 요청한다.
6) MCP 서버가 프로젝트 배열을 검색한다.
7) 검색 결과를 Claude Code나 Codex에 반환한다.
8) AI가 결과를 사용자에게 자연어로 설명한다.
일반 REST API에서는 개발자가 API 호출 코드를 직접 작성한다.
MCP에서는 AI 클라이언트가 Tool의 설명과 스키마를 읽고 호출 여부와 입력값을 결정한다.
물론 MCP가 모든 것을 알아서 해결해주는 것은 아니다.
Tool 설명, 입력 스키마, 권한, 오류 처리, 반환 데이터는 결국 개발자가 제대로 설계해야 한다.
---
15. API와 MCP를 실무 기준으로 다시 비교해보기
1) API가 더 적합한 경우
- 웹이나 모바일 앱에서 서버 기능을 호출할 때
- 외부 개발자에게 서비스 기능을 공개할 때
- 명확한 요청과 응답 규격이 필요한 서비스 간 통신
- 대규모 트래픽과 버전 관리가 필요한 운영 시스템
- 브라우저나 앱에서 직접 사용해야 할 때
2) MCP가 더 적합한 경우
- Claude Code나 Codex가 사내 도구를 사용해야 할 때
- AI가 로컬 파일이나 개발 도구에 접근해야 할 때
- 여러 AI 클라이언트에서 같은 기능을 재사용할 때
- 자연어 요청에 따라 AI가 적절한 기능을 선택해야 할 때
- 기존 API나 데이터베이스를 AI 작업 흐름에 연결할 때
3) 실제로는 같이 사용하는 경우가 많다
예를 들어 회사에 주문 조회 REST API가 이미 있다고 해보자.
웹 관리자 화면에서는 기존 REST API를 그대로 사용한다.
Claude Code나 사내 AI 에이전트가 주문을 조회해야 한다면, REST API를 호출하는 MCP Tool을 추가할 수 있다.
```text
웹 관리자
↓
REST API
Claude Code 또는 Codex
↓
MCP 서버
↓
같은 REST API
```
기존 API를 재사용하면서 AI 연결만 MCP로 표준화하는 구조다.
따라서 MCP를 도입한다고 기존 API 개발 경험이 필요 없어지는 것은 아니다.
오히려 실제 MCP 서버 개발에서는 API, 인증, 데이터베이스, 오류 처리, 네트워크에 대한 기존 백엔드 경험이 그대로 필요하다.
---
16. 직접 만들 때 자주 막힐 수 있는 부분
1) 절대 경로를 사용해야 한다
MCP 클라이언트가 어느 폴더에서 실행될지 항상 같지는 않다.
다음처럼 상대 경로를 사용하면 실행 위치에 따라 파일을 찾지 못할 수 있다.
```text
build/index.js
```
처음에는 다음처럼 절대 경로를 사용하는 것이 안전하다.
```text
C:/dev/project-search-mcp/build/index.js
```
2) TypeScript를 수정한 뒤 다시 빌드해야 한다
`src/index.ts`를 수정했더라도 MCP 클라이언트는 `build/index.js`를 실행한다.
수정 후에는 다시 빌드한다.
```powershell
npm run build
```
3) stdio 서버에서 console.log를 사용하지 않는다
표준 출력은 MCP 통신에 사용된다.
디버깅 로그는 다음처럼 표준 오류로 출력한다.
```typescript
console.error("디버깅 메시지");
```
4) Tool 이름과 설명을 구체적으로 작성한다
다음처럼 이름과 설명이 너무 추상적이면 AI가 언제 호출해야 할지 판단하기 어렵다.
```text
tool1
data 조회
```
다음처럼 목적과 검색 범위를 명확하게 쓰는 편이 좋다.
```text
search_projects
프로젝트 이름, 설명, 역할, 기술 스택에서 관련 프로젝트를 검색한다.
```
5) 쓰기 기능은 읽기 기능보다 더 신중해야 한다
이번 예제는 프로젝트 정보를 읽기만 한다.
하지만 실제 MCP 서버에서는 다음 기능도 만들 수 있다.
- 파일 수정
- Git 커밋
- 데이터베이스 변경
- 이슈 생성
- 배포 실행
- 이메일 전송
이런 Tool은 잘못 호출되면 실제 데이터가 바뀐다.
처음에는 조회 기능과 수정 기능을 분리하고, 수정이나 삭제 기능은 사용자 승인을 거치도록 설계하는 것이 좋다.
6) API 키를 코드에 직접 넣지 않는다
외부 API를 연결할 때는 API 키를 소스 코드에 넣지 않는 것이 기본이다.
환경변수로 전달하고, Git 저장소에 올라가지 않도록 주의해야 한다.
Claude Code와 Codex 모두 MCP 서버를 등록할 때 환경변수를 전달하는 방식을 지원한다.
7) AI의 호출 결과를 그대로 믿지 않는다
MCP를 연결했다고 결과가 항상 정확한 것은 아니다.
Tool에 전달된 입력값이 적절한지, 조회 결과가 완전한지, 쓰기 작업이 예상 범위를 넘지 않았는지 확인해야 한다.
AI 코딩 도구를 사용할 때와 마찬가지로 로그, 테스트, Git diff, 빌드 결과를 개발자가 직접 검증해야 한다.
---
17. 이 예제를 실제 프로젝트로 확장한다면
이번 예제는 배열에서 프로젝트를 검색하는 수준이다.
하지만 구조는 실제 업무용 MCP 서버로 그대로 확장할 수 있다.
1) 포트폴리오 MCP 서버
프로젝트 경력과 기술 스택을 저장해두고 채용공고와 맞는 프로젝트를 찾게 할 수 있다.
예를 들어 다음 Tool을 추가할 수 있다.
```text
search_projects
get_project_detail
find_projects_by_stack
match_job_posting
get_developer_profile
```
2) 사내 문서 검색 MCP 서버
Markdown, Notion, Google Drive, 사내 위키 같은 문서를 검색해 Claude Code나 Codex에 전달할 수 있다.
3) 데이터베이스 조회 MCP 서버
읽기 전용 계정을 사용해 주문, 통계, 장애 이력 등을 자연어로 조회할 수 있다.
운영 데이터베이스에 직접 쓰기 권한을 주는 것은 주의가 필요하다.
4) 유지보수 MCP 서버
서버 로그 검색, 배포 이력 확인, GitHub 이슈 조회, 모니터링 시스템 연결 기능을 하나의 MCP 서버에 묶을 수 있다.
5) 기존 REST API를 감싸는 MCP 서버
이미 운영 중인 API가 있다면 MCP 서버가 해당 API를 호출하고 결과를 AI가 사용하기 좋은 형태로 정리할 수 있다.
개인적으로는 이 방식이 실제 회사에서 MCP를 도입할 때 가장 현실적인 형태라고 본다.
---
18. MCP 서버 개발 경험이 채용공고에 등장하는 이유
MCP 서버의 예제 코드는 생각보다 짧다.
하지만 회사가 채용공고에서 원하는 MCP 경험은 단순히 Tool 하나를 등록해본 경험만을 뜻하지 않을 가능성이 높다.
실제로는 다음 능력을 함께 볼 수 있다.
1) 기존 API와 데이터베이스 구조를 이해할 수 있는가
2) AI가 사용하기 좋은 Tool 단위로 기능을 나눌 수 있는가
3) 입력 스키마와 설명을 명확하게 설계할 수 있는가
4) 인증과 권한을 안전하게 처리할 수 있는가
5) 오류, 타임아웃, 로그를 운영 수준으로 관리할 수 있는가
6) Claude Code나 Codex 같은 MCP 클라이언트에 연결할 수 있는가
7) AI가 잘못 호출할 가능성까지 고려할 수 있는가
MCP 자체만 보면 새로운 프로토콜이지만, 실제 서버를 안정적으로 만들려면 기존 백엔드 개발 경험이 중요하다.
AI가 코드를 대신 만들어주는 시대일수록, 어떤 기능을 열어줘도 되는지 판단하고 결과를 검증하는 개발자의 역할은 오히려 더 중요해진다.
---
19. 결론: MCP는 API를 없애는 기술이 아니다
간단한 프로젝트 검색 MCP 서버를 만들어 Claude Code와 Codex에 연결하는 흐름을 보면 MCP의 역할이 비교적 명확해진다.
REST API는 웹, 앱, 다른 서버가 기능과 데이터를 사용하도록 제공하는 인터페이스다.
MCP는 Claude Code나 Codex 같은 AI 클라이언트가 외부 기능을 발견하고, 입력값을 만들고, 결과를 받아 사용할 수 있도록 연결하는 공통 규격이다.
MCP 서버 안에서는 기존 API, 데이터베이스, 파일, 명령어를 그대로 사용할 수 있다.
따라서 MCP와 API 가운데 하나를 선택하는 문제가 아니다.
기존 시스템은 API로 운영하고, AI가 그 시스템을 사용해야 할 때 MCP를 연결하는 방식으로 보면 된다.
직접 간단한 서버를 만들어보니 MCP는 완전히 새로운 백엔드 기술이라기보다, 기존 개발 기능을 AI 작업 흐름 안으로 가져오는 연결 계층에 가까웠다.
한 줄로 정리하면 이렇다.
API가 기능을 제공하는 통로라면, MCP는 그 기능을 Claude Code와 Codex가 이해하고 사용할 수 있게 만드는 공통 어댑터다.
---
20. 참고한 공식 문서
- [Model Context Protocol 공식 소개](https://modelcontextprotocol.io/docs/getting-started/intro)
- [MCP 공식 TypeScript 서버 구축 가이드](https://modelcontextprotocol.io/docs/develop/build-server)
- [Claude Code MCP 연결 공식 문서](https://code.claude.com/docs/en/mcp)
- [Codex MCP 연결 공식 문서](https://developers.openai.com/codex/mcp)
'개발지식창고 > AI Dev Workflow' 카테고리의 다른 글
| ChatGPT 대화가 너무 길어졌을 때, 새 채팅에서 맥락 이어가는 방법 (0) | 2026.06.20 |
|---|---|
| Codex CLI와 Codex App을 같이 써보니 느낀 차이점 (0) | 2026.05.17 |
| Codex 초기 셋팅과 자주 쓰는 명령어 정리 (0) | 2026.05.09 |
| Claude Code 자주 쓰는 명령어 정리 (0) | 2026.05.06 |
| Windows 11에서 ChatGPT Codex로 Next.js 개발자 홍보 홈페이지 만들어보기 (0) | 2026.05.06 |



