Confluence Communication Server
by KS-GEN-AI
- src
#!/usr/bin/env node
import axios, {AxiosRequestConfig} from 'axios';
import {Server} from "@modelcontextprotocol/sdk/server/index.js";
import {StdioServerTransport} from "@modelcontextprotocol/sdk/server/stdio.js";
import {CallToolRequestSchema, ListToolsRequestSchema,} from "@modelcontextprotocol/sdk/types.js";
/**
* Configure your Confluence instance credentials and URL.
*/
const CONFLUENCE_URL = process.env.CONFLUENCE_URL;
const CONFLUENCE_API_MAIL = process.env.CONFLUENCE_API_MAIL;
const CONFLUENCE_API_KEY = process.env.CONFLUENCE_API_KEY;
/**
* Create an MCP server to handle CQL queries and page retrieval.
*/
const server = new Server(
{
name: "Confluence communication server",
version: "0.1.0",
},
{
capabilities: {
tools: {},
},
}
);
/**
* Handler for listing available tools.
* Provides tools for querying Confluence with CQL and retrieving page content.
*/
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: "execute_cql_search",
description: "Execute a CQL query on Confluence to search pages",
inputSchema: {
type: "object",
properties: {
cql: {
type: "string",
description: "CQL query string"
},
limit: {
type: "integer",
description: "Number of results to return",
default: 10,
}
},
required: ["cql"]
}
},
{
name: "get_page_content",
description: "Get the content of a Confluence page",
inputSchema: {
type: "object",
properties: {
pageId: {
type: "string",
description: "Confluence Page ID"
}
},
required: ["pageId"]
}
}
]
};
});
/**
* Function to execute a CQL query against Confluence.
* @param {string} cql - CQL query string
* @param limit
* @returns {Promise<any>}
*/
async function executeCQL(cql: string, limit: number): Promise<any> {
try {
const params = {
cql,
limit
};
const response = await axios.get(`${CONFLUENCE_URL}/wiki/rest/api/content/search`, { // Updated URL
headers: getAuthHeaders().headers,
params
});
return response.data;
} catch (error: any) {
return {
error: error.response ? error.response.data : error.message
};
}
}
/**
* Function to retrieve content from a Confluence page by ID.
* @param {string} pageId - Confluence Page ID
* @returns {Promise<any>}
*/
async function getPageContent(pageId: string): Promise<any> {
try {
const response = await axios.get(`${CONFLUENCE_URL}/wiki/rest/api/content/${pageId}?expand=body.storage`, { // Updated URL
headers: getAuthHeaders().headers
});
return response.data;
} catch (error: any) {
return {
error: error.response ? error.response.data : error.message
};
}
}
/**
* Function to get the authentication headers.
* @returns {AxiosRequestConfig}
*/
function getAuthHeaders(): AxiosRequestConfig<any> {
const authHeader = `Basic ${Buffer.from(`${CONFLUENCE_API_MAIL}:${CONFLUENCE_API_KEY}`).toString('base64')}`;
return {
headers: {
'Authorization': authHeader,
'Content-Type': 'application/json',
}
};
}
/**
* Handler for the execute_cql_search and get_page_content tools.
*/
server.setRequestHandler(CallToolRequestSchema, async (request) => {
switch (request.params.name) {
case "execute_cql_search": {
const cql = String(request.params.arguments?.cql);
const limit = Number(request.params.arguments?.limit ?? 10);
if (!cql) {
throw new Error("CQL query is required");
}
const response = await executeCQL(cql, limit);
return {
content: [{
type: "text",
text: JSON.stringify(response, null, 2)
}]
};
}
case "get_page_content": {
const pageId = String(request.params.arguments?.pageId);
if (!pageId) {
throw new Error("Page ID is required");
}
const response = await getPageContent(pageId);
return {
content: [{
type: "text",
text: JSON.stringify(response, null, 2)
}]
};
}
default:
throw new Error("Unknown tool");
}
});
/**
* Start the server using stdio transport.
*/
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
}
main().catch((error) => {
console.error("Server error:", error);
process.exit(1);
});