Skip to main content
Glama
nepseli

rag-blob-mcp

by nepseli

RAG Blob MCP

Azure Blob Storage에 저장된 문서 라이브러리에 RAG 에이전트가 검색 액세스할 수 있도록 하는 Model Context Protocol(MCP) 서버와, 문서를 업로드하고 문서와 대화할 수 있는 Streamlit 앱입니다.

  • MCP 서버 — Streamable HTTP 기반 FastMCP로, 모든 Azure Blob Storage 액세스를 담당하며 4개의 도구와 3개의 프롬프트 템플릿을 제공합니다. 시작할 때마다 Blob Storage에서 재구축되는 인메모리 벡터 인덱스(OpenAI 임베딩)를 보유합니다.

  • Streamlit 앱 — 문서 업로드/목록/삭제를 위한 라이브러리(Library) 탭과, 서버의 검색 도구를 호출하는 LangGraph ReAct 에이전트가 답변하는 질문을 위한 채팅(Chat) 탭을 제공합니다.

빠른 시작

1. 사전 요구 사항

  • Python 3.11+ (3.13 기준으로 개발됨)

  • Blob 컨테이너가 있는 Azure Storage Account (없으면 아래 Azure 설정 참조)

  • OpenAI API 키

2. 설치

저장소 루트에서:

python -m venv .venv
.venv\Scripts\activate          # Windows
pip install -r requirements.txt

3. 설정

.env.example(저장소 루트)을 .env로 복사하고 값을 입력하세요:

OPENAI_API_KEY=sk-...
AZURE_STORAGE_CONNECTION_STRING=DefaultEndpointsProtocol=https;AccountName=...;AccountKey=...;EndpointSuffix=core.windows.net
AZURE_STORAGE_CONTAINER_NAME=rag-documents

다른 모든 것(OPENAI_MODEL, OPENAI_EMBEDDING_MODEL, MCP_SERVER_HOST/PORT/URL)은 기본값이 작동하도록 설정되어 있습니다 — 설정 참조.

4. 실행

두 개의 프로세스, 두 개의 터미널에서 실행하며, 둘 다 저장소 루트에서 실행합니다:

# Terminal 1 — MCP server
python server/mcp_server.py
# Terminal 2 — Streamlit app
streamlit run app/streamlit_app.py

http://localhost:8501을 엽니다. 라이브러리 탭에서 PDF/DOCX/TXT/MD 파일을 업로드한 다음, 채팅 탭에서 파일에 대해 질문하세요.

Related MCP server: Legal MCP Server

Azure 설정

아직 Storage Account가 없다면:

  1. Azure Portal → 리소스 만들기 → Storage 계정. 개인 용도에는 표준 성능, LRS 중복이면 충분합니다.

  2. 새 계정에서: 데이터 스토리지 → 컨테이너 → + 컨테이너, 이름을 지정하고(예: rag-documents), 액세스 수준을 비공개(Private)로 설정합니다.

  3. 보안 + 네트워킹 → 액세스 키 → 키 표시에서 연결 문자열을 복사합니다.

  4. .env에 AZURE_STORAGE_CONNECTION_STRING으로 붙여넣고, AZURE_STORAGE_CONTAINER_NAME을 선택한 컨테이너 이름으로 설정합니다.

프로젝트 구조

.
├── server/
│   ├── mcp_server.py      # FastMCP server: tools, prompts, index rebuild, __main__ entrypoint
│   ├── blob_store.py      # Azure Blob Storage wrapper
│   ├── indexing.py        # text extraction (pdf/docx/txt/md) + chunking
│   ├── vector_index.py    # in-memory vector store wrapper
│   └── test_*.py          # automated tests (pytest)
├── agent/
│   └── rag_agent.py       # LangGraph ReAct agent used by the Chat tab
├── app/
│   ├── mcp_client.py      # direct MCP tool-call helpers used by the Library tab
│   └── streamlit_app.py   # the UI
├── scripts/
│   └── smoke_test_server.py  # manual end-to-end smoke test against a running server
├── docs_build/            # scripts that generate PROJECT.docx / PROJECT.pdf
└── pytest.ini

설정

모든 변수는 저장소 루트의 .env에 있습니다:

변수

기본값

용도

OPENAI_API_KEY

— (필수)

채팅 모델 + 임베딩

OPENAI_MODEL

gpt-4.1

RAG 에이전트용 채팅 모델

OPENAI_EMBEDDING_MODEL

text-embedding-3-small

벡터 인덱스용 임베딩 모델

AZURE_STORAGE_CONNECTION_STRING

— (필수)

Blob Storage 액세스

AZURE_STORAGE_CONTAINER_NAME

— (필수)

문서가 저장되는 컨테이너

MCP_SERVER_HOST

127.0.0.1

MCP 서버가 바인딩되는 인터페이스

MCP_SERVER_PORT

8000

MCP 서버가 바인딩되는 포트

MCP_SERVER_URL

http://127.0.0.1:8000/mcp

Streamlit 앱/에이전트가 연결하는 URL — 포트를 변경하면 이 값도 업데이트하세요

사용법

라이브러리 탭 — PDF/DOCX/TXT/MD 파일을 업로드합니다(Streamlit에서 설정된 200MB 제한). 각 업로드는 청크로 분할되고 임베딩된 후 검색 인덱스에 추가됩니다. 문서 목록에는 청크 수와 함께 indexed / failed / pending 상태가 표시됩니다. 삭제하면 Blob Storage와 인덱스에서 모두 문서가 제거됩니다.

채팅 탭 — 자연스러운 영어로 질문합니다. 에이전트가 검색 도구 호출 시점을 결정하고 관련 청크를 검색한 후, 원본 문서를 파일 이름으로 인용하여 답변합니다. 라이브러리가 비어 있거나 관련 없는 내용이면 추측하지 않고 그 사실을 알려줍니다.

테스트

pytest server/ -v

29개의 테스트가 텍스트 추출/청크 분할, 벡터 인덱스, Azure Blob Storage 래퍼(mock 처리), 그리고 4개의 MCP 도구 + 프롬프트를 모두 다룹니다(fastmcp.Client를 프로세스 내에서 사용하고 fake를 사용하므로 실제 Azure/OpenAI 호출은 없음). Streamlit UI나 실제 에이전트/서버 연결에 대한 자동화된 테스트는 없습니다. 실제 실행 중인 서버에 대한 수동 스모크 테스트는 scripts/smoke_test_server.py를 참조하세요.

알려진 제한 사항

  • 인메모리 인덱스, 영속성 없음. 서버를 재시작할 때마다 컨테이너의 모든 문서를 다시 다운로드하고, 다시 추출하고, 다시 임베딩합니다. 소규모 개인 라이브러리에는 적합하지만, 라이브러리가 커질수록 실제 OpenAI API 호출 비용과 시작 시간이 늘어납니다.

  • 단일 사용자, 로컬 전용. 인증이 없고, 동시 쓰기 안전성이 없으며, 어디에도 배포되지 않습니다.

  • 앱이 작동하려면 두 프로세스(MCP 서버, Streamlit 앱)가 모두 실행 중이어야 합니다 — 자세한 내용은 전체 프로젝트 문서를 참조하세요.

전체적인 그림(아키텍처, 설계 결정, 알려진 버그, 다음 단계)은 PROJECT.md를 참조하세요(PROJECT.docx / PROJECT.pdf로도 제공됩니다).

Related MCP Connectors

Related MCP Servers