나는 소셜 미디어 자동화를 위해 LangGraph를 거의 사용했지만 (대신 MCP Server를 만든 이유)
Source: Dev.to
소개
나는 방금 X에 첫 번째 AI‑생성 트윗을 올렸다. 이 트윗은 Groq의 무료 AI로 생성되고, 내가 만든 커스텀 MCP 서버에서 처리된 뒤 Ayrshare를 통해 게시되었으며—모두 월 $0 비용으로 운영된다.
전체 구축 시간? 하루 미만.
나는 거의 LangGraph를 사용할 뻔했다. LangChain의 2,000줄짜리 소셜‑미디어‑에이전트를 며칠 동안 공부했다. 이것은 프로덕션에 바로 사용할 수 있고, 검증된 구현이며, 인상적이다. 하지만 나는 다른 길을 선택했고 그 과정에서 월 $45를 절감했다.
LangGraph를 사용하지 않은 이유
LangGraph는 인상적이다. LangChain 소셜‑미디어‑에이전트 저장소(1.7k+ 스타)는 다음을 제공한다:
- 승인 게이트가 있는 인간‑인‑루프 워크플로우
- 복잡한 프로세스를 위한 상태 체크포인팅
- 다단계 에이전트 오케스트레이션
- 검증된 레퍼런스 구현
소셜‑미디어 자동화를 위해 LangGraph는 콘텐츠 생성, 검토 사이클, 게시 워크플로우, 분석까지—내장된 상태 관리와 함께—모두 제공한다.
맞지 않음
내 사용 사례는 훨씬 단순했다:
- 사용자가 콘텐츠를 제공한다
- AI가 플랫폼에 맞게 최적화한다
- 초안으로 저장한다
- 준비가 되면 게시한다
그래프가 필요하지 않았다; 단일 함수 호출만 필요했다. LangGraph Cloud 설정을 절반쯤 진행했을 때, 내가 잘못된 문제를 풀고 있다는 것을 깨달았다.
LangGraph 요구 사항
- 지속적인 런타임 (LangGraph Cloud $29/월 최소, 혹은 VPS)
- 체크포인팅을 위한 PostgreSQL/MongoDB
- 항상 켜져 있는 인프라
- 프레임워크‑특화 개념 (그래프, 노드, 엣지)
LangGraph는 무상태, 엣지‑배포 함수이며 콜드 스타트가 없는 Cloudflare Workers에서는 실행할 수 없다. 프레임워크를 바꾸면 모든 것을 다시 작성해야 한다.
Model Context Protocol (MCP)를 선택한 이유
MCP는 프레임워크가 아니라 프로토콜이다. 어떤 MCP 클라이언트(Claude Desktop, VS Code + Continue, 커스텀 UI)든 내 서버를 수정 없이 사용할 수 있다.
아키텍처 가정
- 무상태 요청/응답
- 영구성을 위한 SQLite (Cloudflare D1)
- 콜드 스타트 없음
- 전역 분산
구현 스냅샷
- ~800줄 TypeScript
- 8 도구, 3 리소스, 3 프롬프트
- 초안에 대한 전체 CRUD
- AI 콘텐츠 생성
- 다중 플랫폼 게시
MCP 채택이 늘어남에 따라(Anthropic, Zed, Continue, Cody 등) 서버의 활용도는 특정 프레임워크의 라이프사이클에 얽매이지 않기 때문에 급증한다.
비용 비교
| 구성 요소 | MCP 접근법 | LangGraph 접근법 |
|---|---|---|
| 서버 / 런타임 | Cloudflare Workers $5/월 (D1, KV, Vectorize, R2 포함) | LangGraph Cloud $29/월 (또는 VPS $10‑20) |
| LLM API | Groq 무료 티어 | OpenAI $20‑30/월 |
| 데이터베이스 | SQLite (D1) $0‑10/월 | PostgreSQL/MongoDB $0‑10/월 |
| 소셜‑미디어 API | Ayrshare 무료 (월 10포스트) | — |
| 총합 | $5/월 | $50‑80/월 |
프리랜서가 아이디어를 테스트할 때 $5와 $50의 차이는 큰 의미가 있다.
아키텍처 다이어그램
Claude Desktop (Client)
↓ JSON‑RPC over stdio
MCP Server (TypeScript)
├── Tools (LLM‑controlled actions)
│ ├── draft_post
│ ├── schedule_post
│ ├── post_immediately
│ ├── generate_thread
│ └── analyze_engagement
├── Resources (App‑controlled data)
│ ├── drafts://list
│ ├── scheduled://posts
│ └── stats://summary
├── Prompts (User‑invoked templates)
│ ├── write_tweet
│ ├── linkedin_post
│ └── thread_generator
├── Storage (SQLite → D1)
└── Integrations
├── Ayrshare (multi‑platform posting)
└── Groq (AI content generation)
각 레이어는 독립적이며 교체 가능하다.
핵심 구성 요소
스토리지 (SQLite → Cloudflare D1)
import Database from 'better-sqlite3';
export class StorageService {
private db: Database.Database;
constructor(dbPath: string) {
this.db = new Database(dbPath);
this.initializeSchema();
}
createDraft(data: DraftData): Draft {
const id = crypto.randomUUID();
const now = new Date().toISOString();
this.db.prepare(`
INSERT INTO drafts (id, content, platform, tone, status, created_at)
VALUES (?, ?, ?, ?, 'draft', ?)
`).run(id, data.content, data.platform, data.tone, now);
return this.getDraft(id);
}
}
Cloudflare D1로 마이그레이션
// Local development
const db = new Database('./social_media.db');
// Edge runtime
const db = env.DB; // Cloudflare D1 binding
동일한 SQL, 다른 런타임.
소셜‑미디어 API (Ayrshare)
export class SocialMediaAPI {
private apiKey: string;
private baseUrl = 'https://app.ayrshare.com/api';
async postImmediately(content: string, platforms: string[]) {
const response = await fetch(`${this.baseUrl}/post`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${this.apiKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
post: content,
platforms,
}),
});
return response.json();
}
}
하나의 API, 열 개의 플랫폼.
콘텐츠 생성기 (Groq 무료 티어)
import Groq from 'groq-sdk';
export class ContentGenerator {
private client: Groq;
async generate(request: GenerateRequest): Promise {
const systemPrompt = this.buildSystemPrompt(request);
const response = await this.client.chat.completions.create({
model: 'llama-3.3-70b-versatile', // FREE
messages: [
{ role: 'system', content: systemPrompt },
{ role: 'user', content: request.input },
],
max_tokens: 1000,
temperature: 0.7,
});
const text = response.choices[0]?.message?.content || '';
return this.parseResponse(text, request);
}
private buildSystemPrompt(request: GenerateRequest): string {
const platformPrompts = {
twitter: `Create engaging tweets that:
- Stay under ${request.maxLength} characters (STRICT)
- Use ${request.tone} tone
- Hook readers in the first line
- End with engagement (question or CTA)`,
linkedin: `Create professional posts that:
- Are detailed (1,300‑1,500 characters)
- Use ${request.tone} tone
- Start with a compelling hook
- Include 3‑5 key insights with takeaways`,
};
return platformPrompts[request.platform];
}
}
품질은 뛰어나고 비용은 $0. 제한 속도: 30 req/min(충분히 여유).
MCP 서버 스켈레톤
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
const server = new Server(
{ name: 'social-media-server', version: '1.0.0' },
{ capabilities: { tools: {}, resources: {}, prompts: {} } }
);
// Define tools
server.setRequestHandler(ListToolsRequestSchema, async () => ({
tools: [
{
name: 'draft_post',
// …
},
// other tools …
],
}));
서버는 도구, 리소스, 프롬프트를 간단한 JSON‑RPC 인터페이스로 노출하며, MCP 호환 클라이언트라면 누구든 사용할 수 있다.
정리
경량 Model Context Protocol 서버를 Cloudflare Workers에 배포함으로써 나는:
- 지속적인 런타임과 복잡한 상태 관리 필요성을 없앴다
- 월 비용을 ~$50에서 $5로 줄였다
- 하루 안에 완전한 소셜‑미디어 자동화 파이프라인을 제공했다
AI 워크플로우가 단순—생성 → 검토 → 실행—이라면, 프레임워크‑우선 접근보다 프로토콜‑우선 접근이 훨씬 경제적이고 민첩할 수 있다.