본문으로 건너뛰기

Cursor의 MCP 서버 인증 및 보안

MCP 인증

Model Context Protocol(MCP) 서버는 광고 플랫폼 쿼리부터 결제 워크플로 관리까지 Cursor에 강력한 외부 기능을 확장해 줍니다. 하지만 모든 외부 연결은 인증 및 보안 고려 사항을 도입합니다. 이 가이드는 Cursor의 MCP 서버 인증 전체 스펙트럼을 안내하며, OAuth 흐름, API 키 관리, AI 기반 결제를 위한 인간 승인 레이어, 그리고 Live Meta Ads MCP와 같은 서비스에서 사용자가 직면하는 구체적인 과제를 다룹니다.

MCP 인증이 중요한 이유​

Cursor가 MCP 서버에 연결될 때, 해당 서버는 사용자를 대신하여 행동해야 할 수 있습니다: 개인 데이터 읽기, 콘텐츠 게시, 심지어 돈을 지불하는 것까지. 인증은 에이전트가 할 수 있는 것과 할 수 없는 것을 결정하는 게이트키퍼입니다.

보안 모델 개요​

계층책임예시
CursorMCP 클라이언트 호스팅, 연결 관리mcp.json 읽기, 서버 프로세스 생성
MCP 서버외부 API 호출 처리Meta Graph API, Stripe API 호출
인증 제공자신원 검증Meta의 OAuth 토큰, 제공자의 API 키
인간 승인민감한 작업 제어결제 제출 전 승인
경고

프로덕션 API 키나 OAuth 토큰을 저장소에 평문으로 저장하지 마세요. 항상 환경 변수나 시크릿 매니저를 사용하세요. 자격 증명을 git에 커밋하는 것은 개발자가 직면하는 가장 흔한 보안 사고 중 하나입니다.

사전 요구 사항​

Cursor에서 MCP 인증을 구성하기 전에 다음을 확인하세요:

  1. Cursor가 설치되고 최신 버전으로 업데이트됨
  2. npx 기반 MCP 서버를 실행하기 위한 Node.js 18+
  3. 연결하려는 외부 서비스(예: Meta for Developers, Stripe)의 계정
  4. 제공자로부터의 앱 자격 증명(클라이언트 ID, 클라이언트 시크릿 또는 API 키)

MCP 인증 방법 이해​

Cursor는 MCP 서버에 대해 두 가지 주요 인증 패턴을 지원하며, 선택은 연결하려는 서버가 지원하는 것에 전적으로 따릅니다.

방법 1: API 키 인증​

가장 단순한 패턴입니다. MCP 서버는 환경 변수나 헤더를 통해 전달되는 정적 API 키를 기대합니다.

{
"mcpServers": {
"my-api-server": {
"command": "npx",
"args": ["-y", "@my-org/api-mcp-server"],
"env": {
"API_KEY": "${MY_API_KEY}"
}
}
}
}

${MY_API_KEY} 구문은 Cursor에 환경에서 값을 읽어오라고 지시합니다. 쉘 프로필에 설정하세요:

# ~/.zshrc 또는 ~/.bashrc
export MY_API_KEY="sk-your-actual-key-here"
팁

Windows에서는 PowerShell이나 시스템 속성을 통해 환경 변수를 설정합니다. PowerShell에서:

[System.Environment]::SetEnvironmentVariable("MY_API_KEY", "sk-your-key", "User")

그런 다음 Cursor를 재시작하여 새 변수를 로드하게 합니다.

방법 2: OAuth 2.0 인증​

OAuth는 정적 키를 피하고 범위가 지정된, 취소 가능한 액세스를 지원하므로 더 안전합니다. 하지만 설정이 더 복잡합니다. MCP 서버는 브라우저를 열고, 제공자에 로그인하라는 메시지를 표시하고, Cursor에 토큰을 반환하는 OAuth 흐름을 시작합니다.

{
"mcpServers": {
"oauth-server": {
"command": "npx",
"args": ["-y", "@my-org/oauth-mcp-server"],
"env": {
"OAUTH_CLIENT_ID": "${CLIENT_ID}",
"OAUTH_CLIENT_SECRET": "${CLIENT_SECRET}",
"OAUTH_REDIRECT_URI": "http://localhost:3000/callback"
}
}
}
}

OAuth 흐름은 다음과 같이 진행됩니다:

  1. Cursor가 MCP 서버 프로세스를 시작
  2. 서버가 유효한 토큰이 없음을 감지하고 OAuth를 시작
  3. 브라우저가 제공자의 로그인 페이지를 열음
  4. 앱을 인증
  5. 제공자가 localhost:3000/callback으로 인증 코드와 함께 리다이렉트
  6. 서버가 코드를 액세스 및 리프레시 토큰으로 교환
  7. 토큰이 향후 사용을 위해 로컬에 저장됨

Live Meta Ads MCP 설정​

Live Meta Ads MCP는 Cursor에서 가장 자주 요청되는 MCP 통합 중 하나입니다. Meta Graph API에 연결하여 에이전트가 광고 성과, 캠페인 데이터 및 오디언스 인사이트를 쿼리할 수 있게 합니다. 포럼 사용자들은 이 MCP의 인증 실패를 자주 보고합니다. 올바르게 설정하는 방법은 다음과 같습니다.

1단계: Meta 앱 만들기​

  1. Meta for Developers 포털로 이동
  2. 앱 만들기 클릭
  3. 앱 유형으로 비즈니스 선택
  4. Marketing API 제품 추가
  5. App ID와 App Secret 기록

2단계: 장기 액세스 토큰 생성​

Meta의 기본 액세스 토큰은 빨리 만료됩니다. MCP 사용을 위해서는 장기 토큰이 필요합니다:

# 단기 토큰을 장기 토큰으로 교환
curl -X GET "https://graph.facebook.com/v19.0/oauth/access_token" \
-d "grant_type=fb_exchange_token" \
-d "client_id=$META_APP_ID" \
-d "client_secret=$META_APP_SECRET" \
-d "fb_exchange_token=$SHORT_LIVED_TOKEN"

응답에는 약 60일 동안 유효한 토큰이 포함됩니다.

3단계: Cursor에서 MCP 서버 구성​

{
"mcpServers": {
"meta-ads": {
"command": "npx",
"args": ["-y", "@mcp/meta-ads-server"],
"env": {
"META_ACCESS_TOKEN": "${META_ACCESS_TOKEN}",
"META_APP_ID": "${META_APP_ID}",
"META_APP_SECRET": "${META_APP_SECRET}",
"META_API_VERSION": "v19.0"
}
}
}
}

4단계: 연결 확인​

Cursor를 재시작한 후, Cursor 설정을 열고 MCP 섹션으로 이동합니다. meta-ads가 녹색 상태 표시기와 함께 나열되어야 합니다. 오류가 표시되면 아래 문제 해결 섹션을 참조하세요.

경고

Meta 장기 토큰은 60일 후에 만료됩니다. 토큰이 만료되기 전에 새로고침하기 위한 캘린더 알림을 설정하세요. 토큰이 만료되면 에이전트는 조용히 광고 데이터 가져오기에 실패하고, 유일한 증상은 빈 결과나 MCP 로그에 묻힌 인증 오류일 수 있습니다.

일반적인 MCP 인증 실패​

포럼 사용자들은 Cursor의 MCP 인증과 관련된 여러 반복되는 문제를 보고합니다. 가장 흔한 실패와 해결 방법은 다음과 같습니다.

실패 1: 환경에서 토큰을 찾을 수 없음​

증상: MCP 서버는 시작되지만 모든 요청에서 401 Unauthorized를 반환합니다.

원인: Cursor가 환경 변수를 가져오지 못했습니다. 이는 변수가 다른 쉘 프로필에 설정되었거나 Cursor가 이미 실행 중일 때 설정된 경우에 자주 발생합니다.

해결 방법:

# 변수가 존재하는지 확인
echo $META_ACCESS_TOKEN

# 비어 있으면 쉘 프로필에 추가하고 Cursor 재시작
echo 'export META_ACCESS_TOKEN="your-token"' >> ~/.zshrc
source ~/.zshrc

그런 다음 Cursor를 완전히 종료하고 다시 엽니다.

실패 2: OAuth 리다이렉트 URI 불일치​

증상: OAuth 흐름이 브라우저를 열지만, 인증 후 오류 페이지가 표시됩니다.

원인: Meta 앱 구성의 리다이렉트 URI가 MCP 서버가 사용하는 것과 일치하지 않습니다.

해결 방법: Meta for Developers 대시보드에서 앱 설정 > 고급 > OAuth 설정으로 이동하여 http://localhost:3000/callback(또는 MCP 서버가 사용하는 URI)을 허용된 리다이렉트 URI에 추가하세요.

실패 3: 만료되거나 유효하지 않은 토큰​

증상: MCP 서버가 이전에는 작동했지만 갑자기 인증 오류를 반환합니다.

원인: Meta 장기 토큰이 만료되었거나(60일 제한) 취소되었습니다.

해결 방법: 토큰 교환 흐름을 다시 실행하고 환경 변수를 업데이트하세요.

실패 4: 권한 범위 누락​

증상: 인증은 성공하지만 에이전트가 특정 데이터에 액세스할 수 없습니다 (예: 캠페인은 읽을 수 있지만 오디언스 데이터에는 액세스할 수 없음).

원인: Meta 앱에 필요한 API 권한이 없습니다.

해결 방법: Meta 앱 대시보드에서 역할 > 앱 검토 > 권한 및 기능으로 이동하여 추가 범위를 요청하세요:

범위활성화되는 기능
ads_read캠페인 성과 데이터 읽기
ads_management캠페인 생성 및 관리
read_insights상세 분석 데이터 액세스
business_management비즈니스 설정 관리

AI 에이전트 결제를 위한 인간 승인 레이어 구축​

Cursor에서 MCP의 가장 강력하면서도 위험한 사용 사례 중 하나는 AI 에이전트를 결제 시스템에 연결하는 것입니다. 구매나 자금 이체를 할 수 있는 에이전트에는 인간 승인 게이트가 필요합니다. 포럼 사용자들은 이 문제를 해결하기 위해 사용자 정의 승인 레이어를 구축했습니다.

승인 레이어가 필수적인 이유​

승인 레이어가 없으면 결제 MCP 액세스 권한이 있는 AI 에이전트는 다음을 할 수 있습니다:

  • 카드에 예상치 못한 금액 청구
  • 잘못된 수취인에게 결제 전송 | 돌이킬 수 없는 금융 거래 트리거 | 반복된 마이크로 트랜잭션을 통한 비용 축적

결제 승인 레이어 아키텍처​

권장 패턴은 Cursor와 결제 MCP 서버 사이에 승인 게이트웨이를 삽입합니다:

Cursor Agent --> Approval Gateway --> Payment MCP Server --> Stripe/PayPal API
^
|
Human Review

승인 게이트웨이 구현​

실제 결제 서버를 래핑하고 승인을 요구하는 경량 MCP 서버를 만듭니다:

// approval-gateway.ts
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";

const server = new Server({
name: "payment-approval-gateway",
version: "1.0.0",
}, {
capabilities: { tools: {} },
});

// Pending approvals stored in memory (use a database for production)
const pendingApprovals = new Map();

server.setRequestHandler(ListToolsRequestSchema, async () => ({
tools: [
{
name: "request_payment",
description: "Request a payment. Requires human approval before execution.",
inputSchema: {
type: "object",
properties: {
amount: { type: "number", description: "Amount in cents" },
currency: { type: "string", description: "ISO currency code" },
recipient: { type: "string", description: "Recipient identifier" },
reason: { type: "string", description: "Why this payment is needed" },
},
required: ["amount", "currency", "recipient", "reason"],
},
},
{
name: "approve_payment",
description: "Approve a pending payment by ID",
inputSchema: {
type: "object",
properties: {
approval_id: { type: "string" },
},
required: ["approval_id"],
},
},
],
}));

server.setRequestHandler(CallToolRequestSchema, async (request) => {
if (request.params.name === "request_payment") {
const { amount, currency, recipient, reason } = request.params.arguments;
const approvalId = `appr_${Date.now()}`;

pendingApprovals.set(approvalId, {
amount,
currency,
recipient,
reason,
status: "pending",
createdAt: new Date(),
});

return {
content: [{
type: "text",
text: `Payment request created. Approval ID: ${approvalId}\n\n` +
`Amount: ${amount/100} ${currency.toUpperCase()}\n` +
`Recipient: ${recipient}\n` +
`Reason: ${reason}\n\n` +
`To execute this payment, a human must approve it using the approve_payment tool with approval_id: ${approvalId}`,
}],
};
}

if (request.params.name === "approve_payment") {
const { approval_id } = request.params.arguments;
const approval = pendingApprovals.get(approval_id);

if (!approval) {
return { content: [{ type: "text", text: "Error: Approval ID not found." }] };
}

// Forward to actual payment server here
approval.status = "approved";
return {
content: [{
type: "text",
text: `Payment approved and forwarded to payment processor.\nAmount: ${approval.amount/100} ${approval.currency.toUpperCase()}`,
}],
};
}
});

const transport = new StdioServerTransport();
await server.connect(transport);

Cursor에서 승인 게이트웨이 구성​

{
"mcpServers": {
"payments": {
"command": "npx",
"args": ["tsx", "./mcp-servers/approval-gateway.ts"],
"env": {
"STRIPE_SECRET_KEY": "${STRIPE_SECRET_KEY}",
"APPROVAL_TIMEOUT_MS": "300000"
}
}
}
}
팁

승인 타임아웃을 설정하여 인간이 합리적인 시간 내에 승인하지 않으면 요청이 자동으로 만료되도록 합니다. 5분이 좋은 기본값입니다. 이는 오래된 결제 요청이 누적되어 컨텍스트 외에서 승인되는 것을 방지합니다.

경고

승인 게이트웨이 패턴은 AI 에이전트가 이를 우회할 수 없을 때만 작동합니다. 직접 결제 MCP 서버가 Cursor에 구성되어 있지 않은지 확인하세요. 게이트웨이만 노출되어야 합니다. 둘 다 구성되면, 에이전트는 이론적으로 직접 서버를 호출하고 승인을 건너뛸 수 있습니다.

안전한 MCP 서버 구성​

인증 외에도 Cursor에서 MCP 서버를 구성하는 방식은 보안에 영향을 미칩니다. 다음 모범 사례를 따르세요.

프로젝트 범위 vs 글로벌 구성 사용​

Cursor는 글로벌(~/.cursor/mcp.json)과 프로젝트 범위(.cursor/mcp.json) 구성을 모두 지원합니다.

범위파일사용 사례
글로벌~/.cursor/mcp.json모든 프로젝트에서 사용하는 개인 서버
프로젝트.cursor/mcp.json특정 프로젝트 전용 서버
팁

민감한 서버에는 프로젝트 범위 구성을 사용하세요. 이렇게 하면 자격 증명이 글로벌 구성에서 제외되고, 어떤 프로젝트가 어떤 서비스에 액세스할 수 있는지 감사하기 쉬워집니다. .cursor/mcp.json에 시크릿이 포함된 경우 .gitignore에 추가하거나, 환경 변수 참조만 사용하세요.

MCP 도구 액세스 제한​

disabledTools 필드를 사용하여 MCP 서버가 Cursor에 노출하는 도구를 제한할 수 있습니다:

{
"mcpServers": {
"meta-ads": {
"command": "npx",
"args": ["-y", "@mcp/meta-ads-server"],
"env": {
"META_ACCESS_TOKEN": "${META_ACCESS_TOKEN}"
},
"disabledTools": ["delete_campaign", "pause_all_campaigns"]
}
}
}

이는 MCP 서버가 노출하더라도 에이전트가 파괴적인 도구를 사용하는 것을 방지합니다.

전송 보안​

원격 MCP 서버(SSE 기반)의 경우 항상 HTTPS를 사용하세요:

{
"mcpServers": {
"remote-server": {
"url": "https://mcp.example.com/sse",
"headers": {
"Authorization": "Bearer ${REMOTE_MCP_TOKEN}"
}
}
}
}
경고

원격 MCP 서버에 HTTP(비암호화)를 절대 사용하지 마세요. 연결은 인증 토큰을 전송하며, 네트워크의 공격자가 이를 가로챌 수 있습니다. 항상 HTTPS를 사용하고 서버의 TLS 인증서를 확인하세요.

토큰 새로고침 패턴​

많은 OAuth 제공자가 단기 액세스 토큰(1시간)과 함께 장기 리프레시 토큰을 발급합니다. MCP 서버는 중단을 방지하기 위해 자동으로 새로고침을 처리해야 합니다.

패턴 1: 서버 측 새로고침 (권장)​

MCP 서버가 내부적으로 토큰 새로고침을 처리합니다. 액세스 토큰이 만료되면, 서버는 사용자 개입 없이 리프레시 토큰을 사용하여 새 토큰을 얻습니다.

// Inside your MCP server
let accessToken = await loadToken();
let tokenExpiry = Date.now() + 3600 * 1000; // 1 hour

async function ensureValidToken() {
if (Date.now() >= tokenExpiry - 60000) { // refresh 1 min before expiry
const response = await fetch("https://oauth.provider.com/token", {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: new URLSearchParams({
grant_type: "refresh_token",
refresh_token: process.env.REFRESH_TOKEN,
client_id: process.env.CLIENT_ID,
client_secret: process.env.CLIENT_SECRET,
}),
});
const data = await response.json();
accessToken = data.access_token;
tokenExpiry = Date.now() + data.expires_in * 1000;
await saveToken(accessToken, tokenExpiry);
}
return accessToken;
}

패턴 2: Cursor 측 환경 재로드​

MCP 서버가 자동 새로고침을 지원하지 않는 경우, Cursor에서 환경을 재로드할 수 있습니다:

  1. 외부에서 토큰 새로고침
  2. 환경 변수 업데이트
  3. 설정에서 Cursor를 통해 MCP 서버 재시작

패턴 3: 래퍼 스크립트​

MCP 서버를 시작하기 전에 토큰을 새로고침하는 래퍼 스크립트를 만듭니다:

#!/bin/bash
# refresh-and-start.sh

# Refresh the Meta token
NEW_TOKEN=$(node /path/to/refresh-token.js)
export META_ACCESS_TOKEN=$NEW_TOKEN

# Start the MCP server
exec npx -y @mcp/meta-ads-server

래퍼를 사용하도록 Cursor를 구성합니다:

{
"mcpServers": {
"meta-ads": {
"command": "bash",
"args": ["/path/to/refresh-and-start.sh"]
}
}
}
팁

Live Meta Ads MCP의 경우, 60일 토큰 만료가 "갑자기 작동 중단" 보고의 가장 흔한 원인입니다. cron 작업이나 예약된 작업을 사용하여 새로고침 프로세스를 자동화하세요. macOS/Linux에서는 cron을 사용하고, Windows에서는 작업 스케줄러를 사용합니다.

MCP 인증 문제 해결​

MCP 서버 로그 확인​

Cursor는 항상 MCP 서버 오류를 UI에 표시하지는 않습니다. 무슨 일이 일어나고 있는지 확인하려면:

  1. 명령 팔레트 열기 (Cmd/Ctrl + Shift + P)
  2. Output: Show Output Channels 검색
  3. 드롭다운에서 MCP 선택
  4. 로그에서 인증 오류 확인

인증 독립 테스트​

Cursor를 통해 디버깅하기 전에 MCP 서버를 직접 테스트하세요:

# Run the server manually
npx -y @mcp/meta-ads-server

# In another terminal, send a test request
echo '{"jsonrpc":"2.0","method":"tools/list","id":1}' | npx -y @mcp/meta-ads-server

서버가 Cursor 외부에서 인증에 실패하면, 문제는 Cursor가 아닌 자격 증명에 있습니다.

환경 변수 로드 확인​

# Create a test script
cat > test-env.js << 'EOF'
console.log("META_ACCESS_TOKEN:", process.env.META_ACCESS_TOKEN ? "SET" : "NOT SET");
console.log("META_APP_ID:", process.env.META_APP_ID ? "SET" : "NOT SET");
console.log("META_APP_SECRET:", process.env.META_APP_SECRET ? "SET" : "NOT SET");
EOF

# Run with the MCP server's environment
node test-env.js

변수가 NOT SET으로 표시되면, 문제는 쉘 프로필이나 Cursor가 환경을 로드하는 방식에 있습니다.

보안 체크리스트​

프로덕션 환경에서 MCP 서버를 배포하기 전에 이 체크리스트를 확인하세요:

  • API 키는 환경 변수에 저장, 구성 파일에 저장하지 않음
  • 시크릿이 포함된 경우 .cursor/mcp.json을 .gitignore에 추가
  • OAuth 리다이렉트 URI를 localhost로 잠금
  • disabledTools를 통해 파괴적 도구 비활성화
  • 결제 MCP 서버를 승인 게이트웨이로 래핑
  • 자동 실패를 방지하기 위해 토큰 새로고침 자동화
  • 원격 MCP 서버는 HTTPS만 사용
  • MCP 서버 로그에서 예상치 못한 인증 실패 모니터링
  • 액세스 토큰 범위를 최소 필요 권한으로 제한
  • 사용하지 않는 MCP 서버를 구성에서 제거

요약​

Cursor의 MCP 인증은 단순한 API 키 환경 변수에서 자동 토큰 새로고침이 포함된 복잡한 OAuth 흐름까지 스펙트럼에 걸쳐 있습니다. Live Meta Ads MCP는 60일 토큰 만료와 권한 범위 요구 사항으로 인해 일반적인 문제점입니다. 이 가이드의 패턴을 따르면, 민감한 작업을 인간 승인 레이어 뒤에 배치하고 자격 증명을 안전하게 유지하는 안전하고 신뢰할 수 있는 MCP 통합을 구축할 수 있습니다.