Model Context Protocol (MCP): Connect AI to Your Tools and Data · Capstone: an MCP server for a marketing CRM · lesson 16 of 18 · 16 min
Capstone part 1: design an MCP server for a marketing CRM dataset
The brief
You are the AI platform lead at Crescent Growth, a (fictional) marketing agency with offices in Lahore, Dubai and London. Account managers, analysts and an internal reporting agent all need safe access to the agency's CRM and campaign data from Claude, VS Code and custom agents. Your job: design, build and ship crescent-crm, an MCP server over a marketing/CRM dataset.
Success criteria:
- Account managers can prepare client meetings in minutes.
- Analysts can answer campaign-performance questions without writing SQL.
- The reporting agent can generate weekly summaries unattended, read-only.
- No one can bulk-export personal data or send anything to clients without a human.
The dataset
companies(id, name, industry, country, owner_id)
contacts(id, company_id, full_name, role, email, phone, consent_marketing, created_at)
deals(id, company_id, name, stage, value, currency, expected_close, owner_id, updated_at)
campaigns(id, company_id, name, channel, market, start_date, end_date, budget, currency)
campaign_daily(campaign_id, day, spend, impressions, clicks, conversions)
activities(id, company_id, contact_id, type, note, created_by, created_at, idempotency_key UNIQUE)
owners(id, full_name, email, team)
Personal data lives in contacts (names, emails, phones) and activities.note. Currency varies by market (PKR, AED, SAR, GBP, USD).
Step 1: user jobs, not tables
Interview-style job list:
| User | Job | Frequency | |---|---|---| | Account manager | "Brief me on Company X before my call" | Daily | | Account manager | "Log that I spoke to Sara and she wants a proposal by Friday" | Daily | | Analyst | "How did UAE Meta campaigns perform last month vs the month before?" | Weekly | | Head of sales | "Where is our pipeline stuck?" | Weekly | | Reporting agent | "Weekly summary per client" | Weekly, unattended |
Step 2: choose primitives
Tools (model-controlled)
crm_find_companies(query, country?)— read.crm_company_brief(company_id)— read: profile, key contacts (names and roles only), open deals, last 5 activities, active campaigns. The workhorse tool.crm_find_deals(stage?, owner_id?, min_value?, stale_days?)— read.crm_pipeline_summary(group_by)— read, aggregated.crm_campaign_performance(company_id?, market?, channel?, start, end, compare_previous?)— read, aggregated; max 92-day range.crm_log_activity(company_id, contact_id?, type, note, idempotency_key)— write, additive, idempotent.crm_draft_client_email(contact_id, subject, body)— write to a drafts table only; never sends.
Deliberately not included: a generic SQL tool, bulk contact export, email sending, deletion.
Resources (application-controlled)
crm://schema— table and metric definitions (Markdown).crm://playbooks/{name}— agency playbooks such asmeeting-prepandcampaign-retro.
Prompts (user-controlled)
/account-review(company_id)— meeting prep using the brief tool and playbook./campaign-retro(company_id, start, end)— performance retrospective.
Step 3: data protection by design
crm_company_briefreturns contact names and roles, not emails or phones. A separate tool for contact details is omitted in v1; add it later with a dedicated scope if justified.- Respect
consent_marketing: the draft tool refuses contacts without marketing consent for marketing-type emails. - All results are capped (e.g., 25 rows) and paginated; no tool returns more than 50 contacts per call.
- Logs record tool name, user, company ID and duration, not note text or contact details.
Step 4: scopes and roles
| Scope | Tools | Who | |---|---|---| | crm.read | 1–5 | All staff, reporting agent | | crm.write | 6–7 | Account managers (step-up) |
The reporting agent gets a client-credentials token with crm.read only.
Step 5: output schemas
Every read tool returns a Pydantic model (structured content) with IDs for follow-up calls and a note field for truncation messages ("showing 25 of 140; narrow by country"). Money fields carry currency; the server never converts currencies.
Step 6: acceptance tests and evals (write them now)
- Protocol: tools listed in stable order; every property described; date-range violation returns a tool error with guidance.
- Security:
crm.readtoken cannot callcrm_log_activity; wrong-audience token rejected;crm_draft_client_emailrefuses non-consented contacts. - Model eval (25 requests), e.g.:
- "Brief me on Al Noor Trading" →
crm_find_companiesthencrm_company_brief. - "Which deals over AED 50,000 have been stuck in proposal for 30+ days?" →
crm_find_deals(stage="proposal", min_value=50000, stale_days=30). - "Compare our Pakistan search campaigns in August and July" →
crm_campaign_performance(market="PK", channel="search", ..., compare_previous=true).
Design review questions
Before building, walk the design past three people: an account manager (does the brief answer what they actually ask before calls?), an analyst (are the filters and comparison periods right?), and whoever owns privacy (are the personal-data decisions defensible and documented?). Record their objections in the doc; unresolved objections become explicit risks with owners.
Deliverable
A one-page design doc: jobs, primitives with one-line descriptions, scopes, data-protection decisions, and the acceptance tests. Part 2 builds it; part 3 secures, tests and ships it.
Video lecture: Capstone part 1: design an MCP server for a marketing CRM dataset
Lecture coming soon · 15 chapters · about 9 minutes. Read the full transcript below.
- Capstone: crescent-crm
- Why design first?
- Brief and dataset
- Step 1: user jobs
- Step 2: primitives
- Simple example: job-first vs table-first
- Step 3: data protection
- Steps 4–5: scopes and outputs
- Step 6: tests first
- Deliverable
- Why not full database access?
- Deeper: a week at Crescent Growth (fictional)
- Watch me do it: job → tool → eval
- Try this now
- Recap
Lecture transcript
Capstone: crescent-crm
Welcome to the capstone. You're the AI platform lead at Crescent Growth, a fictional marketing agency with offices in Lahore, Dubai and London. Account managers, analysts and a reporting agent all need safe access to the agency's CRM and campaign data from Claude, VS Code and custom agents. Over three lessons you'll design, build and ship an MCP server for it. This first part is design, which is where most of the value is decided.
Why design first?
Why start with design instead of code? Because the decisions that make or break an MCP server, which tools exist, what data they return and who may call them, are cheap to change on paper and expensive to change after hosts, users and agents depend on them. Think of an architect's drawings. Moving a wall on paper takes an eraser. Moving it after the house is built takes a demolition crew. This lesson is your drawing board.
Brief and dataset
Start with success criteria. Account managers can prepare for client meetings in minutes. Analysts can answer campaign questions without writing SQL. The reporting agent can create weekly summaries unattended, and read only. And nobody can bulk export personal data or send anything to clients without a human. Then look at the data: companies, contacts, deals, campaigns with daily stats, activities and owners. Personal data lives in contacts and activity notes, and currencies vary by market.
Step 1: user jobs
Step one: design from user jobs, not tables. Account managers want, brief me on this company before my call, and, log that I spoke to Sara and she wants a proposal by Friday. Analysts want, how did UAE Meta campaigns perform last month versus the month before. The head of sales wants, where is our pipeline stuck. And the reporting agent needs a weekly summary per client. Each job becomes a candidate tool, resource or prompt.
Step 2: primitives
Step two: choose primitives. Seven tools: find companies, a company brief that returns the profile, key contacts, open deals, recent activities and active campaigns in one call, find deals, a pipeline summary, campaign performance with an optional comparison, log activity, which is an idempotent write, and draft client email, which only creates a draft. Two resources: the schema and metric definitions, and agency playbooks. Two prompts: account review and campaign retro. And deliberately left out: a generic SQL tool, bulk export, sending and deletion.
Simple example: job-first vs table-first
A simple example of turning a job into a tool. The account manager's job is, brief me on this company before my call. A table first design gives the model five tools: get company, list contacts, list deals, list activities, list campaigns. The model makes five or more calls and often forgets one. A job first design gives it one tool, company brief, that returns exactly what the meeting needs, with ids for follow up. Fewer calls, fewer mistakes, and it's easier to protect personal data in one place.
Step 3: data protection
Step three: data protection by design. The company brief returns contact names and roles, not emails or phone numbers. The draft tool respects marketing consent and refuses contacts who haven't opted in. Every result is capped and paginated, so no call returns more than fifty contacts. And logs record the tool, the user, the company id and the duration, but never note text or contact details.
Steps 4–5: scopes and outputs
Step four: scopes and roles. The read scope covers the five read tools and goes to all staff and the reporting agent. The write scope covers logging activities and drafting emails, and goes to account managers through step up authorization. The reporting agent uses a machine token with read only access. Step five: output schemas. Every read tool returns a structured model with ids for follow up calls and a note for truncation, like showing twenty five of one hundred and forty. Money always carries its currency, and the server never converts.
Step 6: tests first
Step six: write the tests before you build. Protocol tests: stable tool order, every property described, and a helpful error for date ranges that are too long. Security tests: a read token can't log activities, a wrong audience token is rejected, and drafts to non consented contacts are refused. And a model eval of twenty five requests, such as, which deals over fifty thousand dirhams have been stuck in proposal for thirty days, which should map to find deals with the right filters.
Deliverable
Your deliverable is a one page design document: the jobs, each primitive with a one line description, scopes, data protection decisions, and your acceptance tests and eval requests. This is the artifact reviewers and security teams will ask for, and it keeps the build honest. In part two you'll turn it into working Python.
Why not full database access?
A question you'll get from stakeholders: why not just give the AI read access to the whole database? Because the job doesn't need it, and every extra field is extra risk. A curated set of tools returns exactly what each job requires, with caps and minimal personal data, and it's much easier to explain to a privacy officer or a client. If a new need appears, you add a tool deliberately, with a scope and a review, rather than having unlimited access by default.
Deeper: a week at Crescent Growth (fictional)
Let's deepen Crescent Growth's design decisions with a realistic week. On Monday, an account manager in Dubai prepares for a renewal call with a fictional client, Al Noor Trading. On Wednesday, an analyst in Lahore compares August and July search campaigns in Pakistan. On Friday, the head of sales in London asks which deals are stuck. Every one of those jobs is covered by one or two tools, and none of them needs an email address, a phone number or a bulk export. That's the proof the design is right: the real week runs entirely on the minimal surface, and the personal data stays in the CRM where it belongs.
Watch me do it: job → tool → eval
Watch me do it. Let's turn one user job into a tool definition on screen. The job: head of sales asks, where is our pipeline stuck. I write the tool name, crm find deals. Description: find open deals by stage, minimum value and staleness; returns at most twenty five, largest first; use crm company brief for detail on one company. Inputs: stage as an optional enum of the six stages; minimum value as a number of zero or more, in the deal's own currency; stale days between one and three sixty five. Output: a list of deals with id, name, stage, value, currency, expected close and days since update. Scope: crm read. Now the matching eval request: which deals over fifty thousand dirhams have been stuck in proposal for thirty days. Expected call: stage proposal, min value fifty thousand, stale days thirty. The design doc gets one row per tool, written exactly like this.
Try this now
Try this now. Write the one page crescent CRM design document. List the user jobs, the tools, resources and prompts with one line each, the scopes and who gets them, your personal data decisions, and at least ten acceptance tests and eval requests with the tool calls you expect. Then walk it past an account manager, an analyst and whoever owns privacy. Record their objections. Unresolved objections become named risks with owners.
Recap
To recap: design from jobs, choose primitives deliberately, leave out dangerous capabilities, build data protection in, map scopes to tools, return structured outputs, and write tests first. Your next step: write the crescent CRM design doc with at least ten acceptance tests and eval requests.
Key takeaways
- Start from user jobs, not database tables, when designing MCP tools.
- A workhorse brief tool can replace many endpoint-style calls.
- Leave out generic SQL, bulk export, sending and deletion; add capabilities deliberately later.
- Design data protection in from the start: minimal personal fields, consent checks, caps and clean logs.
- Write acceptance tests and model evals before building.
Try it
Write the one-page crescent-crm design doc with jobs, primitives, scopes, data-protection decisions and at least ten acceptance tests and eval requests.