create_team_note
Create a new note in a HackMD team by specifying team path, title, markdown content, and read/write permissions. Optionally set a custom permalink for direct sharing.
Instructions
Create a note in a team
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| team_path | Yes | Team path | |
| title | No | Note title | |
| content | No | Markdown content | |
| read_permission | No | Read permission | guest |
| write_permission | No | Write permission | owner |
| permalink | No | Custom permalink |
Implementation Reference
- src/tools.ts:161-195 (handler)The tool 'create_team_note' is registered and implemented inline via server.tool(). It accepts team_path, title, content, read_permission, write_permission, and permalink parameters, builds a request body, and POSTs to /teams/:team_path/notes via hackmdFetch.
server.tool( "create_team_note", "Create a note in a team", { team_path: z.string().min(1).describe("Team path"), title: z.string().optional().describe("Note title"), content: z.string().optional().describe("Markdown content"), read_permission: z .enum(["owner", "signed_in", "guest"]) .default("guest") .describe("Read permission"), write_permission: z .enum(["owner", "signed_in", "guest"]) .default("owner") .describe("Write permission"), permalink: z.string().optional().describe("Custom permalink"), }, async ({ team_path, title, content, read_permission, write_permission, permalink }) => { try { const body: Record<string, unknown> = { readPermission: read_permission, writePermission: write_permission, }; if (title !== undefined) body.title = title; if (content !== undefined) body.content = content; if (permalink !== undefined) body.permalink = permalink; return success( await hackmdFetch(`/teams/${team_path}/notes`, { method: "POST", body }) ); } catch (e) { return error((e as Error).message); } } ); - src/tools.ts:161-177 (schema)Zod schema for 'create_team_note' defining the input shape: team_path (string), title (optional string), content (optional string), read_permission (enum), write_permission (enum), and permalink (optional string).
server.tool( "create_team_note", "Create a note in a team", { team_path: z.string().min(1).describe("Team path"), title: z.string().optional().describe("Note title"), content: z.string().optional().describe("Markdown content"), read_permission: z .enum(["owner", "signed_in", "guest"]) .default("guest") .describe("Read permission"), write_permission: z .enum(["owner", "signed_in", "guest"]) .default("owner") .describe("Write permission"), permalink: z.string().optional().describe("Custom permalink"), }, - src/tools.ts:161-195 (registration)Tool registration via server.tool() call within the registerTools function, binding the name, description, schema, and handler inline.
server.tool( "create_team_note", "Create a note in a team", { team_path: z.string().min(1).describe("Team path"), title: z.string().optional().describe("Note title"), content: z.string().optional().describe("Markdown content"), read_permission: z .enum(["owner", "signed_in", "guest"]) .default("guest") .describe("Read permission"), write_permission: z .enum(["owner", "signed_in", "guest"]) .default("owner") .describe("Write permission"), permalink: z.string().optional().describe("Custom permalink"), }, async ({ team_path, title, content, read_permission, write_permission, permalink }) => { try { const body: Record<string, unknown> = { readPermission: read_permission, writePermission: write_permission, }; if (title !== undefined) body.title = title; if (content !== undefined) body.content = content; if (permalink !== undefined) body.permalink = permalink; return success( await hackmdFetch(`/teams/${team_path}/notes`, { method: "POST", body }) ); } catch (e) { return error((e as Error).message); } } ); - src/api.ts:13-38 (helper)hackmdFetch is the HTTP helper used by the handler to make authenticated API calls to the HackMD v1 API.
export async function hackmdFetch( path: string, options: { method?: string; body?: unknown } = {} ): Promise<unknown> { const { method = "GET", body } = options; const token = getToken(); const res = await fetch(`${API_BASE}${path}`, { method, headers: { Authorization: `Bearer ${token}`, ...(body ? { "Content-Type": "application/json" } : {}), }, ...(body ? { body: JSON.stringify(body) } : {}), }); if (!res.ok) { const text = await res.text().catch(() => ""); throw new Error(`HackMD API ${method} ${path} → ${res.status}: ${text}`); } if (res.status === 204) return { success: true }; if (res.status === 202) return { success: true, status: "accepted" }; return res.json(); } - src/helpers.ts:1-12 (helper)success() and error() helpers wrap responses in the MCP content format (text with JSON string).
export function success(data: unknown) { return { content: [{ type: "text" as const, text: JSON.stringify(data, null, 2) }], }; } export function error(message: string) { return { content: [{ type: "text" as const, text: JSON.stringify({ error: message }) }], isError: true as const, }; }