Building a Confluence MCP Server for Claude Code: From Setup to Skills A developer built an open-source Confluence MCP server that allows Claude Code to automate Confluence workflows directly from the terminal. The server exposes tools for publishing pages, syncing content, and uploading images, using the Model Context Protocol to bridge AI assistants with external services. It validates credentials via Zod and registers with Claude Code through a .mcp.json configuration file. Automate your Confluence workflow directly from Claude Code — publish pages, sync content, and upload images without leaving your terminal. GitHub: https://github.com/tariqulislam/confluence-mcp-server https://github.com/tariqulislam/confluence-mcp-server MCP stands for Model Context Protocol — an open standard that lets AI assistants like Claude Code connect to external tools and services. An MCP server acts as a bridge: it exposes a set of tools that Claude Code can call, allowing it to interact with third-party systems like Confluence on your behalf. In this guide you will learn: confluence-mcp-mock/ ├── .env ← your credentials never committed ├── .env.example ← template ├── .mcp.json ← registers MCP servers with Claude Code ├── confluence-mcp/ │ ├── src/ │ │ ├── index.ts ← entry point │ │ ├── server.ts ← tool registration │ │ ├── config.ts ← env validation Zod │ │ ├── confluence/ │ │ │ ├── client.ts ← Axios HTTP client │ │ │ ├── api.ts ← REST API calls │ │ │ ├── parser.ts ← XHTML to structured data │ │ │ └── markdown-converter.ts │ │ └── tools/ ← one file per MCP tool │ │ ├── connection-check.ts │ │ ├── list-pages.ts │ │ ├── publish-page.ts │ │ ├── read-save-page.ts │ │ ├── upload-images.ts │ │ └── sync-pages.ts │ └── build/ ← compiled output └── .claude/skills/ ← slash command definitions ├── confluence-conn-check/ ├── confluence-page-list/ ├── publish-to-confluence/ ├── confluence-upload-images/ └── confluence-sync-pages/ The server reads all credentials from a single .env file at the project root. Copy the example template: cp .env.example .env Then fill in the four Confluence variables: .env never commit this file CONFLUENCE URL=https://your-confluence-instance.com/confluence/ CONFLUENCE USER=your.email@company.com CONFLUENCE PERSONAL ACCESS TOKEN=your token here CONFLUENCE SPACE KEY=MYSPACE The four variables you need: CONFLUENCE URL — Base URL of your Confluence instance. Must end with a trailing slash. Example: https://confluence.company.com/confluence/ CONFLUENCE USER — The email address tied to your Confluence account. CONFLUENCE PERSONAL ACCESS TOKEN — A Bearer token generated in Confluence settings. CONFLUENCE SPACE KEY — The space key where new pages will be created. Example: ENGINEERING When the server starts, config.ts reads the .env file and validates every variable using Zod — a TypeScript schema library. If any variable is missing or malformed, the server exits with a clear error instead of failing silently later. python // confluence-mcp/src/config.ts simplified import dotenv from 'dotenv'; import { z } from 'zod'; dotenv.config { path: join dirname, '..', '..', '.env' } ; const envSchema = z.object { CONFLUENCE URL: z.string .url , CONFLUENCE USER: z.string .email , CONFLUENCE PERSONAL ACCESS TOKEN: z.string .min 1 , CONFLUENCE SPACE KEY: z.string .min 1 , } ; export const config = envSchema.parse process.env ; The validated config is imported by client.ts , which creates a single Axios instance used by every tool: js // confluence-mcp/src/confluence/client.ts simplified const client = axios.create { baseURL: config.CONFLUENCE URL, headers: { Authorization: Bearer ${config.CONFLUENCE PERSONAL ACCESS TOKEN} , Accept: 'application/json', 'Content-Type': 'application/json', }, timeout: 30000, } ; Credentials are set once here and never repeated anywhere else in the codebase. Claude Code discovers MCP servers through the .mcp.json file in the project root: { "mcpServers": { "confluence": { "command": "node", "args": "./confluence-mcp/build/index.js" } } } This tells Claude Code: "When this project is open, launch the node process at that path and communicate with it over stdio." Install dependencies cd confluence-mcp && npm install Compile TypeScript to JavaScript npm run build Restart Claude Code to load the new server During development, use watch mode so the server recompiles on every save: npm run watch The server follows a clean three-layer pattern: Claude Code │ MCP protocol over stdio ▼ server.ts ← registers tools, routes calls │ ▼ tools/ .ts ← one file per tool, handles input/output │ ▼ confluence/api.ts ← REST API calls Confluence v1 endpoints server.ts declares every tool's name, description, and input schema in the ListToolsRequestSchema handler. Claude Code reads this to understand what tools exist. Calls are then routed in the CallToolRequestSchema handler: // server.ts simplified server.setRequestHandler ListToolsRequestSchema, async = { tools: { name: 'confluence connection check', description: 'Verify connection to Confluence and check authentication.', inputSchema: { type: 'object', properties: {}, required: }, }, { name: 'confluence list pages', description: 'List all child pages under a parent page.', inputSchema: { type: 'object', properties: { parent page id: { type: 'string', description: 'ID of the parent page' }, }, required: 'parent page id' , }, }, , } ; server.setRequestHandler CallToolRequestSchema, async request = { switch request.params.name { case 'confluence connection check': return { content: { type: 'text', text: await handleConnectionCheck } }; case 'confluence list pages': return { content: { type: 'text', text: await handleListPages args } }; } } ; confluence connection check — Verifies auth and returns server/user info confluence list pages — Lists all child pages under a parent confluence read save page — Downloads a page sections, tables, images, comments to local JSON confluence publish page — Converts markdown to Confluence XHTML and creates/updates a page confluence upload images — Bulk-uploads images from a local directory as page attachments confluence sync pages — Syncs all child pages to local markdown with change tracking Skills are the user-friendly layer on top of raw MCP tools. A skill is a directory under .claude/skills/ containing a SKILL.md file. .claude/skills/confluence-conn-check/ └── SKILL.md --- name: confluence-conn-check description: Verify Confluence server connection and authentication. argument-hint: no arguments required --- Confluence Connection Check Test the connection to Confluence and verify your credentials. Usage /confluence-conn-check MCP Tool confluence connection check The three frontmatter fields that matter: name — becomes the slash command e.g. /confluence-conn-check description — shown in the / autocomplete menu and used for auto-discovery by Claude argument-hint — hint shown in autocomplete, e.g.