Developer reference
Church Website Editor MCP server
A Model Context Protocol server that lets an AI assistant edit a church's website by operating directly on its GitHub repository. Writes commit to the default branch and auto-deploy to production via Vercel in about 30 seconds. 25tools, GitHub-OAuth scoped to the caller's own repositories.
Looking for the plain-English version? See the pastor's guide.
Connection
- Endpoint
- https://www.elijahdesent.com/api/mcp
- Transport
- Streamable HTTP (stateless)
- Server
- elijahdesent-crm v0.10.0
- Auth
- OAuth 2.1 — identity via GitHub
- Authorization metadata
- /.well-known/oauth-authorization-server
- Protected-resource metadata
- /.well-known/oauth-protected-resource
The endpoint advertises OAuth 2.1 with dynamic client registration; the discovery documents above let a compliant MCP client negotiate the flow automatically. Tokens are bound to the GitHub account that has access to the church's repository, so every call is scoped to repos the caller already owns.
Add as a remote connector
{
"mcpServers": {
"church-website-editor": {
"url": "https://www.elijahdesent.com/api/mcp"
}
}
}Most clients (Claude, ChatGPT developer mode, Perplexity) add it through their connector UI instead — see the setup walkthrough. On first connect, the client opens a GitHub sign-in to authorize.
Conventions
repoaccepts a barename— the server fills in the caller's GitHub owner. Useowner/nameonly for another org.- Every successful write is one commit to the default branch. Vercel auto-deploys on push; no separate deploy step.
- Prefer
replace_in_filefor edits.edit_filereplaces the whole file and is guarded against partial-content wipes (allow_shrinkto override). - read tools never mutate; commit tools push to the repo; status tools report state only.
Tools
Connection & discovery
Establish identity and find the repos and sites the caller can touch.
connection_statusstatusConfirm the caller is authenticated and the GitHub link is live. Use to diagnose auth failures.
No parameters.
Returns Authenticated user, GitHub link state, and the church site(s) wired to the account.
list_my_sitesstatusList the church(es) linked to the caller in the CRM, with their live domains.
No parameters.
Returns Array of { church, domain }.
list_reposreadList GitHub repositories the caller can access. Owner-scoped by default.
| Param | Type | Description |
|---|---|---|
filter | string | Substring to filter repo names (e.g. 'baptist'). |
Returns Array of { name, description, default_branch, private }.
search_reposreadFind a repo by matching across both its name AND description. Broader than list_repos (name-only) — use when you know what a site is about but not its exact repo name.
| Param | Type | Description |
|---|---|---|
queryreq | string | Text to match against repo name or description (e.g. 'baptist', a town, a pastor's name). |
limit | integer | How many matches to return, 1–50. Default 20. |
Returns Matching repos, newest first, each with description, visibility, and last-updated.
get_repo_inforeadReport a repo's framework versions so edits match its conventions. Call before any non-trivial code edit.
| Param | Type | Description |
|---|---|---|
reporeq | string | Repo as 'owner/name', or bare 'name' to use the caller's GitHub owner. |
Returns Next.js / React / Tailwind versions, TypeScript usage, and router (app vs pages).
Reading content
Navigate the tree, read files, search, and inventory live images. All read-only.
list_pagesreadList the contents of a directory. Empty path lists the repo root.
| Param | Type | Description |
|---|---|---|
reporeq | string | Repo as 'owner/name', or bare 'name' to use the caller's GitHub owner. |
path | string | Directory path; empty string for repo root (default). |
ref | string | Branch, tag, or SHA. Defaults to the repo's default branch. |
Returns Array of { name, type: 'file' | 'dir' }.
read_filereadRead the full UTF-8 contents of a file. Always read before editing.
| Param | Type | Description |
|---|---|---|
reporeq | string | Repo as 'owner/name', or bare 'name' to use the caller's GitHub owner. |
pathreq | string | File path within the repo. |
ref | string | Branch, tag, or SHA. Defaults to the repo's default branch. |
Returns Full file contents.
search_contentreadRecursive content search (fetches the tree and greps each text file) — works on fresh, unindexed repos.
| Param | Type | Description |
|---|---|---|
reporeq | string | Repo as 'owner/name', or bare 'name' to use the caller's GitHub owner. |
queryreq | string | Case-insensitive text to find. |
ref | string | Branch, tag, or SHA. Defaults to the repo's default branch. |
path_prefix | string | Only search paths starting with this (e.g. 'src/app/'). |
Returns Up to 30 matching files, each with matching line numbers.
list_photosreadInventory image files with their exact live URLs. Call before pointing a page at a photo to avoid broken-image typos.
| Param | Type | Description |
|---|---|---|
reporeq | string | Repo as 'owner/name', or bare 'name' to use the caller's GitHub owner. |
folder | string | Folder to list from. Defaults to 'public' (site-served images). |
ref | string | Branch, tag, or SHA. Defaults to the repo's default branch. |
Returns Array of images with repo path and live URL.
Writing content
Each successful write is one commit to the default branch, which auto-deploys to production via Vercel (~30s).
replace_in_filecommitTargeted edit — replace exact text. Preferred for small changes; only touches what you specify.
| Param | Type | Description |
|---|---|---|
reporeq | string | Repo as 'owner/name', or bare 'name' to use the caller's GitHub owner. |
pathreq | string | File path within the repo. |
old_stringreq | string | Exact text to find, whitespace included. Add context to make it unique. |
new_stringreq | string | Replacement text. |
messagereq | string | Plain-English commit message. |
branch | string | Branch to commit to. Defaults to default branch. |
replace_all | boolean | Replace every occurrence. Default false (must match exactly once). |
Returns Commit confirmation.
edit_filecommitCreate a new file or replace a file's FULL contents. Has a shrink guard against partial-content wipes.
| Param | Type | Description |
|---|---|---|
reporeq | string | Repo as 'owner/name', or bare 'name' to use the caller's GitHub owner. |
pathreq | string | File path within the repo. |
contentreq | string | Full new file contents (UTF-8). |
messagereq | string | Plain-English commit message. |
branch | string | Branch to commit to. Defaults to default branch. |
allow_shrink | boolean | Override the guard that rejects writes dropping >20 lines AND <60% of prior size. |
Returns Commit confirmation, or a rejection if the shrink guard trips.
upload_photocommitAdd a photo/video. Called without `data`, returns a one-time upload link; small images commit to the repo, videos & large files route to hosted storage automatically.
| Param | Type | Description |
|---|---|---|
reporeq | string | Repo as 'owner/name', or bare 'name' to use the caller's GitHub owner. |
pathreq | string | Save location. Use 'public/<name>.<ext>' for site-served images. |
messagereq | string | Plain-English commit message. |
data | string | Advanced — base64 image bytes. Omit to get an upload link instead. |
branch | string | Branch to commit to. Defaults to default branch. |
Returns A one-time upload link (default), or a commit confirmation when `data` is supplied.
get_uploaded_photo_urlreadResolve where an upload landed after the user has used the link from upload_photo.
| Param | Type | Description |
|---|---|---|
tokenreq | string | The upload link (https://.../u/<token>) or the bare token. |
Returns HOSTED (permanent storage URL), COMMITTED (live repo path), or PENDING (not uploaded yet).
History & undo
Inspect commits and roll changes back non-destructively.
list_recent_changesreadList recent commits, newest first.
| Param | Type | Description |
|---|---|---|
reporeq | string | Repo as 'owner/name', or bare 'name' to use the caller's GitHub owner. |
path | string | Limit to commits touching this file/directory. |
limit | integer | How many to return, 1–50. Default 15. |
Returns Array of { short SHA, time, author, message }.
show_changereadGet the message, touched files, and diff for one commit.
| Param | Type | Description |
|---|---|---|
reporeq | string | Repo as 'owner/name', or bare 'name' to use the caller's GitHub owner. |
shareq | string | Commit SHA (full or short). |
Returns Per-file patch with added/removed lines.
revert_changecommitUndo a commit by creating a new commit that restores the prior state. Original commit stays in history.
| Param | Type | Description |
|---|---|---|
reporeq | string | Repo as 'owner/name', or bare 'name' to use the caller's GitHub owner. |
shareq | string | Commit SHA to revert. |
branch | string | Branch to apply the revert on. Defaults to default branch. |
Returns Revert commit confirmation.
Deployment
Confirm edits reached production.
check_deploy_statusstatusCheck whether recent edits deployed. Auto-discovers the caller's site(s) from GitHub access.
| Param | Type | Description |
|---|---|---|
repo | string | Narrow to one repo. Omit to check all of the caller's sites. |
Returns Deploy state per site; on failure, the last lines of build output.
Custom domains
Attach a custom domain to a site on Vercel and confirm it's pointing correctly. Scoped to projects linked to repos the caller can access. The pastor changes their nameservers at their registrar; the tools never touch the registrar directly.
connect_domainvercelAttach a custom domain to the caller's Vercel project and return plain-English instructions to point the domain's nameservers at Vercel (with an A/CNAME alternative for domains that host email). A bare apex auto-pairs its 'www.'. Goes live once nameservers propagate.
| Param | Type | Description |
|---|---|---|
domainreq | string | Domain to connect, e.g. 'gracebaptist.org' or 'www.gracebaptist.org'. |
repo | string | Which site, as 'owner/name' or 'name'. Needed only if the caller has multiple sites. |
Returns Confirmation plus the Vercel nameservers to set at the registrar (from the Vercel API, e.g. ns1/ns2.vercel-dns.com), and an A/CNAME fallback.
check_domainstatusCheck whether a connected domain's nameservers point at Vercel and the site is verified and live. When fully live and the caller owns exactly one church, records it as that church's live_domain so analytics attribute traffic.
| Param | Type | Description |
|---|---|---|
domainreq | string | Domain to check, e.g. 'gracebaptist.org'. |
repo | string | Which site, as 'owner/name' or 'name'. Needed only if the caller has multiple sites. |
Returns Nameserver status (current vs. expected) + site verification state; when live, confirmation it's been linked for analytics.
redirect_domainvercelChange where a connected domain points: redirect it to another domain (e.g. an old domain or the non-www version → the main site), or pass redirect_to 'none' to serve directly. Can't chain — the target must not itself be a redirect.
| Param | Type | Description |
|---|---|---|
domainreq | string | The connected domain to change, e.g. 'www.gracebaptist.org'. |
redirect_to | string | Domain to send visitors to, e.g. 'gracebaptist.org'. Use 'none' (or omit) to turn the redirect off. |
permanent | boolean | Permanent (308) by default; false for a temporary 307. |
repo | string | Which site, as 'owner/name' or 'name'. Needed only if the caller has multiple sites. |
Returns Confirmation of the new redirect (or that the domain now serves directly). Reports the chaining error if the target is itself a redirect.
Analytics
Read-only traffic data, auto-scoped to the caller's own sites. Pass `church` to disambiguate when they own more than one.
analytics_summaryreadHigh-level traffic over a recent window.
| Param | Type | Description |
|---|---|---|
church | string | Church name or live domain. |
days | integer | Window in days, 1–90. Default 28. |
Returns Total pageviews, unique visitors (devices), country & device breakdown.
top_pagesreadMost-viewed pages over a recent window.
| Param | Type | Description |
|---|---|---|
church | string | Church name or live domain. |
days | integer | Window in days, 1–90. Default 28. |
limit | integer | How many pages, 1–50. Default 10. |
Returns Ranked pages with view counts.
top_referrersreadTop external referrers (direct traffic excluded).
| Param | Type | Description |
|---|---|---|
church | string | Church name or live domain. |
days | integer | Window in days, 1–90. Default 28. |
limit | integer | How many referrers, 1–50. |
Returns Ranked referrers with counts.
traffic_by_dayreadDaily pageviews trend for spotting spikes and quiet weeks.
| Param | Type | Description |
|---|---|---|
church | string | Church name or live domain. |
days | integer | Window in days, 1–90. Default 14. |
Returns Pageviews per day.
Scoring
Audit any church website against the Church Website Score rubric.
score_websitereadFetch a site's homepage and key subpages and return the grading rubric plus page content. The caller (the model) does the scoring — the tool calls no AI itself.
| Param | Type | Description |
|---|---|---|
urlreq | string | The site to score, e.g. 'gracebaptist.org'. |
Returns The full 6-category / 100-point rubric and the fetched page content.
Built and maintained by Pastor Eli (Elijah Desent) · Pastor@elijahdesent.com