Add gateway-first pattern: when AGILITON_API_KEY is set, route all external API calls through the gateway with X-API-Key auth. Falls back to direct API access when gateway is unavailable. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
109 lines
4.0 KiB
JavaScript
109 lines
4.0 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* Confluence MCP Server
|
|
*
|
|
* Provides Confluence Cloud page CRUD and collaboration via Model Context Protocol.
|
|
* Tools: confluence_list_spaces, confluence_create_space, confluence_search,
|
|
* confluence_get_page, confluence_create_page, confluence_update_page,
|
|
* confluence_get_comments, confluence_add_comment
|
|
*/
|
|
import { fileURLToPath } from 'url';
|
|
import { dirname, join } from 'path';
|
|
import dotenv from 'dotenv';
|
|
const __filename = fileURLToPath(import.meta.url);
|
|
const __dirname = dirname(__filename);
|
|
const envPath = join(__dirname, '..', '.env');
|
|
dotenv.config({ path: envPath, override: true });
|
|
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
import { ListToolsRequestSchema, CallToolRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
|
|
import { toolDefinitions, handleListSpaces, handleCreateSpace, handleSearch, handleGetPage, handleCreatePage, handleUpdatePage, handleGetComments, handleAddComment, } from './tools.js';
|
|
const server = new Server({ name: 'confluence-mcp', version: '1.0.0' }, { capabilities: { tools: {} } });
|
|
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
tools: toolDefinitions,
|
|
}));
|
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
const { name, arguments: args } = request.params;
|
|
const a = args;
|
|
let result;
|
|
try {
|
|
switch (name) {
|
|
case 'confluence_list_spaces':
|
|
result = await handleListSpaces({ limit: a.limit });
|
|
break;
|
|
case 'confluence_create_space':
|
|
result = await handleCreateSpace({
|
|
key: a.key,
|
|
name: a.name,
|
|
description: a.description,
|
|
});
|
|
break;
|
|
case 'confluence_search':
|
|
result = await handleSearch({
|
|
query: a.query,
|
|
space_id: a.space_id,
|
|
limit: a.limit,
|
|
});
|
|
break;
|
|
case 'confluence_get_page':
|
|
result = await handleGetPage({ page_id: String(a.page_id) });
|
|
break;
|
|
case 'confluence_create_page':
|
|
result = await handleCreatePage({
|
|
space_id: a.space_id,
|
|
title: a.title,
|
|
body: a.body,
|
|
parent_id: a.parent_id,
|
|
});
|
|
break;
|
|
case 'confluence_update_page':
|
|
result = await handleUpdatePage({
|
|
page_id: String(a.page_id),
|
|
title: a.title,
|
|
body: a.body,
|
|
version_number: a.version_number,
|
|
version_message: a.version_message,
|
|
});
|
|
break;
|
|
case 'confluence_get_comments':
|
|
result = await handleGetComments({
|
|
page_id: String(a.page_id),
|
|
limit: a.limit,
|
|
});
|
|
break;
|
|
case 'confluence_add_comment':
|
|
result = await handleAddComment({
|
|
page_id: String(a.page_id),
|
|
body: a.body,
|
|
});
|
|
break;
|
|
default:
|
|
result = `Unknown tool: ${name}`;
|
|
}
|
|
}
|
|
catch (error) {
|
|
const message = error instanceof Error ? error.message : String(error);
|
|
result = `Error: ${message}`;
|
|
}
|
|
return {
|
|
content: [{ type: 'text', text: result }],
|
|
};
|
|
});
|
|
async function main() {
|
|
const transport = new StdioServerTransport();
|
|
await server.connect(transport);
|
|
console.error('confluence-mcp: Server started');
|
|
}
|
|
main().catch((error) => {
|
|
console.error('confluence-mcp: Fatal error:', error);
|
|
process.exit(1);
|
|
});
|
|
process.on('SIGINT', async () => {
|
|
await server.close();
|
|
process.exit(0);
|
|
});
|
|
process.on('SIGTERM', async () => {
|
|
await server.close();
|
|
process.exit(0);
|
|
});
|