thorbit-deposition-mcp 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/dist/bin/thorbit-deposition-mcp.cjs +174 -0
- package/dist/bin/thorbit-deposition-mcp.cjs.map +1 -0
- package/dist/bin/thorbit-deposition-mcp.d.cts +2 -0
- package/dist/bin/thorbit-deposition-mcp.d.ts +2 -0
- package/dist/bin/thorbit-deposition-mcp.js +173 -0
- package/dist/bin/thorbit-deposition-mcp.js.map +1 -0
- package/dist/index.cjs +202 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +39 -0
- package/dist/index.d.ts +39 -0
- package/dist/index.js +172 -0
- package/dist/index.js.map +1 -0
- package/package.json +41 -0
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
|
|
4
|
+
// bin/thorbit-deposition-mcp.ts
|
|
5
|
+
var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
6
|
+
|
|
7
|
+
// src/deposition-api-client.ts
|
|
8
|
+
var ThorbitDepositionApiClient = class {
|
|
9
|
+
baseUrl;
|
|
10
|
+
apiKey;
|
|
11
|
+
constructor(options) {
|
|
12
|
+
this.baseUrl = options.baseUrl.replace(/\/$/, "");
|
|
13
|
+
this.apiKey = options.apiKey;
|
|
14
|
+
}
|
|
15
|
+
async callTool(toolName, input) {
|
|
16
|
+
const response = await fetch(`${this.baseUrl}/api/v1/mcp/deposition/${toolName}`, {
|
|
17
|
+
method: "POST",
|
|
18
|
+
headers: {
|
|
19
|
+
"x-thorbit-api-key": this.apiKey,
|
|
20
|
+
"Content-Type": "application/json"
|
|
21
|
+
},
|
|
22
|
+
body: JSON.stringify(input ?? {})
|
|
23
|
+
});
|
|
24
|
+
const body = await response.json().catch(() => null);
|
|
25
|
+
if (body && typeof body === "object" && "ok" in body) return body;
|
|
26
|
+
return {
|
|
27
|
+
ok: false,
|
|
28
|
+
requestId: "unavailable",
|
|
29
|
+
error: {
|
|
30
|
+
code: response.ok ? "invalid_response" : `http_${response.status}`,
|
|
31
|
+
message: response.ok ? "Thorbit returned an invalid MCP response" : `Thorbit API request failed with HTTP ${response.status}`
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
// src/deposition-mcp-env.ts
|
|
38
|
+
var import_node_fs = require("fs");
|
|
39
|
+
var import_node_os = require("os");
|
|
40
|
+
var import_node_path = require("path");
|
|
41
|
+
function readApiKeyFile() {
|
|
42
|
+
const explicitPath = process.env.THORBIT_DEPOSITION_MCP_KEY_PATH?.trim();
|
|
43
|
+
const paths = [explicitPath, (0, import_node_path.join)((0, import_node_os.homedir)(), ".thorbit-deposition-mcp-key")].filter(Boolean);
|
|
44
|
+
for (const path of paths) {
|
|
45
|
+
try {
|
|
46
|
+
const value = (0, import_node_fs.readFileSync)(path, "utf8").trim();
|
|
47
|
+
if (value) return value;
|
|
48
|
+
} catch {
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return void 0;
|
|
53
|
+
}
|
|
54
|
+
function resolveThorbitDepositionMcpEnv() {
|
|
55
|
+
const apiKey = (process.env.THORBIT_API_KEY || process.env.THORBIT_MCP_API_KEY || process.env.THORBIT_DEPOSITION_MCP_API_KEY || readApiKeyFile())?.trim();
|
|
56
|
+
if (!apiKey) {
|
|
57
|
+
throw new Error("THORBIT_API_KEY, THORBIT_MCP_API_KEY, or ~/.thorbit-deposition-mcp-key is required");
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
apiKey,
|
|
61
|
+
baseUrl: (process.env.THORBIT_BASE_URL || process.env.THORBIT_DEPOSITION_MCP_BASE_URL || "https://thorbit.ai").trim()
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// src/deposition-mcp-server.ts
|
|
66
|
+
var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
67
|
+
|
|
68
|
+
// src/deposition-mcp-response-formatters.ts
|
|
69
|
+
function formatThorbitDepositionMcpToolResult(toolName, envelope) {
|
|
70
|
+
const text = JSON.stringify({ toolName, ...envelope }, null, 2);
|
|
71
|
+
return {
|
|
72
|
+
content: [{ type: "text", text }],
|
|
73
|
+
isError: !envelope.ok
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// src/deposition-mcp-tool-schemas.ts
|
|
78
|
+
var import_zod = require("zod");
|
|
79
|
+
var ThorbitDepositionStartInputSchema = {
|
|
80
|
+
companyName: import_zod.z.string().min(1).max(255).describe("The challenger company or product being depositioned."),
|
|
81
|
+
productUrl: import_zod.z.string().url().max(2048).describe("URL of the challenger product homepage."),
|
|
82
|
+
categoryName: import_zod.z.string().min(1).max(255).describe('The product category, e.g. "B2B sales analytics".'),
|
|
83
|
+
competitorUrls: import_zod.z.array(import_zod.z.string().url()).max(5).default([]).describe("0-5 competitor URLs. Auto-discovered via SERP if fewer than 2 are provided."),
|
|
84
|
+
reviewsUrl: import_zod.z.string().url().max(2048).optional().describe("Optional customer reviews URL (G2, Trustpilot, Reddit thread)."),
|
|
85
|
+
knownPains: import_zod.z.array(import_zod.z.string().min(1)).max(50).optional().describe("Optional known customer pain points to seed the analysis."),
|
|
86
|
+
projectPublicId: import_zod.z.string().min(1).optional().describe("Optional Thorbit project to associate the run with.")
|
|
87
|
+
};
|
|
88
|
+
var ThorbitDepositionGetInputSchema = {
|
|
89
|
+
runPublicId: import_zod.z.string().min(1).describe("Deposition run public ID returned by thorbit_deposition_start."),
|
|
90
|
+
includePhaseData: import_zod.z.boolean().default(false).describe("Include raw per-phase intermediate data in addition to the lean status.")
|
|
91
|
+
};
|
|
92
|
+
var ThorbitDepositionGetPlaybookInputSchema = {
|
|
93
|
+
runPublicId: import_zod.z.string().min(1).describe("Deposition run public ID. Returns the markdown playbook once the run is complete.")
|
|
94
|
+
};
|
|
95
|
+
var ThorbitDepositionListInputSchema = {
|
|
96
|
+
projectPublicId: import_zod.z.string().min(1).optional().describe("Optional project filter; omit for all org runs."),
|
|
97
|
+
search: import_zod.z.string().max(200).optional().describe("Optional company-name substring filter."),
|
|
98
|
+
status: import_zod.z.enum(["queued", "running", "complete", "failed"]).optional().describe("Optional run status filter."),
|
|
99
|
+
limit: import_zod.z.number().int().min(1).max(100).default(25).describe("Maximum runs to return."),
|
|
100
|
+
offset: import_zod.z.number().int().min(0).default(0).describe("Pagination offset.")
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
// src/deposition-mcp-server.ts
|
|
104
|
+
var VERSION = "0.1.0";
|
|
105
|
+
function readOnlyAnnotations(title) {
|
|
106
|
+
return { title, readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
|
|
107
|
+
}
|
|
108
|
+
function writeAnnotations(title) {
|
|
109
|
+
return { title, readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true };
|
|
110
|
+
}
|
|
111
|
+
var SERVER_INSTRUCTIONS = [
|
|
112
|
+
"Thorbit Depositioning MCP. Runs the durable Depositioning strategy pipeline on hosted Thorbit (this server is a thin client). It researches competitors + customers, finds the binding vulnerability, classifies mover populations, designs a category class, builds a displacement mechanism, and writes a strategy playbook. All write/analysis tools are metered against your API key.",
|
|
113
|
+
"",
|
|
114
|
+
"INTAKE (ask the user these BEFORE thorbit_deposition_start, then run):",
|
|
115
|
+
"1. Company / product name being depositioned.",
|
|
116
|
+
"2. Product URL (the challenger homepage).",
|
|
117
|
+
'3. Category name (e.g. "B2B sales analytics").',
|
|
118
|
+
"4. Optional: 0-5 competitor URLs (auto-discovered via SERP if fewer than 2).",
|
|
119
|
+
"5. Optional: a customer reviews URL (G2 / Trustpilot / Reddit) and known customer pain points.",
|
|
120
|
+
"",
|
|
121
|
+
"ASYNC CONTRACT (important):",
|
|
122
|
+
"- thorbit_deposition_start returns quickly with {runPublicId, poll}. Do NOT block \u2014 follow result.poll.",
|
|
123
|
+
"- Poll thorbit_deposition_get until status is terminal (complete/failed). It returns a LEAN status (phase, progress, binding state, strategy) with a nextAction.",
|
|
124
|
+
"- When status is complete, call thorbit_deposition_get_playbook to read the finished markdown playbook.",
|
|
125
|
+
"- Use thorbit_deposition_list to find past runs (by company/status) and their runPublicId."
|
|
126
|
+
].join("\n");
|
|
127
|
+
function buildThorbitDepositionMcpServer(client) {
|
|
128
|
+
const server = new import_mcp.McpServer({ name: "thorbit-deposition-mcp", version: VERSION }, { instructions: SERVER_INSTRUCTIONS });
|
|
129
|
+
function registerTool(toolName, config) {
|
|
130
|
+
server.registerTool(toolName, config, async (input) => {
|
|
131
|
+
const envelope = await client.callTool(toolName, input);
|
|
132
|
+
return formatThorbitDepositionMcpToolResult(toolName, envelope);
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
registerTool("thorbit_deposition_start", {
|
|
136
|
+
title: "Start Depositioning Run",
|
|
137
|
+
description: "Start a durable Depositioning strategy run for a challenger product in a category. Researches competitors and customers, finds the binding vulnerability, classifies movers, designs a category class, builds a displacement mechanism, and writes a playbook. Returns a runPublicId plus a thorbit_deposition_get poll target. Metered.",
|
|
138
|
+
inputSchema: ThorbitDepositionStartInputSchema,
|
|
139
|
+
annotations: writeAnnotations("Start Depositioning Run")
|
|
140
|
+
});
|
|
141
|
+
registerTool("thorbit_deposition_get", {
|
|
142
|
+
title: "Read Depositioning Run Status",
|
|
143
|
+
description: "Read a Depositioning run: status, current phase, progress, selected binding state and strategy, primary vulnerability, category class, displacement mechanism, and whether the playbook is ready. Returns a nextAction. Poll until status is complete or failed.",
|
|
144
|
+
inputSchema: ThorbitDepositionGetInputSchema,
|
|
145
|
+
annotations: readOnlyAnnotations("Read Depositioning Run Status")
|
|
146
|
+
});
|
|
147
|
+
registerTool("thorbit_deposition_get_playbook", {
|
|
148
|
+
title: "Read Depositioning Playbook",
|
|
149
|
+
description: "Return the finished deposition-playbook markdown for a completed run (executive brief, the four elements, activation guide). Returns not_found until the run completes.",
|
|
150
|
+
inputSchema: ThorbitDepositionGetPlaybookInputSchema,
|
|
151
|
+
annotations: readOnlyAnnotations("Read Depositioning Playbook")
|
|
152
|
+
});
|
|
153
|
+
registerTool("thorbit_deposition_list", {
|
|
154
|
+
title: "List Depositioning Runs",
|
|
155
|
+
description: "List past Depositioning runs (most recent first) with runPublicId, company, category, status, binding state, and strategy. Filter by project, company-name search, or status. Use to find a prior run to read.",
|
|
156
|
+
inputSchema: ThorbitDepositionListInputSchema,
|
|
157
|
+
annotations: readOnlyAnnotations("List Depositioning Runs")
|
|
158
|
+
});
|
|
159
|
+
return server;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// bin/thorbit-deposition-mcp.ts
|
|
163
|
+
async function main() {
|
|
164
|
+
const env = resolveThorbitDepositionMcpEnv();
|
|
165
|
+
const client = new ThorbitDepositionApiClient(env);
|
|
166
|
+
const server = buildThorbitDepositionMcpServer(client);
|
|
167
|
+
await server.connect(new import_stdio.StdioServerTransport());
|
|
168
|
+
}
|
|
169
|
+
main().catch((error) => {
|
|
170
|
+
process.stderr.write(`${error instanceof Error ? error.message : String(error)}
|
|
171
|
+
`);
|
|
172
|
+
process.exit(1);
|
|
173
|
+
});
|
|
174
|
+
//# sourceMappingURL=thorbit-deposition-mcp.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../bin/thorbit-deposition-mcp.ts","../../src/deposition-api-client.ts","../../src/deposition-mcp-env.ts","../../src/deposition-mcp-server.ts","../../src/deposition-mcp-response-formatters.ts","../../src/deposition-mcp-tool-schemas.ts"],"sourcesContent":["import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'\nimport { ThorbitDepositionApiClient } from '../src/deposition-api-client.js'\nimport { resolveThorbitDepositionMcpEnv } from '../src/deposition-mcp-env.js'\nimport { buildThorbitDepositionMcpServer } from '../src/deposition-mcp-server.js'\n\nasync function main() {\n const env = resolveThorbitDepositionMcpEnv()\n const client = new ThorbitDepositionApiClient(env)\n const server = buildThorbitDepositionMcpServer(client)\n await server.connect(new StdioServerTransport())\n}\n\nmain().catch(error => {\n process.stderr.write(`${error instanceof Error ? error.message : String(error)}\\n`)\n process.exit(1)\n})\n","import type { ThorbitDepositionMcpToolName } from './deposition-mcp-tool-names.js'\n\nexport type ThorbitDepositionMcpEnvelope =\n | {\n ok: true\n result: unknown\n warnings?: string[]\n requestId: string\n }\n | {\n ok: false\n error: {\n code: string\n message: string\n details?: unknown\n }\n requestId: string\n }\n\nexport class ThorbitDepositionApiClient {\n private readonly baseUrl: string\n private readonly apiKey: string\n\n constructor(options: { baseUrl: string; apiKey: string }) {\n this.baseUrl = options.baseUrl.replace(/\\/$/, '')\n this.apiKey = options.apiKey\n }\n\n async callTool(toolName: ThorbitDepositionMcpToolName, input: unknown): Promise<ThorbitDepositionMcpEnvelope> {\n const response = await fetch(`${this.baseUrl}/api/v1/mcp/deposition/${toolName}`, {\n method: 'POST',\n headers: {\n 'x-thorbit-api-key': this.apiKey,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(input ?? {}),\n })\n\n const body = await response.json().catch(() => null) as ThorbitDepositionMcpEnvelope | null\n if (body && typeof body === 'object' && 'ok' in body) return body\n\n return {\n ok: false,\n requestId: 'unavailable',\n error: {\n code: response.ok ? 'invalid_response' : `http_${response.status}`,\n message: response.ok ? 'Thorbit returned an invalid MCP response' : `Thorbit API request failed with HTTP ${response.status}`,\n },\n }\n }\n}\n","import { readFileSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { join } from 'node:path'\n\nexport type ThorbitDepositionMcpEnv = {\n apiKey: string\n baseUrl: string\n}\n\nfunction readApiKeyFile(): string | undefined {\n const explicitPath = process.env.THORBIT_DEPOSITION_MCP_KEY_PATH?.trim()\n const paths = [explicitPath, join(homedir(), '.thorbit-deposition-mcp-key')].filter(Boolean) as string[]\n for (const path of paths) {\n try {\n const value = readFileSync(path, 'utf8').trim()\n if (value) return value\n } catch {\n continue\n }\n }\n return undefined\n}\n\nexport function resolveThorbitDepositionMcpEnv(): ThorbitDepositionMcpEnv {\n const apiKey = (\n process.env.THORBIT_API_KEY ||\n process.env.THORBIT_MCP_API_KEY ||\n process.env.THORBIT_DEPOSITION_MCP_API_KEY ||\n readApiKeyFile()\n )?.trim()\n\n if (!apiKey) {\n throw new Error('THORBIT_API_KEY, THORBIT_MCP_API_KEY, or ~/.thorbit-deposition-mcp-key is required')\n }\n\n return {\n apiKey,\n baseUrl: (process.env.THORBIT_BASE_URL || process.env.THORBIT_DEPOSITION_MCP_BASE_URL || 'https://thorbit.ai').trim(),\n }\n}\n","import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport type { ToolAnnotations } from '@modelcontextprotocol/sdk/types.js'\nimport type { ZodRawShape } from 'zod'\nimport type { ThorbitDepositionApiClient } from './deposition-api-client.js'\nimport { formatThorbitDepositionMcpToolResult } from './deposition-mcp-response-formatters.js'\nimport {\n ThorbitDepositionStartInputSchema,\n ThorbitDepositionGetInputSchema,\n ThorbitDepositionGetPlaybookInputSchema,\n ThorbitDepositionListInputSchema,\n} from './deposition-mcp-tool-schemas.js'\nimport type { ThorbitDepositionMcpToolName } from './deposition-mcp-tool-names.js'\n\nconst VERSION = '0.1.0'\n\ntype ThorbitDepositionToolConfig<InputArgs extends ZodRawShape> = {\n title: string\n description: string\n inputSchema: InputArgs\n annotations: ToolAnnotations\n}\n\nfunction readOnlyAnnotations(title: string) {\n return { title, readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false }\n}\n\nfunction writeAnnotations(title: string) {\n return { title, readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true }\n}\n\nexport const SERVER_INSTRUCTIONS = [\n 'Thorbit Depositioning MCP. Runs the durable Depositioning strategy pipeline on hosted Thorbit (this server is a thin client). It researches competitors + customers, finds the binding vulnerability, classifies mover populations, designs a category class, builds a displacement mechanism, and writes a strategy playbook. All write/analysis tools are metered against your API key.',\n '',\n 'INTAKE (ask the user these BEFORE thorbit_deposition_start, then run):',\n '1. Company / product name being depositioned.',\n '2. Product URL (the challenger homepage).',\n '3. Category name (e.g. \"B2B sales analytics\").',\n '4. Optional: 0-5 competitor URLs (auto-discovered via SERP if fewer than 2).',\n '5. Optional: a customer reviews URL (G2 / Trustpilot / Reddit) and known customer pain points.',\n '',\n 'ASYNC CONTRACT (important):',\n '- thorbit_deposition_start returns quickly with {runPublicId, poll}. Do NOT block — follow result.poll.',\n '- Poll thorbit_deposition_get until status is terminal (complete/failed). It returns a LEAN status (phase, progress, binding state, strategy) with a nextAction.',\n '- When status is complete, call thorbit_deposition_get_playbook to read the finished markdown playbook.',\n '- Use thorbit_deposition_list to find past runs (by company/status) and their runPublicId.',\n].join('\\n')\n\nexport function buildThorbitDepositionMcpServer(client: ThorbitDepositionApiClient): McpServer {\n const server = new McpServer({ name: 'thorbit-deposition-mcp', version: VERSION }, { instructions: SERVER_INSTRUCTIONS })\n\n function registerTool<T extends ThorbitDepositionMcpToolName>(\n toolName: T,\n config: ThorbitDepositionToolConfig<ZodRawShape>,\n ): void {\n server.registerTool(toolName, config, async (input) => {\n const envelope = await client.callTool(toolName, input)\n return formatThorbitDepositionMcpToolResult(toolName, envelope)\n })\n }\n\n registerTool('thorbit_deposition_start', {\n title: 'Start Depositioning Run',\n description: 'Start a durable Depositioning strategy run for a challenger product in a category. Researches competitors and customers, finds the binding vulnerability, classifies movers, designs a category class, builds a displacement mechanism, and writes a playbook. Returns a runPublicId plus a thorbit_deposition_get poll target. Metered.',\n inputSchema: ThorbitDepositionStartInputSchema,\n annotations: writeAnnotations('Start Depositioning Run'),\n })\n\n registerTool('thorbit_deposition_get', {\n title: 'Read Depositioning Run Status',\n description: 'Read a Depositioning run: status, current phase, progress, selected binding state and strategy, primary vulnerability, category class, displacement mechanism, and whether the playbook is ready. Returns a nextAction. Poll until status is complete or failed.',\n inputSchema: ThorbitDepositionGetInputSchema,\n annotations: readOnlyAnnotations('Read Depositioning Run Status'),\n })\n\n registerTool('thorbit_deposition_get_playbook', {\n title: 'Read Depositioning Playbook',\n description: 'Return the finished deposition-playbook markdown for a completed run (executive brief, the four elements, activation guide). Returns not_found until the run completes.',\n inputSchema: ThorbitDepositionGetPlaybookInputSchema,\n annotations: readOnlyAnnotations('Read Depositioning Playbook'),\n })\n\n registerTool('thorbit_deposition_list', {\n title: 'List Depositioning Runs',\n description: 'List past Depositioning runs (most recent first) with runPublicId, company, category, status, binding state, and strategy. Filter by project, company-name search, or status. Use to find a prior run to read.',\n inputSchema: ThorbitDepositionListInputSchema,\n annotations: readOnlyAnnotations('List Depositioning Runs'),\n })\n\n return server\n}\n","import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js'\nimport type { ThorbitDepositionMcpEnvelope } from './deposition-api-client.js'\nimport type { ThorbitDepositionMcpToolName } from './deposition-mcp-tool-names.js'\n\nexport function formatThorbitDepositionMcpToolResult(\n toolName: ThorbitDepositionMcpToolName,\n envelope: ThorbitDepositionMcpEnvelope,\n): CallToolResult {\n const text = JSON.stringify({ toolName, ...envelope }, null, 2)\n return {\n content: [{ type: 'text', text }],\n isError: !envelope.ok,\n }\n}\n","import { z } from 'zod'\n\nexport const ThorbitDepositionStartInputSchema = {\n companyName: z.string().min(1).max(255).describe('The challenger company or product being depositioned.'),\n productUrl: z.string().url().max(2048).describe('URL of the challenger product homepage.'),\n categoryName: z.string().min(1).max(255).describe('The product category, e.g. \"B2B sales analytics\".'),\n competitorUrls: z.array(z.string().url()).max(5).default([]).describe('0-5 competitor URLs. Auto-discovered via SERP if fewer than 2 are provided.'),\n reviewsUrl: z.string().url().max(2048).optional().describe('Optional customer reviews URL (G2, Trustpilot, Reddit thread).'),\n knownPains: z.array(z.string().min(1)).max(50).optional().describe('Optional known customer pain points to seed the analysis.'),\n projectPublicId: z.string().min(1).optional().describe('Optional Thorbit project to associate the run with.'),\n}\n\nexport const ThorbitDepositionGetInputSchema = {\n runPublicId: z.string().min(1).describe('Deposition run public ID returned by thorbit_deposition_start.'),\n includePhaseData: z.boolean().default(false).describe('Include raw per-phase intermediate data in addition to the lean status.'),\n}\n\nexport const ThorbitDepositionGetPlaybookInputSchema = {\n runPublicId: z.string().min(1).describe('Deposition run public ID. Returns the markdown playbook once the run is complete.'),\n}\n\nexport const ThorbitDepositionListInputSchema = {\n projectPublicId: z.string().min(1).optional().describe('Optional project filter; omit for all org runs.'),\n search: z.string().max(200).optional().describe('Optional company-name substring filter.'),\n status: z.enum(['queued', 'running', 'complete', 'failed']).optional().describe('Optional run status filter.'),\n limit: z.number().int().min(1).max(100).default(25).describe('Maximum runs to return.'),\n offset: z.number().int().min(0).default(0).describe('Pagination offset.'),\n}\n\nexport const ThorbitDepositionMcpToolInputSchemas = {\n thorbit_deposition_start: ThorbitDepositionStartInputSchema,\n thorbit_deposition_get: ThorbitDepositionGetInputSchema,\n thorbit_deposition_get_playbook: ThorbitDepositionGetPlaybookInputSchema,\n thorbit_deposition_list: ThorbitDepositionListInputSchema,\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// bin/thorbit-deposition-mcp.ts
|
|
4
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
5
|
+
|
|
6
|
+
// src/deposition-api-client.ts
|
|
7
|
+
var ThorbitDepositionApiClient = class {
|
|
8
|
+
baseUrl;
|
|
9
|
+
apiKey;
|
|
10
|
+
constructor(options) {
|
|
11
|
+
this.baseUrl = options.baseUrl.replace(/\/$/, "");
|
|
12
|
+
this.apiKey = options.apiKey;
|
|
13
|
+
}
|
|
14
|
+
async callTool(toolName, input) {
|
|
15
|
+
const response = await fetch(`${this.baseUrl}/api/v1/mcp/deposition/${toolName}`, {
|
|
16
|
+
method: "POST",
|
|
17
|
+
headers: {
|
|
18
|
+
"x-thorbit-api-key": this.apiKey,
|
|
19
|
+
"Content-Type": "application/json"
|
|
20
|
+
},
|
|
21
|
+
body: JSON.stringify(input ?? {})
|
|
22
|
+
});
|
|
23
|
+
const body = await response.json().catch(() => null);
|
|
24
|
+
if (body && typeof body === "object" && "ok" in body) return body;
|
|
25
|
+
return {
|
|
26
|
+
ok: false,
|
|
27
|
+
requestId: "unavailable",
|
|
28
|
+
error: {
|
|
29
|
+
code: response.ok ? "invalid_response" : `http_${response.status}`,
|
|
30
|
+
message: response.ok ? "Thorbit returned an invalid MCP response" : `Thorbit API request failed with HTTP ${response.status}`
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
// src/deposition-mcp-env.ts
|
|
37
|
+
import { readFileSync } from "fs";
|
|
38
|
+
import { homedir } from "os";
|
|
39
|
+
import { join } from "path";
|
|
40
|
+
function readApiKeyFile() {
|
|
41
|
+
const explicitPath = process.env.THORBIT_DEPOSITION_MCP_KEY_PATH?.trim();
|
|
42
|
+
const paths = [explicitPath, join(homedir(), ".thorbit-deposition-mcp-key")].filter(Boolean);
|
|
43
|
+
for (const path of paths) {
|
|
44
|
+
try {
|
|
45
|
+
const value = readFileSync(path, "utf8").trim();
|
|
46
|
+
if (value) return value;
|
|
47
|
+
} catch {
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return void 0;
|
|
52
|
+
}
|
|
53
|
+
function resolveThorbitDepositionMcpEnv() {
|
|
54
|
+
const apiKey = (process.env.THORBIT_API_KEY || process.env.THORBIT_MCP_API_KEY || process.env.THORBIT_DEPOSITION_MCP_API_KEY || readApiKeyFile())?.trim();
|
|
55
|
+
if (!apiKey) {
|
|
56
|
+
throw new Error("THORBIT_API_KEY, THORBIT_MCP_API_KEY, or ~/.thorbit-deposition-mcp-key is required");
|
|
57
|
+
}
|
|
58
|
+
return {
|
|
59
|
+
apiKey,
|
|
60
|
+
baseUrl: (process.env.THORBIT_BASE_URL || process.env.THORBIT_DEPOSITION_MCP_BASE_URL || "https://thorbit.ai").trim()
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// src/deposition-mcp-server.ts
|
|
65
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
66
|
+
|
|
67
|
+
// src/deposition-mcp-response-formatters.ts
|
|
68
|
+
function formatThorbitDepositionMcpToolResult(toolName, envelope) {
|
|
69
|
+
const text = JSON.stringify({ toolName, ...envelope }, null, 2);
|
|
70
|
+
return {
|
|
71
|
+
content: [{ type: "text", text }],
|
|
72
|
+
isError: !envelope.ok
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// src/deposition-mcp-tool-schemas.ts
|
|
77
|
+
import { z } from "zod";
|
|
78
|
+
var ThorbitDepositionStartInputSchema = {
|
|
79
|
+
companyName: z.string().min(1).max(255).describe("The challenger company or product being depositioned."),
|
|
80
|
+
productUrl: z.string().url().max(2048).describe("URL of the challenger product homepage."),
|
|
81
|
+
categoryName: z.string().min(1).max(255).describe('The product category, e.g. "B2B sales analytics".'),
|
|
82
|
+
competitorUrls: z.array(z.string().url()).max(5).default([]).describe("0-5 competitor URLs. Auto-discovered via SERP if fewer than 2 are provided."),
|
|
83
|
+
reviewsUrl: z.string().url().max(2048).optional().describe("Optional customer reviews URL (G2, Trustpilot, Reddit thread)."),
|
|
84
|
+
knownPains: z.array(z.string().min(1)).max(50).optional().describe("Optional known customer pain points to seed the analysis."),
|
|
85
|
+
projectPublicId: z.string().min(1).optional().describe("Optional Thorbit project to associate the run with.")
|
|
86
|
+
};
|
|
87
|
+
var ThorbitDepositionGetInputSchema = {
|
|
88
|
+
runPublicId: z.string().min(1).describe("Deposition run public ID returned by thorbit_deposition_start."),
|
|
89
|
+
includePhaseData: z.boolean().default(false).describe("Include raw per-phase intermediate data in addition to the lean status.")
|
|
90
|
+
};
|
|
91
|
+
var ThorbitDepositionGetPlaybookInputSchema = {
|
|
92
|
+
runPublicId: z.string().min(1).describe("Deposition run public ID. Returns the markdown playbook once the run is complete.")
|
|
93
|
+
};
|
|
94
|
+
var ThorbitDepositionListInputSchema = {
|
|
95
|
+
projectPublicId: z.string().min(1).optional().describe("Optional project filter; omit for all org runs."),
|
|
96
|
+
search: z.string().max(200).optional().describe("Optional company-name substring filter."),
|
|
97
|
+
status: z.enum(["queued", "running", "complete", "failed"]).optional().describe("Optional run status filter."),
|
|
98
|
+
limit: z.number().int().min(1).max(100).default(25).describe("Maximum runs to return."),
|
|
99
|
+
offset: z.number().int().min(0).default(0).describe("Pagination offset.")
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
// src/deposition-mcp-server.ts
|
|
103
|
+
var VERSION = "0.1.0";
|
|
104
|
+
function readOnlyAnnotations(title) {
|
|
105
|
+
return { title, readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
|
|
106
|
+
}
|
|
107
|
+
function writeAnnotations(title) {
|
|
108
|
+
return { title, readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true };
|
|
109
|
+
}
|
|
110
|
+
var SERVER_INSTRUCTIONS = [
|
|
111
|
+
"Thorbit Depositioning MCP. Runs the durable Depositioning strategy pipeline on hosted Thorbit (this server is a thin client). It researches competitors + customers, finds the binding vulnerability, classifies mover populations, designs a category class, builds a displacement mechanism, and writes a strategy playbook. All write/analysis tools are metered against your API key.",
|
|
112
|
+
"",
|
|
113
|
+
"INTAKE (ask the user these BEFORE thorbit_deposition_start, then run):",
|
|
114
|
+
"1. Company / product name being depositioned.",
|
|
115
|
+
"2. Product URL (the challenger homepage).",
|
|
116
|
+
'3. Category name (e.g. "B2B sales analytics").',
|
|
117
|
+
"4. Optional: 0-5 competitor URLs (auto-discovered via SERP if fewer than 2).",
|
|
118
|
+
"5. Optional: a customer reviews URL (G2 / Trustpilot / Reddit) and known customer pain points.",
|
|
119
|
+
"",
|
|
120
|
+
"ASYNC CONTRACT (important):",
|
|
121
|
+
"- thorbit_deposition_start returns quickly with {runPublicId, poll}. Do NOT block \u2014 follow result.poll.",
|
|
122
|
+
"- Poll thorbit_deposition_get until status is terminal (complete/failed). It returns a LEAN status (phase, progress, binding state, strategy) with a nextAction.",
|
|
123
|
+
"- When status is complete, call thorbit_deposition_get_playbook to read the finished markdown playbook.",
|
|
124
|
+
"- Use thorbit_deposition_list to find past runs (by company/status) and their runPublicId."
|
|
125
|
+
].join("\n");
|
|
126
|
+
function buildThorbitDepositionMcpServer(client) {
|
|
127
|
+
const server = new McpServer({ name: "thorbit-deposition-mcp", version: VERSION }, { instructions: SERVER_INSTRUCTIONS });
|
|
128
|
+
function registerTool(toolName, config) {
|
|
129
|
+
server.registerTool(toolName, config, async (input) => {
|
|
130
|
+
const envelope = await client.callTool(toolName, input);
|
|
131
|
+
return formatThorbitDepositionMcpToolResult(toolName, envelope);
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
registerTool("thorbit_deposition_start", {
|
|
135
|
+
title: "Start Depositioning Run",
|
|
136
|
+
description: "Start a durable Depositioning strategy run for a challenger product in a category. Researches competitors and customers, finds the binding vulnerability, classifies movers, designs a category class, builds a displacement mechanism, and writes a playbook. Returns a runPublicId plus a thorbit_deposition_get poll target. Metered.",
|
|
137
|
+
inputSchema: ThorbitDepositionStartInputSchema,
|
|
138
|
+
annotations: writeAnnotations("Start Depositioning Run")
|
|
139
|
+
});
|
|
140
|
+
registerTool("thorbit_deposition_get", {
|
|
141
|
+
title: "Read Depositioning Run Status",
|
|
142
|
+
description: "Read a Depositioning run: status, current phase, progress, selected binding state and strategy, primary vulnerability, category class, displacement mechanism, and whether the playbook is ready. Returns a nextAction. Poll until status is complete or failed.",
|
|
143
|
+
inputSchema: ThorbitDepositionGetInputSchema,
|
|
144
|
+
annotations: readOnlyAnnotations("Read Depositioning Run Status")
|
|
145
|
+
});
|
|
146
|
+
registerTool("thorbit_deposition_get_playbook", {
|
|
147
|
+
title: "Read Depositioning Playbook",
|
|
148
|
+
description: "Return the finished deposition-playbook markdown for a completed run (executive brief, the four elements, activation guide). Returns not_found until the run completes.",
|
|
149
|
+
inputSchema: ThorbitDepositionGetPlaybookInputSchema,
|
|
150
|
+
annotations: readOnlyAnnotations("Read Depositioning Playbook")
|
|
151
|
+
});
|
|
152
|
+
registerTool("thorbit_deposition_list", {
|
|
153
|
+
title: "List Depositioning Runs",
|
|
154
|
+
description: "List past Depositioning runs (most recent first) with runPublicId, company, category, status, binding state, and strategy. Filter by project, company-name search, or status. Use to find a prior run to read.",
|
|
155
|
+
inputSchema: ThorbitDepositionListInputSchema,
|
|
156
|
+
annotations: readOnlyAnnotations("List Depositioning Runs")
|
|
157
|
+
});
|
|
158
|
+
return server;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// bin/thorbit-deposition-mcp.ts
|
|
162
|
+
async function main() {
|
|
163
|
+
const env = resolveThorbitDepositionMcpEnv();
|
|
164
|
+
const client = new ThorbitDepositionApiClient(env);
|
|
165
|
+
const server = buildThorbitDepositionMcpServer(client);
|
|
166
|
+
await server.connect(new StdioServerTransport());
|
|
167
|
+
}
|
|
168
|
+
main().catch((error) => {
|
|
169
|
+
process.stderr.write(`${error instanceof Error ? error.message : String(error)}
|
|
170
|
+
`);
|
|
171
|
+
process.exit(1);
|
|
172
|
+
});
|
|
173
|
+
//# sourceMappingURL=thorbit-deposition-mcp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../bin/thorbit-deposition-mcp.ts","../../src/deposition-api-client.ts","../../src/deposition-mcp-env.ts","../../src/deposition-mcp-server.ts","../../src/deposition-mcp-response-formatters.ts","../../src/deposition-mcp-tool-schemas.ts"],"sourcesContent":["import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'\nimport { ThorbitDepositionApiClient } from '../src/deposition-api-client.js'\nimport { resolveThorbitDepositionMcpEnv } from '../src/deposition-mcp-env.js'\nimport { buildThorbitDepositionMcpServer } from '../src/deposition-mcp-server.js'\n\nasync function main() {\n const env = resolveThorbitDepositionMcpEnv()\n const client = new ThorbitDepositionApiClient(env)\n const server = buildThorbitDepositionMcpServer(client)\n await server.connect(new StdioServerTransport())\n}\n\nmain().catch(error => {\n process.stderr.write(`${error instanceof Error ? error.message : String(error)}\\n`)\n process.exit(1)\n})\n","import type { ThorbitDepositionMcpToolName } from './deposition-mcp-tool-names.js'\n\nexport type ThorbitDepositionMcpEnvelope =\n | {\n ok: true\n result: unknown\n warnings?: string[]\n requestId: string\n }\n | {\n ok: false\n error: {\n code: string\n message: string\n details?: unknown\n }\n requestId: string\n }\n\nexport class ThorbitDepositionApiClient {\n private readonly baseUrl: string\n private readonly apiKey: string\n\n constructor(options: { baseUrl: string; apiKey: string }) {\n this.baseUrl = options.baseUrl.replace(/\\/$/, '')\n this.apiKey = options.apiKey\n }\n\n async callTool(toolName: ThorbitDepositionMcpToolName, input: unknown): Promise<ThorbitDepositionMcpEnvelope> {\n const response = await fetch(`${this.baseUrl}/api/v1/mcp/deposition/${toolName}`, {\n method: 'POST',\n headers: {\n 'x-thorbit-api-key': this.apiKey,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(input ?? {}),\n })\n\n const body = await response.json().catch(() => null) as ThorbitDepositionMcpEnvelope | null\n if (body && typeof body === 'object' && 'ok' in body) return body\n\n return {\n ok: false,\n requestId: 'unavailable',\n error: {\n code: response.ok ? 'invalid_response' : `http_${response.status}`,\n message: response.ok ? 'Thorbit returned an invalid MCP response' : `Thorbit API request failed with HTTP ${response.status}`,\n },\n }\n }\n}\n","import { readFileSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { join } from 'node:path'\n\nexport type ThorbitDepositionMcpEnv = {\n apiKey: string\n baseUrl: string\n}\n\nfunction readApiKeyFile(): string | undefined {\n const explicitPath = process.env.THORBIT_DEPOSITION_MCP_KEY_PATH?.trim()\n const paths = [explicitPath, join(homedir(), '.thorbit-deposition-mcp-key')].filter(Boolean) as string[]\n for (const path of paths) {\n try {\n const value = readFileSync(path, 'utf8').trim()\n if (value) return value\n } catch {\n continue\n }\n }\n return undefined\n}\n\nexport function resolveThorbitDepositionMcpEnv(): ThorbitDepositionMcpEnv {\n const apiKey = (\n process.env.THORBIT_API_KEY ||\n process.env.THORBIT_MCP_API_KEY ||\n process.env.THORBIT_DEPOSITION_MCP_API_KEY ||\n readApiKeyFile()\n )?.trim()\n\n if (!apiKey) {\n throw new Error('THORBIT_API_KEY, THORBIT_MCP_API_KEY, or ~/.thorbit-deposition-mcp-key is required')\n }\n\n return {\n apiKey,\n baseUrl: (process.env.THORBIT_BASE_URL || process.env.THORBIT_DEPOSITION_MCP_BASE_URL || 'https://thorbit.ai').trim(),\n }\n}\n","import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport type { ToolAnnotations } from '@modelcontextprotocol/sdk/types.js'\nimport type { ZodRawShape } from 'zod'\nimport type { ThorbitDepositionApiClient } from './deposition-api-client.js'\nimport { formatThorbitDepositionMcpToolResult } from './deposition-mcp-response-formatters.js'\nimport {\n ThorbitDepositionStartInputSchema,\n ThorbitDepositionGetInputSchema,\n ThorbitDepositionGetPlaybookInputSchema,\n ThorbitDepositionListInputSchema,\n} from './deposition-mcp-tool-schemas.js'\nimport type { ThorbitDepositionMcpToolName } from './deposition-mcp-tool-names.js'\n\nconst VERSION = '0.1.0'\n\ntype ThorbitDepositionToolConfig<InputArgs extends ZodRawShape> = {\n title: string\n description: string\n inputSchema: InputArgs\n annotations: ToolAnnotations\n}\n\nfunction readOnlyAnnotations(title: string) {\n return { title, readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false }\n}\n\nfunction writeAnnotations(title: string) {\n return { title, readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true }\n}\n\nexport const SERVER_INSTRUCTIONS = [\n 'Thorbit Depositioning MCP. Runs the durable Depositioning strategy pipeline on hosted Thorbit (this server is a thin client). It researches competitors + customers, finds the binding vulnerability, classifies mover populations, designs a category class, builds a displacement mechanism, and writes a strategy playbook. All write/analysis tools are metered against your API key.',\n '',\n 'INTAKE (ask the user these BEFORE thorbit_deposition_start, then run):',\n '1. Company / product name being depositioned.',\n '2. Product URL (the challenger homepage).',\n '3. Category name (e.g. \"B2B sales analytics\").',\n '4. Optional: 0-5 competitor URLs (auto-discovered via SERP if fewer than 2).',\n '5. Optional: a customer reviews URL (G2 / Trustpilot / Reddit) and known customer pain points.',\n '',\n 'ASYNC CONTRACT (important):',\n '- thorbit_deposition_start returns quickly with {runPublicId, poll}. Do NOT block — follow result.poll.',\n '- Poll thorbit_deposition_get until status is terminal (complete/failed). It returns a LEAN status (phase, progress, binding state, strategy) with a nextAction.',\n '- When status is complete, call thorbit_deposition_get_playbook to read the finished markdown playbook.',\n '- Use thorbit_deposition_list to find past runs (by company/status) and their runPublicId.',\n].join('\\n')\n\nexport function buildThorbitDepositionMcpServer(client: ThorbitDepositionApiClient): McpServer {\n const server = new McpServer({ name: 'thorbit-deposition-mcp', version: VERSION }, { instructions: SERVER_INSTRUCTIONS })\n\n function registerTool<T extends ThorbitDepositionMcpToolName>(\n toolName: T,\n config: ThorbitDepositionToolConfig<ZodRawShape>,\n ): void {\n server.registerTool(toolName, config, async (input) => {\n const envelope = await client.callTool(toolName, input)\n return formatThorbitDepositionMcpToolResult(toolName, envelope)\n })\n }\n\n registerTool('thorbit_deposition_start', {\n title: 'Start Depositioning Run',\n description: 'Start a durable Depositioning strategy run for a challenger product in a category. Researches competitors and customers, finds the binding vulnerability, classifies movers, designs a category class, builds a displacement mechanism, and writes a playbook. Returns a runPublicId plus a thorbit_deposition_get poll target. Metered.',\n inputSchema: ThorbitDepositionStartInputSchema,\n annotations: writeAnnotations('Start Depositioning Run'),\n })\n\n registerTool('thorbit_deposition_get', {\n title: 'Read Depositioning Run Status',\n description: 'Read a Depositioning run: status, current phase, progress, selected binding state and strategy, primary vulnerability, category class, displacement mechanism, and whether the playbook is ready. Returns a nextAction. Poll until status is complete or failed.',\n inputSchema: ThorbitDepositionGetInputSchema,\n annotations: readOnlyAnnotations('Read Depositioning Run Status'),\n })\n\n registerTool('thorbit_deposition_get_playbook', {\n title: 'Read Depositioning Playbook',\n description: 'Return the finished deposition-playbook markdown for a completed run (executive brief, the four elements, activation guide). Returns not_found until the run completes.',\n inputSchema: ThorbitDepositionGetPlaybookInputSchema,\n annotations: readOnlyAnnotations('Read Depositioning Playbook'),\n })\n\n registerTool('thorbit_deposition_list', {\n title: 'List Depositioning Runs',\n description: 'List past Depositioning runs (most recent first) with runPublicId, company, category, status, binding state, and strategy. Filter by project, company-name search, or status. Use to find a prior run to read.',\n inputSchema: ThorbitDepositionListInputSchema,\n annotations: readOnlyAnnotations('List Depositioning Runs'),\n })\n\n return server\n}\n","import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js'\nimport type { ThorbitDepositionMcpEnvelope } from './deposition-api-client.js'\nimport type { ThorbitDepositionMcpToolName } from './deposition-mcp-tool-names.js'\n\nexport function formatThorbitDepositionMcpToolResult(\n toolName: ThorbitDepositionMcpToolName,\n envelope: ThorbitDepositionMcpEnvelope,\n): CallToolResult {\n const text = JSON.stringify({ toolName, ...envelope }, null, 2)\n return {\n content: [{ type: 'text', text }],\n isError: !envelope.ok,\n }\n}\n","import { z } from 'zod'\n\nexport const ThorbitDepositionStartInputSchema = {\n companyName: z.string().min(1).max(255).describe('The challenger company or product being depositioned.'),\n productUrl: z.string().url().max(2048).describe('URL of the challenger product homepage.'),\n categoryName: z.string().min(1).max(255).describe('The product category, e.g. \"B2B sales analytics\".'),\n competitorUrls: z.array(z.string().url()).max(5).default([]).describe('0-5 competitor URLs. Auto-discovered via SERP if fewer than 2 are provided.'),\n reviewsUrl: z.string().url().max(2048).optional().describe('Optional customer reviews URL (G2, Trustpilot, Reddit thread).'),\n knownPains: z.array(z.string().min(1)).max(50).optional().describe('Optional known customer pain points to seed the analysis.'),\n projectPublicId: z.string().min(1).optional().describe('Optional Thorbit project to associate the run with.'),\n}\n\nexport const ThorbitDepositionGetInputSchema = {\n runPublicId: z.string().min(1).describe('Deposition run public ID returned by thorbit_deposition_start.'),\n includePhaseData: z.boolean().default(false).describe('Include raw per-phase intermediate data in addition to the lean status.'),\n}\n\nexport const ThorbitDepositionGetPlaybookInputSchema = {\n runPublicId: z.string().min(1).describe('Deposition run public ID. Returns the markdown playbook once the run is complete.'),\n}\n\nexport const ThorbitDepositionListInputSchema = {\n projectPublicId: z.string().min(1).optional().describe('Optional project filter; omit for all org runs.'),\n search: z.string().max(200).optional().describe('Optional company-name substring filter.'),\n status: z.enum(['queued', 'running', 'complete', 'failed']).optional().describe('Optional run status filter.'),\n limit: z.number().int().min(1).max(100).default(25).describe('Maximum runs to return.'),\n offset: z.number().int().min(0).default(0).describe('Pagination offset.'),\n}\n\nexport const ThorbitDepositionMcpToolInputSchemas = {\n thorbit_deposition_start: ThorbitDepositionStartInputSchema,\n thorbit_deposition_get: ThorbitDepositionGetInputSchema,\n thorbit_deposition_get_playbook: ThorbitDepositionGetPlaybookInputSchema,\n thorbit_deposition_list: ThorbitDepositionListInputSchema,\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
20
|
+
|
|
21
|
+
// src/index.ts
|
|
22
|
+
var src_exports = {};
|
|
23
|
+
__export(src_exports, {
|
|
24
|
+
SERVER_INSTRUCTIONS: () => SERVER_INSTRUCTIONS,
|
|
25
|
+
ThorbitDepositionApiClient: () => ThorbitDepositionApiClient,
|
|
26
|
+
ThorbitDepositionMcpToolNames: () => ThorbitDepositionMcpToolNames,
|
|
27
|
+
buildThorbitDepositionMcpServer: () => buildThorbitDepositionMcpServer,
|
|
28
|
+
resolveThorbitDepositionMcpEnv: () => resolveThorbitDepositionMcpEnv
|
|
29
|
+
});
|
|
30
|
+
module.exports = __toCommonJS(src_exports);
|
|
31
|
+
|
|
32
|
+
// src/deposition-api-client.ts
|
|
33
|
+
var ThorbitDepositionApiClient = class {
|
|
34
|
+
baseUrl;
|
|
35
|
+
apiKey;
|
|
36
|
+
constructor(options) {
|
|
37
|
+
this.baseUrl = options.baseUrl.replace(/\/$/, "");
|
|
38
|
+
this.apiKey = options.apiKey;
|
|
39
|
+
}
|
|
40
|
+
async callTool(toolName, input) {
|
|
41
|
+
const response = await fetch(`${this.baseUrl}/api/v1/mcp/deposition/${toolName}`, {
|
|
42
|
+
method: "POST",
|
|
43
|
+
headers: {
|
|
44
|
+
"x-thorbit-api-key": this.apiKey,
|
|
45
|
+
"Content-Type": "application/json"
|
|
46
|
+
},
|
|
47
|
+
body: JSON.stringify(input ?? {})
|
|
48
|
+
});
|
|
49
|
+
const body = await response.json().catch(() => null);
|
|
50
|
+
if (body && typeof body === "object" && "ok" in body) return body;
|
|
51
|
+
return {
|
|
52
|
+
ok: false,
|
|
53
|
+
requestId: "unavailable",
|
|
54
|
+
error: {
|
|
55
|
+
code: response.ok ? "invalid_response" : `http_${response.status}`,
|
|
56
|
+
message: response.ok ? "Thorbit returned an invalid MCP response" : `Thorbit API request failed with HTTP ${response.status}`
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
// src/deposition-mcp-server.ts
|
|
63
|
+
var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
64
|
+
|
|
65
|
+
// src/deposition-mcp-response-formatters.ts
|
|
66
|
+
function formatThorbitDepositionMcpToolResult(toolName, envelope) {
|
|
67
|
+
const text = JSON.stringify({ toolName, ...envelope }, null, 2);
|
|
68
|
+
return {
|
|
69
|
+
content: [{ type: "text", text }],
|
|
70
|
+
isError: !envelope.ok
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// src/deposition-mcp-tool-schemas.ts
|
|
75
|
+
var import_zod = require("zod");
|
|
76
|
+
var ThorbitDepositionStartInputSchema = {
|
|
77
|
+
companyName: import_zod.z.string().min(1).max(255).describe("The challenger company or product being depositioned."),
|
|
78
|
+
productUrl: import_zod.z.string().url().max(2048).describe("URL of the challenger product homepage."),
|
|
79
|
+
categoryName: import_zod.z.string().min(1).max(255).describe('The product category, e.g. "B2B sales analytics".'),
|
|
80
|
+
competitorUrls: import_zod.z.array(import_zod.z.string().url()).max(5).default([]).describe("0-5 competitor URLs. Auto-discovered via SERP if fewer than 2 are provided."),
|
|
81
|
+
reviewsUrl: import_zod.z.string().url().max(2048).optional().describe("Optional customer reviews URL (G2, Trustpilot, Reddit thread)."),
|
|
82
|
+
knownPains: import_zod.z.array(import_zod.z.string().min(1)).max(50).optional().describe("Optional known customer pain points to seed the analysis."),
|
|
83
|
+
projectPublicId: import_zod.z.string().min(1).optional().describe("Optional Thorbit project to associate the run with.")
|
|
84
|
+
};
|
|
85
|
+
var ThorbitDepositionGetInputSchema = {
|
|
86
|
+
runPublicId: import_zod.z.string().min(1).describe("Deposition run public ID returned by thorbit_deposition_start."),
|
|
87
|
+
includePhaseData: import_zod.z.boolean().default(false).describe("Include raw per-phase intermediate data in addition to the lean status.")
|
|
88
|
+
};
|
|
89
|
+
var ThorbitDepositionGetPlaybookInputSchema = {
|
|
90
|
+
runPublicId: import_zod.z.string().min(1).describe("Deposition run public ID. Returns the markdown playbook once the run is complete.")
|
|
91
|
+
};
|
|
92
|
+
var ThorbitDepositionListInputSchema = {
|
|
93
|
+
projectPublicId: import_zod.z.string().min(1).optional().describe("Optional project filter; omit for all org runs."),
|
|
94
|
+
search: import_zod.z.string().max(200).optional().describe("Optional company-name substring filter."),
|
|
95
|
+
status: import_zod.z.enum(["queued", "running", "complete", "failed"]).optional().describe("Optional run status filter."),
|
|
96
|
+
limit: import_zod.z.number().int().min(1).max(100).default(25).describe("Maximum runs to return."),
|
|
97
|
+
offset: import_zod.z.number().int().min(0).default(0).describe("Pagination offset.")
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
// src/deposition-mcp-server.ts
|
|
101
|
+
var VERSION = "0.1.0";
|
|
102
|
+
function readOnlyAnnotations(title) {
|
|
103
|
+
return { title, readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
|
|
104
|
+
}
|
|
105
|
+
function writeAnnotations(title) {
|
|
106
|
+
return { title, readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true };
|
|
107
|
+
}
|
|
108
|
+
var SERVER_INSTRUCTIONS = [
|
|
109
|
+
"Thorbit Depositioning MCP. Runs the durable Depositioning strategy pipeline on hosted Thorbit (this server is a thin client). It researches competitors + customers, finds the binding vulnerability, classifies mover populations, designs a category class, builds a displacement mechanism, and writes a strategy playbook. All write/analysis tools are metered against your API key.",
|
|
110
|
+
"",
|
|
111
|
+
"INTAKE (ask the user these BEFORE thorbit_deposition_start, then run):",
|
|
112
|
+
"1. Company / product name being depositioned.",
|
|
113
|
+
"2. Product URL (the challenger homepage).",
|
|
114
|
+
'3. Category name (e.g. "B2B sales analytics").',
|
|
115
|
+
"4. Optional: 0-5 competitor URLs (auto-discovered via SERP if fewer than 2).",
|
|
116
|
+
"5. Optional: a customer reviews URL (G2 / Trustpilot / Reddit) and known customer pain points.",
|
|
117
|
+
"",
|
|
118
|
+
"ASYNC CONTRACT (important):",
|
|
119
|
+
"- thorbit_deposition_start returns quickly with {runPublicId, poll}. Do NOT block \u2014 follow result.poll.",
|
|
120
|
+
"- Poll thorbit_deposition_get until status is terminal (complete/failed). It returns a LEAN status (phase, progress, binding state, strategy) with a nextAction.",
|
|
121
|
+
"- When status is complete, call thorbit_deposition_get_playbook to read the finished markdown playbook.",
|
|
122
|
+
"- Use thorbit_deposition_list to find past runs (by company/status) and their runPublicId."
|
|
123
|
+
].join("\n");
|
|
124
|
+
function buildThorbitDepositionMcpServer(client) {
|
|
125
|
+
const server = new import_mcp.McpServer({ name: "thorbit-deposition-mcp", version: VERSION }, { instructions: SERVER_INSTRUCTIONS });
|
|
126
|
+
function registerTool(toolName, config) {
|
|
127
|
+
server.registerTool(toolName, config, async (input) => {
|
|
128
|
+
const envelope = await client.callTool(toolName, input);
|
|
129
|
+
return formatThorbitDepositionMcpToolResult(toolName, envelope);
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
registerTool("thorbit_deposition_start", {
|
|
133
|
+
title: "Start Depositioning Run",
|
|
134
|
+
description: "Start a durable Depositioning strategy run for a challenger product in a category. Researches competitors and customers, finds the binding vulnerability, classifies movers, designs a category class, builds a displacement mechanism, and writes a playbook. Returns a runPublicId plus a thorbit_deposition_get poll target. Metered.",
|
|
135
|
+
inputSchema: ThorbitDepositionStartInputSchema,
|
|
136
|
+
annotations: writeAnnotations("Start Depositioning Run")
|
|
137
|
+
});
|
|
138
|
+
registerTool("thorbit_deposition_get", {
|
|
139
|
+
title: "Read Depositioning Run Status",
|
|
140
|
+
description: "Read a Depositioning run: status, current phase, progress, selected binding state and strategy, primary vulnerability, category class, displacement mechanism, and whether the playbook is ready. Returns a nextAction. Poll until status is complete or failed.",
|
|
141
|
+
inputSchema: ThorbitDepositionGetInputSchema,
|
|
142
|
+
annotations: readOnlyAnnotations("Read Depositioning Run Status")
|
|
143
|
+
});
|
|
144
|
+
registerTool("thorbit_deposition_get_playbook", {
|
|
145
|
+
title: "Read Depositioning Playbook",
|
|
146
|
+
description: "Return the finished deposition-playbook markdown for a completed run (executive brief, the four elements, activation guide). Returns not_found until the run completes.",
|
|
147
|
+
inputSchema: ThorbitDepositionGetPlaybookInputSchema,
|
|
148
|
+
annotations: readOnlyAnnotations("Read Depositioning Playbook")
|
|
149
|
+
});
|
|
150
|
+
registerTool("thorbit_deposition_list", {
|
|
151
|
+
title: "List Depositioning Runs",
|
|
152
|
+
description: "List past Depositioning runs (most recent first) with runPublicId, company, category, status, binding state, and strategy. Filter by project, company-name search, or status. Use to find a prior run to read.",
|
|
153
|
+
inputSchema: ThorbitDepositionListInputSchema,
|
|
154
|
+
annotations: readOnlyAnnotations("List Depositioning Runs")
|
|
155
|
+
});
|
|
156
|
+
return server;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// src/deposition-mcp-env.ts
|
|
160
|
+
var import_node_fs = require("fs");
|
|
161
|
+
var import_node_os = require("os");
|
|
162
|
+
var import_node_path = require("path");
|
|
163
|
+
function readApiKeyFile() {
|
|
164
|
+
const explicitPath = process.env.THORBIT_DEPOSITION_MCP_KEY_PATH?.trim();
|
|
165
|
+
const paths = [explicitPath, (0, import_node_path.join)((0, import_node_os.homedir)(), ".thorbit-deposition-mcp-key")].filter(Boolean);
|
|
166
|
+
for (const path of paths) {
|
|
167
|
+
try {
|
|
168
|
+
const value = (0, import_node_fs.readFileSync)(path, "utf8").trim();
|
|
169
|
+
if (value) return value;
|
|
170
|
+
} catch {
|
|
171
|
+
continue;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return void 0;
|
|
175
|
+
}
|
|
176
|
+
function resolveThorbitDepositionMcpEnv() {
|
|
177
|
+
const apiKey = (process.env.THORBIT_API_KEY || process.env.THORBIT_MCP_API_KEY || process.env.THORBIT_DEPOSITION_MCP_API_KEY || readApiKeyFile())?.trim();
|
|
178
|
+
if (!apiKey) {
|
|
179
|
+
throw new Error("THORBIT_API_KEY, THORBIT_MCP_API_KEY, or ~/.thorbit-deposition-mcp-key is required");
|
|
180
|
+
}
|
|
181
|
+
return {
|
|
182
|
+
apiKey,
|
|
183
|
+
baseUrl: (process.env.THORBIT_BASE_URL || process.env.THORBIT_DEPOSITION_MCP_BASE_URL || "https://thorbit.ai").trim()
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// src/deposition-mcp-tool-names.ts
|
|
188
|
+
var ThorbitDepositionMcpToolNames = [
|
|
189
|
+
"thorbit_deposition_start",
|
|
190
|
+
"thorbit_deposition_get",
|
|
191
|
+
"thorbit_deposition_get_playbook",
|
|
192
|
+
"thorbit_deposition_list"
|
|
193
|
+
];
|
|
194
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
195
|
+
0 && (module.exports = {
|
|
196
|
+
SERVER_INSTRUCTIONS,
|
|
197
|
+
ThorbitDepositionApiClient,
|
|
198
|
+
ThorbitDepositionMcpToolNames,
|
|
199
|
+
buildThorbitDepositionMcpServer,
|
|
200
|
+
resolveThorbitDepositionMcpEnv
|
|
201
|
+
});
|
|
202
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/deposition-api-client.ts","../src/deposition-mcp-server.ts","../src/deposition-mcp-response-formatters.ts","../src/deposition-mcp-tool-schemas.ts","../src/deposition-mcp-env.ts","../src/deposition-mcp-tool-names.ts"],"sourcesContent":["export { ThorbitDepositionApiClient } from './deposition-api-client.js'\nexport { buildThorbitDepositionMcpServer, SERVER_INSTRUCTIONS } from './deposition-mcp-server.js'\nexport { resolveThorbitDepositionMcpEnv } from './deposition-mcp-env.js'\nexport { ThorbitDepositionMcpToolNames } from './deposition-mcp-tool-names.js'\n","import type { ThorbitDepositionMcpToolName } from './deposition-mcp-tool-names.js'\n\nexport type ThorbitDepositionMcpEnvelope =\n | {\n ok: true\n result: unknown\n warnings?: string[]\n requestId: string\n }\n | {\n ok: false\n error: {\n code: string\n message: string\n details?: unknown\n }\n requestId: string\n }\n\nexport class ThorbitDepositionApiClient {\n private readonly baseUrl: string\n private readonly apiKey: string\n\n constructor(options: { baseUrl: string; apiKey: string }) {\n this.baseUrl = options.baseUrl.replace(/\\/$/, '')\n this.apiKey = options.apiKey\n }\n\n async callTool(toolName: ThorbitDepositionMcpToolName, input: unknown): Promise<ThorbitDepositionMcpEnvelope> {\n const response = await fetch(`${this.baseUrl}/api/v1/mcp/deposition/${toolName}`, {\n method: 'POST',\n headers: {\n 'x-thorbit-api-key': this.apiKey,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(input ?? {}),\n })\n\n const body = await response.json().catch(() => null) as ThorbitDepositionMcpEnvelope | null\n if (body && typeof body === 'object' && 'ok' in body) return body\n\n return {\n ok: false,\n requestId: 'unavailable',\n error: {\n code: response.ok ? 'invalid_response' : `http_${response.status}`,\n message: response.ok ? 'Thorbit returned an invalid MCP response' : `Thorbit API request failed with HTTP ${response.status}`,\n },\n }\n }\n}\n","import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport type { ToolAnnotations } from '@modelcontextprotocol/sdk/types.js'\nimport type { ZodRawShape } from 'zod'\nimport type { ThorbitDepositionApiClient } from './deposition-api-client.js'\nimport { formatThorbitDepositionMcpToolResult } from './deposition-mcp-response-formatters.js'\nimport {\n ThorbitDepositionStartInputSchema,\n ThorbitDepositionGetInputSchema,\n ThorbitDepositionGetPlaybookInputSchema,\n ThorbitDepositionListInputSchema,\n} from './deposition-mcp-tool-schemas.js'\nimport type { ThorbitDepositionMcpToolName } from './deposition-mcp-tool-names.js'\n\nconst VERSION = '0.1.0'\n\ntype ThorbitDepositionToolConfig<InputArgs extends ZodRawShape> = {\n title: string\n description: string\n inputSchema: InputArgs\n annotations: ToolAnnotations\n}\n\nfunction readOnlyAnnotations(title: string) {\n return { title, readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false }\n}\n\nfunction writeAnnotations(title: string) {\n return { title, readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true }\n}\n\nexport const SERVER_INSTRUCTIONS = [\n 'Thorbit Depositioning MCP. Runs the durable Depositioning strategy pipeline on hosted Thorbit (this server is a thin client). It researches competitors + customers, finds the binding vulnerability, classifies mover populations, designs a category class, builds a displacement mechanism, and writes a strategy playbook. All write/analysis tools are metered against your API key.',\n '',\n 'INTAKE (ask the user these BEFORE thorbit_deposition_start, then run):',\n '1. Company / product name being depositioned.',\n '2. Product URL (the challenger homepage).',\n '3. Category name (e.g. \"B2B sales analytics\").',\n '4. Optional: 0-5 competitor URLs (auto-discovered via SERP if fewer than 2).',\n '5. Optional: a customer reviews URL (G2 / Trustpilot / Reddit) and known customer pain points.',\n '',\n 'ASYNC CONTRACT (important):',\n '- thorbit_deposition_start returns quickly with {runPublicId, poll}. Do NOT block — follow result.poll.',\n '- Poll thorbit_deposition_get until status is terminal (complete/failed). It returns a LEAN status (phase, progress, binding state, strategy) with a nextAction.',\n '- When status is complete, call thorbit_deposition_get_playbook to read the finished markdown playbook.',\n '- Use thorbit_deposition_list to find past runs (by company/status) and their runPublicId.',\n].join('\\n')\n\nexport function buildThorbitDepositionMcpServer(client: ThorbitDepositionApiClient): McpServer {\n const server = new McpServer({ name: 'thorbit-deposition-mcp', version: VERSION }, { instructions: SERVER_INSTRUCTIONS })\n\n function registerTool<T extends ThorbitDepositionMcpToolName>(\n toolName: T,\n config: ThorbitDepositionToolConfig<ZodRawShape>,\n ): void {\n server.registerTool(toolName, config, async (input) => {\n const envelope = await client.callTool(toolName, input)\n return formatThorbitDepositionMcpToolResult(toolName, envelope)\n })\n }\n\n registerTool('thorbit_deposition_start', {\n title: 'Start Depositioning Run',\n description: 'Start a durable Depositioning strategy run for a challenger product in a category. Researches competitors and customers, finds the binding vulnerability, classifies movers, designs a category class, builds a displacement mechanism, and writes a playbook. Returns a runPublicId plus a thorbit_deposition_get poll target. Metered.',\n inputSchema: ThorbitDepositionStartInputSchema,\n annotations: writeAnnotations('Start Depositioning Run'),\n })\n\n registerTool('thorbit_deposition_get', {\n title: 'Read Depositioning Run Status',\n description: 'Read a Depositioning run: status, current phase, progress, selected binding state and strategy, primary vulnerability, category class, displacement mechanism, and whether the playbook is ready. Returns a nextAction. Poll until status is complete or failed.',\n inputSchema: ThorbitDepositionGetInputSchema,\n annotations: readOnlyAnnotations('Read Depositioning Run Status'),\n })\n\n registerTool('thorbit_deposition_get_playbook', {\n title: 'Read Depositioning Playbook',\n description: 'Return the finished deposition-playbook markdown for a completed run (executive brief, the four elements, activation guide). Returns not_found until the run completes.',\n inputSchema: ThorbitDepositionGetPlaybookInputSchema,\n annotations: readOnlyAnnotations('Read Depositioning Playbook'),\n })\n\n registerTool('thorbit_deposition_list', {\n title: 'List Depositioning Runs',\n description: 'List past Depositioning runs (most recent first) with runPublicId, company, category, status, binding state, and strategy. Filter by project, company-name search, or status. Use to find a prior run to read.',\n inputSchema: ThorbitDepositionListInputSchema,\n annotations: readOnlyAnnotations('List Depositioning Runs'),\n })\n\n return server\n}\n","import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js'\nimport type { ThorbitDepositionMcpEnvelope } from './deposition-api-client.js'\nimport type { ThorbitDepositionMcpToolName } from './deposition-mcp-tool-names.js'\n\nexport function formatThorbitDepositionMcpToolResult(\n toolName: ThorbitDepositionMcpToolName,\n envelope: ThorbitDepositionMcpEnvelope,\n): CallToolResult {\n const text = JSON.stringify({ toolName, ...envelope }, null, 2)\n return {\n content: [{ type: 'text', text }],\n isError: !envelope.ok,\n }\n}\n","import { z } from 'zod'\n\nexport const ThorbitDepositionStartInputSchema = {\n companyName: z.string().min(1).max(255).describe('The challenger company or product being depositioned.'),\n productUrl: z.string().url().max(2048).describe('URL of the challenger product homepage.'),\n categoryName: z.string().min(1).max(255).describe('The product category, e.g. \"B2B sales analytics\".'),\n competitorUrls: z.array(z.string().url()).max(5).default([]).describe('0-5 competitor URLs. Auto-discovered via SERP if fewer than 2 are provided.'),\n reviewsUrl: z.string().url().max(2048).optional().describe('Optional customer reviews URL (G2, Trustpilot, Reddit thread).'),\n knownPains: z.array(z.string().min(1)).max(50).optional().describe('Optional known customer pain points to seed the analysis.'),\n projectPublicId: z.string().min(1).optional().describe('Optional Thorbit project to associate the run with.'),\n}\n\nexport const ThorbitDepositionGetInputSchema = {\n runPublicId: z.string().min(1).describe('Deposition run public ID returned by thorbit_deposition_start.'),\n includePhaseData: z.boolean().default(false).describe('Include raw per-phase intermediate data in addition to the lean status.'),\n}\n\nexport const ThorbitDepositionGetPlaybookInputSchema = {\n runPublicId: z.string().min(1).describe('Deposition run public ID. Returns the markdown playbook once the run is complete.'),\n}\n\nexport const ThorbitDepositionListInputSchema = {\n projectPublicId: z.string().min(1).optional().describe('Optional project filter; omit for all org runs.'),\n search: z.string().max(200).optional().describe('Optional company-name substring filter.'),\n status: z.enum(['queued', 'running', 'complete', 'failed']).optional().describe('Optional run status filter.'),\n limit: z.number().int().min(1).max(100).default(25).describe('Maximum runs to return.'),\n offset: z.number().int().min(0).default(0).describe('Pagination offset.'),\n}\n\nexport const ThorbitDepositionMcpToolInputSchemas = {\n thorbit_deposition_start: ThorbitDepositionStartInputSchema,\n thorbit_deposition_get: ThorbitDepositionGetInputSchema,\n thorbit_deposition_get_playbook: ThorbitDepositionGetPlaybookInputSchema,\n thorbit_deposition_list: ThorbitDepositionListInputSchema,\n}\n","import { readFileSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { join } from 'node:path'\n\nexport type ThorbitDepositionMcpEnv = {\n apiKey: string\n baseUrl: string\n}\n\nfunction readApiKeyFile(): string | undefined {\n const explicitPath = process.env.THORBIT_DEPOSITION_MCP_KEY_PATH?.trim()\n const paths = [explicitPath, join(homedir(), '.thorbit-deposition-mcp-key')].filter(Boolean) as string[]\n for (const path of paths) {\n try {\n const value = readFileSync(path, 'utf8').trim()\n if (value) return value\n } catch {\n continue\n }\n }\n return undefined\n}\n\nexport function resolveThorbitDepositionMcpEnv(): ThorbitDepositionMcpEnv {\n const apiKey = (\n process.env.THORBIT_API_KEY ||\n process.env.THORBIT_MCP_API_KEY ||\n process.env.THORBIT_DEPOSITION_MCP_API_KEY ||\n readApiKeyFile()\n )?.trim()\n\n if (!apiKey) {\n throw new Error('THORBIT_API_KEY, THORBIT_MCP_API_KEY, or ~/.thorbit-deposition-mcp-key is required')\n }\n\n return {\n apiKey,\n baseUrl: (process.env.THORBIT_BASE_URL || process.env.THORBIT_DEPOSITION_MCP_BASE_URL || 'https://thorbit.ai').trim(),\n }\n}\n","export const ThorbitDepositionMcpToolNames = [\n 'thorbit_deposition_start',\n 'thorbit_deposition_get',\n 'thorbit_deposition_get_playbook',\n 'thorbit_deposition_list',\n] as const\n\nexport type ThorbitDepositionMcpToolName = typeof ThorbitDepositionMcpToolNames[number]\n"],"mappings":"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","names":[]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
|
|
3
|
+
declare const ThorbitDepositionMcpToolNames: readonly ["thorbit_deposition_start", "thorbit_deposition_get", "thorbit_deposition_get_playbook", "thorbit_deposition_list"];
|
|
4
|
+
type ThorbitDepositionMcpToolName = typeof ThorbitDepositionMcpToolNames[number];
|
|
5
|
+
|
|
6
|
+
type ThorbitDepositionMcpEnvelope = {
|
|
7
|
+
ok: true;
|
|
8
|
+
result: unknown;
|
|
9
|
+
warnings?: string[];
|
|
10
|
+
requestId: string;
|
|
11
|
+
} | {
|
|
12
|
+
ok: false;
|
|
13
|
+
error: {
|
|
14
|
+
code: string;
|
|
15
|
+
message: string;
|
|
16
|
+
details?: unknown;
|
|
17
|
+
};
|
|
18
|
+
requestId: string;
|
|
19
|
+
};
|
|
20
|
+
declare class ThorbitDepositionApiClient {
|
|
21
|
+
private readonly baseUrl;
|
|
22
|
+
private readonly apiKey;
|
|
23
|
+
constructor(options: {
|
|
24
|
+
baseUrl: string;
|
|
25
|
+
apiKey: string;
|
|
26
|
+
});
|
|
27
|
+
callTool(toolName: ThorbitDepositionMcpToolName, input: unknown): Promise<ThorbitDepositionMcpEnvelope>;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
declare const SERVER_INSTRUCTIONS: string;
|
|
31
|
+
declare function buildThorbitDepositionMcpServer(client: ThorbitDepositionApiClient): McpServer;
|
|
32
|
+
|
|
33
|
+
type ThorbitDepositionMcpEnv = {
|
|
34
|
+
apiKey: string;
|
|
35
|
+
baseUrl: string;
|
|
36
|
+
};
|
|
37
|
+
declare function resolveThorbitDepositionMcpEnv(): ThorbitDepositionMcpEnv;
|
|
38
|
+
|
|
39
|
+
export { SERVER_INSTRUCTIONS, ThorbitDepositionApiClient, ThorbitDepositionMcpToolNames, buildThorbitDepositionMcpServer, resolveThorbitDepositionMcpEnv };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
|
|
3
|
+
declare const ThorbitDepositionMcpToolNames: readonly ["thorbit_deposition_start", "thorbit_deposition_get", "thorbit_deposition_get_playbook", "thorbit_deposition_list"];
|
|
4
|
+
type ThorbitDepositionMcpToolName = typeof ThorbitDepositionMcpToolNames[number];
|
|
5
|
+
|
|
6
|
+
type ThorbitDepositionMcpEnvelope = {
|
|
7
|
+
ok: true;
|
|
8
|
+
result: unknown;
|
|
9
|
+
warnings?: string[];
|
|
10
|
+
requestId: string;
|
|
11
|
+
} | {
|
|
12
|
+
ok: false;
|
|
13
|
+
error: {
|
|
14
|
+
code: string;
|
|
15
|
+
message: string;
|
|
16
|
+
details?: unknown;
|
|
17
|
+
};
|
|
18
|
+
requestId: string;
|
|
19
|
+
};
|
|
20
|
+
declare class ThorbitDepositionApiClient {
|
|
21
|
+
private readonly baseUrl;
|
|
22
|
+
private readonly apiKey;
|
|
23
|
+
constructor(options: {
|
|
24
|
+
baseUrl: string;
|
|
25
|
+
apiKey: string;
|
|
26
|
+
});
|
|
27
|
+
callTool(toolName: ThorbitDepositionMcpToolName, input: unknown): Promise<ThorbitDepositionMcpEnvelope>;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
declare const SERVER_INSTRUCTIONS: string;
|
|
31
|
+
declare function buildThorbitDepositionMcpServer(client: ThorbitDepositionApiClient): McpServer;
|
|
32
|
+
|
|
33
|
+
type ThorbitDepositionMcpEnv = {
|
|
34
|
+
apiKey: string;
|
|
35
|
+
baseUrl: string;
|
|
36
|
+
};
|
|
37
|
+
declare function resolveThorbitDepositionMcpEnv(): ThorbitDepositionMcpEnv;
|
|
38
|
+
|
|
39
|
+
export { SERVER_INSTRUCTIONS, ThorbitDepositionApiClient, ThorbitDepositionMcpToolNames, buildThorbitDepositionMcpServer, resolveThorbitDepositionMcpEnv };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/deposition-api-client.ts
|
|
4
|
+
var ThorbitDepositionApiClient = class {
|
|
5
|
+
baseUrl;
|
|
6
|
+
apiKey;
|
|
7
|
+
constructor(options) {
|
|
8
|
+
this.baseUrl = options.baseUrl.replace(/\/$/, "");
|
|
9
|
+
this.apiKey = options.apiKey;
|
|
10
|
+
}
|
|
11
|
+
async callTool(toolName, input) {
|
|
12
|
+
const response = await fetch(`${this.baseUrl}/api/v1/mcp/deposition/${toolName}`, {
|
|
13
|
+
method: "POST",
|
|
14
|
+
headers: {
|
|
15
|
+
"x-thorbit-api-key": this.apiKey,
|
|
16
|
+
"Content-Type": "application/json"
|
|
17
|
+
},
|
|
18
|
+
body: JSON.stringify(input ?? {})
|
|
19
|
+
});
|
|
20
|
+
const body = await response.json().catch(() => null);
|
|
21
|
+
if (body && typeof body === "object" && "ok" in body) return body;
|
|
22
|
+
return {
|
|
23
|
+
ok: false,
|
|
24
|
+
requestId: "unavailable",
|
|
25
|
+
error: {
|
|
26
|
+
code: response.ok ? "invalid_response" : `http_${response.status}`,
|
|
27
|
+
message: response.ok ? "Thorbit returned an invalid MCP response" : `Thorbit API request failed with HTTP ${response.status}`
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
// src/deposition-mcp-server.ts
|
|
34
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
35
|
+
|
|
36
|
+
// src/deposition-mcp-response-formatters.ts
|
|
37
|
+
function formatThorbitDepositionMcpToolResult(toolName, envelope) {
|
|
38
|
+
const text = JSON.stringify({ toolName, ...envelope }, null, 2);
|
|
39
|
+
return {
|
|
40
|
+
content: [{ type: "text", text }],
|
|
41
|
+
isError: !envelope.ok
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// src/deposition-mcp-tool-schemas.ts
|
|
46
|
+
import { z } from "zod";
|
|
47
|
+
var ThorbitDepositionStartInputSchema = {
|
|
48
|
+
companyName: z.string().min(1).max(255).describe("The challenger company or product being depositioned."),
|
|
49
|
+
productUrl: z.string().url().max(2048).describe("URL of the challenger product homepage."),
|
|
50
|
+
categoryName: z.string().min(1).max(255).describe('The product category, e.g. "B2B sales analytics".'),
|
|
51
|
+
competitorUrls: z.array(z.string().url()).max(5).default([]).describe("0-5 competitor URLs. Auto-discovered via SERP if fewer than 2 are provided."),
|
|
52
|
+
reviewsUrl: z.string().url().max(2048).optional().describe("Optional customer reviews URL (G2, Trustpilot, Reddit thread)."),
|
|
53
|
+
knownPains: z.array(z.string().min(1)).max(50).optional().describe("Optional known customer pain points to seed the analysis."),
|
|
54
|
+
projectPublicId: z.string().min(1).optional().describe("Optional Thorbit project to associate the run with.")
|
|
55
|
+
};
|
|
56
|
+
var ThorbitDepositionGetInputSchema = {
|
|
57
|
+
runPublicId: z.string().min(1).describe("Deposition run public ID returned by thorbit_deposition_start."),
|
|
58
|
+
includePhaseData: z.boolean().default(false).describe("Include raw per-phase intermediate data in addition to the lean status.")
|
|
59
|
+
};
|
|
60
|
+
var ThorbitDepositionGetPlaybookInputSchema = {
|
|
61
|
+
runPublicId: z.string().min(1).describe("Deposition run public ID. Returns the markdown playbook once the run is complete.")
|
|
62
|
+
};
|
|
63
|
+
var ThorbitDepositionListInputSchema = {
|
|
64
|
+
projectPublicId: z.string().min(1).optional().describe("Optional project filter; omit for all org runs."),
|
|
65
|
+
search: z.string().max(200).optional().describe("Optional company-name substring filter."),
|
|
66
|
+
status: z.enum(["queued", "running", "complete", "failed"]).optional().describe("Optional run status filter."),
|
|
67
|
+
limit: z.number().int().min(1).max(100).default(25).describe("Maximum runs to return."),
|
|
68
|
+
offset: z.number().int().min(0).default(0).describe("Pagination offset.")
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
// src/deposition-mcp-server.ts
|
|
72
|
+
var VERSION = "0.1.0";
|
|
73
|
+
function readOnlyAnnotations(title) {
|
|
74
|
+
return { title, readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
|
|
75
|
+
}
|
|
76
|
+
function writeAnnotations(title) {
|
|
77
|
+
return { title, readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true };
|
|
78
|
+
}
|
|
79
|
+
var SERVER_INSTRUCTIONS = [
|
|
80
|
+
"Thorbit Depositioning MCP. Runs the durable Depositioning strategy pipeline on hosted Thorbit (this server is a thin client). It researches competitors + customers, finds the binding vulnerability, classifies mover populations, designs a category class, builds a displacement mechanism, and writes a strategy playbook. All write/analysis tools are metered against your API key.",
|
|
81
|
+
"",
|
|
82
|
+
"INTAKE (ask the user these BEFORE thorbit_deposition_start, then run):",
|
|
83
|
+
"1. Company / product name being depositioned.",
|
|
84
|
+
"2. Product URL (the challenger homepage).",
|
|
85
|
+
'3. Category name (e.g. "B2B sales analytics").',
|
|
86
|
+
"4. Optional: 0-5 competitor URLs (auto-discovered via SERP if fewer than 2).",
|
|
87
|
+
"5. Optional: a customer reviews URL (G2 / Trustpilot / Reddit) and known customer pain points.",
|
|
88
|
+
"",
|
|
89
|
+
"ASYNC CONTRACT (important):",
|
|
90
|
+
"- thorbit_deposition_start returns quickly with {runPublicId, poll}. Do NOT block \u2014 follow result.poll.",
|
|
91
|
+
"- Poll thorbit_deposition_get until status is terminal (complete/failed). It returns a LEAN status (phase, progress, binding state, strategy) with a nextAction.",
|
|
92
|
+
"- When status is complete, call thorbit_deposition_get_playbook to read the finished markdown playbook.",
|
|
93
|
+
"- Use thorbit_deposition_list to find past runs (by company/status) and their runPublicId."
|
|
94
|
+
].join("\n");
|
|
95
|
+
function buildThorbitDepositionMcpServer(client) {
|
|
96
|
+
const server = new McpServer({ name: "thorbit-deposition-mcp", version: VERSION }, { instructions: SERVER_INSTRUCTIONS });
|
|
97
|
+
function registerTool(toolName, config) {
|
|
98
|
+
server.registerTool(toolName, config, async (input) => {
|
|
99
|
+
const envelope = await client.callTool(toolName, input);
|
|
100
|
+
return formatThorbitDepositionMcpToolResult(toolName, envelope);
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
registerTool("thorbit_deposition_start", {
|
|
104
|
+
title: "Start Depositioning Run",
|
|
105
|
+
description: "Start a durable Depositioning strategy run for a challenger product in a category. Researches competitors and customers, finds the binding vulnerability, classifies movers, designs a category class, builds a displacement mechanism, and writes a playbook. Returns a runPublicId plus a thorbit_deposition_get poll target. Metered.",
|
|
106
|
+
inputSchema: ThorbitDepositionStartInputSchema,
|
|
107
|
+
annotations: writeAnnotations("Start Depositioning Run")
|
|
108
|
+
});
|
|
109
|
+
registerTool("thorbit_deposition_get", {
|
|
110
|
+
title: "Read Depositioning Run Status",
|
|
111
|
+
description: "Read a Depositioning run: status, current phase, progress, selected binding state and strategy, primary vulnerability, category class, displacement mechanism, and whether the playbook is ready. Returns a nextAction. Poll until status is complete or failed.",
|
|
112
|
+
inputSchema: ThorbitDepositionGetInputSchema,
|
|
113
|
+
annotations: readOnlyAnnotations("Read Depositioning Run Status")
|
|
114
|
+
});
|
|
115
|
+
registerTool("thorbit_deposition_get_playbook", {
|
|
116
|
+
title: "Read Depositioning Playbook",
|
|
117
|
+
description: "Return the finished deposition-playbook markdown for a completed run (executive brief, the four elements, activation guide). Returns not_found until the run completes.",
|
|
118
|
+
inputSchema: ThorbitDepositionGetPlaybookInputSchema,
|
|
119
|
+
annotations: readOnlyAnnotations("Read Depositioning Playbook")
|
|
120
|
+
});
|
|
121
|
+
registerTool("thorbit_deposition_list", {
|
|
122
|
+
title: "List Depositioning Runs",
|
|
123
|
+
description: "List past Depositioning runs (most recent first) with runPublicId, company, category, status, binding state, and strategy. Filter by project, company-name search, or status. Use to find a prior run to read.",
|
|
124
|
+
inputSchema: ThorbitDepositionListInputSchema,
|
|
125
|
+
annotations: readOnlyAnnotations("List Depositioning Runs")
|
|
126
|
+
});
|
|
127
|
+
return server;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// src/deposition-mcp-env.ts
|
|
131
|
+
import { readFileSync } from "fs";
|
|
132
|
+
import { homedir } from "os";
|
|
133
|
+
import { join } from "path";
|
|
134
|
+
function readApiKeyFile() {
|
|
135
|
+
const explicitPath = process.env.THORBIT_DEPOSITION_MCP_KEY_PATH?.trim();
|
|
136
|
+
const paths = [explicitPath, join(homedir(), ".thorbit-deposition-mcp-key")].filter(Boolean);
|
|
137
|
+
for (const path of paths) {
|
|
138
|
+
try {
|
|
139
|
+
const value = readFileSync(path, "utf8").trim();
|
|
140
|
+
if (value) return value;
|
|
141
|
+
} catch {
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return void 0;
|
|
146
|
+
}
|
|
147
|
+
function resolveThorbitDepositionMcpEnv() {
|
|
148
|
+
const apiKey = (process.env.THORBIT_API_KEY || process.env.THORBIT_MCP_API_KEY || process.env.THORBIT_DEPOSITION_MCP_API_KEY || readApiKeyFile())?.trim();
|
|
149
|
+
if (!apiKey) {
|
|
150
|
+
throw new Error("THORBIT_API_KEY, THORBIT_MCP_API_KEY, or ~/.thorbit-deposition-mcp-key is required");
|
|
151
|
+
}
|
|
152
|
+
return {
|
|
153
|
+
apiKey,
|
|
154
|
+
baseUrl: (process.env.THORBIT_BASE_URL || process.env.THORBIT_DEPOSITION_MCP_BASE_URL || "https://thorbit.ai").trim()
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// src/deposition-mcp-tool-names.ts
|
|
159
|
+
var ThorbitDepositionMcpToolNames = [
|
|
160
|
+
"thorbit_deposition_start",
|
|
161
|
+
"thorbit_deposition_get",
|
|
162
|
+
"thorbit_deposition_get_playbook",
|
|
163
|
+
"thorbit_deposition_list"
|
|
164
|
+
];
|
|
165
|
+
export {
|
|
166
|
+
SERVER_INSTRUCTIONS,
|
|
167
|
+
ThorbitDepositionApiClient,
|
|
168
|
+
ThorbitDepositionMcpToolNames,
|
|
169
|
+
buildThorbitDepositionMcpServer,
|
|
170
|
+
resolveThorbitDepositionMcpEnv
|
|
171
|
+
};
|
|
172
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/deposition-api-client.ts","../src/deposition-mcp-server.ts","../src/deposition-mcp-response-formatters.ts","../src/deposition-mcp-tool-schemas.ts","../src/deposition-mcp-env.ts","../src/deposition-mcp-tool-names.ts"],"sourcesContent":["import type { ThorbitDepositionMcpToolName } from './deposition-mcp-tool-names.js'\n\nexport type ThorbitDepositionMcpEnvelope =\n | {\n ok: true\n result: unknown\n warnings?: string[]\n requestId: string\n }\n | {\n ok: false\n error: {\n code: string\n message: string\n details?: unknown\n }\n requestId: string\n }\n\nexport class ThorbitDepositionApiClient {\n private readonly baseUrl: string\n private readonly apiKey: string\n\n constructor(options: { baseUrl: string; apiKey: string }) {\n this.baseUrl = options.baseUrl.replace(/\\/$/, '')\n this.apiKey = options.apiKey\n }\n\n async callTool(toolName: ThorbitDepositionMcpToolName, input: unknown): Promise<ThorbitDepositionMcpEnvelope> {\n const response = await fetch(`${this.baseUrl}/api/v1/mcp/deposition/${toolName}`, {\n method: 'POST',\n headers: {\n 'x-thorbit-api-key': this.apiKey,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(input ?? {}),\n })\n\n const body = await response.json().catch(() => null) as ThorbitDepositionMcpEnvelope | null\n if (body && typeof body === 'object' && 'ok' in body) return body\n\n return {\n ok: false,\n requestId: 'unavailable',\n error: {\n code: response.ok ? 'invalid_response' : `http_${response.status}`,\n message: response.ok ? 'Thorbit returned an invalid MCP response' : `Thorbit API request failed with HTTP ${response.status}`,\n },\n }\n }\n}\n","import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport type { ToolAnnotations } from '@modelcontextprotocol/sdk/types.js'\nimport type { ZodRawShape } from 'zod'\nimport type { ThorbitDepositionApiClient } from './deposition-api-client.js'\nimport { formatThorbitDepositionMcpToolResult } from './deposition-mcp-response-formatters.js'\nimport {\n ThorbitDepositionStartInputSchema,\n ThorbitDepositionGetInputSchema,\n ThorbitDepositionGetPlaybookInputSchema,\n ThorbitDepositionListInputSchema,\n} from './deposition-mcp-tool-schemas.js'\nimport type { ThorbitDepositionMcpToolName } from './deposition-mcp-tool-names.js'\n\nconst VERSION = '0.1.0'\n\ntype ThorbitDepositionToolConfig<InputArgs extends ZodRawShape> = {\n title: string\n description: string\n inputSchema: InputArgs\n annotations: ToolAnnotations\n}\n\nfunction readOnlyAnnotations(title: string) {\n return { title, readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false }\n}\n\nfunction writeAnnotations(title: string) {\n return { title, readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true }\n}\n\nexport const SERVER_INSTRUCTIONS = [\n 'Thorbit Depositioning MCP. Runs the durable Depositioning strategy pipeline on hosted Thorbit (this server is a thin client). It researches competitors + customers, finds the binding vulnerability, classifies mover populations, designs a category class, builds a displacement mechanism, and writes a strategy playbook. All write/analysis tools are metered against your API key.',\n '',\n 'INTAKE (ask the user these BEFORE thorbit_deposition_start, then run):',\n '1. Company / product name being depositioned.',\n '2. Product URL (the challenger homepage).',\n '3. Category name (e.g. \"B2B sales analytics\").',\n '4. Optional: 0-5 competitor URLs (auto-discovered via SERP if fewer than 2).',\n '5. Optional: a customer reviews URL (G2 / Trustpilot / Reddit) and known customer pain points.',\n '',\n 'ASYNC CONTRACT (important):',\n '- thorbit_deposition_start returns quickly with {runPublicId, poll}. Do NOT block — follow result.poll.',\n '- Poll thorbit_deposition_get until status is terminal (complete/failed). It returns a LEAN status (phase, progress, binding state, strategy) with a nextAction.',\n '- When status is complete, call thorbit_deposition_get_playbook to read the finished markdown playbook.',\n '- Use thorbit_deposition_list to find past runs (by company/status) and their runPublicId.',\n].join('\\n')\n\nexport function buildThorbitDepositionMcpServer(client: ThorbitDepositionApiClient): McpServer {\n const server = new McpServer({ name: 'thorbit-deposition-mcp', version: VERSION }, { instructions: SERVER_INSTRUCTIONS })\n\n function registerTool<T extends ThorbitDepositionMcpToolName>(\n toolName: T,\n config: ThorbitDepositionToolConfig<ZodRawShape>,\n ): void {\n server.registerTool(toolName, config, async (input) => {\n const envelope = await client.callTool(toolName, input)\n return formatThorbitDepositionMcpToolResult(toolName, envelope)\n })\n }\n\n registerTool('thorbit_deposition_start', {\n title: 'Start Depositioning Run',\n description: 'Start a durable Depositioning strategy run for a challenger product in a category. Researches competitors and customers, finds the binding vulnerability, classifies movers, designs a category class, builds a displacement mechanism, and writes a playbook. Returns a runPublicId plus a thorbit_deposition_get poll target. Metered.',\n inputSchema: ThorbitDepositionStartInputSchema,\n annotations: writeAnnotations('Start Depositioning Run'),\n })\n\n registerTool('thorbit_deposition_get', {\n title: 'Read Depositioning Run Status',\n description: 'Read a Depositioning run: status, current phase, progress, selected binding state and strategy, primary vulnerability, category class, displacement mechanism, and whether the playbook is ready. Returns a nextAction. Poll until status is complete or failed.',\n inputSchema: ThorbitDepositionGetInputSchema,\n annotations: readOnlyAnnotations('Read Depositioning Run Status'),\n })\n\n registerTool('thorbit_deposition_get_playbook', {\n title: 'Read Depositioning Playbook',\n description: 'Return the finished deposition-playbook markdown for a completed run (executive brief, the four elements, activation guide). Returns not_found until the run completes.',\n inputSchema: ThorbitDepositionGetPlaybookInputSchema,\n annotations: readOnlyAnnotations('Read Depositioning Playbook'),\n })\n\n registerTool('thorbit_deposition_list', {\n title: 'List Depositioning Runs',\n description: 'List past Depositioning runs (most recent first) with runPublicId, company, category, status, binding state, and strategy. Filter by project, company-name search, or status. Use to find a prior run to read.',\n inputSchema: ThorbitDepositionListInputSchema,\n annotations: readOnlyAnnotations('List Depositioning Runs'),\n })\n\n return server\n}\n","import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js'\nimport type { ThorbitDepositionMcpEnvelope } from './deposition-api-client.js'\nimport type { ThorbitDepositionMcpToolName } from './deposition-mcp-tool-names.js'\n\nexport function formatThorbitDepositionMcpToolResult(\n toolName: ThorbitDepositionMcpToolName,\n envelope: ThorbitDepositionMcpEnvelope,\n): CallToolResult {\n const text = JSON.stringify({ toolName, ...envelope }, null, 2)\n return {\n content: [{ type: 'text', text }],\n isError: !envelope.ok,\n }\n}\n","import { z } from 'zod'\n\nexport const ThorbitDepositionStartInputSchema = {\n companyName: z.string().min(1).max(255).describe('The challenger company or product being depositioned.'),\n productUrl: z.string().url().max(2048).describe('URL of the challenger product homepage.'),\n categoryName: z.string().min(1).max(255).describe('The product category, e.g. \"B2B sales analytics\".'),\n competitorUrls: z.array(z.string().url()).max(5).default([]).describe('0-5 competitor URLs. Auto-discovered via SERP if fewer than 2 are provided.'),\n reviewsUrl: z.string().url().max(2048).optional().describe('Optional customer reviews URL (G2, Trustpilot, Reddit thread).'),\n knownPains: z.array(z.string().min(1)).max(50).optional().describe('Optional known customer pain points to seed the analysis.'),\n projectPublicId: z.string().min(1).optional().describe('Optional Thorbit project to associate the run with.'),\n}\n\nexport const ThorbitDepositionGetInputSchema = {\n runPublicId: z.string().min(1).describe('Deposition run public ID returned by thorbit_deposition_start.'),\n includePhaseData: z.boolean().default(false).describe('Include raw per-phase intermediate data in addition to the lean status.'),\n}\n\nexport const ThorbitDepositionGetPlaybookInputSchema = {\n runPublicId: z.string().min(1).describe('Deposition run public ID. Returns the markdown playbook once the run is complete.'),\n}\n\nexport const ThorbitDepositionListInputSchema = {\n projectPublicId: z.string().min(1).optional().describe('Optional project filter; omit for all org runs.'),\n search: z.string().max(200).optional().describe('Optional company-name substring filter.'),\n status: z.enum(['queued', 'running', 'complete', 'failed']).optional().describe('Optional run status filter.'),\n limit: z.number().int().min(1).max(100).default(25).describe('Maximum runs to return.'),\n offset: z.number().int().min(0).default(0).describe('Pagination offset.'),\n}\n\nexport const ThorbitDepositionMcpToolInputSchemas = {\n thorbit_deposition_start: ThorbitDepositionStartInputSchema,\n thorbit_deposition_get: ThorbitDepositionGetInputSchema,\n thorbit_deposition_get_playbook: ThorbitDepositionGetPlaybookInputSchema,\n thorbit_deposition_list: ThorbitDepositionListInputSchema,\n}\n","import { readFileSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { join } from 'node:path'\n\nexport type ThorbitDepositionMcpEnv = {\n apiKey: string\n baseUrl: string\n}\n\nfunction readApiKeyFile(): string | undefined {\n const explicitPath = process.env.THORBIT_DEPOSITION_MCP_KEY_PATH?.trim()\n const paths = [explicitPath, join(homedir(), '.thorbit-deposition-mcp-key')].filter(Boolean) as string[]\n for (const path of paths) {\n try {\n const value = readFileSync(path, 'utf8').trim()\n if (value) return value\n } catch {\n continue\n }\n }\n return undefined\n}\n\nexport function resolveThorbitDepositionMcpEnv(): ThorbitDepositionMcpEnv {\n const apiKey = (\n process.env.THORBIT_API_KEY ||\n process.env.THORBIT_MCP_API_KEY ||\n process.env.THORBIT_DEPOSITION_MCP_API_KEY ||\n readApiKeyFile()\n )?.trim()\n\n if (!apiKey) {\n throw new Error('THORBIT_API_KEY, THORBIT_MCP_API_KEY, or ~/.thorbit-deposition-mcp-key is required')\n }\n\n return {\n apiKey,\n baseUrl: (process.env.THORBIT_BASE_URL || process.env.THORBIT_DEPOSITION_MCP_BASE_URL || 'https://thorbit.ai').trim(),\n }\n}\n","export const ThorbitDepositionMcpToolNames = [\n 'thorbit_deposition_start',\n 'thorbit_deposition_get',\n 'thorbit_deposition_get_playbook',\n 'thorbit_deposition_list',\n] as const\n\nexport type ThorbitDepositionMcpToolName = typeof ThorbitDepositionMcpToolNames[number]\n"],"mappings":";;;AAmBO,IAAM,6BAAN,MAAiC;AAAA,EACrB;AAAA,EACA;AAAA,EAEjB,YAAY,SAA8C;AACxD,SAAK,UAAU,QAAQ,QAAQ,QAAQ,OAAO,EAAE;AAChD,SAAK,SAAS,QAAQ;AAAA,EACxB;AAAA,EAEA,MAAM,SAAS,UAAwC,OAAuD;AAC5G,UAAM,WAAW,MAAM,MAAM,GAAG,KAAK,OAAO,0BAA0B,QAAQ,IAAI;AAAA,MAChF,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,qBAAqB,KAAK;AAAA,QAC1B,gBAAgB;AAAA,MAClB;AAAA,MACA,MAAM,KAAK,UAAU,SAAS,CAAC,CAAC;AAAA,IAClC,CAAC;AAED,UAAM,OAAO,MAAM,SAAS,KAAK,EAAE,MAAM,MAAM,IAAI;AACnD,QAAI,QAAQ,OAAO,SAAS,YAAY,QAAQ,KAAM,QAAO;AAE7D,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,WAAW;AAAA,MACX,OAAO;AAAA,QACL,MAAM,SAAS,KAAK,qBAAqB,QAAQ,SAAS,MAAM;AAAA,QAChE,SAAS,SAAS,KAAK,6CAA6C,wCAAwC,SAAS,MAAM;AAAA,MAC7H;AAAA,IACF;AAAA,EACF;AACF;;;AClDA,SAAS,iBAAiB;;;ACInB,SAAS,qCACd,UACA,UACgB;AAChB,QAAM,OAAO,KAAK,UAAU,EAAE,UAAU,GAAG,SAAS,GAAG,MAAM,CAAC;AAC9D,SAAO;AAAA,IACL,SAAS,CAAC,EAAE,MAAM,QAAQ,KAAK,CAAC;AAAA,IAChC,SAAS,CAAC,SAAS;AAAA,EACrB;AACF;;;ACbA,SAAS,SAAS;AAEX,IAAM,oCAAoC;AAAA,EAC/C,aAAa,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,EAAE,SAAS,uDAAuD;AAAA,EACxG,YAAY,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,IAAI,EAAE,SAAS,yCAAyC;AAAA,EACzF,cAAc,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,EAAE,SAAS,mDAAmD;AAAA,EACrG,gBAAgB,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,EAAE,QAAQ,CAAC,CAAC,EAAE,SAAS,6EAA6E;AAAA,EACnJ,YAAY,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,IAAI,EAAE,SAAS,EAAE,SAAS,gEAAgE;AAAA,EAC3H,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,SAAS,EAAE,SAAS,2DAA2D;AAAA,EAC9H,iBAAiB,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS,EAAE,SAAS,qDAAqD;AAC9G;AAEO,IAAM,kCAAkC;AAAA,EAC7C,aAAa,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS,gEAAgE;AAAA,EACxG,kBAAkB,EAAE,QAAQ,EAAE,QAAQ,KAAK,EAAE,SAAS,yEAAyE;AACjI;AAEO,IAAM,0CAA0C;AAAA,EACrD,aAAa,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS,mFAAmF;AAC7H;AAEO,IAAM,mCAAmC;AAAA,EAC9C,iBAAiB,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS,EAAE,SAAS,iDAAiD;AAAA,EACxG,QAAQ,EAAE,OAAO,EAAE,IAAI,GAAG,EAAE,SAAS,EAAE,SAAS,yCAAyC;AAAA,EACzF,QAAQ,EAAE,KAAK,CAAC,UAAU,WAAW,YAAY,QAAQ,CAAC,EAAE,SAAS,EAAE,SAAS,6BAA6B;AAAA,EAC7G,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,EAAE,QAAQ,EAAE,EAAE,SAAS,yBAAyB;AAAA,EACtF,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,QAAQ,CAAC,EAAE,SAAS,oBAAoB;AAC1E;;;AFdA,IAAM,UAAU;AAShB,SAAS,oBAAoB,OAAe;AAC1C,SAAO,EAAE,OAAO,cAAc,MAAM,iBAAiB,OAAO,gBAAgB,MAAM,eAAe,MAAM;AACzG;AAEA,SAAS,iBAAiB,OAAe;AACvC,SAAO,EAAE,OAAO,cAAc,OAAO,iBAAiB,OAAO,gBAAgB,OAAO,eAAe,KAAK;AAC1G;AAEO,IAAM,sBAAsB;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,EAAE,KAAK,IAAI;AAEJ,SAAS,gCAAgC,QAA+C;AAC7F,QAAM,SAAS,IAAI,UAAU,EAAE,MAAM,0BAA0B,SAAS,QAAQ,GAAG,EAAE,cAAc,oBAAoB,CAAC;AAExH,WAAS,aACP,UACA,QACM;AACN,WAAO,aAAa,UAAU,QAAQ,OAAO,UAAU;AACrD,YAAM,WAAW,MAAM,OAAO,SAAS,UAAU,KAAK;AACtD,aAAO,qCAAqC,UAAU,QAAQ;AAAA,IAChE,CAAC;AAAA,EACH;AAEA,eAAa,4BAA4B;AAAA,IACvC,OAAO;AAAA,IACP,aAAa;AAAA,IACb,aAAa;AAAA,IACb,aAAa,iBAAiB,yBAAyB;AAAA,EACzD,CAAC;AAED,eAAa,0BAA0B;AAAA,IACrC,OAAO;AAAA,IACP,aAAa;AAAA,IACb,aAAa;AAAA,IACb,aAAa,oBAAoB,+BAA+B;AAAA,EAClE,CAAC;AAED,eAAa,mCAAmC;AAAA,IAC9C,OAAO;AAAA,IACP,aAAa;AAAA,IACb,aAAa;AAAA,IACb,aAAa,oBAAoB,6BAA6B;AAAA,EAChE,CAAC;AAED,eAAa,2BAA2B;AAAA,IACtC,OAAO;AAAA,IACP,aAAa;AAAA,IACb,aAAa;AAAA,IACb,aAAa,oBAAoB,yBAAyB;AAAA,EAC5D,CAAC;AAED,SAAO;AACT;;;AGzFA,SAAS,oBAAoB;AAC7B,SAAS,eAAe;AACxB,SAAS,YAAY;AAOrB,SAAS,iBAAqC;AAC5C,QAAM,eAAe,QAAQ,IAAI,iCAAiC,KAAK;AACvE,QAAM,QAAQ,CAAC,cAAc,KAAK,QAAQ,GAAG,6BAA6B,CAAC,EAAE,OAAO,OAAO;AAC3F,aAAW,QAAQ,OAAO;AACxB,QAAI;AACF,YAAM,QAAQ,aAAa,MAAM,MAAM,EAAE,KAAK;AAC9C,UAAI,MAAO,QAAO;AAAA,IACpB,QAAQ;AACN;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAEO,SAAS,iCAA0D;AACxE,QAAM,UACJ,QAAQ,IAAI,mBACZ,QAAQ,IAAI,uBACZ,QAAQ,IAAI,kCACZ,eAAe,IACd,KAAK;AAER,MAAI,CAAC,QAAQ;AACX,UAAM,IAAI,MAAM,oFAAoF;AAAA,EACtG;AAEA,SAAO;AAAA,IACL;AAAA,IACA,UAAU,QAAQ,IAAI,oBAAoB,QAAQ,IAAI,mCAAmC,sBAAsB,KAAK;AAAA,EACtH;AACF;;;ACvCO,IAAM,gCAAgC;AAAA,EAC3C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "thorbit-deposition-mcp",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "MCP server for the Thorbit Depositioning strategy pipeline",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js",
|
|
13
|
+
"require": "./dist/index.cjs"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"bin": {
|
|
17
|
+
"thorbit-deposition-mcp": "dist/bin/thorbit-deposition-mcp.js"
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"dist",
|
|
21
|
+
"README.md"
|
|
22
|
+
],
|
|
23
|
+
"scripts": {
|
|
24
|
+
"build": "tsup",
|
|
25
|
+
"test": "vitest run --config vitest.config.ts",
|
|
26
|
+
"typecheck": "tsc --noEmit"
|
|
27
|
+
},
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
30
|
+
"zod": "^3.23.0"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@types/node": "^20.0.0",
|
|
34
|
+
"tsup": "^8.0.0",
|
|
35
|
+
"typescript": "^5.4.0",
|
|
36
|
+
"vitest": "^1.6.0"
|
|
37
|
+
},
|
|
38
|
+
"engines": {
|
|
39
|
+
"node": ">=20"
|
|
40
|
+
}
|
|
41
|
+
}
|