12. 역할별 권한 경계 검증

→ MCP 조회 성공과 UPDATE 차단, inventory_operator의 DELETE·DDL 차단을 직접 확인합니다.

더보기

이 강의는 MCP 연결 표시만 확인하고 끝나지 않습니다.

허용한 조회는 성공하고 허용하지 않은 쓰기는 거부되는지 모두 확인해야 합니다.

 

12.1 MCP에서 세 테이블 조회하기

 

Claude Code에 다음과 같이 요청합니다.

[화면 캡처: Claude Code가 실행 전 SELECT SQL을 제시]
inventory DB의 테이블 목록과 각 테이블의 행 수를 확인해줘.

조건:
- 실행할 SELECT SQL을 먼저 보여준다.
- products, stock_logs, operation_requests를 확인한다.
- 확인하지 못한 열이나 데이터는 추측하지 않는다.

내가 SQL을 검토하고 승인하기 전에는 실행하지 마.

 

Claude Code가 제안한 SQL에서 다음 내용을 확인합니다.

  • SELECT만 포함되어 있는가?
  • 세 실습 테이블을 모두 조회하는가?
  • 데이터 변경 문장이 없는가?

SQL을 검토한 뒤 실행을 승인합니다.

[화면 캡처: Claude Code가 실행 전 SELECT SQL을 제시하고 승인을 기다리는 화면]

 

[화면 캡처: MCP 조회 결과 세 테이블의 행 수가 표시된 화면]

 

테이블 기대 행 수
products 8
stock_logs 16
operation_requests 0

 

 

 

12.2 MCP에서 UPDATE 차단 확인하기

 

는 MCP 서버의 쓰기 제한과 inventory_reader의 DB 권한이 함께 적용되는 연결 경로에서 다시 확인합니다.

현재 값을 같은 값으로 다시 저장하는 UPDATE를 요청합니다. 실제 값은 바뀌지 않지만 UPDATE 권한이 필요한 SQL입니다.

[화면 캡처: Claude Code가 UPDATE SQL을 제시하고 승인을 기다리는 화면]
inventory.products에서 product_id가 1인 행의
stock_quantity를 현재 값으로 다시 저장하는 UPDATE를 준비해줘.

조건:
- 실행할 SQL을 먼저 보여준다.
- 다른 행과 다른 열은 변경하지 않는다.
- 권한 오류나 읽기 전용 차단 메시지를 그대로 설명한다.

내가 승인하기 전에는 실행하지 마.

 

검토할 SQL은 다음과 같습니다.

UPDATE inventory.products
SET stock_quantity = stock_quantity
WHERE product_id = 1;

 

승인 후에도 MCP 서버의 쓰기 제한 또는 MySQL 계정 권한에서 실행이 거부되어야 합니다.

[화면 캡처: MCP의 UPDATE 요청이 권한 오류로 거부된 화면]



 

12.3 inventory_operatorDELETE와 DDL 차단 확인하기

 

inventory_operator는 이후 강의에서 제한된 변경을 수행하지만, 삭제와 DB 구조 변경은 수행할 수 없어야 합니다. 터미널에서 직접 접속합니다.

mysql \
  -h 127.0.0.1 \
  -u inventory_operator \
  -p \
  inventory

 

존재하지 않는 행을 대상으로 DELETE 권한을 확인합니다.

DELETE FROM stock_logs
WHERE log_id = 0;

 

테이블 생성 권한을 확인합니다.

CREATE TABLE permission_test (
  id INT PRIMARY KEY
);

 

두 SQL 모두 권한 오류로 거부되어야 합니다.

관리자 연결에서 permission_test가 생성되지 않았는지 확인합니다.

SHOW TABLES LIKE 'permission_test';

 

조회 결과가 없어야 합니다.

 

 

 

12.4 차단 실습 후 기준 데이터 다시 확인하기

 

Claude Code의 MCP 조회 또는 inventory_reader 직접 연결에서 다음 SQL을 실행합니다.

SELECT COUNT(*) AS products_count
FROM products;

SELECT COUNT(*) AS stock_logs_count
FROM stock_logs;

SELECT COUNT(*) AS operation_requests_count
FROM operation_requests;

SELECT
  product_id,
  product_name,
  stock_quantity
FROM products
WHERE product_id = 1;

 

기대 결과는 다음과 같습니다.

  • products: 8건
  • stock_logs: 16건
  • operation_requests: 0건
  • 상품 1번의 stock_quantity: 25

▶ 지금 해보세요

  1. MCP에서 세 테이블의 행 수를 조회합니다.
  2. 현재 값을 같은 값으로 저장하는 UPDATE를 요청하고 거부를 확인합니다.
  3. inventory_operatorDELETECREATE TABLE이 거부되는지 확인합니다.
  4. 기준 데이터와 상품 1번 재고가 바뀌지 않았는지 다시 조회합니다.

✔ 보안 원칙: MCP 서버 설정과 MySQL 계정 권한을 함께 사용합니다. 한쪽 설정이 잘못되어도 다른 쪽에서 쓰기를 막을 수 있어야 합니다. MCP에서 세 테이블을 조회할 수 있고, MCP의 UPDATE 요청이 거부되고, inventory_operatorDELETE와 DDL이 거부되며, 차단 실습 후 기준 데이터가 8 / 16 / 0과 상품 1번 재고 25로 유지됩니다.

 

13. MySQL 계정과 MCP 연결 오류 해결하기

→ 문제가 생겼을 때 원인을 좁히는 순서와 증상별 확인 항목을 정리합니다.

더보기

문제가 생기면 다음 순서로 원인을 좁힙니다. 설정을 무작정 다시 만들지 않습니다.

MySQL 서비스 실행
  ↓
inventory DB와 세 테이블 존재
  ↓
inventory_reader 직접 접속과 SELECT
  ↓
SHOW GRANTS의 계정·호스트 확인
  ↓
node와 npx 실행
  ↓
claude mcp get의 등록 정보
  ↓
Claude Code /mcp 연결 상태

 

증상 먼저 확인할 항목 해결 방향
Unknown database 'inventory' db/schema.sql 실행 여부 관리자 연결로 스키마 스크립트 실행
Access denied 사용자명, 비밀번호, 계정 호스트 SHOW GRANTS와 MCP 환경변수 대조
npx를 찾을 수 없음 Node.js와 npx 실행 상태 기존 Node.js 설치 자료로 환경 복구
MCP가 연결되지 않음 MCP 환경변수와 서버 실행 명령 claude mcp get mysql-inventory 확인
조회 결과가 비어 있음 기준 데이터 입력 여부 직접 조회에서 8 / 16 / 0 상태 확인
inventory_readerUPDATE가 실행됨 연결 계정과 ALLOW_UPDATE_OPERATION MCP 제거 후 계정·설정 재구성
inventory_operatorDELETE가 실행됨 잘못 부여된 권한 관리자 연결에서 권한 회수 후 재검증

 

MCP 등록 정보를 확인하거나 잘못된 설정을 제거할 때 다음 명령을 사용합니다.

claude mcp get mysql-inventory
claude mcp remove mysql-inventory

 

⚠ 주의: 연결 오류를 해결하기 위해 관리자 계정을 MCP에 연결하거나 inventory_reader의 쓰기 권한을 넓히지 않습니다.

 

13. 이번 강의 완료 기준

→ 체크리스트로 1강 완료 상태를 점검하고, 2강으로 넘기는 상태를 확인합니다.

더보기

13.1 최종 체크리스트

 

다음 항목을 모두 확인합니다.

  • ☐ MySQL, Claude Code, Node.js와 npx가 실행됩니다.
  • inventory-mysql-app 프로젝트 구조가 존재합니다.
  • products, stock_logs, operation_requests가 생성되었습니다.
  • ☐ 상품 8개, 입출고 이력 16건, 실행 요청 0건입니다.
  • ☐ 기존 입출고 이력 16건의 request_id가 모두 NULL입니다.
  • ☐ 구축에 사용한 관리자 연결의 실제 권한을 SHOW GRANTS로 확인했습니다.
  • inventory_reader, inventory_operator, inventory_app 계정이 분리되어 있습니다.
  • inventory_readerSELECT만 가능합니다.
  • inventory_operator는 필요한 DML만 가능하고 DELETE·DDL은 불가능합니다.
  • inventory_app은 1강에서 SELECT만 가능합니다.
  • ☐ 관리자 계정은 MCP 설정에 사용되지 않았습니다.
  • ☐ Claude Code의 MCP 접근과 Python 소스 코드의 Driver 접근을 구분할 수 있습니다.
  • mysql-inventory MCP가 inventory_reader 계정으로 연결됩니다.
  • ☐ MCP 조회에서 세 테이블의 기준 건수 8 / 16 / 0을 확인했습니다.
  • ☐ MCP의 UPDATE가 차단됩니다.
  • inventory_operatorDELETE와 DDL이 차단됩니다.
  • ☐ 차단 실습 후 기준 데이터가 변경되지 않았습니다.

 

 

 

13.2 완성 구조

 

inventory-mysql-app/  # ✅ 프로젝트 구조 생성
├── db/
│   ├── schema.sql    # ✅ 테이블 설계
│   └── roles.sql     # ✅ 계정 설계
├── harness/          # ✅ (빈 폴더)
└── app/              # ✅ (빈 폴더)

inventory DB                     # ✅ DB 구현
├── products                 8건 # ✅ 테이블과 데이터 구현 
├── stock_logs              16건 # ✅ 테이블과 데이터 구현
└── operation_requests       0건 # ✅ 테이블과 데이터 구현

DB 접근 경로와 계정
├── Claude Code MCP  ───── inventory_reader   # ✅ 계정 구현 + MCP 연동
├── Python 하니스    ───── inventory_operator  # ✅ 계정만 구현 + 연동X
└── PySide6 앱       ───── inventory_app       # ✅ 계정만 구현 + 연동X

 

 

 

13.3 이번 강의에서 아직 하지 않는 작업

 

  • Python 실행 하니스 작성
  • inventory_operator를 사용한 실제 재고 변경
  • 트랜잭션과 행 잠금 적용
  • 변경 대상 미리 보기
  • 실행 승인과 요청 ID 중복 차단
  • 요청과 재고 이력의 증거 흐름 분석
  • PySide6 화면과 inventory_app 쓰기 기능 구현
  • MCP, 실행 하니스, 앱 중 작업 위치를 선택하는 세부 판단 기준

위 작업은 3~8강에서 순서대로 수행합니다.

 

 

 

13.4 다음 강의로 넘기는 상태

 

2강은 다음 상태에서 시작합니다.

  • inventory DB가 존재합니다.
  • 세 테이블의 구조가 확정되어 있습니다.
  • 상품 8개와 입출고 이력 16건이 존재합니다.
  • operation_requests는 비어 있습니다.
  • Claude Code의 MySQL MCP가 읽기 전용으로 연결되어 있습니다.
  • MCP 조회 결과와 MySQL 직접 조회 결과를 대조할 수 있습니다.

2강에서는 이 상태를 이용하여 AI가 생성한 조회 SQL과 결과를 다음 네 요소로 나누어 검증합니다.

자연어 요청
  ↕
실제 스키마
  ↕
AI가 생성한 SELECT SQL
  ↕
실행 결과

 

 

 

13.5 참고 문서

 

공식 문서: Claude Code MCP 공식 문서

 

Connect Claude Code to tools via MCP - Claude Code Docs

Learn how to connect Claude Code to your tools with the Model Context Protocol.

code.claude.com

 

 

그 밖에 MySQL MCP 서버 후보 저장소를 참고하세요. 이 저장소는 Claude Code 공식 문서와 별개의 공개 구현입니다. 실제 수업에 적용하기 전에 저장소 상태, 라이선스, 요구 Node.js 버전, 환경변수 이름을 다시 확인합니다.

→ 다음 강의 (2강): 이번 강의에서 연결한 읽기 전용 MCP를 사용해, AI가 생성한 조회 SQL과 결과를 요청 조건·실제 스키마와 대조해 검증하는 습관을 만듭니다.

 

14. 실습 과제

→ 계정·권한 대응표 작성, 최소 권한 오류 찾기, 권한 제한 결과 제출로 1강 내용을 스스로 점검합니다.

더보기

14.1 계정과 DB 접근 경로 대응표 작성하기

 

다음 작업을 수행할 계정과 접근 경로를 선택하고 근거를 작성합니다.

작업 접근 경로 선택할 계정 선택 근거
Claude Code에서 상품 목록 조회      
5강 실행 하니스에서 재고 수량 갱신      
PySide6 앱에서 상품 목록 조회      
테이블 생성      
재고 이력 삭제      

 

✔ 완료 기준:

· Claude Code의 DB 조회에 MySQL MCP와 inventory_reader를 선택했습니다.

· 실행 하니스의 승인된 변경에 MySQL Driver와 inventory_operator를 선택했습니다.

· PySide6 앱의 조회에 MySQL Driver와 inventory_app을 선택했습니다.

· 테이블 생성은 세 역할별 계정의 담당 작업이 아니라고 판단했습니다.

· 재고 이력 삭제는 허용하지 않는 작업이라고 판단했습니다.

 

 

 

14.2 최소 권한 오류 찾기

 

다음 권한 설정의 문제를 찾고 수정합니다.

GRANT ALL PRIVILEGES
ON inventory.*
TO 'inventory_reader'@'127.0.0.1';

GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, ALTER, DROP
ON inventory.*
TO 'inventory_operator'@'127.0.0.1';

 

✔ 완료 기준:

· inventory_readerSELECT 전용으로 수정했습니다.

· inventory_operator에서 DELETE와 DDL 권한을 제거했습니다.

· inventory_operatorUPDATE 범위를 products.stock_quantity로 제한했습니다.

· 필요한 INSERT 대상 테이블을 구분했습니다.

 

 

 

14.3 권한 제한 결과 제출하기

 

다음 결과를 캡처하거나 텍스트로 기록합니다.

  1. 관리자 연결의 SHOW GRANTS
  2. inventory_reader 직접 연결의 SELECT 성공
  3. inventory_reader 직접 연결의 UPDATE 차단 메시지
  4. inventory_operatorDELETE 차단 메시지
  5. inventory_operatorCREATE TABLE 차단 메시지
  6. MCP의 세 테이블 조회 성공
  7. MCP의 UPDATE 차단 메시지
  8. 차단 실습 후 8 / 16 / 0 기준 건수

 

✔ 완료 기준:

· 허용 작업과 차단 작업의 결과가 모두 포함되어 있습니다.

· 오류 메시지를 임의로 성공 메시지로 바꾸지 않고 핵심 문구를 기록했습니다.

· 차단 실습 후 데이터가 변경되지 않았음을 확인했습니다.