@upstash/mcp-server 0.0.7 โ 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/README.md +87 -19
- package/dist/index.js +7 -12
- package/dist/index.js.map +1 -1
- package/package.json +1 -47
package/README.md
CHANGED
|
@@ -4,41 +4,109 @@
|
|
|
4
4
|
|
|
5
5
|
Model Context Protocol (MCP) is a [new, standardized protocol](https://modelcontextprotocol.io/introduction) for managing context between large language models (LLMs) and external systems. In this repository, we provide an installer as well as an MCP Server for [Upstash Developer API's](https://upstash.com/docs/devops/developer-api).
|
|
6
6
|
|
|
7
|
-
This
|
|
7
|
+
This allows you to use any MCP Client to interact with your Upstash account using natural language, e.g.:
|
|
8
8
|
|
|
9
9
|
- "Create a new Redis database in us-east-1"
|
|
10
|
-
- "List
|
|
11
|
-
- "
|
|
10
|
+
- "List my databases"
|
|
11
|
+
- "List keys starting with "user:" in users-db"
|
|
12
12
|
- "Create a backup"
|
|
13
|
-
- "Give me the spikes in throughput
|
|
13
|
+
- "Give me the spikes in throughput during the last 7 days"
|
|
14
14
|
|
|
15
15
|
# Usage
|
|
16
16
|
|
|
17
17
|
## Requirements
|
|
18
18
|
|
|
19
19
|
- Node.js >= v18.0.0
|
|
20
|
-
- Claude Desktop
|
|
21
20
|
- [Upstash API key](https://upstash.com/docs/devops/developer-api) - You can create one from [here](https://console.upstash.com/account/api).
|
|
22
21
|
|
|
23
22
|
## How to use locally
|
|
24
23
|
|
|
25
|
-
### Installing
|
|
24
|
+
### Installing for Claude Desktop
|
|
26
25
|
|
|
27
|
-
To install Upstash for Claude Desktop automatically via [Smithery](https://smithery.ai/server/@upstash/mcp-server):
|
|
26
|
+
To install Upstash MCP Server for Claude Desktop automatically via [Smithery](https://smithery.ai/server/@upstash/mcp-server) run the following command:
|
|
28
27
|
|
|
29
28
|
```bash
|
|
30
|
-
npx -y @smithery/cli install @upstash/mcp-server --client claude
|
|
29
|
+
npx -y @smithery/cli@latest install @upstash/mcp-server --client claude
|
|
31
30
|
```
|
|
32
31
|
|
|
33
|
-
|
|
32
|
+
<details>
|
|
33
|
+
<summary>Install without Smithery</summary>
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
npx @upstash/mcp-server init <UPSTASH_EMAIL> <UPSTASH_API_KEY>
|
|
37
|
+
```
|
|
34
38
|
|
|
35
|
-
|
|
36
|
-
2. Restart Claude Desktop
|
|
37
|
-
3. You should now be able to use Upstash commands in Claude Desktop
|
|
39
|
+
This will edit your MCP config file and add an entry for Upstash.
|
|
38
40
|
|
|
39
|
-
|
|
41
|
+
</details>
|
|
42
|
+
|
|
43
|
+
### Installing for Cursor
|
|
44
|
+
|
|
45
|
+
To install Upstash MCP Server for Cursor automatically via [Smithery](https://smithery.ai/server/@upstash/mcp-server) run the following command:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
npx -y @smithery/cli@latest install @upstash/mcp-server --client cursor
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
<details>
|
|
52
|
+
<summary>Install without Smithery</summary>
|
|
53
|
+
|
|
54
|
+
Add the following command to the MCP config in Cursor. For more info, check the [Cursor MCP docs](https://docs.cursor.com/context/model-context-protocol#configuring-mcp-servers).
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
npx -y @upstash/mcp-server run <UPSTASH_EMAIL> <UPSTASH_API_KEY>
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
</details>
|
|
61
|
+
|
|
62
|
+
### Installing for Windsurf
|
|
40
63
|
|
|
41
|
-
|
|
64
|
+
To install Upstash MCP Server for Windsurf automatically via [Smithery](https://smithery.ai/server/@upstash/mcp-server) run the following command:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
npx -y @smithery/cli@latest install @upstash/mcp-server --client windsurf
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
<details>
|
|
71
|
+
<summary>Install without Smithery</summary>
|
|
72
|
+
|
|
73
|
+
Add the following command to the MCP config in Windsurf. For more info, check out the [Windsurf MCP docs](https://docs.windsurf.com/windsurf/mcp#mcp-config-json).
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
npx -y @upstash/mcp-server run <UPSTASH_EMAIL> <UPSTASH_API_KEY>
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
</details>
|
|
80
|
+
|
|
81
|
+
### Running with Docker
|
|
82
|
+
|
|
83
|
+
You can also use the provided Docker image to run the server.
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
docker build -t upstash-mcp .
|
|
87
|
+
|
|
88
|
+
# Run the stdio server, add this command to you MCP config
|
|
89
|
+
docker run --rm -i \
|
|
90
|
+
-e UPSTASH_EMAIL=<UPSTASH_EMAIL> \
|
|
91
|
+
-e UPSTASH_API_KEY=<UPSTASH_API_KEY> \
|
|
92
|
+
upstash-mcp
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Troubleshooting
|
|
96
|
+
|
|
97
|
+
#### Common Issues
|
|
98
|
+
|
|
99
|
+
Your mcp client might have trouble finding the right binaries because of the differences between your shell and system `PATH`.
|
|
100
|
+
|
|
101
|
+
To fix this, you can get the full path of the binaries by running `which npx` or `which docker` in your shell, and replace the `npx` or `docker` command in the MCP config with the full binary path.
|
|
102
|
+
|
|
103
|
+
#### Node Version Manager
|
|
104
|
+
|
|
105
|
+
If you are using a node version manager like nvm or fnm, please check [this issue](https://github.com/modelcontextprotocol/servers/issues/64#issuecomment-2530337743). You should change the `node` command in the MCP config to the absolute path of the node binary.
|
|
106
|
+
|
|
107
|
+
#### Additional Troubleshooting
|
|
108
|
+
|
|
109
|
+
See the [troubleshooting guide](https://modelcontextprotocol.io/quickstart#troubleshooting) in the MCP documentation. You can also reach out to us at [Discord](https://discord.com/invite/w9SenAtbme).
|
|
42
110
|
|
|
43
111
|
## Tools
|
|
44
112
|
|
|
@@ -65,8 +133,8 @@ See the [troubleshooting guide](https://modelcontextprotocol.io/quickstart#troub
|
|
|
65
133
|
Clone the project and run:
|
|
66
134
|
|
|
67
135
|
```bash
|
|
68
|
-
|
|
69
|
-
|
|
136
|
+
pnpm install
|
|
137
|
+
pnpm run watch
|
|
70
138
|
```
|
|
71
139
|
|
|
72
140
|
This will continuously build the project and watch for changes.
|
|
@@ -85,7 +153,7 @@ This will be used for setting the Claude config and running mcp inspector.
|
|
|
85
153
|
To install the Claude Desktop config for local development, run the following command:
|
|
86
154
|
|
|
87
155
|
```bash
|
|
88
|
-
|
|
156
|
+
pnpm run setup
|
|
89
157
|
```
|
|
90
158
|
|
|
91
159
|
This will add an `upstash` entry to your MCP config file that points to the local build of the package.
|
|
@@ -106,7 +174,7 @@ You can now use Claude Desktop to run Upstash commands.
|
|
|
106
174
|
To view the logs from the MCP Server in real time, run the following command:
|
|
107
175
|
|
|
108
176
|
```bash
|
|
109
|
-
|
|
177
|
+
pnpm run logs
|
|
110
178
|
```
|
|
111
179
|
|
|
112
180
|
### Testing with MCP Inspector
|
|
@@ -114,5 +182,5 @@ npm run logs
|
|
|
114
182
|
You can also use the MCP Inspector to test the tools.
|
|
115
183
|
|
|
116
184
|
```bash
|
|
117
|
-
|
|
185
|
+
pnpm run inspector
|
|
118
186
|
```
|
package/dist/index.js
CHANGED
|
@@ -625,7 +625,7 @@ var envEmail = process.env.UPSTASH_EMAIL;
|
|
|
625
625
|
var USAGE_GENERAL = `Usage: npx @upstash/mcp-server (init|run) <UPSTASH_EMAIL> <UPSTASH_API_KEY>`;
|
|
626
626
|
var USAGE_RUN = `Usage: npx @upstash/mcp-server run <UPSTASH_EMAIL> <UPSTASH_API_KEY>`;
|
|
627
627
|
var USAGE_INIT = `Usage: npx @upstash/mcp-server init <UPSTASH_EMAIL> <UPSTASH_API_KEY>`;
|
|
628
|
-
function parseArguments() {
|
|
628
|
+
async function parseArguments() {
|
|
629
629
|
const [cmd, ...args] = process.argv.slice(2);
|
|
630
630
|
if (!cmd) throw new Error(USAGE_GENERAL);
|
|
631
631
|
else if (cmd === "init") {
|
|
@@ -637,8 +637,8 @@ function parseArguments() {
|
|
|
637
637
|
if (!finalEmail) throw new Error(`Missing email. ${USAGE_INIT}`);
|
|
638
638
|
config.apiKey = finalApiKey;
|
|
639
639
|
config.email = finalEmail;
|
|
640
|
-
testConnection();
|
|
641
|
-
init({
|
|
640
|
+
await testConnection();
|
|
641
|
+
await init({
|
|
642
642
|
executablePath: process.argv[1]
|
|
643
643
|
});
|
|
644
644
|
} else if (cmd === "run") {
|
|
@@ -651,11 +651,8 @@ function parseArguments() {
|
|
|
651
651
|
log("Starting MCP server");
|
|
652
652
|
config.apiKey = finalApiKey;
|
|
653
653
|
config.email = finalEmail;
|
|
654
|
-
testConnection();
|
|
655
|
-
main()
|
|
656
|
-
console.error("Server error:", error);
|
|
657
|
-
process.exit(1);
|
|
658
|
-
});
|
|
654
|
+
await testConnection();
|
|
655
|
+
await main();
|
|
659
656
|
} else {
|
|
660
657
|
throw new Error(`Unknown command: ${cmd}. Expected 'init' or 'run'. ${USAGE_GENERAL}`);
|
|
661
658
|
}
|
|
@@ -664,11 +661,9 @@ async function main() {
|
|
|
664
661
|
const transport = new StdioServerTransport();
|
|
665
662
|
await server.connect(transport);
|
|
666
663
|
}
|
|
667
|
-
|
|
668
|
-
parseArguments();
|
|
669
|
-
} catch (error) {
|
|
664
|
+
parseArguments().catch((error) => {
|
|
670
665
|
if (!(error instanceof Error)) throw error;
|
|
671
666
|
console.error(error.message);
|
|
672
667
|
process.exit(1);
|
|
673
|
-
}
|
|
668
|
+
});
|
|
674
669
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/init.ts","../src/log.ts","../src/config.ts","../src/server.ts","../src/tools/utils.ts","../src/tools/redis/backup.ts","../src/middlewares.ts","../src/http.ts","../src/tools/redis/command.ts","../src/tools/redis/db.ts","../src/utils.ts","../src/tools/redis/index.ts","../src/tools/index.ts","../src/tool.ts","../src/settings.ts","../src/test-connection.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { init } from \"./init\";\nimport { log } from \"./log\";\nimport { server } from \"./server\";\nimport { config } from \"./config\";\nimport \"dotenv/config\";\nimport { testConnection } from \"./test-connection\";\n\nprocess.on(\"uncaughtException\", (error) => {\n log(\"Uncaught exception:\", error.name, error.message, error.stack);\n});\n\nprocess.on(\"unhandledRejection\", (error) => {\n if (error instanceof Error) log(\"Unhandled rejection:\", error.name, error.message, error.stack);\n else log(\"Unhandled rejection:\", error);\n});\n\nconst envApiKey = process.env.UPSTASH_API_KEY;\nconst envEmail = process.env.UPSTASH_EMAIL;\n\nconst USAGE_GENERAL = `Usage: npx @upstash/mcp-server (init|run) <UPSTASH_EMAIL> <UPSTASH_API_KEY>`;\nconst USAGE_RUN = `Usage: npx @upstash/mcp-server run <UPSTASH_EMAIL> <UPSTASH_API_KEY>`;\nconst USAGE_INIT = `Usage: npx @upstash/mcp-server init <UPSTASH_EMAIL> <UPSTASH_API_KEY>`;\n\nfunction parseArguments() {\n const [cmd, ...args] = process.argv.slice(2);\n if (!cmd) throw new Error(USAGE_GENERAL);\n else if (cmd === \"init\") {\n const [email, apiKey, ...rest] = args;\n const finalApiKey = apiKey || envApiKey;\n const finalEmail = email || envEmail;\n\n if (rest.length > 0) throw new Error(`Too many arguments. ${USAGE_INIT}`);\n if (!finalApiKey) throw new Error(`Missing API key. ${USAGE_INIT}`);\n if (!finalEmail) throw new Error(`Missing email. ${USAGE_INIT}`);\n\n config.apiKey = finalApiKey;\n config.email = finalEmail;\n\n testConnection();\n\n init({\n executablePath: process.argv[1],\n });\n } else if (cmd === \"run\") {\n const [email, apiKey, ...rest] = args;\n const finalApiKey = apiKey || envApiKey;\n const finalEmail = email || envEmail;\n\n if (!finalApiKey) throw new Error(`Missing API key. ${USAGE_RUN}`);\n if (!finalEmail) throw new Error(`Missing email. ${USAGE_RUN}`);\n if (rest.length > 0) throw new Error(`Too many arguments. ${USAGE_RUN}`);\n log(\"Starting MCP server\");\n\n config.apiKey = finalApiKey;\n config.email = finalEmail;\n\n testConnection();\n\n // Start the server\n main().catch((error) => {\n console.error(\"Server error:\", error);\n process.exit(1);\n });\n } else {\n throw new Error(`Unknown command: ${cmd}. Expected 'init' or 'run'. ${USAGE_GENERAL}`);\n }\n}\n\nasync function main() {\n const transport = new StdioServerTransport();\n await server.connect(transport);\n}\n\ntry {\n parseArguments();\n} catch (error) {\n if (!(error instanceof Error)) throw error;\n console.error(error.message);\n process.exit(1);\n}\n","/* eslint-disable unicorn/prefer-node-protocol */\nimport path from \"path\";\nimport os from \"os\";\nimport fs from \"fs\";\nimport chalk from \"chalk\";\n\nimport { log } from \"./log\";\nimport { config } from \"./config\";\n\nconst claudeConfigPath = path.join(\n os.homedir(),\n \"Library\",\n \"Application Support\",\n \"Claude\",\n \"claude_desktop_config.json\"\n);\n\nconst UPSTASH_MCP_KEY = \"upstash\";\n\nexport async function init({ executablePath }: { executablePath: string }) {\n const isLocal = executablePath.includes(\"dist/index.js\");\n const upstashConfig = isLocal\n ? {\n command: \"node\",\n args: [executablePath, \"run\", config.email, config.apiKey],\n }\n : {\n command: \"npx\",\n args: [\"-y\", \"@upstash/mcp-server\", \"run\", config.email, config.apiKey],\n };\n\n const configDir = path.dirname(claudeConfigPath);\n if (!fs.existsSync(configDir)) {\n log(chalk.blue(\"Creating Claude config directory...\"));\n fs.mkdirSync(configDir, { recursive: true });\n }\n\n const existingConfig = fs.existsSync(claudeConfigPath)\n ? (JSON.parse(fs.readFileSync(claudeConfigPath, \"utf8\")) as {\n mcpServers?: Record<string, unknown>;\n })\n : { mcpServers: {} };\n\n if (UPSTASH_MCP_KEY in (existingConfig?.mcpServers || {})) {\n log(chalk.yellow(\"Upstash entry already exists. Overriding it.\"));\n }\n\n if (isLocal) {\n log(\n chalk.yellow(\n \"Local executable detected. Using 'node' and absolute path instead of 'npx' for development.\"\n )\n );\n }\n\n const newConfig = {\n ...existingConfig,\n mcpServers: {\n ...existingConfig.mcpServers,\n [UPSTASH_MCP_KEY]: upstashConfig,\n },\n };\n\n fs.writeFileSync(claudeConfigPath, JSON.stringify(newConfig, null, 2));\n\n log(\n chalk.blue(\n \"\\n\" +\n JSON.stringify(\n {\n [UPSTASH_MCP_KEY]: upstashConfig,\n },\n null,\n 2\n ).replaceAll(config.apiKey, \"********\")\n )\n );\n log(chalk.green(`Config written to: \"${claudeConfigPath.replace(os.homedir(), \"~\")}\"`));\n}\n","export function log(...args: unknown[]) {\n const msg = `[DEBUG ${new Date().toISOString()}] ${args.map((arg) => (typeof arg === \"string\" ? arg : JSON.stringify(arg))).join(\" \")}\\n`;\n process.stderr.write(msg);\n}\n","export const config = {\n apiKey: \"\",\n email: \"\",\n};\n","import { Server } from \"@modelcontextprotocol/sdk/server/index.js\";\nimport { ListToolsRequestSchema, CallToolRequestSchema } from \"@modelcontextprotocol/sdk/types.js\";\nimport { log } from \"./log\";\nimport { tools } from \"./tools\";\nimport { convertToTools, handlerResponseToCallResult } from \"./tool\";\n\nexport const server = new Server(\n { name: \"upstash\", version: \"0.1.0\" },\n { capabilities: { tools: {} } }\n);\n\nconst toolsList = convertToTools(tools);\n\nserver.setRequestHandler(ListToolsRequestSchema, async () => {\n log(\"Received list tools request\", toolsList);\n return { tools: toolsList };\n});\n\nserver.setRequestHandler(CallToolRequestSchema, async (request) => {\n const toolName = request.params.name;\n log(\"< received tool call:\", toolName, request.params.arguments);\n try {\n if (toolName in tools) {\n const tool = tools[toolName];\n const result = await tool.handler(request.params.arguments);\n\n const response = handlerResponseToCallResult(result);\n log(\"> tool result:\", response.content.map((item) => item.text).join(\"\\n\"));\n\n return response;\n }\n throw new Error(`Unknown tool: ${toolName}`);\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error);\n log(\"> error in tool call:\", msg);\n return {\n content: [\n {\n type: \"text\",\n text: `Error: ${msg}`,\n },\n ],\n isError: true,\n };\n }\n});\n","import { z } from \"zod\";\nimport { tool } from \".\";\n\nexport const utilTools = {\n timestamps_to_date: tool({\n description: `Use this tool to convert a timestamp to a human-readable date`,\n inputSchema: z.object({\n timestamps: z.array(z.number()).describe(\"Array of timestamps to convert\"),\n }),\n handler: async ({ timestamps }) => {\n return timestamps.map((timestamp) => new Date(timestamp).toUTCString());\n },\n }),\n}","import { z } from \"zod\";\nimport { json, tool } from \"..\";\nimport { http } from \"../../http\";\nimport type { RedisBackup } from \"./types\";\n\nexport const redisBackupTools = {\n redis_database_create_backup: tool({\n description: `Create a backup of a specific Upstash redis database.\nNOTE: Ask user to choose a name for the backup`,\n inputSchema: z.object({\n database_id: z.string().describe(\"The ID of the database to create a backup for.\"),\n backup_name: z.string().describe(\"A name for the backup.\"),\n }),\n handler: async ({ database_id, backup_name }) => {\n await http.post([\"v2/redis/create-backup\", database_id], {\n name: backup_name,\n });\n\n return \"OK\";\n },\n }),\n\n redis_database_delete_backup: tool({\n description: `Delete a backup of a specific Upstash redis database.`,\n inputSchema: z.object({\n database_id: z.string().describe(\"The ID of the database to delete a backup from.\"),\n backup_id: z.string().describe(\"The ID of the backup to delete.\"),\n }),\n handler: async ({ database_id, backup_id }) => {\n await http.delete([\"v2/redis/delete-backup\", database_id, backup_id]);\n\n return \"OK\";\n },\n }),\n\n redis_database_restore_backup: tool({\n description: `Restore a backup of a specific Upstash redis database. A backup can only be restored to the same database it was created from.`,\n inputSchema: z.object({\n database_id: z.string().describe(\"The ID of the database to restore a backup to.\"),\n backup_id: z.string().describe(\"The ID of the backup to restore.\"),\n }),\n handler: async ({ database_id, backup_id }) => {\n await http.post([\"v2/redis/restore-backup\", database_id], {\n backup_id,\n });\n\n return \"OK\";\n },\n }),\n\n redis_database_list_backups: tool({\n // TODO: Add explanation for fields\n // TODO: Is this in bytes?\n description: `List all backups of a specific Upstash redis database.`,\n inputSchema: z.object({\n database_id: z.string().describe(\"The ID of the database to list backups for.\"),\n }),\n handler: async ({ database_id }) => {\n const backups = await http.get<RedisBackup[]>([\"v2/redis/list-backup\", database_id]);\n\n return json(backups);\n },\n }),\n\n redis_database_set_daily_backup: tool({\n description: `Enable or disable daily backups for a specific Upstash redis database.`,\n inputSchema: z.object({\n database_id: z\n .string()\n .describe(\"The ID of the database to enable or disable daily backups for.\"),\n enable: z.boolean().describe(\"Whether to enable or disable daily backups.\"),\n }),\n handler: async ({ database_id, enable }) => {\n await http.patch([\n `v2/redis/${enable ? \"enable-dailybackup\" : \"disable-dailybackup\"}`,\n database_id,\n ]);\n\n return \"OK\";\n },\n }),\n};\n","import type { UpstashRequest } from \"./http\";\n\ntype Middleware = (req: UpstashRequest, next: () => Promise<unknown>) => Promise<unknown>;\n\nconst formatCreationTime = (obj: unknown) => {\n if (\n obj &&\n typeof obj === \"object\" &&\n \"creation_time\" in obj &&\n typeof obj.creation_time === \"number\" &&\n obj.creation_time > 0\n ) {\n obj.creation_time = new Date(obj.creation_time * 1000).toLocaleString();\n }\n};\n\nconst middlewares: Middleware[] = [\n // Middleware to format creation_time field to human readable format\n async (req, next) => {\n const res = await next();\n if (Array.isArray(res)) {\n for (const element of res) {\n formatCreationTime(element);\n }\n } else {\n formatCreationTime(res);\n }\n return res;\n },\n];\n\nexport const applyMiddlewares = async (\n req: UpstashRequest,\n func: (req: UpstashRequest) => Promise<unknown>\n) => {\n let next = async () => func(req);\n for (const middleware of middlewares.reverse()) {\n const prevNext = next;\n next = async () => middleware(req, prevNext);\n }\n return next();\n};\n","import { config } from \"./config\";\nimport { log } from \"./log\";\nimport { applyMiddlewares } from \"./middlewares\";\nimport type { RequestInit } from \"node-fetch\";\nimport fetch from \"node-fetch\";\n\nexport type UpstashRequest = {\n method: string;\n path?: string[] | string;\n /**\n * Request body will be serialized to json\n */\n body?: unknown;\n};\n\ntype HttpClientConfig = {\n baseUrl: string;\n};\n\nclass HttpClient {\n private readonly baseUrl: string;\n\n public constructor(config: HttpClientConfig) {\n this.baseUrl = config.baseUrl.replace(/\\/$/, \"\");\n }\n\n public async get<TResponse>(path: string[] | string): Promise<TResponse> {\n return this.requestWithMiddleware<TResponse>({ method: \"GET\", path });\n }\n\n public async post<TResponse>(path: string[] | string, body: unknown): Promise<TResponse> {\n return this.requestWithMiddleware<TResponse>({ method: \"POST\", path, body });\n }\n\n public async patch<TResponse>(path: string[] | string, body?: unknown): Promise<TResponse> {\n return this.requestWithMiddleware<TResponse>({ method: \"PATCH\", path, body });\n }\n\n public async delete<TResponse>(path: string[] | string): Promise<TResponse> {\n return this.requestWithMiddleware<TResponse>({ method: \"DELETE\", path });\n }\n\n private async requestWithMiddleware<TResponse>(req: UpstashRequest): Promise<TResponse> {\n const res = await applyMiddlewares(req, async (req) => {\n return this.request<TResponse>(req);\n });\n\n return res as TResponse;\n }\n\n private async request<TResponse>(req: UpstashRequest): Promise<TResponse> {\n if (!req.path) {\n req.path = [];\n } else if (typeof req.path === \"string\") {\n req.path = [req.path];\n }\n\n const url = [this.baseUrl, ...req.path].join(\"/\");\n const token = [config.email, config.apiKey].join(\":\");\n\n const init: RequestInit = {\n method: req.method,\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Basic ${Buffer.from(token).toString(\"base64\")}`,\n },\n };\n\n if (req.method !== \"GET\") {\n init.body = JSON.stringify(req.body);\n }\n\n log(\"Sending request\", {\n url,\n ...init,\n headers: { ...init.headers, Authorization: \"***\" },\n });\n\n // fetch is defined by isomorphic fetch\n const res = await fetch(url, init);\n if (!res.ok) {\n throw new Error(`Request failed (${res.status} ${res.statusText}): ${await res.text()}`);\n }\n return (await res.json()) as TResponse;\n }\n}\n\nexport const http = new HttpClient({ baseUrl: \"https://api.upstash.com\" });\n","import { z } from \"zod\";\nimport { json, tool } from \"..\";\nimport { log } from \"../../log\";\nimport fetch from \"node-fetch\";\n\ntype RedisCommandResult =\n | {\n result: unknown;\n }\n | {\n error: string;\n };\n\nexport const redisCommandTools = {\n redis_database_run_single_redis_command: tool({\n description: `Run a single Redis command on a specific Upstash redis database.\nNOTE: For discovery, use SCAN over KEYS. Use TYPE to get the type of a key.\nNOTE: SCAN cursor [MATCH pattern] [COUNT count] [TYPE type]`,\n inputSchema: z.object({\n database_rest_url: z\n .string()\n .describe(\"The REST URL of the database. Example: https://***.upstash.io\"),\n database_rest_token: z.string().describe(\"The REST token of the database.\"),\n command: z\n .array(z.string())\n .describe(\"The Redis command to run. Example: ['SET', 'foo', 'bar', 'EX', 100]\"),\n }),\n\n handler: async ({ database_rest_url, database_rest_token, command }) => {\n const req = await fetch(database_rest_url, {\n method: \"POST\",\n body: JSON.stringify(command),\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${database_rest_token}`,\n },\n });\n\n const result = (await req.json()) as RedisCommandResult;\n\n log(\"command result:\", result);\n\n if (\"error\" in result) {\n throw new Error(\"Redis error: \" + result.error);\n }\n\n const isScanCommand = command[0].toLocaleLowerCase().includes(\"scan\");\n const messages = [json(result)];\n\n if (isScanCommand)\n messages.push(`NOTE: Use the returned cursor to get the next set of keys.\nNOTE: The result might be too large to be returned. If applicable, stop after the second SCAN command and ask the user if they want to continue.`);\n\n return messages;\n },\n }),\n\n redis_database_run_multiple_redis_commands: tool({\n description: `Run multiple Redis commands on a specific Upstash redis database`,\n inputSchema: z.object({\n database_rest_url: z\n .string()\n .describe(\"The REST URL of the database. Example: https://***.upstash.io\"),\n database_rest_token: z.string().describe(\"The REST token of the database.\"),\n commands: z\n .array(z.array(z.string()))\n .describe(\"The Redis commands to run. Example: [['SET', 'foo', 'bar'], ['GET', 'foo']]\"),\n }),\n\n handler: async ({ database_rest_url, database_rest_token, commands }) => {\n const req = await fetch(database_rest_url + \"/pipeline\", {\n method: \"POST\",\n body: JSON.stringify(commands),\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${database_rest_token}`,\n },\n });\n\n const result = (await req.json()) as RedisCommandResult[];\n\n log(\"commands result:\", result);\n\n if (result.some((r) => \"error\" in r)) {\n throw new Error(\"Some commands in the pipeline resulted in an error:\\n\" + json(result));\n }\n\n return json(result);\n },\n }),\n};\n","import { z } from \"zod\";\nimport { json, tool } from \"..\";\nimport { http } from \"../../http\";\nimport type { RedisDatabase, RedisUsageResponse, UsageData } from \"./types\";\nimport { pruneFalsy } from \"../../utils\";\n\nconst readRegionSchema = z.union([\n z.literal(\"us-east-1\"),\n z.literal(\"us-west-1\"),\n z.literal(\"us-west-2\"),\n z.literal(\"eu-west-1\"),\n z.literal(\"eu-central-1\"),\n z.literal(\"ap-southeast-1\"),\n z.literal(\"ap-southeast-2\"),\n z.literal(\"sa-east-1\"),\n]);\n\nconst GENERIC_DATABASE_NOTES =\n \"\\nNOTE: Don't show the database ID from the response to the user unless explicitly asked or needed.\\n\";\n\nexport const redisDbOpsTools = {\n redis_database_create_new: tool({\n description: `Create a new Upstash redis database. \nNOTE: Ask user for the region and name of the database.${GENERIC_DATABASE_NOTES}`,\n inputSchema: z.object({\n name: z.string().describe(\"Name of the database.\"),\n primary_region: readRegionSchema.describe(`Primary Region of the Global Database.`),\n read_regions: z\n .array(readRegionSchema)\n .optional()\n .describe(`Array of read regions of the db`),\n }),\n handler: async ({ name, primary_region, read_regions }) => {\n const newDb = await http.post<RedisDatabase>(\"v2/redis/database\", {\n name,\n region: \"global\",\n primary_region,\n read_regions,\n });\n\n return [\n json(newDb),\n `Upstash console url: https://console.upstash.com/redis/${newDb.database_id}`,\n ];\n },\n }),\n\n redis_database_delete: tool({\n description: `Delete an Upstash redis database.`,\n inputSchema: z.object({\n database_id: z.string().describe(\"The ID of the database to delete.\"),\n }),\n handler: async ({ database_id }) => {\n await http.delete([\"v2/redis/database\", database_id]);\n\n return \"Database deleted successfully.\";\n },\n }),\n\n redis_database_list_databases: tool({\n description: `List all Upstash redis databases. Only their names and ids.${GENERIC_DATABASE_NOTES}`,\n handler: async () => {\n const dbs = await http.get<RedisDatabase[]>(\"v2/redis/databases\");\n\n const messages = [\n json(\n dbs.map((db) => {\n const result = {\n database_id: db.database_id,\n database_name: db.database_name,\n state: db.state === \"active\" ? undefined : db.state,\n };\n return pruneFalsy(result);\n })\n ),\n ];\n\n if (dbs.length > 2)\n messages.push(\n `NOTE: If the user did not specify a database name for the next command, ask them to choose a database from the list.`\n );\n messages.push(\n \"NOTE: If the user wants to see dbs in another team, mention that they need to create a new management api key for that team and initialize MCP server with the newly created key.\"\n );\n\n return messages;\n },\n }),\n\n redis_database_get_details: tool({\n description: `Get further details of a specific Upstash redis database. Includes all details of the database including usage statistics.\ndb_disk_threshold: Total disk usage limit.\ndb_memory_threshold: Maximum memory usage.\ndb_daily_bandwidth_limit: Maximum daily network bandwidth usage.\ndb_request_limit: Total number of commands allowed.\nAll sizes are in bytes\n${GENERIC_DATABASE_NOTES}\n `,\n inputSchema: z.object({\n database_id: z.string().describe(\"The ID of the database to get details for.\"),\n }),\n handler: async ({ database_id }) => {\n const db = await http.get<RedisDatabase>([\"v2/redis/database\", database_id]);\n\n return json(db);\n },\n }),\n\n redis_database_update_regions: tool({\n description: `Update the read regions of an Upstash redis database.`,\n inputSchema: z.object({\n id: z.string().describe(\"The ID of your database.\"),\n read_regions: z\n .array(readRegionSchema)\n .describe(\n \"Array of the new read regions of the database. This will replace the old regions array. Available regions: us-east-1, us-west-1, us-west-2, eu-west-1, eu-central-1, ap-southeast-1, ap-southeast-2, sa-east-1\"\n ),\n }),\n handler: async ({ id, read_regions }) => {\n const updatedDb = await http.post<RedisDatabase>([\"v2/redis/update-regions\", id], {\n read_regions,\n });\n\n return json(updatedDb);\n },\n }),\n\n redis_database_reset_password: tool({\n description: `Reset the password of an Upstash redis database.`,\n inputSchema: z.object({\n id: z.string().describe(\"The ID of your database.\"),\n }),\n handler: async ({ id }) => {\n const updatedDb = await http.post<RedisDatabase>([\"v2/redis/reset-password\", id], {});\n\n return json(updatedDb);\n },\n }),\n\n redis_database_get_usage_last_5_days: tool({\n description: `Get PRECISE command count and bandwidth usage statistics of an Upstash redis database over the last 5 days. This is a precise stat, not an average.\nNOTE: Ask user first if they want to see stats for each database seperately or just for one.`,\n inputSchema: z.object({\n id: z.string().describe(\"The ID of your database.\"),\n }),\n handler: async ({ id }) => {\n const stats = await http.get<RedisUsageResponse>([\"v2/redis/stats\", `${id}?period=3h`]);\n\n return [\n json({\n days: stats.days,\n command_usage: stats.dailyrequests,\n bandwidth_usage: stats.bandwidths,\n }),\n `NOTE: Times are calculated according to UTC+0`,\n ];\n },\n }),\n\n redis_database_get_stats: tool({\n description: `Get SAMPLED usage statistics of an Upstash redis database over a period of time (1h, 3h, 12h, 1d, 3d, 7d). Use this to check for peak usages and latency problems.\nIncludes: read_latency_mean, write_latency_mean, keyspace, throughput (cmds/sec), diskusage\nNOTE: If the user does not specify which stat to get, use throughput as default.`,\n inputSchema: z.object({\n id: z.string().describe(\"The ID of your database.\"),\n period: z\n .union([\n z.literal(\"1h\"),\n z.literal(\"3h\"),\n z.literal(\"12h\"),\n z.literal(\"1d\"),\n z.literal(\"3d\"),\n z.literal(\"7d\"),\n ])\n .describe(\"The period of the stats.\"),\n type: z\n .union([\n z.literal(\"read_latency_mean\"),\n z.literal(\"write_latency_mean\"),\n z.literal(\"keyspace\").describe(\"Number of keys in db\"),\n z\n .literal(\"throughput\")\n .describe(\"commands per second (sampled), calculate area for estimated count\"),\n z.literal(\"diskusage\").describe(\"Current disk usage in bytes\"),\n ])\n .describe(\"The type of stat to get\"),\n }),\n handler: async ({ id, period, type }) => {\n const stats = await http.get<RedisUsageResponse>([\n \"v2/redis/stats\",\n `${id}?period=${period}`,\n ]);\n\n const stat = stats[type];\n\n if (!Array.isArray(stat))\n throw new Error(\n `Invalid key provided: ${type}. Valid keys are: ${Object.keys(stats).join(\", \")}`\n );\n\n return [\n JSON.stringify(parseUsageData(stat)),\n `NOTE: Use the timestamps_to_date tool to parse timestamps if needed`,\n `NOTE: Don't try to plot multiple stats in the same chart`,\n ];\n },\n }),\n};\n\nconst parseUsageData = (data: UsageData) => {\n if (!data) return \"NO DATA\";\n if (!Array.isArray(data)) return \"INVALID DATA\";\n if (data.length === 0 || data.length === 1) return \"NO DATA\";\n const filteredData = data.filter((d) => d.x && d.y);\n return {\n start: filteredData[0].x,\n // last one can be null, so use the second last\n // eslint-disable-next-line unicorn/prefer-at\n end: filteredData[filteredData.length - 1]?.x,\n data: data.map((d) => [new Date(d.x).getTime(), d.y]),\n };\n};\n","export function pruneFalsy(obj: Record<string, any>) {\n return Object.fromEntries(Object.entries(obj).filter(([, value]) => value));\n}\n","import { utilTools } from \"../utils\";\nimport { redisBackupTools } from \"./backup\";\nimport { redisCommandTools } from \"./command\";\nimport { redisDbOpsTools } from \"./db\";\n\nexport const redisTools = {\n ...redisDbOpsTools,\n ...redisBackupTools,\n ...redisCommandTools,\n ...utilTools,\n};\n","import type { ZodSchema } from \"zod\";\nimport type { CustomTool } from \"../tool\";\nimport { redisTools } from \"./redis\";\n\nexport const json = (json: unknown) =>\n typeof json === \"string\" ? json : JSON.stringify(json, null, 2);\n\nexport const tools = {\n ...redisTools,\n} as unknown as Record<string, CustomTool>;\n\n// Only used for type inference\nexport function tool<TSchema extends ZodSchema>(tool: CustomTool<TSchema>) {\n return tool;\n}\n","import type { CallToolResultSchema } from \"@modelcontextprotocol/sdk/types.js\";\nimport type { ZodSchema } from \"zod\";\nimport { z } from \"zod\";\nimport { zodToJsonSchema } from \"zod-to-json-schema\";\nimport { MAX_MESSAGE_LENGTH } from \"./settings\";\n\ntype HandlerResponse = string | string[] | z.infer<typeof CallToolResultSchema>;\n\nexport type CustomTool<TSchema extends ZodSchema = ZodSchema> = {\n description: string;\n\n /**\n * Zod schema for the input of the tool.\n */\n inputSchema?: TSchema;\n\n /**\n * The handler function for the tool.\n * @param input Parsed input according to the input schema.\n * @returns\n * If result is a string, it will be displayed as a single text block.\n * If result is an array of strings, each string will be displayed as a separate text block.\n * You can also return a CallToolResult object to display more complex content.\n */\n handler: (input: z.infer<TSchema>) => Promise<HandlerResponse>;\n};\n\nexport function handlerResponseToCallResult(\n response: HandlerResponse\n): z.infer<typeof CallToolResultSchema> {\n if (typeof response === \"string\" || Array.isArray(response)) {\n const array = Array.isArray(response) ? response : [response];\n\n // Truncate messages that are too long\n const truncatedArray = array.map((item) =>\n item.length > MAX_MESSAGE_LENGTH\n ? `${item.slice(0, MAX_MESSAGE_LENGTH)}... (MESSAGE TRUNCATED, MENTION THIS TO USER)`\n : item\n );\n\n return {\n content: truncatedArray.map((text) => ({ type: \"text\", text })),\n };\n } else return response;\n}\n\nfunction convertToJsonSchema(schema: ZodSchema) {\n const jsonSchema = zodToJsonSchema(schema);\n delete jsonSchema.$schema;\n\n // Remove additionalProperties field from all objects, as it's not needed\n const removeAdditionalProperties = (schema: any) => {\n if (schema.type !== \"object\") return;\n\n delete schema.additionalProperties;\n for (const value of Object.values(schema.properties)) {\n removeAdditionalProperties(value);\n }\n };\n\n removeAdditionalProperties(jsonSchema);\n\n return jsonSchema;\n}\n\nexport function convertToTools(tools: Record<string, CustomTool>) {\n return Object.entries(tools).map(([name, tool]) => ({\n name,\n description: tool.description,\n inputSchema: convertToJsonSchema(tool.inputSchema ?? z.object({})),\n }));\n}\n","export const MAX_MESSAGE_LENGTH = 8000;\n","import { http } from \"./http\";\nimport { log } from \"./log\";\n\nexport async function testConnection() {\n log(\"๐งช Testing connection to Upstash API\");\n // TODO: Test the connection to the Upstash API here\n // to check if the token is valid\n const res = await http.get<[]>(\"v2/teams\");\n\n if (!Array.isArray(res))\n throw new Error(\"Invalid response from Upstash API. Check your API key and email.\");\n\n log(\"โ
Connection to Upstash API is successful\");\n}\n"],"mappings":"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","names":["z","config","path","req","init","z","z","fetch","z","z","z","json","tool","z","schema","tools","tool","z","tool"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/init.ts","../src/log.ts","../src/config.ts","../src/server.ts","../src/tools/utils.ts","../src/tools/redis/backup.ts","../src/middlewares.ts","../src/http.ts","../src/tools/redis/command.ts","../src/tools/redis/db.ts","../src/utils.ts","../src/tools/redis/index.ts","../src/tools/index.ts","../src/tool.ts","../src/settings.ts","../src/test-connection.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { init } from \"./init\";\nimport { log } from \"./log\";\nimport { server } from \"./server\";\nimport { config } from \"./config\";\nimport \"dotenv/config\";\nimport { testConnection } from \"./test-connection\";\n\nprocess.on(\"uncaughtException\", (error) => {\n log(\"Uncaught exception:\", error.name, error.message, error.stack);\n});\n\nprocess.on(\"unhandledRejection\", (error) => {\n if (error instanceof Error) log(\"Unhandled rejection:\", error.name, error.message, error.stack);\n else log(\"Unhandled rejection:\", error);\n});\n\nconst envApiKey = process.env.UPSTASH_API_KEY;\nconst envEmail = process.env.UPSTASH_EMAIL;\n\nconst USAGE_GENERAL = `Usage: npx @upstash/mcp-server (init|run) <UPSTASH_EMAIL> <UPSTASH_API_KEY>`;\nconst USAGE_RUN = `Usage: npx @upstash/mcp-server run <UPSTASH_EMAIL> <UPSTASH_API_KEY>`;\nconst USAGE_INIT = `Usage: npx @upstash/mcp-server init <UPSTASH_EMAIL> <UPSTASH_API_KEY>`;\n\nasync function parseArguments() {\n const [cmd, ...args] = process.argv.slice(2);\n if (!cmd) throw new Error(USAGE_GENERAL);\n else if (cmd === \"init\") {\n const [email, apiKey, ...rest] = args;\n const finalApiKey = apiKey || envApiKey;\n const finalEmail = email || envEmail;\n\n if (rest.length > 0) throw new Error(`Too many arguments. ${USAGE_INIT}`);\n if (!finalApiKey) throw new Error(`Missing API key. ${USAGE_INIT}`);\n if (!finalEmail) throw new Error(`Missing email. ${USAGE_INIT}`);\n\n config.apiKey = finalApiKey;\n config.email = finalEmail;\n\n await testConnection();\n\n await init({\n executablePath: process.argv[1],\n });\n } else if (cmd === \"run\") {\n const [email, apiKey, ...rest] = args;\n const finalApiKey = apiKey || envApiKey;\n const finalEmail = email || envEmail;\n\n if (!finalApiKey) throw new Error(`Missing API key. ${USAGE_RUN}`);\n if (!finalEmail) throw new Error(`Missing email. ${USAGE_RUN}`);\n if (rest.length > 0) throw new Error(`Too many arguments. ${USAGE_RUN}`);\n log(\"Starting MCP server\");\n\n config.apiKey = finalApiKey;\n config.email = finalEmail;\n\n await testConnection();\n\n // Start the server\n await main();\n } else {\n throw new Error(`Unknown command: ${cmd}. Expected 'init' or 'run'. ${USAGE_GENERAL}`);\n }\n}\n\nasync function main() {\n const transport = new StdioServerTransport();\n await server.connect(transport);\n}\n\n// eslint-disable-next-line unicorn/prefer-top-level-await\nparseArguments().catch((error) => {\n if (!(error instanceof Error)) throw error;\n console.error(error.message);\n process.exit(1);\n});\n","/* eslint-disable unicorn/prefer-node-protocol */\nimport path from \"path\";\nimport os from \"os\";\nimport fs from \"fs\";\nimport chalk from \"chalk\";\n\nimport { log } from \"./log\";\nimport { config } from \"./config\";\n\nconst claudeConfigPath = path.join(\n os.homedir(),\n \"Library\",\n \"Application Support\",\n \"Claude\",\n \"claude_desktop_config.json\"\n);\n\nconst UPSTASH_MCP_KEY = \"upstash\";\n\nexport async function init({ executablePath }: { executablePath: string }) {\n const isLocal = executablePath.includes(\"dist/index.js\");\n const upstashConfig = isLocal\n ? {\n command: \"node\",\n args: [executablePath, \"run\", config.email, config.apiKey],\n }\n : {\n command: \"npx\",\n args: [\"-y\", \"@upstash/mcp-server\", \"run\", config.email, config.apiKey],\n };\n\n const configDir = path.dirname(claudeConfigPath);\n if (!fs.existsSync(configDir)) {\n log(chalk.blue(\"Creating Claude config directory...\"));\n fs.mkdirSync(configDir, { recursive: true });\n }\n\n const existingConfig = fs.existsSync(claudeConfigPath)\n ? (JSON.parse(fs.readFileSync(claudeConfigPath, \"utf8\")) as {\n mcpServers?: Record<string, unknown>;\n })\n : { mcpServers: {} };\n\n if (UPSTASH_MCP_KEY in (existingConfig?.mcpServers || {})) {\n log(chalk.yellow(\"Upstash entry already exists. Overriding it.\"));\n }\n\n if (isLocal) {\n log(\n chalk.yellow(\n \"Local executable detected. Using 'node' and absolute path instead of 'npx' for development.\"\n )\n );\n }\n\n const newConfig = {\n ...existingConfig,\n mcpServers: {\n ...existingConfig.mcpServers,\n [UPSTASH_MCP_KEY]: upstashConfig,\n },\n };\n\n fs.writeFileSync(claudeConfigPath, JSON.stringify(newConfig, null, 2));\n\n log(\n chalk.blue(\n \"\\n\" +\n JSON.stringify(\n {\n [UPSTASH_MCP_KEY]: upstashConfig,\n },\n null,\n 2\n ).replaceAll(config.apiKey, \"********\")\n )\n );\n log(chalk.green(`Config written to: \"${claudeConfigPath.replace(os.homedir(), \"~\")}\"`));\n}\n","export function log(...args: unknown[]) {\n const msg = `[DEBUG ${new Date().toISOString()}] ${args.map((arg) => (typeof arg === \"string\" ? arg : JSON.stringify(arg))).join(\" \")}\\n`;\n process.stderr.write(msg);\n}\n","export const config = {\n apiKey: \"\",\n email: \"\",\n};\n","import { Server } from \"@modelcontextprotocol/sdk/server/index.js\";\nimport { ListToolsRequestSchema, CallToolRequestSchema } from \"@modelcontextprotocol/sdk/types.js\";\nimport { log } from \"./log\";\nimport { tools } from \"./tools\";\nimport { convertToTools, handlerResponseToCallResult } from \"./tool\";\n\nexport const server = new Server(\n { name: \"upstash\", version: \"0.1.0\" },\n { capabilities: { tools: {} } }\n);\n\nconst toolsList = convertToTools(tools);\n\nserver.setRequestHandler(ListToolsRequestSchema, async () => {\n log(\"Received list tools request\", toolsList);\n return { tools: toolsList };\n});\n\nserver.setRequestHandler(CallToolRequestSchema, async (request) => {\n const toolName = request.params.name;\n log(\"< received tool call:\", toolName, request.params.arguments);\n try {\n if (toolName in tools) {\n const tool = tools[toolName];\n const result = await tool.handler(request.params.arguments);\n\n const response = handlerResponseToCallResult(result);\n log(\"> tool result:\", response.content.map((item) => item.text).join(\"\\n\"));\n\n return response;\n }\n throw new Error(`Unknown tool: ${toolName}`);\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error);\n log(\"> error in tool call:\", msg);\n return {\n content: [\n {\n type: \"text\",\n text: `Error: ${msg}`,\n },\n ],\n isError: true,\n };\n }\n});\n","import { z } from \"zod\";\nimport { tool } from \".\";\n\nexport const utilTools = {\n timestamps_to_date: tool({\n description: `Use this tool to convert a timestamp to a human-readable date`,\n inputSchema: z.object({\n timestamps: z.array(z.number()).describe(\"Array of timestamps to convert\"),\n }),\n handler: async ({ timestamps }) => {\n return timestamps.map((timestamp) => new Date(timestamp).toUTCString());\n },\n }),\n}","import { z } from \"zod\";\nimport { json, tool } from \"..\";\nimport { http } from \"../../http\";\nimport type { RedisBackup } from \"./types\";\n\nexport const redisBackupTools = {\n redis_database_create_backup: tool({\n description: `Create a backup of a specific Upstash redis database.\nNOTE: Ask user to choose a name for the backup`,\n inputSchema: z.object({\n database_id: z.string().describe(\"The ID of the database to create a backup for.\"),\n backup_name: z.string().describe(\"A name for the backup.\"),\n }),\n handler: async ({ database_id, backup_name }) => {\n await http.post([\"v2/redis/create-backup\", database_id], {\n name: backup_name,\n });\n\n return \"OK\";\n },\n }),\n\n redis_database_delete_backup: tool({\n description: `Delete a backup of a specific Upstash redis database.`,\n inputSchema: z.object({\n database_id: z.string().describe(\"The ID of the database to delete a backup from.\"),\n backup_id: z.string().describe(\"The ID of the backup to delete.\"),\n }),\n handler: async ({ database_id, backup_id }) => {\n await http.delete([\"v2/redis/delete-backup\", database_id, backup_id]);\n\n return \"OK\";\n },\n }),\n\n redis_database_restore_backup: tool({\n description: `Restore a backup of a specific Upstash redis database. A backup can only be restored to the same database it was created from.`,\n inputSchema: z.object({\n database_id: z.string().describe(\"The ID of the database to restore a backup to.\"),\n backup_id: z.string().describe(\"The ID of the backup to restore.\"),\n }),\n handler: async ({ database_id, backup_id }) => {\n await http.post([\"v2/redis/restore-backup\", database_id], {\n backup_id,\n });\n\n return \"OK\";\n },\n }),\n\n redis_database_list_backups: tool({\n // TODO: Add explanation for fields\n // TODO: Is this in bytes?\n description: `List all backups of a specific Upstash redis database.`,\n inputSchema: z.object({\n database_id: z.string().describe(\"The ID of the database to list backups for.\"),\n }),\n handler: async ({ database_id }) => {\n const backups = await http.get<RedisBackup[]>([\"v2/redis/list-backup\", database_id]);\n\n return json(backups);\n },\n }),\n\n redis_database_set_daily_backup: tool({\n description: `Enable or disable daily backups for a specific Upstash redis database.`,\n inputSchema: z.object({\n database_id: z\n .string()\n .describe(\"The ID of the database to enable or disable daily backups for.\"),\n enable: z.boolean().describe(\"Whether to enable or disable daily backups.\"),\n }),\n handler: async ({ database_id, enable }) => {\n await http.patch([\n `v2/redis/${enable ? \"enable-dailybackup\" : \"disable-dailybackup\"}`,\n database_id,\n ]);\n\n return \"OK\";\n },\n }),\n};\n","import type { UpstashRequest } from \"./http\";\n\ntype Middleware = (req: UpstashRequest, next: () => Promise<unknown>) => Promise<unknown>;\n\nconst formatCreationTime = (obj: unknown) => {\n if (\n obj &&\n typeof obj === \"object\" &&\n \"creation_time\" in obj &&\n typeof obj.creation_time === \"number\" &&\n obj.creation_time > 0\n ) {\n obj.creation_time = new Date(obj.creation_time * 1000).toLocaleString();\n }\n};\n\nconst middlewares: Middleware[] = [\n // Middleware to format creation_time field to human readable format\n async (req, next) => {\n const res = await next();\n if (Array.isArray(res)) {\n for (const element of res) {\n formatCreationTime(element);\n }\n } else {\n formatCreationTime(res);\n }\n return res;\n },\n];\n\nexport const applyMiddlewares = async (\n req: UpstashRequest,\n func: (req: UpstashRequest) => Promise<unknown>\n) => {\n let next = async () => func(req);\n for (const middleware of middlewares.reverse()) {\n const prevNext = next;\n next = async () => middleware(req, prevNext);\n }\n return next();\n};\n","import { config } from \"./config\";\nimport { log } from \"./log\";\nimport { applyMiddlewares } from \"./middlewares\";\nimport type { RequestInit } from \"node-fetch\";\nimport fetch from \"node-fetch\";\n\nexport type UpstashRequest = {\n method: string;\n path?: string[] | string;\n /**\n * Request body will be serialized to json\n */\n body?: unknown;\n};\n\ntype HttpClientConfig = {\n baseUrl: string;\n};\n\nclass HttpClient {\n private readonly baseUrl: string;\n\n public constructor(config: HttpClientConfig) {\n this.baseUrl = config.baseUrl.replace(/\\/$/, \"\");\n }\n\n public async get<TResponse>(path: string[] | string): Promise<TResponse> {\n return this.requestWithMiddleware<TResponse>({ method: \"GET\", path });\n }\n\n public async post<TResponse>(path: string[] | string, body: unknown): Promise<TResponse> {\n return this.requestWithMiddleware<TResponse>({ method: \"POST\", path, body });\n }\n\n public async patch<TResponse>(path: string[] | string, body?: unknown): Promise<TResponse> {\n return this.requestWithMiddleware<TResponse>({ method: \"PATCH\", path, body });\n }\n\n public async delete<TResponse>(path: string[] | string): Promise<TResponse> {\n return this.requestWithMiddleware<TResponse>({ method: \"DELETE\", path });\n }\n\n private async requestWithMiddleware<TResponse>(req: UpstashRequest): Promise<TResponse> {\n const res = await applyMiddlewares(req, async (req) => {\n return this.request<TResponse>(req);\n });\n\n return res as TResponse;\n }\n\n private async request<TResponse>(req: UpstashRequest): Promise<TResponse> {\n if (!req.path) {\n req.path = [];\n } else if (typeof req.path === \"string\") {\n req.path = [req.path];\n }\n\n const url = [this.baseUrl, ...req.path].join(\"/\");\n const token = [config.email, config.apiKey].join(\":\");\n\n const init: RequestInit = {\n method: req.method,\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Basic ${Buffer.from(token).toString(\"base64\")}`,\n },\n };\n\n if (req.method !== \"GET\") {\n init.body = JSON.stringify(req.body);\n }\n\n log(\"Sending request\", {\n url,\n ...init,\n headers: { ...init.headers, Authorization: \"***\" },\n });\n\n // fetch is defined by isomorphic fetch\n const res = await fetch(url, init);\n if (!res.ok) {\n throw new Error(`Request failed (${res.status} ${res.statusText}): ${await res.text()}`);\n }\n return (await res.json()) as TResponse;\n }\n}\n\nexport const http = new HttpClient({ baseUrl: \"https://api.upstash.com\" });\n","import { z } from \"zod\";\nimport { json, tool } from \"..\";\nimport { log } from \"../../log\";\nimport fetch from \"node-fetch\";\n\ntype RedisCommandResult =\n | {\n result: unknown;\n }\n | {\n error: string;\n };\n\nexport const redisCommandTools = {\n redis_database_run_single_redis_command: tool({\n description: `Run a single Redis command on a specific Upstash redis database.\nNOTE: For discovery, use SCAN over KEYS. Use TYPE to get the type of a key.\nNOTE: SCAN cursor [MATCH pattern] [COUNT count] [TYPE type]`,\n inputSchema: z.object({\n database_rest_url: z\n .string()\n .describe(\"The REST URL of the database. Example: https://***.upstash.io\"),\n database_rest_token: z.string().describe(\"The REST token of the database.\"),\n command: z\n .array(z.string())\n .describe(\"The Redis command to run. Example: ['SET', 'foo', 'bar', 'EX', 100]\"),\n }),\n\n handler: async ({ database_rest_url, database_rest_token, command }) => {\n const req = await fetch(database_rest_url, {\n method: \"POST\",\n body: JSON.stringify(command),\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${database_rest_token}`,\n },\n });\n\n const result = (await req.json()) as RedisCommandResult;\n\n log(\"command result:\", result);\n\n if (\"error\" in result) {\n throw new Error(\"Redis error: \" + result.error);\n }\n\n const isScanCommand = command[0].toLocaleLowerCase().includes(\"scan\");\n const messages = [json(result)];\n\n if (isScanCommand)\n messages.push(`NOTE: Use the returned cursor to get the next set of keys.\nNOTE: The result might be too large to be returned. If applicable, stop after the second SCAN command and ask the user if they want to continue.`);\n\n return messages;\n },\n }),\n\n redis_database_run_multiple_redis_commands: tool({\n description: `Run multiple Redis commands on a specific Upstash redis database`,\n inputSchema: z.object({\n database_rest_url: z\n .string()\n .describe(\"The REST URL of the database. Example: https://***.upstash.io\"),\n database_rest_token: z.string().describe(\"The REST token of the database.\"),\n commands: z\n .array(z.array(z.string()))\n .describe(\"The Redis commands to run. Example: [['SET', 'foo', 'bar'], ['GET', 'foo']]\"),\n }),\n\n handler: async ({ database_rest_url, database_rest_token, commands }) => {\n const req = await fetch(database_rest_url + \"/pipeline\", {\n method: \"POST\",\n body: JSON.stringify(commands),\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${database_rest_token}`,\n },\n });\n\n const result = (await req.json()) as RedisCommandResult[];\n\n log(\"commands result:\", result);\n\n if (result.some((r) => \"error\" in r)) {\n throw new Error(\"Some commands in the pipeline resulted in an error:\\n\" + json(result));\n }\n\n return json(result);\n },\n }),\n};\n","import { z } from \"zod\";\nimport { json, tool } from \"..\";\nimport { http } from \"../../http\";\nimport type { RedisDatabase, RedisUsageResponse, UsageData } from \"./types\";\nimport { pruneFalsy } from \"../../utils\";\n\nconst readRegionSchema = z.union([\n z.literal(\"us-east-1\"),\n z.literal(\"us-west-1\"),\n z.literal(\"us-west-2\"),\n z.literal(\"eu-west-1\"),\n z.literal(\"eu-central-1\"),\n z.literal(\"ap-southeast-1\"),\n z.literal(\"ap-southeast-2\"),\n z.literal(\"sa-east-1\"),\n]);\n\nconst GENERIC_DATABASE_NOTES =\n \"\\nNOTE: Don't show the database ID from the response to the user unless explicitly asked or needed.\\n\";\n\nexport const redisDbOpsTools = {\n redis_database_create_new: tool({\n description: `Create a new Upstash redis database. \nNOTE: Ask user for the region and name of the database.${GENERIC_DATABASE_NOTES}`,\n inputSchema: z.object({\n name: z.string().describe(\"Name of the database.\"),\n primary_region: readRegionSchema.describe(`Primary Region of the Global Database.`),\n read_regions: z\n .array(readRegionSchema)\n .optional()\n .describe(`Array of read regions of the db`),\n }),\n handler: async ({ name, primary_region, read_regions }) => {\n const newDb = await http.post<RedisDatabase>(\"v2/redis/database\", {\n name,\n region: \"global\",\n primary_region,\n read_regions,\n });\n\n return [\n json(newDb),\n `Upstash console url: https://console.upstash.com/redis/${newDb.database_id}`,\n ];\n },\n }),\n\n redis_database_delete: tool({\n description: `Delete an Upstash redis database.`,\n inputSchema: z.object({\n database_id: z.string().describe(\"The ID of the database to delete.\"),\n }),\n handler: async ({ database_id }) => {\n await http.delete([\"v2/redis/database\", database_id]);\n\n return \"Database deleted successfully.\";\n },\n }),\n\n redis_database_list_databases: tool({\n description: `List all Upstash redis databases. Only their names and ids.${GENERIC_DATABASE_NOTES}`,\n handler: async () => {\n const dbs = await http.get<RedisDatabase[]>(\"v2/redis/databases\");\n\n const messages = [\n json(\n dbs.map((db) => {\n const result = {\n database_id: db.database_id,\n database_name: db.database_name,\n state: db.state === \"active\" ? undefined : db.state,\n };\n return pruneFalsy(result);\n })\n ),\n ];\n\n if (dbs.length > 2)\n messages.push(\n `NOTE: If the user did not specify a database name for the next command, ask them to choose a database from the list.`\n );\n messages.push(\n \"NOTE: If the user wants to see dbs in another team, mention that they need to create a new management api key for that team and initialize MCP server with the newly created key.\"\n );\n\n return messages;\n },\n }),\n\n redis_database_get_details: tool({\n description: `Get further details of a specific Upstash redis database. Includes all details of the database including usage statistics.\ndb_disk_threshold: Total disk usage limit.\ndb_memory_threshold: Maximum memory usage.\ndb_daily_bandwidth_limit: Maximum daily network bandwidth usage.\ndb_request_limit: Total number of commands allowed.\nAll sizes are in bytes\n${GENERIC_DATABASE_NOTES}\n `,\n inputSchema: z.object({\n database_id: z.string().describe(\"The ID of the database to get details for.\"),\n }),\n handler: async ({ database_id }) => {\n const db = await http.get<RedisDatabase>([\"v2/redis/database\", database_id]);\n\n return json(db);\n },\n }),\n\n redis_database_update_regions: tool({\n description: `Update the read regions of an Upstash redis database.`,\n inputSchema: z.object({\n id: z.string().describe(\"The ID of your database.\"),\n read_regions: z\n .array(readRegionSchema)\n .describe(\n \"Array of the new read regions of the database. This will replace the old regions array. Available regions: us-east-1, us-west-1, us-west-2, eu-west-1, eu-central-1, ap-southeast-1, ap-southeast-2, sa-east-1\"\n ),\n }),\n handler: async ({ id, read_regions }) => {\n const updatedDb = await http.post<RedisDatabase>([\"v2/redis/update-regions\", id], {\n read_regions,\n });\n\n return json(updatedDb);\n },\n }),\n\n redis_database_reset_password: tool({\n description: `Reset the password of an Upstash redis database.`,\n inputSchema: z.object({\n id: z.string().describe(\"The ID of your database.\"),\n }),\n handler: async ({ id }) => {\n const updatedDb = await http.post<RedisDatabase>([\"v2/redis/reset-password\", id], {});\n\n return json(updatedDb);\n },\n }),\n\n redis_database_get_usage_last_5_days: tool({\n description: `Get PRECISE command count and bandwidth usage statistics of an Upstash redis database over the last 5 days. This is a precise stat, not an average.\nNOTE: Ask user first if they want to see stats for each database seperately or just for one.`,\n inputSchema: z.object({\n id: z.string().describe(\"The ID of your database.\"),\n }),\n handler: async ({ id }) => {\n const stats = await http.get<RedisUsageResponse>([\"v2/redis/stats\", `${id}?period=3h`]);\n\n return [\n json({\n days: stats.days,\n command_usage: stats.dailyrequests,\n bandwidth_usage: stats.bandwidths,\n }),\n `NOTE: Times are calculated according to UTC+0`,\n ];\n },\n }),\n\n redis_database_get_stats: tool({\n description: `Get SAMPLED usage statistics of an Upstash redis database over a period of time (1h, 3h, 12h, 1d, 3d, 7d). Use this to check for peak usages and latency problems.\nIncludes: read_latency_mean, write_latency_mean, keyspace, throughput (cmds/sec), diskusage\nNOTE: If the user does not specify which stat to get, use throughput as default.`,\n inputSchema: z.object({\n id: z.string().describe(\"The ID of your database.\"),\n period: z\n .union([\n z.literal(\"1h\"),\n z.literal(\"3h\"),\n z.literal(\"12h\"),\n z.literal(\"1d\"),\n z.literal(\"3d\"),\n z.literal(\"7d\"),\n ])\n .describe(\"The period of the stats.\"),\n type: z\n .union([\n z.literal(\"read_latency_mean\"),\n z.literal(\"write_latency_mean\"),\n z.literal(\"keyspace\").describe(\"Number of keys in db\"),\n z\n .literal(\"throughput\")\n .describe(\"commands per second (sampled), calculate area for estimated count\"),\n z.literal(\"diskusage\").describe(\"Current disk usage in bytes\"),\n ])\n .describe(\"The type of stat to get\"),\n }),\n handler: async ({ id, period, type }) => {\n const stats = await http.get<RedisUsageResponse>([\n \"v2/redis/stats\",\n `${id}?period=${period}`,\n ]);\n\n const stat = stats[type];\n\n if (!Array.isArray(stat))\n throw new Error(\n `Invalid key provided: ${type}. Valid keys are: ${Object.keys(stats).join(\", \")}`\n );\n\n return [\n JSON.stringify(parseUsageData(stat)),\n `NOTE: Use the timestamps_to_date tool to parse timestamps if needed`,\n `NOTE: Don't try to plot multiple stats in the same chart`,\n ];\n },\n }),\n};\n\nconst parseUsageData = (data: UsageData) => {\n if (!data) return \"NO DATA\";\n if (!Array.isArray(data)) return \"INVALID DATA\";\n if (data.length === 0 || data.length === 1) return \"NO DATA\";\n const filteredData = data.filter((d) => d.x && d.y);\n return {\n start: filteredData[0].x,\n // last one can be null, so use the second last\n // eslint-disable-next-line unicorn/prefer-at\n end: filteredData[filteredData.length - 1]?.x,\n data: data.map((d) => [new Date(d.x).getTime(), d.y]),\n };\n};\n","export function pruneFalsy(obj: Record<string, any>) {\n return Object.fromEntries(Object.entries(obj).filter(([, value]) => value));\n}\n","import { utilTools } from \"../utils\";\nimport { redisBackupTools } from \"./backup\";\nimport { redisCommandTools } from \"./command\";\nimport { redisDbOpsTools } from \"./db\";\n\nexport const redisTools = {\n ...redisDbOpsTools,\n ...redisBackupTools,\n ...redisCommandTools,\n ...utilTools,\n};\n","import type { ZodSchema } from \"zod\";\nimport type { CustomTool } from \"../tool\";\nimport { redisTools } from \"./redis\";\n\nexport const json = (json: unknown) =>\n typeof json === \"string\" ? json : JSON.stringify(json, null, 2);\n\nexport const tools = {\n ...redisTools,\n} as unknown as Record<string, CustomTool>;\n\n// Only used for type inference\nexport function tool<TSchema extends ZodSchema>(tool: CustomTool<TSchema>) {\n return tool;\n}\n","import type { CallToolResultSchema } from \"@modelcontextprotocol/sdk/types.js\";\nimport type { ZodSchema } from \"zod\";\nimport { z } from \"zod\";\nimport { zodToJsonSchema } from \"zod-to-json-schema\";\nimport { MAX_MESSAGE_LENGTH } from \"./settings\";\n\ntype HandlerResponse = string | string[] | z.infer<typeof CallToolResultSchema>;\n\nexport type CustomTool<TSchema extends ZodSchema = ZodSchema> = {\n description: string;\n\n /**\n * Zod schema for the input of the tool.\n */\n inputSchema?: TSchema;\n\n /**\n * The handler function for the tool.\n * @param input Parsed input according to the input schema.\n * @returns\n * If result is a string, it will be displayed as a single text block.\n * If result is an array of strings, each string will be displayed as a separate text block.\n * You can also return a CallToolResult object to display more complex content.\n */\n handler: (input: z.infer<TSchema>) => Promise<HandlerResponse>;\n};\n\nexport function handlerResponseToCallResult(\n response: HandlerResponse\n): z.infer<typeof CallToolResultSchema> {\n if (typeof response === \"string\" || Array.isArray(response)) {\n const array = Array.isArray(response) ? response : [response];\n\n // Truncate messages that are too long\n const truncatedArray = array.map((item) =>\n item.length > MAX_MESSAGE_LENGTH\n ? `${item.slice(0, MAX_MESSAGE_LENGTH)}... (MESSAGE TRUNCATED, MENTION THIS TO USER)`\n : item\n );\n\n return {\n content: truncatedArray.map((text) => ({ type: \"text\", text })),\n };\n } else return response;\n}\n\nfunction convertToJsonSchema(schema: ZodSchema) {\n const jsonSchema = zodToJsonSchema(schema);\n delete jsonSchema.$schema;\n\n // Remove additionalProperties field from all objects, as it's not needed\n const removeAdditionalProperties = (schema: any) => {\n if (schema.type !== \"object\") return;\n\n delete schema.additionalProperties;\n for (const value of Object.values(schema.properties)) {\n removeAdditionalProperties(value);\n }\n };\n\n removeAdditionalProperties(jsonSchema);\n\n return jsonSchema;\n}\n\nexport function convertToTools(tools: Record<string, CustomTool>) {\n return Object.entries(tools).map(([name, tool]) => ({\n name,\n description: tool.description,\n inputSchema: convertToJsonSchema(tool.inputSchema ?? z.object({})),\n }));\n}\n","export const MAX_MESSAGE_LENGTH = 8000;\n","import { http } from \"./http\";\nimport { log } from \"./log\";\n\nexport async function testConnection() {\n log(\"๐งช Testing connection to Upstash API\");\n // TODO: Test the connection to the Upstash API here\n // to check if the token is valid\n const res = await http.get<[]>(\"v2/teams\");\n\n if (!Array.isArray(res))\n throw new Error(\"Invalid response from Upstash API. Check your API key and email.\");\n\n log(\"โ
Connection to Upstash API is successful\");\n}\n"],"mappings":"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","names":["z","config","path","req","init","z","z","fetch","z","z","z","json","tool","z","schema","tools","tool","z","tool"]}
|
package/package.json
CHANGED
|
@@ -1,47 +1 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": "0.0.7",
|
|
3
|
-
"name": "@upstash/mcp-server",
|
|
4
|
-
"description": "MCP server for Upstash",
|
|
5
|
-
"license": "MIT",
|
|
6
|
-
"type": "module",
|
|
7
|
-
"bin": {
|
|
8
|
-
"mcp-server": "./dist/index.js"
|
|
9
|
-
},
|
|
10
|
-
"repository": {
|
|
11
|
-
"type": "git",
|
|
12
|
-
"url": "git+https://github.com/upstash/mcp-server.git"
|
|
13
|
-
},
|
|
14
|
-
"bugs": {
|
|
15
|
-
"url": "https://github.com/upstash/mcp-server/issues"
|
|
16
|
-
},
|
|
17
|
-
"scripts": {
|
|
18
|
-
"build": "tsup && node -e \"require('fs').chmodSync('dist/index.js', '755')\"",
|
|
19
|
-
"watch": "npm run build && tsup --watch",
|
|
20
|
-
"inspector": "npx @modelcontextprotocol/inspector node --enable-source-maps dist/index.js run",
|
|
21
|
-
"setup": "node ./dist/index.js init",
|
|
22
|
-
"logs": "tail -n 20 -f ~/Library/Logs/Claude/mcp*.log",
|
|
23
|
-
"test": "bun test",
|
|
24
|
-
"fmt": "prettier --write .",
|
|
25
|
-
"lint": "eslint \"**/*.{js,ts,tsx}\" --quiet --fix"
|
|
26
|
-
},
|
|
27
|
-
"files": [
|
|
28
|
-
"dist"
|
|
29
|
-
],
|
|
30
|
-
"devDependencies": {
|
|
31
|
-
"@typescript-eslint/eslint-plugin": "8.4.0",
|
|
32
|
-
"@typescript-eslint/parser": "8.4.0",
|
|
33
|
-
"eslint": "9.10.0",
|
|
34
|
-
"eslint-plugin-unicorn": "55.0.0",
|
|
35
|
-
"prettier": "^3.4.2",
|
|
36
|
-
"tsup": "^8.3.5"
|
|
37
|
-
},
|
|
38
|
-
"dependencies": {
|
|
39
|
-
"@modelcontextprotocol/sdk": "^1.0.3",
|
|
40
|
-
"@types/node": "15",
|
|
41
|
-
"chalk": "^5.3.0",
|
|
42
|
-
"dotenv": "^16.4.7",
|
|
43
|
-
"node-fetch": "^3.3.2",
|
|
44
|
-
"zod": "^3.24.1",
|
|
45
|
-
"zod-to-json-schema": "^3.24.1"
|
|
46
|
-
}
|
|
47
|
-
}
|
|
1
|
+
{ "version": "v0.1.0", "name": "@upstash/mcp-server", "description": "MCP server for Upstash", "license": "MIT", "type": "module", "bin": { "mcp-server": "./dist/index.js" }, "repository": { "type": "git", "url": "git+https://github.com/upstash/mcp-server.git" }, "bugs": { "url": "https://github.com/upstash/mcp-server/issues" }, "scripts": { "build": "tsup && node -e \"require('fs').chmodSync('dist/index.js', '755')\"", "watch": "npm run build && tsup --watch", "inspector": "npx @modelcontextprotocol/inspector node --enable-source-maps dist/index.js run", "setup": "node ./dist/index.js init", "logs": "tail -n 20 -f ~/Library/Logs/Claude/mcp*.log", "fmt": "prettier --write .", "test": "vitest", "lint": "eslint \"**/*.{js,ts,tsx}\" --quiet --fix" }, "files": [ "dist" ], "devDependencies": { "@typescript-eslint/eslint-plugin": "8.4.0", "@typescript-eslint/parser": "8.4.0", "eslint": "9.10.0", "eslint-plugin-unicorn": "55.0.0", "prettier": "^3.4.2", "tsup": "^8.3.5", "vitest": "^3.1.1" }, "dependencies": { "@modelcontextprotocol/sdk": "^1.8.0", "@types/node": "15", "chalk": "^5.3.0", "dotenv": "^16.4.7", "node-fetch": "^3.3.2", "zod": "^3.24.1", "zod-to-json-schema": "^3.24.1" } }
|