Hopp til hovedinnhold

MCP-server

B1 API leverer en MCP (Model Context Protocol)-server på /mcp. Enhver MCP-klar AI-klient -- Claude Code, Claude Desktop, OpenAI Agents SDK, Cursor, eller dine egne -- kan koble til den og kalle den underliggende REST API på vegne av en autentisert kirkebruker. Det er et tynt, generisk innpakning: det er tre verktøy, og de eksponerer hele API-overflaten dynamisk i stedet for å håndmodellere hvert sluttpunkt.

Før du begynner

  • En B1 API-nøkkel (cak_…) med omfangene klienten skal ha
  • Et nåbart B1 API-vertsnavn -- https://api.churchapps.org for vertskirker, eller din egen distribusjon
  • En MCP-klient. Se Claude og ChatGPT for sluttbruker-oppsett

Sluttpunkt

POST /mcp
Content-Type: application/json
Accept: application/json, text/event-stream
Authorization: Bearer cak_<prefix>.<secret>
AspektVerdi
Vei/mcp (relativt til API-verten)
MetodePOST bare -- forespørsel/respons og SSE streaming skjer begge på samme sluttpunkt
TransportMCP Streamable HTTP
Sesjon-modellTilstandsløs. En frisk MCP-server-instans bygges per forespørsel -- ingen sesjon-id, ingen gjenopptakelse
AuthBærer token. cak_… API-nøkler og B1 JWTs begge fungerer; oppløsning er det samme som noe annet autentisert sluttpunkt

En forespørsel hvis Authorization-hode mangler eller er ugyldig returnerer:

{ "error": "Unauthorized — MCP requires a valid bearer token (cak_* API key or JWT)." }

med HTTP 401.

Verktøy

Tre verktøy, alle generiske. Modellen bruker list_endpoints for oppdagelse, describe_endpoint for å lære nyttelast-form, og api_call for å faktisk påkalle API-en.

list_endpoints

Returnerer hele beholdningen av registrerte REST-ruter, filtrert etter et valgfritt understreng og/eller HTTP-verb. Hver oppføring inkluderer kontroller-navn og API-nøkkelomfang mest sannsynlig trengt.

Inndata:

FeltTypeBeskrivelse
filterstreng (valgfritt)Case-insensitive understreng samsvart mot banen, f.eks. "people"
methodenum (valgfritt)GET / POST / PUT / DELETE / PATCH

Utdata: et JSON-dokument av formen

{
"total": 24,
"endpoints": [
{
"method": "GET",
"path": "/membership/people",
"controller": "PersonController.getAll",
"likelyScopes": ["people:read", "people:write"]
}
]
}

Beholdningen bygges en gang ved API-oppstart fra direkte-ruttetabellen -- noe du kan treffe med curl vises her.

describe_endpoint

Returnerer en kort sammenfatning pluss, hvor tilgjengelig, et håndkurert forespørselsformat og responseksempel for ett sluttpunkt.

Inndata:

FeltTypeBeskrivelse
methodstrengHTTP-verb
pathstrengFull vei som returnert av list_endpoints

Utdata: for kuraterte sluttpunkter, et eksempel med summary, requestBody, og responseSample. For ikke-kuraterte sluttpunkter, en fallback-melding som instruerer modellen å kalle GET først for å se formen. Omtrent ett dusin høytrafikkruter (mennesker, grupper, donasjoner, frammøte, fond) er kuraterte.

api_call

Påkaller det valgte REST-sluttpunktet, in-prosess, gjennom samme Express-meldings-stabel som en normal HTTP-forespørsel -- auth, kropp-analyse, revisjonslogging og per-kirke-omfang alle gjør alle.

Inndata:

FeltTypeBeskrivelse
methodenumGET / POST / PUT / DELETE / PATCH
pathstrengVei inkludert enhver modulprefikks, f.eks. /membership/people
queryobjekt (valgfritt)Flatt objekt av strengeparametere
bodynoe (valgfritt)JSON forespørsel-kropp -- typisk en matrise av modellobjekter for POST

Utdata:

{
"status": 200,
"truncated": false,
"body": [ /* the controller's JSON response */ ]
}

Verktøy-resultat er merket isError: true for enhver respons med status >= 400.

Auth-modell

MCP-forespørselen selv kjøres gjennom CustomAuthProvider.getUser() -- samme vei hver autentisert B1-sluttpunkt bruker. En cak_… bærer løses til en Principal hvis tillatelser er utstedelsespersonens gjeldende RBAC, krysset med nøkkels innvilgede omfang. Dette krysset blir omberegnet på hver forespørsel, så:

  • Å fjerne et omfang fra en nøkkel (ved å slette og gjenopprett den) kutter tilgangen på neste kall.
  • Å fjerne en tillatelse fra den underliggende personen i B1Admin kutter tilgangen på neste kall, selv om nøkkelen fortsatt eksisterer.

For nestede api_call-påkallinger kopieres den opprinnelige Authorization-hodet til den syntetiske forespørselen, så CustomAuthProvider kjøres igjen og omfang-krysset re-brukes per kall. Det er ingen tokencaching.

Vei-blokkering

Et lite sett av ruter er ikke nåbare via api_call, selv med en gyldig nøkkel:

MønsterHvorfor
/giving/donate/webhook/*Leverandør-webhook-sluttpunkter forventer rå, signatur-verifiserte kropper fra Stripe/PayPal -- ikke generelle anropere
/membership/oauth/clients*OAuth-klient-registrering er operatør-bare
/membership/people/apiEmailsUtesperret av operatøren jwtSecret, ikke bruker-tillatelser
Enhver rute som forventer multipart/form-dataFilast-opp er ikke JSON-RPC-venlig

En blokkert vei returnerer et isError: true verktøy-resultat med en beskrivende melding; den underliggende ruten blir aldri påkalt.

Respons-størrelse-begrenset

Hver api_call respons-kropp er begrenset til 64 KB av tatt utgang. Hvis en spørring overskrider grensen, bærer responsen "truncated": true og modellen forventes å prøve igjen med smalere spørring-parametre. Dette holder en enkelt verktøy-respons fra å blåse ut klientens kontekstvindu.

Hastighetsbegrensning

Det er ingen applikasjons-nivå hastighetsbegrensning på /mcp. Dremling utsettes til API Gateway / Lambda-samtidighet i produksjon, og til hva som helst din omvendte fullmakt håndhever i selvvert-distribusjoner.

Lokal utvikling

MCP-sluttpunktet monteres sammen med alt annet når API-en kjøres lokalt:

cd Api
npm run dev
# Server listening on http://localhost:8084

Ved oppstart bekrefter log-linja 📡 MCP server ready at /mcp — N routes in inventory at beholdningen ble bygget.

Prøv det med MCP Inspector:

npx @modelcontextprotocol/inspector

I Inspector UI peker du den på http://localhost:8084/mcp og setter Authorization-hodet til Bearer cak_<prefix>.<secret>. Kall list_endpoints først; du burde se full rutelist. Så api_call({ method: "GET", path: "/membership/people" }) burde returnere dine lokale frø-mennesker.