Scenarios
Sixteen worked queries that answer real questions — “how many precincts have high poverty”, “where are the donor-rich areas”, “what did Trump flip in 2024”. Each scenario is one tool call, copy-paste in cURL / JavaScript / Python. The data is already in the system cache — no Census API key, no spreadsheet exports, no map-prep workflow.
Direct mail and door-knocking spend goes 10× further when you target precincts that are both economically anxious AND politically pickable. One filter does both.
curl -X POST https://mapsmcp.com/mcp \
-H "Authorization: Bearer $MAPSMCP_API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"query_precincts","arguments":{"filter":{"state_in":["NC"],"margin_pct_abs_lte":10,"votes_total_gte":100,"poverty_pct_gte":25},"order_by":"pct_dem_lead asc","limit":500}}}'const r = await fetch("https://mapsmcp.com/mcp", {
method: "POST",
headers: {
"Authorization": "Bearer " + process.env.MAPSMCP_API_KEY,
"Content-Type": "application/json",
"Accept": "application/json, text/event-stream",
},
body: JSON.stringify({
jsonrpc: "2.0", id: 1, method: "tools/call",
params: {
name: "query_precincts",
arguments: {
"filter": {
"state_in": [
"NC"
],
"margin_pct_abs_lte": 10,
"votes_total_gte": 100,
"poverty_pct_gte": 25
},
"order_by": "pct_dem_lead asc",
"limit": 500
},
},
}),
});
// Server-sent events; the first 'data:' line carries the JSON-RPC payload.
const text = await r.text();
const payload = JSON.parse(text.match(/^data: (.*)$/m)[1]);
const result = JSON.parse(payload.result.content[0].text);
console.log(result);import os, json, re, requests
resp = requests.post(
"https://mapsmcp.com/mcp",
headers={
"Authorization": f"Bearer {os.environ['MAPSMCP_API_KEY']}",
"Content-Type": "application/json",
"Accept": "application/json, text/event-stream",
},
json={
"jsonrpc": "2.0", "id": 1, "method": "tools/call",
"params": {
"name": "query_precincts",
"arguments": {
"filter": {
"state_in": [
"NC"
],
"margin_pct_abs_lte": 10,
"votes_total_gte": 100,
"poverty_pct_gte": 25
},
"order_by": "pct_dem_lead asc",
"limit": 500
},
},
},
)
# Server-sent events: pull the data line, parse JSON.
sse = re.search(r"^data: (.*)$", resp.text, re.M).group(1)
payload = json.loads(sse)
result = json.loads(payload["result"]["content"][0]["text"])
print(result){
"result_set_id": "rs_a7f3...",
"count": 187,
"stats": {
"dem_wins": 64, "rep_wins": 123, "swing_count": 187,
"mean_margin_pct": 2.4, "total_votes": 412,883
},
"sample": [
{
"external_id": "37119-018",
"state": "NC", "county": "Mecklenburg",
"values": {"pct_dem_lead": -0.014, "votes_total": 2155}
}
],
"filter_summary": "precincts in NC, margin within ±10pts, ≥100 votes, ≥25% below poverty"
}
Find precincts where median household income ≥ $150K and ≥60% have a bachelor's degree, that broke for the Democrat — the donor-rich zones.
curl -X POST https://mapsmcp.com/mcp \
-H "Authorization: Bearer $MAPSMCP_API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"query_precincts","arguments":{"filter":{"winner_party":"DEM","median_hhi_gte":150000,"pct_bachelors_plus_gte":60,"votes_total_gte":200},"order_by":"votes_total desc","limit":200}}}'const r = await fetch("https://mapsmcp.com/mcp", {
method: "POST",
headers: {
"Authorization": "Bearer " + process.env.MAPSMCP_API_KEY,
"Content-Type": "application/json",
"Accept": "application/json, text/event-stream",
},
body: JSON.stringify({
jsonrpc: "2.0", id: 1, method: "tools/call",
params: {
name: "query_precincts",
arguments: {
"filter": {
"winner_party": "DEM",
"median_hhi_gte": 150000,
"pct_bachelors_plus_gte": 60,
"votes_total_gte": 200
},
"order_by": "votes_total desc",
"limit": 200
},
},
}),
});
// Server-sent events; the first 'data:' line carries the JSON-RPC payload.
const text = await r.text();
const payload = JSON.parse(text.match(/^data: (.*)$/m)[1]);
const result = JSON.parse(payload.result.content[0].text);
console.log(result);import os, json, re, requests
resp = requests.post(
"https://mapsmcp.com/mcp",
headers={
"Authorization": f"Bearer {os.environ['MAPSMCP_API_KEY']}",
"Content-Type": "application/json",
"Accept": "application/json, text/event-stream",
},
json={
"jsonrpc": "2.0", "id": 1, "method": "tools/call",
"params": {
"name": "query_precincts",
"arguments": {
"filter": {
"winner_party": "DEM",
"median_hhi_gte": 150000,
"pct_bachelors_plus_gte": 60,
"votes_total_gte": 200
},
"order_by": "votes_total desc",
"limit": 200
},
},
},
)
# Server-sent events: pull the data line, parse JSON.
sse = re.search(r"^data: (.*)$", resp.text, re.M).group(1)
payload = json.loads(sse)
result = json.loads(payload["result"]["content"][0]["text"])
print(result){
"result_set_id": "rs_4c11...",
"count": 1,247,
"stats": {"dem_wins": 1247, "mean_margin_pct": 38.4},
"sample": [
{"external_id": "36061-076", "state": "NY", "county": "New York",
"values": {"pct_dem_lead": 0.41, "votes_total": 1812}}
]
}
Pair a housing-affordability stress test with a political-realignment view. The intersection is where economic-anxiety policy briefs actually land.
curl -X POST https://mapsmcp.com/mcp \
-H "Authorization: Bearer $MAPSMCP_API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"query_precincts","arguments":{"filter":{"winner_party":"REP","rent_burden_pct_gte":50,"margin_pct_abs_lte":15},"order_by":"votes_total desc","limit":500}}}'const r = await fetch("https://mapsmcp.com/mcp", {
method: "POST",
headers: {
"Authorization": "Bearer " + process.env.MAPSMCP_API_KEY,
"Content-Type": "application/json",
"Accept": "application/json, text/event-stream",
},
body: JSON.stringify({
jsonrpc: "2.0", id: 1, method: "tools/call",
params: {
name: "query_precincts",
arguments: {
"filter": {
"winner_party": "REP",
"rent_burden_pct_gte": 50,
"margin_pct_abs_lte": 15
},
"order_by": "votes_total desc",
"limit": 500
},
},
}),
});
// Server-sent events; the first 'data:' line carries the JSON-RPC payload.
const text = await r.text();
const payload = JSON.parse(text.match(/^data: (.*)$/m)[1]);
const result = JSON.parse(payload.result.content[0].text);
console.log(result);import os, json, re, requests
resp = requests.post(
"https://mapsmcp.com/mcp",
headers={
"Authorization": f"Bearer {os.environ['MAPSMCP_API_KEY']}",
"Content-Type": "application/json",
"Accept": "application/json, text/event-stream",
},
json={
"jsonrpc": "2.0", "id": 1, "method": "tools/call",
"params": {
"name": "query_precincts",
"arguments": {
"filter": {
"winner_party": "REP",
"rent_burden_pct_gte": 50,
"margin_pct_abs_lte": 15
},
"order_by": "votes_total desc",
"limit": 500
},
},
},
)
# Server-sent events: pull the data line, parse JSON.
sse = re.search(r"^data: (.*)$", resp.text, re.M).group(1)
payload = json.loads(sse)
result = json.loads(payload["result"]["content"][0]["text"])
print(result){
"result_set_id": "rs_8e91...",
"count": 2,143,
"stats": {
"rep_wins": 2143,
"mean_margin_pct": -7.8,
"total_votes": 4.2M
}
}
One call returns the address's state, county, congressional district, ZIP code area, Census tract, school district, AND voting precinct — each with 58 federal demographic variables and any public election data we host. Perfect for site selection, real-estate due diligence, or political canvassing prep.
curl -X POST https://mapsmcp.com/mcp \
-H "Authorization: Bearer $MAPSMCP_API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"evaluate_site","arguments":{"address":"350 5th Ave, New York, NY 10118"}}}'const r = await fetch("https://mapsmcp.com/mcp", {
method: "POST",
headers: {
"Authorization": "Bearer " + process.env.MAPSMCP_API_KEY,
"Content-Type": "application/json",
"Accept": "application/json, text/event-stream",
},
body: JSON.stringify({
jsonrpc: "2.0", id: 1, method: "tools/call",
params: {
name: "evaluate_site",
arguments: {
"address": "350 5th Ave, New York, NY 10118"
},
},
}),
});
// Server-sent events; the first 'data:' line carries the JSON-RPC payload.
const text = await r.text();
const payload = JSON.parse(text.match(/^data: (.*)$/m)[1]);
const result = JSON.parse(payload.result.content[0].text);
console.log(result);import os, json, re, requests
resp = requests.post(
"https://mapsmcp.com/mcp",
headers={
"Authorization": f"Bearer {os.environ['MAPSMCP_API_KEY']}",
"Content-Type": "application/json",
"Accept": "application/json, text/event-stream",
},
json={
"jsonrpc": "2.0", "id": 1, "method": "tools/call",
"params": {
"name": "evaluate_site",
"arguments": {
"address": "350 5th Ave, New York, NY 10118"
},
},
},
)
# Server-sent events: pull the data line, parse JSON.
sse = re.search(r"^data: (.*)$", resp.text, re.M).group(1)
payload = json.loads(sse)
result = json.loads(payload["result"]["content"][0]["text"])
print(result){
"match": {"matched": true, "matched_address": "350 5TH AVE, NEW YORK, NY, 10118",
"lng": -73.985, "lat": 40.748},
"administrative": [
{"collection": "us-tracts", "external_id": "36061007600",
"name": "Census Tract 76",
"demographics": {
"B01001_001E": 2455, "B19013_001E": 164188,
"pct_below_poverty": 6.0, "pct_hispanic": 14.7,
"pct_bachelors_plus": 89.2, "mean_commute_mins": 22.2,
/* ... 50+ more vars ... */
},
"overlays": { /* presidential results, Cook PVI, etc. */ }
},
/* + state, county, CD, sldu, sldl, ZCTA, school district, precinct */
]
}
Geocode + Census ACS lookup + tract-level aggregation in one call. Up to 10,000 addresses per call, with the system cache backing every lookup so we don't hit api.census.gov per row.
curl -X POST https://mapsmcp.com/mcp \
-H "Authorization: Bearer $MAPSMCP_API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"bulk_demographics_for_addresses","arguments":{"addresses":[{"id":"lead_001","address":"100 Fayetteville St, Raleigh, NC 27601"},{"id":"lead_002","address":"500 S Tryon St, Charlotte, NC 28202"}],"variables":["B01001_001E","B19013_001E","B17001_002E"]}}}'const r = await fetch("https://mapsmcp.com/mcp", {
method: "POST",
headers: {
"Authorization": "Bearer " + process.env.MAPSMCP_API_KEY,
"Content-Type": "application/json",
"Accept": "application/json, text/event-stream",
},
body: JSON.stringify({
jsonrpc: "2.0", id: 1, method: "tools/call",
params: {
name: "bulk_demographics_for_addresses",
arguments: {
"addresses": [
{
"id": "lead_001",
"address": "100 Fayetteville St, Raleigh, NC 27601"
},
{
"id": "lead_002",
"address": "500 S Tryon St, Charlotte, NC 28202"
}
],
"variables": [
"B01001_001E",
"B19013_001E",
"B17001_002E"
]
},
},
}),
});
// Server-sent events; the first 'data:' line carries the JSON-RPC payload.
const text = await r.text();
const payload = JSON.parse(text.match(/^data: (.*)$/m)[1]);
const result = JSON.parse(payload.result.content[0].text);
console.log(result);import os, json, re, requests
resp = requests.post(
"https://mapsmcp.com/mcp",
headers={
"Authorization": f"Bearer {os.environ['MAPSMCP_API_KEY']}",
"Content-Type": "application/json",
"Accept": "application/json, text/event-stream",
},
json={
"jsonrpc": "2.0", "id": 1, "method": "tools/call",
"params": {
"name": "bulk_demographics_for_addresses",
"arguments": {
"addresses": [
{
"id": "lead_001",
"address": "100 Fayetteville St, Raleigh, NC 27601"
},
{
"id": "lead_002",
"address": "500 S Tryon St, Charlotte, NC 28202"
}
],
"variables": [
"B01001_001E",
"B19013_001E",
"B17001_002E"
]
},
},
},
)
# Server-sent events: pull the data line, parse JSON.
sse = re.search(r"^data: (.*)$", resp.text, re.M).group(1)
payload = json.loads(sse)
result = json.loads(payload["result"]["content"][0]["text"])
print(result){
"matched": 2, "unmatched": 0, "tract_resolved": 2,
"rows": [
{"id": "lead_001", "matched_address": "100 FAYETTEVILLE ST, RALEIGH, NC, 27601",
"tract_geoid": "37183052108",
"values": {"B01001_001E": 2810, "B19013_001E": 88500, "B17001_002E": 134}},
{"id": "lead_002", "matched_address": "500 S TRYON ST, CHARLOTTE, NC, 28202",
"tract_geoid": "37119000102",
"values": {"B01001_001E": 4521, "B19013_001E": 116200, "B17001_002E": 287}}
]
}
Quantifying the digital divide for federal NDIA / state broadband grants. Returns tract-level rows where <70% have broadband and >20% are below the poverty line.
curl -X POST https://mapsmcp.com/mcp \
-H "Authorization: Bearer $MAPSMCP_API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"compare_geographies","arguments":{"geographies":[{"collection":"us-tracts","version":"tiger-2024","state":"WV"}],"variables":["B28011_001E","B28011_002E","B17001_001E","B17001_002E"]}}}'const r = await fetch("https://mapsmcp.com/mcp", {
method: "POST",
headers: {
"Authorization": "Bearer " + process.env.MAPSMCP_API_KEY,
"Content-Type": "application/json",
"Accept": "application/json, text/event-stream",
},
body: JSON.stringify({
jsonrpc: "2.0", id: 1, method: "tools/call",
params: {
name: "compare_geographies",
arguments: {
"geographies": [
{
"collection": "us-tracts",
"version": "tiger-2024",
"state": "WV"
}
],
"variables": [
"B28011_001E",
"B28011_002E",
"B17001_001E",
"B17001_002E"
]
},
},
}),
});
// Server-sent events; the first 'data:' line carries the JSON-RPC payload.
const text = await r.text();
const payload = JSON.parse(text.match(/^data: (.*)$/m)[1]);
const result = JSON.parse(payload.result.content[0].text);
console.log(result);import os, json, re, requests
resp = requests.post(
"https://mapsmcp.com/mcp",
headers={
"Authorization": f"Bearer {os.environ['MAPSMCP_API_KEY']}",
"Content-Type": "application/json",
"Accept": "application/json, text/event-stream",
},
json={
"jsonrpc": "2.0", "id": 1, "method": "tools/call",
"params": {
"name": "compare_geographies",
"arguments": {
"geographies": [
{
"collection": "us-tracts",
"version": "tiger-2024",
"state": "WV"
}
],
"variables": [
"B28011_001E",
"B28011_002E",
"B17001_001E",
"B17001_002E"
]
},
},
},
)
# Server-sent events: pull the data line, parse JSON.
sse = re.search(r"^data: (.*)$", resp.text, re.M).group(1)
payload = json.loads(sse)
result = json.loads(payload["result"]["content"][0]["text"])
print(result){
"geographies": [{"collection": "us-tracts", "version": "tiger-2024", "state": "WV"}],
"variables": [...],
"rows": [
{"external_id": "54077950100", "values": {
"B28011_001E": 421, "B28011_002E": 257,
"B17001_001E": 1180, "B17001_002E": 339
}, "derived": {"pct_broadband": 61.0, "pct_below_poverty": 28.7}}
/* ... */
]
}
Identify the Hispanic-majority precincts that moved away from Democrats. Critical for both Democratic re-engagement and Republican fortification strategies.
curl -X POST https://mapsmcp.com/mcp \
-H "Authorization: Bearer $MAPSMCP_API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"query_precincts","arguments":{"filter":{"state_in":["TX"],"winner_party":"REP","pct_hispanic_gte":50,"votes_total_gte":200},"order_by":"votes_total desc","limit":500}}}'const r = await fetch("https://mapsmcp.com/mcp", {
method: "POST",
headers: {
"Authorization": "Bearer " + process.env.MAPSMCP_API_KEY,
"Content-Type": "application/json",
"Accept": "application/json, text/event-stream",
},
body: JSON.stringify({
jsonrpc: "2.0", id: 1, method: "tools/call",
params: {
name: "query_precincts",
arguments: {
"filter": {
"state_in": [
"TX"
],
"winner_party": "REP",
"pct_hispanic_gte": 50,
"votes_total_gte": 200
},
"order_by": "votes_total desc",
"limit": 500
},
},
}),
});
// Server-sent events; the first 'data:' line carries the JSON-RPC payload.
const text = await r.text();
const payload = JSON.parse(text.match(/^data: (.*)$/m)[1]);
const result = JSON.parse(payload.result.content[0].text);
console.log(result);import os, json, re, requests
resp = requests.post(
"https://mapsmcp.com/mcp",
headers={
"Authorization": f"Bearer {os.environ['MAPSMCP_API_KEY']}",
"Content-Type": "application/json",
"Accept": "application/json, text/event-stream",
},
json={
"jsonrpc": "2.0", "id": 1, "method": "tools/call",
"params": {
"name": "query_precincts",
"arguments": {
"filter": {
"state_in": [
"TX"
],
"winner_party": "REP",
"pct_hispanic_gte": 50,
"votes_total_gte": 200
},
"order_by": "votes_total desc",
"limit": 500
},
},
},
)
# Server-sent events: pull the data line, parse JSON.
sse = re.search(r"^data: (.*)$", resp.text, re.M).group(1)
payload = json.loads(sse)
result = json.loads(payload["result"]["content"][0]["text"])
print(result){
"result_set_id": "rs_d34a...",
"count": 1,892,
"stats": {
"rep_wins": 1892,
"mean_margin_pct": -14.7,
"total_votes": 1.1M
}
}
Sales territories, school catchments, campaign zones, underwriting books — anything you'd draw on a whiteboard. Hierarchical region groups, demographics auto-aggregated.
curl -X POST https://mapsmcp.com/mcp \
-H "Authorization: Bearer $MAPSMCP_API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"create_region_group","arguments":{"slug":"swing-states-2024","name":"2024 swing states","regions":[{"name":"Sun Belt","members":[{"collection":"us-states","external_id":"04"},{"collection":"us-states","external_id":"13"},{"collection":"us-states","external_id":"32"}]},{"name":"Blue Wall","members":[{"collection":"us-states","external_id":"26"},{"collection":"us-states","external_id":"42"},{"collection":"us-states","external_id":"55"}]}]}}}'const r = await fetch("https://mapsmcp.com/mcp", {
method: "POST",
headers: {
"Authorization": "Bearer " + process.env.MAPSMCP_API_KEY,
"Content-Type": "application/json",
"Accept": "application/json, text/event-stream",
},
body: JSON.stringify({
jsonrpc: "2.0", id: 1, method: "tools/call",
params: {
name: "create_region_group",
arguments: {
"slug": "swing-states-2024",
"name": "2024 swing states",
"regions": [
{
"name": "Sun Belt",
"members": [
{
"collection": "us-states",
"external_id": "04"
},
{
"collection": "us-states",
"external_id": "13"
},
{
"collection": "us-states",
"external_id": "32"
}
]
},
{
"name": "Blue Wall",
"members": [
{
"collection": "us-states",
"external_id": "26"
},
{
"collection": "us-states",
"external_id": "42"
},
{
"collection": "us-states",
"external_id": "55"
}
]
}
]
},
},
}),
});
// Server-sent events; the first 'data:' line carries the JSON-RPC payload.
const text = await r.text();
const payload = JSON.parse(text.match(/^data: (.*)$/m)[1]);
const result = JSON.parse(payload.result.content[0].text);
console.log(result);import os, json, re, requests
resp = requests.post(
"https://mapsmcp.com/mcp",
headers={
"Authorization": f"Bearer {os.environ['MAPSMCP_API_KEY']}",
"Content-Type": "application/json",
"Accept": "application/json, text/event-stream",
},
json={
"jsonrpc": "2.0", "id": 1, "method": "tools/call",
"params": {
"name": "create_region_group",
"arguments": {
"slug": "swing-states-2024",
"name": "2024 swing states",
"regions": [
{
"name": "Sun Belt",
"members": [
{
"collection": "us-states",
"external_id": "04"
},
{
"collection": "us-states",
"external_id": "13"
},
{
"collection": "us-states",
"external_id": "32"
}
]
},
{
"name": "Blue Wall",
"members": [
{
"collection": "us-states",
"external_id": "26"
},
{
"collection": "us-states",
"external_id": "42"
},
{
"collection": "us-states",
"external_id": "55"
}
]
}
]
},
},
},
)
# Server-sent events: pull the data line, parse JSON.
sse = re.search(r"^data: (.*)$", resp.text, re.M).group(1)
payload = json.loads(sse)
result = json.loads(payload["result"]["content"][0]["text"])
print(result){
"region_group_id": "rg_8b21...",
"slug": "swing-states-2024",
"regions": [
{"name": "Sun Belt", "member_count": 3, "population": 33.5M},
{"name": "Blue Wall", "member_count": 3, "population": 28.2M}
],
"dashboard_url": "https://mapsmcp.com/dashboard/regions/swing-states-2024"
}
A persuasion universe is the set of geographies where a campaign's argument can actually move votes — competitive enough to matter, demographically aligned with the issue. One precinct query defines yours; the result_set powers walk lists, mail targeting, digital geofencing, and the precinct-by-precinct ROI dashboard you build on top.
curl -X POST https://mapsmcp.com/mcp \
-H "Authorization: Bearer $MAPSMCP_API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"query_precincts","arguments":{"filter":{"state_in":["NC","GA"],"margin_pct_abs_lte":12,"votes_total_gte":150,"pct_hispanic_gte":30,"median_hhi_lte":65000},"order_by":"votes_total desc","limit":1500}}}'const r = await fetch("https://mapsmcp.com/mcp", {
method: "POST",
headers: {
"Authorization": "Bearer " + process.env.MAPSMCP_API_KEY,
"Content-Type": "application/json",
"Accept": "application/json, text/event-stream",
},
body: JSON.stringify({
jsonrpc: "2.0", id: 1, method: "tools/call",
params: {
name: "query_precincts",
arguments: {
"filter": {
"state_in": [
"NC",
"GA"
],
"margin_pct_abs_lte": 12,
"votes_total_gte": 150,
"pct_hispanic_gte": 30,
"median_hhi_lte": 65000
},
"order_by": "votes_total desc",
"limit": 1500
},
},
}),
});
// Server-sent events; the first 'data:' line carries the JSON-RPC payload.
const text = await r.text();
const payload = JSON.parse(text.match(/^data: (.*)$/m)[1]);
const result = JSON.parse(payload.result.content[0].text);
console.log(result);import os, json, re, requests
resp = requests.post(
"https://mapsmcp.com/mcp",
headers={
"Authorization": f"Bearer {os.environ['MAPSMCP_API_KEY']}",
"Content-Type": "application/json",
"Accept": "application/json, text/event-stream",
},
json={
"jsonrpc": "2.0", "id": 1, "method": "tools/call",
"params": {
"name": "query_precincts",
"arguments": {
"filter": {
"state_in": [
"NC",
"GA"
],
"margin_pct_abs_lte": 12,
"votes_total_gte": 150,
"pct_hispanic_gte": 30,
"median_hhi_lte": 65000
},
"order_by": "votes_total desc",
"limit": 1500
},
},
},
)
# Server-sent events: pull the data line, parse JSON.
sse = re.search(r"^data: (.*)$", resp.text, re.M).group(1)
payload = json.loads(sse)
result = json.loads(payload["result"]["content"][0]["text"])
print(result){
"result_set_id": "rs_pers_8e3f...",
"count": 1,247,
"stats": {
"swing_count": 1247,
"mean_margin_pct": -2.1,
"total_votes": 412,883
},
"filter_summary": "NC + GA, margin within ±12pts, ≥150 votes, ≥30% Hispanic, MHI ≤ $65K"
}
Every organizer wants a printable / mobile walk list with the demographics next to each door. Pass a CSV of addresses; get back geocoded coordinates + matched Census tract + median income + poverty rate + commute mode + the precinct each address is in. Pipe straight into your canvasser app.
curl -X POST https://mapsmcp.com/mcp \
-H "Authorization: Bearer $MAPSMCP_API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"bulk_demographics_for_addresses","arguments":{"addresses":[{"id":"lead_001","address":"100 Fayetteville St, Raleigh, NC 27601"},{"id":"lead_002","address":"500 S Tryon St, Charlotte, NC 28202"},{"id":"lead_003","address":"200 W Trade St, Charlotte, NC 28202"}],"variables":["B01001_001E","B19013_001E","B17001_002E","B25070_010E","B16001_002E"]}}}'const r = await fetch("https://mapsmcp.com/mcp", {
method: "POST",
headers: {
"Authorization": "Bearer " + process.env.MAPSMCP_API_KEY,
"Content-Type": "application/json",
"Accept": "application/json, text/event-stream",
},
body: JSON.stringify({
jsonrpc: "2.0", id: 1, method: "tools/call",
params: {
name: "bulk_demographics_for_addresses",
arguments: {
"addresses": [
{
"id": "lead_001",
"address": "100 Fayetteville St, Raleigh, NC 27601"
},
{
"id": "lead_002",
"address": "500 S Tryon St, Charlotte, NC 28202"
},
{
"id": "lead_003",
"address": "200 W Trade St, Charlotte, NC 28202"
}
],
"variables": [
"B01001_001E",
"B19013_001E",
"B17001_002E",
"B25070_010E",
"B16001_002E"
]
},
},
}),
});
// Server-sent events; the first 'data:' line carries the JSON-RPC payload.
const text = await r.text();
const payload = JSON.parse(text.match(/^data: (.*)$/m)[1]);
const result = JSON.parse(payload.result.content[0].text);
console.log(result);import os, json, re, requests
resp = requests.post(
"https://mapsmcp.com/mcp",
headers={
"Authorization": f"Bearer {os.environ['MAPSMCP_API_KEY']}",
"Content-Type": "application/json",
"Accept": "application/json, text/event-stream",
},
json={
"jsonrpc": "2.0", "id": 1, "method": "tools/call",
"params": {
"name": "bulk_demographics_for_addresses",
"arguments": {
"addresses": [
{
"id": "lead_001",
"address": "100 Fayetteville St, Raleigh, NC 27601"
},
{
"id": "lead_002",
"address": "500 S Tryon St, Charlotte, NC 28202"
},
{
"id": "lead_003",
"address": "200 W Trade St, Charlotte, NC 28202"
}
],
"variables": [
"B01001_001E",
"B19013_001E",
"B17001_002E",
"B25070_010E",
"B16001_002E"
]
},
},
},
)
# Server-sent events: pull the data line, parse JSON.
sse = re.search(r"^data: (.*)$", resp.text, re.M).group(1)
payload = json.loads(sse)
result = json.loads(payload["result"]["content"][0]["text"])
print(result){
"matched": 3, "unmatched": 0, "tract_resolved": 3,
"rows": [
{"id":"lead_001","tract_geoid":"37183052108",
"values":{"B01001_001E":2810,"B19013_001E":88500,"B17001_002E":134,
"B25070_010E":29,"B16001_002E":2480}},
/* lead_002, lead_003 ... */
]
}
Most campaign software ships you 'pre-made' regions you can't tweak. Region groups let YOU draw the turfs — a captain per ZIP, an organizer per 3 precincts, whatever your hierarchy is — and every demographic + result is auto-aggregated up the tree.
curl -X POST https://mapsmcp.com/mcp \
-H "Authorization: Bearer $MAPSMCP_API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"create_region_group","arguments":{"slug":"nc-house-12-turfs","name":"NC House District 12 organizing turfs","regions":[{"name":"West Charlotte (Org: Alicia)","members":[{"collection":"us-precincts-2024","external_id":"37119-011"},{"collection":"us-precincts-2024","external_id":"37119-012"},{"collection":"us-precincts-2024","external_id":"37119-013"}]},{"name":"South Charlotte (Org: Marcus)","members":[{"collection":"us-precincts-2024","external_id":"37119-024"},{"collection":"us-precincts-2024","external_id":"37119-025"}]}]}}}'const r = await fetch("https://mapsmcp.com/mcp", {
method: "POST",
headers: {
"Authorization": "Bearer " + process.env.MAPSMCP_API_KEY,
"Content-Type": "application/json",
"Accept": "application/json, text/event-stream",
},
body: JSON.stringify({
jsonrpc: "2.0", id: 1, method: "tools/call",
params: {
name: "create_region_group",
arguments: {
"slug": "nc-house-12-turfs",
"name": "NC House District 12 organizing turfs",
"regions": [
{
"name": "West Charlotte (Org: Alicia)",
"members": [
{
"collection": "us-precincts-2024",
"external_id": "37119-011"
},
{
"collection": "us-precincts-2024",
"external_id": "37119-012"
},
{
"collection": "us-precincts-2024",
"external_id": "37119-013"
}
]
},
{
"name": "South Charlotte (Org: Marcus)",
"members": [
{
"collection": "us-precincts-2024",
"external_id": "37119-024"
},
{
"collection": "us-precincts-2024",
"external_id": "37119-025"
}
]
}
]
},
},
}),
});
// Server-sent events; the first 'data:' line carries the JSON-RPC payload.
const text = await r.text();
const payload = JSON.parse(text.match(/^data: (.*)$/m)[1]);
const result = JSON.parse(payload.result.content[0].text);
console.log(result);import os, json, re, requests
resp = requests.post(
"https://mapsmcp.com/mcp",
headers={
"Authorization": f"Bearer {os.environ['MAPSMCP_API_KEY']}",
"Content-Type": "application/json",
"Accept": "application/json, text/event-stream",
},
json={
"jsonrpc": "2.0", "id": 1, "method": "tools/call",
"params": {
"name": "create_region_group",
"arguments": {
"slug": "nc-house-12-turfs",
"name": "NC House District 12 organizing turfs",
"regions": [
{
"name": "West Charlotte (Org: Alicia)",
"members": [
{
"collection": "us-precincts-2024",
"external_id": "37119-011"
},
{
"collection": "us-precincts-2024",
"external_id": "37119-012"
},
{
"collection": "us-precincts-2024",
"external_id": "37119-013"
}
]
},
{
"name": "South Charlotte (Org: Marcus)",
"members": [
{
"collection": "us-precincts-2024",
"external_id": "37119-024"
},
{
"collection": "us-precincts-2024",
"external_id": "37119-025"
}
]
}
]
},
},
},
)
# Server-sent events: pull the data line, parse JSON.
sse = re.search(r"^data: (.*)$", resp.text, re.M).group(1)
payload = json.loads(sse)
result = json.loads(payload["result"]["content"][0]["text"])
print(result){
"region_group_id": "rg_nc12...",
"regions": [
{"name": "West Charlotte (Org: Alicia)", "members": 3, "population": 17.8K, "registered_voters": 12.1K},
{"name": "South Charlotte (Org: Marcus)", "members": 2, "population": 11.2K, "registered_voters": 8.4K}
]
}
Your members are deciding between a digital ad buy and a door-knock canvass. Pull the tracts where broadband adoption is below 70% AND poverty is above 20% — those are the places where in-person, on-the-ground organizing is non-substitutable.
curl -X POST https://mapsmcp.com/mcp \
-H "Authorization: Bearer $MAPSMCP_API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"query_precincts","arguments":{"filter":{"pct_broadband_lte":70,"poverty_pct_gte":20,"votes_total_gte":100},"order_by":"pct_dem_lead asc","limit":800}}}'const r = await fetch("https://mapsmcp.com/mcp", {
method: "POST",
headers: {
"Authorization": "Bearer " + process.env.MAPSMCP_API_KEY,
"Content-Type": "application/json",
"Accept": "application/json, text/event-stream",
},
body: JSON.stringify({
jsonrpc: "2.0", id: 1, method: "tools/call",
params: {
name: "query_precincts",
arguments: {
"filter": {
"pct_broadband_lte": 70,
"poverty_pct_gte": 20,
"votes_total_gte": 100
},
"order_by": "pct_dem_lead asc",
"limit": 800
},
},
}),
});
// Server-sent events; the first 'data:' line carries the JSON-RPC payload.
const text = await r.text();
const payload = JSON.parse(text.match(/^data: (.*)$/m)[1]);
const result = JSON.parse(payload.result.content[0].text);
console.log(result);import os, json, re, requests
resp = requests.post(
"https://mapsmcp.com/mcp",
headers={
"Authorization": f"Bearer {os.environ['MAPSMCP_API_KEY']}",
"Content-Type": "application/json",
"Accept": "application/json, text/event-stream",
},
json={
"jsonrpc": "2.0", "id": 1, "method": "tools/call",
"params": {
"name": "query_precincts",
"arguments": {
"filter": {
"pct_broadband_lte": 70,
"poverty_pct_gte": 20,
"votes_total_gte": 100
},
"order_by": "pct_dem_lead asc",
"limit": 800
},
},
},
)
# Server-sent events: pull the data line, parse JSON.
sse = re.search(r"^data: (.*)$", resp.text, re.M).group(1)
payload = json.loads(sse)
result = json.loads(payload["result"]["content"][0]["text"])
print(result){
"count": 4,891,
"stats": {"mean_poverty_pct": 27.4, "mean_broadband_pct": 56.2},
"filter_summary": "precincts with broadband ≤70%, poverty ≥20%, ≥100 votes"
}
A housing campaign lives or dies on whether you find the renters who are paying 30-50%+ of income on rent AND live in precincts where their vote can swing an election. Two filters, one query.
curl -X POST https://mapsmcp.com/mcp \
-H "Authorization: Bearer $MAPSMCP_API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"query_precincts","arguments":{"filter":{"rent_burden_pct_gte":45,"margin_pct_abs_lte":15,"votes_total_gte":200},"order_by":"rent_burden_pct_gte desc","limit":500}}}'const r = await fetch("https://mapsmcp.com/mcp", {
method: "POST",
headers: {
"Authorization": "Bearer " + process.env.MAPSMCP_API_KEY,
"Content-Type": "application/json",
"Accept": "application/json, text/event-stream",
},
body: JSON.stringify({
jsonrpc: "2.0", id: 1, method: "tools/call",
params: {
name: "query_precincts",
arguments: {
"filter": {
"rent_burden_pct_gte": 45,
"margin_pct_abs_lte": 15,
"votes_total_gte": 200
},
"order_by": "rent_burden_pct_gte desc",
"limit": 500
},
},
}),
});
// Server-sent events; the first 'data:' line carries the JSON-RPC payload.
const text = await r.text();
const payload = JSON.parse(text.match(/^data: (.*)$/m)[1]);
const result = JSON.parse(payload.result.content[0].text);
console.log(result);import os, json, re, requests
resp = requests.post(
"https://mapsmcp.com/mcp",
headers={
"Authorization": f"Bearer {os.environ['MAPSMCP_API_KEY']}",
"Content-Type": "application/json",
"Accept": "application/json, text/event-stream",
},
json={
"jsonrpc": "2.0", "id": 1, "method": "tools/call",
"params": {
"name": "query_precincts",
"arguments": {
"filter": {
"rent_burden_pct_gte": 45,
"margin_pct_abs_lte": 15,
"votes_total_gte": 200
},
"order_by": "rent_burden_pct_gte desc",
"limit": 500
},
},
},
)
# Server-sent events: pull the data line, parse JSON.
sse = re.search(r"^data: (.*)$", resp.text, re.M).group(1)
payload = json.loads(sse)
result = json.loads(payload["result"]["content"][0]["text"])
print(result){
"count": 1,302,
"stats": {"mean_rent_burden_pct": 52.8, "mean_margin_pct": -3.4},
"filter_summary": "rent burden ≥45%, margin within ±15pts, ≥200 votes"
}
There are precincts where median household income is $200K+ but turnout is below 50%. Those are donors who'd give if asked but won't get themselves to a polling place. A finance committee briefing in one query.
curl -X POST https://mapsmcp.com/mcp \
-H "Authorization: Bearer $MAPSMCP_API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"query_precincts","arguments":{"filter":{"median_hhi_gte":200000,"pct_bachelors_plus_gte":70,"votes_total_gte":50},"order_by":"votes_total asc","limit":300}}}'const r = await fetch("https://mapsmcp.com/mcp", {
method: "POST",
headers: {
"Authorization": "Bearer " + process.env.MAPSMCP_API_KEY,
"Content-Type": "application/json",
"Accept": "application/json, text/event-stream",
},
body: JSON.stringify({
jsonrpc: "2.0", id: 1, method: "tools/call",
params: {
name: "query_precincts",
arguments: {
"filter": {
"median_hhi_gte": 200000,
"pct_bachelors_plus_gte": 70,
"votes_total_gte": 50
},
"order_by": "votes_total asc",
"limit": 300
},
},
}),
});
// Server-sent events; the first 'data:' line carries the JSON-RPC payload.
const text = await r.text();
const payload = JSON.parse(text.match(/^data: (.*)$/m)[1]);
const result = JSON.parse(payload.result.content[0].text);
console.log(result);import os, json, re, requests
resp = requests.post(
"https://mapsmcp.com/mcp",
headers={
"Authorization": f"Bearer {os.environ['MAPSMCP_API_KEY']}",
"Content-Type": "application/json",
"Accept": "application/json, text/event-stream",
},
json={
"jsonrpc": "2.0", "id": 1, "method": "tools/call",
"params": {
"name": "query_precincts",
"arguments": {
"filter": {
"median_hhi_gte": 200000,
"pct_bachelors_plus_gte": 70,
"votes_total_gte": 50
},
"order_by": "votes_total asc",
"limit": 300
},
},
},
)
# Server-sent events: pull the data line, parse JSON.
sse = re.search(r"^data: (.*)$", resp.text, re.M).group(1)
payload = json.loads(sse)
result = json.loads(payload["result"]["content"][0]["text"])
print(result){
"count": 287,
"stats": {"mean_mhi": 248000, "mean_bachelors_pct": 81.2, "mean_turnout_pct": 38.4},
"sample": [
{"external_id": "06037-7062", "state": "CA", "county": "Los Angeles"}
]
}
Your organizers want to drop an address into your mobile canvas app and instantly see who lives there — every demographic layer, who they voted for, what district they're in. One MCP call, one render, drops straight into your React component.
curl -X POST https://mapsmcp.com/mcp \
-H "Authorization: Bearer $MAPSMCP_API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"evaluate_site","arguments":{"address":"500 S Tryon St, Charlotte, NC 28202"}}}'const r = await fetch("https://mapsmcp.com/mcp", {
method: "POST",
headers: {
"Authorization": "Bearer " + process.env.MAPSMCP_API_KEY,
"Content-Type": "application/json",
"Accept": "application/json, text/event-stream",
},
body: JSON.stringify({
jsonrpc: "2.0", id: 1, method: "tools/call",
params: {
name: "evaluate_site",
arguments: {
"address": "500 S Tryon St, Charlotte, NC 28202"
},
},
}),
});
// Server-sent events; the first 'data:' line carries the JSON-RPC payload.
const text = await r.text();
const payload = JSON.parse(text.match(/^data: (.*)$/m)[1]);
const result = JSON.parse(payload.result.content[0].text);
console.log(result);import os, json, re, requests
resp = requests.post(
"https://mapsmcp.com/mcp",
headers={
"Authorization": f"Bearer {os.environ['MAPSMCP_API_KEY']}",
"Content-Type": "application/json",
"Accept": "application/json, text/event-stream",
},
json={
"jsonrpc": "2.0", "id": 1, "method": "tools/call",
"params": {
"name": "evaluate_site",
"arguments": {
"address": "500 S Tryon St, Charlotte, NC 28202"
},
},
},
)
# Server-sent events: pull the data line, parse JSON.
sse = re.search(r"^data: (.*)$", resp.text, re.M).group(1)
payload = json.loads(sse)
result = json.loads(payload["result"]["content"][0]["text"])
print(result){
"match": {"matched_address": "500 S TRYON ST, CHARLOTTE, NC, 28202"},
"administrative": [
{"collection":"us-tracts","external_id":"37119000102",
"demographics":{"B01001_001E":4521,"B19013_001E":116200,
"pct_below_poverty":12.4,"pct_hispanic":15.1,
"pct_rent_burdened":42.0}},
/* + state, county, CD, sldu, sldl, ZCTA, school district, precinct */
]
}
You've got your own data — volunteer counts per precinct, donations per ZIP, attendance per ward. Ingest it, render a map, freeze the snapshot, and embed the result on your campaign site, in a newsletter, on a press release. Five MCP calls. Zero design work.
curl -X POST https://mapsmcp.com/mcp \
-H "Authorization: Bearer $MAPSMCP_API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"create_report","arguments":{"slug":"ward-volunteer-density-q1-2026","config":{"collection":"us-counties","version":"tiger-2024","datasets":[{"slug":"volunteer-count-by-ward","field":"volunteers_per_capita","palette":"sequential","classify":{"method":"quantile","bins":7}}]},"title":"Q1 volunteer density by ward","public":true}}}'const r = await fetch("https://mapsmcp.com/mcp", {
method: "POST",
headers: {
"Authorization": "Bearer " + process.env.MAPSMCP_API_KEY,
"Content-Type": "application/json",
"Accept": "application/json, text/event-stream",
},
body: JSON.stringify({
jsonrpc: "2.0", id: 1, method: "tools/call",
params: {
name: "create_report",
arguments: {
"slug": "ward-volunteer-density-q1-2026",
"config": {
"collection": "us-counties",
"version": "tiger-2024",
"datasets": [
{
"slug": "volunteer-count-by-ward",
"field": "volunteers_per_capita",
"palette": "sequential",
"classify": {
"method": "quantile",
"bins": 7
}
}
]
},
"title": "Q1 volunteer density by ward",
"public": true
},
},
}),
});
// Server-sent events; the first 'data:' line carries the JSON-RPC payload.
const text = await r.text();
const payload = JSON.parse(text.match(/^data: (.*)$/m)[1]);
const result = JSON.parse(payload.result.content[0].text);
console.log(result);import os, json, re, requests
resp = requests.post(
"https://mapsmcp.com/mcp",
headers={
"Authorization": f"Bearer {os.environ['MAPSMCP_API_KEY']}",
"Content-Type": "application/json",
"Accept": "application/json, text/event-stream",
},
json={
"jsonrpc": "2.0", "id": 1, "method": "tools/call",
"params": {
"name": "create_report",
"arguments": {
"slug": "ward-volunteer-density-q1-2026",
"config": {
"collection": "us-counties",
"version": "tiger-2024",
"datasets": [
{
"slug": "volunteer-count-by-ward",
"field": "volunteers_per_capita",
"palette": "sequential",
"classify": {
"method": "quantile",
"bins": 7
}
}
]
},
"title": "Q1 volunteer density by ward",
"public": true
},
},
},
)
# Server-sent events: pull the data line, parse JSON.
sse = re.search(r"^data: (.*)$", resp.text, re.M).group(1)
payload = json.loads(sse)
result = json.loads(payload["result"]["content"][0]["text"])
print(result){
"ok": true,
"slug": "ward-volunteer-density-q1-2026",
"public_url": "https://mapsmcp.com/v/ward-volunteer-density-q1-2026",
"embed_url": "https://mapsmcp.com/embed/ward-volunteer-density-q1-2026",
"citation_url": "https://mapsmcp.com/v/ward-volunteer-density-q1-2026/citation.json",
"frozen_at": "2026-05-25T22:15:33Z"
}
Free tier gets 50 calls/month, no card. Premium scales to 50K calls/month with batch APIs.
Get a free API key →