Azure Files MCP
Azure Files MCP (읽기 전용)
원격 MCP 서버로, Claude에게 Azure Files SMB 공유의 한 폴더에 대한 읽기 전용 액세스를 제공합니다. 각 연결 사용자는 자신의 NTFS 권한이 허용하는 내용만 볼 수 있습니다.
두 가지 도구만 있으며, 그 외에는 없습니다:
list_directory(path)- 구성된 루트 폴더 아래의 파일/폴더를 나열합니다.read_file(path)- 구성된 루트 폴더 아래의 파일 내용을 읽습니다. 일반 텍스트 파일은 그대로 반환되고, PDF, Word(.docx), Excel(.xlsx)은 자동으로 텍스트로 변환됩니다(아래 "PDF/Word/Excel 파일 읽기" 참조).
이 코드베이스에는 쓰기, 삭제, 이름 변경 도구가 전혀 없습니다. 스텁으로 처리되지도, 구성으로 비활성화되지도, 그냥 존재하지 않습니다.
단계별 Azure/Entra 설정 지침은 SETUP.md를 참조하세요. 이 파일은 아키텍처와 설계 결정을 다루고, SETUP.md는 포털에서 클릭별로 진행하는 방법을 다룹니다.
티켓을 처음 읽었을 때 예상하는 것과는 조금 다른 이유
원래 설계는 다음과 같았습니다: 비권한 Storage File Data SMB Share Reader RBAC 역할을 할당한 다음, 각 사용자의 자체 OAuth 토큰으로 Azure Files의 FileREST API를 호출하면 Azure가 사용자별로 NTFS ACL을 자동으로 적용할 것이라고 가정했습니다.
그것은 작동하지 않습니다. Microsoft의 REST API 문서(Microsoft Entra ID로 인증 (REST API))에서 직접 확인했습니다: 모든 FileREST 읽기 작업(디렉터리 및 파일 나열, 파일 가져오기, 파일 속성 가져오기 등)에는 .../files/read 와 .../readFileBackupSemantics/action 이 모두 필요합니다. readFileBackupSemantics/action - NTFS ACL 평가를 명시적으로 건너뛰는 모드를 가리키는 Microsoft 자체 용어 - 은 Storage File Data Privileged Reader/Contributor 에 의해서만 부여됩니다. Storage File Data SMB Share Reader는 REST 권한 표에 전혀 나타나지 않습니다 - 이는 실제 SMB 프로토콜 연결(포트 445, Kerberos)에만 적용되며, Node HTTPS 백엔드가 FileREST를 호출할 때는 사용할 수 없습니다.
따라서 REST를 통해서는 역할이 권한이 있거나(ACL 우회) 무관합니다. Azure 자체가 요청별 REST/OAuth 기준으로 NTFS ACL을 적용하도록 하는 방법은 없습니다.
이 서버가 대신 하는 일: Storage File Data Privileged Reader (여전히 읽기 전용, 여전히 사용자별 인증 - 아래 참조)를 사용하고, Azure Files가 모든 파일/폴더에 대해 노출하는 실제 보안 설명자를 사용하여 코드에서 NTFS 권한을 자체적으로 적용합니다:
파일/폴더의 NTFS 권한을 SDDL 문자열로 가져옵니다(
getPermissionREST 호출).DACL을 개별 ACE로 구문 분석합니다(
src/acl/sddl.ts- 직접 작성; 이를 위한 유지 관리되는 Node/TS 라이브러리는 없습니다).Microsoft Graph를 통해 호출 사용자 자신의 온-프레미스 AD SID와 그들이 전이적으로 속한 모든 그룹 SID를 확인합니다(
src/graph/sidResolver.ts).실제 Windows AccessCheck 의미 체계를 사용하여 해당 SID 집합에 대해 DACL을 평가합니다 - 명시적 거부는 명시적 허용보다 우선하며, 언급되지 않은 비트는 기본적으로 거부됩니다(
src/acl/evaluate.ts).
이것은 진정한 사용자별 적용입니다. Azure의 RBAC 계층에 위임하는 대신 여기서 구현했을 뿐입니다. Azure에는 REST로 호출 가능한 메커니즘이 없기 때문입니다. 실제 보안 경계는 이 코드베이스이지 Azure RBAC가 아닙니다 - 아래 내용을 추론할 때 이 점을 명심하세요.
아키텍처
이 서버는 자체 OAuth 2.1 인증 서버입니다. Claude는 Entra와 직접 통신하지 않습니다. 이것은 의도적인 설계 선택이며, 명백한 선택이 아니므로 그 이유를 설명할 가치가 있습니다: MCP 사양은 클라이언트가 MCP 서버의 자체 URL과 동일한 RFC 8707 resource 매개변수를 보내도록 요구하며, Entra는 앱 등록의 확인된 식별자 URI와 일치하는 resource 값만 허용합니다. Entra는 *.azurewebsites.net URL을 (확인되지 않은 도메인)으로 등록하는 것을 단호히 거부합니다 - AADSTS9010010으로 실시간 확인되었으며, 포털 설정으로는 수정할 수 없습니다. 따라서 대신 Claude는 이 서버에 대해 인증하고(자체 URL이 리소스 검사를 쉽게 충족), 서버는 실제 로그인을 백그라운드에서 Entra로 중계하며(src/auth/mcpOAuthProvider.ts), Claude에게 Entra의 실제 수정되지 않은 액세스 토큰을 돌려줍니다. 그 핸드오프 이후에는 모든 것이 일반 Entra 발급 베어러 토큰으로 정상적으로 작동합니다.
모든 읽기 요청:
Claude는 이 서버 자체의
/authorize및/token엔드포인트(src/auth/mcpOAuthProvider.ts)를 통해 인증하며, 이는/oauth/callback경로를 통해 실제 로그인을 Entra로 중계하고 Entra의 실제 액세스 토큰(대상 = 이 앱의 Entra 앱 등록)을 돌려줍니다. 이 서버는 들어오는 요청에서 토큰을 검증만 합니다(src/auth/tokenVerifier.ts- Entra의 JWKS를 통한 서명, 발급자, 대상, 만료) - 자체적으로 발급하거나 서명하지 않습니다.path는 Azure 호출 전에 정규화되고 구성된 루트 폴더에 대해 확인됩니다(src/files/pathScope.ts) - 루트 밖으로 해석되는 경로는 토큰이 허용하는 것과 관계없이 거부됩니다.들어오는 사용자 토큰은 OAuth2 on-behalf-of 흐름(
src/auth/obo.ts,@azure/identity의OnBehalfOfCredential)을 통해https://storage.azure.com/.default로 범위가 지정된 새 토큰으로 교환됩니다. 모든 Azure Files 호출은 이 사용자별 토큰으로 이루어집니다(src/files/shareClient.ts) - 공유 서비스 주체나 정적 키가 아닙니다.파일/디렉터리의 NTFS 권한을 가져와 사용자가 보유한 SID에 대해 평가합니다(
src/graph/sidResolver.ts+src/acl/). 액세스가 허용되지 않으면 도구는 권한 거부 오류를 반환하고 그 외에는 아무것도 반환하지 않습니다.액세스가 허용된 경우에만 도구는 3단계에서 이미 가져온 디렉터리 목록이나 파일 내용을 반환합니다 - PDF/Word/Excel의 경우 먼저 일반 텍스트로 변환됩니다(아래 참조).
모든 호출(허용, 거부, 오류)은 사용자, 요청된 경로, 결과를 기록하는 구조화된 감사 로그 한 줄을 생성합니다(
src/audit/log.ts). 아래 "감사 로깅" 참조.
사용자 자신의 SID/그룹 SID를 확인하는 것은 OBO가 아닌 앱 전용 Graph 클라이언트 자격 증명 호출(src/graph/sidResolver.ts)을 사용합니다. 이는 의도적입니다: 파일 데이터가 아닌 ID 메타데이터(이 사용자가 속한 그룹)이므로 공유 앱 ID를 사용해도 "파일 데이터 읽기에 공유 자격 증명을 사용하지 않음"을 위반하지 않습니다 - 실제 Azure Files 읽기는 전체적으로 엄격히 사용자별로 유지됩니다.
resolveHeldSids는 모든 list_directory/read_file 호출에서 실행되므로 그 결과(사용자 자신의 SID와 모든 전이 그룹 SID)는 사용자별로 SID_CACHE_TTL_MS(기본 5분, .env.example 참조) 동안 메모리에 캐시됩니다 - 캐시 적중 시 Microsoft Graph를 완전히 건너뜁니다. 그룹 구성원 변경은 충분히 드물어서 이 캐시는 요청당 지연 시간과 Graph 부하를 실질적으로 줄이면서 권한 변경 시 오래된 정보 창을 크게 넓히지 않습니다. 캐시를 비활성화하려면 SID_CACHE_TTL_MS=0으로 설정하세요(예: 나타나지 않는 권한 변경을 디버깅하는 동안).
1단계의 OAuth 중계는 진행 중인 로그인을 두 개의 수명이 짧고 일회용인 메모리 내 맵(pendingAuthorizations, issuedCodes in mcpOAuthProvider.ts)으로 추적합니다. 단일 App Service 인스턴스에는 문제가 없지만, 이 서버는 해당 상태를 공유 저장소(예: Redis)로 옮기기 전에는 한 인스턴스 이상으로 확장해서는 안 됩니다 - 두 번째 인스턴스는 다른 인스턴스에서 시작되어 다른 인스턴스에서 완료된 로그인을 무작위로 실패시킬 수 있습니다.
PDF/Word/Excel 파일 읽기
read_file은 몇 가지 일반적인 이진 문서 형식을 서버 측에서 일반 텍스트로 변환합니다(src/files/textExtract.ts). 이 커넥터의 결과를 렌더링하는 MCP 클라이언트는 Claude가 추론할 수 있도록 이진 "리소스" blob을 자체적으로 구문 분석할 수 없기 때문입니다 - 채팅에서 실제로 읽을 수 있는 것은 텍스트 내용뿐입니다. 처리되는 형식: .pdf, .docx, .xlsx. 처리되지 않는 형식: 레거시 이진 .doc/.xls(2007 이전 Office 형식)는 읽을 수 없는 blob을 반환하고, 스캔/이미지 전용 PDF는 쓰레기 대신 "추출 가능한 텍스트 없음"이라는 명확한 메시지를 반환합니다(OCR 없음). 추출 출력은 원시 파일 크기 제한(MAX_READ_FILE_BYTES)과 독립적으로 제한됩니다. 밀도 높은 스프레드시트의 텍스트 형태가 이진 크기를 초과할 수 있기 때문입니다.
감사 로깅
읽기 액세스는 Azure RBAC가 아닌 이 서버 자체 코드에서 전적으로 적용되므로(위 참조) 다른 곳에는 감사 추적이 없습니다 - 이 서버의 감사 로그(src/audit/log.ts)가 전부입니다. 모든 list_directory/read_file 호출은 결과에 관계없이 정확히 하나의 JSON 줄을 stdout으로 생성합니다: 타임스탬프, 도구 이름, 요청된 경로, 호출 사용자의 oid 및 UPN, 결정(granted / denied / error), granted 이외의 경우 이유, 호출에 걸린 시간. 로깅 라이브러리를 통하지 않고 일반 console.log JSON 줄로 작성되므로 배포 대상이 이미 수집하는 stdout 로그 파이프라인(예: Azure App Service의 로그 스트림 / Log Analytics)으로 추가 연결 없이 흘러갑니다.
필수 Azure/Entra 구성(이 저장소에서 자동화되지 않음)
전체 클릭별 단계는 SETUP.md에 있습니다. 실제로 필요한 것의 요약:
RBAC: 이 커넥터를 사용할 수 있어야 하는 Entra 그룹에 Storage File Data Privileged Reader(읽기 전용, Contributor 사용 금지)를 스토리지 계정 자체 범위로 할당합니다. 이는 원래 티켓의 SMB Share Reader 역할을 대체합니다 - 위 근거 참조. 이것은 "이 사람이 아예 요청할 수 있는지"를 판별하는 대략적인 게이트이며 실제 권한 검사가 아닙니다 - 실제 NTFS 권한(코드에서 적용, 위 참조)이 각 사용자가 실제로 보는 내용을 계속 제어합니다.
앱 등록: 하나의 앱 등록이 세 가지 역할을 합니다 - Claude용 OAuth 클라이언트, Azure Storage로의 On-Behalf-Of 교환을 위한 ID, (일반적으로) Graph용 앱 전용 ID. 필요한 것:
API 노출: 응용 프로그램 ID URI
api://<client-id>(기본값)와access_as_user라는 이름의 범위.인증: 정확히 하나의 웹 리디렉션 URI,
<PUBLIC_BASE_URL>/oauth/callback- Claude의 콜백이 아닌 이 서버 자체의 콜백. Claude의 플랫폼 전체 콜백(https://claude.ai/api/mcp/auth_callback)은 Entra에 전혀 등록되지 않습니다. 이유는 위 "아키텍처" 참조.클라이언트 비밀.
이 서버는 동적 클라이언트 등록을 지원하지 않습니다 - 하나의 클라이언트(이 앱 등록의 자체 클라이언트 ID/비밀)만 인식하며, 이는 Claude에서 사용자 지정 커넥터로 추가할 때 OAuth 클라이언트 ID/비밀로 구성하는 값이기도 합니다.
Graph API 권한(애플리케이션, 관리자 동의)
GRAPH_CLIENT_ID가 가리키는 앱 등록에 대해:User.Read.All및GroupMember.Read.All(또는 더 넓은Directory.Read.All) - 사용자의onPremisesSecurityIdentifier와 전이 그룹 구성원을 읽는 데 필요합니다.
구성
모든 설정은 환경 변수입니다 - .env.example 및 SETUP.md의 전체 참조 표를 참조하세요. 재사용에 중요한 것: ROOT_PATH(및 STORAGE_ACCOUNT_NAME/SHARE_NAME)는 나중에 이 서버를 다른 폴더, 공유 또는 클라이언트로 다시 지정하기 위해 변경해야 하는 유일한 것입니다. 프로세스 시작 시 한 번 읽히며 도구 매개변수로 절대 허용되지 않으므로 호출자가 런타임에 범위를 넓힐 방법이 없습니다.
다른 폴더/공유로 다시 지정하려면:
App Service 구성에서
STORAGE_ACCOUNT_NAME,SHARE_NAME,ROOT_PATH를 업데이트합니다.대상 Entra 그룹이 새 스토리지 계정에
Storage File Data Privileged Reader를 가지고 있는지 확인합니다.앱을 다시 시작합니다. 코드나 빌드 변경은 필요 없습니다.
로컬 실행
npm install
cp .env.example .env # fill in real values
npm run dev빌드, 타입 검사, 테스트
npm run build # tsc type-check + emit to dist/
npm test # vitest - sddl parser, ACE evaluator, path-scope, SID cache, audit log unit testsAzure App Service에 배포
전체 안내는 SETUP.md를 참조하세요. 짧은 버전:
src/,package.json,package-lock.json,tsconfig.json을 zip으로 패키징하세요 - 절대 사전 빌드된dist/나node_modules/를 포함하지 마세요. Azure의 Oryx 빌더가 배포할 때마다 서버 측에서 새로 컴파일합니다(App SettingSCM_DO_BUILD_DURING_DEPLOYMENT=true필요).zip을 Linux App Service 플랜(Node 20+)에 배포하되, 정확히 하나의 인스턴스로 배포하세요(위 "Architecture"의 인메모리 OAuth 릴레이 상태 관련 참고 사항 참조).
.env.example의 모든 변수를 App Service Application Settings로 설정하세요(커밋된.env파일이 아닌).PUBLIC_BASE_URL은 App Service의 실제 HTTPS URL이어야 하며, 끝에 슬래시가 없어야 합니다 - 슬래시가 있으면 생성된 URL에 이중 슬래시가 생기고 Entra 리디렉션 URI 매칭이 깨집니다.Claude를 연결하기 전에 검증하세요:
GET /healthz가ok를 반환하고,GET /.well-known/oauth-protected-resource/mcp가 JSON 메타데이터 문서를 반환하는지 확인하세요(리소스 서버 URL 자체에/mcp경로 구성 요소가 있으므로 RFC 9728에 따라/mcp접미사가 필요합니다).Claude가 연결하는 MCP 엔드포인트는
POST {PUBLIC_BASE_URL}/mcp입니다.
이 서버는 App Service의 기본 제공 "Easy Auth" MCP 통합에 의존하는 대신 OAuth를 직접 구현합니다(JWT 검증, /.well-known/oauth-* 메타데이터 엔드포인트,
그리고 이제 MCP SDK의 mcpAuthRouter를 통한 전체 인증 서버 릴레이). 해당 통합은 실제로 존재하지만
아직 미리 보기 단계이며, Microsoft의 자체 문서에서도 검증된 토큰을 다운스트림 리소스로 전달하는 것을 명시적으로 경고합니다 -
어차피 Storage에 대한 on-behalf-of 교환을 직접 작성해야 하므로, 해당 통합을 사용해도 코드 양이 줄지 않고
미리 보기 단계의 위험만 추가될 뿐입니다.
알려진 제한 사항
도메인 로컬 AD 그룹은 확인되지 않을 수 있습니다. NTFS ACL은 Microsoft Graph의
onPremisesSecurityIdentifier를 통해 확인되는 온프레미스 AD SID와 매칭됩니다. 도메인 로컬 그룹은 Entra ID에 안정적으로 동기화/쓰기백되지 않으므로, 동기화되지 않은 도메인 로컬 그룹에 액세스를 부여하는 ACE는 매칭할 수 없습니다. 이는 폐쇄적(closed) 으로 실패합니다: 확인되지 않은 그룹 SID는 ALLOW ACE를 충족할 수 없으므로, 최악의 경우 사용자가 자신에게 부여된 권한보다 적게 보는 것이지 더 많이 보는 경우는 절대 없습니다(src/graph/sidResolver.ts,src/acl/evaluate.ts). 대상 폴더의 ACL이 도메인 로컬 그룹을 사용하는 경우, 테스트 중에 실제 사용자에게 권한이 부족하게 적용되지 않는지 확인하세요; 문제가 있다면 유니버설/글로벌 그룹으로 ACL을 재설정하거나 LDAP 폴백 조회를 추가하는 방법이 있습니다(여기서는 구현되지 않음).상위 폴더에 대한 디렉터리 트래버스(
FILE_TRAVERSE)는 별도로 확인되지 않습니다. Windows는 대부분의 실제 배포에서 Authenticated Users에게 "트래버스 검사 우회"를 기본적으로 부여하므로 이는 일반적인 실제 동작과 일치하지만, 클라이언트 환경에서 공유 루트와ROOT_PATH사이의 폴더에 기본값이 아닌 트래버스 제한이 있는 경우 테스트 중에 다시 검증하세요.단일 App Service 인스턴스만 지원 - 위 "Architecture"의 OAuth 릴레이 참고 사항을 참조하세요.
쓰기/삭제/이름 변경 없음 - 설계상 의도된 것이며, 결함이 아니라 의도적인 제약입니다.
레거시 바이너리
.doc/.xls및 스캔/이미지 전용 PDF는 읽을 수 없습니다 - 위 "Reading PDF/Word/Excel files"를 참조하세요.대상 테넌트의 온프레미스 AD가 Entra에 동기화되어 있어야 합니다(Entra Connect / Cloud Sync) - 온프레미스 SID가 흘러들어와야 하며, 전체 사용자별 NTFS 적용 모델이 이에 의존합니다. 온프레미스 AD가 없는 클라우드 전용 Entra 네이티브 테넌트에서는 작동하지 않습니다.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Read-only MCP access to sessions, funnels, campaigns, errors, live visitors, and anomalies.
Read-only CVE intelligence, remediation playbooks, and agent setup guides. Not a scanner.
Read-only access to your VortexIQ store data: audits, KPIs, alerts, Brand DNA, reports, Ask VIQ.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/H1er0/Azure-Files-MCP'
If you have feedback or need assistance with the MCP directory API, please join our Discord server