@getthesis/mcp-server 0.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/package.json +20 -0
- package/src/index.js +158 -0
package/package.json
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@getthesis/mcp-server",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "MCP server for Thesis — gives AI agents direct access to strategic context",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "src/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"thesis-mcp": "src/index.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"src/"
|
|
12
|
+
],
|
|
13
|
+
"engines": {
|
|
14
|
+
"node": ">=18"
|
|
15
|
+
},
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
18
|
+
"zod": "^3.25.0"
|
|
19
|
+
}
|
|
20
|
+
}
|
package/src/index.js
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
4
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
|
|
7
|
+
// ─── Config ──────────────────────────────────────────────────────────
|
|
8
|
+
|
|
9
|
+
const API_URL = process.env.THESIS_API_URL || "https://www.getthesis.io";
|
|
10
|
+
const API_KEY = process.env.THESIS_API_KEY;
|
|
11
|
+
|
|
12
|
+
async function api(path, options = {}) {
|
|
13
|
+
if (!API_KEY) throw new Error("THESIS_API_KEY not set");
|
|
14
|
+
|
|
15
|
+
const res = await fetch(`${API_URL}${path}`, {
|
|
16
|
+
...options,
|
|
17
|
+
headers: {
|
|
18
|
+
Authorization: `Bearer ${API_KEY}`,
|
|
19
|
+
"Content-Type": "application/json",
|
|
20
|
+
...options.headers,
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
const contentType = res.headers.get("content-type") || "";
|
|
25
|
+
if (contentType.includes("application/json")) {
|
|
26
|
+
const data = await res.json();
|
|
27
|
+
if (!res.ok) throw new Error(data.error || `HTTP ${res.status}`);
|
|
28
|
+
return data;
|
|
29
|
+
}
|
|
30
|
+
const text = await res.text();
|
|
31
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
32
|
+
return text;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// ─── Server ──────────────────────────────────────────────────────────
|
|
36
|
+
|
|
37
|
+
const server = new McpServer({ name: "thesis", version: "0.1.0" });
|
|
38
|
+
|
|
39
|
+
// ─── Tools ───────────────────────────────────────────────────────────
|
|
40
|
+
|
|
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
|
+
server.tool(
|
|
56
|
+
"thesis_list_items",
|
|
57
|
+
"List items in the Thesis workbench. Shows items ready for agent execution, dispatched, or awaiting review.",
|
|
58
|
+
{
|
|
59
|
+
status: z.enum(["ready", "dispatched", "in_progress", "review", "completed"]).optional().describe("Filter by agent status"),
|
|
60
|
+
},
|
|
61
|
+
async ({ status }) => {
|
|
62
|
+
try {
|
|
63
|
+
const query = status ? `?agentStatus=${status}` : "";
|
|
64
|
+
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
|
+
}
|
|
71
|
+
}
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
server.tool(
|
|
75
|
+
"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.",
|
|
77
|
+
{ itemId: z.string().describe("The item ID to dispatch") },
|
|
78
|
+
async ({ itemId }) => {
|
|
79
|
+
try {
|
|
80
|
+
const data = await api(`/api/v1/items/${itemId}/dispatch`, {
|
|
81
|
+
method: "POST",
|
|
82
|
+
body: JSON.stringify({ provider: "claude_code" }),
|
|
83
|
+
});
|
|
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
|
+
}
|
|
88
|
+
}
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
server.tool(
|
|
92
|
+
"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.",
|
|
94
|
+
{
|
|
95
|
+
itemId: z.string().describe("The item ID"),
|
|
96
|
+
summary: z.string().describe("What was built"),
|
|
97
|
+
decisions: z.string().optional().describe("Key decisions made and why"),
|
|
98
|
+
unexpected: z.string().optional().describe("Anything unexpected encountered"),
|
|
99
|
+
successCriteriaMet: z.boolean().nullable().optional().describe("true = met, false = not met, null = partially"),
|
|
100
|
+
},
|
|
101
|
+
async ({ itemId, summary, decisions, unexpected, successCriteriaMet }) => {
|
|
102
|
+
try {
|
|
103
|
+
const data = await api(`/api/v1/items/${itemId}/outcome`, {
|
|
104
|
+
method: "POST",
|
|
105
|
+
body: JSON.stringify({ summary, decisions, unexpected, successCriteriaMet }),
|
|
106
|
+
});
|
|
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
|
+
}
|
|
111
|
+
}
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
server.tool(
|
|
115
|
+
"thesis_get_beliefs",
|
|
116
|
+
"Get all active strategic beliefs in the workspace with confidence levels. Use this to understand the strategic context.",
|
|
117
|
+
{},
|
|
118
|
+
async () => {
|
|
119
|
+
try {
|
|
120
|
+
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
|
+
}
|
|
127
|
+
}
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
server.tool(
|
|
131
|
+
"thesis_check_shifts",
|
|
132
|
+
"Check if any beliefs have shifted since items were dispatched. Use this to verify the strategic ground hasn't moved during execution.",
|
|
133
|
+
{},
|
|
134
|
+
async () => {
|
|
135
|
+
try {
|
|
136
|
+
const data = await api("/api/v1/check");
|
|
137
|
+
if (!data.hasShifts) return { content: [{ type: "text", text: "All clear — no belief shifts." }] };
|
|
138
|
+
const lines = [];
|
|
139
|
+
if (data.changedBeliefs?.length) {
|
|
140
|
+
lines.push("Changed beliefs:");
|
|
141
|
+
data.changedBeliefs.forEach((b) => lines.push(` - [${b.confidence}] ${b.statement}`));
|
|
142
|
+
}
|
|
143
|
+
if (data.shiftedItems?.length) {
|
|
144
|
+
lines.push("Affected items:");
|
|
145
|
+
data.shiftedItems.forEach((i) => lines.push(` - ${i.title} (${i.agentStatus})`));
|
|
146
|
+
}
|
|
147
|
+
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
148
|
+
} catch (err) {
|
|
149
|
+
return { content: [{ type: "text", text: `Error: ${err.message}` }], isError: true };
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
);
|
|
153
|
+
|
|
154
|
+
// ─── Start ───────────────────────────────────────────────────────────
|
|
155
|
+
|
|
156
|
+
const transport = new StdioServerTransport();
|
|
157
|
+
await server.connect(transport);
|
|
158
|
+
console.error("Thesis MCP server running");
|