lunaarc-mcp 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,123 @@
1
+ # LunaArc MCP Server
2
+
3
+ MCP (Model Context Protocol) server for [LunaArc](https://lunaarc.de) - Connect AI assistants like Claude to your LunaArc workspace.
4
+
5
+ ## Features
6
+
7
+ - **Wiki**: List, read, search, create and update wiki pages
8
+ - **Kanban**: View board, read cards, create and manage tasks
9
+ - **Todos**: View todo lists, read and create todos
10
+
11
+ ## Installation
12
+
13
+ ```bash
14
+ npx lunaarc-mcp
15
+ ```
16
+
17
+ Or install globally:
18
+
19
+ ```bash
20
+ npm install -g lunaarc-mcp
21
+ ```
22
+
23
+ ## Configuration
24
+
25
+ ### Environment Variables
26
+
27
+ | Variable | Description | Required |
28
+ |----------|-------------|----------|
29
+ | `LUNAARC_API_URL` | LunaArc MCP API endpoint | Yes |
30
+ | `LUNAARC_TOKEN` | Your project token (starts with `lac_prj_`) | Yes |
31
+
32
+ Get your token from: **LunaArc Project Settings > Integrations > MCP Integration**
33
+
34
+ ### Claude Desktop
35
+
36
+ Add to your Claude Desktop config (`~/Library/Application Support/Claude/claude_desktop_config.json` on macOS):
37
+
38
+ ```json
39
+ {
40
+ "mcpServers": {
41
+ "lunaarc": {
42
+ "command": "npx",
43
+ "args": ["-y", "lunaarc-mcp"],
44
+ "env": {
45
+ "LUNAARC_API_URL": "https://api.lunaarc.de/mcp/v1",
46
+ "LUNAARC_TOKEN": "lac_prj_your_token_here"
47
+ }
48
+ }
49
+ }
50
+ }
51
+ ```
52
+
53
+ ### Claude Code
54
+
55
+ Add to your Claude Code settings (`.claude/settings.json` or global config):
56
+
57
+ ```json
58
+ {
59
+ "mcpServers": {
60
+ "lunaarc": {
61
+ "command": "npx",
62
+ "args": ["-y", "lunaarc-mcp"],
63
+ "env": {
64
+ "LUNAARC_API_URL": "https://api.lunaarc.de/mcp/v1",
65
+ "LUNAARC_TOKEN": "lac_prj_your_token_here"
66
+ }
67
+ }
68
+ }
69
+ }
70
+ ```
71
+
72
+ ## Available Tools
73
+
74
+ ### Wiki Tools
75
+
76
+ | Tool | Description |
77
+ |------|-------------|
78
+ | `wiki_list` | List all wiki pages with hierarchy |
79
+ | `wiki_read` | Read a specific page by ID or slug |
80
+ | `wiki_search` | Search pages by title and content |
81
+ | `wiki_page_create` | Create a new wiki page |
82
+ | `wiki_page_update` | Update an existing page |
83
+
84
+ ### Kanban Tools
85
+
86
+ | Tool | Description |
87
+ |------|-------------|
88
+ | `kanban_board_get` | Get board with all columns and cards |
89
+ | `kanban_card_read` | Read card details |
90
+ | `kanban_card_create` | Create card in AI Inbox |
91
+ | `kanban_card_update` | Update AI-created cards |
92
+ | `kanban_assigned_get` | Get cards assigned to AI |
93
+ | `kanban_assigned_update` | Update assigned cards |
94
+ | `kanban_card_move` | Move assigned cards between columns |
95
+ | `kanban_card_comment` | Add comments to assigned cards |
96
+
97
+ ### Todo Tools
98
+
99
+ | Tool | Description |
100
+ |------|-------------|
101
+ | `todos_lists` | Get all todo lists with todos |
102
+ | `todos_read` | Read todo details |
103
+ | `todos_create` | Create a new todo |
104
+ | `todos_update` | Update a todo |
105
+
106
+ ## AI Workflow
107
+
108
+ Cards created by AI are placed in a special **AI Inbox** column for human review. The AI can:
109
+
110
+ 1. Create cards in the AI Inbox
111
+ 2. Update cards it created (while in AI Inbox)
112
+ 3. Work on cards assigned to it by humans
113
+ 4. Move assigned cards through the workflow
114
+ 5. Add comments to document progress
115
+
116
+ ## Requirements
117
+
118
+ - Node.js 18 or higher
119
+ - LunaArc account with MCP integration enabled
120
+
121
+ ## License
122
+
123
+ MIT
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+
3
+ import('../dist/server.js');
@@ -0,0 +1,176 @@
1
+ interface WikiPageSummary {
2
+ id: string;
3
+ parent_id: string | null;
4
+ title: string;
5
+ slug: string;
6
+ icon: string | null;
7
+ position: number;
8
+ created_at: string;
9
+ updated_at: string;
10
+ }
11
+ interface WikiPage {
12
+ id: string;
13
+ project_id: string;
14
+ parent_id: string | null;
15
+ title: string;
16
+ slug: string;
17
+ content: string | null;
18
+ icon: string | null;
19
+ position: number;
20
+ created_by: string;
21
+ created_at: string;
22
+ updated_at: string;
23
+ }
24
+ interface WikiSearchResult {
25
+ id: string;
26
+ title: string;
27
+ slug: string;
28
+ icon: string | null;
29
+ snippet: string;
30
+ updated_at: string;
31
+ }
32
+ interface KanbanCard {
33
+ id: string;
34
+ title: string;
35
+ description: string | null;
36
+ position: number;
37
+ priority: string;
38
+ labels: string[];
39
+ due_date: string | null;
40
+ created_by_ai: boolean;
41
+ created_at: string;
42
+ updated_at: string;
43
+ }
44
+ interface AIAssignedCard {
45
+ id: string;
46
+ column_id: string;
47
+ column_name: string;
48
+ title: string;
49
+ description: string | null;
50
+ priority: string;
51
+ labels: string[];
52
+ due_date: string | null;
53
+ created_at: string;
54
+ updated_at: string;
55
+ }
56
+ interface KanbanColumn {
57
+ id: string;
58
+ name: string;
59
+ position: number;
60
+ color: string | null;
61
+ wip_limit: number | null;
62
+ is_ai_inbox: boolean;
63
+ card_count: number;
64
+ cards: KanbanCard[];
65
+ }
66
+ interface KanbanBoard {
67
+ board: {
68
+ id: string;
69
+ name: string;
70
+ description: string | null;
71
+ };
72
+ columns: KanbanColumn[];
73
+ }
74
+ interface Todo {
75
+ id: string;
76
+ title: string;
77
+ description: string | null;
78
+ completed: boolean;
79
+ completed_at: string | null;
80
+ due_date: string | null;
81
+ position: number;
82
+ created_at: string;
83
+ updated_at: string;
84
+ }
85
+ interface TodoList {
86
+ id: string;
87
+ name: string;
88
+ description: string | null;
89
+ position: number;
90
+ todo_count: number;
91
+ completed_count: number;
92
+ todos: Todo[];
93
+ }
94
+ export declare class LunaArcApiClient {
95
+ private baseUrl;
96
+ private token;
97
+ constructor(baseUrl: string, token: string);
98
+ private request;
99
+ listWikiPages(): Promise<WikiPageSummary[]>;
100
+ getWikiPage(idOrSlug: string): Promise<WikiPage>;
101
+ searchWiki(query: string): Promise<WikiSearchResult[]>;
102
+ createWikiPage(params: {
103
+ title: string;
104
+ content?: string;
105
+ parent_id?: string;
106
+ icon?: string;
107
+ }): Promise<{
108
+ id: string;
109
+ message: string;
110
+ }>;
111
+ updateWikiPage(pageId: string, params: {
112
+ title?: string;
113
+ content?: string;
114
+ icon?: string;
115
+ }): Promise<{
116
+ id: string;
117
+ message: string;
118
+ }>;
119
+ getKanbanBoard(): Promise<KanbanBoard>;
120
+ getKanbanCard(cardId: string): Promise<KanbanCard>;
121
+ createKanbanCard(params: {
122
+ title: string;
123
+ description?: string;
124
+ priority?: 'low' | 'medium' | 'high' | 'urgent';
125
+ labels?: string[];
126
+ }): Promise<{
127
+ id: string;
128
+ message: string;
129
+ }>;
130
+ updateKanbanCard(cardId: string, params: {
131
+ title?: string;
132
+ description?: string;
133
+ priority?: 'low' | 'medium' | 'high' | 'urgent';
134
+ labels?: string[];
135
+ }): Promise<{
136
+ id: string;
137
+ message: string;
138
+ }>;
139
+ getAIAssignedCards(): Promise<AIAssignedCard[]>;
140
+ moveKanbanCard(cardId: string, column: string): Promise<{
141
+ id: string;
142
+ message: string;
143
+ }>;
144
+ updateAIAssignedCard(cardId: string, params: {
145
+ title?: string;
146
+ description?: string;
147
+ priority?: 'low' | 'medium' | 'high' | 'urgent';
148
+ labels?: string[];
149
+ }): Promise<{
150
+ id: string;
151
+ message: string;
152
+ }>;
153
+ addKanbanCardComment(cardId: string, content: string): Promise<string>;
154
+ getTodoLists(): Promise<TodoList[]>;
155
+ getTodo(todoId: string): Promise<Todo>;
156
+ createTodo(params: {
157
+ todo_list_id: string;
158
+ title: string;
159
+ description?: string;
160
+ due_date?: string;
161
+ }): Promise<{
162
+ id: string;
163
+ message: string;
164
+ }>;
165
+ updateTodo(todoId: string, params: {
166
+ title?: string;
167
+ description?: string;
168
+ completed?: boolean;
169
+ due_date?: string | null;
170
+ }): Promise<{
171
+ id: string;
172
+ message: string;
173
+ }>;
174
+ }
175
+ export declare function createApiClient(): LunaArcApiClient;
176
+ export {};
@@ -0,0 +1,124 @@
1
+ "use strict";
2
+ // API client for communicating with LunaArc REST API
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.LunaArcApiClient = void 0;
5
+ exports.createApiClient = createApiClient;
6
+ class LunaArcApiClient {
7
+ baseUrl;
8
+ token;
9
+ constructor(baseUrl, token) {
10
+ this.baseUrl = baseUrl.replace(/\/$/, ''); // Remove trailing slash
11
+ this.token = token;
12
+ }
13
+ async request(endpoint, options = {}) {
14
+ const url = `${this.baseUrl}${endpoint}`;
15
+ const response = await fetch(url, {
16
+ ...options,
17
+ headers: {
18
+ 'Content-Type': 'application/json',
19
+ Authorization: `Bearer ${this.token}`,
20
+ ...options.headers,
21
+ },
22
+ });
23
+ const data = (await response.json());
24
+ if (!response.ok || !data.success) {
25
+ throw new Error(data.message || data.error || `API error: ${response.status}`);
26
+ }
27
+ return data.data;
28
+ }
29
+ // Wiki API methods
30
+ async listWikiPages() {
31
+ return this.request('/wiki/pages');
32
+ }
33
+ async getWikiPage(idOrSlug) {
34
+ return this.request(`/wiki/pages/${encodeURIComponent(idOrSlug)}`);
35
+ }
36
+ async searchWiki(query) {
37
+ return this.request(`/wiki/search?q=${encodeURIComponent(query)}`);
38
+ }
39
+ async createWikiPage(params) {
40
+ return this.request('/wiki/pages', {
41
+ method: 'POST',
42
+ body: JSON.stringify(params),
43
+ });
44
+ }
45
+ async updateWikiPage(pageId, params) {
46
+ return this.request(`/wiki/pages/${encodeURIComponent(pageId)}`, {
47
+ method: 'PATCH',
48
+ body: JSON.stringify(params),
49
+ });
50
+ }
51
+ // Kanban API methods
52
+ async getKanbanBoard() {
53
+ return this.request('/kanban/board');
54
+ }
55
+ async getKanbanCard(cardId) {
56
+ return this.request(`/kanban/cards/${encodeURIComponent(cardId)}`);
57
+ }
58
+ async createKanbanCard(params) {
59
+ return this.request('/kanban/cards', {
60
+ method: 'POST',
61
+ body: JSON.stringify(params),
62
+ });
63
+ }
64
+ async updateKanbanCard(cardId, params) {
65
+ return this.request(`/kanban/cards/${encodeURIComponent(cardId)}`, {
66
+ method: 'PATCH',
67
+ body: JSON.stringify(params),
68
+ });
69
+ }
70
+ async getAIAssignedCards() {
71
+ return this.request('/kanban/assigned');
72
+ }
73
+ async moveKanbanCard(cardId, column) {
74
+ return this.request(`/kanban/cards/${encodeURIComponent(cardId)}/move`, {
75
+ method: 'POST',
76
+ body: JSON.stringify({ column }),
77
+ });
78
+ }
79
+ async updateAIAssignedCard(cardId, params) {
80
+ return this.request(`/kanban/cards/${encodeURIComponent(cardId)}/assigned`, {
81
+ method: 'PATCH',
82
+ body: JSON.stringify(params),
83
+ });
84
+ }
85
+ async addKanbanCardComment(cardId, content) {
86
+ const result = await this.request(`/kanban/cards/${encodeURIComponent(cardId)}/comments`, {
87
+ method: 'POST',
88
+ body: JSON.stringify({ content }),
89
+ });
90
+ return result.id;
91
+ }
92
+ // Todos API methods
93
+ async getTodoLists() {
94
+ return this.request('/todos/lists');
95
+ }
96
+ async getTodo(todoId) {
97
+ return this.request(`/todos/${encodeURIComponent(todoId)}`);
98
+ }
99
+ async createTodo(params) {
100
+ return this.request('/todos', {
101
+ method: 'POST',
102
+ body: JSON.stringify(params),
103
+ });
104
+ }
105
+ async updateTodo(todoId, params) {
106
+ return this.request(`/todos/${encodeURIComponent(todoId)}`, {
107
+ method: 'PATCH',
108
+ body: JSON.stringify(params),
109
+ });
110
+ }
111
+ }
112
+ exports.LunaArcApiClient = LunaArcApiClient;
113
+ // Create client instance from environment variables
114
+ function createApiClient() {
115
+ const apiUrl = process.env.LUNAARC_API_URL;
116
+ const token = process.env.LUNAARC_TOKEN;
117
+ if (!apiUrl) {
118
+ throw new Error('LUNAARC_API_URL environment variable is required');
119
+ }
120
+ if (!token) {
121
+ throw new Error('LUNAARC_TOKEN environment variable is required');
122
+ }
123
+ return new LunaArcApiClient(apiUrl, token);
124
+ }
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/server.js ADDED
@@ -0,0 +1,84 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ const index_js_1 = require("@modelcontextprotocol/sdk/server/index.js");
5
+ const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
6
+ const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
7
+ const client_js_1 = require("./api/client.js");
8
+ const wiki_js_1 = require("./tools/wiki.js");
9
+ const kanban_js_1 = require("./tools/kanban.js");
10
+ const todos_js_1 = require("./tools/todos.js");
11
+ // All available tools
12
+ const allTools = [...wiki_js_1.wikiTools, ...kanban_js_1.kanbanTools, ...todos_js_1.todosTools];
13
+ // Create API client
14
+ let apiClient;
15
+ try {
16
+ apiClient = (0, client_js_1.createApiClient)();
17
+ }
18
+ catch (error) {
19
+ console.error('Failed to initialize LunaArc MCP Server:');
20
+ console.error(error instanceof Error ? error.message : error);
21
+ console.error('\nPlease ensure the following environment variables are set:');
22
+ console.error(' LUNAARC_API_URL - The LunaArc API URL (e.g., https://api.lunaarc.de/mcp/v1)');
23
+ console.error(' LUNAARC_TOKEN - Your project token (starts with lac_prj_)');
24
+ process.exit(1);
25
+ }
26
+ // Create MCP server
27
+ const server = new index_js_1.Server({
28
+ name: 'lunaarc-mcp',
29
+ version: '1.0.0',
30
+ }, {
31
+ capabilities: {
32
+ tools: {},
33
+ },
34
+ });
35
+ // Handle list tools request
36
+ server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => {
37
+ return {
38
+ tools: allTools,
39
+ };
40
+ });
41
+ // Handle tool calls
42
+ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
43
+ const { name, arguments: args } = request.params;
44
+ try {
45
+ // Route to appropriate handler
46
+ if (name.startsWith('wiki_')) {
47
+ return await (0, wiki_js_1.handleWikiTool)(apiClient, name, args || {});
48
+ }
49
+ else if (name.startsWith('kanban_')) {
50
+ return await (0, kanban_js_1.handleKanbanTool)(apiClient, name, args || {});
51
+ }
52
+ else if (name.startsWith('todos_')) {
53
+ return await (0, todos_js_1.handleTodosTool)(apiClient, name, args || {});
54
+ }
55
+ else {
56
+ throw new Error(`Unknown tool: ${name}`);
57
+ }
58
+ }
59
+ catch (error) {
60
+ const message = error instanceof Error ? error.message : 'An unexpected error occurred';
61
+ return {
62
+ content: [
63
+ {
64
+ type: 'text',
65
+ text: `❌ Error: ${message}`,
66
+ },
67
+ ],
68
+ isError: true,
69
+ };
70
+ }
71
+ });
72
+ // Start server with stdio transport
73
+ async function main() {
74
+ const transport = new stdio_js_1.StdioServerTransport();
75
+ await server.connect(transport);
76
+ // Log to stderr (stdout is used for MCP communication)
77
+ console.error('LunaArc MCP Server started');
78
+ console.error(`API URL: ${process.env.LUNAARC_API_URL}`);
79
+ console.error(`Available tools: ${allTools.map((t) => t.name).join(', ')}`);
80
+ }
81
+ main().catch((error) => {
82
+ console.error('Fatal error:', error);
83
+ process.exit(1);
84
+ });
@@ -0,0 +1,154 @@
1
+ import { LunaArcApiClient } from '../api/client.js';
2
+ export declare const kanbanTools: ({
3
+ name: string;
4
+ description: string;
5
+ inputSchema: {
6
+ type: "object";
7
+ properties: {
8
+ card_id?: undefined;
9
+ title?: undefined;
10
+ description?: undefined;
11
+ priority?: undefined;
12
+ labels?: undefined;
13
+ column?: undefined;
14
+ content?: undefined;
15
+ };
16
+ required: never[];
17
+ };
18
+ } | {
19
+ name: string;
20
+ description: string;
21
+ inputSchema: {
22
+ type: "object";
23
+ properties: {
24
+ card_id: {
25
+ type: string;
26
+ description: string;
27
+ };
28
+ title?: undefined;
29
+ description?: undefined;
30
+ priority?: undefined;
31
+ labels?: undefined;
32
+ column?: undefined;
33
+ content?: undefined;
34
+ };
35
+ required: string[];
36
+ };
37
+ } | {
38
+ name: string;
39
+ description: string;
40
+ inputSchema: {
41
+ type: "object";
42
+ properties: {
43
+ title: {
44
+ type: string;
45
+ description: string;
46
+ };
47
+ description: {
48
+ type: string;
49
+ description: string;
50
+ };
51
+ priority: {
52
+ type: string;
53
+ enum: string[];
54
+ description: string;
55
+ };
56
+ labels: {
57
+ type: string;
58
+ items: {
59
+ type: string;
60
+ };
61
+ description: string;
62
+ };
63
+ card_id?: undefined;
64
+ column?: undefined;
65
+ content?: undefined;
66
+ };
67
+ required: string[];
68
+ };
69
+ } | {
70
+ name: string;
71
+ description: string;
72
+ inputSchema: {
73
+ type: "object";
74
+ properties: {
75
+ card_id: {
76
+ type: string;
77
+ description: string;
78
+ };
79
+ title: {
80
+ type: string;
81
+ description: string;
82
+ };
83
+ description: {
84
+ type: string;
85
+ description: string;
86
+ };
87
+ priority: {
88
+ type: string;
89
+ enum: string[];
90
+ description: string;
91
+ };
92
+ labels: {
93
+ type: string;
94
+ items: {
95
+ type: string;
96
+ };
97
+ description: string;
98
+ };
99
+ column?: undefined;
100
+ content?: undefined;
101
+ };
102
+ required: string[];
103
+ };
104
+ } | {
105
+ name: string;
106
+ description: string;
107
+ inputSchema: {
108
+ type: "object";
109
+ properties: {
110
+ card_id: {
111
+ type: string;
112
+ description: string;
113
+ };
114
+ column: {
115
+ type: string;
116
+ description: string;
117
+ };
118
+ title?: undefined;
119
+ description?: undefined;
120
+ priority?: undefined;
121
+ labels?: undefined;
122
+ content?: undefined;
123
+ };
124
+ required: string[];
125
+ };
126
+ } | {
127
+ name: string;
128
+ description: string;
129
+ inputSchema: {
130
+ type: "object";
131
+ properties: {
132
+ card_id: {
133
+ type: string;
134
+ description: string;
135
+ };
136
+ content: {
137
+ type: string;
138
+ description: string;
139
+ };
140
+ title?: undefined;
141
+ description?: undefined;
142
+ priority?: undefined;
143
+ labels?: undefined;
144
+ column?: undefined;
145
+ };
146
+ required: string[];
147
+ };
148
+ })[];
149
+ export declare function handleKanbanTool(client: LunaArcApiClient, toolName: string, args: Record<string, unknown>): Promise<{
150
+ content: {
151
+ type: 'text';
152
+ text: string;
153
+ }[];
154
+ }>;