Case study · WorkZeal

WorkZeal MCP

one server that lets any AI work in the CRM

Claude, ChatGPT, Cursor or our own agents connect by URL, sign in as the user, and get 43 typed tools for companies, deals, tasks, documents, finance and mail. Each call runs with that user's rights, in their company's database.

  • 43typed tools over the public API
  • 2ways to sign in: OAuth 2.1 or an API key
  • 2regions, one codebase
  • 0delete tools: an AI can't erase data
WorkZeal · Model Context Protocol · .NET 10

How an AI gets into the CRM, safely

The MCP server is a thin, typed layer over WorkZeal's public API. It never touches a database itself: every tool becomes one API call with the user's own token, so the AI can do exactly what that person can do in the app, and nothing more.

CONNECT ONCE EVERY TOOL CALL AI client Claude · ChatGPT MCP server 401 + resource metadata Sign-in server OAuth 2.1 · PKCE · DCR User signs in password or Google User's token 60 min · refresh 60 days Settings → API: one key per grant switch it off and the AI is cut off at once add URL discover consent issue registered AI client picks a tool MCP server · .NET 10 streamable HTTP · stateless 43 typed tools checks token #1 Public API checks token #2 · key enabled? user's edit rights per record picks the company's database Company database one per customer JSON result, or a clear error the model can read and fix Bearer token on every request
The top lane happens once per client: standard MCP authorization, so Claude or ChatGPT can connect with no code from us. The bottom lane runs on every tool call. The server holds no data and no session, so it scales behind any load balancer.

Why MCP, not another integration

One server, every AIClaude, ChatGPT, Cursor, VS Code and our own agents use the same URL. No plugin per vendor.
The user's own rightsThe AI signs in as a person and sees only what that person sees in the app.
Live data, not a copyTools read and write the real CRM, so answers are as fresh as the last click.

How I built it

1A thin, typed proxy

ASP.NET Core with the official C# MCP SDK. Each tool is one method with typed, described parameters that calls one public API endpoint. Business rules stay in one place, the API.

2Standard sign-in

OAuth 2.1 from the MCP spec: protected-resource metadata, dynamic client registration, PKCE S256, refresh-token rotation and revocation, on our own sign-in server. A plain API key still works for scripts.

3Rights checked twice

  • Token checked by the MCP server and again by the API
  • Key must still be enabled in the database
  • Edit rights checked per record
  • Each company in its own database

4Tools made for models

  • No delete tools at all
  • Partial updates: only the fields sent change
  • Ask before sending mail or changing money
  • Errors as readable JSON, never a crash

The 43 tools

Companies & contacts 11

insert_company · get_company · update_company · find_company_contacts · insert_contact · list_contacts · …

Deals & documents 10

insert_deal · update_deal · add_deal_goods · insert_document · add_document_goods · …

Tasks, finance, stock 9

insert_task · update_task · insert_finance · list_finance · list_goods · update_good · …

My day & KPI 4

get_my_day · get_my_tasks · get_my_kpi · get_team_kpi

Search & reference 5

list_records · list_users · get_directory · list_custom_filters · list_additional_fields

Mail, chat, agents 4

send_email · list_mail_accounts · send_chat_message · report_automation_result

What real use changed

An SSE-only clientone AI platform still spoke the old SSE transport, so the server runs both, switched by config
30k tokens of toolsthe full tool list cost that much per turn; each agent now gets only the tools it needs
Old API keyshad no expiry, so expiry is enforced when present and old scripts keep working
"Who is me?"list_users marks the signed-in user, so "my tasks" and "assign to me" just work

Connecting takes one line

# Claude Code
claude mcp add --transport http workzeal https://mcp.workzeal.com/mcp

# claude.ai: Settings → Connectors → Add custom connector → same URL, then sign in