Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion assemblymcp/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

class Settings(BaseSettings):
# Core Settings
assembly_api_key: str | None = Field(None, description="National Assembly API Key")
api_key: str | None = Field(None, description="National Assembly API Key")
default_assembly_age: str = Field("22", description="Default Assembly Age (e.g. 22)")

# Logging Settings
Expand Down
6 changes: 3 additions & 3 deletions assemblymcp/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@

# Initialize API Client globally to load specs once
try:
client = AssemblyAPIClient(api_key=settings.assembly_api_key)
client = AssemblyAPIClient(api_key=settings.api_key)
except Exception as e:
logger.error(f"Failed to initialize client: {e}")
client = None
Expand Down Expand Up @@ -106,7 +106,7 @@ async def get_assembly_info() -> str:
return "Error: API Client not initialized. Please check API key configuration."

try:
api_key_status = "configured" if settings.assembly_api_key else "not configured"
api_key_status = "configured" if settings.api_key else "not configured"
service_count = len(client.service_map)
return (
"AssemblyMCP – 대한민국 국회 OpenAPI (Korean National Assembly Open API)\n"
Expand Down Expand Up @@ -704,7 +704,7 @@ def main():
"""Run the MCP server"""
sys.stdout.reconfigure(line_buffering=True)
# Validate settings on startup (but don't fail if API key is missing yet)
if not settings.assembly_api_key:
if not settings.api_key:
logger.warning("ASSEMBLY_API_KEY is not configured. The server will run but tools will fail.")

# Check for transport configuration
Expand Down
4 changes: 4 additions & 0 deletions assemblymcp/services.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@ def _collect_rows(raw_data: Any) -> list[dict[str, Any]]:
rows: list[dict[str, Any]] = []

def _walk(node: Any) -> None:
# Pydantic model → convert to dict and treat as a row
if hasattr(node, "model_dump"):
rows.append(node.model_dump())
return
if isinstance(node, dict):
Comment on lines +71 to 75
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Pydantic 모델을 처리할 때 model_dump()를 호출하고 즉시 rows에 추가한 뒤 return하는 방식은, 해당 모델이 개별 데이터 행(row)이 아닌 전체 응답을 감싸는 컨테이너(Wrapper) 모델일 경우 문제를 일으킬 수 있습니다. 국회 API의 특성상 응답 객체는 여러 계층으로 중첩되어 있으며, 실제 데이터 행은 특정 키("row") 아래의 리스트에 존재합니다.

만약 assembly_client가 반환하는 모델이 전체 응답 구조를 유지하고 있다면, 이 로직은 개별 데이터 행이 아닌 전체 응답 객체 하나를 rows에 담게 되어 이후의 데이터 파싱(예: _build_bill) 과정에서 필드 누락으로 인한 오류가 발생할 수 있습니다. 모델을 dict로 변환한 후 내부 구조를 계속 탐색(walk)하여 실제 데이터 행을 찾도록 하거나, 모델이 컨테이너인지 개별 행인지에 따라 분기 처리하는 것이 더 안전합니다.

Suggested change
# Pydantic model → convert to dict and treat as a row
if hasattr(node, "model_dump"):
rows.append(node.model_dump())
return
if isinstance(node, dict):
# Pydantic 모델인 경우 dict로 변환하여 내부 구조(특히 "row" 키)를 탐색하도록 합니다.
if hasattr(node, "model_dump"):
node = node.model_dump()
if isinstance(node, dict):

if "row" in node and isinstance(node["row"], list):
for entry in node["row"]:
Expand Down