All the MCP?
The latest updates on your projects. Learn more about Vercel for GitHub.
| Project | Deployment | Review | Updated (UTC) |
|---|---|---|---|
| mxstbr.com | Preview, Comment | Dec 15, 2025 4:00pm |
On it
Summary
- Inlined chore MCP tool registrations, replacing the shared choreTools map with explicit
server.registerToolcalls while keeping existing schemas, metadata, and output handling for each chore and reward action. app/lib/chores.tsL257-L960
Testing
- Not run (not requested).
@codex https://github.com/codex use the content field across all the tools to return a text description of what the tool returned.
Summary
- Added descriptive messages for reading the chore board and included them in both text content and structured payloads for MCP responses. app/lib/chores.tsL253-L288
- Ensured completion, undo, and reward redemption tools return textual summaries alongside their structured results for clearer outputs. app/lib/chores.tsL390-L447 app/lib/chores.tsL925-L961
Testing
- Not run (not requested)
@codex fix all the anyOutputSchema's. Make them the actual structured output schemas.
Summary
- Replaced permissive MCP output schemas with specific structured response validators for calendar, finance, and Telegram tools to match their returned payloads. app/lib/calendar.tsL36-L190 app/lib/finance.tsL16-L149 app/lib/telegram.tsL10-L35
- Added detailed chore snapshot and result schemas and wired them into all chore tool registrations so outputs now reflect the actual structured content returned by each action. app/lib/chores.tsL51-L166 app/lib/chores.tsL367-L425
Testing
- ⚠️ Not run (not requested)
@codex I think the export from ai is experimental_createMCPClient for now? Go research and fix it
Export createMCPClient doesn't exist in target module 1 | import { openai } from '@ai-sdk/openai'
2 | import { createMCPClient, stepCountIs, Experimental_Agent as Agent } from 'ai' | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 3 | import { Redis } from '@upstash/redis' 4 | import { colors } from 'app/(os)/cal/data' 5 | import { PRESETS } from 'app/(os)/cal/presets' The export createMCPClient was not found in module [project]/node_modules/.pnpm/[email protected][email protected]/node_modules/ai/dist/index.mjs [app-route] (ecmascript).
Summary
- Updated the Clippy MCP client import to use the SDK’s
experimental_createMCPClientexport while retaining the existing client usage. app/lib/clippy-agent.tsL1-L6
Testing
- ⚠️ Not run (not requested)
@codex
./app/lib/clippy-agent.ts:185:28
Type error: Generic type 'Agent<TOOLS, OUTPUT, OUTPUT_PARTIAL>' requires between 1 and 3 type arguments.
183 | </PRESETS>`
184 |
> 185 | let clippyPromise: Promise<Agent> | null = null
| ^
186 |
187 | export async function getClippy() {
188 | if (clippyPromise) return clippyPromise
Next.js build worker exited with code: 1 and signal: null
ELIFECYCLE Command failed with exit code 1.
Error: Command "pnpm run build" exited with 1
Summary
- Specified generics for the Clippy agent promise to satisfy the AI SDK
Agenttype requirements. app/lib/clippy-agent.tsL185-L223
Testing
- ❌
pnpm build(failed because Turbopack could not fetch Google Fonts Inter due to TLS/network restrictions).
@codex in production Clippy agent fails because:
Clippy MCP client error TypeError: fetch failed
at ignore-listed frames {
[cause]: Error: connect ECONNREFUSED 127.0.0.1:3000
at <unknown> (Error: connect ECONNREFUSED 127.0.0.1:3000) {
errno: -111,
code: 'ECONNREFUSED',
syscall: 'connect',
address: '127.0.0.1',
port: 3000
}
}
Fix it by connecting to the "local" /api/mcp server always of the same vercel deployment/origin URL/whatever.
Summary
- Added a deployment URL resolver for the Clippy MCP client that prioritizes Vercel and site environment variables, warning if production would fall back to localhost. app/lib/clippy-agent.tsL13-L33
- Pointed the MCP SSE transport at the resolved deployment origin while keeping existing auth headers and error logging for the client. app/lib/clippy-agent.tsL213-L225
Testing
- ⚠️ Not run (not requested)
@codex that didn't work.
Clippy MCP client error TypeError: fetch failed
at ignore-listed frames {
[cause]: Error: connect ECONNREFUSED 127.0.0.1:3000
at <unknown> (Error: connect ECONNREFUSED 127.0.0.1:3000) {
errno: -111,
code: 'ECONNREFUSED',
syscall: 'connect',
address: '127.0.0.1',
port: 3000
}
Summary
- Resolved MCP transport origin detection by preferring deployment environment URLs and falling back to the incoming request host before using the local default, reducing production failures. app/lib/clippy-agent.tsL1-L40
Testing
- ⚠️ Not run (not requested)
@codex
⚠ The "middleware" file convention is deprecated. Please use "proxy" instead. Learn more: https://nextjs.org/docs/messages/middleware-to-proxy
Creating an optimized production build ...
✓ Compiled successfully in 27.8s
Running TypeScript ...
Failed to compile.
./app/lib/clippy-agent.ts:26:34
Type error: Property 'get' does not exist on type 'Promise<ReadonlyHeaders>'.
24 |
25 | try {
> 26 | const hostHeader = headers().get('host') ?? undefined
| ^
27 | if (hostHeader) return `https://${hostHeader}`
28 | } catch (error) {
29 | console.warn('Unable to read request headers for MCP origin resolution', error)
Next.js build worker exited with code: 1 and signal: null
ELIFECYCLE Command failed with exit code 1.
Error: Command "pnpm run build" exited with 1
Summary
- Made MCP deployment URL resolution asynchronous, awaiting request headers before deriving the deployment host and falling back as needed. app/lib/clippy-agent.tsL14-L41
- Reused the resolved deployment origin when configuring the Clippy MCP SSE transport during agent initialization. app/lib/clippy-agent.tsL218-L233
Testing
- Not run (not requested).
@codex I'm going to /chores/admin on the Vercel preview, opening the Clippy popup chat, entering a query, and then I get that same can't connect to localhost:3000 error. None of the previous commits fixed it. Something's wrong with that popup. Why doesn't it work anymore?
Summary
- Resolved MCP origin detection to prioritize deployment environment variables, request URLs, and forwarded headers before falling back, reducing localhost fallbacks in production. app/lib/clippy-agent.tsL14-L50
- Passed incoming requests to Clippy initialization across chat, email, SMS, and Telegram routes so the MCP client targets the current deployment host consistently. app/api/chat/route.tsL19-L24 app/api/email/route.tsL6-L39 app/api/text/route.tsL9-L68 app/api/telegram/route.tsL10-L98
Testing
- ⚠️ Not run (not requested)
@codex getting this error in prod when sending a message to Clippy now:
Unhandled Rejection: Error: redisUrl is required
at /var/task/.next/server/chunks/[root-of-the-server]__d2a7d211._.js:28:8717
at Generator.next (<anonymous>)
at /var/task/.next/server/chunks/[root-of-the-server]__d2a7d211._.js:7:469744
at new Promise (<anonymous>)
at eP (/var/task/.next/server/chunks/[root-of-the-server]__d2a7d211._.js:7:469564)
at aR (/var/task/.next/server/chunks/[root-of-the-server]__d2a7d211._.js:28:8613)
at /var/task/.next/server/chunks/[root-of-the-server]__d2a7d211._.js:28:13048
at Generator.next (<anonymous>)
at /var/task/.next/server/chunks/[root-of-the-server]__d2a7d211._.js:7:469744
at new Promise (<anonymous>)
I think this is the mcp-handler package. Use the Upstash redis URL + Upstash redis token env vars and combine them together as per the Upstash docs:
Upstash docs
REST API
REST API enables you to access your Upstash database using REST.
Get Started
If you do not have a database already, follow these steps to create one.
In the Upstash Console, select your database. Then, in the database page, you will see the section that includes the endpoint URL and token details. When you hover over the Endpoint or Token / Readonly Token fields, copy button will appear for each. You can click it to easily copy the values you need for your connection.
Copy the HTTPS for REST URL and the Token for authorization. Send an HTTP SET request to the
provided URL by adding an Authorization: Bearer $TOKEN header like below: (See the sample command with your credentials in the cURL tab of Connection section)
curl https://us1-merry-cat-32748.upstash.io/set/foo/bar \
-H "Authorization: Bearer 2553feg6a2d9842h2a0gcdb5f8efe9934"
The above script executes a SET foo bar command. It will return a JSON
response:
{ "result": "OK" }
You can also set the token as _token request parameter as below:
curl https://us1-merry-cat-32748.upstash.io/set/foo/bar?_token=2553feg6a2d9842h2a0gcdb5f8efe9934
API Semantics
Upstash REST API follows the same convention with
Redis Protocol. Give the command name and
parameters in the same order as Redis protocol by separating them with a /.
curl REST_URL/COMMAND/arg1/arg2/../argN
Here are some examples:
-
SET foo bar->REST_URL/set/foo/bar -
SET foo bar EX 100->REST_URL/set/foo/bar/EX/100 -
GET foo->REST_URL/get/foo -
MGET foo1 foo2 foo3->REST_URL/mget/foo1/foo2/foo3 -
HGET employee:23381 salary->REST_URL/hget/employee:23381/salary -
ZADD teams 100 team-x 90 team-y->REST_URL/zadd/teams/100/team-x/90/team-y
JSON or Binary Value
To post a JSON or a binary value, you can use an HTTP POST request and set value as the request body:
curl -X POST -d '$VALUE' https://us1-merry-cat-32748.upstash.io/set/foo \
-H "Authorization: Bearer 2553feg6a2d9842h2a0gcdb5f8efe9934"
In the example above, $VALUE sent in request body is appended to the command
as REST_URL/set/foo/$VALUE.
Please note that when making a POST request to the Upstash REST API, the request body is appended as the last parameter of the Redis command. If there are additional parameters in the Redis command after the value, you should include them as query parameters in the request:
curl -X POST -d '$VALUE' https://us1-merry-cat-32748.upstash.io/set/foo?EX=100 \
-H "Authorization: Bearer 2553feg6a2d9842h2a0gcdb5f8efe9934"
Above command is equivalent to REST_URL/set/foo/$VALUE/EX/100.
POST Command in Body
Alternatively, you can send the whole command in the request body as a single JSON array. Array's first element must be the command name and command parameters should be appended next to each other in the same order as Redis protocol.
curl -X POST -d '[COMMAND, ARG1, ARG2,.., ARGN]' REST_URL
For example, Redis command SET foo bar EX 100 can be sent inside the request
body as:
curl -X POST -d '["SET", "foo", "bar", "EX", 100]' https://us1-merry-cat-32748.upstash.io \
-H "Authorization: Bearer 2553feg6a2d9842h2a0gcdb5f8efe9934"
HTTP Codes
-
200 OK: When request is accepted and successfully executed. -
400 Bad Request: When there's a syntax error, an invalid/unsupported command is sent or command execution fails. -
401 Unauthorized: When authentication fails; auth token is missing or invalid. -
405 Method Not Allowed: When an unsupported HTTP method is used. OnlyHEAD,GET,POSTandPUTmethods are allowed.
Response
REST API returns a JSON response by default. When command execution is successful, response
JSON will have a single result field and its value will contain the Redis
response. It can be either;
- a
nullvalue
{ "result": null }
- an integer
{ "result": 137 }
- a string
{ "result": "value" }
- an array value:
{ "result": ["value1", null, "value2"] }
If command is rejected or fails, response JSON will have a single error field
with a string value explaining the failure:
{"error":"WRONGPASS invalid password"}
{"error":"ERR wrong number of arguments for 'get' command"}
Base64 Encoded Responses
If the response contains an invalid utf-8 character, it will be replaced with
a � (Replacement character U+FFFD). This can happen when you are using binary
operations like BITOP NOT etc.
If you prefer the raw response in base64 format, you can achieve this by setting
the Upstash-Encoding header to base64. In this case, all strings in the response
will be base64 encoded, except for the "OK" response.
curl https://us1-merry-cat-32748.upstash.io/SET/foo/bar \
-H "Authorization: Bearer 2553feg6a2d9842h2a0gcdb5f8efe9934" \
-H "Upstash-Encoding: base64"
# {"result":"OK"}
curl https://us1-merry-cat-32748.upstash.io/GET/foo \
-H "Authorization: Bearer 2553feg6a2d9842h2a0gcdb5f8efe9934" \
-H "Upstash-Encoding: base64"
# {"result":"YmFy"}
RESP2 Format Responses
REST API returns a JSON response by default and the response content type is set to application/json.
If you prefer the binary response in RESP2 format, you can achieve this by setting
the Upstash-Response-Format header to resp2. In this case, the response content type
is set to application/octet-stream and the raw response is returned as binary similar to a TCP-based Redis client.
The default value for this option is json.
Any format other than json and resp2 is not allowed and will result in a HTTP 400 Bad Request.
This option is not applicable to /multi-exec transactions endpoint, as it only returns response in JSON format.
Additionally, setting the Upstash-Encoding header to base64 is not permitted when the Upstash-Response-Format is set to resp2
and will result in a HTTP 400 Bad Request.
curl https://us1-merry-cat-32748.upstash.io/SET/foo/bar \
-H "Authorization: Bearer 2553feg6a2d9842h2a0gcdb5f8efe9934" \
-H "Upstash-Reponse-Format: resp2"
# +OK\r\n
curl https://us1-merry-cat-32748.upstash.io/GET/foo \
-H "Authorization: Bearer 2553feg6a2d9842h2a0gcdb5f8efe9934" \
-H "Upstash-Reponse-Format: resp2"
# $3\r\nbar\r\n
Pipelining
Upstash REST API provides support for command pipelining, allowing you to send multiple commands as a batch instead of sending them individually and waiting for responses. With the pipeline API, you can include several commands in a single HTTP request, and the response will be a JSON array. Each item in the response array corresponds to the result of a command in the same order as they were included in the pipeline.
API endpoint for command pipelining is /pipeline. Pipelined commands should be
send as a two dimensional JSON array in the request body, each row containing
name of the command and its arguments.
Request syntax:
curl -X POST https://us1-merry-cat-32748.upstash.io/pipeline \
-H "Authorization: Bearer $TOKEN" \
-d '
[
["CMD_A", "arg0", "arg1", ..., "argN"],
["CMD_B", "arg0", "arg1", ..., "argM"],
...
]
'
Response syntax:
[{"result":"RESPONSE_A"},{"result":"RESPONSE_B"},{"error":"ERR ..."}, ...]
For example you can write the curl command below to send following Redis
commands using pipeline:
SET key1 valuex
SETEX key2 13 valuez
INCR key1
ZADD myset 11 item1 22 item2
curl -X POST https://us1-merry-cat-32748.upstash.io/pipeline \
-H "Authorization: Bearer 2553feg6a2d9842h2a0gcdb5f8efe9934" \
-d '
[
["SET", "key1", "valuex"],
["SETEX", "key2", 13, "valuez"],
["INCR", "key1"],
["ZADD", "myset", 11, "item1", 22, "item2"]
]
'
And pipeline response will be:
[
{ "result": "OK" },
{ "result": "OK" },
{ "error": "ERR value is not an int or out of range" },
{ "result": 2 }
]
You can use pipelining when;
- You need more throughput, since pipelining saves from multiple round-trip times. (But beware that latency of each command in the pipeline will be equal to the total latency of the whole pipeline.)
- Your commands are independent of each other, response of a former command is not needed to submit a subsequent command.
Transactions
Upstash REST API supports transactions to execute multiple commands atomically. With transactions API, several commands are sent using a single HTTP request, and a single JSON array response is returned. Each item in the response array corresponds to the command in the same order within the transaction.
API endpoint for transaction is /multi-exec. Transaction commands should be
send as a two dimensional JSON array in the request body, each row containing
name of the command and its arguments.
Request syntax:
curl -X POST https://us1-merry-cat-32748.upstash.io/multi-exec \
-H "Authorization: Bearer $TOKEN" \
-d '
[
["CMD_A", "arg0", "arg1", ..., "argN"],
["CMD_B", "arg0", "arg1", ..., "argM"],
...
]
'
Response syntax:
In case when transaction is successful, multiple responses corresponding to each command is returned in json as follows:
[{"result":"RESPONSE_A"},{"result":"RESPONSE_B"},{"error":"ERR ..."}, ...]
If transaction is discarded as a whole, a single error is returned in json as follows:
{ "error": "ERR ..." }
A transaction might be discarded in following cases:
- There is a syntax error on the transaction request.
- At least one of the commands is unsupported.
- At least one of the commands exceeds the max request size.
- At least one of the commands exceeds the daily request limit.
Note that a command may still fail even if it is a supported and valid command. In that case, all commands will be executed. Upstash Redis will not stop the processing of commands. This is to provide same semantics with Redis when there are errors inside a transaction.
Example:
You can write the curl command below to send following Redis commands using
REST transaction API:
MULTI
SET key1 valuex
SETEX key2 13 valuez
INCR key1
ZADD myset 11 item1 22 item2
EXEC
curl -X POST https://us1-merry-cat-32748.upstash.io/multi-exec \
-H "Authorization: Bearer 2553feg6a2d9842h2a0gcdb5f8efe9934" \
-d '
[
["SET", "key1", "valuex"],
["SETEX", "key2", 13, "valuez"],
["INCR", "key1"],
["ZADD", "myset", 11, "item1", 22, "item2"]
]
'
And transaction response will be:
[
{ "result": "OK" },
{ "result": "OK" },
{ "error": "ERR value is not an int or out of range" },
{ "result": 2 }
]
Monitor Command
Upstash REST API provides Redis MONITOR command using
Server Send Events mechanism. API endpoint is /monitor.
curl -X POST https://us1-merry-cat-32748.upstash.io/monitor \
-H "Authorization: Bearer 2553feg6a2d9842h2a0gcdb5f8efe9934" \
-H "Accept:text/event-stream"
This request will listen for Redis monitor events and incoming data will be received as:
data: "OK"
data: 1721284005.242090 [0 0.0.0.0:0] "GET" "k"
data: 1721284008.663811 [0 0.0.0.0:0] "SET" "k" "v"
data: 1721284025.561585 [0 0.0.0.0:0] "DBSIZE"
data: 1721284030.601034 [0 0.0.0.0:0] "KEYS" "*"
Subscribe & Publish Commands
Simiar to MONITOR command, Upstash REST API provides Redis SUBSCRIBE and
PUBLISH commands. The SUBSCRIBE endpoint works using
Server Send Events mechanism.
API endpoints are /subscribe and /publish
Following request will subscribe to a channel named chat:
curl -X POST https://us1-merry-cat-32748.upstash.io/subscribe/chat \
-H "Authorization: Bearer 2553feg6a2d9842h2a0gcdb5f8efe9934" \
-H "Accept:text/event-stream"
Following request will publish to a channel named chat:
curl -X POST https://us1-merry-cat-32748.upstash.io/publish/chat/hello \
-H "Authorization: Bearer 2553feg6a2d9842h2a0gcdb5f8efe9934"
The subscriber will receive incoming messages as:
data: subscribe,chat,1
data: message,chat,hello
data: message,chat,how are you today?
Security and Authentication
You need to add a header to your API requests as Authorization: Bearer $TOKEN
or set the token as a url parameter _token=$TOKEN.
curl -X POST https://us1-merry-cat-32748.upstash.io/info \
-H "Authorization: Bearer 2553feg6a2d9842h2a0gcdb5f8efe9934"
OR
curl -X POST https://us1-merry-cat-32748.upstash.io/info?_token=2553feg6a2d9842h2a0gcdb5f8efe9934
Upstash by default provides two separate access tokens per database: "Standard" and "Read Only".
-
Standard token has full privilege over the database, can execute any command.
-
Read Only token permits access to the read commands only. Some powerful read commands (e.g. SCAN, KEYS) are also restricted with read only token. It makes sense to use Read Only token when you access Upstash Redis from web and mobile clients where the token is exposed to public.
You can get/copy the tokens by clicking copy button next to
UPSTASH_REDIS_REST_TOKEN in REST API section of the console. For the Read
Only token, just enable the "Read-Only Token" switch.
REST Token for ACL Users
In addition to the tokens provided by default, you can create REST tokens for
the users created via ACL SETUSER
command. Upstash provides a custom ACL subcommand to generate REST tokens:
ACL RESTTOKEN. It expects two arguments; username and user's password. And
returns the REST token for the user as a string response.
ACL RESTTOKEN <username> <password>
Generate a REST token for the specified username & password.
Token will have the same permissions with the user.
You can execute ACL RESTTOKEN command via redis-cli:
redis-cli> ACL RESTTOKEN default 35fedg8xyu907d84af29222ert
"AYNgAS2553feg6a2d9842h2a0gcdb5f8efe9934DQ="
Or via CLI on the Upstash console:
If the user doesn't exist or password doesn't match then an error will be returned.
redis-cli> ACL RESTTOKEN upstash fakepass
(error) ERR Wrong password or user "upstash" does not exist
Redis Protocol vs REST API
REST API Pros
-
If you want to access to Upstash database from an environment like CloudFlare Workers, WebAssembly, Fastly Compute@Edge then you can not use Redis protocol as it is based on TCP. You can use REST API in those environments.
-
REST API is request (HTTP) based where Redis protocol is connection based. If you are running serverless functions (AWS Lambda etc), you may need to manage the Redis client's connections. REST API does not have such an issue.
-
Redis protocol requires Redis clients. On the other hand, REST API is accessible with any HTTP client.
Redis Protocol Pros
-
If you have legacy code that relies on Redis clients, the Redis protocol allows you to utilize Upstash without requiring any modifications to your code.
-
By leveraging the Redis protocol, you can take advantage of the extensive Redis ecosystem. For instance, you can seamlessly integrate your Upstash database as a session cache for your Express application.
Cost and Pricing
Upstash pricing is based on per command/request. So the same pricing listed in our pricing applies to your REST calls too.
Metrics and Monitoring
In the current version, we do not expose any metrics specific to API calls in the console. But the metrics of the database backing the API should give a good summary about the performance of your APIs.
REST - Redis API Compatibility
| Feature | REST Support? | Notes |
|---|---|---|
| String | ✅ | |
| Bitmap | ✅ | |
| Hash | ✅ | |
| List | ✅ | Blocking commands (BLPOP - BRPOP - BRPOPLPUSH) are not supported. |
| Set | ✅ | |
| SortedSet | ✅ | Blocking commands (BZPOPMAX - BZPOPMIN) are not supported. |
| Geo | ✅ | |
| HyperLogLog | ✅ | |
| Transactions | ✅ | WATCH/UNWATCH/DISCARD are not supported |
| Generic | ✅ | |
| Server | ✅ | |
| Scripting | ✅ | |
| Pub/Sub | ✅ | |
| Connection | ⚠️ | Only PING and ECHO are supported. |
| JSON | ✅ | |
| Streams | ✅ | Supported, except blocking versions of XREAD and XREADGROUP. |
| Cluster | ❌ |
To find navigation and other pages in this documentation, fetch the llms.txt file at: https://upstash.com/docs/llms.txt
Summary
- Derived the MCP handler Redis URL from
UPSTASH_REDIS_REST_URLandUPSTASH_REDIS_REST_TOKEN, falling back to existing Redis env vars when missing. app/api/[transport]/route.tsL5-L16 - Passed the derived Redis URL into the MCP handler configuration to ensure production requests use the Upstash endpoint instead of localhost defaults. app/api/[transport]/route.tsL20-L30
Testing
- ⚠️ Not run (not requested)