Porchlight

Porchlight for AI assistants

The API and MCP server

What it's for

Let an AI assistant (like Claude) or a program of your own see your gatherings and, if you allow it, say whether you're coming and sign you up to bring something or help out. Ask it "what's on this week?", "am I bringing anything Sunday?" or "tell them I'm coming to the retreat, just me". If you lead a group, it can run your gatherings too: "move Thursday's study to Friday at 7" or "cancel the 19th and tell everyone why".

It works as you, with your key: it sees what you see in the app, and nothing more. Home addresses follow the same rules as in the app. Group chats, prayer requests and notes are end-to-end encrypted on your phone, so they aren't available here: Porchlight's servers can't read them either.

Get a key

In Porchlight, tap your picture (top right), then AI assistants and API. Name the key after what will use it, and turn on Can answer and sign up for me if it should do more than look. If you lead a group, you can also turn on Can plan and change gatherings I run, so it can put gatherings on the calendar, change or move them, and cancel them. Then tap Make key.

Keys start with plk_. Copy yours straight away: it's shown only once (we keep only a scrambled copy that can check it, not the key itself). Treat it like a password. To change what it can do, tap what it says beside its name (like Can answer): the same key works the new way at once. Remove it on the same screen and it stops working at once.

Connect an assistant (MCP)

Porchlight is an MCP server, for assistants that speak the Model Context Protocol. It's at https://porchlight.tech/mcp (Streamable HTTP), and takes your key in a header: Authorization: Bearer plk_…. The tools are the operations below; a key gets only the ones it's allowed to do (one that can only look gets only the ones that look).

With Claude Code:

claude mcp add --transport http porchlight https://porchlight.tech/mcp --header "Authorization: Bearer plk_your-key"

Other assistants and tools that can connect to a remote MCP server with a header work the same way.

Connect by signing in (claude.ai, ChatGPT and others)

Assistants that add an MCP server as a connector, and sign you in themselves, don't need a key. Add a custom connector with the address https://porchlight.tech/mcp. It sends you to Porchlight, where you sign in if you need to and choose whether it can only look or also Can answer and sign up for me (and, for a group's leader, Can plan and change gatherings I run). Tap Allow, and you're back where you started, connected.

It's listed under AI assistants and API with your keys, marked Connected. Remove it there and it's disconnected at once. Tap what it says beside its name to change what it can do, without connecting again.

For developers: this is OAuth 2.1 as the MCP specification describes it. A 401 from /mcp points to /.well-known/oauth-protected-resource, which names Porchlight as the authorization server (/.well-known/oauth-authorization-server). Clients register themselves (dynamic client registration, at /oauth/register), send people to /oauth/authorize with PKCE (S256 only), and swap the code at /oauth/token. Scopes are read, write and manage (each includes the one before); the person picks, so a token may get less than was asked for, and its scope says what it got. Access tokens last an hour; refresh tokens last 90 days and are replaced each time they're used.

Use the API

The same operations, as a plain web API: https://porchlight.tech/api/v1, with your key in the Authorization header, JSON in and out. Dates are YYYY-MM-DD and times HH:MM, in the group's own time zone.

curl https://porchlight.tech/api/v1/gatherings?days=7 \
  -H "Authorization: Bearer plk_your-key"

When something doesn't work, you get an HTTP error and { "error": "…" } saying why, in words you can pass on: 400 (something's missing or wrong), 401 (no key, or it's been removed), 403 (not allowed: a key that can only look, say, or a gathering you don't run), 404 (no such gathering, or not one you can see) or 409 (it's taken already). There's an OpenAPI description at https://porchlight.tech/api/v1/openapi.json.

What it can do

Who you are

Any key

GET /api/v1/me

MCP tool: get_profile

The person this key belongs to: their name, email, and their household (the people one answer covers).

Returns: Your name and email, and your household's name and people (or null).

Your groups

Any key

GET /api/v1/groups

MCP tool: list_groups

Every group you're in: its name, what kind of group it is, how many people, whether you lead it, and when it next meets.

Returns: A list of groups, each with its id, name, kind, member count, your role and its next gathering's date.

Coming up

Any key

GET /api/v1/gatherings

MCP tool: list_gatherings

Gatherings coming up in your groups, soonest first: when and where, your answer, how many are coming, and what's still needed. Use it to answer "what's on this week?" or to find a gathering's id.

  • group_id (query, text): Only this group's (from list_groups). Leave out for all your groups.
  • days (query, number): How far ahead to look, in days (1 to 120). Leave out for everything scheduled.

Returns: A list of gatherings (see Gathering).

One gathering

Any key

GET /api/v1/gatherings/{gathering_id}

MCP tool: get_gathering

Everything about one gathering that you can see in the app: when and where, the details and agenda, the menu (what's needed, who's bringing what), jobs, who's coming, and your answer. Ids of menu items and jobs are what sign_up takes.

  • gathering_id (in the path, text, required): The gathering's id, from list_gatherings.

Returns: The gathering, with its agenda, menu, jobs, who's coming and the people your answer covers.

What you signed up for

Any key

GET /api/v1/commitments

MCP tool: list_commitments

Everything you've said you'll do, across your groups: hosting, jobs, dishes, meal crews and rides, soonest first.

Returns: A list of commitments, each with the gathering, its date and what you're doing.

Your notifications

Any key

GET /api/v1/notifications

MCP tool: list_notifications

Your recent notifications in Porchlight, newest first: reminders, changes to gatherings, invitations and the like.

  • unread_only (query, true or false): Only the ones you haven't read yet.

Returns: A list of notifications, each with its title, text, when, and whether it's been read.

Your Secret Santa person

Any key

GET /api/v1/secret-santa

MCP tool: get_secret_santa

Every Secret Santa you're in, with the person you're shopping for once you've revealed them in the app: their name, their wishlist (each question with their answer, links included), your anonymous Secret Santa messages with them (reading them here doesn't mark them read), and what you've said you're getting them. Also the party's date and budget. Their email, phone and address aren't included. If you haven't revealed your person yet, open Secret Santa in the app first: the reveal is yours to do.

Returns: A list of Secret Santas, each with the party and your person (or why there isn't one yet).

Say what you're getting them

Needs a key that can answer

PUT /api/v1/secret-santa/{gathering_id}/gift

MCP tool: set_secret_santa_gift

Note what you're getting your Secret Santa person, as you can in the app. Only you (and someone running it who isn't playing) can see it, so the same gift isn't bought twice. Send an empty gift to clear it.

  • gathering_id (in the path, text, required): The Christmas party's id, from get_secret_santa.
  • gift (JSON body, text, required): What you're getting them ("A board game and hot sauce"), up to 500 characters.

Returns: What you're getting them, as saved.

Say if you're coming

Needs a key that can answer

PUT /api/v1/gatherings/{gathering_id}/rsvp

MCP tool: answer_gathering

Answer for a gathering: going, maybe, or not going. In a household, one answer covers everyone in it; to say only some of them are going, list their keys (from get_gathering's my_household). If it's full, going puts you on the waitlist.

  • gathering_id (in the path, text, required): The gathering's id, from list_gatherings.
  • status (JSON body, text, required): Your answer. One of going, maybe, not_going.
  • who (JSON body, list of text): In a household: the keys of who's going (from my_household). Leave out for everyone.
  • note (JSON body, text): A short note with your answer ("Running 10 minutes late").

Returns: The gathering, with your answer as it now stands.

Bring something, or take a job

Needs a key that can answer

POST /api/v1/gatherings/{gathering_id}/signups

MCP tool: sign_up

Sign yourself up for something on a gathering: a dish on the menu, a job (childcare, setup), a meal crew or shared gear. Use the item's id from get_gathering. For an open-ended dish ("an entree"), say what you'll bring in note.

  • gathering_id (in the path, text, required): The gathering's id, from list_gatherings.
  • item_id (JSON body, text, required): The menu item's or job's id, from get_gathering.
  • note (JSON body, text): For a dish: what you're bringing ("Grandma's lasagna").

Returns: The gathering, with you signed up.

Let something go

Needs a key that can answer

DELETE /api/v1/gatherings/{gathering_id}/signups/{item_id}

MCP tool: drop_sign_up

Take yourself off something you signed up for on a gathering (a dish, a job, a crew), so someone else can.

  • gathering_id (in the path, text, required): The gathering's id, from list_gatherings.
  • item_id (in the path, text, required): The menu item's or job's id.

Returns: The gathering, without you on it.

A gathering's food plan

Any key

GET /api/v1/gatherings/{gathering_id}/food-plan

MCP tool: get_food_plan

For a gathering whose group plans its meals with a food plan (with meal crews): each meal (its day, name, its crew's note such as "Pick up the pizzas", and who's on its crew), its dishes (what's good to know, prep notes, and each ingredient as planned and as worked out for how many are coming), how many it's for (grown-ups, kids at half a portion, and anyone more the planner added), and the shopping list for every meal together, by section of the store. Whoever plans the food also sees what's been ticked off.

  • gathering_id (in the path, text, required): The gathering's id, from list_gatherings.

Returns: The meals with their dishes and ingredients, how many it's for, and the shopping list.

Plan a dish for a meal

Needs a key that can plan gatherings

POST /api/v1/gatherings/{gathering_id}/food-plan/dishes

MCP tool: set_food_plan_dish

Add a dish to one of a gathering's meals, or change one (with dish_id): its name, what's good to know, prep notes for whoever cooks it, and its ingredients. Give each ingredient's amount per person ("4" oz of pasta a person), per so many people (1 jar of parmesan per 12), or as a set amount for the whole meal; the app works out how much to buy from who's coming. For something bought as it is (chips, 3 bags in total), give it one ingredient with the dish's own name. Only the group's leaders, the gathering's organizer and its meal planner can. Replacing a dish replaces all its ingredients.

  • gathering_id (in the path, text, required): The gathering's id, from list_gatherings.
  • meal_id (JSON body, text, required): The meal (its crew's id), from get_food_plan.
  • dish_id (JSON body, text): To change a dish already planned: its id, from get_food_plan.
  • name (JSON body, text, required): What it is ("Spaghetti and meat sauce").
  • tags (JSON body, list of text): What's good to know about it: any of Vegetarian, Vegan, Gluten-free, Dairy-free, Contains nuts, Spicy, or "contains:" and an allergen of its own ("contains:Peanuts").
  • prep_notes (JSON body, text): For whoever's cooking it: how to make it, when to start, what's where.
  • ingredients (JSON body, list of text): Everything it takes.

Returns: The food plan, with the dish as saved.

Take a dish off a meal

Needs a key that can plan gatherings

DELETE /api/v1/gatherings/{gathering_id}/food-plan/dishes/{dish_id}

MCP tool: remove_food_plan_dish

Take a dish off a gathering's food plan. Only the group's leaders, the gathering's organizer and its meal planner can.

  • gathering_id (in the path, text, required): The gathering's id, from list_gatherings.
  • dish_id (in the path, text, required): The dish's id, from get_food_plan.

Returns: The food plan, without it.

Count more people in

Needs a key that can plan gatherings

PUT /api/v1/gatherings/{gathering_id}/food-plan/extra

MCP tool: set_food_plan_extra

How many more people to cook for than have said they're coming (people you know are coming who haven't answered yet). Only the group's leaders, the gathering's organizer and its meal planner can.

  • gathering_id (in the path, text, required): The gathering's id, from list_gatherings.
  • extra (JSON body, number, required): How many more (0 for none).

Returns: The food plan, with the new numbers.

Plan a gathering

Needs a key that can plan gatherings

POST /api/v1/groups/{group_id}/gatherings

MCP tool: create_gathering

Put a new one-time gathering on a group's calendar, in a group you lead. Everyone in the group hears about it unless notify is false. Confirm the details with the person first.

  • group_id (in the path, text, required): The group's id, from list_groups (one where your role is leader).
  • title (JSON body, text, required): What it's called ("Sunday Dinner").
  • date (JSON body, text, required): The day it's on (or starts), as YYYY-MM-DD.
  • end_date (JSON body, text): For one that runs over several days (a retreat or trip): its last day, as YYYY-MM-DD.
  • start_time (JSON body, text): When it starts, on a 24-hour clock ("18:30").
  • end_time (JSON body, text): When it ends, on a 24-hour clock.
  • location (JSON body, text): Where, as people would say it ("Grace Church", "The Parks' house").
  • address (JSON body, text): The street address, shown only to the people the app shows addresses to.
  • details (JSON body, text): What people should know (up to 2,000 characters).
  • capacity (JSON body, number): How many people can come. Past that, people go on a waitlist.
  • sign_up_by (JSON body, text): The last day people can say they're coming, as YYYY-MM-DD.
  • cost (JSON body, text): What it costs, in words ("$20 per person").
  • notify (JSON body, true or false): Tell everyone in the group it's on the calendar. On unless you send false.

Returns: The new gathering (see One gathering).

Change a gathering

Needs a key that can plan gatherings

PATCH /api/v1/gatherings/{gathering_id}

MCP tool: update_gathering

Change a gathering you run (as a group leader or its organizer): its name, when, where, details, spots, sign-up deadline or cost. Send only what changes. For a repeating gathering, this changes just that date. Once it's over, only its date and time (to put it off) and its cost can change.

  • gathering_id (in the path, text, required): The gathering's id, from list_gatherings.
  • title (JSON body, text): What it's called ("Sunday Dinner").
  • date (JSON body, text): The day it's on (or starts), as YYYY-MM-DD. Moving it starts its reminders over.
  • end_date (JSON body, text): For one that runs over several days (a retreat or trip): its last day, as YYYY-MM-DD. Send an empty string to clear it.
  • start_time (JSON body, text): When it starts, on a 24-hour clock ("18:30"). Send an empty string to clear it.
  • end_time (JSON body, text): When it ends, on a 24-hour clock. Send an empty string to clear it.
  • location (JSON body, text): Where, as people would say it ("Grace Church", "The Parks' house"). Send an empty string to clear it.
  • address (JSON body, text): The street address, shown only to the people the app shows addresses to. Send an empty string to clear it.
  • details (JSON body, text): What people should know (up to 2,000 characters). Send an empty string to clear it.
  • capacity (JSON body, number): How many people can come. Past that, people go on a waitlist. Send 0 for no limit.
  • sign_up_by (JSON body, text): The last day people can say they're coming, as YYYY-MM-DD. Send an empty string to clear it.
  • cost (JSON body, text): What it costs, in words ("$20 per person"). Send an empty string to clear it.
  • notify (JSON body, true or false): Tell everyone it has a new time or place (only sent when the date, start time or place changed). Leave out to change it quietly.

Returns: The gathering as it now stands.

Cancel a gathering

Needs a key that can plan gatherings

POST /api/v1/gatherings/{gathering_id}/cancel

MCP tool: cancel_gathering

Call off a gathering you run. Everyone coming hears it's cancelled, with your reason if you give one. It stays on the calendar marked cancelled, and restore_gathering puts it back on.

  • gathering_id (in the path, text, required): The gathering's id, from list_gatherings.
  • reason (JSON body, text): Why, in a sentence, passed on to everyone ("Snow's too deep, let's try next week").

Returns: The gathering, cancelled.

Put a cancelled gathering back on

Needs a key that can plan gatherings

POST /api/v1/gatherings/{gathering_id}/restore

MCP tool: restore_gathering

Undo cancel_gathering: the gathering's back on, and everyone hears the good news.

  • gathering_id (in the path, text, required): The gathering's id, from list_gatherings.

Returns: The gathering, back on.

A gathering

Gatherings come back with:

  • id, group (its id and name), title, date, end_date (for one over several days), start_time, end_time, status (scheduled or cancelled), invite_only (just for the people invited, so don't mention it to anyone else) and url (its page in Porchlight).
  • where (the host's place by its name, or the location), address (only when the app would show it to you), host and needs_host.
  • my_answer (going, maybe, not_going, waitlist, or null if you haven't said), coming (how many), spots (when seats are limited), sign_up_by and cost.
  • still_needed (what nobody's signed up for yet), my_jobs and my_dishes.
  • From get_gathering, also: details, agenda, menu (each item's id, open_spots, who's bringing it and whether it's mine), jobs (jobs, meal crews and shared gear, the same way), who_is_coming and my_household (the key of everyone your answer covers, for answering for some of them), and you_run_it (you lead its group or organize it, so you can change or cancel it with a key that can plan gatherings).

Good to know

An assistant acting for you does exactly what you could: answering tells the same people the app would, and signing up shows on the gathering for everyone. Planning or cancelling a gathering tells everyone just as the app does, and changing one tells them when you send notify. Please don't hammer it: it's a small, free app.

Questions, or something you'd like it to do? Tap your picture, then Help & support, then Contact support.