Glasscubes MCP server
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Glasscubes MCP serverWhich clients still owe us year-end documents, and what's missing?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Glasscubes MCP server
An MCP server that lets Claude, ChatGPT and other MCP clients work with a Glasscubes client portal: workspaces, information requests (document requests sent to clients, and which items are still outstanding), tasks, file and folder metadata, workspace members and calendar events, and (when enabled) creating tasks and changing their state. It is built from Glasscubes' public API documentation and its published Swagger 2.0 document (https://api.glasscubes.com/rest/swagger.json).
Once it's connected, someone at the practice can ask things like:
"Which clients still owe us year-end documents, and which items are missing?"
"What's overdue in the Evans Bakery workspace?"
"What are my open tasks, and what's on the Evans calendar in October?"
"What's in the Year end 2026 folder, and who uploaded the last bank statement?"
With writes enabled: "Create a task for Jo to chase Priya for her P60 by 20 October, and mark 'Draft Evans accounts' as completed."
Tools
Tool | What it does | API calls |
| The current user's workspaces with group and pinned flag. Pages 50 at a time until a page comes back shorter than asked for, which the API documents as the end. |
|
| Labels on the workspaces the user can access. |
|
| One workspace: the user's permission, modules, group, public page. |
|
| Members (users and user groups) with names, company and active status. |
|
| Requests in a workspace with status, due date, recipient name and a count of items per item status. Optional |
|
| One request with every item's status, file count and query/response/note counts, and its assignments. |
|
| Account-wide templates, or a workspace's with |
|
| The user's My Tasks, or a workspace's tasks with the documented |
|
| One task with state, dates, assignees, labels, attachment titles and form submissions. |
|
| Files and folders in a workspace root or one folder: titles, versions, sizes, who updated them, labels. Metadata only. |
|
| Events in a workspace between two dates (sent in the documented |
|
| Creates a task in a workspace or in the user's My Tasks, with optional due date and user/group assignees. Title up to 253 and description up to 63,999 characters: this server's own limits, borrowed from the post endpoint (the spec documents none for tasks). Only registered when writes are enabled. |
|
| Reads the task, sets it to |
|
Not covered on purpose: file downloads, previews and signed URLs (never called); sending, deleting or editing information requests; e-signatures, forms, posts, polls, portfolios, workspace creation and membership changes; the "(Internal)" operations in the spec; and GET operations that change state, which the spec contains and this server never calls: GET /v2/cal/delete-event/{eventId} (deletes an event), GET /v2/file2/{id}/lock/add and /lock/remove, GET /v2/user/expiretoken and GET /v2/user/invalidate (end the current token). There is no reminder endpoint for information requests in the spec, so there is no reminder tool.
Related MCP server: clio-mcp
Setup
Requires Node 18 or later.
npm install
npm run buildCredentials
Glasscubes issues a client_id and client_secret to an application on request ("Simply contact us for your client ID", support article "Glasscubes API"). With those, the API documentation describes getting a user's access token from /auth/{cid}/passwd with that user's email address and password; /auth/code (a code handed to your redirect URL after the user logs in) is listed in the spec but the documentation page says it "is not currently supported, however it can be implemented on request". Access tokens are valid for 24 hours; /auth/refresh exchanges a refresh token for a new access and refresh token pair.
This server never takes an email address or password and never calls the password endpoint. It takes tokens you already have:
GLASSCUBES_ACCESS_TOKENon its own works for up to 24 hours.Add
GLASSCUBES_REFRESH_TOKENwithGLASSCUBES_CLIENT_IDandGLASSCUBES_CLIENT_SECRETand the server renews the access token itself throughPOST /v2/auth/refreshwhen the API rejects it. With these three set, the access token can be left out and the server refreshes before its first call.
Claude Desktop: add this to claude_desktop_config.json:
{
"mcpServers": {
"glasscubes": {
"command": "node",
"args": ["/absolute/path/to/glasscubes-mcp/dist/index.js"],
"env": {
"GLASSCUBES_ACCESS_TOKEN": "your-access-token",
"GLASSCUBES_REFRESH_TOKEN": "your-refresh-token",
"GLASSCUBES_CLIENT_ID": "your-client-id",
"GLASSCUBES_CLIENT_SECRET": "your-client-secret"
}
}
}
}Claude Code:
claude mcp add glasscubes \
-e GLASSCUBES_ACCESS_TOKEN=your-access-token \
-e GLASSCUBES_REFRESH_TOKEN=your-refresh-token \
-e GLASSCUBES_CLIENT_ID=your-client-id \
-e GLASSCUBES_CLIENT_SECRET=your-client-secret \
-- node /absolute/path/to/glasscubes-mcp/dist/index.jsVariable | Required | Meaning |
| yes, unless the three refresh variables are set | A user's access token, sent as |
| no | That user's refresh token, for |
| with a refresh token | The client ID Glasscubes issued for your application. |
| with a refresh token | The matching client secret. |
| no |
|
| no | Defaults to |
Safety defaults
Read-only unless
GLASSCUBES_ALLOW_WRITES=true. Read tools carry the MCPreadOnlyHintannotation.create_taskonly adds, so it is marked not destructive and not idempotent.set_task_stateoverwrites a task's state, so it is marked destructive (and idempotent); it reads the task first and returnsprevious_state, which can be passed back to undo the change.Personal data of clients and staff: names, company names and client codes are returned; email addresses (members, task assignees, request recipients and assignments, calendar attendees), calendar event locations (often an address), an information request's
publicUrland each assignment'spublicUrl(links into the client's view of the request) are only returned withinclude_contact_details=true. Profile picture URLs are never returned.Free text is redacted unless
include_contact_details=true: names of people, workspaces, workspace groups, user groups, modules and labels, client codes, request subjects, descriptions and item names, task titles and descriptions, file and folder titles, form names, event titles and descriptions, a public workspace's title and description, template names, and Glasscubes' own error messages. In all of these, email addresses become[email redacted], phone-number-like sequences[phone redacted], UK postcodes (any case)[postcode redacted]and National Insurance numbers[NI number redacted]. A payment card number (13 to 19 digits that pass the Luhn check) becomes[card number redacted]whether or not contact details were requested. The phone match is a heuristic: international numbers written with+or00(optionally with a bracketed trunk prefix or area code, as in+44 (0)7700 900123or+1 (415) 555-2671), UK numbers with a bracketed area code, and UK-style0…numbers of 9 to 11 digits; other digit strings starting with0are redacted too.Not redacted, because they cannot be told apart from ordinary text, dates, references and figures: street addresses (only the postcode is caught), dates of birth, UTRs, bank sort codes and account numbers, and money amounts such as salaries. A practice that types these into request descriptions, task text or file titles will see them returned.
Calendar events never include video-call details: Zoom host and join links and passwords, Teams join links and conference codes are dropped;
has_video_callsays whether there is one.No file is ever downloaded or previewed;
list_filesreturns metadata only.IDs must be positive whole numbers of at most 15 digits (the spec types every path ID as
integer/int64; 15 digits keeps every ID exact as a JSON number, which is howcreate_tasksends workspace and assignee IDs); anything else is refused before a request is made. Calendar dates must be realYYYY-MM-DDdates withfromnot afterto;create_taskrefuses a start date after the due date (the API's errCode 130) and a start date without a due date, before sending anything.Errors follow the documented convention (HTTP 400 with
{errCode, errMsg}). errCode 121 or 115, or an HTTP 401, is treated as a rejected token: with refresh configured the token is refreshed once and the request repeated, otherwise the message says to checkGLASSCUBES_ACCESS_TOKEN. errCode 120, 133 or 200 (or an HTTP 404) is reported as not found; 116 as access denied; 100, 109 to 113 and 119 as a problem with the account or user. The access token, refresh tokens and client secret are replaced with[redacted]if they ever appear in an error message.Glasscubes documents no rate limit and no 429. Requests are spaced 250 ms apart. A 429 is retried at most twice for any method, waiting for
Retry-After(seconds, fractional seconds or an HTTP-date; 2 s then 4 s when absent); a wait longer than 10 seconds makes the call give up at once and say how long to wait. 502, 503 and 504 are retried the same way forGETonly (the suite exercises 502 on a GET; 503 and 504 take the same code path).PUT /v2/taskandPOST /v2/task/{id}/stateare never retried after a gateway error, because the request may already have been processed; the message says to check withlist_tasksorget_taskfirst. The token refresh (a POST) is not retried after a gateway error either.A read that gets a 200 whose body is not JSON (a proxy or login page), is empty, or is JSON of the wrong shape (
nullor an object where the API documents a list;null, a list or an empty object where it documents a single record) is an error saying the result is unknown, never an empty list: "no documents outstanding" must not come from a missing answer. An empty 200 body is accepted only from the writes:POST /v2/task/{id}/statedocuments no response body, and aPUT /v2/taskthat answered 200 without the created task is reported as created with a note to checklist_tasks.
Tests
npm testThe suite runs offline once spec.json is present (it is gitignored and downloaded from https://api.glasscubes.com/rest/swagger.json on the first run if missing). It takes about 45 seconds.
Validates every fixture record against the Swagger 2.0 definitions (
WorkspaceListItem,WorkspaceListLabel,WorkspaceInfoV3,WorkspaceMemberInfo,InformationRequestReadDto,InformationRequestTemplateReadDto,TaskResponse,DiscItem,EventInfo) with Ajv in draft-04 mode, and also fails on any key a definition does not declare, since the definitions allow extra keys and mark almost nothing required. Two negative controls prove the schema and the key walk actually reject things.Starts a local mock of the API under
/restthat serves those fixtures and validates its list, detail and task-creation responses against each operation's documented response schema. The spec publishes no schema for errors; the mock's error bodies follow the documentation page's{errCode, errMsg}form and are validated against a schema written from that text. The mock answers a missing or wrong token with 400 and errCode 121, an unknown ID with 400 and errCode 120 "Item deleted", a bad calendar date with errCode 144, and a wrong refresh token with errCode 104 (all documented codes; which one the live API sends in each case is the mock's assumption). The refresh operation's documented form fields and content type are asserted from the spec.Starts the built server and drives it over stdio with the official MCP client: 28 checks covering tool names and annotations (and that no task length limit is attributed to the API), every read tool,
first/countpaging to the documented short page with requests about 250 ms apart (and continuing fromfirst), a page ofcount+1 cut tomax_results,max_resultscaps on information requests and tasks,q/g/l,workspaceIdandorderpassed through, the localstatusesfilter, the redaction patterns themselves (including what they do not catch), redaction of emails, phones, postcodes and NI numbers by default in free text and in workspace, group, module and label names and client codes, and their return on request, event locations only on request, card numbers redacted always, profile pictures and video-call secrets never returned, no download endpoint ever called, thePUT /v2/taskbody validated against the spec'sTaskRequest(15-digit IDs sent exactly), aPUTanswered 200 without a body, the state change as a query parameter withprevious_stateread first and used to undo, local refusals, bad IDs (including 16 digits and more), statuses,orderand bounds refused before any request, the not-found (errCode 120, 133, 200 and HTTP 404), access-denied (116) and account-error (100, 109 to 113, 119) messages, an expired token refreshed with the documented form POST and the rotated refresh token used next time, starting with only a refresh token, a refresh that hits a 502 not retried, an early refresh before theexpiresIna refresh returned, three simultaneous calls sharing one refresh, and a token rejected again after refreshing reported without a second refresh, error text redacted with the access token, refresh token and client secret scrubbed, the 429 retry (seconds, fractional and HTTP-dateRetry-After, the 2 s fallback when it is missing, a persistent 429, a wait above the cap, a 429 onPUT /v2/taskretried once), 502 retried for GET (and reported after 3 in a row), a 502 on the PUT and a 503 on the POST never retried, a 200 that is not JSON, empty, or JSON of the wrong shape for every read tool, the write gate (unset andfalse), wrong access and refresh tokens (errCode 121 and 115, and an undocumented 401), a pastedBearerprefix, and, as the last check, that every request of the whole run went under/rest, carried a Bearer token the mock issued or the deliberately wrong one of the wrong-token checks (none on the refresh), and matched a documented method and path, and that the password route was never called.
Status
This is a working prototype. It has not been run against the live API, because it was built without a Glasscubes account (there is no free trial and client IDs are issued on request). Everything below comes from the spec and the documentation page and should be confirmed on a real account:
What an expired or wrong token gets back. The documentation lists general errors 121 ("OAuth problem…") and 115 ("Unauthorised access") without saying which one, and with which HTTP status, a bad token produces; the server refreshes on either (and on a 401).
What an unknown ID gets back. The mock answers 400 with errCode 120 "Item deleted", which the spec documents for a missing workspace on several endpoints; the live API might instead answer 200 with an empty body or
null, which this server reports as an unknown result rather than as not found.Token refresh: whether
POST /v2/auth/refreshreally rotates the refresh token (the documentation says it returns "a new user access token and refresh token pair") and whether the old one stops working. The new pair is kept in memory only, so after a restart the refresh token in the environment may already have been used; the error message then says to obtain a new pair.What
q,gandlonGET /v3/workspace-list/{first}/{count}do (the spec gives no description; the mock reads them as a name search, a group ID and a label), and the largestcountthe API accepts (50 per page is this server's own choice).Whether that page covers
[first, first+count)or, as the summary writes it,[first, first+count]. The mock serves the half-open range (at mostcountitems); the server advances by the number of items actually returned and cuts the result tomax_results, so either reading works, and the tests include a page ofcount+1.orderonGET /v2/task/workspace/{id}: the spec says the endpoint returns tasks that are not completed, and liststodo,allandcustomwithout saying whetherallincludes completed tasks. The mock ignores it.Task dates. The spec asks for the beginning and end of the day, then converted to UTC; this server takes the day boundaries in UTC and sends
T00:00:00.000ZandT23:59:59.000Zon the given days, so during British Summer Time the task spans 01:00 to 00:59 UK time. WhetherstartDatemay be omitted whenendDateis given is not documented; the server always sends both.The response of
POST /v2/task/{id}/state, documented only as "default: successful operation" with no body.Length limits for task titles and descriptions: the spec documents none for tasks.
create_taskrefuses titles over 253 and descriptions over 63,999 characters on its own, borrowing the limit the spec documents forPUT /v2/post(errCode 125).The meaning of the item statuses (
WAITING,COMPLETE,DELEGETED,AMEND,RESUBMITED,VERIFIED,DECLINED) and request statuses; the spec lists them without descriptions, so the server reports counts per status rather than deciding which are "outstanding". The tool descriptions sayWAITINGpresumably means not yet provided, and say that this is an assumption.For
STANDARDversusPERSONAL_TAXrequests, which ofsentToUser,sentToEmail,firstName/lastNameandclientCodeare filled in.Whether the calendar range is inclusive and in which time zone the dates are read.
Rate limits: none documented, and no 429 appears in the spec; the throttle is a guess on the polite side.
Whether Glasscubes'
errMsgtexts ever echo personal data or tokens; the server redacts and scrubs them regardless.
Going to production
This version runs locally over stdio with one user's tokens. For a practice to connect from claude.ai or ChatGPT without handling tokens, the next step is a remote server (Streamable HTTP) behind OAuth, hosted by Glasscubes, built on the /auth/code flow the documentation says can be enabled, and then a listing in the Claude and ChatGPT connector directories.
Licence
MIT. Built by Alexandru Dragoș (alexandru.dragos96@gmail.com) with an AI agent (Claude) working under his direction.
This server cannot be deployed
Maintenance
Related MCP Connectors
Client intake: files, copy and logins from clients, from the browser or your AI agent.
- AurentiaOAuthfr.aurentia
Your Aurentia workspace — projects, CRM, tasks, deliverables — in Claude, Cursor or any MCP client.
Governed memory and workspace for any AI: tasks, calendar, mail and pages, with per-action consent.
Task management for people and AI agents, with scoped OAuth access to issues, projects, and docs.
Related MCP Servers
- AlicenseCqualityAmaintenanceEnables Claude to access and manage your law firm's MyCase account, including cases, clients, tasks, invoices, and more.1001MIT
- AlicenseNot gradedqualityAmaintenanceConnects Claude to Clio practice management, enabling AI-assisted access to matters, contacts, documents, tasks, and billing with audit logging and encryption for law firm compliance.299 npm25MIT
- AlicenseNot gradedqualityCmaintenanceEnables AI assistants to interact with Jurisly workspaces for tasks like drafting invoices, finding hearing dates, and editing documents through natural language.Apache 2.0
- AlicenseNot gradedqualityCmaintenanceEnables AI assistants to read, create, and update legal practice data—cases with history and movements, clients, tasks, and financial transactions—using the firm's API token.MIT