MCP Server
Connect AI agents to Anchor via the MCP server or in-tab WebMCP tools.
Two ways agents connect
Anchor exposes tools to AI agents in two different places. They are not interchangeable.
| MCP server (Cursor / Claude Desktop) | WebMCP (this browser tab) | |
|---|---|---|
| Where the agent runs | A coding agent on your computer | An AI feature in Chromium (or an extension) on the signed-in dashboard |
| How you connect | Add https://anchorapp.co.za/api/mcp as an MCP server URL | Open the signed-in dashboard in a supporting Chromium build — the page registers tools itself |
| Auth | OAuth; Bearer tokens (mcp_at_…) | Your existing signed-in session cookie |
| What it can do | The full remote catalogue for that org (create, post, reports, …) | Screen-scoped anchor_* tools: reads, navigate, draft creates, and high-risk writes that open the existing confirm/send UI. Never the full remote list at once |
Do not add https://anchorapp.co.za (the website origin) as an MCP server URL. That URL is the app, not a tool server. WebMCP is not configured as an MCP server at all. The only MCP server URL is /api/mcp.
WebMCP is Chromium-only and experimental. Firefox and Safari keep the full human UI; they simply do not register in-tab tools. We do not claim it works in every browser.
What is MCP?
The Model Context Protocol (MCP) is an open standard that lets AI coding agents and assistants interact with external tools and data sources. Anchor's built-in MCP server gives any MCP-compatible agent direct access to your accounting data -- creating entries, managing invoices, generating reports, and more.
WebMCP (this browser tab)
WebMCP is a draft browser API (document.modelContext) so an in-tab agent can call typed tools instead of scraping buttons.
When you are signed in to Anchor in a supporting Chromium build:
- Use Chrome 149+. This origin serves a WebMCP origin trial token, so you should not need a flag. If tools still do not appear, enable
chrome://flags/#enable-webmcp-testingand relaunch (see Chrome WebMCP). - Open the dashboard (not the public marketing or docs pages, and not
/admin). - The page registers tools named
anchor_*for the screen you are on — typically a few dozen, never the full remote catalogue.anchor_list_available_packslists packs and whether they are registered in this tab.anchor_navigatemoves this tab to an allowlisted dashboard path. - Ask the in-tab agent to list invoices or open a record — it should call those tools. Amounts are integer cents (1250 = R12.50). Draft invoice lines use
unitPriceCents. Creating a contact or draft invoice navigates this tab to the new record.
Tools always run as you, on the current organisation. Signing out or leaving the dashboard unregisters them.
Screen-scoped packs
In-tab tools mount from the layout you have open and unregister when you leave. Open Sales → Invoices and you get invoice tools; Quotes, Orders, and Delivery Notes each register their own set. Open Banking and those sales tools go away. Settings registers one tab at a time (General is not Email is not Backups). Reports register that report only, not every report at once.
This is capability parity with the dashboard, not a dump of hundreds of MCP server tools into the tab.
What in-tab tools can do
| Area | Where | What the agent can do |
|---|---|---|
| Shell | Any signed-in dashboard screen | Current user/org, navigate, list packs, dashboard summary, contact list/get/create, marketing-consent update |
| Contacts | /contacts | Update a contact; merge or delete via the existing confirm dialogs |
| Sales | /sales | List/get invoices; create or update a draft invoice; on an open invoice, send, void, or write-off via the existing dialogs |
| Quotes | /sales/quotes | List/get/create quotes; send, accept, decline, delete, convert to invoice, or convert to a sales order via the existing dialogs |
| Orders | /sales/orders | List/get/create sales orders; on an open order, send, deliver, invoice, close leftover, or cancel via the existing dialogs |
| Delivery notes | /sales/delivery-notes | List/get GDNs; on an open note, send email or cancel via the existing dialogs. A GDN is not a tax invoice |
| Cash sales | /sales/receipts | List/get/create cash sales; post via the existing confirm |
| Credit notes | /sales/credit-notes | List/get/create; send, apply, or void via the existing dialogs |
| Payments | /sales/payments | List/get payments; create, batch, or delete via the existing confirms |
| Purchases | /purchases | Bills, purchase orders, expenses, debit notes, requisitions, landed costs, and recurring bills — list/get/create, plus pay/approve/send/void (and similar) via the existing dialogs on the open record |
| Banking | /accounting/banking | List bank accounts and lines; open the existing categorize, match, split, transfer, and statement-check sheets (you complete them) |
| Journals | /accounting | List/get/create draft journal entries; post or void this entry via confirm |
| Chart of accounts | /accounting/accounts | List/get/create/update accounts; delete via confirm |
| Fixed assets | /accounting/fixed-assets | List/get/create assets and categories; dispose, depreciate, revalue, impair via the existing dialogs |
| Other accounting | /accounting/loans, accruals, budgets, opening balances, recurring journals | List/get/create where the screen supports it; post/run/set via confirm |
| Reports | /reports/… | Run that report (read-only). The reports index does not dump every report tool |
| Inventory | /inventory | Items and warehouses; BOMs and assembly orders. Completing an assembly opens the existing Complete dialog |
| Tax | /tax | Tax rates, currencies, periods, VAT/BAS/sales-tax/Schedule C reads. Filing a period opens the existing confirm |
| Settings | /settings (per tab) | Period lock and fiscal-year close/reopen on General; members, roles, control accounts, document numbering, bank rules, email SMTP, backups, trash, import/export, reminders, tags, cost centres, webhooks, Stripe, approvals, procurement, notification prefs — each on its own tab |
| Documents | /documents (and a contact’s Files tab) | List and attach files |
| Notifications | /notifications | List inbox items and mark read |
| CRM | /crm | List/get/create deals; mark won/lost and move stage via the existing confirms |
| Projects | /projects | List/get projects; time entries and timers on the Time tab |
High-risk writes (Class D) — send, void, post, pay, file a tax period, lock dates, restore a backup, complete an assembly, merge a contact, and similar — open the same dialog a human uses. The agent waits; you confirm or cancel. Those tools never call the mutating REST path themselves.
What WebMCP does not do
- Put the full remote MCP catalogue (hundreds of tools) on one page
- Payroll (still off for this product)
- Anything on
/admin(no in-tab tools on site-admin screens) - Recover a written-off invoice (there is no recover control on the invoice page)
- Change or reset a password (human-only in Account → Security; agents can read
hasPasswordviaget_password_status/anchor_get_context) - Change the sign-in email (human-only in Account → Profile; agents can read the masked status via
get_email_change_status/anchor_get_contextuser.emailChange) - Chatwoot / in-app support chat (no MCP tools; use the help widget)
- Firefox, Safari, or public pages (
/,/docs,/pay,/portal,/sign-in)
Prerequisites
- Any plan -- MCP access is available on all plans, including Free
- Any MCP-compatible client (Claude Desktop, Claude Code, Cursor, Windsurf, Cline, VS Code Copilot, or other MCP-enabled agents)
Connecting Your Agent
Any MCP-compatible agent can connect to Anchor's MCP server. The server uses Streamable HTTP transport at /api/mcp and OAuth 2.1 for authentication. Most agents handle the OAuth flow automatically -- they will open a browser window for you to sign in and authorize access on first connect.
The examples below use https://anchorapp.co.za/api/mcp (this hosted product).
Claude Desktop
Add to your Claude Desktop config (claude_desktop_config.json):
{
"mcpServers": {
"Anchor": {
"url": "https://anchorapp.co.za/api/mcp"
}
}
}Claude Code
claude mcp add Anchor --transport streamable-http https://anchorapp.co.za/api/mcpCursor
Go to Cursor Settings > MCP and add a new server, or add to .cursor/mcp.json in your project:
{
"mcpServers": {
"Anchor": {
"url": "https://anchorapp.co.za/api/mcp"
}
}
}Cursor auto-detects Streamable HTTP transport from the URL and handles OAuth automatically.
Windsurf
Go to Windsurf Settings > Cascade > MCP and click View raw config, or edit ~/.codeium/windsurf/mcp_config.json directly:
{
"mcpServers": {
"Anchor": {
"serverUrl": "https://anchorapp.co.za/api/mcp"
}
}
}VS Code (GitHub Copilot)
Add to .vscode/mcp.json in your workspace (available in VS Code 1.99+):
{
"servers": {
"Anchor": {
"type": "http",
"url": "https://anchorapp.co.za/api/mcp"
}
}
}Or add to your user settings.json to make it available across all workspaces:
{
"mcp": {
"servers": {
"Anchor": {
"type": "http",
"url": "https://anchorapp.co.za/api/mcp"
}
}
}
}Other MCP Clients
Any agent that supports the MCP Streamable HTTP transport can connect. Point it at:
https://anchorapp.co.za/api/mcpThe client will discover OAuth endpoints automatically via the /.well-known/oauth-authorization-server metadata endpoint.
OAuth Flow
Anchor uses OAuth 2.1 with PKCE for MCP authentication:
- The MCP client discovers OAuth endpoints via
/.well-known/oauth-authorization-serveron the MCP endpoint - The client registers dynamically at
/api/mcp/oauth/register - The client redirects you to
/api/mcp/oauth/authorizeto sign in - You select an organization and approve the connection
- The client receives an authorization code and exchanges it for access/refresh tokens at
/api/mcp/oauth/token - Access tokens expire after 1 hour; refresh tokens last 30 days
Available Tools
The names below are the MCP server catalogue (/api/mcp). In-tab WebMCP uses anchor_* names on the screen you have open — not this full list at once. See WebMCP.
Organization
get_organization-- Get current organization details
Chart of Accounts
list_accounts-- List all accounts with optional type filterget_account-- Get account with calculated balancecreate_account-- Create a new accountupdate_account-- Update account detailsdelete_account-- Delete an account (fails if it has transactions)
Control Account Mappings
list_control_account_mappings-- List role → chart account mappings (AR, AP, VAT, bank, …)set_control_account_mapping-- Set or clear one role mapping (accountIdUUID or null to reset)
Document numbering
list_document_number_sequences-- List prefix, separator, padWidth, nextNumber, and preview (e.g.INV-00001orINP02401). Document numbers are strings, not money.set_document_number_sequence-- Set one entity (manage:accounts). Sage example:prefix=INP,separator="",padWidth=5,nextNumber=2401→ next autoINP02401.
Journal Entries
list_entries-- List entries with status/date filtersget_entry-- Get entry with line itemscreate_entry-- Create a new entry (debits must equal credits)post_entry-- Post a draft entryvoid_entry-- Void a posted entry (creates reversing entry)
Contacts
list_contacts-- Search and filter contactsget_contact-- Get contact details (includesaddresses)create_contact-- Create a customer, supplier, or both. Optionaladdresses(billing/shippingstreet).addresses.billingis printed on invoices and quotes.nullclears; omit to leave empty. Country preferably ISO-2 (ZA).update_contact-- Update contact details. Provided scalar fields are patched. Whenaddressesis provided, it replaces the whole JSONB (not a deep-merge) — shipping is dropped if not included.nullclears. Omitaddressesto leave it unchanged. GET first if you must keep shipping.
Quotes
list_quotes-- List sales quotes with optional status filterget_quote-- Get a quote with line items (includesinventoryItemIdwhen set)create_quote-- Create a draft quote. Optional lineinventoryItemIdis persisted. Does not reserve or decrement stock. Amounts in integer cents. Omit linetaxRateIdto use the contact’sdefaultTaxRateId(or no tax if the contact is tax-exempt / has no default).taxRateId: nullis explicit no tax and does not fall back.update_quote-- Update a draft quote. ReplacinglineswithoutinventoryItemIdstores NULL and drops the catalogue link; GET then put to keep it. Replacinglinesthat omittaxRateIdapplies the contact default (not the old line tax).convert_quote_to_invoice-- Invoice lines inherit each quote line'sinventoryItemId. Stock is not relieved until the invoice is sent. Blocked with 409 when the quote is already a sales order.convert_quote_to_sales_order-- Copy an accepted quote into a draft sales order. Does not reserve untilsend_sales_order. Blocked with 409 when the quote already has invoices. Quote → invoice and quote → SO are mutually exclusive.send_quote-- Send a draft quote. By default it only marks the quote sent; withsendEmail: trueandrecipientEmailit first emails the quote (with a portal link and, ifattachPdf, the PDF), as the quote page's Send doesaccept_quote-- Mark a sent quote as accepteddecline_quote-- Mark a sent quote as declineddelete_quote-- Soft-delete a quote (draft/sent/accepted/declined/expired withbilledTotal0). Converted to invoice, converted to sales order, or progress-invoiced quotes cannot be deleted. Quote number is not reused.get_quote_pdf-- Download URL for the quote PDF (any status, including sent)
Invoices
list_invoices-- List invoices with filtersget_invoice-- Get invoice with line itemscreate_invoice-- Create an invoice with line items. Invoice number is auto-assigned from Settings → Document numbering (defaultINV-#####) unlessinvoiceNumberis provided. Omit linetaxRateIdto use the contact’sdefaultTaxRateId(or no tax if tax-exempt / unset).taxRateId: nullis explicit no tax. REST omit is the same — TaxShopHub no-VAT lines must sendnull.update_invoice-- Update a draft invoice. Replacinglinesthat omittaxRateIdapplies the contact default. Sales-order invoices cannot replace lines.void_invoice-- Void an invoice. SO-linked stock reverses COGS back to GDNI and does not restock.pay_invoice-- Record a customer payment, as the invoice page's Record payment does: a payment (PAY-…) allocated to the invoice and DR Bank / CR Accounts receivable. Amount in cents, at most the amount due. Optionaldate(default today),method,reference,bankAccountId(the payment then posts to that bank account's ledger account instead of the default bank). Rolemanage:paymentsget_invoice_pdf-- Download URL. Optionalvariant: omit for the tax invoice;podis not a tax invoice and does not post;with-podis one PDF (the tax invoice, then the proof of delivery).
Sales orders / delivery notes
Amounts in integer cents. Delivery quantities and stock invoice quantities are whole units. Service and free-text invoice quantities may have two decimal places. get_sales_order remaining fields are still stored ×100 — divide by 100 before passing to create tools. Reservation is not a sale. A GDN is not a tax invoice.
list_sales_orders-- List sales orders (status,contactId,quoteId, pagination)get_sales_order-- One order plus lines,remainingToDeliver,remainingToInvoice(×100)create_sales_order-- Draft. Does not reserve. To convert a quote, useconvert_quote_to_sales_orderupdate_sales_order-- Draft only. ReplacinglineswithoutinventoryItemIdstores NULLdelete_sales_order-- Soft-delete a draft onlysend_sales_order-- Always reserves stock lines (on-hand unchanged). Email optionalvoid_sales_order-- Cancel. Blocked when live delivery notes or invoices existclose_sales_order-- Cancel undelivered leftover. Blocked while delivered stock is unbilledcreate_invoice_from_sales_order-- Draft tax invoice. Omitlinesto invoice all remaining (stock: delivered remainder; service: ordered remainder). The dashboard sendslines. Tallies bump on invoice send, not hereget_sales_order_pdf-- Download URL for the sales order PDFlist_delivery_notes-- List GDNs. Not tax invoicesget_delivery_note-- One GDN with linescreate_delivery_note-- Issue immediately: reserved down, on-hand down, DR GDNI / CR Inventory. No VATvoid_delivery_note-- Restock and reverse GDNI. Blocked if those units are invoicedsend_delivery_note-- Email the GDN (no stock change)get_delivery_note_pdf-- Download URL. Not a priced invoice. PDF footer: “This is not a tax invoice.”
Bills
list_bills-- List bills; filter by status,unpaidOnly, due dates (dueFrom/dueTo, soonest due first) or supplierget_bill-- One bill with its supplier, lines, amount paid and amount duecreate_bill-- Create a bill with line items. Optional lineinventoryItemIdis a stock purchase: posting capitalises Inventory and increases on-hand. ReplacinglineswithoutinventoryItemIdstores NULL.approve_bill-- Approve a pending bill (or receive a draft) and post it, as the bill page does: the journal (expense or stock and input VAT against accounts payable), stock receipts and GRNI clearing. Refused for a locked period, a missing exchange rate or a broken three-way match. Roleapprove:billspay_bill-- Record a supplier payment, as the bill page's Record payment does: a payment (PAY-…) allocated to the bill and DR Accounts payable / CR Bank. Amount in cents, at most the amount due. Optionaldate(default today),method,reference,bankAccountId(credits that bank account's ledger account instead of the default bank). Rolemanage:paymentsvoid_bill-- Void a bill
Inventory / assembly
Item tools. unitOfMeasure is a display-only label (bag, carton, batch). Stock is still whole units — no conversion. Amounts are integer cents.
list_inventory_items-- List items (on-hand is whole units; costs in cents). AlsoquantityReservedandquantityAvailable(on-hand minus reserved). OptionalitemTypefilterstockorservice.get_inventory_item-- One item by ID (itemTypeisstockorservice; includes reserved and available)create_inventory_item-- Create an item. OptionalitemType(stockdefault, orservice). Service items cannot havequantityOnHand> 0. OptionalunitOfMeasureis display-only. Prices in cents.update_inventory_item-- Patch master fields (not stock). OptionalitemType. Converting stock → service is rejected while quantity is on hand.delete_inventory_item-- Soft-delete an itemadjust_inventory_stock-- Quantity, write-down, or revaluation; posts the matching journal. Rejected for service items.transfer_inventory_stock-- Move whole units between warehouses (no journal). Blocked if it would steal warehouse-reserved unitsapply_stock_take-- Apply counted quantities and complete the takelist_inventory_movements-- Stock ledger
BOM tools:
list_boms-- List BOMs with components andcostBreakdown(cents, per finished unit)get_bom-- One BOM +costBreakdowncreate_bom-- Finished item, name, optional labour/overhead cents. Components added separately. Does not move stock.update_bom-- Patch name, description, labour/overhead,isActivedelete_bom-- Hide a BOM (blocked if draft or in-progress orders exist)add_bom_component-- Item, quantity, optional wastage %. Quantity may be decimal; build ceils to whole units.update_bom_component-- Patch qty / wastageremove_bom_component-- Remove a component line
Assembly tools. Amounts in integer cents. Order quantity is whole units. build_assembly is complete.
list_assembly_orders-- List orders (no consumption preview)get_assembly_order-- One order +consumptionPreviewcreate_assembly_order-- Draft against an active BOM. Does not move stock.update_assembly_order-- Quantity / notes only (no status)start_assembly_order-- Draft → in progress. Does not reserve stock or post WIP.cancel_assembly_order-- Status only. Nothing to reverse.build_assembly-- Complete the order: issue components, receive the finished item, post the journal. Optionaldate. ReturnstotalCost/unitCost(cents). There is no second complete tool.
On the dashboard Inventory → Assembly / BOM screens, in-tab WebMCP can list/create those records. Completing an assembly opens the existing Complete dialog (you confirm). Amounts are still integer cents.
Reports
trial_balance-- Trial balance (mode:as_atdefault /ytdoptional)balance_sheet-- Balance sheetprofit_and_loss-- P&L with date rangeaged_receivables-- AR aging bucketsaged_payables-- AP aging bucketsget_vat_return-- VAT report for a date range without filing: South Africa F4 / F14 / F20 plus supporting S1 / P1 (other countries: 9-box). The same figures as Reports → VAT Return. Not a full VAT201 and not tax advice.get_spend_by_account-- Total spent on 1–20 expense accounts for a date range, with the posted lines behind it. Matchesprofit_and_lossto the cent; refunds reduce spend.get_general_ledger-- General ledger for a date range: per account the opening balance, period debits and credits, closing balance and lines with running balances; or one account's lines a page at a time. Optional cost centre or project filter. The same figures as Reports → General Ledger.get_profitability-- Profit per customer (invoice totals against bill totals) or per project (job costing) for a date range, as on Reports → Profitabilityfind_duplicate_transactions-- Possible duplicate invoices or bills (same contact and total within 7 days), as on Reports → Duplicate Detectionget_financial_calendar-- Due invoices and bills, the next recurring invoices and budget periods between two dates, as on Reports → Financial Calendarget_unrealized_fx-- Unrealised exchange gains and losses on unpaid foreign-currency invoices and bills at today's rates, as on Tax → Currenciesget_recurring_transactions-- Repeating bank statement lines (debit orders, subscriptions) with frequency and average amountlist_bank_accounts-- Bank accounts with their statement balance, as on Accounting → Banking (usereconciliation_reportfor the ledger balance)get_vendor_spend-- Spend per supplier for a date range (bills that are not draft or void), with a monthly trend for the top five. The same figures as Reports → Vendor Spend.get_expense_analytics-- Expenses per expense account and per month for a date range, net of refunds. The same figures as Reports → Expense Analytics.get_payment_performance-- Average days from issue to payment for paid invoices and bills, per customer and supplier, with late counts and on-time rates. The same figures as Reports → Payment Performance.get_tax_summary-- Output and input tax per tax rate for a date range, from invoice and bill lines. The same figures as Reports → Tax Summary; for the South African VAT201 useget_vat_return.get_pnl_comparison-- Profit and loss for the last N months, quarters or years side by side, with the change from each previous period. The same figures as Reports → P&L Comparison.get_monthly_trends-- Revenue, expenses and net income for each of the last N months, as in the dashboard trend charts.get_bank_cash_flow-- Money in and out of one or all bank accounts per day, week or month, from the bank lines. The same figures as Reports → Bank Cash Flow.get_financial_ratios-- Liquidity, leverage, margin, DSO/DPO and return ratios with the balances behind them. The same figures as Reports → Financial Ratios; Anchor's figures, not advice.get_inventory_valuation-- Active items valued at purchase price and sale price, with margins. The same figures as Inventory → Valuation.
ARIA
set_aria_allowed-- Allow or turn off ARIA for this organisation (manage:billing). The site-wide switch must also be on.ask_aria-- Ask Anchor's built-in assistant a question in plain language (English or Afrikaans). It runs one Anchor report or search with your permissions and answers from that result only; every figure comes from the tool. Returnskind,text, an optional table and links, the tool used, and clarify options. Refuses tax advice; never writes. Each question is recorded in the audit log. Errors while ARIA is switched off.
Search
search_documents-- Find invoices, bills, quotes or credit notes by meaning (supplier or customer, what was bought, a reference), in English or Afrikaans. Filters: types, date range, amount in cents with a tolerance, status. A document number in the query comes first.scoreis a similarity rank, never an amount.search_contacts-- Find customers or suppliers by what they do or what you bought from them, or by part of a name or code.search_help-- Search Anchor's help pages; returns section links under/docs.
Each returns mode: vector (meaning search) or keyword when the search index is not available yet.
Amount Conventions
- All monetary amounts in tool inputs/outputs are in integer cents (e.g.
1250= $12.50) - Invoice/bill line item
unitPriceandquantityare decimal numbers (the system converts to cents internally) - Exchange rates are stored as integers with 6 decimal places (
1000000= 1.0)
Testing
With MCP Inspector
The MCP Inspector is the easiest way to test the MCP server interactively during development.
# Start the dev server first
pnpm dev
# Launch MCP Inspector pointed at your local instance
npx @modelcontextprotocol/inspector --url http://localhost:3000/api/mcpThe Inspector will open in your browser and walk you through the OAuth flow. Once authenticated, you can browse available tools, invoke them with custom inputs, and inspect the JSON-RPC responses.
Manual OAuth Flow
If you want to test the OAuth flow step by step:
1. Check metadata discovery
curl http://localhost:3000/.well-known/oauth-authorization-server/api/mcpThis should return JSON with all OAuth endpoint URLs.
2. Register a client
curl -X POST http://localhost:3000/api/mcp/oauth/register \
-H "Content-Type: application/json" \
-d '{"redirect_uris": ["http://localhost:9999/callback"], "client_name": "Test Client"}'Save the client_id from the response.
3. Start the authorization flow
Open this URL in your browser (replace CLIENT_ID with the value from step 2):
http://localhost:3000/api/mcp/oauth/authorize?client_id=CLIENT_ID&redirect_uri=http://localhost:9999/callback&code_challenge=TEST_CHALLENGE&code_challenge_method=S256&state=test123&response_type=codeYou will be redirected to sign in (if needed) and then to the consent page. After approving, you'll be redirected to the callback URL with a code parameter.
4. Exchange code for tokens
curl -X POST http://localhost:3000/api/mcp/oauth/token \
-H "Content-Type: application/json" \
-d '{
"grant_type": "authorization_code",
"code": "THE_CODE_FROM_STEP_3",
"redirect_uri": "http://localhost:9999/callback",
"client_id": "CLIENT_ID",
"code_verifier": "THE_VERIFIER_MATCHING_YOUR_CHALLENGE"
}'This returns access_token and refresh_token.
5. Call the MCP endpoint
curl -X POST http://localhost:3000/api/mcp \
-H "Authorization: Bearer mcp_at_YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2025-03-26",
"capabilities": {},
"clientInfo": { "name": "test", "version": "1.0" }
}
}'6. List available tools
curl -X POST http://localhost:3000/api/mcp \
-H "Authorization: Bearer mcp_at_YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/list",
"params": {}
}'7. Call a tool
curl -X POST http://localhost:3000/api/mcp \
-H "Authorization: Bearer mcp_at_YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "get_organization",
"arguments": {}
}
}'With an MCP Client (local)
For local testing with any MCP client, point it at localhost:
http://localhost:3000/api/mcpFor example, in Claude Desktop config:
{
"mcpServers": {
"Anchor-local": {
"url": "http://localhost:3000/api/mcp"
}
}
}Or in Cursor's .cursor/mcp.json:
{
"mcpServers": {
"Anchor-local": {
"url": "http://localhost:3000/api/mcp"
}
}
}Restart your agent and it will initiate the OAuth flow in your browser.
Troubleshooting
MCP or API access is blocked
API and MCP access is included. If a client is refused, contact support.
"Invalid access token"
Your access token has expired. MCP clients should automatically refresh tokens using the refresh token. If this persists, disconnect and reconnect the MCP server.
"Not a member of this organization"
Your user account has been removed from the organization. Ask an admin to re-add you.
In-tab agent does not see anchor_* tools
WebMCP only registers on the signed-in dashboard, and only in Chromium with the WebMCP API enabled. Public pages (/, /docs, /pay, …) and /admin register nothing. This is not an MCP server connection problem — do not add the website origin as an MCP server URL.
If the agent is on /dashboard and you asked it to list bills, navigate to Purchases first (anchor_navigate / anchor_list_available_packs). Tools are screen-scoped; they are not all registered at once.