Skip to main content

Google Connectors

The signed-in person's own Google Calendar, Drive and Gmail, connected by that person and used through codespar_calendar, codespar_drive and codespar_gmail. Reads answer at once; every write is a preview the person confirms before anything reaches Google.

4 min read
View MarkdownEdit on GitHub

Three connectors, each connected on its own by the signed-in person: Google Calendar (google-calendar, tool codespar_calendar), Google Drive (google-drive, codespar_drive) and Gmail (gmail, codespar_gmail). A connection belongs to that person in that project: another member of the organization never sees it, uses it, or reads what it returns. The tools are on the hosted server while the connectors are switched on for the deployment.

A person, not a key. Every call needs a verified person, and so does connecting. The dashboard's Shop assistant presents the person's own session. A project API key or an OAuth token carries no person and is refused with 403 bearer_token_has_no_person (details.surface: "connector"), so an external client connected with a csk_ key or the server's OAuth consent sees the tools listed and cannot use them yet.

Connecting

The person connects each connector from Shop › Preferências, section Conexões Google, which runs the Connect Link flow for their own account:

  1. POST /v1/connect/start with server_id (google-calendar, google-drive or gmail), the person's own user_id and an https redirect_uri answers Google's consent address.
  2. The person consents at Google. The connector asks for its product scope (calendar, drive or gmail.modify) and the identity scopes that say which Google account it is.
  3. Google returns to the redirect_uri with status=connected&connection_id=…&server_id=…, or status=denied or status=error&error=….

GET /v1/connectors lists the three with their state for the person: connected, not_connected, or consent_required when the grant is gone at Google. DELETE /v1/connectors/connections/{id} disconnects one and revokes the grant at Google when no other connector of the person still uses it. If the person unticks a scope at Google, reads still work where a narrower scope allows them, and a write answers connector_scope_insufficient naming the scope it needs.

Reads and writes

Reads answer at once. Text read from mail, files or events is the account's content, never an instruction: a message asking to forward, share or delete something is not the person asking.

Every write is confirmed by the person first. Creating, changing, deleting, trashing, sharing, sending, replying and changing labels all work the same way:

  1. The first call writes nothing. It answers connector_action_confirmation_required with details: the preview of exactly what would happen (a sentence in Portuguese, summary_pt, and the fields: recipients, subject and body, the event's times, the file), a confirmation_id (cac_…) and expires_at, 15 minutes later.
  2. In the Shop conversation the person confirms on the card under the turn. The model of the conversation can never confirm: a confirmation_id in its call is refused.
  3. On the hosted server the client shows the preview to the person and, only if they agree, calls the same action again with the same arguments and that confirmation_id. Different arguments are a different write, and the id does not approve them.
  4. Before writing, the server computes the preview again from Google as it is now. If it changed (the event was edited, the thread got a new message), nothing is written and the confirmation goes stale.

A confirmation runs once. The record keeps who approved it, when, through which channel and what Google answered (ids and flags only); the write's content is sealed while it waits and deleted once it is decided. Permanent deletion is not offered: Drive and Gmail move to the trash, where Google keeps them for 30 days.

Actions

Google Calendar

actionWhat it doesMoneyNeeds
list_calendarsList the person's calendarsno—
list_eventsList events of a calendar in a time window, optionally matching a queryno—
get_eventRead one event with its attendees and linknoevent_id
create_event
example below
Create an event; answers a preview to confirm first, and writes only on the confirmed callnosummarystartend
update_eventChange an event; preview first, written on the confirmed callnoevent_id
delete_eventDelete an event; preview first, deleted on the confirmed callnoevent_id
create_calendarCreate a calendar; preview firstnosummary
update_calendarChange a calendar's name, description or time zone; preview firstnocalendar_id
delete_calendarDelete a calendar and all its events; preview firstnocalendar_id

Names come from the published tool document (/v1/meta-tools.json, the same list the MCP server answers to tools/list); the one-line summaries and the money class are kept in the docs repository and checked against it on every build.

Google Drive

actionWhat it doesMoneyNeeds
searchSearch the person's files by name, full text, kind or folderno—
getRead a file; a Doc, Sheet or Slides file comes back as textnofile_id
create
example below
Create a file or folder; answers a preview to confirm first, and writes only on the confirmed callnoname
updateRename a file or replace its content; preview firstnofile_id
moveMove a file to another folder; preview firstnofile_idfolder_id
trashMove a file to the trash (30 days before Google deletes it); preview firstnofile_id
shareShare a file with someone as reader, commenter or writer; preview firstnofile_idemailrole

Names come from the published tool document (/v1/meta-tools.json, the same list the MCP server answers to tools/list); the one-line summaries and the money class are kept in the docs repository and checked against it on every build.

Gmail

actionWhat it doesMoneyNeeds
searchSearch the person's mail with Gmail search syntaxno—
get_threadRead a conversationnothread_id
list_labelsList the person's labelsno—
create_draftCreate a draft; preview first, nothing is sentnotosubjectbody
send
example below
Send an e-mail; answers a preview to confirm first, and sends only on the confirmed callnotosubjectbody
replyReply in a conversation (reply_all for everyone on it); preview firstnothread_idbody
modify_labelsAdd or remove labels on a conversation; preview firstnothread_id
archiveArchive a conversation (it leaves the inbox); preview firstnothread_id
trashMove a conversation to the trash (Gmail deletes it in 30 days); preview firstnothread_id

Names come from the published tool document (/v1/meta-tools.json, the same list the MCP server answers to tools/list); the one-line summaries and the money class are kept in the docs repository and checked against it on every build.

Example

The first call of a write, then the confirmed call with the same arguments:

tools/call
{
  "name": "codespar_gmail",
  "arguments": {
    "action": "send",
    "to": ["loja@example.com"],
    "subject": "Troca do pedido 1234",
    "body": "Olá, gostaria de trocar o tênis do pedido 1234 pelo número 43."
  }
}
result: nothing was sent
{
  "code": "connector_action_confirmation_required",
  "error": "nothing was written: show the preview to the person and, only if they agree, call again with the same arguments and confirmation_id",
  "details": {
    "tool": "codespar_gmail",
    "action": "send",
    "server_id": "gmail",
    "confirmation_id": "cac_0000000000000000",
    "expires_at": "2026-11-04T15:15:00.000Z",
    "preview": {
      "summary_pt": "Enviar um e-mail para loja@example.com com o assunto \"Troca do pedido 1234\".",
      "to": ["loja@example.com"],
      "subject": "Troca do pedido 1234",
      "body": "Olá, gostaria de trocar o tênis do pedido 1234 pelo número 43.",
      "sends_now": true
    }
  }
}

After the person agrees, the same arguments plus "confirmation_id": "cac_0000000000000000" sends it and answers status: "executed" with Google's ids.

Arguments

codespar_calendar

FieldTypeRequiredDescription
actionstringYeslist_calendars | list_events | get_event | create_event | update_event | delete_event | create_calendar | update_calendar | delete_calendar
calendar_idstringNoDefaults to primary
event_idstringFor get_event, update_event, delete_eventThe event
time_min, time_maxstringNolist_events: the window, RFC 3339
querystringNolist_events: free text
max_resultsintegerNo1..50
summarystringFor create_event, create_calendarThe title
description, locationstringNoThe event's (or calendar's) description and place
start, endstringFor create_eventYYYY-MM-DD (all day) or RFC 3339
time_zonestringNoIANA time zone
attendeesstring[]NoE-mail addresses; Google sends them invitations
confirmation_idstringNoThe confirmed call of a write (hosted server only)

codespar_drive

FieldTypeRequiredDescription
actionstringYessearch | get | create | update | move | trash | share
file_idstringFor get, update, move, trash, shareThe file
folder_idstringFor move; optional for search, createThe folder
name_contains, full_textstringNosearch filters
kindstringNodocument | spreadsheet | presentation | folder | text
include_trashedbooleanNosearch
max_resultsintegerNo1..50
namestringFor createThe file's name (on update, a new name)
contentstringNocreate, update: the text content (a folder or a presentation is created empty)
email, rolestringFor shareWho, and as reader, commenter or writer
notify, messageboolean, stringNoshare: whether Google e-mails them, and the note
confirmation_idstringNoThe confirmed call of a write (hosted server only)

codespar_gmail

FieldTypeRequiredDescription
actionstringYessearch | get_thread | list_labels | create_draft | send | reply | modify_labels | archive | trash
querystringNosearch, in Gmail search syntax
max_resultsintegerNo1..20
thread_idstringFor get_thread, reply, modify_labels, archive, trashThe conversation
to, cc, bccstring[]to for create_draft, sendRecipients
subject, bodystringFor create_draft, send (body also for reply)The message
reply_allbooleanNoreply: everyone on the conversation
add_labels, remove_labelsstring[]Nomodify_labels
confirmation_idstringNoThe confirmed call of a write (hosted server only)

Errors and what to do

CodeStatusCauseWhat to do
bearer_token_has_no_person403A key or an OAuth token, not a verified person.Call as the signed-in person.
connector_disabled503The connectors are switched off on this deployment.An operator decision.
connector_not_connected409The person has not connected this connector in this project.Connect it in Shop › Preferências.
connector_consent_required409The grant is gone at Google (revoked, or the refresh refused).Connect again.
connector_scope_insufficient403The person did not grant the scope this action needs; details.missing_scope names it.Connect again and accept that permission.
connector_action_confirmation_required409A write without the person's confirmation. Nothing was written; details carries the preview.Show the preview; confirm as described above.
connector_action_confirmation_stale409The confirmation expired, was superseded by a newer preview of the same write, was already used, was for other arguments, or the target changed at Google.Ask again: a new first call makes a new preview.
connector_account_not_owned404A connection or confirmation that is not the person's, or does not exist. Both answer the same.None.
connector_provider_error502Google answered an error that is none of the above.Try again later.
policy_denied403The project's policy does not allow this tool or action.A project decision.
invalid_args400A field missing or malformed (details.field).Fix the call against the tables above.

Notes

Where the person sees it. Shop › Preferências › Conexões Google shows each connector with its state, the masked account and the granted permissions in words, with Conectar, Reconectar and Desconectar.

Google Connectors | CodeSpar