create-project-with-headings
Create structured projects in Things 3 with predefined headings, tasks, deadlines, and organization to manage work systematically.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| title | Yes | Title of the new project to create in Things | |
| goal | No | Short description of what the project is trying to achieve | |
| work_type | No | Optional category like design, software, content, workshop, personal | |
| methodology | No | Optional methodology or framework to reflect in the heading structure | |
| notes | No | Notes for the project | |
| when | No | today, tomorrow, anytime, someday, YYYY-MM-DD or YYYY-MM-DD@HH:MM | |
| deadline | No | Deadline date for the project | |
| tags | No | Tag names to apply to the project | |
| area-id | No | Area UUID to place the project into | |
| area | No | Area title to place the project into | |
| headings | No | Explicit headings to create. If omitted, headings are inferred. | |
| todos | No | Top-level to-dos to create in the project after the headings | |
| todos_by_heading | No | Map of heading title to to-do titles that should be created under that heading | |
| reveal | No | Reveal the newly created project in Things |
Implementation Reference
- src/index.ts:1765-1853 (handler)The implementation of the 'create-project-with-headings' MCP tool. It defines the input schema, handles the request, builds a structured payload, and uses Things' JSON URL scheme to perform the creation.
"create-project-with-headings", { title: z.string().describe("Title of the new project to create in Things"), goal: z .string() .optional() .describe("Short description of what the project is trying to achieve"), work_type: z .string() .optional() .describe("Optional category like design, software, content, workshop, personal"), methodology: z .string() .optional() .describe("Optional methodology or framework to reflect in the heading structure"), notes: z.string().optional().describe("Notes for the project"), when: z.string().optional().describe("today, tomorrow, anytime, someday, YYYY-MM-DD or YYYY-MM-DD@HH:MM"), deadline: z.string().optional().describe("Deadline date for the project"), tags: z.array(z.string()).optional().describe("Tag names to apply to the project"), "area-id": z.string().optional().describe("Area UUID to place the project into"), area: z.string().optional().describe("Area title to place the project into"), headings: z.array(z.string()).min(1).optional().describe("Explicit headings to create. If omitted, headings are inferred."), todos: z.array(z.string()).optional().describe("Top-level to-dos to create in the project after the headings"), todos_by_heading: z .record(z.array(z.string())) .optional() .describe("Map of heading title to to-do titles that should be created under that heading"), reveal: z.boolean().optional().describe("Reveal the newly created project in Things"), }, async ({ title, goal, work_type, methodology, notes, when, deadline, tags, area, "area-id": areaId, headings, todos, todos_by_heading, reveal, }) => { const inferredHeadings = uniqueHeadingNames( headings?.length ? headings : inferHeadingTemplate({ projectTitle: `${title} ${methodology ?? ""}`.trim(), goal, workType: work_type, }) ); const payload = buildStructuredProjectPayload({ title, notes, when, deadline, tags, area, areaId, headings: inferredHeadings, todosByHeading: todos_by_heading, todos, }); const data = JSON.stringify(payload); const enriched = await enrichWriteParams("json", { data, reveal, }); const url = await openThingsURL("json", buildURLParams(enriched)); return buildTextResponse(`Created structured project "${title}" with headings`, { title, goal: goal ?? null, workType: work_type ?? null, methodology: methodology ?? null, headings: inferredHeadings, todosByHeading: todos_by_heading ?? {}, todos: todos ?? [], payload, url, guidance: "Use this tool for brand-new projects that need headings. For existing projects, inspect headings first and ask the user to create missing headings manually.", }); } );