전자세금계산서 MCP 설정 — Claude로 매입·매출 계산서 자동 처리하기
전자세금계산서 발행·조회 API를 MCP 서버로 래핑해 Claude 워크플로에 통합하는 방법을 단계별로 설명합니다. 홈택스 계산서 자동화부터 매입·매출 조회까지 Claude 세금계산서 연동 완전 가이드.
전자세금계산서 발행·조회 API를 MCP 서버로 감싸면 Claude에게 “이번 달 매입 계산서 목록 보여줘” 또는 “거래처별 매출 합계 정리해줘”라고 말하는 것만으로 홈택스 또는 중계사업자 API 데이터를 즉시 받아볼 수 있습니다. 이 가이드는 전자세금계산서 API 접근 방법을 파악하고, Node.js 기반 MCP 서버를 구성해 Claude Desktop에 연결하는 전 과정을 단계별로 안내합니다. 직접 API를 호출하는 MCP 서버를 구성하면 Excel 다운로드·수동 조회 없이 세금계산서 데이터를 대화형으로 처리할 수 있습니다.
전자세금계산서 MCP가 필요한 이유
국내 법인·개인사업자는 매월 홈택스에서 매입·매출 전자세금계산서를 조회하고, 부가세 신고 자료를 정리하는 반복 작업을 수행합니다. 홈택스 웹에 직접 접속해 검색 조건을 설정하고 엑셀로 내려받은 뒤 집계하는 과정은 번거롭고 오류 가능성이 높습니다.
MCP(Model Context Protocol)는 AI 클라이언트가 외부 도구를 표준화된 방식으로 호출할 수 있게 해주는 프로토콜입니다. 전자세금계산서 API를 MCP 서버로 래핑하면 Claude가 대화 안에서 계산서 데이터를 직접 조회하고, 집계·분류·이상 탐지 등의 분석 작업을 이어서 처리합니다. 세무 담당자나 1인 사업자가 반복적인 계산서 조회 업무를 Claude에게 위임할 수 있는 구조를 만드는 것이 핵심입니다.
데이터 흐름 구조
사용자 요청 ("이번 달 매입 세금계산서 목록 조회")
│
▼
Claude Desktop (MCP 클라이언트)
│ MCP 프로토콜 (JSON-RPC over stdio)
▼
전자세금계산서 MCP 서버 (로컬 Node.js 프로세스)
│ HTTPS REST API 호출 + API 키 인증
▼
전자세금계산서 API (홈택스 또는 중계사업자)
│ JSON 계산서 목록/상세 데이터 응답
▼
Claude가 데이터 파싱 → 집계·분석 → 자연어 답변
전자세금계산서 API 접근 경로 이해하기
국내에서 전자세금계산서 API를 연동하는 방법은 크게 두 가지입니다.
| 방법 | 특징 | API 키 발급 | 전자서명 필요 여부 |
|---|---|---|---|
| 국세청 홈택스 직접 연동 | 공식 API, 법인 대상 | 홈택스 사업자 등록 후 신청 | 공인전자서명 필요 |
| 공인 중계사업자 REST API | 간편 연동, SaaS 서비스 | 각 서비스 회원 가입 후 발급 | 서비스 내 처리(선택) |
홈택스 직접 연동은 공식 경로이지만 공인전자서명 처리가 복잡합니다. 중계사업자 API는 국세청에서 공인한 전자세금계산서 서비스들이 제공하는 REST API로, 인증서 처리를 서비스 측에서 담당해 MCP 서버 구성이 비교적 수월합니다. 이 가이드는 REST API 방식을 공통 기준으로 설명합니다. 실제 엔드포인트와 파라미터는 사용하는 서비스의 공식 API 문서를 참고하세요.
준비물
| 항목 | 설명 | 필수 여부 |
|---|---|---|
| Claude Desktop | Anthropic 공식 데스크톱 앱 | 필수 |
| Node.js 18 이상 | MCP 서버 실행 환경 | 필수 |
| 전자세금계산서 API 키 | 홈택스 또는 중계사업자 발급 | 필수 |
| 사업자등록번호 | API 인증에 사용 | 필수 |
| npm | Node.js와 함께 설치됨 | 필수 |
단계별 설정 방법
1단계: API 키 준비 및 접근 방법 파악
사용하는 전자세금계산서 서비스(홈택스 또는 중계사업자)의 API 문서를 확인해 다음 정보를 미리 준비합니다.
- API 기본 URL(Base URL)
- API 키 또는 토큰 인증 방식
- 매입 계산서 목록 조회 엔드포인트
- 매출 계산서 목록 조회 엔드포인트
- 날짜 범위, 페이징 파라미터 명칭
준비된 정보를 안전한 곳에 메모해 두고 2단계로 이동합니다.
2단계: MCP 서버 프로젝트 생성 및 의존성 설치
로컬에 새 디렉터리를 만들고 필요한 패키지를 설치합니다.
# 프로젝트 디렉터리 생성
mkdir etax-mcp-server && cd etax-mcp-server
# Node.js 패키지 초기화
npm init -y
# MCP SDK 및 HTTP 클라이언트, 환경변수 로더 설치
npm install @modelcontextprotocol/sdk node-fetch dotenv
설치 후 package.json에서 "type" 필드를 "module"로 변경합니다.
{
"name": "etax-mcp-server",
"version": "1.0.0",
"type": "module",
"main": "index.js",
"scripts": {
"start": "node index.js"
}
}
3단계: 환경 변수 파일 작성
프로젝트 루트에 .env 파일을 생성하고 API 인증 정보를 입력합니다.
touch .env
echo ".env" >> .gitignore
.env 파일 내용 예시(실제 서비스에 맞게 키 이름과 값 수정):
ETAX_API_BASE_URL=https://api.예시중계사업자.com/v1
ETAX_API_KEY=여기에_발급받은_API_키_입력
ETAX_BIZ_NO=1234567890
보안을 위해 .env는 반드시 .gitignore에 포함시키고 버전 관리에서 제외하세요.
4단계: 전자세금계산서 MCP 서버 코드 작성
아래는 매입·매출 계산서 목록 조회 도구를 구현한 MCP 서버 예시입니다. 실제 엔드포인트와 파라미터명은 사용하는 API 서비스 문서에 맞게 반드시 수정해야 합니다.
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
CallToolRequestSchema,
ListToolsRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
import fetch from "node-fetch";
import "dotenv/config";
const BASE_URL = process.env.ETAX_API_BASE_URL;
const API_KEY = process.env.ETAX_API_KEY;
const BIZ_NO = process.env.ETAX_BIZ_NO;
const server = new Server(
{ name: "etax-mcp-server", version: "1.0.0" },
{ capabilities: { tools: {} } }
);
// 도구 목록 반환
server.setRequestHandler(ListToolsRequestSchema, async () => ({
tools: [
{
name: "list_purchase_invoices",
description:
"지정한 기간의 매입 전자세금계산서 목록을 조회합니다. 발급일 기준 날짜 범위를 입력합니다.",
inputSchema: {
type: "object",
properties: {
startDate: {
type: "string",
description: "조회 시작일 (YYYY-MM-DD 형식, 예: 2026-07-01)",
},
endDate: {
type: "string",
description: "조회 종료일 (YYYY-MM-DD 형식, 예: 2026-07-31)",
},
},
required: ["startDate", "endDate"],
},
},
{
name: "list_sales_invoices",
description:
"지정한 기간의 매출 전자세금계산서 목록을 조회합니다. 발급일 기준 날짜 범위를 입력합니다.",
inputSchema: {
type: "object",
properties: {
startDate: {
type: "string",
description: "조회 시작일 (YYYY-MM-DD 형식)",
},
endDate: {
type: "string",
description: "조회 종료일 (YYYY-MM-DD 형식)",
},
},
required: ["startDate", "endDate"],
},
},
],
}));
// 공통 API 호출 함수
async function fetchInvoices(type, startDate, endDate) {
const endpoint = type === "purchase" ? "/invoices/purchase" : "/invoices/sales";
const url = `${BASE_URL}${endpoint}?bizNo=${BIZ_NO}&startDate=${startDate}&endDate=${endDate}`;
const res = await fetch(url, {
headers: {
Authorization: `Bearer ${API_KEY}`,
"Content-Type": "application/json",
},
});
if (!res.ok) {
const errText = await res.text();
throw new Error(`API 오류 (${res.status}): ${errText}`);
}
return res.json();
}
// 도구 실행 핸들러
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
try {
if (name === "list_purchase_invoices") {
const data = await fetchInvoices("purchase", args.startDate, args.endDate);
const items = data.items ?? [];
const totalVat = items.reduce((sum, inv) => sum + (inv.vat ?? 0), 0);
const totalAmount = items.reduce((sum, inv) => sum + (inv.amount ?? 0), 0);
return {
content: [
{
type: "text",
text: [
`[매입 세금계산서 조회 결과]`,
`기간: ${args.startDate} ~ ${args.endDate}`,
`건수: ${items.length}건`,
`공급가액 합계: ${totalAmount.toLocaleString()}원`,
`부가세 합계: ${totalVat.toLocaleString()}원`,
`---`,
...items.slice(0, 10).map(
(inv) =>
`• ${inv.issueDate ?? "-"} | ${inv.supplierName ?? "-"} | 공급가액 ${(inv.amount ?? 0).toLocaleString()}원 | 부가세 ${(inv.vat ?? 0).toLocaleString()}원`
),
items.length > 10 ? `... 외 ${items.length - 10}건` : "",
]
.filter(Boolean)
.join("\n"),
},
],
};
}
if (name === "list_sales_invoices") {
const data = await fetchInvoices("sales", args.startDate, args.endDate);
const items = data.items ?? [];
const totalVat = items.reduce((sum, inv) => sum + (inv.vat ?? 0), 0);
const totalAmount = items.reduce((sum, inv) => sum + (inv.amount ?? 0), 0);
return {
content: [
{
type: "text",
text: [
`[매출 세금계산서 조회 결과]`,
`기간: ${args.startDate} ~ ${args.endDate}`,
`건수: ${items.length}건`,
`공급가액 합계: ${totalAmount.toLocaleString()}원`,
`부가세 합계: ${totalVat.toLocaleString()}원`,
`---`,
...items.slice(0, 10).map(
(inv) =>
`• ${inv.issueDate ?? "-"} | ${inv.recipientName ?? "-"} | 공급가액 ${(inv.amount ?? 0).toLocaleString()}원 | 부가세 ${(inv.vat ?? 0).toLocaleString()}원`
),
items.length > 10 ? `... 외 ${items.length - 10}건` : "",
]
.filter(Boolean)
.join("\n"),
},
],
};
}
throw new Error(`알 수 없는 도구: ${name}`);
} catch (err) {
return {
content: [{ type: "text", text: `오류: ${err.message}` }],
};
}
});
const transport = new StdioServerTransport();
await server.connect(transport);
주의: 위 코드의 엔드포인트(/invoices/purchase, /invoices/sales), 응답 필드명(items, vat, amount, supplierName 등)은 예시입니다. 실제 API 문서의 명세에 맞게 반드시 수정해야 합니다. 존재하지 않는 엔드포인트를 그대로 사용하면 연결되지 않습니다.
5단계: Claude Desktop 설정 파일에 MCP 서버 등록
Claude Desktop의 설정 파일을 열어 서버를 추가합니다.
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json
{
"mcpServers": {
"etax-mcp": {
"command": "node",
"args": ["/절대경로/etax-mcp-server/index.js"],
"env": {
"ETAX_API_BASE_URL": "https://api.예시중계사업자.com/v1",
"ETAX_API_KEY": "여기에_API_키_입력",
"ETAX_BIZ_NO": "사업자등록번호_10자리"
}
}
}
}
macOS/Linux에서 프로젝트 디렉터리 안에서 pwd 명령을 실행하면 절대 경로를 확인할 수 있습니다.
6단계: Claude Desktop 재시작 및 동작 확인
설정 파일 저장 후 Claude Desktop을 완전히 종료하고 다시 시작합니다. 이후 채팅창에 다음과 같이 입력해 보세요.
2026년 7월 매입 전자세금계산서 목록을 조회해서 공급업체별로 정리해줘.
Claude가 list_purchase_invoices 도구를 호출하고 계산서 목록과 합계를 응답하면 연결이 성공한 것입니다.
흔한 오류와 해결 방법
| 오류 증상 | 주요 원인 | 해결 방법 |
|---|---|---|
| HTTP 401 Unauthorized | API 키 누락 또는 만료 | .env 또는 설정 파일의 API 키 재확인, 재발급 검토 |
| HTTP 403 Forbidden | 사업자등록번호 불일치 또는 권한 없음 | ETAX_BIZ_NO 값을 하이픈 없는 10자리로 재입력 |
| HTTP 404 Not Found | 엔드포인트 URL 오류 | API 문서의 실제 경로와 BASE_URL 재확인 |
| 빈 items 배열 반환 | 날짜 범위에 계산서 없음 | 조회 기간 확인, API 날짜 형식(YYYYMMDD vs YYYY-MM-DD) 확인 |
| MCP 서버 연결 안 됨 | 파일 절대 경로 오류 | pwd로 확인한 절대 경로로 수정 |
| node 명령 인식 실패 | Node.js 미설치 또는 PATH 미등록 | Node.js 18 이상 설치 후 터미널 재시작 |
날짜 형식 주의: 일부 API는 날짜를 YYYY-MM-DD가 아닌 YYYYMMDD(하이픈 없음) 형식으로 요구합니다. 연동하는 API 문서에서 날짜 파라미터 형식을 반드시 확인하세요.
활용 예시 — Claude와 함께할 수 있는 세무 작업
전자세금계산서 MCP 서버를 연결하면 다음과 같은 작업을 대화 형태로 처리할 수 있습니다.
| 활용 시나리오 | Claude 입력 예시 |
|---|---|
| 월별 부가세 집계 | ”7월 매입 세금계산서의 부가세 합계를 알려줘” |
| 거래처별 매출 분석 | ”2분기 매출 계산서를 거래처별로 정렬하고 상위 5곳 보여줘” |
| 누락 계산서 탐지 | ”매입 계산서 목록에서 1,000만 원 이상 거래 중 특이 사항 있으면 알려줘” |
| 부가세 신고 자료 준비 | ”1기 확정 신고(1~6월) 매출·매입 부가세 합계를 표로 정리해줘” |
법령 연동으로 세무 정확성 높이기
전자세금계산서 MCP만으로는 “이 거래에 부가세가 맞게 적용됐나?” 같은 법적 해석이 어렵습니다. 한국 법령 MCP를 함께 설정하면 Claude가 부가가치세법 조문을 실시간으로 검색해 계산서 처리 기준을 설명할 수 있습니다. 법령·판례 검색이 필요하면 한국 법령 MCP 서버도 참고하세요.
계약서 자동 생성이 필요한 경우 한국 계약서 자동생성 MCP를 함께 사용하면 세금계산서 발행 기반 거래 계약서를 Claude Code에서 자동으로 작성할 수 있습니다.
법률·세금 카테고리에서 국내 세무·법률 관련 MCP 서버를 더 찾아보세요. 전체 MCP 서버 목록에서도 다양한 한국형 MCP 서버를 탐색할 수 있습니다.
자주 묻는 질문
홈택스 전자세금계산서 API는 누구나 신청할 수 있나요?
국세청 홈택스 전자세금계산서 API는 사업자등록이 된 법인·개인사업자가 신청할 수 있습니다. API 접근 방법은 국세청 전자세금계산서 포털(hometax.go.kr) 또는 공인된 전자세금계산서 중계사업자를 통한 간접 연동 두 가지가 있습니다. 중계사업자 API는 회원 가입만으로 발급받을 수 있어 개인사업자에게 더 접근하기 편리합니다.
전자세금계산서와 전자계산서(면세)의 차이점은 무엇인가요?
전자세금계산서는 부가가치세 과세 거래에 발행하고, 전자계산서는 면세 거래(의료·교육 등)에 발행합니다. API 호출 엔드포인트와 전송 필드가 다르므로 연동 대상 거래 유형을 먼저 확인해야 합니다. 과세·면세 거래를 모두 처리한다면 두 종류의 도구를 각각 MCP 서버에 구현하는 것이 좋습니다.
Claude가 실제로 세금계산서를 발행할 수 있나요?
MCP 서버에 발행 API 도구를 구현하면 Claude가 도구를 호출해 발행 요청을 보낼 수 있습니다. 단, 전자서명(공인인증서)이 필요한 경우 서버 측에서 인증서를 처리해야 하며, 세법상 발행 책임은 사업자에게 있으므로 자동화 적용 전 세무사와 검토를 권장합니다.
API 없이도 홈택스 세금계산서를 MCP로 연동할 수 있나요?
홈택스 웹 스크래핑 방식은 이용약관 위반 소지가 있어 권장하지 않습니다. 공인 중계사업자 API를 활용하면 별도 전자서명 없이도 간편하게 연동할 수 있습니다. 공인 중계사업자 목록은 국세청 홈택스 공지사항에서 확인할 수 있습니다.
한국 법령 MCP와 전자세금계산서 MCP를 함께 써서 부가세 규정을 자동으로 확인할 수 있나요?
네, 가능합니다. 한국 법령 MCP로 부가가치세법 조문을 조회하고, 전자세금계산서 MCP로 실제 거래 데이터를 불러온 뒤, Claude가 두 맥락을 합쳐 세법 적용 여부를 분석하는 워크플로를 구성할 수 있습니다.
MCP 서버가 오류를 반환할 때 가장 먼저 확인할 곳은 어디인가요?
터미널에서 node index.js를 직접 실행해 오류 로그를 확인하세요. 주요 원인은 API 키 오류(401), 사업자등록번호 형식 불일치, 날짜 범위 초과, 네트워크 방화벽 차단 순서로 점검하면 빠르게 원인을 찾을 수 있습니다.
다음 단계
전자세금계산서 MCP 서버를 구성했다면, 이제 Claude에게 반복적인 세금계산서 조회·집계 업무를 맡길 수 있습니다. 부가세 신고 기간에는 “1기 확정 신고 기간(1~6월)의 매입·매출 부가세 합계를 표로 정리해줘”라고 입력하는 것만으로 신고 준비 자료를 빠르게 확인할 수 있습니다.
한국 법령 MCP를 함께 설치하면 세금계산서 처리 기준, 가산세 규정, 면세 범위 등 세법 조문을 Claude가 실시간으로 참조하며 더 정확한 세무 지원을 받을 수 있습니다. 새로운 전자세금계산서 연동 MCP 서버를 개발하셨다면 MCP모아 등록 페이지에서 공유해 주세요.