mcp-blogspot-posting
Blogger Posting
Documentation
MCP Blogger Posting Server (MCP λΈλ‘κ·Έ ν¬μ€ν μλ²)
Google Blogger APIμ MCP(Model Context Protocol) Toolμ κ²°ν©ν μ€μ ν λΈλ‘κ·Έ ν¬μ€ν μλν μλ²
π μ£Όμ μ λ°μ΄νΈ (2025-06-14)
- server/info μλν¬μΈνΈ μ§μ: MCP Inspector/ν΄λΌμ΄μΈνΈμμ `server/info` μμ²μΌλ‘ μλ² μ΄λ¦/λ²μ μ 보λ₯Ό μ§μ μ‘°νν μ μμ΅λλ€.
- λ‘κΉ μ μ± κ°ν: MCP μλ²μ λͺ¨λ λ‘κ·Έλ λ°λμ stderr(console.error) λλ MCP νλ‘ν μ½ μ μ© λ‘κΉ ν¨μλ§ μ¬μ©ν΄μΌ νλ©°, stdout μ€μΌ μ νλ‘ν μ½ νμ± μλ¬κ° λ°μν μ μμ΅λλ€.
- μ€μκ° JSON μ‘μ μΆμ : `[DEBUG][STDIO_SEND] ...` ννμ stderr λ‘κ·Έλ‘ μ€μ μ‘μ λλ JSON λ©μμ§λ₯Ό μ€μκ°μΌλ‘ μΆμ ν μ μμ΅λλ€.
β¨ μ£Όμ κΈ°λ₯
- Google Blogger API μ°λ: MCP Toolλ‘ λΈλ‘κ·Έ ν¬μ€ν /λ°°μΉν¬μ€ν μλν
- MCP Tool νμ€ μ§μ: LLM/MCP ν΄λΌμ΄μΈνΈμμ blog-post, blog-batch-post Tool νΈμΆ κ°λ₯
- νκ²½λ³μ κΈ°λ° λ³΄μ/μ€μ : .env, client_secret νμΌ, μΈμ¦ ν ν° μμ κ΄λ¦¬
- ν μ€νΈ/μ΄μ/νμ₯μ±: μ λ/ν΅ν© ν μ€νΈ, νκ²½λ³ μ€μ , 보μ κ°μ΄λ μ 곡
- κ²½λνλ ꡬ쑰: λΆνμν 리μμ€/ν둬ννΈ/μμ μ½λ μ κ±°, Tool μ€μ¬μ μμ MCP μλ²
- νλΌλ―Έν° κΈ°λ° config: credentialPath, blogUrl λ± νκ²½λ³μ/νλΌλ―Έν°λ‘ μ μ°νκ² μ€μ
- μλ² μ 보 μλν¬μΈνΈ(server/info) μ 곡: MCP Inspector/ν΄λΌμ΄μΈνΈμμ `server/info` μμ²μΌλ‘ μλ² μ΄λ¦/λ²μ μ 보λ₯Ό μ§μ μ‘°ν κ°λ₯
π λΉ λ₯Έ μμ
1. νμ νμΌ μ€λΉ
- `.env` νμΌ(νκ²½λ³μ)
- Google OAuth2 client_secret JSON νμΌ(κ²½λ‘λ νκ²½λ³μλ‘ μ§μ )
- `.gitignore`μ `.env`, `client_secret*.json` λ°λμ ν¬ν¨
2. νκ²½λ³μ μμ(.env)
GOOGLE_CLIENT_SECRET_PATH=C:/dev/mcp-servers/mcp-blogspot-posting/client_secret_...json
SESSION_SECRET=your-session-secret
BLOG_ID=your-blog-id (μ ν)
PORT=30003. μμ‘΄μ± μ€μΉ λ° λΉλ
npm install
npm run build4. μλ² μ€ν
npm run dev5. MCP Tool μ¬μ© μμ
- MCP Inspector/ν΄λΌμ΄μΈνΈμμ blog-post, blog-batch-post Tool νμΈ λ° νΈμΆ
- μ λ ₯ μμ:
{
"title": "ν
μ€νΈ ν¬μ€νΈ",
"content": "λ΄μ©",
"labels": ["ν
μ€νΈ", "μλν"],
"isDraft": false
}- μΈμ¦ ν ν°μ΄ μμΌλ©΄ μλ¬, μΈμ¦ ν μ μ ν¬μ€ν
π μ£Όμ ꡬ쑰
mcp-blogspot-posting/
βββ src/
β βββ managers/ # Tool νΈλ€λ¬
β βββ services/ # BloggerService λ± λΉμ¦λμ€ λ‘μ§
β βββ types/ # νμ
μ μ (bloggerTypes λ±)
β βββ lib/ # μΈμ¦/ν ν° κ΄λ¦¬ λ±
βββ test/ # μ λ/ν΅ν© ν
μ€νΈ
βββ .env # νκ²½λ³μ (gitignore νμ)
βββ client_secret_*.json # Google OAuth2 μν¬λ¦Ώ (gitignore νμ)
βββ .gitignore
βββ package.json
βββ README.mdπ¦ μλ² μμ λ° λΈλ‘κ·Έ ID κ΄λ¦¬ μ μ±
1. μλ² μμ μ
2. API νΈμΆ μ
3. μ΄μ/보μ μ£Όμμ¬ν
π§ͺ ν μ€νΈ
- `npm test`λ‘ μ λ ν μ€νΈ μ€ν
- ν΅ν© ν μ€νΈλ .env/νκ²½λ³μ/μ€μ blogUrl λ± μ€λ°μ΄ν° μ£Όμ νμ
- MCP Tool μ μ λμ, μΈμ¦ μ€ν¨/μ±κ³΅ μΌμ΄μ€ μλ κ²μ¦
π μΆκ° μ°Έκ³
- MCP Inspector λ±μΌλ‘ Tool λͺ©λ‘/νΈμΆ ν μ€νΈ κΆμ₯
- μΈμ¦/ν ν° λ°κΈμ Google OAuth2 곡μ κ°μ΄λ μ°Έκ³
- Tool/μλΉμ€ νμ₯ μ managers/services ꡬ쑰 νμ©
- BaseServer ꡬ쑰 κ°μ μΌλ‘ λΆνμν 리μμ€/ν둬ννΈ/μμ μ½λ μμ΄ κ²½λν κ°λ₯
π οΈ MCP Tool μ λ ₯/μΆλ ₯ ν¬λ§· λ° μμ
blog-post Tool
- μ€λͺ : Google Bloggerμ λ¨μΌ ν¬μ€νΈλ₯Ό μμ±ν©λλ€.
- μ λ ₯(JSON):
{
"title": "ν¬μ€νΈ μ λͺ©", // (νμ)
"content": "ν¬μ€νΈ λ΄μ©(HTML)", // (νμ)
"labels": ["λΌλ²¨1", "λΌλ²¨2"], // (μ ν)
"isDraft": true, // (μ ν, κΈ°λ³Έκ°: true)
}- μ λ ₯ νλ μ€λͺ :
| νλλͺ | νμ | νμ | μ€λͺ |
|---|---|---|---|
| ---------- | ----------- | ------ | --------------------- |
| title | string | β | ν¬μ€νΈ μ λͺ© |
| content | string | β | ν¬μ€νΈ λ΄μ©(HTML) |
| labels | string[] | β | λΌλ²¨ λͺ©λ‘ |
| isDraft | boolean | β | μ΄μ μ¬λΆ(true/false, κΈ°λ³Έκ°: true) |
- λΉκ³ : λΈλ‘κ·Έ IDλ μλ² νκ²½λ³μ(BLOG_ID)λ‘ κ΄λ¦¬λλ©°, μ¬μ©μκ° μ λ ₯ν νμκ° μμ΅λλ€.
- μΆλ ₯(JSON):
{
"content": [
{ "type": "text", "text": "ν¬μ€νΈ μμ± μ±κ³΅!\nURL: https://...\nμ λͺ©: ..." }
],
"isError": false
}- μΆλ ₯ νλ μ€λͺ :
| νλλͺ | νμ | μ€λͺ |
|---|---|---|
| ---------- | ----------- | -------------------------------------- |
| content | array | λ©μμ§(μ±κ³΅/μ€ν¨/μμΈμ 보) |
| isError | boolean | μ€ν¨ μ¬λΆ(true: μλ¬, false: μ±κ³΅) |
- μλ¬ μμ:
{
"content": [
{ "type": "text", "text": "μΈμ¦ ν ν°μ΄ μμ΅λλ€. λ¨Όμ μΈμ¦μ μλ£νμΈμ." }
],
"isError": true
}blog-batch-post Tool
- μ€λͺ : μ¬λ¬ ν¬μ€νΈλ₯Ό ν λ²μ μμ±ν©λλ€.
- μ λ ₯(JSON):
{
"posts": [
// (νμ)
{
"title": "μ λͺ©1", // (νμ)
"content": "λ΄μ©1", // (νμ)
"labels": ["λΌλ²¨A"], // (μ ν)
"isDraft": true, // (μ ν, κΈ°λ³Έκ°: true)
},
{
"title": "μ λͺ©2", // (νμ)
"content": "λ΄μ©2", // (νμ)
},
],
}- μ λ ₯ νλ μ€λͺ :
| νλλͺ | νμ | νμ | μ€λͺ |
|---|---|---|---|
| ---------- | ----------- | ------ | --------------------- |
| posts | object[] | β | ν¬μ€νΈ λ°°μ΄ |
| β title | string | β | ν¬μ€νΈ μ λͺ© |
| β content | string | β | ν¬μ€νΈ λ΄μ©(HTML) |
| β labels | string[] | β | λΌλ²¨ λͺ©λ‘ |
| β isDraft | boolean | β | μ΄μ μ¬λΆ(true/false, κΈ°λ³Έκ°: true) |
- λΉκ³ : λΈλ‘κ·Έ IDλ μλ² νκ²½λ³μ(BLOG_ID)λ‘ κ΄λ¦¬λλ©°, μ¬μ©μκ° μ λ ₯ν νμκ° μμ΅λλ€.
- μΆλ ₯(JSON):
{
"content": [
{ "type": "text", "text": "λ°°μΉ ν¬μ€ν
μλ£! μ±κ³΅: 2, μ€ν¨: 0" },
{ "type": "text", "text": "[ {\"success\":true,\"postId\":\"...\",...} ]" }
],
"isError": false
}- μΆλ ₯ νλ μ€λͺ :
| νλλͺ | νμ | μ€λͺ |
|---|---|---|
| ---------- | ----------- | -------------------------------------- |
| content | array | λ©μμ§(μ±κ³΅/μ€ν¨/μμΈμ 보) |
| isError | boolean | μ€ν¨ μ¬λΆ(true: μλ¬, false: μ±κ³΅) |
- μλ¬ μμ:
{
"content": [
{ "type": "text", "text": "μΈμ¦ ν ν°μ΄ μμ΅λλ€. λ¨Όμ μΈμ¦μ μλ£νμΈμ." }
],
"isError": true
}π λΌμ΄μ μ€
μ΄ νλ‘μ νΈλ MIT λΌμ΄μ μ€λ₯Ό λ°λ¦ λλ€.
βοΈ ν΄λΌμ΄μΈνΈμμ MCP μλ² μ€μ μμ
MCP ν΄λΌμ΄μΈνΈ(μ: MCP Inspector, ν΅ν© MCP νλ«νΌ λ±)μμ blogspot-posting μλ²λ₯Ό μ€νν λλ μλμ κ°μ΄ `mcpServers` μ€μ μ μ¬μ©ν©λλ€.
{
"mcpServers": {
"blogspot-posting": {
"command": "npx",
"args": ["-y", "server-blogspot-posting"],
"env": {
"GOOGLE_CLIENT_SECRET_PATH": "/path/to/client_secret_xxx.json",
"BLOG_ID": "your-blog-id",
},
},
},
}- `command`, `args`: MCP μλ² μ€ν λͺ λ Ή λ° μΈμ
- `env`: μλ²μ μ£Όμ ν νκ²½λ³μ(μν¬λ¦Ώ κ²½λ‘)
- νμμ λ°λΌ μΆκ° νκ²½λ³μ(.envμ μλ κ°)λ₯Ό λͺ¨λ envμ λͺ μ κ°λ₯
> NOTE: νμ¬ λ²μ μμλ SESSION_SECRETμ νμνμ§ μμ΅λλ€. (μΈμ κΈ°λ° μΈμ¦/λ‘κ·ΈμΈ κΈ°λ₯μ΄ μΆκ°λ κ²½μ°μλ§ νμ)
β οΈ blogId μΊμ νμΌ(.blog_id_cache.json) κ²½λ‘ μ μ± λ° μ£Όμμ¬ν
- λΈλ‘κ·Έ ID μΊμ νμΌ(.blog_id_cache.json)μ νμ νλ‘μ νΈ λ£¨νΈ(μ΅μμ ν΄λ)μλ§ μμ±λ©λλ€.
- λΉλ(dist) ν΄λ λ± λ€λ₯Έ μμΉμ μΊμ νμΌμ΄ μμ±λλ λ¬Έμ λ₯Ό 2025-06-12μ μμ νμμΌλ©°, μ΄μ μ΄λ€ νκ²½μμ μ€νν΄λ 루νΈμλ§ μμ±λ©λλ€.
- dist/.blog_id_cache.json λ± μλͺ»λ μμΉμ μΊμ νμΌμ΄ μλ€λ©΄ μλμΌλ‘ μμ νμΈμ.
- λ°λμ .gitignoreμ .blog_id_cache.jsonμ ν¬ν¨ν΄ gitμ 컀λ°λμ§ μλλ‘ νμΈμ.
- μλ² μ€ν/λΉλ μμΉμ 무κ΄νκ² μΊμ νμΌμ΄ 루νΈμλ§ μμ±λλμ§ μ΄μ/ν μ€νΈ νκ²½μμ νμΈνμΈμ.
π§βπ» λλ²κΉ /μ΄μ κ°μ΄λ
- MCP μλ²μ λͺ¨λ λ‘κ·Έλ λ°λμ stderr(console.error) λλ MCP νλ‘ν μ½ μ μ© λ‘κΉ ν¨μλ§ μ¬μ©ν΄μΌ νλ©°, stdout μ€μΌ μ νλ‘ν μ½ νμ± μλ¬κ° λ°μν μ μμ΅λλ€.
- `[DEBUG][STDIO_SEND] ...` stderr λ‘κ·Έλ₯Ό ν΅ν΄ μ€μ μ‘μ λλ JSON λ©μμ§λ₯Ό μ€μκ°μΌλ‘ μΆμ νμ¬, νμ± μλ¬ λ° νλ‘ν μ½ λ¬Έμ λ₯Ό μ μνκ² μ§λ¨ν μ μμ΅λλ€.
- Inspector/ν΄λΌμ΄μΈνΈμμ `server/info`λ‘ μλ² μ 보 μ‘°ν λ° tools/list λ± μ μ λμμ νμΈνμΈμ.
π¦ MCP Tool/μλ² μλν¬μΈνΈ μμ
- μλ² μ 보 μ‘°ν(server/info):
{ "method": "server/info" }β μλ΅ μμ:
{ "name": "blogspot-mcp-server", "version": "1.0.0" }Frequently asked questions
What is mcp-blogspot-posting?
mcp-blogspot-posting is Blogger Posting
How do I install mcp-blogspot-posting?
Open the GitHub repository and follow its README. Most MCP servers are added to your client's MCP config, then called by your agent.
Is mcp-blogspot-posting open source?
Yes β it is hosted on GitHub at https://github.com/beanspapa/mcp-blogspot-posting.
Related MCP tools
Model Context Protocol Servers
The Open-Source Multimodal AI Agent Stack: Connecting Cutting-Edge AI Models and Agent Infra
A MCP for Claude Desktop / Claude Code / Windsurf / Cursor to build n8n workflows for you
MCP server to provide Figma layout information to AI coding agents like Cursor
The world's best AI personal assistant for email. Open source app to help you reach inbox zero fast.
Instant is the best backend for AI-coded apps. You get auth, permissions, storage, presence, and streams β everything you need to ship apps your users will love.
Run your own MCP server? See who uses it and what to fix.
Measure it with TrackMCP