@dashtray/mcp-server 0.0.0-stage → 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/README.md CHANGED
@@ -1,3 +1,305 @@
1
- # Temporary Holding Version
1
+ # Dashtray MCP Server
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Model Context Protocol server for [Dashtray](https://dashtray.app) - send notifications to your phone from AI agents, build scripts, and automation tools.
4
+
5
+ ## Features
6
+
7
+ - **Single, focused tool:** `send_notification` - send alerts to your phone
8
+ - **No preset management:** Notifications are automatically logged in history
9
+ - **Auto-prefixed:** All notifications prefixed with "MCP - " for clarity
10
+ - **Rate-limited:** Per-plan limits (Starter 100/min, Pro 1000/min)
11
+ - **Secure:** SHA256-hashed API keys, bearer token auth
12
+ - **Lightweight:** Minimal dependencies, ~30KB bundle
13
+
14
+ ## Installation
15
+
16
+ ### Option 1: From npm
17
+
18
+ ```bash
19
+ npm install @dashtray/mcp-server
20
+ # or run directly:
21
+ npx @dashtray/mcp-server
22
+ ```
23
+
24
+ ### Option 2: From source
25
+
26
+ ```bash
27
+ git clone https://github.com/bhupeshpr25/dashtray.git
28
+ cd dashtray/packages/mcp-server
29
+ npm install
30
+ npm run build
31
+ ```
32
+
33
+ ## Setup
34
+
35
+ ### 1. Get Your API Key
36
+
37
+ 1. Open **Dashtray** on your phone
38
+ 2. Go to **Settings → Integrations → API Keys**
39
+ 3. Tap **Generate New Key**
40
+ 4. Give it a name (e.g., "Claude Desktop")
41
+ 5. **Copy the full key** (starts with `sk_test_` or `sk_live_`)
42
+ 6. Save it securely - you won't see it again
43
+
44
+ ### 2. Set Environment Variables
45
+
46
+ Create a `.env` file or export in your shell:
47
+
48
+ ```bash
49
+ export DASHTRAY_API_KEY="sk_test_your_key_here"
50
+ export DASHTRAY_API_ENDPOINT="https://api.dashtray.app" # Optional, uses default if omitted
51
+ ```
52
+
53
+ ### 3. Configure Your Agent
54
+
55
+ #### Claude Desktop
56
+
57
+ Edit `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows):
58
+
59
+ ```json
60
+ {
61
+ "mcpServers": {
62
+ "dashtray": {
63
+ "command": "npx",
64
+ "args": ["-y", "@dashtray/mcp-server"],
65
+ "env": {
66
+ "DASHTRAY_API_KEY": "sk_test_your_key_here",
67
+ "DASHTRAY_API_ENDPOINT": "https://api.dashtray.app"
68
+ }
69
+ }
70
+ }
71
+ }
72
+ ```
73
+
74
+ Or if installed from source, point `command` at `node` with the built path:
75
+
76
+ ```json
77
+ {
78
+ "mcpServers": {
79
+ "dashtray": {
80
+ "command": "node",
81
+ "args": ["/path/to/dashtray/packages/mcp-server/dist/index.js"],
82
+ "env": {
83
+ "DASHTRAY_API_KEY": "sk_test_your_key_here",
84
+ "DASHTRAY_API_ENDPOINT": "https://api.dashtray.app"
85
+ }
86
+ }
87
+ }
88
+ }
89
+ ```
90
+
91
+ Then restart Claude Desktop.
92
+
93
+ #### Cline
94
+
95
+ In your project's `.cline/config.json`:
96
+
97
+ ```json
98
+ {
99
+ "mcpServers": {
100
+ "dashtray": {
101
+ "command": "npx",
102
+ "args": ["-y", "@dashtray/mcp-server"],
103
+ "env": {
104
+ "DASHTRAY_API_KEY": "sk_test_your_key_here"
105
+ }
106
+ }
107
+ }
108
+ }
109
+ ```
110
+
111
+ #### Custom Agents
112
+
113
+ Start the server and connect via stdio:
114
+
115
+ ```javascript
116
+ import { ChildProcess, spawn } from "child_process";
117
+
118
+ const server = spawn("node", ["/path/to/dashtray/packages/mcp-server/dist/index.js"], {
119
+ env: {
120
+ ...process.env,
121
+ DASHTRAY_API_KEY: "sk_test_your_key_here",
122
+ },
123
+ });
124
+
125
+ // Connect to server via server.stdio
126
+ ```
127
+
128
+ ## Usage
129
+
130
+ ### Send a Notification
131
+
132
+ ```typescript
133
+ // The send_notification tool accepts:
134
+ {
135
+ "title": "Build Passed", // Required: notification title (max 255 chars)
136
+ "body": "Production build #42 completed in 3m 21s" // Required: details (max 1000 chars)
137
+ }
138
+ ```
139
+
140
+ ### Examples
141
+
142
+ **Build Alert:**
143
+ ```
144
+ Title: Build Failed
145
+ Body: Docker image build failed. Error: unauthorized. Check credentials.
146
+ ```
147
+
148
+ **Deployment Status:**
149
+ ```
150
+ Title: Deployment Complete
151
+ Body: App v1.2.3 deployed to production. 50 instances running, health check passed.
152
+ ```
153
+
154
+ **Test Results:**
155
+ ```
156
+ Title: Tests Passed
157
+ Body: All 342 tests passed. Coverage: 87%. Duration: 2m 15s.
158
+ ```
159
+
160
+ **Long-Running Task:**
161
+ ```
162
+ Title: Analysis Complete
163
+ Body: Dataset processed. 1.2M records. Anomalies: 3. Report: https://...
164
+ ```
165
+
166
+ ## API Reference
167
+
168
+ ### Tool: `send_notification`
169
+
170
+ **Description:** Send a notification to your Dashtray account. Notifications appear on your phone with "MCP - " prefix and are logged in history.
171
+
172
+ **Inputs:**
173
+ | Field | Type | Required | Max Length | Notes |
174
+ |-------|------|----------|-----------|-------|
175
+ | `title` | string | Yes | 255 | Notification title. Auto-prefixed with "MCP - " |
176
+ | `body` | string | Yes | 1000 | Notification details/body |
177
+
178
+ **Outputs:**
179
+ ```json
180
+ {
181
+ "success": true,
182
+ "message": "Notification sent successfully!\n\nTitle: Build Passed\nBody: ...\n\nIt will appear on your phone with the \"MCP - \" prefix..."
183
+ }
184
+ ```
185
+
186
+ **Errors:**
187
+ - `DASHTRAY_API_KEY not set` - Missing environment variable
188
+ - `Invalid input: title is required` - Missing or empty title
189
+ - `Invalid input: body must be 1000 chars or less` - Body too long
190
+ - `API error: 401 Unauthorized` - Invalid API key
191
+ - `API error: 429 Too Many Requests` - Rate limit exceeded
192
+ - `API error: 500 Internal Server Error` - Server error
193
+
194
+ ## Configuration
195
+
196
+ ### Environment Variables
197
+
198
+ | Variable | Required | Default | Description |
199
+ |----------|----------|---------|-------------|
200
+ | `DASHTRAY_API_KEY` | Yes | - | API key from Dashtray app |
201
+ | `DASHTRAY_API_ENDPOINT` | No | https://api.dashtray.app | Dashtray API URL (self-hosted or cloud) |
202
+
203
+ ### API Key Formats
204
+
205
+ - `sk_test_*` - Test key (development/staging, no rate limiting)
206
+ - `sk_live_*` - Live key (production, subject to rate limits)
207
+
208
+ ## Rate Limiting
209
+
210
+ Notifications are rate-limited per-plan:
211
+
212
+ | Plan | Limit | Window |
213
+ |------|-------|--------|
214
+ | Starter | 100/min | 1 minute sliding window |
215
+ | Pro | 1000/min | 1 minute sliding window |
216
+
217
+ When rate limit is exceeded, the API returns `429 Too Many Requests`.
218
+
219
+ ## Troubleshooting
220
+
221
+ ### "DASHTRAY_API_KEY environment variable is not set"
222
+
223
+ **Solution:** Set the environment variable in your shell or config file.
224
+
225
+ ```bash
226
+ export DASHTRAY_API_KEY="sk_test_..."
227
+ ```
228
+
229
+ ### "API error: 401 Unauthorized"
230
+
231
+ **Solution:** Check your API key:
232
+ 1. Open Dashtray app
233
+ 2. Go to Settings → Integrations → API Keys
234
+ 3. Verify the key is still active (hasn't been revoked)
235
+ 4. Generate a new key if needed
236
+
237
+ ### "API error: 429 Too Many Requests"
238
+
239
+ **Solution:** You've hit your rate limit for this plan. Either:
240
+ - Wait a minute and retry
241
+ - Upgrade your plan in the app
242
+ - Batch notifications together
243
+
244
+ ### "Failed to send notification: ECONNREFUSED"
245
+
246
+ **Solution:** Check that:
247
+ 1. `DASHTRAY_API_ENDPOINT` is correct
248
+ 2. The endpoint is reachable from your network
249
+ 3. No firewall is blocking the connection
250
+
251
+ ### Tool not appearing in Claude Desktop
252
+
253
+ **Solution:**
254
+ 1. Restart Claude Desktop completely
255
+ 2. Check `claude_desktop_config.json` is valid JSON
256
+ 3. Verify Node 18+ is installed (`node --version`) so `npx` can fetch the server
257
+
258
+ ### "Invalid input: title is required"
259
+
260
+ **Solution:** The title must be a non-empty string:
261
+
262
+ ```typescript
263
+ // ❌ Wrong
264
+ send_notification({ body: "Only body" })
265
+
266
+ // ✓ Right
267
+ send_notification({ title: "Alert", body: "Details" })
268
+ ```
269
+
270
+ ## Development
271
+
272
+ ### Build
273
+
274
+ ```bash
275
+ npm run build
276
+ ```
277
+
278
+ ### Watch Mode
279
+
280
+ ```bash
281
+ npm run watch
282
+ ```
283
+
284
+ ### Manual Testing
285
+
286
+ ```bash
287
+ export DASHTRAY_API_KEY="sk_test_..."
288
+ node dist/index.js
289
+ ```
290
+
291
+ Then send a test request (requires MCP client like Claude Desktop).
292
+
293
+ ## Support
294
+
295
+ - **Dashtray App Issues:** Settings → Help & Support
296
+ - **MCP Server Issues:** GitHub Issues
297
+ - **API Questions:** See [API Reference](https://docs.dashtray.app/api-reference/overview)
298
+
299
+ ## License
300
+
301
+ MIT
302
+
303
+ ---
304
+
305
+ **Dashtray MCP Server** - Minimal, focused, production-ready.
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Dashtray MCP Server
4
+ *
5
+ * Model Context Protocol server that provides a single tool:
6
+ * - send_notification: Send notifications to your phone via Dashtray
7
+ *
8
+ * Usage:
9
+ * - Local (stdio): node dist/index.js
10
+ * - Environment: Set DASHTRAY_API_KEY and DASHTRAY_API_ENDPOINT
11
+ *
12
+ * Configuration:
13
+ * - Get API key from: Dashtray app → Settings → Integrations → API Keys
14
+ * - Default endpoint: https://api.dashtray.app (or self-hosted)
15
+ *
16
+ * SDK notes (matches @modelcontextprotocol/sdk >= 1.x):
17
+ * - `Server` from `server/index.js`; the stdio transport lives in
18
+ * `server/stdio.js` and request schemas/types in `types.js`.
19
+ * - Handlers register against the exported request SCHEMAS (validated
20
+ * end-to-end by the SDK), not string method names.
21
+ */
22
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,211 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Dashtray MCP Server
4
+ *
5
+ * Model Context Protocol server that provides a single tool:
6
+ * - send_notification: Send notifications to your phone via Dashtray
7
+ *
8
+ * Usage:
9
+ * - Local (stdio): node dist/index.js
10
+ * - Environment: Set DASHTRAY_API_KEY and DASHTRAY_API_ENDPOINT
11
+ *
12
+ * Configuration:
13
+ * - Get API key from: Dashtray app → Settings → Integrations → API Keys
14
+ * - Default endpoint: https://api.dashtray.app (or self-hosted)
15
+ *
16
+ * SDK notes (matches @modelcontextprotocol/sdk >= 1.x):
17
+ * - `Server` from `server/index.js`; the stdio transport lives in
18
+ * `server/stdio.js` and request schemas/types in `types.js`.
19
+ * - Handlers register against the exported request SCHEMAS (validated
20
+ * end-to-end by the SDK), not string method names.
21
+ */
22
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
23
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
24
+ import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
25
+ import { z } from "zod";
26
+ /**
27
+ * Dashtray Notification Schema
28
+ * Matches POST /api/v1/notifications/send endpoint
29
+ */
30
+ // Limits match the backend's validateNotificationInput (title 1–200,
31
+ // body 1–500) exactly - rejecting early with a clear message beats letting
32
+ // the API 400 with a generic validation error.
33
+ const NotificationSchema = z.object({
34
+ title: z
35
+ .string()
36
+ .min(1, "Title is required")
37
+ .max(200, "Title must be 200 chars or less"),
38
+ body: z
39
+ .string()
40
+ .min(1, "Body is required")
41
+ .max(500, "Body must be 500 chars or less"),
42
+ });
43
+ /**
44
+ * Get API credentials from environment
45
+ */
46
+ function getApiCredentials() {
47
+ const apiKey = process.env.DASHTRAY_API_KEY;
48
+ if (!apiKey) {
49
+ throw new Error("DASHTRAY_API_KEY environment variable is not set. " +
50
+ "Get it from: Dashtray app → Settings → Integrations → API Keys");
51
+ }
52
+ const endpoint = process.env.DASHTRAY_API_ENDPOINT || "https://api.dashtray.app";
53
+ return { apiKey, endpoint };
54
+ }
55
+ /**
56
+ * Send notification to Dashtray
57
+ */
58
+ async function sendNotification(notification, apiKey, endpoint) {
59
+ const url = `${endpoint}/api/v1/notifications/send`;
60
+ try {
61
+ const response = await fetch(url, {
62
+ method: "POST",
63
+ headers: {
64
+ "Content-Type": "application/json",
65
+ Authorization: `Bearer ${apiKey}`,
66
+ },
67
+ body: JSON.stringify({
68
+ title: notification.title,
69
+ body: notification.body,
70
+ }),
71
+ });
72
+ if (!response.ok) {
73
+ const errorData = (await response.json().catch(() => ({})));
74
+ return {
75
+ ok: false,
76
+ error: `API error: ${response.status} ${response.statusText}. ${errorData.error || ""}`,
77
+ };
78
+ }
79
+ const data = (await response.json());
80
+ return {
81
+ ok: true,
82
+ data: data.data || { ...notification, id: "sent", createdAt: Date.now() },
83
+ };
84
+ }
85
+ catch (error) {
86
+ return {
87
+ ok: false,
88
+ error: `Failed to send notification: ${error instanceof Error ? error.message : String(error)}`,
89
+ };
90
+ }
91
+ }
92
+ /**
93
+ * MCP Server Main
94
+ */
95
+ async function main() {
96
+ const { apiKey, endpoint } = getApiCredentials();
97
+ const server = new Server({
98
+ name: "dashtray",
99
+ version: "1.0.0",
100
+ }, {
101
+ capabilities: {
102
+ tools: {},
103
+ },
104
+ });
105
+ // Define the send_notification tool
106
+ const sendNotificationTool = {
107
+ name: "send_notification",
108
+ description: "Send a notification to your Dashtray account. " +
109
+ "Notifications appear on your phone with 'MCP - ' prefix and are also logged in history. " +
110
+ "Perfect for build alerts, deployment updates, workflow notifications, etc.",
111
+ inputSchema: {
112
+ type: "object",
113
+ properties: {
114
+ title: {
115
+ type: "string",
116
+ description: "Short notification title (max 200 chars). Will be prefixed with 'MCP - ' in the app.",
117
+ examples: [
118
+ "Build Complete",
119
+ "Deployment Failed",
120
+ "Test Suite Passed",
121
+ ],
122
+ },
123
+ body: {
124
+ type: "string",
125
+ description: "Notification body/details (max 500 chars). Can include status, error details, links, etc.",
126
+ examples: [
127
+ "Build succeeded in 2m 15s. Ready to deploy.",
128
+ "E2E tests failed on 3 files. See logs for details.",
129
+ ],
130
+ },
131
+ },
132
+ required: ["title", "body"],
133
+ },
134
+ };
135
+ // Register tools/list handler (schema-based, per current SDK contract)
136
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
137
+ return {
138
+ tools: [sendNotificationTool],
139
+ };
140
+ });
141
+ // Handle tool calls
142
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
143
+ if (request.params.name !== "send_notification") {
144
+ return {
145
+ content: [
146
+ {
147
+ type: "text",
148
+ text: `Unknown tool: ${request.params.name}`,
149
+ },
150
+ ],
151
+ isError: true,
152
+ };
153
+ }
154
+ try {
155
+ // Validate input
156
+ const args = request.params.arguments;
157
+ const validated = NotificationSchema.parse({
158
+ title: args.title,
159
+ body: args.body,
160
+ });
161
+ // Send to Dashtray
162
+ const result = await sendNotification(validated, apiKey, endpoint);
163
+ if (!result.ok) {
164
+ return {
165
+ content: [
166
+ {
167
+ type: "text",
168
+ text: `Error sending notification: ${result.error}`,
169
+ },
170
+ ],
171
+ isError: true,
172
+ };
173
+ }
174
+ // Success response
175
+ return {
176
+ content: [
177
+ {
178
+ type: "text",
179
+ text: `Notification sent successfully!\n\nTitle: ${result.data?.title}\nBody: ${result.data?.body}\n\nIt will appear on your phone with the "MCP - " prefix and also be logged in your Dashtray history.`,
180
+ },
181
+ ],
182
+ };
183
+ }
184
+ catch (error) {
185
+ const message = error instanceof z.ZodError
186
+ ? `Invalid input: ${error.issues.map((e) => `${e.path.join(".")}: ${e.message}`).join(", ")}`
187
+ : error instanceof Error
188
+ ? error.message
189
+ : String(error);
190
+ return {
191
+ content: [
192
+ {
193
+ type: "text",
194
+ text: `Error: ${message}`,
195
+ },
196
+ ],
197
+ isError: true,
198
+ };
199
+ }
200
+ });
201
+ // Start server with stdio transport
202
+ const transport = new StdioServerTransport();
203
+ await server.connect(transport);
204
+ console.error("Dashtray MCP Server started");
205
+ console.error(`Using endpoint: ${endpoint}`);
206
+ console.error("Listening on stdio...");
207
+ }
208
+ main().catch((error) => {
209
+ console.error("Fatal error:", error);
210
+ process.exit(1);
211
+ });
package/package.json CHANGED
@@ -1,6 +1,53 @@
1
1
  {
2
2
  "name": "@dashtray/mcp-server",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "1.0.0",
4
+ "description": "Dashtray MCP Server - send notifications to your phone via MCP agents",
5
+ "type": "module",
6
+ "bin": {
7
+ "dashtray-mcp": "./dist/index.js"
8
+ },
9
+ "exports": {
10
+ ".": {
11
+ "import": "./dist/index.js",
12
+ "types": "./dist/index.d.ts"
13
+ }
14
+ },
15
+ "main": "./dist/index.js",
16
+ "types": "./dist/index.d.ts",
17
+ "files": [
18
+ "dist",
19
+ "README.md"
20
+ ],
21
+ "keywords": [
22
+ "mcp",
23
+ "model-context-protocol",
24
+ "notifications",
25
+ "dashtray",
26
+ "agents"
27
+ ],
28
+ "author": "Dashtray",
29
+ "license": "MIT",
30
+ "repository": {
31
+ "type": "git",
32
+ "url": "git+https://github.com/bhupeshpr25/dashtray.git",
33
+ "directory": "packages/mcp-server"
34
+ },
35
+ "homepage": "https://dashtray.app",
36
+ "bugs": "https://github.com/bhupeshpr25/dashtray/issues",
37
+ "dependencies": {
38
+ "@modelcontextprotocol/sdk": "^1.0.0",
39
+ "zod": "^4.4.3"
40
+ },
41
+ "devDependencies": {
42
+ "@types/node": "^24.3.0",
43
+ "typescript": "^5.4.0"
44
+ },
45
+ "engines": {
46
+ "node": ">=18.0.0"
47
+ },
48
+ "scripts": {
49
+ "build": "tsc",
50
+ "dev": "node dist/index.js",
51
+ "watch": "tsc --watch"
52
+ }
6
53
  }