mcp-server-zignal 1.0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Zignal
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,149 @@
1
+ # Zignal MCP Server
2
+
3
+ MCP server for [Zignal](https://zignal.dev) - AI agent analytics and signal detection.
4
+
5
+ This server allows AI assistants like Claude to track conversations, detect signals (user frustration, task failures, feature requests, etc.), and retrieve analytics in real-time.
6
+
7
+ ## Features
8
+
9
+ - **Create Events**: Track AI conversations and interactions
10
+ - **List Events**: Search and filter tracked events
11
+ - **List Signals**: Retrieve detected signals (issues, risks, feedback)
12
+
13
+ ## Installation
14
+
15
+ ```bash
16
+ cd mcp-server-zignal
17
+ npm install
18
+ npm run build
19
+ ```
20
+
21
+ ## Configuration
22
+
23
+ ### 1. Get your Zignal API key
24
+
25
+ Sign up at [zignal.dev](https://zignal.dev) and create a project to get your API key.
26
+
27
+ ### 2. Configure Claude Desktop
28
+
29
+ Add the server to your Claude Desktop configuration:
30
+
31
+ **MacOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
32
+ **Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
33
+
34
+ ```json
35
+ {
36
+ "mcpServers": {
37
+ "zignal": {
38
+ "command": "node",
39
+ "args": [
40
+ "/absolute/path/to/zignal/mcp-server-zignal/dist/index.js"
41
+ ],
42
+ "env": {
43
+ "ZIGNAL_API_KEY": "zk_proj_your_api_key_here"
44
+ }
45
+ }
46
+ }
47
+ }
48
+ ```
49
+
50
+ ### 3. Restart Claude Desktop
51
+
52
+ The Zignal tools will now be available in Claude Desktop.
53
+
54
+ ## Environment Variables
55
+
56
+ - `ZIGNAL_API_KEY` (required): Your Zignal API key
57
+ - `ZIGNAL_BASE_URL` (optional): API base URL (defaults to `https://kanshi-production.up.railway.app`)
58
+
59
+ ## Available Tools
60
+
61
+ ### `zignal_create_events`
62
+
63
+ Create one or more events for AI signal classification.
64
+
65
+ **Example:**
66
+ ```json
67
+ {
68
+ "events": [
69
+ {
70
+ "user_id": "user_123",
71
+ "event": "ai.conversation",
72
+ "properties": {
73
+ "session_id": "sess_xyz"
74
+ },
75
+ "ai_data": {
76
+ "model": "claude-3",
77
+ "convo_id": "conv_abc",
78
+ "input": "I can't figure out how to export my data",
79
+ "output": "I'll help you export your data..."
80
+ }
81
+ }
82
+ ]
83
+ }
84
+ ```
85
+
86
+ ### `zignal_list_events`
87
+
88
+ List and search events with filters.
89
+
90
+ **Parameters:**
91
+ - `limit`: Number of events (1-100, default 50)
92
+ - `cursor`: Pagination cursor
93
+ - `user_id`: Filter by user
94
+ - `convo_id`: Filter by conversation
95
+ - `event`: Filter by event type
96
+ - `has_signals`: Filter events with/without signals
97
+ - `signal_type`: Filter by signal type (issue, risk, feedback)
98
+
99
+ ### `zignal_list_signals`
100
+
101
+ List detected signals across events.
102
+
103
+ **Parameters:**
104
+ - `limit`: Number of signals (1-1000, default 100)
105
+ - `type`: Filter by type (issue, risk, feedback, or all)
106
+ - `name`: Filter by signal name (partial match)
107
+
108
+ ## Signal Types
109
+
110
+ Events with `ai_data.input` and `ai_data.output` are automatically analyzed for:
111
+
112
+ | Signal | Type | Description |
113
+ |--------|------|-------------|
114
+ | User Frustration | issue | User expresses anger or dissatisfaction |
115
+ | Task Failure | issue | AI failed to complete the request |
116
+ | Escalation Needed | risk | Requires human intervention |
117
+ | Confusion | issue | User doesn't understand the response |
118
+ | Feature Request | feedback | User requests new capability |
119
+ | Positive Feedback | feedback | User expresses satisfaction |
120
+ | Bug Report | issue | User reports unexpected behavior |
121
+
122
+ ## Example Usage in Claude
123
+
124
+ Once configured, you can ask Claude:
125
+
126
+ > "Track this conversation in Zignal and check for any signals"
127
+
128
+ > "Show me the last 10 events where signals were detected"
129
+
130
+ > "List all user frustration signals from today"
131
+
132
+ Claude will use the Zignal MCP server to track conversations and retrieve analytics automatically.
133
+
134
+ ## Development
135
+
136
+ ```bash
137
+ # Install dependencies
138
+ npm install
139
+
140
+ # Build
141
+ npm run build
142
+
143
+ # Watch mode
144
+ npm run dev
145
+ ```
146
+
147
+ ## License
148
+
149
+ MIT
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,254 @@
1
+ #!/usr/bin/env node
2
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
3
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
+ import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
5
+ // Configuration from environment
6
+ const ZIGNAL_API_KEY = process.env.ZIGNAL_API_KEY;
7
+ const ZIGNAL_BASE_URL = process.env.ZIGNAL_BASE_URL || "https://kanshi-production.up.railway.app";
8
+ if (!ZIGNAL_API_KEY) {
9
+ console.error("Error: ZIGNAL_API_KEY environment variable is required");
10
+ process.exit(1);
11
+ }
12
+ // Helper function to make Zignal API requests
13
+ async function zignalRequest(method, path, body) {
14
+ const url = `${ZIGNAL_BASE_URL}${path}`;
15
+ const headers = {
16
+ Authorization: `Bearer ${ZIGNAL_API_KEY}`,
17
+ "Content-Type": "application/json",
18
+ };
19
+ const response = await fetch(url, {
20
+ method,
21
+ headers,
22
+ body: body ? JSON.stringify(body) : undefined,
23
+ });
24
+ if (!response.ok) {
25
+ const error = await response.text();
26
+ throw new Error(`Zignal API error (${response.status}): ${error}`);
27
+ }
28
+ return response.json();
29
+ }
30
+ // Create MCP server
31
+ const server = new Server({
32
+ name: "mcp-server-zignal",
33
+ version: "1.0.0",
34
+ }, {
35
+ capabilities: {
36
+ tools: {},
37
+ },
38
+ });
39
+ // List available tools
40
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
41
+ return {
42
+ tools: [
43
+ {
44
+ name: "zignal_create_events",
45
+ description: "Create one or more events in Zignal for AI signal classification. Use this to track conversations, user interactions, or AI completions. Events with ai_data (input/output) will be automatically analyzed for signals like user frustration, task failure, confusion, etc.",
46
+ inputSchema: {
47
+ type: "object",
48
+ properties: {
49
+ events: {
50
+ type: "array",
51
+ description: "Array of 1-100 events to create",
52
+ items: {
53
+ type: "object",
54
+ properties: {
55
+ user_id: {
56
+ type: "string",
57
+ description: "User identifier (email, user ID, or anonymous ID)",
58
+ },
59
+ event: {
60
+ type: "string",
61
+ description: 'Event type (e.g., "ai.conversation", "ai.completion")',
62
+ },
63
+ properties: {
64
+ type: "object",
65
+ description: "Custom metadata (session_id, page, plan, etc.)",
66
+ },
67
+ ai_data: {
68
+ type: "object",
69
+ description: "AI conversation data for signal detection",
70
+ properties: {
71
+ model: {
72
+ type: "string",
73
+ description: 'AI model name (e.g., "gpt-4", "claude-3")',
74
+ },
75
+ convo_id: {
76
+ type: "string",
77
+ description: "Conversation/thread ID",
78
+ },
79
+ input: {
80
+ type: "string",
81
+ description: "User's message or prompt",
82
+ },
83
+ output: {
84
+ type: "string",
85
+ description: "AI's response",
86
+ },
87
+ },
88
+ },
89
+ },
90
+ required: ["user_id", "event"],
91
+ },
92
+ },
93
+ },
94
+ required: ["events"],
95
+ },
96
+ },
97
+ {
98
+ name: "zignal_list_events",
99
+ description: "List and search events with optional filters. Use this to retrieve tracked conversations, filter by user, conversation ID, event type, or whether signals were detected.",
100
+ inputSchema: {
101
+ type: "object",
102
+ properties: {
103
+ limit: {
104
+ type: "number",
105
+ description: "Number of events to return (1-100, default 50)",
106
+ default: 50,
107
+ },
108
+ cursor: {
109
+ type: "string",
110
+ description: "Pagination cursor from previous response",
111
+ },
112
+ user_id: {
113
+ type: "string",
114
+ description: "Filter by user ID",
115
+ },
116
+ convo_id: {
117
+ type: "string",
118
+ description: "Filter by conversation ID",
119
+ },
120
+ event: {
121
+ type: "string",
122
+ description: "Filter by event type",
123
+ },
124
+ has_signals: {
125
+ type: "boolean",
126
+ description: "Filter events with/without signals",
127
+ },
128
+ signal_type: {
129
+ type: "string",
130
+ description: 'Filter by signal type ("issue", "risk", "feedback")',
131
+ },
132
+ },
133
+ },
134
+ },
135
+ {
136
+ name: "zignal_list_signals",
137
+ description: "List detected signals across all events. Signals represent important patterns like user frustration, task failures, feature requests, etc. Use this to monitor conversation quality and identify issues.",
138
+ inputSchema: {
139
+ type: "object",
140
+ properties: {
141
+ limit: {
142
+ type: "number",
143
+ description: "Number of signals to return (1-1000, default 100)",
144
+ default: 100,
145
+ },
146
+ type: {
147
+ type: "string",
148
+ description: 'Filter by signal type ("issue", "risk", "feedback", or "all")',
149
+ default: "all",
150
+ },
151
+ name: {
152
+ type: "string",
153
+ description: "Filter by signal name (partial match)",
154
+ },
155
+ },
156
+ },
157
+ },
158
+ ],
159
+ };
160
+ });
161
+ // Handle tool calls
162
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
163
+ const { name, arguments: args } = request.params;
164
+ try {
165
+ switch (name) {
166
+ case "zignal_create_events": {
167
+ const { events } = args;
168
+ const result = await zignalRequest("POST", "/v1/events", events);
169
+ return {
170
+ content: [
171
+ {
172
+ type: "text",
173
+ text: JSON.stringify(result, null, 2),
174
+ },
175
+ ],
176
+ };
177
+ }
178
+ case "zignal_list_events": {
179
+ const params = new URLSearchParams();
180
+ const { limit, cursor, user_id, convo_id, event, has_signals, signal_type, } = args;
181
+ if (limit)
182
+ params.append("limit", limit);
183
+ if (cursor)
184
+ params.append("cursor", cursor);
185
+ if (user_id)
186
+ params.append("user_id", user_id);
187
+ if (convo_id)
188
+ params.append("convo_id", convo_id);
189
+ if (event)
190
+ params.append("event", event);
191
+ if (has_signals !== undefined)
192
+ params.append("has_signals", String(has_signals));
193
+ if (signal_type)
194
+ params.append("signal_type", signal_type);
195
+ const queryString = params.toString();
196
+ const path = `/v1/events${queryString ? `?${queryString}` : ""}`;
197
+ const result = await zignalRequest("GET", path);
198
+ return {
199
+ content: [
200
+ {
201
+ type: "text",
202
+ text: JSON.stringify(result, null, 2),
203
+ },
204
+ ],
205
+ };
206
+ }
207
+ case "zignal_list_signals": {
208
+ const params = new URLSearchParams();
209
+ const { limit, type, name: signalName } = args;
210
+ if (limit)
211
+ params.append("limit", limit);
212
+ if (type)
213
+ params.append("type", type);
214
+ if (signalName)
215
+ params.append("name", signalName);
216
+ const queryString = params.toString();
217
+ const path = `/v1/signals${queryString ? `?${queryString}` : ""}`;
218
+ const result = await zignalRequest("GET", path);
219
+ return {
220
+ content: [
221
+ {
222
+ type: "text",
223
+ text: JSON.stringify(result, null, 2),
224
+ },
225
+ ],
226
+ };
227
+ }
228
+ default:
229
+ throw new Error(`Unknown tool: ${name}`);
230
+ }
231
+ }
232
+ catch (error) {
233
+ const errorMessage = error instanceof Error ? error.message : String(error);
234
+ return {
235
+ content: [
236
+ {
237
+ type: "text",
238
+ text: `Error: ${errorMessage}`,
239
+ },
240
+ ],
241
+ isError: true,
242
+ };
243
+ }
244
+ });
245
+ // Start server
246
+ async function main() {
247
+ const transport = new StdioServerTransport();
248
+ await server.connect(transport);
249
+ console.error("Zignal MCP server running on stdio");
250
+ }
251
+ main().catch((error) => {
252
+ console.error("Fatal error:", error);
253
+ process.exit(1);
254
+ });
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "mcp-server-zignal",
3
+ "version": "1.0.0",
4
+ "description": "MCP server for Zignal - AI agent analytics and signal detection",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "bin": {
8
+ "mcp-server-zignal": "dist/index.js"
9
+ },
10
+ "files": [
11
+ "dist",
12
+ "README.md",
13
+ "LICENSE"
14
+ ],
15
+ "scripts": {
16
+ "build": "tsc",
17
+ "dev": "tsc --watch",
18
+ "start": "node dist/index.js",
19
+ "prepublishOnly": "npm run build"
20
+ },
21
+ "keywords": [
22
+ "mcp",
23
+ "model-context-protocol",
24
+ "zignal",
25
+ "analytics",
26
+ "ai",
27
+ "signals",
28
+ "conversation-analytics",
29
+ "claude",
30
+ "anthropic"
31
+ ],
32
+ "author": "Zignal",
33
+ "license": "MIT",
34
+ "homepage": "https://zignal.dev",
35
+ "engines": {
36
+ "node": ">=18"
37
+ },
38
+ "dependencies": {
39
+ "@modelcontextprotocol/sdk": "^1.0.4"
40
+ },
41
+ "devDependencies": {
42
+ "@types/node": "^22.10.2",
43
+ "typescript": "^5.7.2"
44
+ }
45
+ }