@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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/index.js +86 -47
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@getthesis/mcp-server",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "MCP server for Thesis — gives AI agents direct access to strategic context",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
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.1.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 { content: [{ type: "text", text: "No items found." }] };
66
- const lines = data.items.map((i) => `- [${i.agentStatus || i.status}] ${i.title} (ID: ${i.id})`);
67
- return { content: [{ type: "text", text: lines.join("\n") }] };
68
- } catch (err) {
69
- return { content: [{ type: "text", text: `Error: ${err.message}` }], isError: true };
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 starting work on an item.",
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 { content: [{ type: "text", text: data.brief || JSON.stringify(data, null, 2) }] };
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 the workspace's strategic beliefs to generate evidence.",
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 { content: [{ type: "text", text: `Outcome recorded. Status: ${data.status || "review"}. Evidence analysis running.` }] };
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. Use this to understand the strategic context.",
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 { content: [{ type: "text", text: "No active beliefs." }] };
122
- const lines = data.beliefs.map((b) => `- [${b.confidence}] ${b.statement}`);
123
- return { content: [{ type: "text", text: lines.join("\n") }] };
124
- } catch (err) {
125
- return { content: [{ type: "text", text: `Error: ${err.message}` }], isError: true };
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 { content: [{ type: "text", text: "All clear — no belief shifts." }] };
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.shiftedItems?.length) {
144
- lines.push("Affected items:");
145
- data.shiftedItems.forEach((i) => lines.push(` - ${i.title} (${i.agentStatus})`));
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 { content: [{ type: "text", text: lines.join("\n") }] };
148
- } catch (err) {
149
- return { content: [{ type: "text", text: `Error: ${err.message}` }], isError: true };
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");