@getthesis/mcp-server 0.1.0 → 0.2.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/package.json +1 -1
- package/src/index.js +86 -47
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -32,26 +32,20 @@ async function api(path, options = {}) {
|
|
|
32
32
|
return text;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
+
function ok(text) {
|
|
36
|
+
return { content: [{ type: "text", text }] };
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function err(msg) {
|
|
40
|
+
return { content: [{ type: "text", text: `Error: ${msg}` }], isError: true };
|
|
41
|
+
}
|
|
42
|
+
|
|
35
43
|
// ─── Server ──────────────────────────────────────────────────────────
|
|
36
44
|
|
|
37
|
-
const server = new McpServer({ name: "thesis", version: "0.
|
|
45
|
+
const server = new McpServer({ name: "thesis", version: "0.2.0" });
|
|
38
46
|
|
|
39
47
|
// ─── Tools ───────────────────────────────────────────────────────────
|
|
40
48
|
|
|
41
|
-
server.tool(
|
|
42
|
-
"thesis_get_brief",
|
|
43
|
-
"Get the full strategic brief for a workbench item. Returns the item's context including linked beliefs, theme, success criteria, constraints, and design principles. Use this before starting work on an item.",
|
|
44
|
-
{ itemId: z.string().describe("The item ID") },
|
|
45
|
-
async ({ itemId }) => {
|
|
46
|
-
try {
|
|
47
|
-
const brief = await api(`/api/v1/items/${itemId}/brief`);
|
|
48
|
-
return { content: [{ type: "text", text: typeof brief === "string" ? brief : JSON.stringify(brief, null, 2) }] };
|
|
49
|
-
} catch (err) {
|
|
50
|
-
return { content: [{ type: "text", text: `Error: ${err.message}` }], isError: true };
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
);
|
|
54
|
-
|
|
55
49
|
server.tool(
|
|
56
50
|
"thesis_list_items",
|
|
57
51
|
"List items in the Thesis workbench. Shows items ready for agent execution, dispatched, or awaiting review.",
|
|
@@ -62,18 +56,31 @@ server.tool(
|
|
|
62
56
|
try {
|
|
63
57
|
const query = status ? `?agentStatus=${status}` : "";
|
|
64
58
|
const data = await api(`/api/v1/items${query}`);
|
|
65
|
-
if (!data.items?.length) return
|
|
66
|
-
const lines = data.items.map(
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
return
|
|
70
|
-
}
|
|
59
|
+
if (!data.items?.length) return ok("No items found.");
|
|
60
|
+
const lines = data.items.map(
|
|
61
|
+
(i) => `- [${i.agentStatus || i.status}] ${i.title} (ID: ${i.id})${i.themeName ? ` — Theme: ${i.themeName}` : ""}`
|
|
62
|
+
);
|
|
63
|
+
return ok(lines.join("\n"));
|
|
64
|
+
} catch (e) { return err(e.message); }
|
|
65
|
+
}
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
server.tool(
|
|
69
|
+
"thesis_get_brief",
|
|
70
|
+
"Get the full strategic brief for a workbench item. Returns the item's strategic context including beliefs, theme, success criteria, constraints, and design principles. Use this before starting work on an item.",
|
|
71
|
+
{ itemId: z.string().describe("The item ID") },
|
|
72
|
+
async ({ itemId }) => {
|
|
73
|
+
try {
|
|
74
|
+
const data = await api(`/api/v1/items/${itemId}/brief`);
|
|
75
|
+
// Return the markdown version for readability
|
|
76
|
+
return ok(data.markdown || JSON.stringify(data, null, 2));
|
|
77
|
+
} catch (e) { return err(e.message); }
|
|
71
78
|
}
|
|
72
79
|
);
|
|
73
80
|
|
|
74
81
|
server.tool(
|
|
75
82
|
"thesis_dispatch",
|
|
76
|
-
"Dispatch an item for agent execution. Assembles the strategic brief, marks the item as dispatched, and returns the full brief. Call this when
|
|
83
|
+
"Dispatch an item for agent execution. Assembles the strategic brief, marks the item as dispatched, and returns the full brief. Call this when you are about to start working on an item.",
|
|
77
84
|
{ itemId: z.string().describe("The item ID to dispatch") },
|
|
78
85
|
async ({ itemId }) => {
|
|
79
86
|
try {
|
|
@@ -81,16 +88,14 @@ server.tool(
|
|
|
81
88
|
method: "POST",
|
|
82
89
|
body: JSON.stringify({ provider: "claude_code" }),
|
|
83
90
|
});
|
|
84
|
-
return
|
|
85
|
-
} catch (err)
|
|
86
|
-
return { content: [{ type: "text", text: `Error: ${err.message}` }], isError: true };
|
|
87
|
-
}
|
|
91
|
+
return ok(data.brief || JSON.stringify(data, null, 2));
|
|
92
|
+
} catch (e) { return err(e.message); }
|
|
88
93
|
}
|
|
89
94
|
);
|
|
90
95
|
|
|
91
96
|
server.tool(
|
|
92
97
|
"thesis_report_outcome",
|
|
93
|
-
"Report the outcome of completed work back to Thesis. This triggers AI analysis against
|
|
98
|
+
"Report the outcome of completed work back to Thesis. Include what you built, key decisions, and anything unexpected. This triggers AI evidence analysis against strategic beliefs.",
|
|
94
99
|
{
|
|
95
100
|
itemId: z.string().describe("The item ID"),
|
|
96
101
|
summary: z.string().describe("What was built"),
|
|
@@ -104,26 +109,24 @@ server.tool(
|
|
|
104
109
|
method: "POST",
|
|
105
110
|
body: JSON.stringify({ summary, decisions, unexpected, successCriteriaMet }),
|
|
106
111
|
});
|
|
107
|
-
return
|
|
108
|
-
} catch (err)
|
|
109
|
-
return { content: [{ type: "text", text: `Error: ${err.message}` }], isError: true };
|
|
110
|
-
}
|
|
112
|
+
return ok(`Outcome recorded. Status: ${data.status || "review"}. Evidence analysis running.`);
|
|
113
|
+
} catch (e) { return err(e.message); }
|
|
111
114
|
}
|
|
112
115
|
);
|
|
113
116
|
|
|
114
117
|
server.tool(
|
|
115
118
|
"thesis_get_beliefs",
|
|
116
|
-
"Get all active strategic beliefs in the workspace with confidence levels
|
|
119
|
+
"Get all active strategic beliefs in the workspace with confidence levels and evidence counts.",
|
|
117
120
|
{},
|
|
118
121
|
async () => {
|
|
119
122
|
try {
|
|
120
123
|
const data = await api("/api/v1/beliefs");
|
|
121
|
-
if (!data.beliefs?.length) return
|
|
122
|
-
const lines = data.beliefs.map(
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
return
|
|
126
|
-
}
|
|
124
|
+
if (!data.beliefs?.length) return ok("No active beliefs.");
|
|
125
|
+
const lines = data.beliefs.map(
|
|
126
|
+
(b) => `- [${b.confidence}] ${b.statement} (${b.evidenceCount || 0} evidence, ${b.dependentThemeCount || 0} themes)`
|
|
127
|
+
);
|
|
128
|
+
return ok(lines.join("\n"));
|
|
129
|
+
} catch (e) { return err(e.message); }
|
|
127
130
|
}
|
|
128
131
|
);
|
|
129
132
|
|
|
@@ -134,20 +137,56 @@ server.tool(
|
|
|
134
137
|
async () => {
|
|
135
138
|
try {
|
|
136
139
|
const data = await api("/api/v1/check");
|
|
137
|
-
if (!data.hasShifts) return
|
|
140
|
+
if (!data.hasShifts) return ok("All clear — no belief shifts detected.");
|
|
138
141
|
const lines = [];
|
|
139
142
|
if (data.changedBeliefs?.length) {
|
|
140
143
|
lines.push("Changed beliefs:");
|
|
141
144
|
data.changedBeliefs.forEach((b) => lines.push(` - [${b.confidence}] ${b.statement}`));
|
|
142
145
|
}
|
|
143
|
-
if (data.
|
|
144
|
-
lines.push("Affected items:");
|
|
145
|
-
data.
|
|
146
|
+
if (data.affectedItems?.length) {
|
|
147
|
+
lines.push("Affected dispatched items:");
|
|
148
|
+
data.affectedItems.forEach((i) => lines.push(` - ${i.title} (${i.agentStatus})`));
|
|
146
149
|
}
|
|
147
|
-
return
|
|
148
|
-
} catch (err)
|
|
149
|
-
|
|
150
|
-
|
|
150
|
+
return ok(lines.join("\n"));
|
|
151
|
+
} catch (e) { return err(e.message); }
|
|
152
|
+
}
|
|
153
|
+
);
|
|
154
|
+
|
|
155
|
+
server.tool(
|
|
156
|
+
"thesis_get_context",
|
|
157
|
+
"Search context entries in the workspace. Use this to find customer feedback, market signals, or other evidence relevant to your current task.",
|
|
158
|
+
{
|
|
159
|
+
query: z.string().optional().describe("Search query to filter entries"),
|
|
160
|
+
limit: z.number().optional().default(10).describe("Max results"),
|
|
161
|
+
},
|
|
162
|
+
async ({ query, limit }) => {
|
|
163
|
+
try {
|
|
164
|
+
const params = new URLSearchParams();
|
|
165
|
+
if (query) params.set("q", query);
|
|
166
|
+
if (limit) params.set("limit", String(limit));
|
|
167
|
+
const data = await api(`/api/v1/context?${params}`);
|
|
168
|
+
if (!data.entries?.length) return ok("No context entries found.");
|
|
169
|
+
const lines = data.entries.map(
|
|
170
|
+
(e) => `### ${e.title}${e.source ? ` (${e.source})` : ""}\n${e.content}\n`
|
|
171
|
+
);
|
|
172
|
+
return ok(lines.join("\n"));
|
|
173
|
+
} catch (e) { return err(e.message); }
|
|
174
|
+
}
|
|
175
|
+
);
|
|
176
|
+
|
|
177
|
+
server.tool(
|
|
178
|
+
"thesis_get_design_principles",
|
|
179
|
+
"Get the workspace's design principles and constraints. Reference these when making implementation decisions.",
|
|
180
|
+
{},
|
|
181
|
+
async () => {
|
|
182
|
+
try {
|
|
183
|
+
const data = await api("/api/v1/design-principles");
|
|
184
|
+
if (!data.principles?.length) return ok("No design principles set.");
|
|
185
|
+
const lines = data.principles.map(
|
|
186
|
+
(p) => `- ${p.statement}${p.rationale ? ` — ${p.rationale}` : ""}`
|
|
187
|
+
);
|
|
188
|
+
return ok(lines.join("\n"));
|
|
189
|
+
} catch (e) { return err(e.message); }
|
|
151
190
|
}
|
|
152
191
|
);
|
|
153
192
|
|
|
@@ -155,4 +194,4 @@ server.tool(
|
|
|
155
194
|
|
|
156
195
|
const transport = new StdioServerTransport();
|
|
157
196
|
await server.connect(transport);
|
|
158
|
-
console.error("Thesis MCP server running");
|
|
197
|
+
console.error("Thesis MCP server v0.2.0 running");
|