mcp-server-andru-intelligence 0.1.1 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mcp-server-andru-intelligence",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "mcpName": "io.github.geter-andru/andru-intelligence",
5
5
  "description": "Andru Revenue Intelligence MCP Server — ICP scoring, persona profiling, competitive positioning, and buyer intelligence for technical SaaS founders.",
6
6
  "type": "module",
package/server.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
+ "$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
2
3
  "name": "io.github.geter-andru/andru-intelligence",
3
4
  "title": "Andru Revenue Intelligence",
4
- "description": "Strategic revenue intelligence for technical SaaS founders. ICP scoring, persona profiling, competitive positioning, buyer journey mapping, champion selling, and pre-meeting briefs — powered by 20 years of B2B sales wisdom.",
5
+ "description": "Revenue intelligence for SaaS founders: ICP scoring, persona profiling, competitive positioning.",
5
6
  "version": "0.1.1",
6
7
  "websiteUrl": "https://andru.ai",
7
8
  "repository": {
package/src/catalog.js ADDED
@@ -0,0 +1,369 @@
1
+ /**
2
+ * Static Tool & Resource Catalog
3
+ *
4
+ * Contains all MCP tool definitions and resource definitions so the server
5
+ * can respond to ListTools/ListResources without calling the backend.
6
+ * Tool *execution* still proxies to the Andru API.
7
+ *
8
+ * Source of truth: backend/src/mcp/tools/*.js + backend/src/mcp/resources/*.js
9
+ */
10
+
11
+ // ── 15 Tools ────────────────────────────────────────────────────────────────
12
+
13
+ export const tools = [
14
+ {
15
+ name: 'get_icp_fit_score',
16
+ description: 'Score a company against your ICP criteria. Returns a score (0-100), tier (A/B/C/D), and breakdown across 5 dimensions: firmographics, technographics, pain points, budget fit, and behavioral signals. No AI calls — pure algorithmic scoring.',
17
+ inputSchema: {
18
+ type: 'object',
19
+ properties: {
20
+ companyName: { type: 'string', description: 'Company name' },
21
+ domain: { type: 'string', description: 'Company domain' },
22
+ industry: { type: 'string', description: 'Industry vertical' },
23
+ employeeCount: { type: 'number', description: 'Number of employees' },
24
+ revenue: { type: 'string', description: 'Revenue range (e.g., "$1M-$5M")' },
25
+ geography: { type: 'string', description: 'HQ location' },
26
+ techStack: {
27
+ type: 'array',
28
+ items: { type: 'string' },
29
+ description: 'Technologies used',
30
+ },
31
+ painPoints: {
32
+ type: 'array',
33
+ items: { type: 'string' },
34
+ description: 'Known pain points or challenges',
35
+ },
36
+ triggerEvents: {
37
+ type: 'array',
38
+ items: { type: 'string' },
39
+ description: 'Recent trigger events (e.g., "just raised Series B", "new CTO hired")',
40
+ },
41
+ },
42
+ },
43
+ },
44
+
45
+ {
46
+ name: 'get_persona_profile',
47
+ description: 'Find the best-matching buyer persona from your ICP for a given job title, industry, and company size. Returns persona details including MBTI distribution, pain points, empathy map, and messaging angles.',
48
+ inputSchema: {
49
+ type: 'object',
50
+ properties: {
51
+ title: { type: 'string', description: 'Job title (e.g., "VP Engineering", "CTO", "Head of Sales")' },
52
+ industry: { type: 'string', description: 'Industry context' },
53
+ companySize: { type: 'string', description: 'Company size range' },
54
+ },
55
+ required: ['title'],
56
+ },
57
+ },
58
+
59
+ {
60
+ name: 'get_disqualification_signals',
61
+ description: 'Classify an opportunity using 3-layer scoring: ICP fit score, anti-pattern matching, and learned churn patterns. Returns STRONG/MODERATE/MARGINAL/ANTI_PATTERN classification with reasoning chain.',
62
+ inputSchema: {
63
+ type: 'object',
64
+ properties: {
65
+ companyName: { type: 'string', description: 'Company name' },
66
+ industry: { type: 'string', description: 'Industry' },
67
+ employeeCount: { type: 'number', description: 'Number of employees' },
68
+ revenue: { type: 'string', description: 'Revenue range' },
69
+ geography: { type: 'string', description: 'Location' },
70
+ techStack: { type: 'array', items: { type: 'string' }, description: 'Technologies used' },
71
+ dealContext: {
72
+ type: 'object',
73
+ properties: {
74
+ dealValue: { type: 'number', description: 'Deal value' },
75
+ stage: { type: 'string', description: 'Current deal stage' },
76
+ daysInPipeline: { type: 'number', description: 'Days since deal entered pipeline' },
77
+ championIdentified: { type: 'boolean', description: 'Has a champion been identified?' },
78
+ },
79
+ description: 'Current deal context (if applicable)',
80
+ },
81
+ },
82
+ },
83
+ },
84
+
85
+ {
86
+ name: 'get_messaging_framework',
87
+ description: 'Get messaging framework for a specific segment, funnel stage, or persona type. Returns value props, MBTI-adapted message templates, objection responses, voice variants, and content recommendations.',
88
+ inputSchema: {
89
+ type: 'object',
90
+ properties: {
91
+ segment: { type: 'string', description: 'Target segment or vertical' },
92
+ stage: {
93
+ type: 'string',
94
+ enum: ['awareness', 'consideration', 'decision'],
95
+ description: 'Buyer journey stage',
96
+ },
97
+ channel: { type: 'string', description: 'Channel (email, linkedin, phone, etc.)' },
98
+ personaType: { type: 'string', description: 'Target persona title' },
99
+ mbtiCategory: {
100
+ type: 'string',
101
+ enum: ['Analytical', 'Driver', 'Expressive', 'Amiable'],
102
+ description: 'MBTI communication category for message adaptation',
103
+ },
104
+ },
105
+ },
106
+ },
107
+
108
+ {
109
+ name: 'get_competitive_positioning',
110
+ description: 'Get competitive positioning intelligence against a specific competitor. Returns differentiation points, landmines to avoid, winning themes, and battlecard data.',
111
+ inputSchema: {
112
+ type: 'object',
113
+ properties: {
114
+ competitorName: { type: 'string', description: 'Competitor company name' },
115
+ competitorFeatures: {
116
+ type: 'array',
117
+ items: { type: 'string' },
118
+ description: 'Known competitor features or capabilities',
119
+ },
120
+ context: {
121
+ type: 'string',
122
+ description: 'Additional context (e.g., "enterprise deal", "competing on price")',
123
+ },
124
+ },
125
+ required: ['competitorName'],
126
+ },
127
+ },
128
+
129
+ {
130
+ name: 'classify_opportunity',
131
+ description: 'Classify an opportunity with full analysis: ICP fit score, persona match, disqualification check, risk assessment, and recommended next actions. Combines multiple engines for a comprehensive assessment.',
132
+ inputSchema: {
133
+ type: 'object',
134
+ properties: {
135
+ companyName: { type: 'string', description: 'Company name' },
136
+ contactTitle: { type: 'string', description: 'Primary contact job title' },
137
+ industry: { type: 'string', description: 'Industry' },
138
+ employeeCount: { type: 'number', description: 'Number of employees' },
139
+ revenue: { type: 'string', description: 'Revenue range' },
140
+ geography: { type: 'string', description: 'Location' },
141
+ dealValue: { type: 'number', description: 'Estimated deal value' },
142
+ dealStage: { type: 'string', description: 'Current deal stage' },
143
+ techStack: { type: 'array', items: { type: 'string' }, description: 'Technologies used' },
144
+ painPoints: { type: 'array', items: { type: 'string' }, description: 'Known pain points' },
145
+ triggerEvents: { type: 'array', items: { type: 'string' }, description: 'Trigger events' },
146
+ championIdentified: { type: 'boolean', description: 'Has a champion been identified?' },
147
+ competitorInvolved: { type: 'string', description: 'Known competitor in the deal' },
148
+ },
149
+ required: ['companyName'],
150
+ },
151
+ },
152
+
153
+ {
154
+ name: 'get_account_plan',
155
+ description: 'Get a structured account plan for a target company. Returns stakeholder map, value propositions, capability gaps, meeting prep, MEDDICC assessment, and CRM update package. Requires an existing Pure Signal ICP pipeline.',
156
+ inputSchema: {
157
+ type: 'object',
158
+ properties: {
159
+ accountName: { type: 'string', description: 'Target account/company name' },
160
+ domain: { type: 'string', description: 'Company domain' },
161
+ industry: { type: 'string', description: 'Industry vertical' },
162
+ stakeholders: {
163
+ type: 'array',
164
+ items: {
165
+ type: 'object',
166
+ properties: {
167
+ name: { type: 'string' },
168
+ title: { type: 'string' },
169
+ role: { type: 'string', description: 'Buying committee role (champion, economic_buyer, etc.)' },
170
+ },
171
+ },
172
+ description: 'Known stakeholders at the account',
173
+ },
174
+ dealContext: {
175
+ type: 'object',
176
+ properties: {
177
+ stage: { type: 'string', description: 'Current deal stage' },
178
+ value: { type: 'number', description: 'Deal value' },
179
+ nextMeeting: { type: 'string', description: 'Next meeting date/context' },
180
+ },
181
+ description: 'Current deal context',
182
+ },
183
+ },
184
+ required: ['accountName'],
185
+ },
186
+ },
187
+
188
+ {
189
+ name: 'get_capability_profile',
190
+ description: "Get a structured capability profile for the authenticated user's product. Returns capabilities, target customer, verified outcomes, trust signals, pricing model, and integrations. Includes values-based alignment scoring. Designed for buyer-side agent evaluation.",
191
+ inputSchema: {
192
+ type: 'object',
193
+ properties: {
194
+ includeOutcomes: { type: 'boolean', description: 'Include verified outcomes (default: true)' },
195
+ includeTrustSignals: { type: 'boolean', description: 'Include trust signals (default: true)' },
196
+ forceRefresh: { type: 'boolean', description: 'Force regeneration even if cached (default: false)' },
197
+ },
198
+ },
199
+ },
200
+
201
+ {
202
+ name: 'get_evaluation_criteria',
203
+ description: "Evaluate seller-buyer alignment across Andru's 6 values: Empathy (pain point coverage), Clarity (outcome specificity), Authenticity (claim verification), Focus (feature relevance), Accountability (outcome tracking), Alignment (mutual investment). Returns scores 0-100 per dimension plus overall.",
204
+ inputSchema: {
205
+ type: 'object',
206
+ properties: {
207
+ buyerPainPoints: {
208
+ type: 'array',
209
+ items: { type: 'string' },
210
+ description: "Buyer's known pain points",
211
+ },
212
+ buyerIndustry: { type: 'string', description: "Buyer's industry" },
213
+ buyerSize: { type: 'string', description: 'Buyer company size' },
214
+ requiredCapabilities: {
215
+ type: 'array',
216
+ items: { type: 'string' },
217
+ description: 'Capabilities the buyer needs',
218
+ },
219
+ },
220
+ },
221
+ },
222
+
223
+ {
224
+ name: 'get_icp_profile',
225
+ description: 'Get the full Pure Signal ICP profile. Returns all 5 intelligence layers (Product-Market, Role, Psychological, Timing, Channel), the seven critical buyer questions, and anti-patterns/disqualifiers. Optionally filter to specific layers.',
226
+ inputSchema: {
227
+ type: 'object',
228
+ properties: {
229
+ layers: {
230
+ type: 'array',
231
+ items: { type: 'number', enum: [1, 2, 3, 4, 5] },
232
+ description: 'Specific layers to include (1-5). Omit for all layers.',
233
+ },
234
+ includeSevenAnswers: { type: 'boolean', description: 'Include seven answers (default: true)' },
235
+ includeAntiPatterns: { type: 'boolean', description: 'Include anti-patterns (default: true)' },
236
+ },
237
+ },
238
+ },
239
+
240
+ {
241
+ name: 'discover_prospects',
242
+ description: 'Discover companies that match your ICP using AI-powered web search. Returns a list of prospects with confidence scores and evidence. NOTE: This is an expensive operation that calls Claude API with web search — it may take 15-30 seconds and consumes AI credits.',
243
+ inputSchema: {
244
+ type: 'object',
245
+ properties: {
246
+ companyName: {
247
+ type: 'string',
248
+ description: 'Your company name',
249
+ },
250
+ productDescription: {
251
+ type: 'string',
252
+ description: 'Description of your product or service',
253
+ },
254
+ coreCapability: {
255
+ type: 'string',
256
+ description: 'Your core capability or "pure signal" — the single most important thing your product does',
257
+ },
258
+ industry: {
259
+ type: 'string',
260
+ description: 'Target industry to search within (optional)',
261
+ },
262
+ targetMarket: {
263
+ type: 'string',
264
+ description: 'Target market segment (optional, e.g., "Series A SaaS companies")',
265
+ },
266
+ },
267
+ required: ['companyName', 'productDescription'],
268
+ },
269
+ },
270
+
271
+ {
272
+ name: 'get_pre_brief',
273
+ description: 'Generate a pre-meeting brief with talk track, discovery questions, objection prep, and contextual intelligence. Provide an eventId for calendar-linked briefs, or provide meeting context directly. NOTE: This calls the AI API and consumes credits.',
274
+ inputSchema: {
275
+ type: 'object',
276
+ properties: {
277
+ eventId: {
278
+ type: 'string',
279
+ description: 'Calendar event ID (from Andru calendar integration). If provided, pulls all context automatically.',
280
+ },
281
+ dealId: {
282
+ type: 'string',
283
+ description: 'Associated deal ID for additional deal intelligence (optional)',
284
+ },
285
+ briefType: {
286
+ type: 'string',
287
+ enum: ['general', 'discovery', 'demo', 'negotiation', 'renewal', 'expansion'],
288
+ description: 'Type of meeting brief to generate (default: general)',
289
+ },
290
+ },
291
+ },
292
+ },
293
+
294
+ {
295
+ name: 'get_syndication_status',
296
+ description: 'Check the sync status of your ICP intelligence across connected CRM platforms (HubSpot, Salesforce, Pipedrive). Shows which platforms are up to date, which are stale, and the last sync time for each.',
297
+ inputSchema: {
298
+ type: 'object',
299
+ properties: {},
300
+ },
301
+ },
302
+
303
+ {
304
+ name: 'trigger_syndication',
305
+ description: 'Manually trigger ICP intelligence syndication to your connected CRM platforms (HubSpot, Salesforce, Pipedrive). Detects which platforms are stale and pushes updated ICP data. Use get_syndication_status first to check which platforms need updating.',
306
+ inputSchema: {
307
+ type: 'object',
308
+ properties: {
309
+ platforms: {
310
+ type: 'array',
311
+ items: { type: 'string' },
312
+ description: 'Optional filter — only sync these platforms (e.g., ["hubspot"]). If omitted, syncs all stale platforms.',
313
+ },
314
+ },
315
+ },
316
+ },
317
+
318
+ {
319
+ name: 'batch_fit_score',
320
+ description: 'Score multiple companies against ICP criteria in a single batch. Returns individual scores plus aggregate statistics. Max 50 companies per call.',
321
+ inputSchema: {
322
+ type: 'object',
323
+ properties: {
324
+ companies: {
325
+ type: 'array',
326
+ items: {
327
+ type: 'object',
328
+ properties: {
329
+ companyName: { type: 'string', description: 'Company name' },
330
+ domain: { type: 'string', description: 'Company domain' },
331
+ industry: { type: 'string', description: 'Industry vertical' },
332
+ employeeCount: { type: 'number', description: 'Number of employees' },
333
+ revenue: { type: 'string', description: 'Revenue range' },
334
+ geography: { type: 'string', description: 'HQ location' },
335
+ techStack: { type: 'array', items: { type: 'string' }, description: 'Technologies used' },
336
+ painPoints: { type: 'array', items: { type: 'string' }, description: 'Known pain points' },
337
+ triggerEvents: { type: 'array', items: { type: 'string' }, description: 'Recent trigger events' },
338
+ },
339
+ },
340
+ description: 'Companies to score (max 50)',
341
+ },
342
+ },
343
+ required: ['companies'],
344
+ },
345
+ },
346
+ ];
347
+
348
+ // ── 3 Resources ─────────────────────────────────────────────────────────────
349
+
350
+ export const resources = [
351
+ {
352
+ uri: 'andru://icp/profile',
353
+ name: 'ICP Profile',
354
+ description: 'Your canonical Ideal Customer Profile — the Pure Signal ICP output including all 5 layers of intelligence, 7 critical answers, and anti-patterns.',
355
+ mimeType: 'application/json',
356
+ },
357
+ {
358
+ uri: 'andru://pipeline/runs',
359
+ name: 'Pipeline Runs',
360
+ description: 'Your GTM pipeline runs — lists all completed pipeline runs with their stage outputs (ICP, Lead Gen Strategy, Account Plans, Overview Deck).',
361
+ mimeType: 'application/json',
362
+ },
363
+ {
364
+ uri: 'andru://accounts',
365
+ name: 'Account Plans',
366
+ description: 'Your account plans — company summaries, tiers, pipeline values, stakeholder counts, and generation status.',
367
+ mimeType: 'application/json',
368
+ },
369
+ ];
package/src/index.js CHANGED
@@ -31,21 +31,41 @@ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
31
31
  import { AndruClient } from './client.js';
32
32
  import { createServer } from './server.js';
33
33
 
34
- const apiKey = process.env.ANDRU_API_KEY;
34
+ async function main() {
35
+ const apiKey = process.env.ANDRU_API_KEY;
36
+ const apiUrl = process.env.ANDRU_API_URL || 'https://api.andru.ai';
35
37
 
36
- if (!apiKey) {
37
- console.error('[Andru MCP] Error: ANDRU_API_KEY environment variable is required');
38
- console.error('[Andru MCP] Get your API key at https://app.andru.ai/settings/api-keys');
39
- process.exit(1);
40
- }
38
+ // When no API key, server still starts (tool listing works from static catalog,
39
+ // but tool execution will return an error). This allows registry scanners
40
+ // to discover tools without needing credentials.
41
+ let client = null;
42
+ if (apiKey) {
43
+ client = new AndruClient(apiKey, apiUrl);
44
+ } else {
45
+ console.error('[Andru MCP] Warning: ANDRU_API_KEY not set. Tool listing works, but execution requires an API key.');
46
+ console.error('[Andru MCP] Get your API key at https://app.andru.ai/settings/api-keys');
47
+ }
41
48
 
42
- const apiUrl = process.env.ANDRU_API_URL || 'https://api.andru.ai';
49
+ const server = createServer(client);
50
+ const transport = new StdioServerTransport();
43
51
 
44
- const client = new AndruClient(apiKey, apiUrl);
45
- const server = createServer(client);
46
- const transport = new StdioServerTransport();
52
+ await server.connect(transport);
53
+
54
+ console.error('[Andru MCP] Server running on stdio transport');
55
+ if (client) {
56
+ console.error(`[Andru MCP] API endpoint: ${apiUrl}`);
57
+ }
58
+ }
47
59
 
48
- await server.connect(transport);
60
+ main().catch((err) => {
61
+ console.error('[Andru MCP] Fatal error:', err);
62
+ process.exit(1);
63
+ });
49
64
 
50
- console.error('[Andru MCP] Server running on stdio transport');
51
- console.error(`[Andru MCP] API endpoint: ${apiUrl}`);
65
+ /**
66
+ * Smithery sandbox server — used by Smithery's scanner to discover
67
+ * tools and resources without real credentials.
68
+ */
69
+ export function createSandboxServer() {
70
+ return createServer(null);
71
+ }
package/src/server.js CHANGED
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * Andru MCP Server (Thin Proxy)
3
3
  *
4
- * Creates an MCP server that proxies all tool and resource requests
5
- * to the Andru backend API via the AndruClient.
4
+ * Lists tools and resources from the static catalog (no network needed).
5
+ * Proxies tool execution and resource reads to the Andru backend API.
6
6
  */
7
7
 
8
8
  import { Server } from '@modelcontextprotocol/sdk/server/index.js';
@@ -12,18 +12,19 @@ import {
12
12
  ListResourcesRequestSchema,
13
13
  ReadResourceRequestSchema,
14
14
  } from '@modelcontextprotocol/sdk/types.js';
15
+ import { tools, resources } from './catalog.js';
15
16
 
16
17
  /**
17
18
  * Create an MCP server backed by the Andru API.
18
19
  *
19
- * @param {import('./client.js').AndruClient} client
20
+ * @param {import('./client.js').AndruClient | null} client — null during scan mode (no API key)
20
21
  * @returns {Server}
21
22
  */
22
23
  export function createServer(client) {
23
24
  const server = new Server(
24
25
  {
25
26
  name: 'andru-intelligence',
26
- version: '0.1.0',
27
+ version: '0.1.1',
27
28
  },
28
29
  {
29
30
  capabilities: {
@@ -33,19 +34,24 @@ export function createServer(client) {
33
34
  }
34
35
  );
35
36
 
36
- // --- Tool handlers (proxy to backend) ---
37
+ // --- Tool listing (static catalog — no network) ---
37
38
 
38
39
  server.setRequestHandler(
39
40
  ListToolsRequestSchema,
40
- async () => {
41
- const result = await client.listTools();
42
- return { tools: result.tools };
43
- }
41
+ async () => ({ tools })
44
42
  );
45
43
 
44
+ // --- Tool execution (proxy to backend) ---
45
+
46
46
  server.setRequestHandler(
47
47
  CallToolRequestSchema,
48
48
  async (request) => {
49
+ if (!client) {
50
+ return {
51
+ content: [{ type: 'text', text: JSON.stringify({ error: 'ANDRU_API_KEY not configured. Tool execution requires an API key.' }) }],
52
+ isError: true,
53
+ };
54
+ }
49
55
  const { name, arguments: args } = request.params;
50
56
  try {
51
57
  return await client.callTool(name, args || {});
@@ -61,19 +67,27 @@ export function createServer(client) {
61
67
  }
62
68
  );
63
69
 
64
- // --- Resource handlers (proxy to backend) ---
70
+ // --- Resource listing (static catalog — no network) ---
65
71
 
66
72
  server.setRequestHandler(
67
73
  ListResourcesRequestSchema,
68
- async () => {
69
- const result = await client.listResources();
70
- return { resources: result.resources };
71
- }
74
+ async () => ({ resources })
72
75
  );
73
76
 
77
+ // --- Resource reading (proxy to backend) ---
78
+
74
79
  server.setRequestHandler(
75
80
  ReadResourceRequestSchema,
76
81
  async (request) => {
82
+ if (!client) {
83
+ return {
84
+ contents: [{
85
+ uri: request.params.uri,
86
+ mimeType: 'text/plain',
87
+ text: JSON.stringify({ error: 'ANDRU_API_KEY not configured. Resource reads require an API key.' }),
88
+ }],
89
+ };
90
+ }
77
91
  const { uri } = request.params;
78
92
  try {
79
93
  return await client.readResource(uri);