Connect an AI assistant
Reassign has a Model Context Protocol (MCP) server. An AI assistant that supports MCP can read and change your day plan through this server.
The MCP server accepts only OAuth sign-in. For scripts and your own apps, use the REST API with a personal access token.
Connect an AI assistant
- MCP server URL
https://reassign.app/api/mcp- Claude Code
claude mcp add --transport http reassign https://reassign.app/api/mcp
Cursor: Add to Cursor
Before you start
You need these items:
- A Reassign account.
- Reassign Pro. The 7-day free trial includes it.
- An AI app that can add a remote MCP server.
The trial needs no card. Without Pro or the trial, the sign-in page shows an "Upgrade to Pro" button.
Server address
Add this address as a remote MCP server in your AI app:
MCP server address
https://reassign.app/api/mcp
You can also copy the address in the Reassign web app. Go to Settings › Integrations › MCP and find the Server address field.
| Item | Value |
|---|---|
| Transport | Streamable HTTP, in stateless JSON mode |
| Request | One POST for each call. The result is one JSON body. |
| Server-sent events (SSE) | Not supported. A GET request gets HTTP 405. |
| Session | The server keeps no session. |
| Server name | reassign (title "Reassign") |
| Server version | 2026.10.3.1, plus + and a 12-character build commit on a deployed server. A new version does not clear a cached tools/list. |
Connect
Do these steps in an app that supports MCP:
- Add
https://reassign.app/api/mcpas a remote MCP server. - The app opens the Reassign sign-in page. Sign in with an email code or a passkey.
- Read the access that the app asks for. Then click Allow.
- In Reassign, go to Settings › Integrations › Authorized apps. Make sure that the app shows in the list.
The assistant can then read your events and create, edit, and delete them.
If you connected a calendar, the changes of the assistant also sync to that calendar. This is the same as a change that you make on the dial. The assistant cannot change events from a read-only calendar. Refer to Calendars.
claude.ai and Claude Desktop
claude.ai and Claude Desktop use the same connectors for your account. A connector that you add on claude.ai is also in Claude Desktop.
- Go to Settings › Connectors.
- Click Add custom connector.
- Paste the URL
https://reassign.app/api/mcp. - Sign in to Reassign and click Allow.
Claude Code
-
Run this command in your terminal:
Terminal
claude mcp add --transport http reassign https://reassign.app/api/mcp -
Start Claude Code, run
/mcp, and select reassign. -
Sign in to Reassign in the browser, and click Allow.
ChatGPT
- Add
https://reassign.app/api/mcpas a remote MCP server (a custom connector) in ChatGPT. - Sign in to Reassign and click Allow.
The menu names in ChatGPT can change.
Sign-in and permissions
The server uses OAuth 2.0 with PKCE (S256). Your AI app does the OAuth steps itself:
- The app sends a request without a token. The server replies with HTTP 401 and a
WWW-Authenticateheader. - The header points to the metadata at
/.well-known/oauth-protected-resource/api/mcp. - The app registers itself at
/api/oauth/register(dynamic client registration). - The app opens the consent page. You sign in and click Allow or Deny.
- The app gets an access token and sends it as
Authorization: Bearer <token>.
The consent page shows the name of the app and the label "Unverified app" for an app that registered itself.
Scopes
| Scope | Consent title | Access |
|---|---|---|
events:read | View your schedule | Read your events, plans, and reflections. |
events:write | Read and edit your schedule | Read, create, change and delete events and other plan data. It includes events:read. |
- For
events:write, the consent text is "Read your schedule, and add, change, or remove events." - If the app asks for no scope, the server gives both scopes.
- The consent page shows only the scopes that the app asks for. It has no control to select read-only access.
- A token refresh cannot add a scope.
- Each token refresh returns a new refresh token and spends the old one. The client must store the new refresh token each time. Refer to Authentication.
Token lifetimes
| Item | Lifetime |
|---|---|
| Authorization code | 60 seconds |
| Access token | 1 hour |
| Refresh token | 30 days |
Personal access tokens
The MCP server accepts only OAuth access tokens. It does not accept personal access tokens (prefix rsk_live_). It also refuses an OAuth token for the REST API. Use personal access tokens with the REST API. Refer to Authentication.
Revoke access
- In Reassign, go to Settings › Integrations › Authorized apps.
- Find the app in the list. The list shows the scope, the date of approval, and the date of last use.
- Click Revoke.
The server stops all tokens of that app immediately. The app gets HTTP 401 with the detail authorization revoked.
Tools
Reassign has 10 tools. A read tool needs events:read or events:write. A write tool needs events:write.
| Tool | What it does | Access |
|---|---|---|
get_schedule | Reads the events, free time and load for a date range (from to to). For one day, send the same date two times. The load is for each area, activity type, and project. It can also include weather and energy reports. | Read |
find_event | Finds scheduled events and Inbox items by name. | Read |
show_day | Shows the day as the interactive 24-hour dial in the conversation. | Read |
write_events | Creates, updates, shifts, or reflects events, or changes their checklists, one or many in one call. An update with a new start or end moves an event. Optional dryRun: true checks the ops without applying them. | Write |
delete_events | Deletes events or clears whole days. | Write |
manage_categories | Creates, updates, or deletes areas, activity types, and projects. It can also split or relink a project. A delete of a category that items use needs reassignTo. | Write |
manage_inbox | Writes to the Inbox, the tray of time blocks that have no time yet. | Write |
undo_changes | Reverses a recent change with its undo token. | Write |
review_day | Confirms the review of a past day, or discards the review of any day. | Write |
send_feedback | Sends 1 to 10 product feedback reports together to the Reassign team. It does not change your schedule. | No scope |
send_feedback needs no scope, so a read-only token can report a problem. It writes no user data. Refer to Rate limits for its limits.
tools/list can also show an eleventh tool, get_more_tools:
- It is not a Reassign tool. The PostHog MCP SDK adds it when the product analytics of the server are on.
- An assistant calls it when no tool fits the request. It sends a
contexttext that tells what it needs. - The server records the first 500 characters of
contextas a missing-tool report. The tool changes no data. - It has no REST twin.
The server does not capture the assistant's model. Tool schemas have no llm_model parameter, and results contain no conversation_id block. Until 2026-12-01, calls from an older cached schema may still send llm_model or conversation_id; the server strips these arguments before validation. Refresh tools/list to get the current schemas.
- All dates are ISO
YYYY-MM-DD. - A time is a local datetime
YYYY-MM-DDTHH:MMin the time zone of the user, with no offset. A span isstartandend. An event past midnight ends on the next date. - A result with a span gives
timezoneone time, at the top level. - Each tool refuses an argument that it does not know.
get_schedulegivesintegrations.sources[].account, the account name at the calendar provider, to every caller.get_schedulegivescopyStyleon each writable event calendar inintegrations.sources[].calendars[], andbusyCopyTitlewithbusy. It can also giveintegrations.aiRuleWarnings. Refer to Scheduling.- The clock times in the prose of a tool, for example in
show_dayand in theget_scheduleweather line, are 24-hour (15:00). The time format setting of the app does not change them. - Shared fields use the same names as the REST API. Refer to Core concepts and the REST reference, for example Events and Scheduling. The MCP read fields below describe the differences.
Read a schedule
Call get_schedule with from and to. It returns now, timezone, the events, free slots, and load for each day. The dates are inclusive. For one day, send the same date in both fields.
minDurationis an optional whole number from 1 to 1440, in minutes. It keeps onlyfreeSlotsat least that long. It returns each full gap and leaves the events unchanged.includeLookups: falseleaves outareas,activityTypes,projects, andintegrations. Use it when the assistant has them from an earlier call.includeSeries: trueadds the recurring series inseries.includeBacklog: trueadds up to 50 Inbox items inbacklog, top of tray first.backlogPlannedOnfilters by planned day.backlogProjectIdfilters by project; send"none"for the items with no project.backlogMinPriority(0 to 4) keeps the items with that priority or a higher priority. PassnextBacklogOffsetasbacklogOffsetwith the same filters for the next page;nullmeans the last page. These arguments needincludeBacklog: true.projectslists the projects:{ id, name, areaId }. An archived project also hasarchived: true. An archived project refuses new links. Amanage_categoriesprojectupdatewitharchived: falserestores it.- Each day has
loadByProject, the blocking minutes for each project.projectId: nullis the time with no project. A read of more than one day also has a top-levelloadByProjectwith the total. Refer to Projects and priority. - To find an Inbox item by name, use
find_event.get_schedulerefusesbacklogQuery. The RESTGET /scheduleendpoint still accepts it.
Weather and energy
For one day, get_schedule can include two text reports:
| Argument | Result |
|---|---|
includeWeather: true | Replaces the short weather headline with the full forecast for the day. Use it for outdoor plans or weather questions. |
weatherLocation | A city or place name to forecast, for example London. Requires includeWeather: true. Omit it to use the saved city, or a city guessed from the account's time zone. |
includeEnergy: true | Adds energy: the forecast energy curve, with peak and dip windows from logged sleep. With no sleep logged, the report asks the user to log sleep. |
includeWeather: true and includeEnergy: true each require from to equal to. A range, or weatherLocation without includeWeather: true, fails input validation.
get_schedule arguments
{
"from": "2026-10-03",
"to": "2026-10-03",
"includeWeather": true,
"weatherLocation": "London",
"includeEnergy": true
}
The weather and energy values are prose. Their text can change; do not parse it. With weatherLocation, the forecast date and times are local to that place, and the report names its IANA time zone. The top-level timezone still applies to events and free slots.
For REST, use GET /weather and GET /energy. REST GET /schedule does not accept these three arguments.
Find events and Inbox items
Call find_event with a query. It searches names, with a case- and accent-insensitive match. Events match fuzzily; an Inbox name must contain the query.
find_event arguments
{
"query": "dentist"
}
The result is { events, inbox, inboxMatchedCount, nextInboxOffset, ambiguous, timezone }.
eventsis best match first. A series appears once, as the occurrence that matches best; a tie gives the one nearest to today.ambiguousistruewhen different events match equally well. Inbox matches do not affect it.- Each event has a
scorefrom 0 to 1 for its name match:1is exact,0.9is a prefix, and0.75is a substring. Matches below0.34are omitted. Inbox items have noscore. inboxhas up to 50 matches, top of tray first, in the same shape as theget_schedulebacklogitems. Use their ids withmanage_inbox.areaIdandactivityTypeIdfilter both lists.from,to, andtimeOfDayfilter events only. The date range includes an event that overlaps a requested day, also an overnight event that started earlier.timeOfDayuses the start time. See Search events for the event search window and filters.inboxMatchedCountis the total after filtering. To read the next page, sendnextInboxOffsetasinboxOffsetwith the same query and filters. Anulloffset means the last page.inboxOffsetis a nonnegative integer and defaults to0. It pages Inbox items only; it does not pageevents.
REST GET /events/search returns { events, ambiguous, timezone }. To search the Inbox through REST, use GET /schedule with includeBacklog=true and backlogQuery.
Undo tokens
- Each write tool call that changes data and records an undo receipt returns one
undoTokenand itsexpiresAt, at the top level. This is true forwrite_events,delete_events,manage_categories,manage_inbox, andreview_day. - One token undoes all the changes of that call.
- A call that changed nothing returns no
undoToken. A rejected batch also returns noundoToken. If the server cannot record the undo, the call also returns noundoToken, and the change stays. Areview_daydiscard of a day with nothing recorded returnsnoop: true, emptyupdatedanddeletedIds, and noundoToken. - Send the token to
undo_changesbeforeexpiresAt(30 minutes). After that, the change stays. - You can use each token one time only.
- One
undo_changescall takes 1 to 20 tokens.undo_changesreturns no new token. - A
stalerow can list the rows that block the undo inerror.conflictingRows. Refer to Stale tokens.
Batches
write_events,delete_events, andmanage_inboxtake 1 to 50 operations in one call.- A batch is atomic by default. If one operation fails, the server applies none of them.
- With
partial: true, the server applies the valid operations and reports the others as errors. - A
scheduleoperation ofmanage_inboxobeys the rules of an event write. The span is 5 minutes to 168 hours. A blocking block that overlaps a blocking event fails withconflictandnearestSlots. get_schedulegivesuserPreferences.conflictPolicy. Its value is always"propose": a write that overlaps a blocking event fails withconflictand givesnearestSlots.- The result has one row for each operation:
{ index, status, result?, error?, reason?, warnings? }.statusis"ok","error", or"skipped". - For
manage_categories, the rows are in the arraysareasandactivityTypes. The result has aprojectsarray only when the call sent project ops. write_eventsanddelete_eventsread the result rows after the full batch commits. A later operation can change the row of an earlier operation.- A
manage_categoriesdelete of a category that events, Inbox items, trackers, or calendar defaults use needsreassignTo. Send another id to move the links, ornullto clear them. Without it, the row fails withvalidation, and itserrorhasusageandreassignTargets. For an area,usagealso hasprojects, the count of its projects that are not archived. Ask the user, then send the delete again. Refer to Delete a category that items use. - A
manage_categoriesdelete of a shared default hides it, and your copy of it, for you only. - A
manage_categoriescreate or rename to the name of an area or an activity type that exists fails withconflict. Use the id of that category. - A project name must be unique among your live projects, in all areas. A duplicate fails with
conflict. A delete of a project that a synced task list or Linear project feeds also fails withconflict. Link the list to a different project first, or archive the project. write_eventsandmanage_inboxtakeprojectIdandpriority(0 none to 4 urgent). When a write sets a new project and noareaId, the item gets the area of the project, if the project has an area. Onupdate,projectId: nullremoves the project and keeps the area.
An ok row from write_events can have warnings: ["classification_pending"]. The change is saved, but queued AI classification can fill eligible fields after the reply. A create keeps its kind, also the default blocking. Refer to Rows. Read the event again if you need its latest classification. The warning appears only when classification is queued and the account and plan allow it.
Check an event write
Add top-level dryRun: true to write_events to check its operations without applying them. It still requires events:write.
write_events dry run arguments
{
"dryRun": true,
"ops": [
{
"op": "create",
"name": "Deep work",
"start": "2026-10-03T14:00",
"end": "2026-10-03T15:30"
}
]
}
- A valid op returns
status: "skipped"andreason: "Dry run: this op is valid and was not applied.". - An invalid op returns its usual
error, includingconflictsandnearestSlotswhen available. - A dry run with only valid ops succeeds. If any op fails, the call has
isError: true, including withpartial: true; valid ops still appear as skipped rows. - The call writes nothing and returns no
undoToken. It does not reserve a time. - To apply the ops, send them again without
dryRun. The server checks conflicts again against the schedule at that time.
This flag belongs to MCP write_events. REST POST /events and MCP delete_events do not accept it.
Schedule new work
- Call
get_schedulefor the date or range. Read the localnow,timezone, and each day'sfreeSlots. SetminDurationto the requested number of minutes to omit shorter gaps. - Choose a span that fits the requested duration inside a free slot. For a new event, call
write_eventswith anop: "create", aname, and the concrete localstartandend. - Keep the returned
undoTokensoundo_changescan reverse the booking.
write_events arguments
{
"ops": [
{
"op": "create",
"name": "Deep work",
"start": "2026-10-03T14:00",
"end": "2026-10-03T15:30"
}
]
}
- The example assumes that the span fits in a free slot from the preceding read. Times use the account's
timezone. - On today, the returned free slots begin on a 5-minute mark more than 5 minutes after
now. write_eventschecks for conflicts when it writes. If the time became busy, read the schedule again or choose a returnednearestSlotsspan, then send the revised create.- For an existing Inbox item, use
manage_inboxwithop: "schedule", itsid, and the chosenstartandend. This places the same item on the dial. calendarIdandmirrorCalendarIdson a create choose the calendars.mirrorStylessets each copy tofull,private, orbusy. A series with copies needs a home calendar. A series from a connected calendar is an exception. Refer to Rules of the fields.- A client-minted create
idmust be a UUID. Omit it to let the server make one.
REST clients can use POST /schedule/plan to search a window and book its best slot in one call.
Send product feedback
Collect the session's product feedback in one send_feedback call, with one item per issue in reports. Send 1 to 10 reports. Each needs a kind (bug, idea, or other) and a nonempty message of up to 4000 characters. Describe the problem, what you expected, and steps to reproduce. Leave out personal details and private schedule contents; the account is attached automatically.
send_feedback arguments
{
"reports": [
{
"kind": "bug",
"message": "The dial did not refresh after a successful event move. Reopening the day showed the new time."
},
{
"kind": "idea",
"message": "Let the dial highlight the free slots returned for a requested duration."
}
]
}
The tool returns {} once accepted. One call sends one email to the team. The user receives at most one acknowledgment email per UTC day. REST POST /feedback keeps its single-report body { kind, message, submissionId? } and returns HTTP 204.
Retries
- A
write_eventscreate has norequestId. If a response is lost, read the schedule to check whether the event was created before you send it again. A create can send its own UUIDid. After a lost response, read that id to check the create. send_feedbacktakes an optional top-levelsubmissionId(UUID). Use the same value with identical reports for retries within 24 hours; use a new value for new content.
Resources
The server has one resource and no prompts.
| URI | Name | Content |
|---|---|---|
ui://reassign/dial | Reassign dial | The interactive 24-hour dial as an HTML page, for the conversation. |
The show_day tool uses this resource. An app that supports MCP Apps can show the dial in the conversation.
Errors
Request errors
The server sends these errors before a tool runs. The body is a JSON-RPC error.
| HTTP | JSON-RPC code | Message | Cause |
|---|---|---|---|
| 401 | -32001 | Unauthorized | No token, a token that is not valid or expired, or a revoked app. |
| 403 | -32600 | Reassign needs an active subscription. | The account has no Reassign Pro plan and no trial. error.data is { "code": "permission", "feature": "mcp" }. |
| 403 | -32600 | Origin not allowed. | A browser request from an origin that is not allowed. |
| 405 | -32000 | Method not allowed — this MCP endpoint is POST-only (no SSE). | A GET request. |
| 500 | -32603 | Internal server error. | A server error. Do not retry. |
| 503 | -32000 | Temporary backend error — please retry. | A temporary server error. Retry the request. |
Tool errors
A tool that refuses a call returns isError: true and one text block. The text is the JSON error envelope { "error": { code, message } }, also for a tool that returns prose. The error can also have the optional detail fields of the REST API: issues, feature, conflictingRows, conflictingRowsTruncated, usage, and reassignTargets. Refer to Error format. The code is also in _meta["reassign/error"].code. _meta has only the code.
For a rejected batch, the text is { error, timezone?, results }. For manage_categories, it is { error, areas, activityTypes, projects? }. The detail fields are only in the rows. _meta has a code only when all failed operations have the same code. _meta never has the codes unauthorized or batch_rejected.
Arguments that do not match the input schema of a tool do not get to the tool. The MCP SDK refuses them with isError: true and a prose text Input validation error: …, with no _meta. The REST API answers the same input with 422 validation.
| Code | Meaning |
|---|---|
conflict | The requested time, name, or id is already taken, or a short busy state blocks the write. A retry can work only for the busy state. |
not_found | The event, area, activity type, project, or day does not exist. An archived project also gives not_found for a new link. |
validation | The arguments are wrong: out of range, contradictory, or not complete. A bad operation row has issues. |
permission | The target item does not allow the action, for example a park of a recurring event. |
scope | The token does not have the scope that the tool needs. |
stale | An undo_changes row cannot apply, because a row that the write changed has a newer change. The undo changes nothing. The row can have conflictingRows. |
read_only | You cannot change the event or the field from Reassign. For example, a task app owns the planned day of an Inbox item, or a project change cannot move the linked task in its app. |
rate_limited | The caller sent too many requests. Wait, then try again. |
internal | The server failed. A retry can work. |
- In an atomic batch of
write_events,delete_events,manage_inbox, ormanage_categories, the valid operations showstatus: "skipped"when another operation fails. Only the failed operations showstatus: "error". - A
write_eventsdry run usesskippedfor every valid operation even when all of them are valid. Refer to Check an event write. - In
write_events,manage_inbox, andmanage_categories, a bad operation becomes an error row with the codevalidation. It does not fail the full call. - A
write_eventsormanage_inboxcall whose writes changed data is never a refusal. If the server cannot read a changed item again, its row has the codeinternal. The call keeps any recordedundoToken. - An
undo_changesrow fails withconflictwhile a calendar sync sends the same change. The undo changes nothing. Try it again after a short time.
Rate limits
The server has no general rate limit for tool calls, and no limit for each token. The limit of 600 requests per minute for each OAuth grant or personal access token applies to the REST API only. Refer to Errors.
Only send_feedback has limits:
| Limit | Value |
|---|---|
| Each user | 10 in 1 minute |
| Each user | 30 in 1 hour |
| All users | 120 in 1 minute |
These limits count submissions, including retries and delivery failures, across the app, REST, and MCP. A grouped submission counts once. Above a limit, send_feedback returns the code rate_limited. Each server instance counts these limits separately.
The OAuth token endpoint has its own limit for each IP address. Refer to Authentication.
Example prompts
Type requests such as these to your assistant:
- "What is on my schedule today?"
- "Find 90 minutes of free time tomorrow afternoon for deep work."
- "Move my gym session to 18:00."
- "Clear my plan for Friday." Then: "Undo that."
- "Mark my events from yesterday as kept or skipped, then confirm the day."