exponential-mcp 0.4.0 → 0.5.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/dist/cli.js +0 -0
- package/dist/index.js +73 -5
- package/package.json +2 -2
- package/dist/api.d.ts +0 -84
- package/dist/api.js +0 -82
package/dist/cli.js
CHANGED
|
File without changes
|
package/dist/index.js
CHANGED
|
@@ -260,13 +260,54 @@ const TOOLS = [
|
|
|
260
260
|
},
|
|
261
261
|
{
|
|
262
262
|
name: 'get_goals',
|
|
263
|
-
description:
|
|
263
|
+
description: "List objectives (goals). Each objective carries its linked projects, which is how work ladders up to an OKR: every action has a projectId. Objectives have INTEGER ids — key results, which are separate, have CUIDs (see get_key_results). Use tree: true for the annual → quarterly cascade.",
|
|
264
264
|
inputSchema: {
|
|
265
265
|
type: 'object',
|
|
266
266
|
properties: {
|
|
267
267
|
workspaceId: {
|
|
268
268
|
type: 'string',
|
|
269
|
-
description: 'Optional workspace ID'
|
|
269
|
+
description: 'Optional workspace ID. With it the list is workspace-wide (every member\'s objectives); without it you get your own.'
|
|
270
|
+
},
|
|
271
|
+
period: {
|
|
272
|
+
type: 'string',
|
|
273
|
+
description: 'Optional period filter, e.g. "Q3-2026" or "Annual-2026"'
|
|
274
|
+
},
|
|
275
|
+
status: {
|
|
276
|
+
type: 'string',
|
|
277
|
+
description: 'Optional status: planned, active, completed, archived, on-hold'
|
|
278
|
+
},
|
|
279
|
+
tree: {
|
|
280
|
+
type: 'boolean',
|
|
281
|
+
description: 'Return objectives nested parent → child (up to 5 levels), each with its projects and key results, instead of a flat list'
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
},
|
|
286
|
+
{
|
|
287
|
+
name: 'get_key_results',
|
|
288
|
+
description: "List key results — the measurable half of an OKR. By default groups them under their objectives (the richest read: one call for 'how is the quarter going'). Pass flat: true for a bare list. Key result ids are CUIDs; the goalId tying one to its objective is an integer.",
|
|
289
|
+
inputSchema: {
|
|
290
|
+
type: 'object',
|
|
291
|
+
properties: {
|
|
292
|
+
workspaceId: {
|
|
293
|
+
type: 'string',
|
|
294
|
+
description: "Optional workspace ID. With it the list is workspace-wide (every member's key results); without it you get your own."
|
|
295
|
+
},
|
|
296
|
+
period: {
|
|
297
|
+
type: 'string',
|
|
298
|
+
description: 'Optional period filter, e.g. "Q3-2026"'
|
|
299
|
+
},
|
|
300
|
+
goalId: {
|
|
301
|
+
type: 'number',
|
|
302
|
+
description: 'Optional objective ID (an integer). Only applies with flat: true.'
|
|
303
|
+
},
|
|
304
|
+
status: {
|
|
305
|
+
type: 'string',
|
|
306
|
+
description: 'Optional status: not-started, on-track, at-risk, off-track, achieved. Only applies with flat: true.'
|
|
307
|
+
},
|
|
308
|
+
flat: {
|
|
309
|
+
type: 'boolean',
|
|
310
|
+
description: 'Return a flat list of key results rather than grouping them by objective'
|
|
270
311
|
}
|
|
271
312
|
}
|
|
272
313
|
}
|
|
@@ -465,10 +506,17 @@ async function main() {
|
|
|
465
506
|
],
|
|
466
507
|
};
|
|
467
508
|
}
|
|
509
|
+
// Goes through the SDK's GoalsApi rather than a raw tRPC path. The old
|
|
510
|
+
// implementation called `goal.list`, which does not exist — the tool
|
|
511
|
+
// hard-errored with `No procedure found on path "goal.list"` on every
|
|
512
|
+
// invocation.
|
|
468
513
|
case 'get_goals': {
|
|
469
|
-
const
|
|
470
|
-
|
|
471
|
-
|
|
514
|
+
const workspaceId = args?.workspaceId;
|
|
515
|
+
const period = args?.period;
|
|
516
|
+
const status = args?.status;
|
|
517
|
+
const goals = args?.tree
|
|
518
|
+
? await client.goals.tree({ workspaceId, status })
|
|
519
|
+
: await client.goals.list({ workspaceId, period, status });
|
|
472
520
|
return {
|
|
473
521
|
content: [
|
|
474
522
|
{
|
|
@@ -478,6 +526,26 @@ async function main() {
|
|
|
478
526
|
],
|
|
479
527
|
};
|
|
480
528
|
}
|
|
529
|
+
case 'get_key_results': {
|
|
530
|
+
const workspaceId = args?.workspaceId;
|
|
531
|
+
const period = args?.period;
|
|
532
|
+
const keyResults = args?.flat
|
|
533
|
+
? await client.goals.keyResults.list({
|
|
534
|
+
workspaceId,
|
|
535
|
+
period,
|
|
536
|
+
goalId: args?.goalId,
|
|
537
|
+
status: args?.status,
|
|
538
|
+
})
|
|
539
|
+
: await client.goals.keyResults.byObjective({ workspaceId, period });
|
|
540
|
+
return {
|
|
541
|
+
content: [
|
|
542
|
+
{
|
|
543
|
+
type: 'text',
|
|
544
|
+
text: JSON.stringify(keyResults, null, 2),
|
|
545
|
+
},
|
|
546
|
+
],
|
|
547
|
+
};
|
|
548
|
+
}
|
|
481
549
|
case 'search': {
|
|
482
550
|
const results = await trpcClient.search.global.query({
|
|
483
551
|
query: args?.query,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "exponential-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "MCP server for Exponential - connect Claude to your projects, actions, and goals",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"dependencies": {
|
|
27
27
|
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
28
28
|
"commander": "^12.0.0",
|
|
29
|
-
"exponential-sdk": "^1.
|
|
29
|
+
"exponential-sdk": "^1.12.0",
|
|
30
30
|
"zod": "^3.22.0"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
package/dist/api.d.ts
DELETED
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Exponential API Client
|
|
3
|
-
* Handles authenticated requests to the Exponential API
|
|
4
|
-
*/
|
|
5
|
-
export interface ExponentialConfig {
|
|
6
|
-
apiKey: string;
|
|
7
|
-
baseUrl?: string;
|
|
8
|
-
}
|
|
9
|
-
export interface Project {
|
|
10
|
-
id: string;
|
|
11
|
-
name: string;
|
|
12
|
-
description?: string;
|
|
13
|
-
status: string;
|
|
14
|
-
priority: string;
|
|
15
|
-
progress: number;
|
|
16
|
-
}
|
|
17
|
-
export interface Action {
|
|
18
|
-
id: string;
|
|
19
|
-
name: string;
|
|
20
|
-
description?: string;
|
|
21
|
-
status: string;
|
|
22
|
-
priority: string;
|
|
23
|
-
dueDate?: string;
|
|
24
|
-
projectId?: string;
|
|
25
|
-
project?: {
|
|
26
|
-
name: string;
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
export interface Goal {
|
|
30
|
-
id: number;
|
|
31
|
-
title: string;
|
|
32
|
-
description?: string;
|
|
33
|
-
period?: string;
|
|
34
|
-
keyResults: KeyResult[];
|
|
35
|
-
}
|
|
36
|
-
export interface KeyResult {
|
|
37
|
-
id: string;
|
|
38
|
-
title: string;
|
|
39
|
-
targetValue?: number;
|
|
40
|
-
currentValue?: number;
|
|
41
|
-
status: string;
|
|
42
|
-
}
|
|
43
|
-
export interface Workspace {
|
|
44
|
-
id: string;
|
|
45
|
-
name: string;
|
|
46
|
-
slug: string;
|
|
47
|
-
}
|
|
48
|
-
export declare class ExponentialAPI {
|
|
49
|
-
private apiKey;
|
|
50
|
-
private baseUrl;
|
|
51
|
-
constructor(config: ExponentialConfig);
|
|
52
|
-
private request;
|
|
53
|
-
private trpcQuery;
|
|
54
|
-
private trpcMutation;
|
|
55
|
-
getWorkspaces(): Promise<Workspace[]>;
|
|
56
|
-
getProjects(workspaceId?: string): Promise<Project[]>;
|
|
57
|
-
getProject(id: string): Promise<Project>;
|
|
58
|
-
getActions(params?: {
|
|
59
|
-
projectId?: string;
|
|
60
|
-
status?: string;
|
|
61
|
-
}): Promise<Action[]>;
|
|
62
|
-
createAction(data: {
|
|
63
|
-
name: string;
|
|
64
|
-
description?: string;
|
|
65
|
-
projectId?: string;
|
|
66
|
-
priority?: string;
|
|
67
|
-
dueDate?: string;
|
|
68
|
-
}): Promise<Action>;
|
|
69
|
-
updateAction(id: string, data: {
|
|
70
|
-
name?: string;
|
|
71
|
-
status?: string;
|
|
72
|
-
priority?: string;
|
|
73
|
-
dueDate?: string;
|
|
74
|
-
}): Promise<Action>;
|
|
75
|
-
completeAction(id: string): Promise<Action>;
|
|
76
|
-
getGoals(workspaceId?: string): Promise<Goal[]>;
|
|
77
|
-
getGoal(id: number): Promise<Goal>;
|
|
78
|
-
quickCreateAction(text: string): Promise<Action>;
|
|
79
|
-
search(query: string): Promise<{
|
|
80
|
-
projects: Project[];
|
|
81
|
-
actions: Action[];
|
|
82
|
-
goals: Goal[];
|
|
83
|
-
}>;
|
|
84
|
-
}
|
package/dist/api.js
DELETED
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Exponential API Client
|
|
3
|
-
* Handles authenticated requests to the Exponential API
|
|
4
|
-
*/
|
|
5
|
-
const DEFAULT_BASE_URL = 'https://www.exponential.im';
|
|
6
|
-
export class ExponentialAPI {
|
|
7
|
-
apiKey;
|
|
8
|
-
baseUrl;
|
|
9
|
-
constructor(config) {
|
|
10
|
-
this.apiKey = config.apiKey;
|
|
11
|
-
this.baseUrl = config.baseUrl || DEFAULT_BASE_URL;
|
|
12
|
-
}
|
|
13
|
-
async request(endpoint, options = {}) {
|
|
14
|
-
const url = `${this.baseUrl}${endpoint}`;
|
|
15
|
-
const response = await fetch(url, {
|
|
16
|
-
...options,
|
|
17
|
-
headers: {
|
|
18
|
-
'Authorization': `Bearer ${this.apiKey}`,
|
|
19
|
-
'Content-Type': 'application/json',
|
|
20
|
-
...options.headers,
|
|
21
|
-
},
|
|
22
|
-
});
|
|
23
|
-
if (!response.ok) {
|
|
24
|
-
const error = await response.text();
|
|
25
|
-
throw new Error(`Exponential API error (${response.status}): ${error}`);
|
|
26
|
-
}
|
|
27
|
-
return response.json();
|
|
28
|
-
}
|
|
29
|
-
// tRPC-style calls
|
|
30
|
-
async trpcQuery(procedure, input) {
|
|
31
|
-
const inputStr = input ? encodeURIComponent(JSON.stringify(input)) : '';
|
|
32
|
-
const url = `/api/trpc/${procedure}${inputStr ? `?input=${inputStr}` : ''}`;
|
|
33
|
-
return this.request(url).then(r => r.result.data);
|
|
34
|
-
}
|
|
35
|
-
async trpcMutation(procedure, input) {
|
|
36
|
-
const url = `/api/trpc/${procedure}`;
|
|
37
|
-
return this.request(url, {
|
|
38
|
-
method: 'POST',
|
|
39
|
-
body: JSON.stringify(input),
|
|
40
|
-
}).then(r => r.result.data);
|
|
41
|
-
}
|
|
42
|
-
// === Workspace ===
|
|
43
|
-
async getWorkspaces() {
|
|
44
|
-
return this.trpcQuery('workspace.list');
|
|
45
|
-
}
|
|
46
|
-
// === Projects ===
|
|
47
|
-
async getProjects(workspaceId) {
|
|
48
|
-
return this.trpcQuery('project.list', { workspaceId });
|
|
49
|
-
}
|
|
50
|
-
async getProject(id) {
|
|
51
|
-
return this.trpcQuery('project.get', { id });
|
|
52
|
-
}
|
|
53
|
-
// === Actions ===
|
|
54
|
-
async getActions(params) {
|
|
55
|
-
return this.trpcQuery('action.list', params);
|
|
56
|
-
}
|
|
57
|
-
async createAction(data) {
|
|
58
|
-
return this.trpcMutation('action.create', data);
|
|
59
|
-
}
|
|
60
|
-
async updateAction(id, data) {
|
|
61
|
-
return this.trpcMutation('action.update', { id, ...data });
|
|
62
|
-
}
|
|
63
|
-
async completeAction(id) {
|
|
64
|
-
return this.updateAction(id, { status: 'COMPLETED' });
|
|
65
|
-
}
|
|
66
|
-
// === Goals (OKRs) ===
|
|
67
|
-
async getGoals(workspaceId) {
|
|
68
|
-
return this.trpcQuery('goal.list', { workspaceId });
|
|
69
|
-
}
|
|
70
|
-
async getGoal(id) {
|
|
71
|
-
return this.trpcQuery('goal.get', { id });
|
|
72
|
-
}
|
|
73
|
-
// === Quick Actions ===
|
|
74
|
-
async quickCreateAction(text) {
|
|
75
|
-
// Uses natural language parsing (dates, project names, etc.)
|
|
76
|
-
return this.trpcMutation('action.quickCreate', { text });
|
|
77
|
-
}
|
|
78
|
-
// === Search ===
|
|
79
|
-
async search(query) {
|
|
80
|
-
return this.trpcQuery('search.global', { query });
|
|
81
|
-
}
|
|
82
|
-
}
|