sensor-tower-mcp-pro 1.2.10

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.
Files changed (47) hide show
  1. package/README.md +136 -0
  2. package/bin/sensortower-mcp.js +2 -0
  3. package/dist/client.d.ts +17 -0
  4. package/dist/client.d.ts.map +1 -0
  5. package/dist/client.js +100 -0
  6. package/dist/client.js.map +1 -0
  7. package/dist/config.d.ts +12 -0
  8. package/dist/config.d.ts.map +1 -0
  9. package/dist/config.js +142 -0
  10. package/dist/config.js.map +1 -0
  11. package/dist/index.d.ts +6 -0
  12. package/dist/index.d.ts.map +1 -0
  13. package/dist/index.js +88 -0
  14. package/dist/index.js.map +1 -0
  15. package/dist/tools/app-analysis.d.ts +580 -0
  16. package/dist/tools/app-analysis.d.ts.map +1 -0
  17. package/dist/tools/app-analysis.js +451 -0
  18. package/dist/tools/app-analysis.js.map +1 -0
  19. package/dist/tools/index.d.ts +10 -0
  20. package/dist/tools/index.d.ts.map +1 -0
  21. package/dist/tools/index.js +19 -0
  22. package/dist/tools/index.js.map +1 -0
  23. package/dist/tools/market-analysis.d.ts +391 -0
  24. package/dist/tools/market-analysis.d.ts.map +1 -0
  25. package/dist/tools/market-analysis.js +298 -0
  26. package/dist/tools/market-analysis.js.map +1 -0
  27. package/dist/tools/search.d.ts +162 -0
  28. package/dist/tools/search.d.ts.map +1 -0
  29. package/dist/tools/search.js +126 -0
  30. package/dist/tools/search.js.map +1 -0
  31. package/dist/tools/store-marketing.d.ts +200 -0
  32. package/dist/tools/store-marketing.d.ts.map +1 -0
  33. package/dist/tools/store-marketing.js +170 -0
  34. package/dist/tools/store-marketing.js.map +1 -0
  35. package/dist/tools/utilities.d.ts +76 -0
  36. package/dist/tools/utilities.d.ts.map +1 -0
  37. package/dist/tools/utilities.js +140 -0
  38. package/dist/tools/utilities.js.map +1 -0
  39. package/dist/tools/your-metrics.d.ts +140 -0
  40. package/dist/tools/your-metrics.d.ts.map +1 -0
  41. package/dist/tools/your-metrics.js +121 -0
  42. package/dist/tools/your-metrics.js.map +1 -0
  43. package/dist/utils.d.ts +7 -0
  44. package/dist/utils.d.ts.map +1 -0
  45. package/dist/utils.js +64 -0
  46. package/dist/utils.js.map +1 -0
  47. package/package.json +54 -0
package/README.md ADDED
@@ -0,0 +1,136 @@
1
+ # Sensor Tower MCP Server (npm)
2
+
3
+ A pure Node.js implementation of the Model Context Protocol server for Sensor Tower APIs. Access mobile app intelligence data directly in MCP-compatible tools like Cursor and Claude Desktop.
4
+
5
+ ## Features
6
+
7
+ - **App Intelligence** - Metadata, rankings, downloads, revenue estimates
8
+ - **Search & Discovery** - Find apps and publishers by name or description
9
+ - **Market Analysis** - Category rankings, featured apps, competitor insights
10
+ - **Multi-Token Failover** - Automatic switch to backup tokens when quota exhausted
11
+ - **No Python Required** - Pure Node.js implementation
12
+
13
+ ## Quick Start
14
+
15
+ ```bash
16
+ # Run directly with npx (recommended)
17
+ npx sensortower-mcp
18
+
19
+ # Or install globally
20
+ npm install -g sensortower-mcp
21
+ sensortower-mcp
22
+ ```
23
+
24
+ ## Requirements
25
+
26
+ - **Node.js 18+**
27
+ - Sensor Tower API token
28
+
29
+ ## MCP Configuration
30
+
31
+ ### Cursor / Claude Desktop
32
+
33
+ Add to your MCP settings:
34
+
35
+ ```json
36
+ {
37
+ "mcpServers": {
38
+ "sensortower": {
39
+ "command": "npx",
40
+ "args": ["-y", "sensortower-mcp"],
41
+ "env": {
42
+ "SENSOR_TOWER_API_TOKEN": "primary_token",
43
+ "SENSOR_TOWER_API_TOKEN_BACKUP": "backup_token"
44
+ }
45
+ }
46
+ }
47
+ }
48
+ ```
49
+
50
+ ## Multi-Token Failover
51
+
52
+ When a token's API quota is exhausted (429/403 error), the server automatically switches to the next available backup token. This ensures uninterrupted API access.
53
+
54
+ ### Environment Variables
55
+
56
+ | Variable | Description |
57
+ |----------|-------------|
58
+ | `SENSOR_TOWER_API_TOKEN` | Primary API token (required) |
59
+ | `SENSOR_TOWER_API_TOKEN_BACKUP` | First backup token |
60
+ | `SENSOR_TOWER_API_TOKEN_2` | Second backup token |
61
+ | `SENSOR_TOWER_API_TOKEN_3` | Third backup token (up to 10) |
62
+
63
+ ### Example with Multiple Tokens
64
+
65
+ ```bash
66
+ SENSOR_TOWER_API_TOKEN=token1 \
67
+ SENSOR_TOWER_API_TOKEN_BACKUP=token2 \
68
+ SENSOR_TOWER_API_TOKEN_2=token3 \
69
+ npx sensortower-mcp
70
+ ```
71
+
72
+ ## API Token
73
+
74
+ Get your API token from [Sensor Tower Account Settings](https://app.sensortower.com/users/edit/api-settings).
75
+
76
+ ## Available Tools
77
+
78
+ | Tool | Description |
79
+ |------|-------------|
80
+ | `get_app_metadata` | App details, ratings, categories |
81
+ | `search_entities` | Search apps and publishers |
82
+ | `get_category_rankings` | Top apps by category |
83
+ | `get_download_estimates` | Download trends and estimates |
84
+ | `get_revenue_estimates` | Revenue data and forecasts |
85
+ | `get_creatives` | Advertising creatives |
86
+ | `get_usage_active_users` | Active users data |
87
+ | `top_in_app_purchases` | Top in-app purchases |
88
+ | `version_history` | App version history |
89
+ | `get_country_codes` | Available country codes |
90
+ | `get_category_ids` | Platform category IDs |
91
+
92
+ ## Command Line Options
93
+
94
+ ```bash
95
+ npx sensortower-mcp [OPTIONS]
96
+
97
+ Options:
98
+ --transport <type> Transport type: stdio (default) or http
99
+ --port <port> HTTP port (default: 8666, only for http transport)
100
+ --token <token> API token (or set SENSOR_TOWER_API_TOKEN env var)
101
+ --backup-token <tok> Backup API token for failover
102
+ --help, -h Show help message
103
+ ```
104
+
105
+ ## Examples
106
+
107
+ ```bash
108
+ # Run with stdio transport (for MCP clients)
109
+ SENSOR_TOWER_API_TOKEN=your_token npx sensortower-mcp
110
+
111
+ # Run with HTTP transport
112
+ npx sensortower-mcp --transport http --port 8666
113
+ ```
114
+
115
+ ## Development
116
+
117
+ ```bash
118
+ # Install dependencies
119
+ npm install
120
+
121
+ # Build
122
+ npm run build
123
+
124
+ # Run locally
125
+ npm start
126
+ ```
127
+
128
+ ## Links
129
+
130
+ - [GitHub Repository](https://github.com/sensortower/sensortower-mcp)
131
+ - [Sensor Tower API Docs](https://docs.sensortower.com/)
132
+ - [Model Context Protocol](https://modelcontextprotocol.io/)
133
+
134
+ ## License
135
+
136
+ MIT License
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ require('../dist/index.js');
@@ -0,0 +1,17 @@
1
+ /**
2
+ * HTTP client for Sensor Tower API
3
+ */
4
+ export declare class SensorTowerClient {
5
+ private tokens;
6
+ private currentTokenIndex;
7
+ constructor(tokens: string[]);
8
+ private getAuthToken;
9
+ private switchToBackupToken;
10
+ getTokenStatus(): {
11
+ current: number;
12
+ total: number;
13
+ };
14
+ makeRequest<T>(endpoint: string, params: Record<string, any>): Promise<T>;
15
+ private sleep;
16
+ }
17
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,MAAM,CAAW;IACzB,OAAO,CAAC,iBAAiB,CAAa;gBAE1B,MAAM,EAAE,MAAM,EAAE;IAO5B,OAAO,CAAC,YAAY;IAIpB,OAAO,CAAC,mBAAmB;IAU3B,cAAc,IAAI;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE;IAO9C,WAAW,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAsE/E,OAAO,CAAC,KAAK;CAGd"}
package/dist/client.js ADDED
@@ -0,0 +1,100 @@
1
+ "use strict";
2
+ /**
3
+ * HTTP client for Sensor Tower API
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.SensorTowerClient = void 0;
7
+ const config_1 = require("./config");
8
+ class SensorTowerClient {
9
+ tokens;
10
+ currentTokenIndex = 0;
11
+ constructor(tokens) {
12
+ if (tokens.length === 0) {
13
+ throw new Error('At least one API token is required');
14
+ }
15
+ this.tokens = tokens;
16
+ }
17
+ getAuthToken() {
18
+ return this.tokens[this.currentTokenIndex];
19
+ }
20
+ switchToBackupToken() {
21
+ if (this.currentTokenIndex < this.tokens.length - 1) {
22
+ this.currentTokenIndex++;
23
+ console.error(`⚠️ Token #${this.currentTokenIndex} quota exceeded, switching to token #${this.currentTokenIndex + 1}`);
24
+ return true;
25
+ }
26
+ console.error(`❌ All ${this.tokens.length} tokens exhausted`);
27
+ return false;
28
+ }
29
+ getTokenStatus() {
30
+ return {
31
+ current: this.currentTokenIndex + 1,
32
+ total: this.tokens.length,
33
+ };
34
+ }
35
+ async makeRequest(endpoint, params) {
36
+ params.auth_token = this.getAuthToken();
37
+ let backoffMs = 500;
38
+ const maxAttempts = 5;
39
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
40
+ try {
41
+ const url = new URL(endpoint, config_1.API_BASE_URL);
42
+ Object.entries(params).forEach(([key, value]) => {
43
+ if (value !== undefined && value !== null) {
44
+ url.searchParams.append(key, String(value));
45
+ }
46
+ });
47
+ const response = await fetch(url.toString(), {
48
+ method: 'GET',
49
+ headers: {
50
+ 'Accept': 'application/json',
51
+ },
52
+ });
53
+ if (!response.ok) {
54
+ const statusCode = response.status;
55
+ // Check for quota/rate limit errors
56
+ let isQuotaError = statusCode === 429;
57
+ if (statusCode === 403) {
58
+ try {
59
+ const errorBody = await response.text();
60
+ const errorMessage = errorBody.toLowerCase();
61
+ isQuotaError = ['quota', 'limit', 'exceeded', 'rate'].some(keyword => errorMessage.includes(keyword));
62
+ }
63
+ catch {
64
+ // Ignore parse errors
65
+ }
66
+ }
67
+ // Try backup token on quota errors
68
+ if (isQuotaError && this.switchToBackupToken()) {
69
+ params.auth_token = this.getAuthToken();
70
+ console.error('Retrying request with backup token...');
71
+ continue;
72
+ }
73
+ // Retry on server errors
74
+ if ([429, 500, 502, 503, 504].includes(statusCode) && attempt < maxAttempts - 1) {
75
+ await this.sleep(backoffMs);
76
+ backoffMs = Math.min(backoffMs * 2, 8000);
77
+ continue;
78
+ }
79
+ throw new Error(`HTTP ${statusCode}: ${response.statusText}`);
80
+ }
81
+ return await response.json();
82
+ }
83
+ catch (error) {
84
+ if (attempt < maxAttempts - 1 && error instanceof TypeError) {
85
+ // Network error, retry
86
+ await this.sleep(backoffMs);
87
+ backoffMs = Math.min(backoffMs * 2, 8000);
88
+ continue;
89
+ }
90
+ throw error;
91
+ }
92
+ }
93
+ throw new Error('Max retry attempts exceeded');
94
+ }
95
+ sleep(ms) {
96
+ return new Promise(resolve => setTimeout(resolve, ms));
97
+ }
98
+ }
99
+ exports.SensorTowerClient = SensorTowerClient;
100
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Configuration for Sensor Tower MCP Server
3
+ */
4
+ export declare const API_BASE_URL: string;
5
+ export interface Config {
6
+ tokens: string[];
7
+ transport: 'stdio' | 'http';
8
+ port: number;
9
+ }
10
+ export declare function getConfig(): Config;
11
+ export declare function parseArgs(): Config;
12
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,eAAO,MAAM,YAAY,QAA4D,CAAC;AAEtF,MAAM,WAAW,MAAM;IACrB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,SAAS,EAAE,OAAO,GAAG,MAAM,CAAC;IAC5B,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,SAAS,IAAI,MAAM,CAclC;AA2BD,wBAAgB,SAAS,IAAI,MAAM,CA6ClC"}
package/dist/config.js ADDED
@@ -0,0 +1,142 @@
1
+ "use strict";
2
+ /**
3
+ * Configuration for Sensor Tower MCP Server
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.API_BASE_URL = void 0;
7
+ exports.getConfig = getConfig;
8
+ exports.parseArgs = parseArgs;
9
+ exports.API_BASE_URL = process.env.API_BASE_URL || 'https://api.sensortower.com';
10
+ function getConfig() {
11
+ const tokens = collectTokensFromEnv();
12
+ if (tokens.length === 0) {
13
+ console.error('Error: SENSOR_TOWER_API_TOKEN environment variable is required');
14
+ console.error('Get your API token from: https://app.sensortower.com/users/edit/api-settings');
15
+ process.exit(1);
16
+ }
17
+ return {
18
+ tokens,
19
+ transport: process.env.TRANSPORT || 'stdio',
20
+ port: parseInt(process.env.PORT || '8666', 10),
21
+ };
22
+ }
23
+ /**
24
+ * Collect all tokens from environment variables
25
+ * Supports: SENSOR_TOWER_API_TOKEN, SENSOR_TOWER_API_TOKEN_BACKUP,
26
+ * SENSOR_TOWER_API_TOKEN_2, SENSOR_TOWER_API_TOKEN_3, etc.
27
+ */
28
+ function collectTokensFromEnv() {
29
+ const tokens = [];
30
+ // Primary token
31
+ const primary = process.env.SENSOR_TOWER_API_TOKEN;
32
+ if (primary)
33
+ tokens.push(primary);
34
+ // Backup token (legacy support)
35
+ const backup = process.env.SENSOR_TOWER_API_TOKEN_BACKUP;
36
+ if (backup)
37
+ tokens.push(backup);
38
+ // Additional numbered tokens (2, 3, 4, ...)
39
+ for (let i = 2; i <= 10; i++) {
40
+ const token = process.env[`SENSOR_TOWER_API_TOKEN_${i}`];
41
+ if (token)
42
+ tokens.push(token);
43
+ }
44
+ return tokens;
45
+ }
46
+ function parseArgs() {
47
+ const args = process.argv.slice(2);
48
+ const tokens = [];
49
+ let transport = 'stdio';
50
+ let port = 8666;
51
+ // First collect from environment
52
+ tokens.push(...collectTokensFromEnv());
53
+ for (let i = 0; i < args.length; i++) {
54
+ switch (args[i]) {
55
+ case '--token':
56
+ // Primary token from CLI overrides env
57
+ const cliToken = args[++i];
58
+ if (cliToken && !tokens.includes(cliToken)) {
59
+ tokens.unshift(cliToken); // Add to front as primary
60
+ }
61
+ break;
62
+ case '--backup-token':
63
+ // Add backup token
64
+ const backupToken = args[++i];
65
+ if (backupToken && !tokens.includes(backupToken)) {
66
+ tokens.push(backupToken);
67
+ }
68
+ break;
69
+ case '--transport':
70
+ transport = args[++i];
71
+ break;
72
+ case '--port':
73
+ port = parseInt(args[++i] || '8666', 10);
74
+ break;
75
+ case '--help':
76
+ case '-h':
77
+ printHelp();
78
+ process.exit(0);
79
+ }
80
+ }
81
+ if (tokens.length === 0) {
82
+ console.error('Error: SENSOR_TOWER_API_TOKEN environment variable or --token argument is required');
83
+ console.error('Get your API token from: https://app.sensortower.com/users/edit/api-settings');
84
+ process.exit(1);
85
+ }
86
+ return { tokens, transport, port };
87
+ }
88
+ function printHelp() {
89
+ console.log(`
90
+ Sensor Tower MCP Server
91
+
92
+ A Model Context Protocol server for accessing Sensor Tower's mobile app intelligence APIs.
93
+
94
+ USAGE:
95
+ npx sensortower-mcp [OPTIONS]
96
+
97
+ OPTIONS:
98
+ --transport <type> Transport type: stdio (default) or http
99
+ --port <port> HTTP port (default: 8666, only for http transport)
100
+ --token <token> Primary API token (or set SENSOR_TOWER_API_TOKEN env var)
101
+ --backup-token <tok> Backup API token for failover (can use multiple times)
102
+ --help, -h Show this help message
103
+
104
+ ENVIRONMENT VARIABLES:
105
+ SENSOR_TOWER_API_TOKEN Primary API token
106
+ SENSOR_TOWER_API_TOKEN_BACKUP First backup token
107
+ SENSOR_TOWER_API_TOKEN_2 Second backup token
108
+ SENSOR_TOWER_API_TOKEN_3 Third backup token (up to 10)
109
+
110
+ TOKEN FAILOVER:
111
+ When a token's quota is exhausted (429/403 error), the server automatically
112
+ switches to the next available backup token. This ensures uninterrupted
113
+ API access across multiple tokens.
114
+
115
+ EXAMPLES:
116
+ # Run with single token
117
+ SENSOR_TOWER_API_TOKEN=token1 npx sensortower-mcp
118
+
119
+ # Run with multiple backup tokens
120
+ SENSOR_TOWER_API_TOKEN=token1 \\
121
+ SENSOR_TOWER_API_TOKEN_BACKUP=token2 \\
122
+ SENSOR_TOWER_API_TOKEN_2=token3 \\
123
+ npx sensortower-mcp
124
+
125
+ MCP CONFIGURATION (Cursor/Claude Desktop):
126
+ {
127
+ "mcpServers": {
128
+ "sensortower": {
129
+ "command": "npx",
130
+ "args": ["-y", "sensortower-mcp"],
131
+ "env": {
132
+ "SENSOR_TOWER_API_TOKEN": "primary_token",
133
+ "SENSOR_TOWER_API_TOKEN_BACKUP": "backup_token"
134
+ }
135
+ }
136
+ }
137
+ }
138
+
139
+ For more information: https://github.com/sensortower/sensortower-mcp
140
+ `);
141
+ }
142
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Sensor Tower MCP Server - Main entry point
4
+ */
5
+ export {};
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;GAEG"}
package/dist/index.js ADDED
@@ -0,0 +1,88 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ /**
4
+ * Sensor Tower MCP Server - Main entry point
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ const index_js_1 = require("@modelcontextprotocol/sdk/server/index.js");
8
+ const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
9
+ const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
10
+ const config_1 = require("./config");
11
+ const client_1 = require("./client");
12
+ const tools_1 = require("./tools");
13
+ async function main() {
14
+ const config = (0, config_1.parseArgs)();
15
+ console.error('🚀 Starting Sensor Tower MCP Server...');
16
+ console.error(`📡 Transport: ${config.transport}`);
17
+ console.error(`🔑 API Tokens configured: ${config.tokens.length} (auto-failover enabled)`);
18
+ // Create API client with all tokens
19
+ const client = new client_1.SensorTowerClient(config.tokens);
20
+ // Register all tools
21
+ const allTools = {
22
+ ...(0, tools_1.registerAppAnalysisTools)(client),
23
+ ...(0, tools_1.registerSearchTools)(client),
24
+ ...(0, tools_1.registerUtilityTools)(),
25
+ ...(0, tools_1.registerMarketAnalysisTools)(client),
26
+ ...(0, tools_1.registerStoreMarketingTools)(client),
27
+ ...(0, tools_1.registerYourMetricsTools)(client),
28
+ };
29
+ // Create MCP server
30
+ const server = new index_js_1.Server({
31
+ name: 'sensortower-mcp',
32
+ version: '1.2.10',
33
+ }, {
34
+ capabilities: {
35
+ tools: {},
36
+ },
37
+ });
38
+ // Handle list tools request
39
+ server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => {
40
+ return {
41
+ tools: Object.entries(allTools).map(([name, tool]) => ({
42
+ name,
43
+ description: tool.description,
44
+ inputSchema: tool.inputSchema,
45
+ })),
46
+ };
47
+ });
48
+ // Handle call tool request
49
+ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
50
+ const { name, arguments: args } = request.params;
51
+ const tool = allTools[name];
52
+ if (!tool) {
53
+ throw new Error(`Unknown tool: ${name}`);
54
+ }
55
+ try {
56
+ const result = await tool.handler(args || {});
57
+ return {
58
+ content: [
59
+ {
60
+ type: 'text',
61
+ text: JSON.stringify(result, null, 2),
62
+ },
63
+ ],
64
+ };
65
+ }
66
+ catch (error) {
67
+ const message = error instanceof Error ? error.message : String(error);
68
+ return {
69
+ content: [
70
+ {
71
+ type: 'text',
72
+ text: `Error: ${message}`,
73
+ },
74
+ ],
75
+ isError: true,
76
+ };
77
+ }
78
+ });
79
+ // Start server with stdio transport
80
+ const transport = new stdio_js_1.StdioServerTransport();
81
+ await server.connect(transport);
82
+ console.error('Sensor Tower MCP Server running on stdio');
83
+ }
84
+ main().catch((error) => {
85
+ console.error('Fatal error:', error);
86
+ process.exit(1);
87
+ });
88
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}