MCP Server (connect AI agents)
Connect AI agents to Core with workspace permissions and optional write access.
Experimental — the MCP server is in beta. Behavior may change as we refine the connect experience.
Core exposes a Model Context Protocol (MCP) server so AI agents — Claude, Cursor, ChatGPT, or your own — can work with Core as you. Every request uses your existing Core permissions and stays in one workspace. You choose read-only or read-and-write access when connecting.
Quickest available setup: open core-it.tools/mcp and choose your AI tool. The page opens the install flow for Cursor and VS Code, provides a command for Claude Code, and keeps the URL beside guided steps for Claude and ChatGPT. No tokens to paste.
The connect page and the endpoint are different URLs.
core-it.tools/mcpis a page you open in a browser. The endpoint you paste into an MCP client ishttps://core-it.tools/api/mcp. Pasting the connect page into a client fails during sign-in — see Troubleshooting below.
What an agent can do
The agent gets tools filtered by your effective workspace permissions:
| Area | Examples |
|---|---|
| Tickets | Search and retrieve tickets, list every ticket for a company or date range, and review messages, checklists, SLA status, time entries, attention queues, and ticket analytics |
| Companies and assets | Find companies, contacts, assets, company health, and customer asset lists |
| Projects and contracts | Review projects, tasks, resourcing, contracts, renewals, billing summaries, and actual hours |
| Financials and capacity | Review forecasts, targets, revenue, opportunities, capacity, availability, resource plans, and headcount forecasts |
| Operations | Review schedules, onsite visits, dispatch, team information, automations, reports, activity, notifications, and meetings |
| Knowledge | Search knowledge-base articles and documents |
| Discovery | Search across Core, list tags, and identify the connected user and workspace |
Sensitive discovery, financial, resourcing, roster, project, contract, automation, and reporting tools are shown only when the connected user has the permissions they require. Everything still follows what you can already see or do in Core.
With read-and-write access, selected create, update, delete, and action tools are also available when your Core permissions allow them. Writes run immediately under your Core permissions; there is no separate approval step or approval link. Every write is bounded and idempotent, is recorded in an immutable mutation ledger and the MCP audit log, and runs through the same tenant-pinned data policies. Unsupported or human-only workflows stay hidden or return an explicit handoff instead of silently approximating the UI workflow.
Why agents sometimes only see prepare_* tools: MCP connections default to Read only at OAuth consent unless you choose Read and write. Read-only connections never advertise write tools such as assign_ticket; they still see read handoffs like prepare_ticket_bulk_workflow. Reconnect with read-and-write access (Settings → Agents) if you need direct assignment. Some clients also only load the first page of tools/list; Core prioritizes direct ticket writes on that first page when you have write access.
Common ticket writes (when your role includes the matching permissions):
| Action | MCP tool | Notes |
|---|---|---|
| Assign or reassign one ticket | assign_ticket | Pass ticketId, expectedUpdatedAt from get_ticket, and assignee: { action: "set", technicianId } or { action: "clear" }. Resolve technicianId with search_staff. Same authorization as the ticket assignee field in Core — not the bulk-assign card. |
| Update title, priority, status, due date | update_ticket | Uses keep/set/clear per field; cannot complete a ticket (use close_ticket). |
| Add an internal ticket note | add_internal_ticket_note | Requires a read-and-write connection with ticket update permission. Pass ticketId, expectedUpdatedAt from get_ticket, and bodyText. Optional images appends private inline PNG, JPEG or WebP screenshots. No customer email, status change, public attachments or mention notifications. |
Everhour sync filters
Managers and administrators can use list_everhour_sync_filters to read client and project rules. Pass entityType and externalId for an exact lookup, including a provider ID with no Core mapping yet. Names come from Core mappings and otherwise fall back to the Everhour ID.
Use update_everhour_sync_filter with that row's expectedVersion, entityType, externalId, and an operation of include, exclude, or never_sync. Include adds explicit selection. Exclude removes explicit selection and can broaden the scope when the final selection is cleared. Never sync hard-blocks the item, including a client's projects.
Updates preserve connection credentials and schedules. Refresh after changing the same rule or receiving a stale-version response. Filter management requires access to all workspace companies.
Reconciliation cases
resolve_reconciliation_case and skip_reconciliation_case close one open case with notes. link_reconciliation_match links an open Xero contact case to a Xero contact, or an open HubSpot renewal case to a Core contract, and resolves the case in the same transaction. Each takes the case itemId and expectedUpdatedAt from get_reconciliation_case.
get_reconciliation_case returns the daily renewal matcher's short reason in standardized_details.agent.summary, with its action and confidence. Open renewal cases require a decision even when one contract has a high matching score. Candidate contracts appear only after deterministic customer, date, and existing-link checks pass; older unchecked suggestions are hidden until the renewal check refreshes them. Clear matches linked automatically are resolved with their reason retained for audit. The raw payload remains withheld.
A renewal deal can be open or closed won. A closed-won renewal can be linked after the daily renewal check confirms its stage in HubSpot. The call fails before anything changes when the deal is closed lost or Core can't confirm it, and the error says why. Skip a closed-lost case instead. The check and the write use the same deal lookup.
Payment schedule billing
These tools follow the Mark payment lines billed workflow on a contract's payment schedule.
| Action | MCP tool | Notes |
|---|---|---|
| Suggest Xero invoices for ready lines | suggest_payment_schedule_invoice_matches | Read only. Pass contract_id. Returns each line with kind: exact is a unique one-to-one match; ambiguous, amount_mismatch, and none need a person to choose. Review rows include a reason and a readable review_note. unresolved_invoice_links lists billed lines whose invoice number matches no synced Xero invoice, or more than one. Nothing is applied. Requires contract read, billing read, and revenue access. |
| Mark reviewed lines billed | mark_payment_schedule_lines_billed | Pass contractId, lines (each lineId and its reviewed expectedAmount, up to 100), and optional xeroInvoiceId and xeroInvoiceNumber. Works on Itemized and Unified schedules. A number alone that matches exactly one synced Xero sales invoice also stores its ID; invoiceNumberLookup reports , , or . A billed line with no invoice gains the one you pass. Requires contract read and billing update. All lines succeed or none do; a changed amount is rejected, and so is a different invoice on a billed line unless you opt in to replace it. |
Payment schedule, line, and contract ids are Core ids of up to 9 letters or numbers; older imported lines can have shorter ids such as wrs26l08.
Suggestions and invoice statuses come from synced Xero invoices. The 6-hourly Xero sync refreshes every invoice changed in Xero since the last successful sync and older invoices still authorised in Core, so a payment or void recorded later appears without a full resync.
The agent must not choose lines on its own or treat a suggestion as a decision. Agree on the lines and invoice with the agent before it calls mark_payment_schedule_lines_billed or unmark_payment_schedule_lines_billed; the call changes the schedule immediately.
Contract billing and project audits
You can pass a contract number such as CT-20261023-0579 to get_contract as contract_id. The result includes Core's internal contract ID, which you use for writes.
| Task | MCP tool | How to use it |
|---|---|---|
| Review every contact billing assignment | list_contract_billing_units | Pass a Core contract ID or CT number. Follow next_cursor until it is null; total_count is returned on the first page. Use state to choose all, open or ended assignments. |
| Assign, end or move a contact's billing item | assign_contract_billing_unit, end_contract_billing_unit, move_contract_billing_unit | Use internal contract, contact and billing-type IDs. Ending or moving also requires the assignment's latest updated_at as expectedUpdatedAt. An end date is inclusive; a move ends the old assignment the day before its new effectiveDate. Moves stay within the same company. |
| Review every payment line | list_contract_payment_schedule_lines | Pass a Core contract ID or CT number and optionally schedule_id. Follow next_cursor to reach later months. |
| Find contracts by client |
Lists return at most 50 records per call; duplicate searches return at most 25 pairs. Date-window project filters match known start and end dates. A project with a missing required date is omitted when that filter is used. Assignment, billing-item and payment-line writes require a read-and-write connection, the matching contract/contact/billing permissions, and experimental features enabled. Assignment and billing-item changes never regenerate charges for months before the current month. A stale version fails without changing the record; read it again before retrying with a new action key.
How writes run
On a read-and-write connection, a write tool runs as soon as the agent calls it, as you and within your Core permissions. There is no approval link, confirmation page, or batch approval step.
- Idempotent. Every write takes an
idempotency_key. A retry with the same arguments and key returns the original outcome (idempotent_replay) instead of running the action again. Use a new key for a changed action. - Version-checked. Tools that edit an existing record take
expectedUpdatedAt(or a similar version) from the latest read and fail if the record changed. When two writes change the same record, run them in order and read the new version between them. For example, runupdate_contractbeforelink_reconciliation_matchon the same contract. - Ledgered and audited. Core records the user, workspace, connection, tool, redacted arguments, and outcome of every write in an immutable mutation ledger and the MCP audit log.
- Bounded. Each write has a hard cap on the number of records it can change. Core refuses a write prompted by content its screener flags as hostile.
Agents built for the earlier approval flow keep working. Core ignores leftover approval fields, and request_batch_approval returns approval_not_required without changing anything. Old Confirm agent action links open Settings → Agents.
Companies and contacts
Company creation does not require a primary contact. The create_company tool accepts an optional primaryContact with name, email, phone, and phoneCountryCode. Supply a name and at least an email or phone. An email matching one unattached contact in your workspace links that contact when your permissions allow it. Core reports the linked contact's name. If the contact belongs to another company, is archived, or cannot be safely linked, Core returns a clear duplicate-email error and creates no company. Linking never changes the existing contact's name or phone.
Company creation and contact linking commit together. Core records the acting user as the creator. Reuse the same idempotency_key and arguments for retries.
Connecting an agent
The guided path is the connect page — choose your tool and follow its setup steps. If you'd rather wire it up by hand, the endpoint is all you need:
- In your MCP client, add the Core MCP endpoint:
https://core-it.tools/api/mcp. Use that exact path —/api/mcp, not/mcp. - When prompted, sign in to Core, choose a workspace, and select Read only or Read and write.
- That's it — you never copy or paste a token.
Core is a remote server. Use the endpoint URL; there is no Core MCP package to install.
Example prompt for an agent:
Connect to the Core MCP server at
https://core-it.tools/api/mcp. Use the server's browser login/approval flow; do not ask me to paste tokens into chat.
Workspace pinning
When you approve, the connection is pinned to the workspace you chose. If you later switch workspaces inside Core, the agent keeps seeing the workspace it was connected to — it does not follow your active workspace. To connect an agent to a different workspace, revoke it and reconnect.
Managing & revoking
Go to Settings → Agents to see every agent you've connected, its access level, and when it was last used. You can immediately downgrade a write-enabled connection to read-only or revoke it. To add write access to an existing read-only connection, revoke it and reconnect through the agent's OAuth flow.
In the Office, your agent sits at a desk in the typing pool while it works for you (a tool call in the last 10 minutes). Only you see your own agents there.
Security model
- Runs as you. The agent sees only what you can see in Core. If you can't open a ticket, neither can the agent.
- Explicit write consent. Existing and read-only connections cannot mutate data. Write tools appear only after you approve read-and-write access, and your normal permissions still apply.
- Workspace-bound. Access stays on the workspace you approved at connect time.
- Suspension-aware. If your account is disabled or the workspace is suspended, the agent is blocked immediately.
- Bounded and replay-safe. Writes have hard scope caps and require a stable idempotency key so retries do not duplicate the action.
- No extra approval, no extra power. Writes run immediately, but only within what your Core role already allows.
- Audited. Core records tool activity and immutable mutation outcomes, including who ran each write, so connections can be reviewed. You can revoke any connection at any time from Settings → Agents.
Current coverage
Core exposes only workflows that have a bounded, permission-aware implementation. A read-and-write connection does not imply that every Core screen is currently agent-operable. If a workflow is not yet supported, the agent should say so and link you to the exact Core screen instead of approximating the change.
Coverage is tracked per feature and tested against the UI's underlying command or query. Because the MCP server is experimental, check the tool list reported by your connected agent for the current set of available actions.
Capacity and complete reporting
get_operations_rates returns the same costs, monthly billable hours, break-even, and profitability rates as Operations → Rates. Choose period (for example, leading-12 or ytd), margin_pct, and an operating unit. For a custom window use period: "custom" with month_from and month_through in YYYY-MM format. months_averaged identifies the exact months used, and each month identifies actual or projected costs and partial data. Forecast expenses require the same financial access as the screen; other authorized Rates viewers receive completed-month calculations. A null fully burdened cost indicates that overhead allocation is unavailable, rather than a zero cost. get_profit_by_lob remains the completed-month current-year profit report.
search_staff, list_team, and get_technician use the operational employee roster by default. Set include_resource_people: true to include contractors and resource-only people. Set include_inactive: true independently to include suspended and terminated people. Use both when auditing the complete resource roster. These reads include employment dates and home unit; customer-portal people remain excluded. get_technician_availability returns lifecycle information for a requested person and limits availability to their employment windows. Ending employment also closes capacity targets after the last working day.
list_resource_pools returns pool names and their line of business. Use list_resource_pool_members for each pool's complete membership, including people whose home line of business differs from the pool. Resourcing bookings include the pool ID and name.
get_capacity_matrix accepts a calendar month, line of business, Resourced selection, assignment status, project statuses, and Penciled %. It uses the screen's capacity calculations and database pool attribution. Each person has separate direct and pool-allocated hours and configured resource-pool membership. Header and footer totals cover the full visible roster, even when the people span several pages. People booked into another unit remain visible with the capacity actually allocated to that unit, including zero capacity. The screen's summary, footer, and export update together when project details arrive. The default current project filter excludes unsigned deal statuses; selecting deal statuses or all includes them deliberately.
get_resource_pool_capacity returns one pool's monthly configured capacity, booked hours, and remaining hours. Hard-percent contributions use each member's available billable capacity after holidays and approved time off. Unresourced contributions use the positive monthly capacity left after direct confirmed and weighted penciled hours. Shared hours are not deducted again. Remaining hours equal configured capacity minus pool bookings and can be negative. These planning totals are separate from the database's per-project, daily attribution weights. Pool capacity uses full member capacity across home lines of business.
Paged tools return continuation values in pagination. Keep filters and the page limit unchanged between calls.
- For Rates, staff searches/lists, Xero actuals, pools, members, capacity, contracts, and contract revenue, pass
pagination.next_offsetasoffsetuntil it isnull. - For project resourcing and resource plans, pass
pagination.next_assignment_offsetandpagination.next_cell_offsetasassignment_offsetandcell_offset. Stop when both arenull. Assignment details repeat while daily cells are paged. Merge records by their IDs. - Date windows filter booking cells. Assignment metadata remains pageable even when it has no cells in the window, because valid month edits can book hours outside an assignment's nominal dates.
- Resourcing pages require a limit of at least two rows. Every response retains the 50-row cap across assignments and daily cells.
- Contract revenue totals describe the returned page. Sum
page_scheduled_totalacross pages for a complete result. get_xero_actualsretains individual records indata; each page contains up to 50 records. Omitoperating_unit_idfor all units, or passoperating_unit_id: nullfor rows with no unit. Follow every page before computing report totals.partial_throughis the last observed date for a partial month.get_contractis a bounded summary. Uselist_contract_billing_rates,list_contract_billing_units, andlist_contract_payment_schedule_linesand follow eachnext_cursorfor complete child records.
Project search and detail include the primary line of business, whether or not the project has operating-unit shares. Numeric offsets do not provide a frozen snapshot if bookings change during a report.
Rate limits
To keep the service reliable, agent requests are limited per connection and per network. If an agent hits the limit, it should wait briefly and try again.
Troubleshooting
"Couldn't register with Core's sign-in service" (or a similar registration error when adding a custom connector)
First check that the connector points at https://core-it.tools/api/mcp and not https://core-it.tools/mcp.
The connect page has no MCP endpoint behind it, so a client pointed there finds no sign-in metadata, falls back to guessing a registration address on the domain, and reports a registration failure.
"Authorization with Core failed" right after you approved the consent screen
After approving access, check Settings → Agents for an entry with the selected workspace and access level. Reopen the client connection and check whether tools are listed; a client error alone does not show whether Core completed the connection.
If no entry appears there, the approval did not finish. Reconnect and complete the consent screen.
"This connector has no tools available"
- Confirm the connection is listed in Settings → Agents. If it is not, reconnect.
- Tool visibility follows your permissions. If your Core account has a narrow role, the agent sees a correspondingly narrow tool set.
- Tools are listed in pages. A client that does not follow pagination shows only the first page.
Each reconnect creates a new connection
Some clients register a fresh OAuth identity every time you connect (dynamic client registration), so each attempt is a new row rather than an update of the previous one.
Core cleans up abandoned attempts automatically:
- On a successful reconnect to the same workspace, never-used prior attempts for the same agent product are retired.
- Unused connections older than 7 days, and connections idle for 90 days, are expired by a daily cleanup job.
Previously used connections that still matter stay until idle expiry or you revoke them. Check Settings → Agents for leftover entries (including any that say Finish revoking) and revoke what you no longer need.
Add screenshots to an internal note
Read get_ticket first for ticketId and expectedUpdatedAt, then call add_internal_ticket_note once. No browser or upload URL is needed. Keep bodyText nonempty. Supply image bytes as canonical base64, without a data URL prefix or whitespace.
{
"ticketId": "YOUR_TICKET_ID",
"expectedUpdatedAt": "2026-10-30T12:00:00Z",
"bodyText": "The connection error is still visible.",
"images": [{ "mimeType": "image/png", "dataBase64": "BASE64_OF_YOUR_PNG" }],
"idempotency_key": "connection-check-note-1",
"originating_source": { "kind": "none" }
}
Replace the ticket, version and image placeholders with the values from your ticket and file. Use originating_source to identify any Core record that prompted the write, following the source-screening contract above.
Images appear after the text in order and remain staff-only after reload. Accepted formats are static PNG (image/png), JPEG (image/jpeg) and WebP (image/webp). Limits are three images, 1 MiB each, 2 MiB total, 16 million pixels and 8192 pixels per dimension. Resize or compress larger screenshots locally. Core fully decodes and re-encodes images, removes metadata, and checks the normalized byte limits and workspace storage quota. URLs, filenames, HTML and arbitrary BlockNote input are not accepted.
On response loss, retry the exact same arguments and idempotency key. If Core reports an indeterminate result, inspect the ticket and mutation outcome before another write; do not retry with a new key. A definitive stale-version rejection requires reading the ticket again before creating a newly intended action.