에러 코드
JSON-RPC 표준 + ainote 확장.
JSON-RPC 표준
| 코드 | 의미 | 원인 |
|---|---|---|
| -32700 | Parse error | JSON 문법 오류 |
| -32600 | Invalid Request | jsonrpc 필드 누락 등 |
| -32601 | Method not found | method 가 tools/list / tools/call 아님 |
| -32602 | Invalid params | 도구 파라미터 잘못 |
| -32603 | Internal error | 서버 내부 오류 |
ainote 확장 (-32000 ~ -32099)
| 코드 | 의미 | 원인 | 해결 |
|---|---|---|---|
| -32000 | Tool not found | params.name 이 도구 목록에 없음 | tools/list 로 확인 |
| -32001 | Unauthorized | 헤더 누락 / 잘못 | 인증 가이드 |
| -32002 | Rate limit exceeded | 분당/일당 한도 초과 | Retry-After 헤더 대기 |
| -32003 | Validation failed | 비즈니스 규칙 위반 | data.field 확인 |
| -32004 | Quota exceeded | 저장량/vault 개수 한도 | 정리 또는 유료 플랜 |
| -32005 | Resource not found | 태스크/문서 ID 없음 | list_* 로 확인 |
| -32006 | Conflict | 충돌 (예: vault sync) | 수동 해결 |
| -32007 | Permission denied | 키 권한 부족 (read-only 키로 write) | 권한 키 발급 |
응답 예시
json
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32602,
"message": "Invalid params: title is required",
"data": {
"field": "title",
"constraint": "required"
}
}
}HTTP 상태 코드
JSON-RPC 응답은 보통 HTTP 200 (에러도). 단:
- HTTP 401 —
Authorization자체 형식 잘못 (JSON 파싱도 안 함) - HTTP 429 — Rate limit (매우 빠른 reject)
- HTTP 500 — 서버 다운 (보통은 200 + error code)
자주 보는 시나리오
처음 호출이 401
json
{ "code": -32001, "message": "Unauthorized" }체크:
- 키 prefix
McpKey(공백 1개) - 키 64자 (
MCP Key) 또는 24자 (User API Key) - 키 발급 후 폐기 안 됨
자연어 파싱 실패
json
{
"code": -32602,
"message": "Could not parse due_at from title",
"data": { "title": "tomorrow at noonish maybe" }
}해결: 명시적 ISO 8601:
json
{ "title": "회의", "due_at": "2026-05-08T12:00:00+09:00" }429 Rate limit
http
HTTP/1.1 429 Too Many Requests
Retry-After: 30
{ "error": { "code": -32002, "message": "Rate limit exceeded" } }Retry-After: 30 → 30초 대기 후 재시도.
Quota 초과
json
{
"code": -32004,
"message": "Vault quota exceeded",
"data": { "current": 100, "limit": 100, "type": "vault_count" }
}해결: 안 쓰는 vault 삭제 또는 유료 플랜.
클라이언트 처리 권장
typescript
async function callMcp(name, args) {
const res = await fetch(URL, {...});
const json = await res.json();
if (json.error) {
if (json.error.code === -32002) {
// Rate limit — exponential backoff
const retry = parseInt(res.headers.get('Retry-After') || '5');
await sleep(retry * 1000);
return callMcp(name, args);
}
if (json.error.code === -32001) {
throw new AuthError(json.error.message);
}
throw new McpError(json.error.code, json.error.message, json.error.data);
}
return json.result;
}