space ocr
가이드아티클요금문서

Claude Code 에서 OCR 쓰기: space ocr MCP 서버 연결

호스팅되는 space ocr MCP 서버를 Claude Code 에 연결해 문서 사진에서 좌표가 붙은 구조화 필드와 검토 목록을 받고, 그대로 보관해 조회하는 방법을 정리했습니다.

Claude Code 에서 송장·영수증·명함·신분증·각종 양식 사진을 넘기고, 흩어진 텍스트 대신 이름 붙은 필드로 받을 수 있다. 그 입구가 space ocr MCP 서버다. 호스팅된 엔드포인트를 한 번 등록해 두면 그 툴이 Claude Code 기본 툴 옆에 서고, 문서가 나온 자리에서 어시스턴트가 알아서 집는다.

무엇이 달라지는지는 정확히 적어 둘 만하다. 사진을 대화에 붙이는 방식은 같은 항목이 매번 필요해지기 전까지, 값이 지면 어디에 있었는지 기록이 필요해지기 전까지, 결과를 둘 곳이 필요해지기 전까지는 통한다. 그렇다고 OCR 엔진·파싱 계층·데이터베이스를 직접 세우면 그 셋의 유지보수가 남는다. 여기서는 추출이 서버에서 돌아 형태가 고정된 응답을 주고, 값마다 읽어 낸 자리의 좌표가 붙으며, 같은 서버가 문서를 작업공간에 보관하므로 두 번째부터는 다시 읽지 않고 조회한다.

연결

서버는 https://mcp.space-ocr.com/mcp 에 있고 Streamable HTTP 위의 MCP 로 말한다. 설치할 것도, 띄워 둘 프로세스도 없다. URL 을 등록하고 API 키는 요청마다 베어러 헤더로 실어 보내면 끝이다. Claude Code 는 명령 한 줄이다.

1
2
claude mcp add --transport http space-ocr https://mcp.space-ocr.com/mcp \
  --header "Authorization: Bearer YOUR_API_KEY"

Cursor · VS Code · Windsurf 는 같은 URL 과 헤더를 mcp.json 에 적는다. 헤더를 넣을 수 없는 클라이언트 — claude.ai · Claude 데스크톱 · Claude 모바일 — 는 같은 URL 을 커스텀 커넥터로 추가하면 OAuth 동의 화면이 열려 어떤 API 키로 동작할지 고르게 된다. 어느 쪽이든 키는 그 요청에만 쓰이고 서버에 저장되지 않는다.

1
2
3
4
5
6
7
8
{
  "mcpServers": {
    "space-ocr": {
      "url": "https://mcp.space-ocr.com/mcp",
      "headers": { "Authorization": "Bearer YOUR_API_KEY" }
    }
  }
}

키와 비용

API 키는 space-ocr.com → Developer → API Keys 에서 발급한다(spocr_ 로 시작). 모든 계정에 매월 무료 크레딧 100개가 주어지고 카드 등록은 필요 없으며 매달 리셋된다. 그 이상은 1 크레딧 ₩100 이다.

과금 단위는 페이지다. 읽기 3종 중 하나, 또는 업로드 1페이지가 각각 정확히 1 크레딧이고, 실패한 읽기는 자동 환불된다. 나머지는 전부 무료다 — 트리 훑기, 보관된 행 조회, 셀 수정, 업로드 링크 발급. 남은 양은 space_balance 가 알려 준다(무료 한도 → 플랜 한도 → 선불 잔액 순으로 소비). 큰 배치 전에 한 번 불러 둘 값이 있다.

툴 13종

먼저 space_guide 를 읽힌다. 서버가 스스로를 설명하는 가이드이고, 여섯 개의 짧은 항목(start · upload · schemas · verification · queries · workflows)이 그대로 대화에 실린다. 네트워크도 크레딧도 쓰지 않는다.

읽기는 3종이고 모두 아무것도 저장하지 않는다.

  • ocr_extract — 이름 붙은 필드 추출. fields 스키마를 선언하거나 autoFields: true 로 모델이 제안하게 둔다.
  • ocr_markdown — 레이아웃을 살린 마크다운. 제목·목록·표(셀마다 row / col)에 요소 단위 좌표가 붙는다.
  • ocr_text — 읽기 순서를 되살린 원문 텍스트. 다단 지면이 뒤섞여 돌아오지 않고, 블록 단위 좌표가 붙는다.

나머지 10종이 작업공간을 움직인다. space_list 는 트리 훑기, space_view 는 아이템 읽기와 조회, space_create 는 폴더/시트/문서 묶음/메모 생성, space_inbox 는 업로드 링크 발급, space_upload 는 이미 URL 인 사진 투입, space_job 은 업로드 잡 확인, space_edit 은 셀 값·메모 본문 수정, space_balance 는 잔량, space_delete 는 2단계 삭제다. 툴마다 뒤에 있는 REST 라우트까지 담은 표는 API 문서에 있다.

사진을 넣는 법

툴 호출에는 이미지 바이트를 실을 수 없고, 첫 시도는 대개 여기서 막힌다. space_upload 가 받는 것은 이미 공개 https:// URL 인 사진뿐이다(한 번에 20장, 장당 20MB). 그 밖의 것은 전부 space_inbox 를 지난다 — 로컬 디스크의 파일, 대화에 첨부된 사진, 지금 찍을 스캔. 시트나 묶음 하나를 겨냥한 만료 시각이 있는 업로드 링크를 발급하고, 바이트는 그 장비에서 space ocr 로 직접 가며 대화를 경유하지 않는다. 응답에는 두 결말이 함께 온다. 셸 명령을 돌릴 수 있으면 curl 한 줄을, 못 하면 사용자에게 보여 줄 링크를 쓴다.

업로드는 비동기다. space_upload 는 즉시 잡을 돌려주고 한 페이지에 대략 20초가 걸린다. space_job 으로 따라가도 되고, 잠시 뒤 space_view 로 대상을 읽어도 행은 들어와 있다. 다루는 것은 사진뿐이다. PDF 는 아무 불평 없이 올라간 뒤 끝내 읽히지 않으므로, 페이지를 사진으로 바꿔서 보내야 한다.

한 번 읽고 버릴 것인가, 행으로 남길 것인가

ocr_* 는 아무것도 저장하지 않는다. 다시 반복할 일 없는 조회, 또는 시트 컬럼을 설계하기 전에 낯선 문서를 autoFields 로 한 장 떠보는 용도에 맞는다. 사용자가 다시 볼 것은 작업공간에 넣는다.

만드는 것은 space_create 다. 폴더는 묶는 상자이고, 루트 바로 아래에는 폴더만 놓인다. 시트는 안에 들어온 사진마다 정해진 columns 를 뽑아 사진 한 장을 한 행으로 만든다 — 비교하거나 거를 값은 여기로 간다. 문서 묶음은 각 페이지를 markdown(읽을 산문) 또는 text(검색할 낱말)로 바꾸고 페이지를 한 덩어리로 유지한다. 메모는 그냥 텍스트다.

주소 규칙 하나를 알아 두면 반나절을 아낀다. 폴더는 이름으로 가리키지만, 나머지는 목록이나 생성 호출이 돌려준 path 로 가리킨다. 그 마지막 마디는 표시 이름이 아니라 uniqueKey 다 — 「March」라는 시트는 /invoices/March 에 없다. 받은 path 를 그대로 들고 다니고, 표시 이름으로 다시 조립하지 말 것.

행이 쌓이면 조회도 space_view 의 일이다. where 로 거르고(반복하면 AND, 연산자는 = != > >= < <= 와 포함 ~), sort 로 정렬하고, select 로 컬럼을 추리고, limit / offset 으로 나눠 받는다. 좌표는 응답을 가볍게 두려고 기본에서 빠지므로, 지면 위 위치를 짚거나 셀별 판정을 읽어야 할 때 boxes: true 를 붙인다. 조회는 무료라, 거르기를 서버에 맡기는 것이 곧 답과 컨텍스트를 작게 유지하는 방법이다.

돌아오는 것

읽기 3종도, 업로드가 만든 행도 응답의 형태는 하나다. data.values 는 선언한 스키마 그대로의 데이터다. data.cells 는 path 를 키로 한 평평한 맵이고(total, items[0].price), 항목마다 읽어 낸 자리의 축 정렬 box 와 4점 quad, 판정 verified, review, 그 근거인 evidence 가 들어 있다. data.review 는 문서 한 장 분의 집계이고 flagged 에 확인할 path 와 reasons 가 모인다. data.normalized 는 스칼라 타입을 선언했을 때만 붙어, 인쇄된 값 옆에 해석된 값을 둔다. data.image 는 0–1000 정규화 좌표를 픽셀로 되돌리는 기준이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
{
  "status": "success",
  "data": {
    "values": {
      "store_name": "슈퍼마켓 ABC",
      "date": "2025-04-10",
      "invoice_no": "",
      "total": "₩4,780"
    },
    "cells": {
      "total": {
        "box": { "xmin": 380, "ymin": 720, "xmax": 530, "ymax": 742 },
        "quad": [{"x":380,"y":720},{"x":530,"y":720},{"x":530,"y":742},{"x":380,"y":742}],
        "verified": true,
        "review": null,
        "evidence": { "text_match": true, "source": "vision_symbol_match", "match_ratio": 1.0 },
        "normalized": { "value": 4780, "type": "number", "method": "deterministic" }
      }
    },
    "review": {
      "unit": "field",
      "declared": 4,
      "returned": 3,
      "boxed": 3,
      "verified": 3,
      "flagged": [ { "path": "invoice_no", "reasons": ["missing"] } ],
      "by_reason": { "missing": 1 }
    },
    "normalized": { "total": 4780 },
    "image": { "width": 1654, "height": 2339 }
  }
}
✓ Verified

값을 검증할 수 있는 이유. 좌표는 LLM 이 짐작한 위치가 아니다. 지면에서 실제로 검출된 OCR 심볼에 다시 앵커링되고, 0–1000 정규화 격자로 돌아오며, 픽셀 환산 기준은 data.image 다. 위치가 실재하므로 값을 문서 위에 그려 읽어 낸 자리와 눈으로 대조할 수 있다. 그 옆에서 verified 가 판정을 말한다 — 검토 사유가 서면 false, 대조가 돌았는데 아무것도 서지 않으면 true, 대조할 대상이 없으면 null. 문자 대조 자체는 evidence.text_match 가 보고하므로, 선언한 규칙에 걸린 셀인데 글자는 일치하는 조합은 모순이 아니라 정상이다. 둘 다 증거이지 증명은 아니다 — 두 엔진이 같은 오독에 합의할 수 있으니 업무 규칙 검산은 뒤에 남겨 둔다.

삭제는 두 번의 호출

space_delete 는 첫 호출에서 절대 지우지 않는다. confirm 없이 부르면 그 경로가 품고 있는 것 — 대상, 아래에 있는 폴더/시트/묶음/메모/사진의 개수, 표본 — 을 돌려주고, 10분쯤 유효한 서명된 confirm 토큰을 함께 발급한다. 에이전트는 그 요약을 보여 주고 명시적인 동의를 기다린 뒤, 토큰을 붙여 다시 부른다. 토큰은 호출한 키와 그 경로에 묶인 서명이라 지어낼 수 없고, 시트에 발급된 토큰으로 그 시트의 행을 지울 수도 없다.

이 절차가 있는 이유는 삭제가 아래로 번지고 되돌릴 수 없기 때문이다. 폴더를 지우면 안의 사진까지 함께 사라진다. 행을 지워도 스캔은 환불되지 않는다 — 그 페이지는 업로드 시점에 읽혀 이미 과금됐다.

네 가지 습관

서버가 스스로 운용 규칙을 밝혀 둔다. 싸게 돌면서 근거를 댈 수 있는 에이전트와, 크레딧을 태우며 짐작하는 에이전트를 가르는 것이 이 넷이다.

  1. 쌓되, 토해내지 말 것. 두 장째부터는 ocr_* 를 직접 부르지 말고 space_createspace_inbox 로 간다. 무거운 데이터는 대화에 되붙이지 말고 API 뒤에 둔다.
  2. 스캔 전에 확인. 배치 전에 space_balance, 두 번째 시트를 만들기 전에 space_list. 이미 행이 된 문서에 두 번 낼 이유가 없다.
  3. 저장된 행으로 답하기. 모든 행을 컨텍스트로 끌어오지 말고 where / sort / select / limit 로 시트에 묻는다. 조회는 무료이고, 사진을 읽는 것은 무료가 아니다.
  4. 위치를 인용하고 불확실한 것은 표시. 값마다 읽어 낸 박스와 판정이 붙어 있다. data.review.flagged 에 오른 것은 단정하지 말고 «확인 필요» 로 내밀고, 값은 인쇄된 그대로 달라고 요청한다 — 지면에 없는 값은 지면에 앵커링될 수 없다.
관련