@pollychrome/joan-mcp 1.0.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.
Files changed (83) hide show
  1. package/README.md +385 -0
  2. package/bin/joan-mcp +16 -0
  3. package/dist/auth.d.ts +49 -0
  4. package/dist/auth.d.ts.map +1 -0
  5. package/dist/auth.js +264 -0
  6. package/dist/auth.js.map +1 -0
  7. package/dist/cli.d.ts +7 -0
  8. package/dist/cli.d.ts.map +1 -0
  9. package/dist/cli.js +326 -0
  10. package/dist/cli.js.map +1 -0
  11. package/dist/client/api-client.d.ts +86 -0
  12. package/dist/client/api-client.d.ts.map +1 -0
  13. package/dist/client/api-client.js +182 -0
  14. package/dist/client/api-client.js.map +1 -0
  15. package/dist/client/types.d.ts +270 -0
  16. package/dist/client/types.d.ts.map +1 -0
  17. package/dist/client/types.js +5 -0
  18. package/dist/client/types.js.map +1 -0
  19. package/dist/config.d.ts +33 -0
  20. package/dist/config.d.ts.map +1 -0
  21. package/dist/config.js +71 -0
  22. package/dist/config.js.map +1 -0
  23. package/dist/index.d.ts +14 -0
  24. package/dist/index.d.ts.map +1 -0
  25. package/dist/index.js +118 -0
  26. package/dist/index.js.map +1 -0
  27. package/dist/resources/goals.d.ts +7 -0
  28. package/dist/resources/goals.d.ts.map +1 -0
  29. package/dist/resources/goals.js +49 -0
  30. package/dist/resources/goals.js.map +1 -0
  31. package/dist/resources/index.d.ts +16 -0
  32. package/dist/resources/index.d.ts.map +1 -0
  33. package/dist/resources/index.js +20 -0
  34. package/dist/resources/index.js.map +1 -0
  35. package/dist/resources/milestones.d.ts +7 -0
  36. package/dist/resources/milestones.d.ts.map +1 -0
  37. package/dist/resources/milestones.js +40 -0
  38. package/dist/resources/milestones.js.map +1 -0
  39. package/dist/resources/notes.d.ts +7 -0
  40. package/dist/resources/notes.d.ts.map +1 -0
  41. package/dist/resources/notes.js +33 -0
  42. package/dist/resources/notes.js.map +1 -0
  43. package/dist/resources/projects.d.ts +7 -0
  44. package/dist/resources/projects.d.ts.map +1 -0
  45. package/dist/resources/projects.js +97 -0
  46. package/dist/resources/projects.js.map +1 -0
  47. package/dist/resources/tasks.d.ts +7 -0
  48. package/dist/resources/tasks.d.ts.map +1 -0
  49. package/dist/resources/tasks.js +36 -0
  50. package/dist/resources/tasks.js.map +1 -0
  51. package/dist/tools/goals.d.ts +7 -0
  52. package/dist/tools/goals.d.ts.map +1 -0
  53. package/dist/tools/goals.js +114 -0
  54. package/dist/tools/goals.js.map +1 -0
  55. package/dist/tools/index.d.ts +16 -0
  56. package/dist/tools/index.d.ts.map +1 -0
  57. package/dist/tools/index.js +20 -0
  58. package/dist/tools/index.js.map +1 -0
  59. package/dist/tools/milestones.d.ts +7 -0
  60. package/dist/tools/milestones.d.ts.map +1 -0
  61. package/dist/tools/milestones.js +119 -0
  62. package/dist/tools/milestones.js.map +1 -0
  63. package/dist/tools/notes.d.ts +7 -0
  64. package/dist/tools/notes.d.ts.map +1 -0
  65. package/dist/tools/notes.js +82 -0
  66. package/dist/tools/notes.js.map +1 -0
  67. package/dist/tools/projects.d.ts +7 -0
  68. package/dist/tools/projects.d.ts.map +1 -0
  69. package/dist/tools/projects.js +63 -0
  70. package/dist/tools/projects.js.map +1 -0
  71. package/dist/tools/tasks.d.ts +7 -0
  72. package/dist/tools/tasks.d.ts.map +1 -0
  73. package/dist/tools/tasks.js +125 -0
  74. package/dist/tools/tasks.js.map +1 -0
  75. package/dist/utils/converters.d.ts +78 -0
  76. package/dist/utils/converters.d.ts.map +1 -0
  77. package/dist/utils/converters.js +79 -0
  78. package/dist/utils/converters.js.map +1 -0
  79. package/dist/utils/errors.d.ts +27 -0
  80. package/dist/utils/errors.d.ts.map +1 -0
  81. package/dist/utils/errors.js +104 -0
  82. package/dist/utils/errors.js.map +1 -0
  83. package/package.json +53 -0
package/dist/config.js ADDED
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Configuration management for Joan MCP server
3
+ */
4
+ import { z } from 'zod';
5
+ import { getAuthToken } from './auth.js';
6
+ import { ConfigurationError } from './utils/errors.js';
7
+ const ConfigSchema = z.object({
8
+ apiUrl: z.string().url(),
9
+ authToken: z.string().min(1),
10
+ });
11
+ const DEFAULT_API_URL = 'https://joan-api.alexbbenson.workers.dev/api/v1';
12
+ /**
13
+ * Load configuration from environment and stored credentials
14
+ */
15
+ export async function loadConfig() {
16
+ const apiUrl = process.env.JOAN_API_URL || DEFAULT_API_URL;
17
+ let authToken;
18
+ try {
19
+ authToken = await getAuthToken();
20
+ }
21
+ catch (error) {
22
+ throw new ConfigurationError('No authentication token found. Run "joan-mcp login" to authenticate or set JOAN_AUTH_TOKEN environment variable.');
23
+ }
24
+ const config = {
25
+ apiUrl,
26
+ authToken,
27
+ };
28
+ try {
29
+ return ConfigSchema.parse(config);
30
+ }
31
+ catch (error) {
32
+ if (error instanceof z.ZodError) {
33
+ const issues = error.issues.map(i => `${i.path.join('.')}: ${i.message}`).join(', ');
34
+ throw new ConfigurationError(`Invalid configuration: ${issues}`);
35
+ }
36
+ throw error;
37
+ }
38
+ }
39
+ /**
40
+ * Get the API URL (for display purposes, without needing full config)
41
+ */
42
+ export function getApiUrl() {
43
+ return process.env.JOAN_API_URL || DEFAULT_API_URL;
44
+ }
45
+ /**
46
+ * Get the base app URL (for login redirects)
47
+ */
48
+ export function getAppUrl() {
49
+ const apiUrl = getApiUrl();
50
+ // Convert API URL to app URL
51
+ if (apiUrl.includes('joan-api.alexbbenson.workers.dev')) {
52
+ return 'https://joan.nintai.app';
53
+ }
54
+ if (apiUrl.includes('joan-api-staging')) {
55
+ return 'https://staging.joan.nintai.app';
56
+ }
57
+ // Local development
58
+ if (apiUrl.includes('localhost:8787')) {
59
+ return 'http://localhost:5174';
60
+ }
61
+ // Default to production
62
+ return 'https://joan.nintai.app';
63
+ }
64
+ /**
65
+ * Get the MCP auth URL (for CLI login flow)
66
+ */
67
+ export function getMcpAuthUrl(port) {
68
+ const appUrl = getAppUrl();
69
+ return `${appUrl}/mcp-auth?port=${port}`;
70
+ }
71
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAEvD,MAAM,YAAY,GAAG,CAAC,CAAC,MAAM,CAAC;IAC5B,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;IACxB,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;CAC7B,CAAC,CAAC;AAIH,MAAM,eAAe,GAAG,iDAAiD,CAAC;AAE1E;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU;IAC9B,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,eAAe,CAAC;IAE3D,IAAI,SAAiB,CAAC;IACtB,IAAI,CAAC;QACH,SAAS,GAAG,MAAM,YAAY,EAAE,CAAC;IACnC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,kBAAkB,CAC1B,kHAAkH,CACnH,CAAC;IACJ,CAAC;IAED,MAAM,MAAM,GAAG;QACb,MAAM;QACN,SAAS;KACV,CAAC;IAEF,IAAI,CAAC;QACH,OAAO,YAAY,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IACpC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,CAAC,CAAC,QAAQ,EAAE,CAAC;YAChC,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACrF,MAAM,IAAI,kBAAkB,CAAC,0BAA0B,MAAM,EAAE,CAAC,CAAC;QACnE,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,SAAS;IACvB,OAAO,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,eAAe,CAAC;AACrD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,SAAS;IACvB,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,6BAA6B;IAC7B,IAAI,MAAM,CAAC,QAAQ,CAAC,kCAAkC,CAAC,EAAE,CAAC;QACxD,OAAO,yBAAyB,CAAC;IACnC,CAAC;IACD,IAAI,MAAM,CAAC,QAAQ,CAAC,kBAAkB,CAAC,EAAE,CAAC;QACxC,OAAO,iCAAiC,CAAC;IAC3C,CAAC;IACD,oBAAoB;IACpB,IAAI,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,CAAC;QACtC,OAAO,uBAAuB,CAAC;IACjC,CAAC;IACD,wBAAwB;IACxB,OAAO,yBAAyB,CAAC;AACnC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,OAAO,GAAG,MAAM,kBAAkB,IAAI,EAAE,CAAC;AAC3C,CAAC"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Joan MCP Server - Entry Point
3
+ *
4
+ * This MCP server enables AI assistants like Claude to interact with
5
+ * Joan productivity app features including Projects, Tasks, Goals,
6
+ * Milestones, and Notes.
7
+ */
8
+ /**
9
+ * Start the MCP server
10
+ */
11
+ export declare function startServer(): Promise<void>;
12
+ export { loadConfig } from './config.js';
13
+ export { JoanApiClient } from './client/api-client.js';
14
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AA4EH;;GAEG;AACH,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CA0CjD;AAGD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,118 @@
1
+ /**
2
+ * Joan MCP Server - Entry Point
3
+ *
4
+ * This MCP server enables AI assistants like Claude to interact with
5
+ * Joan productivity app features including Projects, Tasks, Goals,
6
+ * Milestones, and Notes.
7
+ */
8
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
9
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
10
+ import { loadConfig } from './config.js';
11
+ import { JoanApiClient } from './client/api-client.js';
12
+ import { registerAllTools } from './tools/index.js';
13
+ import { registerAllResources } from './resources/index.js';
14
+ const SERVER_NAME = 'joan-mcp';
15
+ const SERVER_VERSION = '1.0.0';
16
+ /**
17
+ * Server instructions that describe Joan MCP to AI assistants.
18
+ * These are automatically sent to clients during initialization.
19
+ */
20
+ const SERVER_INSTRUCTIONS = `
21
+ Joan is a productivity application for managing projects, tasks, goals, milestones, and notes. This MCP server enables you to interact with the user's Joan data.
22
+
23
+ ## Available Tools (Write Operations)
24
+
25
+ ### Tasks
26
+ - create_task: Create a new task in a project (requires project_id, title; optional: description, status, priority, due_date, column_id)
27
+ - update_task: Update task properties (title, description, status, priority, due_date, column_id)
28
+ - complete_task: Mark a task as completed
29
+ - delete_task: Delete a task
30
+
31
+ ### Projects
32
+ - create_project: Create a new project (name required; optional: description, status, start_date, end_date)
33
+ - update_project: Update project properties
34
+
35
+ ### Milestones
36
+ - create_milestone: Create a milestone in a project (requires project_id, title; optional: description, target_date)
37
+ - update_milestone: Update milestone details
38
+ - delete_milestone: Delete a milestone
39
+ - link_tasks_to_milestone: Associate tasks with a milestone
40
+ - unlink_task_from_milestone: Remove a task from a milestone
41
+
42
+ ### Goals
43
+ - create_goal: Create a new goal (title required; optional: description, target_date, status)
44
+ - update_goal: Update goal progress or details
45
+ - delete_goal: Delete a goal
46
+ - link_task_to_goal: Link a task to track goal progress
47
+ - unlink_task_from_goal: Remove task from goal tracking
48
+
49
+ ### Notes
50
+ - create_note: Create a new note (title required; optional: content, tags)
51
+ - update_note: Update note content or metadata
52
+ - delete_note: Delete a note
53
+
54
+ ## Available Resources (Read Operations)
55
+
56
+ Use these URIs to read Joan data:
57
+ - joan://projects - List all projects
58
+ - joan://projects/{id} - Get project details with stats
59
+ - joan://projects/{id}/tasks - Get tasks in a project
60
+ - joan://projects/{id}/milestones - Get project milestones
61
+ - joan://projects/{id}/columns - Get kanban columns
62
+ - joan://tasks - List all tasks
63
+ - joan://tasks/{id} - Get task details
64
+ - joan://goals - List all goals
65
+ - joan://goals/{id} - Get goal with linked tasks
66
+ - joan://notes - List all notes
67
+ - joan://notes/{id} - Get note details
68
+
69
+ ## Usage Guidelines
70
+
71
+ 1. When the user mentions tasks, projects, goals, or productivity tracking, consider using Joan tools
72
+ 2. Always read relevant resources first to get context (e.g., list projects before creating a task)
73
+ 3. Task status values: "todo", "in_progress", "done", "blocked"
74
+ 4. Task priority values: "low", "medium", "high", "urgent"
75
+ 5. Project status values: "planning", "active", "on_hold", "completed", "archived"
76
+ 6. Goal status values: "not_started", "in_progress", "completed", "abandoned"
77
+ `.trim();
78
+ /**
79
+ * Start the MCP server
80
+ */
81
+ export async function startServer() {
82
+ // Load configuration
83
+ const config = await loadConfig();
84
+ // Initialize API client
85
+ const apiClient = new JoanApiClient({
86
+ baseUrl: config.apiUrl,
87
+ authToken: config.authToken,
88
+ });
89
+ // Verify auth token works
90
+ try {
91
+ await apiClient.getCurrentUser();
92
+ }
93
+ catch (error) {
94
+ console.error('Failed to verify authentication. Please check your token.');
95
+ console.error('Run "joan-mcp login" to authenticate or set JOAN_AUTH_TOKEN.');
96
+ process.exit(1);
97
+ }
98
+ // Create MCP server with instructions for AI assistants
99
+ const server = new McpServer({
100
+ name: SERVER_NAME,
101
+ version: SERVER_VERSION,
102
+ }, {
103
+ instructions: SERVER_INSTRUCTIONS,
104
+ });
105
+ // Register all tools (write operations)
106
+ registerAllTools(server, apiClient);
107
+ // Register all resources (read operations)
108
+ registerAllResources(server, apiClient);
109
+ // Connect via stdio transport
110
+ const transport = new StdioServerTransport();
111
+ await server.connect(transport);
112
+ // Log to stderr so it doesn't interfere with MCP protocol
113
+ console.error(`${SERVER_NAME} v${SERVER_VERSION} started`);
114
+ }
115
+ // Export for CLI
116
+ export { loadConfig } from './config.js';
117
+ export { JoanApiClient } from './client/api-client.js';
118
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAE5D,MAAM,WAAW,GAAG,UAAU,CAAC;AAC/B,MAAM,cAAc,GAAG,OAAO,CAAC;AAE/B;;;GAGG;AACH,MAAM,mBAAmB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyD3B,CAAC,IAAI,EAAE,CAAC;AAGT;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,qBAAqB;IACrB,MAAM,MAAM,GAAG,MAAM,UAAU,EAAE,CAAC;IAElC,wBAAwB;IACxB,MAAM,SAAS,GAAG,IAAI,aAAa,CAAC;QAClC,OAAO,EAAE,MAAM,CAAC,MAAM;QACtB,SAAS,EAAE,MAAM,CAAC,SAAS;KAC5B,CAAC,CAAC;IAEH,0BAA0B;IAC1B,IAAI,CAAC;QACH,MAAM,SAAS,CAAC,cAAc,EAAE,CAAC;IACnC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,2DAA2D,CAAC,CAAC;QAC3E,OAAO,CAAC,KAAK,CAAC,8DAA8D,CAAC,CAAC;QAC9E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,wDAAwD;IACxD,MAAM,MAAM,GAAG,IAAI,SAAS,CAC1B;QACE,IAAI,EAAE,WAAW;QACjB,OAAO,EAAE,cAAc;KACxB,EACD;QACE,YAAY,EAAE,mBAAmB;KAClC,CACF,CAAC;IAEF,wCAAwC;IACxC,gBAAgB,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAEpC,2CAA2C;IAC3C,oBAAoB,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAExC,8BAA8B;IAC9B,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAEhC,0DAA0D;IAC1D,OAAO,CAAC,KAAK,CAAC,GAAG,WAAW,KAAK,cAAc,UAAU,CAAC,CAAC;AAC7D,CAAC;AAED,iBAAiB;AACjB,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * MCP resources for goal data
3
+ */
4
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
5
+ import type { JoanApiClient } from '../client/api-client.js';
6
+ export declare function registerGoalResources(server: McpServer, client: JoanApiClient): void;
7
+ //# sourceMappingURL=goals.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"goals.d.ts","sourceRoot":"","sources":["../../src/resources/goals.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAE7D,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,GAAG,IAAI,CAiEpF"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * MCP resources for goal data
3
+ */
4
+ export function registerGoalResources(server, client) {
5
+ // List all goals
6
+ server.resource('joan://goals', 'List all goals', async () => {
7
+ const goals = await client.listGoals({ include_tasks: true });
8
+ return {
9
+ contents: [{
10
+ uri: 'joan://goals',
11
+ mimeType: 'application/json',
12
+ text: JSON.stringify(goals, null, 2),
13
+ }],
14
+ };
15
+ });
16
+ // Goal details resource template
17
+ server.resource('joan://goals/{goalId}', 'Get detailed information about a specific goal including linked tasks', async (uri) => {
18
+ const match = uri.pathname.match(/^\/\/goals\/([^/]+)$/);
19
+ const goalId = match?.[1];
20
+ if (!goalId) {
21
+ throw new Error('Invalid goal URI');
22
+ }
23
+ const goal = await client.getGoal(goalId);
24
+ return {
25
+ contents: [{
26
+ uri: uri.toString(),
27
+ mimeType: 'application/json',
28
+ text: JSON.stringify(goal, null, 2),
29
+ }],
30
+ };
31
+ });
32
+ // Goal stats resource template
33
+ server.resource('joan://goals/{goalId}/stats', 'Get statistics for a specific goal', async (uri) => {
34
+ const match = uri.pathname.match(/^\/\/goals\/([^/]+)\/stats$/);
35
+ const goalId = match?.[1];
36
+ if (!goalId) {
37
+ throw new Error('Invalid goal stats URI');
38
+ }
39
+ const stats = await client.getGoalStats(goalId);
40
+ return {
41
+ contents: [{
42
+ uri: uri.toString(),
43
+ mimeType: 'application/json',
44
+ text: JSON.stringify(stats, null, 2),
45
+ }],
46
+ };
47
+ });
48
+ }
49
+ //# sourceMappingURL=goals.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"goals.js","sourceRoot":"","sources":["../../src/resources/goals.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,MAAM,UAAU,qBAAqB,CAAC,MAAiB,EAAE,MAAqB;IAC5E,iBAAiB;IACjB,MAAM,CAAC,QAAQ,CACb,cAAc,EACd,gBAAgB,EAChB,KAAK,IAAI,EAAE;QACT,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;QAE9D,OAAO;YACL,QAAQ,EAAE,CAAC;oBACT,GAAG,EAAE,cAAc;oBACnB,QAAQ,EAAE,kBAAkB;oBAC5B,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;iBACrC,CAAC;SACH,CAAC;IACJ,CAAC,CACF,CAAC;IAEF,iCAAiC;IACjC,MAAM,CAAC,QAAQ,CACb,uBAAuB,EACvB,uEAAuE,EACvE,KAAK,EAAE,GAAG,EAAE,EAAE;QACZ,MAAM,KAAK,GAAG,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,sBAAsB,CAAC,CAAC;QACzD,MAAM,MAAM,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;QAE1B,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CAAC,kBAAkB,CAAC,CAAC;QACtC,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAE1C,OAAO;YACL,QAAQ,EAAE,CAAC;oBACT,GAAG,EAAE,GAAG,CAAC,QAAQ,EAAE;oBACnB,QAAQ,EAAE,kBAAkB;oBAC5B,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;iBACpC,CAAC;SACH,CAAC;IACJ,CAAC,CACF,CAAC;IAEF,+BAA+B;IAC/B,MAAM,CAAC,QAAQ,CACb,6BAA6B,EAC7B,oCAAoC,EACpC,KAAK,EAAE,GAAG,EAAE,EAAE;QACZ,MAAM,KAAK,GAAG,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,6BAA6B,CAAC,CAAC;QAChE,MAAM,MAAM,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;QAE1B,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;QAC5C,CAAC;QAED,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;QAEhD,OAAO;YACL,QAAQ,EAAE,CAAC;oBACT,GAAG,EAAE,GAAG,CAAC,QAAQ,EAAE;oBACnB,QAAQ,EAAE,kBAAkB;oBAC5B,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;iBACrC,CAAC;SACH,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Resource registration for Joan MCP server
3
+ */
4
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
5
+ import type { JoanApiClient } from '../client/api-client.js';
6
+ import { registerProjectResources } from './projects.js';
7
+ import { registerTaskResources } from './tasks.js';
8
+ import { registerMilestoneResources } from './milestones.js';
9
+ import { registerGoalResources } from './goals.js';
10
+ import { registerNoteResources } from './notes.js';
11
+ /**
12
+ * Register all resources with the MCP server
13
+ */
14
+ export declare function registerAllResources(server: McpServer, client: JoanApiClient): void;
15
+ export { registerProjectResources, registerTaskResources, registerMilestoneResources, registerGoalResources, registerNoteResources, };
16
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/resources/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,wBAAwB,EAAE,MAAM,eAAe,CAAC;AACzD,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,EAAE,0BAA0B,EAAE,MAAM,iBAAiB,CAAC;AAC7D,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAEnD;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,GAAG,IAAI,CAMnF;AAED,OAAO,EACL,wBAAwB,EACxB,qBAAqB,EACrB,0BAA0B,EAC1B,qBAAqB,EACrB,qBAAqB,GACtB,CAAC"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Resource registration for Joan MCP server
3
+ */
4
+ import { registerProjectResources } from './projects.js';
5
+ import { registerTaskResources } from './tasks.js';
6
+ import { registerMilestoneResources } from './milestones.js';
7
+ import { registerGoalResources } from './goals.js';
8
+ import { registerNoteResources } from './notes.js';
9
+ /**
10
+ * Register all resources with the MCP server
11
+ */
12
+ export function registerAllResources(server, client) {
13
+ registerProjectResources(server, client);
14
+ registerTaskResources(server, client);
15
+ registerMilestoneResources(server, client);
16
+ registerGoalResources(server, client);
17
+ registerNoteResources(server, client);
18
+ }
19
+ export { registerProjectResources, registerTaskResources, registerMilestoneResources, registerGoalResources, registerNoteResources, };
20
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/resources/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,EAAE,wBAAwB,EAAE,MAAM,eAAe,CAAC;AACzD,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,EAAE,0BAA0B,EAAE,MAAM,iBAAiB,CAAC;AAC7D,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAEnD;;GAEG;AACH,MAAM,UAAU,oBAAoB,CAAC,MAAiB,EAAE,MAAqB;IAC3E,wBAAwB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACzC,qBAAqB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,0BAA0B,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC3C,qBAAqB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,qBAAqB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AACxC,CAAC;AAED,OAAO,EACL,wBAAwB,EACxB,qBAAqB,EACrB,0BAA0B,EAC1B,qBAAqB,EACrB,qBAAqB,GACtB,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * MCP resources for milestone data
3
+ */
4
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
5
+ import type { JoanApiClient } from '../client/api-client.js';
6
+ export declare function registerMilestoneResources(server: McpServer, client: JoanApiClient): void;
7
+ //# sourceMappingURL=milestones.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"milestones.d.ts","sourceRoot":"","sources":["../../src/resources/milestones.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAE7D,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,GAAG,IAAI,CAkDzF"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * MCP resources for milestone data
3
+ */
4
+ export function registerMilestoneResources(server, client) {
5
+ // Milestone details resource template (requires project context)
6
+ server.resource('joan://projects/{projectId}/milestones/{milestoneId}', 'Get detailed information about a specific milestone including linked tasks', async (uri) => {
7
+ const match = uri.pathname.match(/^\/\/projects\/([^/]+)\/milestones\/([^/]+)$/);
8
+ const projectId = match?.[1];
9
+ const milestoneId = match?.[2];
10
+ if (!projectId || !milestoneId) {
11
+ throw new Error('Invalid milestone URI');
12
+ }
13
+ const milestone = await client.getMilestone(projectId, milestoneId);
14
+ return {
15
+ contents: [{
16
+ uri: uri.toString(),
17
+ mimeType: 'application/json',
18
+ text: JSON.stringify(milestone, null, 2),
19
+ }],
20
+ };
21
+ });
22
+ // Milestone resources
23
+ server.resource('joan://projects/{projectId}/milestones/{milestoneId}/resources', 'Get resources (links and notes) attached to a milestone', async (uri) => {
24
+ const match = uri.pathname.match(/^\/\/projects\/([^/]+)\/milestones\/([^/]+)\/resources$/);
25
+ const projectId = match?.[1];
26
+ const milestoneId = match?.[2];
27
+ if (!projectId || !milestoneId) {
28
+ throw new Error('Invalid milestone resources URI');
29
+ }
30
+ const resources = await client.getMilestoneResources(projectId, milestoneId);
31
+ return {
32
+ contents: [{
33
+ uri: uri.toString(),
34
+ mimeType: 'application/json',
35
+ text: JSON.stringify(resources, null, 2),
36
+ }],
37
+ };
38
+ });
39
+ }
40
+ //# sourceMappingURL=milestones.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"milestones.js","sourceRoot":"","sources":["../../src/resources/milestones.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,MAAM,UAAU,0BAA0B,CAAC,MAAiB,EAAE,MAAqB;IACjF,iEAAiE;IACjE,MAAM,CAAC,QAAQ,CACb,sDAAsD,EACtD,4EAA4E,EAC5E,KAAK,EAAE,GAAG,EAAE,EAAE;QACZ,MAAM,KAAK,GAAG,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,8CAA8C,CAAC,CAAC;QACjF,MAAM,SAAS,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;QAC7B,MAAM,WAAW,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;QAE/B,IAAI,CAAC,SAAS,IAAI,CAAC,WAAW,EAAE,CAAC;YAC/B,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;QAC3C,CAAC;QAED,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;QAEpE,OAAO;YACL,QAAQ,EAAE,CAAC;oBACT,GAAG,EAAE,GAAG,CAAC,QAAQ,EAAE;oBACnB,QAAQ,EAAE,kBAAkB;oBAC5B,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;iBACzC,CAAC;SACH,CAAC;IACJ,CAAC,CACF,CAAC;IAEF,sBAAsB;IACtB,MAAM,CAAC,QAAQ,CACb,gEAAgE,EAChE,yDAAyD,EACzD,KAAK,EAAE,GAAG,EAAE,EAAE;QACZ,MAAM,KAAK,GAAG,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,yDAAyD,CAAC,CAAC;QAC5F,MAAM,SAAS,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;QAC7B,MAAM,WAAW,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;QAE/B,IAAI,CAAC,SAAS,IAAI,CAAC,WAAW,EAAE,CAAC;YAC/B,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;QACrD,CAAC;QAED,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,qBAAqB,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;QAE7E,OAAO;YACL,QAAQ,EAAE,CAAC;oBACT,GAAG,EAAE,GAAG,CAAC,QAAQ,EAAE;oBACnB,QAAQ,EAAE,kBAAkB;oBAC5B,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;iBACzC,CAAC;SACH,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * MCP resources for note data
3
+ */
4
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
5
+ import type { JoanApiClient } from '../client/api-client.js';
6
+ export declare function registerNoteResources(server: McpServer, client: JoanApiClient): void;
7
+ //# sourceMappingURL=notes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notes.d.ts","sourceRoot":"","sources":["../../src/resources/notes.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAE7D,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,GAAG,IAAI,CAyCpF"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * MCP resources for note data
3
+ */
4
+ export function registerNoteResources(server, client) {
5
+ // List all notes
6
+ server.resource('joan://notes', 'List all notes', async () => {
7
+ const notes = await client.listNotes();
8
+ return {
9
+ contents: [{
10
+ uri: 'joan://notes',
11
+ mimeType: 'application/json',
12
+ text: JSON.stringify(notes, null, 2),
13
+ }],
14
+ };
15
+ });
16
+ // Note details resource template
17
+ server.resource('joan://notes/{noteId}', 'Get detailed information about a specific note', async (uri) => {
18
+ const match = uri.pathname.match(/^\/\/notes\/([^/]+)$/);
19
+ const noteId = match?.[1];
20
+ if (!noteId) {
21
+ throw new Error('Invalid note URI');
22
+ }
23
+ const note = await client.getNote(noteId);
24
+ return {
25
+ contents: [{
26
+ uri: uri.toString(),
27
+ mimeType: 'application/json',
28
+ text: JSON.stringify(note, null, 2),
29
+ }],
30
+ };
31
+ });
32
+ }
33
+ //# sourceMappingURL=notes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notes.js","sourceRoot":"","sources":["../../src/resources/notes.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,MAAM,UAAU,qBAAqB,CAAC,MAAiB,EAAE,MAAqB;IAC5E,iBAAiB;IACjB,MAAM,CAAC,QAAQ,CACb,cAAc,EACd,gBAAgB,EAChB,KAAK,IAAI,EAAE;QACT,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,SAAS,EAAE,CAAC;QAEvC,OAAO;YACL,QAAQ,EAAE,CAAC;oBACT,GAAG,EAAE,cAAc;oBACnB,QAAQ,EAAE,kBAAkB;oBAC5B,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;iBACrC,CAAC;SACH,CAAC;IACJ,CAAC,CACF,CAAC;IAEF,iCAAiC;IACjC,MAAM,CAAC,QAAQ,CACb,uBAAuB,EACvB,gDAAgD,EAChD,KAAK,EAAE,GAAG,EAAE,EAAE;QACZ,MAAM,KAAK,GAAG,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,sBAAsB,CAAC,CAAC;QACzD,MAAM,MAAM,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;QAE1B,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CAAC,kBAAkB,CAAC,CAAC;QACtC,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAE1C,OAAO;YACL,QAAQ,EAAE,CAAC;oBACT,GAAG,EAAE,GAAG,CAAC,QAAQ,EAAE;oBACnB,QAAQ,EAAE,kBAAkB;oBAC5B,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;iBACpC,CAAC;SACH,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * MCP resources for project data
3
+ */
4
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
5
+ import type { JoanApiClient } from '../client/api-client.js';
6
+ export declare function registerProjectResources(server: McpServer, client: JoanApiClient): void;
7
+ //# sourceMappingURL=projects.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projects.d.ts","sourceRoot":"","sources":["../../src/resources/projects.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAE7D,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,GAAG,IAAI,CAyIvF"}
@@ -0,0 +1,97 @@
1
+ /**
2
+ * MCP resources for project data
3
+ */
4
+ export function registerProjectResources(server, client) {
5
+ // List all projects
6
+ server.resource('joan://projects', 'List all projects', async () => {
7
+ const projects = await client.listProjects({ include_members: true });
8
+ return {
9
+ contents: [{
10
+ uri: 'joan://projects',
11
+ mimeType: 'application/json',
12
+ text: JSON.stringify(projects, null, 2),
13
+ }],
14
+ };
15
+ });
16
+ // Project details resource template
17
+ server.resource('joan://projects/{projectId}', 'Get detailed information about a specific project', async (uri) => {
18
+ const match = uri.pathname.match(/^\/\/projects\/([^/]+)$/);
19
+ const projectId = match?.[1];
20
+ if (!projectId) {
21
+ throw new Error('Invalid project URI');
22
+ }
23
+ const project = await client.getProject(projectId);
24
+ return {
25
+ contents: [{
26
+ uri: uri.toString(),
27
+ mimeType: 'application/json',
28
+ text: JSON.stringify(project, null, 2),
29
+ }],
30
+ };
31
+ });
32
+ // Project tasks resource template
33
+ server.resource('joan://projects/{projectId}/tasks', 'Get all tasks for a specific project', async (uri) => {
34
+ const match = uri.pathname.match(/^\/\/projects\/([^/]+)\/tasks$/);
35
+ const projectId = match?.[1];
36
+ if (!projectId) {
37
+ throw new Error('Invalid project tasks URI');
38
+ }
39
+ const tasks = await client.getProjectTasks(projectId);
40
+ return {
41
+ contents: [{
42
+ uri: uri.toString(),
43
+ mimeType: 'application/json',
44
+ text: JSON.stringify(tasks, null, 2),
45
+ }],
46
+ };
47
+ });
48
+ // Project milestones resource template
49
+ server.resource('joan://projects/{projectId}/milestones', 'Get all milestones for a specific project', async (uri) => {
50
+ const match = uri.pathname.match(/^\/\/projects\/([^/]+)\/milestones$/);
51
+ const projectId = match?.[1];
52
+ if (!projectId) {
53
+ throw new Error('Invalid project milestones URI');
54
+ }
55
+ const milestones = await client.listMilestones(projectId, { include_tasks: true });
56
+ return {
57
+ contents: [{
58
+ uri: uri.toString(),
59
+ mimeType: 'application/json',
60
+ text: JSON.stringify(milestones, null, 2),
61
+ }],
62
+ };
63
+ });
64
+ // Project columns resource template
65
+ server.resource('joan://projects/{projectId}/columns', 'Get kanban columns for a specific project', async (uri) => {
66
+ const match = uri.pathname.match(/^\/\/projects\/([^/]+)\/columns$/);
67
+ const projectId = match?.[1];
68
+ if (!projectId) {
69
+ throw new Error('Invalid project columns URI');
70
+ }
71
+ const columns = await client.getProjectColumns(projectId);
72
+ return {
73
+ contents: [{
74
+ uri: uri.toString(),
75
+ mimeType: 'application/json',
76
+ text: JSON.stringify(columns, null, 2),
77
+ }],
78
+ };
79
+ });
80
+ // Project analytics resource template
81
+ server.resource('joan://projects/{projectId}/analytics', 'Get analytics and statistics for a specific project', async (uri) => {
82
+ const match = uri.pathname.match(/^\/\/projects\/([^/]+)\/analytics$/);
83
+ const projectId = match?.[1];
84
+ if (!projectId) {
85
+ throw new Error('Invalid project analytics URI');
86
+ }
87
+ const analytics = await client.getProjectAnalytics(projectId);
88
+ return {
89
+ contents: [{
90
+ uri: uri.toString(),
91
+ mimeType: 'application/json',
92
+ text: JSON.stringify(analytics, null, 2),
93
+ }],
94
+ };
95
+ });
96
+ }
97
+ //# sourceMappingURL=projects.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projects.js","sourceRoot":"","sources":["../../src/resources/projects.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * MCP resources for task data
3
+ */
4
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
5
+ import type { JoanApiClient } from '../client/api-client.js';
6
+ export declare function registerTaskResources(server: McpServer, client: JoanApiClient): void;
7
+ //# sourceMappingURL=tasks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tasks.d.ts","sourceRoot":"","sources":["../../src/resources/tasks.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAG7D,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,GAAG,IAAI,CA2CpF"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * MCP resources for task data
3
+ */
4
+ import { formatTask } from '../utils/converters.js';
5
+ export function registerTaskResources(server, client) {
6
+ // List all tasks
7
+ server.resource('joan://tasks', 'List all tasks across all projects', async () => {
8
+ const tasks = await client.listTasks();
9
+ const formattedTasks = tasks.map(t => formatTask(t));
10
+ return {
11
+ contents: [{
12
+ uri: 'joan://tasks',
13
+ mimeType: 'application/json',
14
+ text: JSON.stringify(formattedTasks, null, 2),
15
+ }],
16
+ };
17
+ });
18
+ // Task details resource template
19
+ server.resource('joan://tasks/{taskId}', 'Get detailed information about a specific task', async (uri) => {
20
+ const match = uri.pathname.match(/^\/\/tasks\/([^/]+)$/);
21
+ const taskId = match?.[1];
22
+ if (!taskId) {
23
+ throw new Error('Invalid task URI');
24
+ }
25
+ const task = await client.getTaskWithSubtasks(taskId);
26
+ const formattedTask = formatTask(task);
27
+ return {
28
+ contents: [{
29
+ uri: uri.toString(),
30
+ mimeType: 'application/json',
31
+ text: JSON.stringify(formattedTask, null, 2),
32
+ }],
33
+ };
34
+ });
35
+ }
36
+ //# sourceMappingURL=tasks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tasks.js","sourceRoot":"","sources":["../../src/resources/tasks.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAEpD,MAAM,UAAU,qBAAqB,CAAC,MAAiB,EAAE,MAAqB;IAC5E,iBAAiB;IACjB,MAAM,CAAC,QAAQ,CACb,cAAc,EACd,oCAAoC,EACpC,KAAK,IAAI,EAAE;QACT,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,SAAS,EAAE,CAAC;QACvC,MAAM,cAAc,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;QAErD,OAAO;YACL,QAAQ,EAAE,CAAC;oBACT,GAAG,EAAE,cAAc;oBACnB,QAAQ,EAAE,kBAAkB;oBAC5B,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,cAAc,EAAE,IAAI,EAAE,CAAC,CAAC;iBAC9C,CAAC;SACH,CAAC;IACJ,CAAC,CACF,CAAC;IAEF,iCAAiC;IACjC,MAAM,CAAC,QAAQ,CACb,uBAAuB,EACvB,gDAAgD,EAChD,KAAK,EAAE,GAAG,EAAE,EAAE;QACZ,MAAM,KAAK,GAAG,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,sBAAsB,CAAC,CAAC;QACzD,MAAM,MAAM,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;QAE1B,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CAAC,kBAAkB,CAAC,CAAC;QACtC,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,mBAAmB,CAAC,MAAM,CAAC,CAAC;QACtD,MAAM,aAAa,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;QAEvC,OAAO;YACL,QAAQ,EAAE,CAAC;oBACT,GAAG,EAAE,GAAG,CAAC,QAAQ,EAAE;oBACnB,QAAQ,EAAE,kBAAkB;oBAC5B,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;iBAC7C,CAAC;SACH,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * MCP tools for goal management
3
+ */
4
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
5
+ import type { JoanApiClient } from '../client/api-client.js';
6
+ export declare function registerGoalTools(server: McpServer, client: JoanApiClient): void;
7
+ //# sourceMappingURL=goals.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"goals.d.ts","sourceRoot":"","sources":["../../src/tools/goals.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAG7D,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,GAAG,IAAI,CAwIhF"}