MCP 서버 연결
`mcp/servers.json` 으로 외부 MCP 서버를 Agent 에 연결
Agent 는 부팅 시 Model Context Protocol
서버에 연결합니다. 해당 도구들은 내장 도구와 동일한 ToolRegistry
로 들어가며 기본적으로 defer_loading: true 가 표시됩니다 (schema 는
모델이 tool_search 를 호출할 때에만 가져옵니다).
두 개의 파일 위치
서버 설정은 두 곳에서 읽혀 병합됩니다:
- 사용자 전역:
<dataDir>/mcp/servers.json, 기본값~/.minara/mcp/servers.json.MINARA_DATA_DIR로 디렉터리를 덮어쓸 수 있습니다. 개인 자격 증명과 모든 저장소에서 사용 가능하길 원하는 서버를 둡니다.mcp/servers.json이 없으면 기존 경로<dataDir>/mcp.json도 읽으므로 기존 설정은 그대로 동작합니다. - 프로젝트 로컬:
<repo>/.minara/mcp/servers.json.cwd에서 위로 올라가며 가장 가까운.minara/디렉터리 (.git/와 같은 레벨) 를 찾아 해석합니다. 단일 저장소에 개발 URL 또는 테넌트별 token 을 고정하고 싶을 때 사용. 기존 경로<repo>/.minara/mcp.json도 동일한 폴백입니다.
id 가 충돌하면 프로젝트 항목이 이깁니다. 따라서 저장소는 전역에
선언된 서버의 authTokenEnv 나 url 을 덮어쓸 수 있습니다.
두 파일은 동일한 스키마를 공유합니다:
{
"mcpServers": {
"slack": {
"url": "https://mcp.example.com/slack/",
"authTokenEnv": "SLACK_MCP_TOKEN",
"headers": { "X-Tenant": "acme" }
},
"etherscan": {
"url": "https://mcp.example.com/etherscan/",
"timeoutMs": 60000,
"subagent": {
"systemPrompt": "EVM 블록 익스플로러 질의 전담.",
"maxSteps": 10
}
}
}
}JSON 키가 서버 id 가 되어 mcp_<id>_* 도구명 접두사로 사용됩니다.
같은 서버를 다른 별칭으로 두 번 등록해야 할 경우 항목 안에 "id"
필드를 명시하면 키보다 우선합니다.
필드
| 필드 | 필수 | 설명 |
|---|---|---|
url | 예 | Streamable-HTTP MCP 엔드포인트. SSE 전용 엔드포인트는 미지원. |
authTokenEnv | 아니오 | bearer token 을 담은 환경 변수 이름. 연결 시 환경에서 해석하여 Authorization: Bearer <token> 로 전송. secret 을 디스크에 남기지 않으므로 authToken 보다 우선. |
authToken | 아니오 | bearer token 리터럴 값. 존재하면 읽지만, 이 파일을 쓰는 도구 (minara mcp add, chat 내 설치 경로) 는 inline token 을 거부하고 authTokenEnv 를 요구합니다. 신뢰할 수 있는 호스트에서 직접 작성한 파일은 여전히 사용 가능. |
headers | 아니오 | 모든 요청에 병합되는 추가 HTTP 헤더. secret 헤더 값 (Authorization, X-Api-Key) 은 환경 변수를 참조해야 합니다. 예: "Authorization": "Bearer ${SLACK_MCP_TOKEN}". |
timeoutMs | 아니오 | 단일 호출 타임아웃. 기본 30000. |
label | 아니오 | 로그용 표시명. 기본은 id. |
maxTools | 아니오 | 서버당 등록 도구 수 상한. 기본 64. |
include | 아니오 | 원격 도구 이름 화이트리스트. 외 나머지는 폐기. |
subagent | 아니오 | 설정 시 해당 서버 도구들을 단일 mcp_<id>_query 로 묶어 내부 agent 루프로 구동. 도구가 많은 서버에서 페르소나 + 스텝 예산으로 메인 루프를 깔끔하게 유지할 때 유용. |
잘못된 항목 (url 누락, 타입 오류) 은 로그를 남기고 건너뜁니다 :
한 항목이 깨졌다고 다른 서버 연결이 막히지 않습니다.
우선순위
MCP_SERVERS환경 변수 : 서버 설정 JSON 배열. 두 파일 위치 를 모두 쇼트서킷합니다. 테스트나 secrets manager 가 블롭을 직접 주입하는 컨테이너 배포에서 사용.- 병합된 서버 설정 : 전역
<dataDir>/mcp/servers.json과 프로젝트 로컬<repo>/.minara/mcp/servers.json을 병합 (각각 같은 레벨의 기존 경로mcp.json으로 폴백). id 가 충돌하면 프로젝트 항목이 전역을 덮어쓰고, id 가 다른 항목은 합집합이 됩니다. - v1 서버별 URL 환경 변수 :
MCP_EVM_RPC_URL,MCP_ETHERSCAN_URL,MCP_SOLSCAN_URL,MCP_GOPLUS_URL. 각각 독립적으로 게이트되며, 앞 두 계층이 모두 비어 있을 때만 참고됩니다.
디스크에 설정 파일이 있어도 MCP_SERVERS=… 는 항상 파일 계층을
쇼트서킷하므로 재현성이 유지됩니다.
보안
secret 을 설정 파일에 쓰지 마세요. 인증은 authTokenEnv (환경 변수
이름) 로 표현하고, token 은 연결 시 환경에서 해석됩니다. 이 파일을 쓰는
도구 (minara mcp add 와 chat 내 설치 경로) 가 이를 강제합니다. inline
authToken 도, 리터럴 값을 담은 secret 헤더도 거부하므로 token 이 Agent
를 거쳐 디스크에 도달하지 않습니다.
신뢰할 수 있는 호스트에서 직접 작성한 파일은 여전히 리터럴 authToken
을 담을 수 있고 loader 가 읽습니다. 공유 호스트에서는 authTokenEnv 를
우선하세요. 꼭 리터럴 token 을 저장해야 한다면:
chmod 600 ~/.minara/mcp/servers.json과chmod 600 <repo>/.minara/mcp/servers.json.- 또는
MCP_SERVERS로 secrets manager (Vault, AWS Secrets Manager, doppler 등) 에서 주입하고 설정 파일을 비워둡니다. - 프로젝트 로컬 파일은 저장소 협업자와 token 을 공유하고 싶지 않다면
.minara/를.gitignore에 추가합니다.
관측
부팅 로그는 module: "app", action: mcp_initialized 라인에서 연결된
서버와 도구 수를 보고합니다. 서버 단위 실패는
mcp_server_connect_failed 로 표시됩니다.
REPL 의 pnpm dev -- status (또는 대응되는 HTTP gateway 엔드포인트)
에서 현재 MCP 상태 배열을 확인할 수 있습니다.