@tightknitai/tightknit 0.1.0-alpha.7 → 0.1.0-alpha.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -113,7 +113,7 @@ async function parseErrorResponse(response) {
|
|
|
113
113
|
let message;
|
|
114
114
|
try {
|
|
115
115
|
const body = await response.json();
|
|
116
|
-
message =
|
|
116
|
+
message = JSON.stringify(body);
|
|
117
117
|
} catch {
|
|
118
118
|
message = response.statusText;
|
|
119
119
|
}
|
|
@@ -176,9 +176,10 @@ async function listEvents(params) {
|
|
|
176
176
|
);
|
|
177
177
|
}
|
|
178
178
|
async function createEvent(input) {
|
|
179
|
+
const { description, ...rest } = input;
|
|
179
180
|
return apiRequest("/calendar_events", {
|
|
180
181
|
method: "POST",
|
|
181
|
-
body:
|
|
182
|
+
body: { ...rest, description: { text: description } },
|
|
182
183
|
idempotencyKey: crypto.randomUUID()
|
|
183
184
|
});
|
|
184
185
|
}
|
|
@@ -277,4 +278,4 @@ export {
|
|
|
277
278
|
sendMessage,
|
|
278
279
|
search
|
|
279
280
|
};
|
|
280
|
-
//# sourceMappingURL=chunk-
|
|
281
|
+
//# sourceMappingURL=chunk-DW4LVC2F.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/config.ts","../src/core/version.ts","../src/core/client.ts"],"sourcesContent":["import Conf from \"conf\";\n\nexport type Environment = \"production\" | \"staging\";\n\ninterface TightknitConfig {\n apiKey: string;\n defaultOutput: \"json\" | \"table\";\n environment: Environment;\n}\n\nconst config = new Conf<TightknitConfig>({\n projectName: \"tightknit\",\n defaults: {\n apiKey: \"\",\n defaultOutput: \"table\",\n environment: \"production\",\n },\n});\n\n/** Runtime API key set via --api-key flag (highest precedence) */\nlet runtimeApiKey: string | undefined;\n\n/** Set a runtime API key (from --api-key flag). Takes highest precedence. */\nexport function setRuntimeApiKey(key: string | undefined): void {\n runtimeApiKey = key;\n}\n\n/** Get the API key — --api-key flag > env var > stored config */\nexport function getApiKey(): string {\n return runtimeApiKey || process.env.TIGHTKNIT_API_KEY || config.get(\"apiKey\");\n}\n\n/** Set the API key */\nexport function setApiKey(key: string): void {\n config.set(\"apiKey\", key);\n}\n\n/** Get the default output format */\nexport function getDefaultOutput(): \"json\" | \"table\" {\n return config.get(\"defaultOutput\");\n}\n\n/** Set the default output format */\nexport function setDefaultOutput(format: \"json\" | \"table\"): void {\n config.set(\"defaultOutput\", format);\n}\n\n/** Get the configured environment */\nexport function getEnvironment(): Environment {\n return (process.env.TIGHTKNIT_ENVIRONMENT as Environment) || config.get(\"environment\");\n}\n\n/** Set the environment */\nexport function setEnvironment(env: Environment): void {\n config.set(\"environment\", env);\n}\n\nconst VALID_CONFIG_KEYS = \"api-key, default-output, environment\";\n\n/** Get a config value by key name */\nexport function getConfigValue(key: string): string {\n switch (key) {\n case \"api-key\":\n return getApiKey();\n case \"default-output\":\n return getDefaultOutput();\n case \"environment\":\n return getEnvironment();\n default:\n throw new Error(`Unknown config key: ${key}. Valid keys: ${VALID_CONFIG_KEYS}`);\n }\n}\n\n/** Set a config value by key name */\nexport function setConfigValue(key: string, value: string): void {\n switch (key) {\n case \"api-key\":\n setApiKey(value);\n break;\n case \"default-output\":\n if (value !== \"json\" && value !== \"table\") {\n throw new Error(`Invalid output format: ${value}. Must be \"json\" or \"table\"`);\n }\n setDefaultOutput(value);\n break;\n case \"environment\":\n if (value !== \"production\" && value !== \"staging\") {\n throw new Error(`Invalid environment: ${value}. Must be \"production\" or \"staging\"`);\n }\n setEnvironment(value);\n break;\n default:\n throw new Error(`Unknown config key: ${key}. Valid keys: ${VALID_CONFIG_KEYS}`);\n }\n}\n\n/** Get the config file path (useful for debugging) */\nexport function getConfigPath(): string {\n return config.path;\n}\n","import { readFileSync } from 'node:fs';\nimport { fileURLToPath } from 'node:url';\nimport { dirname, join } from 'node:path';\n\n/** Walks up from the current module to find the CLI's package.json version */\nfunction readVersion(): string {\n let dir = dirname(fileURLToPath(import.meta.url));\n for (let i = 0; i < 5; i++) {\n try {\n const pkgPath = join(dir, 'package.json');\n const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8')) as {\n name?: string;\n version?: string;\n };\n if (pkg.name === '@tightknitai/tightknit') {\n return pkg.version ?? '0.0.0';\n }\n } catch {\n // continue walking up\n }\n dir = dirname(dir);\n }\n return '0.0.0';\n}\n\nexport const VERSION = readVersion();\n","import { getApiKey, getEnvironment } from \"./config\";\nimport type { ApiError } from \"./types\";\n\nconst BASE_URLS = {\n production: \"https://api.tightknit.ai\",\n staging: \"https://staging-api.tightknit.ai\",\n} as const;\n\nconst API_PREFIX = \"/admin/v0\";\n\n/** Get the base URL for the current environment */\nfunction getBaseUrl(): string {\n return BASE_URLS[getEnvironment()];\n}\n\ninterface RequestOptions {\n method?: \"GET\" | \"POST\" | \"PATCH\" | \"DELETE\";\n body?: Record<string, unknown>;\n params?: Record<string, string | number | boolean | undefined>;\n idempotencyKey?: string;\n}\n\n/** Build a URL with query parameters */\nfunction buildUrl(path: string, params?: Record<string, string | number | boolean | undefined>): string {\n const url = new URL(`${API_PREFIX}${path}`, getBaseUrl());\n if (params) {\n for (const [key, value] of Object.entries(params)) {\n if (value !== undefined) {\n url.searchParams.set(key, String(value));\n }\n }\n }\n return url.toString();\n}\n\n/** Parse an API error response into a structured error */\nasync function parseErrorResponse(response: Response): Promise<ApiError> {\n let message: string;\n try {\n const body = await response.json() as Record<string, unknown>;\n message = JSON.stringify(body);\n } catch {\n message = response.statusText;\n }\n\n return {\n error: true,\n code: response.status,\n message: `${message} (${response.status})`,\n };\n}\n\n/** Make an authenticated request to the Tightknit API */\nexport async function apiRequest<T>(path: string, options: RequestOptions = {}): Promise<T> {\n const { method = \"GET\", body, params, idempotencyKey } = options;\n\n const apiKey = getApiKey();\n if (!apiKey) {\n throw new TightknitApiError(\n 'No API key configured. Run: tightknit config set api-key <YOUR_KEY>',\n 401\n );\n }\n\n const headers: Record<string, string> = {\n Authorization: `Bearer ${apiKey}`,\n \"Content-Type\": \"application/json\",\n };\n\n if (idempotencyKey && (method === \"POST\" || method === \"PATCH\")) {\n headers[\"Idempotency-Key\"] = idempotencyKey;\n }\n\n const url = buildUrl(path, params);\n\n const response = await fetch(url, {\n method,\n headers,\n body: body ? JSON.stringify(body) : undefined,\n });\n\n if (!response.ok) {\n const apiError = await parseErrorResponse(response);\n throw new TightknitApiError(apiError.message, apiError.code);\n }\n\n if (response.status === 204) {\n return undefined as T;\n }\n\n return (await response.json()) as T;\n}\n\n/** Custom error class for Tightknit API errors */\nexport class TightknitApiError extends Error {\n code: number;\n\n constructor(message: string, code: number) {\n super(message);\n this.name = \"TightknitApiError\";\n this.code = code;\n }\n\n toJSON(): ApiError {\n return {\n error: true,\n code: this.code,\n message: this.message,\n };\n }\n}\n\n// --- Calendar Events ---\n// Paths use underscores: /calendar_events\n\nexport interface ListEventsParams {\n page?: number;\n per_page?: number;\n time_filter?: \"upcoming\" | \"past\";\n date_filter?: string;\n status?: \"draft\" | \"needs_approval\" | \"published\";\n published_to_site?: boolean;\n is_unlisted?: boolean;\n feed_id?: string;\n tag_ids?: string;\n}\n\n/**\n * List calendar events with optional filtering and pagination.\n * @param params - Optional filters for time, status, feed, pagination, etc.\n * @returns Paginated list of calendar events.\n */\nexport async function listEvents(params?: ListEventsParams) {\n return apiRequest<{ data: unknown[]; page: number; per_page: number }>(\n \"/calendar_events\",\n { params: params as Record<string, string | number | boolean | undefined> }\n );\n}\n\nexport interface CreateEventInput {\n title: string;\n description: string;\n start_date: string;\n end_date: string;\n location?: string;\n link?: string;\n status?: \"needs_approval\" | \"published\";\n slug?: string;\n publish_to_site?: boolean;\n is_unlisted?: boolean;\n allow_public_guest_list?: boolean;\n enable_registration_button?: boolean;\n triggers_webhooks?: boolean;\n external_speakers?: string;\n cover_image_file_id?: string;\n reminders_config?: number[];\n publish_to_slack_channels?: string[];\n}\n\n/**\n * Create a new calendar event.\n * @param input - Event details including title, dates, and optional settings.\n * @returns The created event's ID and success status.\n */\nexport async function createEvent(input: CreateEventInput) {\n const { description, ...rest } = input;\n return apiRequest<{ success: boolean; data: { calendar_event_id: string } }>(\"/calendar_events\", {\n method: \"POST\",\n body: { ...rest, description: { text: description } },\n idempotencyKey: crypto.randomUUID(),\n });\n}\n\n/**\n * Get a single calendar event by ID.\n * @param id - The calendar event ID.\n * @returns The calendar event details.\n */\nexport async function getEvent(id: string) {\n return apiRequest<unknown>(`/calendar_events/${id}`);\n}\n\n/**\n * Delete a calendar event by ID.\n * @param id - The calendar event ID.\n * @returns void on success (204 response).\n */\nexport async function deleteEvent(id: string) {\n return apiRequest<void>(`/calendar_events/${id}`, { method: \"DELETE\" });\n}\n\nexport interface UpdateAttendeeInput {\n user: { slack_user_id: string } | { email: string } | { profile_id: string };\n personal_join_link?: string;\n}\n\n/**\n * Update or add an attendee for a calendar event.\n * @param eventId - The calendar event ID.\n * @param input - Attendee user identifier and optional join link.\n * @returns The updated attendee details.\n */\nexport async function updateAttendee(eventId: string, input: UpdateAttendeeInput) {\n return apiRequest<unknown>(`/calendar_events/${eventId}/attendees`, {\n method: \"PATCH\",\n body: input as unknown as Record<string, unknown>,\n idempotencyKey: crypto.randomUUID(),\n });\n}\n\n// --- Awards ---\n\nexport interface AssignAwardInput {\n recipient: { slack_user_id: string } | { email: string } | { profile_id: string };\n sender?: { slack_user_id: string } | { email: string } | { profile_id: string } | null;\n send_anonymously?: boolean;\n}\n\n/**\n * Assign an award to a recipient.\n * @param awardId - The award ID to assign.\n * @param input - Recipient identifier and optional sender/anonymity settings.\n * @returns Success status.\n */\nexport async function assignAward(awardId: string, input: AssignAwardInput) {\n return apiRequest<{ success: boolean }>(`/awards/${awardId}/assign`, {\n method: \"POST\",\n body: input as unknown as Record<string, unknown>,\n idempotencyKey: crypto.randomUUID(),\n });\n}\n\n// --- Feeds ---\n\nexport interface ListFeedsParams {\n page?: number;\n per_page?: number;\n is_unlisted?: boolean;\n is_archived?: boolean;\n}\n\n/**\n * List feeds with optional filtering and pagination.\n * @param params - Optional filters for unlisted/archived status and pagination.\n * @returns Paginated list of feeds.\n */\nexport async function listFeeds(params?: ListFeedsParams) {\n return apiRequest<{ data: unknown[]; page: number; per_page: number }>(\n \"/feeds\",\n { params: params as Record<string, string | number | boolean | undefined> }\n );\n}\n\n/**\n * Get a single feed by ID.\n * @param feedId - The feed ID.\n * @returns The feed details.\n */\nexport async function getFeed(feedId: string) {\n return apiRequest<unknown>(`/feeds/${feedId}`);\n}\n\nexport interface ListPostsInFeedParams {\n page?: number;\n per_page?: number;\n sort?: \"oldest\" | \"newest\" | \"most-recent-activity\";\n}\n\n/**\n * List posts within a feed with optional sorting and pagination.\n * @param feedId - The feed ID to list posts from.\n * @param params - Optional sort order and pagination.\n * @returns Paginated list of posts.\n */\nexport async function listPostsInFeed(feedId: string, params?: ListPostsInFeedParams) {\n return apiRequest<{ data: unknown[]; page: number; per_page: number }>(\n `/feeds/${feedId}/posts`,\n { params: params as Record<string, string | number | boolean | undefined> }\n );\n}\n\n// --- Posts ---\n\n/**\n * Get a single post by ID.\n * @param postId - The post ID.\n * @returns The post details.\n */\nexport async function getPost(postId: string) {\n return apiRequest<unknown>(`/posts/${postId}`);\n}\n\n// --- Members ---\n\nexport interface AddMemberInput {\n email: string;\n full_name: string;\n avatar_url_original?: string;\n}\n\n/**\n * Add a new member to the community (Enterprise feature).\n * @param input - Member details including email, name, and optional avatar.\n * @returns The created member details.\n */\nexport async function addMember(input: AddMemberInput) {\n return apiRequest<unknown>(\"/members\", {\n method: \"POST\",\n body: input as unknown as Record<string, unknown>,\n idempotencyKey: crypto.randomUUID(),\n });\n}\n\n/**\n * Check if a user is a member of the community by email.\n * @param email - The email address to check.\n * @returns Membership status and details.\n */\nexport async function checkMembership(email: string) {\n return apiRequest<unknown>(\"/members/check\", {\n method: \"POST\",\n body: { email },\n });\n}\n\n// --- Groups ---\n\nexport interface AddUserToGroupInput {\n user: { slack_user_id: string } | { email: string } | { profile_id: string };\n}\n\n/**\n * Add a user to a group.\n * @param groupId - The group ID.\n * @param input - User identifier to add to the group.\n * @returns The updated group membership details.\n */\nexport async function addUserToGroup(groupId: string, input: AddUserToGroupInput) {\n return apiRequest<unknown>(`/groups/${groupId}/members`, {\n method: \"POST\",\n body: input as unknown as Record<string, unknown>,\n idempotencyKey: crypto.randomUUID(),\n });\n}\n\n// --- Messages ---\n\nexport interface SendMessageInput {\n channel: string;\n text: string;\n thread_ts?: string;\n}\n\n/**\n * Send a message to a Slack channel.\n * @param input - Channel, message text, and optional thread timestamp.\n * @returns The sent message details.\n */\nexport async function sendMessage(input: SendMessageInput) {\n return apiRequest<unknown>(\"/messages\", {\n method: \"POST\",\n body: input as unknown as Record<string, unknown>,\n idempotencyKey: crypto.randomUUID(),\n });\n}\n\n// --- Search ---\n\nexport interface SearchParams {\n q: string;\n type: \"post\" | \"comment\" | \"content_resource\";\n page?: number;\n per_page?: number;\n}\n\n/**\n * Search across community content (Beta).\n * @param params - Search query, content type, and optional pagination.\n * @returns Paginated search results.\n */\nexport async function search(params: SearchParams) {\n return apiRequest<{ data: unknown[]; page: number; per_page: number }>(\n \"/search\",\n { params: params as unknown as Record<string, string | number | boolean | undefined> }\n );\n}\n"],"mappings":"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","names":[]}
|
package/dist/cli/index.js
CHANGED
package/dist/mcp/server.js
CHANGED
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
sendMessage,
|
|
18
18
|
setConfigValue,
|
|
19
19
|
updateAttendee
|
|
20
|
-
} from "../chunk-
|
|
20
|
+
} from "../chunk-DW4LVC2F.js";
|
|
21
21
|
|
|
22
22
|
// src/mcp/server.ts
|
|
23
23
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
@@ -30,6 +30,9 @@ var UserIdentifierSchema = z.union([
|
|
|
30
30
|
z.object({ email: z.string() }),
|
|
31
31
|
z.object({ profile_id: z.string() })
|
|
32
32
|
]);
|
|
33
|
+
var READ_ONLY = { readOnlyHint: true, destructiveHint: false };
|
|
34
|
+
var WRITE = { readOnlyHint: false, destructiveHint: false };
|
|
35
|
+
var DESTRUCTIVE = { readOnlyHint: false, destructiveHint: true };
|
|
33
36
|
function registerTools(server2) {
|
|
34
37
|
server2.tool(
|
|
35
38
|
"list_events",
|
|
@@ -42,6 +45,7 @@ function registerTools(server2) {
|
|
|
42
45
|
feed_id: z.string().optional().describe("Filter by feed ID"),
|
|
43
46
|
tag_ids: z.string().optional().describe("Comma-separated tag UUIDs")
|
|
44
47
|
},
|
|
48
|
+
READ_ONLY,
|
|
45
49
|
async (params) => {
|
|
46
50
|
const result = await listEvents(params);
|
|
47
51
|
return {
|
|
@@ -55,6 +59,7 @@ function registerTools(server2) {
|
|
|
55
59
|
"get_event",
|
|
56
60
|
"Retrieve a calendar event by ID",
|
|
57
61
|
{ id: z.string().describe("Calendar event ID") },
|
|
62
|
+
READ_ONLY,
|
|
58
63
|
async ({ id }) => {
|
|
59
64
|
const result = await getEvent(id);
|
|
60
65
|
return {
|
|
@@ -66,20 +71,21 @@ function registerTools(server2) {
|
|
|
66
71
|
);
|
|
67
72
|
server2.tool(
|
|
68
73
|
"create_event",
|
|
69
|
-
|
|
74
|
+
'Create a new calendar event. IMPORTANT: You must provide either a "link" or "location" (or both).',
|
|
70
75
|
{
|
|
71
76
|
title: z.string().describe("Event title (3-70 chars)"),
|
|
72
|
-
description: z.string().describe("Event description"),
|
|
73
|
-
start_date: z.string().describe("Start date/time (ISO 8601)"),
|
|
74
|
-
end_date: z.string().describe("End date/time (ISO 8601)"),
|
|
75
|
-
location: z.string().optional().describe(
|
|
76
|
-
link: z.string().optional().describe(
|
|
77
|
-
slug: z.string().optional().describe("URL slug"),
|
|
78
|
-
status: z.enum(["needs_approval", "published"]).optional().describe("Event status"),
|
|
79
|
-
publish_to_site: z.boolean().optional().describe("Publish to companion site"),
|
|
77
|
+
description: z.string().describe("Event description (plain text)"),
|
|
78
|
+
start_date: z.string().describe("Start date/time (ISO 8601 with timezone, e.g. 2026-04-10T16:00:00-04:00)"),
|
|
79
|
+
end_date: z.string().describe("End date/time (ISO 8601 with timezone, e.g. 2026-04-10T17:00:00-04:00)"),
|
|
80
|
+
location: z.string().optional().describe('Event location/address. At least one of "link" or "location" is required.'),
|
|
81
|
+
link: z.string().optional().describe('Event link/URL (e.g. Zoom/Meet link). At least one of "link" or "location" is required.'),
|
|
82
|
+
slug: z.string().optional().describe("URL slug (3-70 chars, auto-generated if omitted)"),
|
|
83
|
+
status: z.enum(["needs_approval", "published"]).optional().describe("Event status (defaults to published)"),
|
|
84
|
+
publish_to_site: z.boolean().optional().describe("Publish to companion site (defaults to true)"),
|
|
80
85
|
enable_registration_button: z.boolean().optional().describe("Enable registration button"),
|
|
81
86
|
triggers_webhooks: z.boolean().optional().describe("Trigger webhooks")
|
|
82
87
|
},
|
|
88
|
+
WRITE,
|
|
83
89
|
async (input) => {
|
|
84
90
|
const result = await createEvent(input);
|
|
85
91
|
return {
|
|
@@ -93,6 +99,7 @@ function registerTools(server2) {
|
|
|
93
99
|
"delete_event",
|
|
94
100
|
"Delete a calendar event by ID",
|
|
95
101
|
{ id: z.string().describe("Calendar event ID") },
|
|
102
|
+
DESTRUCTIVE,
|
|
96
103
|
async ({ id }) => {
|
|
97
104
|
await deleteEvent(id);
|
|
98
105
|
return {
|
|
@@ -113,8 +120,9 @@ function registerTools(server2) {
|
|
|
113
120
|
user: UserIdentifierSchema.describe(
|
|
114
121
|
"User identifier (email, slack_user_id, or profile_id)"
|
|
115
122
|
),
|
|
116
|
-
personal_join_link: z.string().optional().describe("Personal join link for the attendee")
|
|
123
|
+
personal_join_link: z.string().optional().describe("Personal join link URL for the attendee (must be a valid URL)")
|
|
117
124
|
},
|
|
125
|
+
WRITE,
|
|
118
126
|
async ({ event_id, user, personal_join_link }) => {
|
|
119
127
|
const result = await updateAttendee(event_id, {
|
|
120
128
|
user,
|
|
@@ -138,6 +146,7 @@ function registerTools(server2) {
|
|
|
138
146
|
),
|
|
139
147
|
send_anonymously: z.boolean().optional().describe("Send anonymously")
|
|
140
148
|
},
|
|
149
|
+
WRITE,
|
|
141
150
|
async ({ award_id, recipient, sender, send_anonymously }) => {
|
|
142
151
|
const result = await assignAward(award_id, {
|
|
143
152
|
recipient,
|
|
@@ -160,6 +169,7 @@ function registerTools(server2) {
|
|
|
160
169
|
is_unlisted: z.boolean().optional().describe("Filter to unlisted feeds"),
|
|
161
170
|
is_archived: z.boolean().optional().describe("Filter to archived feeds")
|
|
162
171
|
},
|
|
172
|
+
READ_ONLY,
|
|
163
173
|
async (params) => {
|
|
164
174
|
const result = await listFeeds(params);
|
|
165
175
|
return {
|
|
@@ -173,6 +183,7 @@ function registerTools(server2) {
|
|
|
173
183
|
"get_feed",
|
|
174
184
|
"Retrieve a feed by ID",
|
|
175
185
|
{ feed_id: z.string().describe("Feed ID") },
|
|
186
|
+
READ_ONLY,
|
|
176
187
|
async ({ feed_id }) => {
|
|
177
188
|
const result = await getFeed(feed_id);
|
|
178
189
|
return {
|
|
@@ -191,6 +202,7 @@ function registerTools(server2) {
|
|
|
191
202
|
per_page: z.number().optional().describe("Records per page"),
|
|
192
203
|
sort: z.enum(["oldest", "newest", "most-recent-activity"]).optional().describe("Sort method")
|
|
193
204
|
},
|
|
205
|
+
READ_ONLY,
|
|
194
206
|
async ({ feed_id, ...params }) => {
|
|
195
207
|
const result = await listPostsInFeed(feed_id, params);
|
|
196
208
|
return {
|
|
@@ -204,6 +216,7 @@ function registerTools(server2) {
|
|
|
204
216
|
"get_post",
|
|
205
217
|
"Retrieve a post by ID",
|
|
206
218
|
{ post_id: z.string().describe("Post ID") },
|
|
219
|
+
READ_ONLY,
|
|
207
220
|
async ({ post_id }) => {
|
|
208
221
|
const result = await getPost(post_id);
|
|
209
222
|
return {
|
|
@@ -221,6 +234,7 @@ function registerTools(server2) {
|
|
|
221
234
|
full_name: z.string().describe("Member full name"),
|
|
222
235
|
avatar_url_original: z.string().optional().describe("Avatar image URL")
|
|
223
236
|
},
|
|
237
|
+
WRITE,
|
|
224
238
|
async (input) => {
|
|
225
239
|
const result = await addMember(input);
|
|
226
240
|
return {
|
|
@@ -234,6 +248,7 @@ function registerTools(server2) {
|
|
|
234
248
|
"check_membership",
|
|
235
249
|
"Check if an email is a community member",
|
|
236
250
|
{ email: z.string().describe("Email address to check") },
|
|
251
|
+
READ_ONLY,
|
|
237
252
|
async ({ email }) => {
|
|
238
253
|
const result = await checkMembership(email);
|
|
239
254
|
return {
|
|
@@ -251,6 +266,7 @@ function registerTools(server2) {
|
|
|
251
266
|
text: z.string().describe("Message text (plain text or Slack mrkdwn)"),
|
|
252
267
|
thread_ts: z.string().optional().describe("Thread timestamp to reply to")
|
|
253
268
|
},
|
|
269
|
+
WRITE,
|
|
254
270
|
async (input) => {
|
|
255
271
|
const result = await sendMessage(input);
|
|
256
272
|
return {
|
|
@@ -267,6 +283,7 @@ function registerTools(server2) {
|
|
|
267
283
|
group_id: z.string().describe("Group ID"),
|
|
268
284
|
user: UserIdentifierSchema.describe("User identifier")
|
|
269
285
|
},
|
|
286
|
+
WRITE,
|
|
270
287
|
async ({ group_id, user }) => {
|
|
271
288
|
const result = await addUserToGroup(group_id, { user });
|
|
272
289
|
return {
|
|
@@ -285,6 +302,7 @@ function registerTools(server2) {
|
|
|
285
302
|
page: z.number().optional().describe("Page number (0-indexed)"),
|
|
286
303
|
per_page: z.number().optional().describe("Records per page")
|
|
287
304
|
},
|
|
305
|
+
READ_ONLY,
|
|
288
306
|
async (params) => {
|
|
289
307
|
const result = await search(params);
|
|
290
308
|
return {
|
|
@@ -298,6 +316,7 @@ function registerTools(server2) {
|
|
|
298
316
|
"get_config",
|
|
299
317
|
"Get a CLI configuration value",
|
|
300
318
|
{ key: z.string().describe("Config key (api-key, default-output, environment)") },
|
|
319
|
+
READ_ONLY,
|
|
301
320
|
async ({ key }) => {
|
|
302
321
|
const value = getConfigValue(key);
|
|
303
322
|
const displayValue = key === "api-key" && value ? `${value.slice(0, 8)}...` : value;
|
|
@@ -318,6 +337,7 @@ function registerTools(server2) {
|
|
|
318
337
|
key: z.string().describe("Config key (api-key, default-output)"),
|
|
319
338
|
value: z.string().describe("Config value")
|
|
320
339
|
},
|
|
340
|
+
WRITE,
|
|
321
341
|
async ({ key, value }) => {
|
|
322
342
|
setConfigValue(key, value);
|
|
323
343
|
return {
|
package/dist/mcp/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/mcp/server.ts","../../src/mcp/tools.ts"],"sourcesContent":["import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport { VERSION } from '../core/version';\nimport { registerTools } from './tools';\n\nconst server = new McpServer({\n name: 'tightknit',\n version: VERSION,\n});\n\nregisterTools(server);\n\nconst transport = new StdioServerTransport();\nawait server.connect(transport);\n","import { z } from 'zod';\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport {\n listEvents,\n getEvent,\n createEvent,\n deleteEvent,\n updateAttendee,\n assignAward,\n listFeeds,\n getFeed,\n listPostsInFeed,\n getPost,\n addMember,\n checkMembership,\n sendMessage,\n addUserToGroup,\n search\n} from '../core/client';\nimport { getConfigValue, setConfigValue } from '../core/config';\n\nconst UserIdentifierSchema = z.union([\n z.object({ slack_user_id: z.string() }),\n z.object({ email: z.string() }),\n z.object({ profile_id: z.string() })\n]);\n\n/** Register all Tightknit tools on the MCP server */\nexport function registerTools(server: McpServer): void {\n // --- Calendar Events ---\n\n server.tool(\n 'list_events',\n 'List calendar events with pagination and filters',\n {\n page: z.number().optional().describe('Page number (0-indexed)'),\n per_page: z.number().optional().describe('Records per page'),\n time_filter: z\n .enum(['upcoming', 'past'])\n .optional()\n .describe('Filter by upcoming or past'),\n status: z\n .enum(['draft', 'needs_approval', 'published'])\n .optional()\n .describe('Filter by status'),\n feed_id: z.string().optional().describe('Filter by feed ID'),\n tag_ids: z.string().optional().describe('Comma-separated tag UUIDs')\n },\n async (params) => {\n const result = await listEvents(params);\n return {\n content: [\n { type: 'text' as const, text: JSON.stringify(result, null, 2) }\n ]\n };\n }\n );\n\n server.tool(\n 'get_event',\n 'Retrieve a calendar event by ID',\n { id: z.string().describe('Calendar event ID') },\n async ({ id }) => {\n const result = await getEvent(id);\n return {\n content: [\n { type: 'text' as const, text: JSON.stringify(result, null, 2) }\n ]\n };\n }\n );\n\n server.tool(\n 'create_event',\n 'Create a new calendar event',\n {\n title: z.string().describe('Event title (3-70 chars)'),\n description: z.string().describe('Event description'),\n start_date: z.string().describe('Start date/time (ISO 8601)'),\n end_date: z.string().describe('End date/time (ISO 8601)'),\n location: z.string().optional().describe('Event location'),\n link: z.string().optional().describe('Event link/URL'),\n slug: z.string().optional().describe('URL slug'),\n status: z\n .enum(['needs_approval', 'published'])\n .optional()\n .describe('Event status'),\n publish_to_site: z\n .boolean()\n .optional()\n .describe('Publish to companion site'),\n enable_registration_button: z\n .boolean()\n .optional()\n .describe('Enable registration button'),\n triggers_webhooks: z.boolean().optional().describe('Trigger webhooks')\n },\n async (input) => {\n const result = await createEvent(input);\n return {\n content: [\n { type: 'text' as const, text: JSON.stringify(result, null, 2) }\n ]\n };\n }\n );\n\n server.tool(\n 'delete_event',\n 'Delete a calendar event by ID',\n { id: z.string().describe('Calendar event ID') },\n async ({ id }) => {\n await deleteEvent(id);\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify({ success: true }, null, 2)\n }\n ]\n };\n }\n );\n\n server.tool(\n 'update_event_attendee',\n 'Update a calendar event attendee',\n {\n event_id: z.string().describe('Calendar event ID'),\n user: UserIdentifierSchema.describe(\n 'User identifier (email, slack_user_id, or profile_id)'\n ),\n personal_join_link: z\n .string()\n .optional()\n .describe('Personal join link for the attendee')\n },\n async ({ event_id, user, personal_join_link }) => {\n const result = await updateAttendee(event_id, {\n user,\n personal_join_link\n });\n return {\n content: [\n { type: 'text' as const, text: JSON.stringify(result, null, 2) }\n ]\n };\n }\n );\n\n // --- Awards ---\n\n server.tool(\n 'assign_award',\n 'Assign an award to a user and send a Slack notification',\n {\n award_id: z.string().describe('Award UUID'),\n recipient: UserIdentifierSchema.describe('Recipient user identifier'),\n sender: UserIdentifierSchema.optional().describe(\n 'Sender user identifier'\n ),\n send_anonymously: z.boolean().optional().describe('Send anonymously')\n },\n async ({ award_id, recipient, sender, send_anonymously }) => {\n const result = await assignAward(award_id, {\n recipient,\n sender,\n send_anonymously\n });\n return {\n content: [\n { type: 'text' as const, text: JSON.stringify(result, null, 2) }\n ]\n };\n }\n );\n\n // --- Feeds ---\n\n server.tool(\n 'list_feeds',\n 'List feeds with pagination',\n {\n page: z.number().optional().describe('Page number (0-indexed)'),\n per_page: z.number().optional().describe('Records per page'),\n is_unlisted: z.boolean().optional().describe('Filter to unlisted feeds'),\n is_archived: z.boolean().optional().describe('Filter to archived feeds')\n },\n async (params) => {\n const result = await listFeeds(params);\n return {\n content: [\n { type: 'text' as const, text: JSON.stringify(result, null, 2) }\n ]\n };\n }\n );\n\n server.tool(\n 'get_feed',\n 'Retrieve a feed by ID',\n { feed_id: z.string().describe('Feed ID') },\n async ({ feed_id }) => {\n const result = await getFeed(feed_id);\n return {\n content: [\n { type: 'text' as const, text: JSON.stringify(result, null, 2) }\n ]\n };\n }\n );\n\n server.tool(\n 'list_feed_posts',\n 'List posts in a feed',\n {\n feed_id: z.string().describe('Feed ID or \"home\" for the Home feed'),\n page: z.number().optional().describe('Page number (0-indexed)'),\n per_page: z.number().optional().describe('Records per page'),\n sort: z\n .enum(['oldest', 'newest', 'most-recent-activity'])\n .optional()\n .describe('Sort method')\n },\n async ({ feed_id, ...params }) => {\n const result = await listPostsInFeed(feed_id, params);\n return {\n content: [\n { type: 'text' as const, text: JSON.stringify(result, null, 2) }\n ]\n };\n }\n );\n\n // --- Posts ---\n\n server.tool(\n 'get_post',\n 'Retrieve a post by ID',\n { post_id: z.string().describe('Post ID') },\n async ({ post_id }) => {\n const result = await getPost(post_id);\n return {\n content: [\n { type: 'text' as const, text: JSON.stringify(result, null, 2) }\n ]\n };\n }\n );\n\n // --- Members ---\n\n server.tool(\n 'add_member',\n 'Add a member to the community (Enterprise plan required)',\n {\n email: z.string().describe('Member email address'),\n full_name: z.string().describe('Member full name'),\n avatar_url_original: z.string().optional().describe('Avatar image URL')\n },\n async (input) => {\n const result = await addMember(input);\n return {\n content: [\n { type: 'text' as const, text: JSON.stringify(result, null, 2) }\n ]\n };\n }\n );\n\n server.tool(\n 'check_membership',\n 'Check if an email is a community member',\n { email: z.string().describe('Email address to check') },\n async ({ email }) => {\n const result = await checkMembership(email);\n return {\n content: [\n { type: 'text' as const, text: JSON.stringify(result, null, 2) }\n ]\n };\n }\n );\n\n // --- Messages ---\n\n server.tool(\n 'send_message',\n 'Send a Slack message to a channel or user',\n {\n channel: z.string().describe('Slack channel ID or user ID'),\n text: z.string().describe('Message text (plain text or Slack mrkdwn)'),\n thread_ts: z.string().optional().describe('Thread timestamp to reply to')\n },\n async (input) => {\n const result = await sendMessage(input);\n return {\n content: [\n { type: 'text' as const, text: JSON.stringify(result, null, 2) }\n ]\n };\n }\n );\n\n // --- Groups ---\n\n server.tool(\n 'add_group_member',\n 'Add a user to a group',\n {\n group_id: z.string().describe('Group ID'),\n user: UserIdentifierSchema.describe('User identifier')\n },\n async ({ group_id, user }) => {\n const result = await addUserToGroup(group_id, { user });\n return {\n content: [\n { type: 'text' as const, text: JSON.stringify(result, null, 2) }\n ]\n };\n }\n );\n\n // --- Search ---\n\n server.tool(\n 'search',\n '[Beta] Search documents by query',\n {\n q: z.string().describe('Search query string'),\n type: z\n .enum(['post', 'comment', 'content_resource'])\n .describe('Entity type to search'),\n page: z.number().optional().describe('Page number (0-indexed)'),\n per_page: z.number().optional().describe('Records per page')\n },\n async (params) => {\n const result = await search(params);\n return {\n content: [\n { type: 'text' as const, text: JSON.stringify(result, null, 2) }\n ]\n };\n }\n );\n\n // --- Config ---\n\n server.tool(\n 'get_config',\n 'Get a CLI configuration value',\n { key: z.string().describe('Config key (api-key, default-output, environment)') },\n async ({ key }) => {\n const value = getConfigValue(key);\n const displayValue =\n key === 'api-key' && value ? `${value.slice(0, 8)}...` : value;\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify({ key, value: displayValue }, null, 2)\n }\n ]\n };\n }\n );\n\n server.tool(\n 'set_config',\n 'Set a CLI configuration value',\n {\n key: z.string().describe('Config key (api-key, default-output)'),\n value: z.string().describe('Config value')\n },\n async ({ key, value }) => {\n setConfigValue(key, value);\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify(\n { success: true, key, value: key === 'api-key' ? '***' : value },\n null,\n 2\n )\n }\n ]\n };\n }\n );\n}\n"],"mappings":"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","names":["server"]}
|
|
1
|
+
{"version":3,"sources":["../../src/mcp/server.ts","../../src/mcp/tools.ts"],"sourcesContent":["import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport { VERSION } from '../core/version';\nimport { registerTools } from './tools';\n\nconst server = new McpServer({\n name: 'tightknit',\n version: VERSION,\n});\n\nregisterTools(server);\n\nconst transport = new StdioServerTransport();\nawait server.connect(transport);\n","import { z } from 'zod';\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport {\n listEvents,\n getEvent,\n createEvent,\n deleteEvent,\n updateAttendee,\n assignAward,\n listFeeds,\n getFeed,\n listPostsInFeed,\n getPost,\n addMember,\n checkMembership,\n sendMessage,\n addUserToGroup,\n search\n} from '../core/client';\nimport { getConfigValue, setConfigValue } from '../core/config';\n\nconst UserIdentifierSchema = z.union([\n z.object({ slack_user_id: z.string() }),\n z.object({ email: z.string() }),\n z.object({ profile_id: z.string() })\n]);\n\nconst READ_ONLY = { readOnlyHint: true, destructiveHint: false } as const;\nconst WRITE = { readOnlyHint: false, destructiveHint: false } as const;\nconst DESTRUCTIVE = { readOnlyHint: false, destructiveHint: true } as const;\n\n/** Register all Tightknit tools on the MCP server */\nexport function registerTools(server: McpServer): void {\n // --- Calendar Events ---\n\n server.tool(\n 'list_events',\n 'List calendar events with pagination and filters',\n {\n page: z.number().optional().describe('Page number (0-indexed)'),\n per_page: z.number().optional().describe('Records per page'),\n time_filter: z\n .enum(['upcoming', 'past'])\n .optional()\n .describe('Filter by upcoming or past'),\n status: z\n .enum(['draft', 'needs_approval', 'published'])\n .optional()\n .describe('Filter by status'),\n feed_id: z.string().optional().describe('Filter by feed ID'),\n tag_ids: z.string().optional().describe('Comma-separated tag UUIDs')\n },\n READ_ONLY,\n async (params) => {\n const result = await listEvents(params);\n return {\n content: [\n { type: 'text' as const, text: JSON.stringify(result, null, 2) }\n ]\n };\n }\n );\n\n server.tool(\n 'get_event',\n 'Retrieve a calendar event by ID',\n { id: z.string().describe('Calendar event ID') },\n READ_ONLY,\n async ({ id }) => {\n const result = await getEvent(id);\n return {\n content: [\n { type: 'text' as const, text: JSON.stringify(result, null, 2) }\n ]\n };\n }\n );\n\n server.tool(\n 'create_event',\n 'Create a new calendar event. IMPORTANT: You must provide either a \"link\" or \"location\" (or both).',\n {\n title: z.string().describe('Event title (3-70 chars)'),\n description: z.string().describe('Event description (plain text)'),\n start_date: z.string().describe('Start date/time (ISO 8601 with timezone, e.g. 2026-04-10T16:00:00-04:00)'),\n end_date: z.string().describe('End date/time (ISO 8601 with timezone, e.g. 2026-04-10T17:00:00-04:00)'),\n location: z.string().optional().describe('Event location/address. At least one of \"link\" or \"location\" is required.'),\n link: z.string().optional().describe('Event link/URL (e.g. Zoom/Meet link). At least one of \"link\" or \"location\" is required.'),\n slug: z.string().optional().describe('URL slug (3-70 chars, auto-generated if omitted)'),\n status: z\n .enum(['needs_approval', 'published'])\n .optional()\n .describe('Event status (defaults to published)'),\n publish_to_site: z\n .boolean()\n .optional()\n .describe('Publish to companion site (defaults to true)'),\n enable_registration_button: z\n .boolean()\n .optional()\n .describe('Enable registration button'),\n triggers_webhooks: z.boolean().optional().describe('Trigger webhooks')\n },\n WRITE,\n async (input) => {\n const result = await createEvent(input);\n return {\n content: [\n { type: 'text' as const, text: JSON.stringify(result, null, 2) }\n ]\n };\n }\n );\n\n server.tool(\n 'delete_event',\n 'Delete a calendar event by ID',\n { id: z.string().describe('Calendar event ID') },\n DESTRUCTIVE,\n async ({ id }) => {\n await deleteEvent(id);\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify({ success: true }, null, 2)\n }\n ]\n };\n }\n );\n\n server.tool(\n 'update_event_attendee',\n 'Update a calendar event attendee',\n {\n event_id: z.string().describe('Calendar event ID'),\n user: UserIdentifierSchema.describe(\n 'User identifier (email, slack_user_id, or profile_id)'\n ),\n personal_join_link: z\n .string()\n .optional()\n .describe('Personal join link URL for the attendee (must be a valid URL)')\n },\n WRITE,\n async ({ event_id, user, personal_join_link }) => {\n const result = await updateAttendee(event_id, {\n user,\n personal_join_link\n });\n return {\n content: [\n { type: 'text' as const, text: JSON.stringify(result, null, 2) }\n ]\n };\n }\n );\n\n // --- Awards ---\n\n server.tool(\n 'assign_award',\n 'Assign an award to a user and send a Slack notification',\n {\n award_id: z.string().describe('Award UUID'),\n recipient: UserIdentifierSchema.describe('Recipient user identifier'),\n sender: UserIdentifierSchema.optional().describe(\n 'Sender user identifier'\n ),\n send_anonymously: z.boolean().optional().describe('Send anonymously')\n },\n WRITE,\n async ({ award_id, recipient, sender, send_anonymously }) => {\n const result = await assignAward(award_id, {\n recipient,\n sender,\n send_anonymously\n });\n return {\n content: [\n { type: 'text' as const, text: JSON.stringify(result, null, 2) }\n ]\n };\n }\n );\n\n // --- Feeds ---\n\n server.tool(\n 'list_feeds',\n 'List feeds with pagination',\n {\n page: z.number().optional().describe('Page number (0-indexed)'),\n per_page: z.number().optional().describe('Records per page'),\n is_unlisted: z.boolean().optional().describe('Filter to unlisted feeds'),\n is_archived: z.boolean().optional().describe('Filter to archived feeds')\n },\n READ_ONLY,\n async (params) => {\n const result = await listFeeds(params);\n return {\n content: [\n { type: 'text' as const, text: JSON.stringify(result, null, 2) }\n ]\n };\n }\n );\n\n server.tool(\n 'get_feed',\n 'Retrieve a feed by ID',\n { feed_id: z.string().describe('Feed ID') },\n READ_ONLY,\n async ({ feed_id }) => {\n const result = await getFeed(feed_id);\n return {\n content: [\n { type: 'text' as const, text: JSON.stringify(result, null, 2) }\n ]\n };\n }\n );\n\n server.tool(\n 'list_feed_posts',\n 'List posts in a feed',\n {\n feed_id: z.string().describe('Feed ID or \"home\" for the Home feed'),\n page: z.number().optional().describe('Page number (0-indexed)'),\n per_page: z.number().optional().describe('Records per page'),\n sort: z\n .enum(['oldest', 'newest', 'most-recent-activity'])\n .optional()\n .describe('Sort method')\n },\n READ_ONLY,\n async ({ feed_id, ...params }) => {\n const result = await listPostsInFeed(feed_id, params);\n return {\n content: [\n { type: 'text' as const, text: JSON.stringify(result, null, 2) }\n ]\n };\n }\n );\n\n // --- Posts ---\n\n server.tool(\n 'get_post',\n 'Retrieve a post by ID',\n { post_id: z.string().describe('Post ID') },\n READ_ONLY,\n async ({ post_id }) => {\n const result = await getPost(post_id);\n return {\n content: [\n { type: 'text' as const, text: JSON.stringify(result, null, 2) }\n ]\n };\n }\n );\n\n // --- Members ---\n\n server.tool(\n 'add_member',\n 'Add a member to the community (Enterprise plan required)',\n {\n email: z.string().describe('Member email address'),\n full_name: z.string().describe('Member full name'),\n avatar_url_original: z.string().optional().describe('Avatar image URL')\n },\n WRITE,\n async (input) => {\n const result = await addMember(input);\n return {\n content: [\n { type: 'text' as const, text: JSON.stringify(result, null, 2) }\n ]\n };\n }\n );\n\n server.tool(\n 'check_membership',\n 'Check if an email is a community member',\n { email: z.string().describe('Email address to check') },\n READ_ONLY,\n async ({ email }) => {\n const result = await checkMembership(email);\n return {\n content: [\n { type: 'text' as const, text: JSON.stringify(result, null, 2) }\n ]\n };\n }\n );\n\n // --- Messages ---\n\n server.tool(\n 'send_message',\n 'Send a Slack message to a channel or user',\n {\n channel: z.string().describe('Slack channel ID or user ID'),\n text: z.string().describe('Message text (plain text or Slack mrkdwn)'),\n thread_ts: z.string().optional().describe('Thread timestamp to reply to')\n },\n WRITE,\n async (input) => {\n const result = await sendMessage(input);\n return {\n content: [\n { type: 'text' as const, text: JSON.stringify(result, null, 2) }\n ]\n };\n }\n );\n\n // --- Groups ---\n\n server.tool(\n 'add_group_member',\n 'Add a user to a group',\n {\n group_id: z.string().describe('Group ID'),\n user: UserIdentifierSchema.describe('User identifier')\n },\n WRITE,\n async ({ group_id, user }) => {\n const result = await addUserToGroup(group_id, { user });\n return {\n content: [\n { type: 'text' as const, text: JSON.stringify(result, null, 2) }\n ]\n };\n }\n );\n\n // --- Search ---\n\n server.tool(\n 'search',\n '[Beta] Search documents by query',\n {\n q: z.string().describe('Search query string'),\n type: z\n .enum(['post', 'comment', 'content_resource'])\n .describe('Entity type to search'),\n page: z.number().optional().describe('Page number (0-indexed)'),\n per_page: z.number().optional().describe('Records per page')\n },\n READ_ONLY,\n async (params) => {\n const result = await search(params);\n return {\n content: [\n { type: 'text' as const, text: JSON.stringify(result, null, 2) }\n ]\n };\n }\n );\n\n // --- Config ---\n\n server.tool(\n 'get_config',\n 'Get a CLI configuration value',\n { key: z.string().describe('Config key (api-key, default-output, environment)') },\n READ_ONLY,\n async ({ key }) => {\n const value = getConfigValue(key);\n const displayValue =\n key === 'api-key' && value ? `${value.slice(0, 8)}...` : value;\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify({ key, value: displayValue }, null, 2)\n }\n ]\n };\n }\n );\n\n server.tool(\n 'set_config',\n 'Set a CLI configuration value',\n {\n key: z.string().describe('Config key (api-key, default-output)'),\n value: z.string().describe('Config value')\n },\n WRITE,\n async ({ key, value }) => {\n setConfigValue(key, value);\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify(\n { success: true, key, value: key === 'api-key' ? '***' : value },\n null,\n 2\n )\n }\n ]\n };\n }\n );\n}\n"],"mappings":"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","names":["server"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tightknitai/tightknit",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.8",
|
|
4
4
|
"description": "CLI and MCP server for the Tightknit API",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -34,6 +34,8 @@
|
|
|
34
34
|
"test": "vitest run",
|
|
35
35
|
"test:unit": "vitest run",
|
|
36
36
|
"test:unit-silent": "vitest run --reporter=dot",
|
|
37
|
+
"test:mcp": "npx @modelcontextprotocol/inspector node bin/tightknit-mcp.js",
|
|
38
|
+
"test:mcp:dev": "npx @modelcontextprotocol/inspector tsx src/mcp/server.ts",
|
|
37
39
|
"typecheck": "tsc --noEmit"
|
|
38
40
|
},
|
|
39
41
|
"dependencies": {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/core/config.ts","../src/core/version.ts","../src/core/client.ts"],"sourcesContent":["import Conf from \"conf\";\n\nexport type Environment = \"production\" | \"staging\";\n\ninterface TightknitConfig {\n apiKey: string;\n defaultOutput: \"json\" | \"table\";\n environment: Environment;\n}\n\nconst config = new Conf<TightknitConfig>({\n projectName: \"tightknit\",\n defaults: {\n apiKey: \"\",\n defaultOutput: \"table\",\n environment: \"production\",\n },\n});\n\n/** Runtime API key set via --api-key flag (highest precedence) */\nlet runtimeApiKey: string | undefined;\n\n/** Set a runtime API key (from --api-key flag). Takes highest precedence. */\nexport function setRuntimeApiKey(key: string | undefined): void {\n runtimeApiKey = key;\n}\n\n/** Get the API key — --api-key flag > env var > stored config */\nexport function getApiKey(): string {\n return runtimeApiKey || process.env.TIGHTKNIT_API_KEY || config.get(\"apiKey\");\n}\n\n/** Set the API key */\nexport function setApiKey(key: string): void {\n config.set(\"apiKey\", key);\n}\n\n/** Get the default output format */\nexport function getDefaultOutput(): \"json\" | \"table\" {\n return config.get(\"defaultOutput\");\n}\n\n/** Set the default output format */\nexport function setDefaultOutput(format: \"json\" | \"table\"): void {\n config.set(\"defaultOutput\", format);\n}\n\n/** Get the configured environment */\nexport function getEnvironment(): Environment {\n return (process.env.TIGHTKNIT_ENVIRONMENT as Environment) || config.get(\"environment\");\n}\n\n/** Set the environment */\nexport function setEnvironment(env: Environment): void {\n config.set(\"environment\", env);\n}\n\nconst VALID_CONFIG_KEYS = \"api-key, default-output, environment\";\n\n/** Get a config value by key name */\nexport function getConfigValue(key: string): string {\n switch (key) {\n case \"api-key\":\n return getApiKey();\n case \"default-output\":\n return getDefaultOutput();\n case \"environment\":\n return getEnvironment();\n default:\n throw new Error(`Unknown config key: ${key}. Valid keys: ${VALID_CONFIG_KEYS}`);\n }\n}\n\n/** Set a config value by key name */\nexport function setConfigValue(key: string, value: string): void {\n switch (key) {\n case \"api-key\":\n setApiKey(value);\n break;\n case \"default-output\":\n if (value !== \"json\" && value !== \"table\") {\n throw new Error(`Invalid output format: ${value}. Must be \"json\" or \"table\"`);\n }\n setDefaultOutput(value);\n break;\n case \"environment\":\n if (value !== \"production\" && value !== \"staging\") {\n throw new Error(`Invalid environment: ${value}. Must be \"production\" or \"staging\"`);\n }\n setEnvironment(value);\n break;\n default:\n throw new Error(`Unknown config key: ${key}. Valid keys: ${VALID_CONFIG_KEYS}`);\n }\n}\n\n/** Get the config file path (useful for debugging) */\nexport function getConfigPath(): string {\n return config.path;\n}\n","import { readFileSync } from 'node:fs';\nimport { fileURLToPath } from 'node:url';\nimport { dirname, join } from 'node:path';\n\n/** Walks up from the current module to find the CLI's package.json version */\nfunction readVersion(): string {\n let dir = dirname(fileURLToPath(import.meta.url));\n for (let i = 0; i < 5; i++) {\n try {\n const pkgPath = join(dir, 'package.json');\n const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8')) as {\n name?: string;\n version?: string;\n };\n if (pkg.name === '@tightknitai/tightknit') {\n return pkg.version ?? '0.0.0';\n }\n } catch {\n // continue walking up\n }\n dir = dirname(dir);\n }\n return '0.0.0';\n}\n\nexport const VERSION = readVersion();\n","import { getApiKey, getEnvironment } from \"./config\";\nimport type { ApiError } from \"./types\";\n\nconst BASE_URLS = {\n production: \"https://api.tightknit.ai\",\n staging: \"https://staging-api.tightknit.ai\",\n} as const;\n\nconst API_PREFIX = \"/admin/v0\";\n\n/** Get the base URL for the current environment */\nfunction getBaseUrl(): string {\n return BASE_URLS[getEnvironment()];\n}\n\ninterface RequestOptions {\n method?: \"GET\" | \"POST\" | \"PATCH\" | \"DELETE\";\n body?: Record<string, unknown>;\n params?: Record<string, string | number | boolean | undefined>;\n idempotencyKey?: string;\n}\n\n/** Build a URL with query parameters */\nfunction buildUrl(path: string, params?: Record<string, string | number | boolean | undefined>): string {\n const url = new URL(`${API_PREFIX}${path}`, getBaseUrl());\n if (params) {\n for (const [key, value] of Object.entries(params)) {\n if (value !== undefined) {\n url.searchParams.set(key, String(value));\n }\n }\n }\n return url.toString();\n}\n\n/** Parse an API error response into a structured error */\nasync function parseErrorResponse(response: Response): Promise<ApiError> {\n let message: string;\n try {\n const body = await response.json() as Record<string, unknown>;\n message = (body.message as string) || (body.error as string) || response.statusText;\n } catch {\n message = response.statusText;\n }\n\n return {\n error: true,\n code: response.status,\n message: `${message} (${response.status})`,\n };\n}\n\n/** Make an authenticated request to the Tightknit API */\nexport async function apiRequest<T>(path: string, options: RequestOptions = {}): Promise<T> {\n const { method = \"GET\", body, params, idempotencyKey } = options;\n\n const apiKey = getApiKey();\n if (!apiKey) {\n throw new TightknitApiError(\n 'No API key configured. Run: tightknit config set api-key <YOUR_KEY>',\n 401\n );\n }\n\n const headers: Record<string, string> = {\n Authorization: `Bearer ${apiKey}`,\n \"Content-Type\": \"application/json\",\n };\n\n if (idempotencyKey && (method === \"POST\" || method === \"PATCH\")) {\n headers[\"Idempotency-Key\"] = idempotencyKey;\n }\n\n const url = buildUrl(path, params);\n\n const response = await fetch(url, {\n method,\n headers,\n body: body ? JSON.stringify(body) : undefined,\n });\n\n if (!response.ok) {\n const apiError = await parseErrorResponse(response);\n throw new TightknitApiError(apiError.message, apiError.code);\n }\n\n if (response.status === 204) {\n return undefined as T;\n }\n\n return (await response.json()) as T;\n}\n\n/** Custom error class for Tightknit API errors */\nexport class TightknitApiError extends Error {\n code: number;\n\n constructor(message: string, code: number) {\n super(message);\n this.name = \"TightknitApiError\";\n this.code = code;\n }\n\n toJSON(): ApiError {\n return {\n error: true,\n code: this.code,\n message: this.message,\n };\n }\n}\n\n// --- Calendar Events ---\n// Paths use underscores: /calendar_events\n\nexport interface ListEventsParams {\n page?: number;\n per_page?: number;\n time_filter?: \"upcoming\" | \"past\";\n date_filter?: string;\n status?: \"draft\" | \"needs_approval\" | \"published\";\n published_to_site?: boolean;\n is_unlisted?: boolean;\n feed_id?: string;\n tag_ids?: string;\n}\n\n/**\n * List calendar events with optional filtering and pagination.\n * @param params - Optional filters for time, status, feed, pagination, etc.\n * @returns Paginated list of calendar events.\n */\nexport async function listEvents(params?: ListEventsParams) {\n return apiRequest<{ data: unknown[]; page: number; per_page: number }>(\n \"/calendar_events\",\n { params: params as Record<string, string | number | boolean | undefined> }\n );\n}\n\nexport interface CreateEventInput {\n title: string;\n description: string;\n start_date: string;\n end_date: string;\n location?: string;\n link?: string;\n status?: \"needs_approval\" | \"published\";\n slug?: string;\n publish_to_site?: boolean;\n is_unlisted?: boolean;\n allow_public_guest_list?: boolean;\n enable_registration_button?: boolean;\n triggers_webhooks?: boolean;\n external_speakers?: string;\n cover_image_file_id?: string;\n reminders_config?: number[];\n publish_to_slack_channels?: string[];\n}\n\n/**\n * Create a new calendar event.\n * @param input - Event details including title, dates, and optional settings.\n * @returns The created event's ID and success status.\n */\nexport async function createEvent(input: CreateEventInput) {\n return apiRequest<{ success: boolean; data: { calendar_event_id: string } }>(\"/calendar_events\", {\n method: \"POST\",\n body: input as unknown as Record<string, unknown>,\n idempotencyKey: crypto.randomUUID(),\n });\n}\n\n/**\n * Get a single calendar event by ID.\n * @param id - The calendar event ID.\n * @returns The calendar event details.\n */\nexport async function getEvent(id: string) {\n return apiRequest<unknown>(`/calendar_events/${id}`);\n}\n\n/**\n * Delete a calendar event by ID.\n * @param id - The calendar event ID.\n * @returns void on success (204 response).\n */\nexport async function deleteEvent(id: string) {\n return apiRequest<void>(`/calendar_events/${id}`, { method: \"DELETE\" });\n}\n\nexport interface UpdateAttendeeInput {\n user: { slack_user_id: string } | { email: string } | { profile_id: string };\n personal_join_link?: string;\n}\n\n/**\n * Update or add an attendee for a calendar event.\n * @param eventId - The calendar event ID.\n * @param input - Attendee user identifier and optional join link.\n * @returns The updated attendee details.\n */\nexport async function updateAttendee(eventId: string, input: UpdateAttendeeInput) {\n return apiRequest<unknown>(`/calendar_events/${eventId}/attendees`, {\n method: \"PATCH\",\n body: input as unknown as Record<string, unknown>,\n idempotencyKey: crypto.randomUUID(),\n });\n}\n\n// --- Awards ---\n\nexport interface AssignAwardInput {\n recipient: { slack_user_id: string } | { email: string } | { profile_id: string };\n sender?: { slack_user_id: string } | { email: string } | { profile_id: string } | null;\n send_anonymously?: boolean;\n}\n\n/**\n * Assign an award to a recipient.\n * @param awardId - The award ID to assign.\n * @param input - Recipient identifier and optional sender/anonymity settings.\n * @returns Success status.\n */\nexport async function assignAward(awardId: string, input: AssignAwardInput) {\n return apiRequest<{ success: boolean }>(`/awards/${awardId}/assign`, {\n method: \"POST\",\n body: input as unknown as Record<string, unknown>,\n idempotencyKey: crypto.randomUUID(),\n });\n}\n\n// --- Feeds ---\n\nexport interface ListFeedsParams {\n page?: number;\n per_page?: number;\n is_unlisted?: boolean;\n is_archived?: boolean;\n}\n\n/**\n * List feeds with optional filtering and pagination.\n * @param params - Optional filters for unlisted/archived status and pagination.\n * @returns Paginated list of feeds.\n */\nexport async function listFeeds(params?: ListFeedsParams) {\n return apiRequest<{ data: unknown[]; page: number; per_page: number }>(\n \"/feeds\",\n { params: params as Record<string, string | number | boolean | undefined> }\n );\n}\n\n/**\n * Get a single feed by ID.\n * @param feedId - The feed ID.\n * @returns The feed details.\n */\nexport async function getFeed(feedId: string) {\n return apiRequest<unknown>(`/feeds/${feedId}`);\n}\n\nexport interface ListPostsInFeedParams {\n page?: number;\n per_page?: number;\n sort?: \"oldest\" | \"newest\" | \"most-recent-activity\";\n}\n\n/**\n * List posts within a feed with optional sorting and pagination.\n * @param feedId - The feed ID to list posts from.\n * @param params - Optional sort order and pagination.\n * @returns Paginated list of posts.\n */\nexport async function listPostsInFeed(feedId: string, params?: ListPostsInFeedParams) {\n return apiRequest<{ data: unknown[]; page: number; per_page: number }>(\n `/feeds/${feedId}/posts`,\n { params: params as Record<string, string | number | boolean | undefined> }\n );\n}\n\n// --- Posts ---\n\n/**\n * Get a single post by ID.\n * @param postId - The post ID.\n * @returns The post details.\n */\nexport async function getPost(postId: string) {\n return apiRequest<unknown>(`/posts/${postId}`);\n}\n\n// --- Members ---\n\nexport interface AddMemberInput {\n email: string;\n full_name: string;\n avatar_url_original?: string;\n}\n\n/**\n * Add a new member to the community (Enterprise feature).\n * @param input - Member details including email, name, and optional avatar.\n * @returns The created member details.\n */\nexport async function addMember(input: AddMemberInput) {\n return apiRequest<unknown>(\"/members\", {\n method: \"POST\",\n body: input as unknown as Record<string, unknown>,\n idempotencyKey: crypto.randomUUID(),\n });\n}\n\n/**\n * Check if a user is a member of the community by email.\n * @param email - The email address to check.\n * @returns Membership status and details.\n */\nexport async function checkMembership(email: string) {\n return apiRequest<unknown>(\"/members/check\", {\n method: \"POST\",\n body: { email },\n });\n}\n\n// --- Groups ---\n\nexport interface AddUserToGroupInput {\n user: { slack_user_id: string } | { email: string } | { profile_id: string };\n}\n\n/**\n * Add a user to a group.\n * @param groupId - The group ID.\n * @param input - User identifier to add to the group.\n * @returns The updated group membership details.\n */\nexport async function addUserToGroup(groupId: string, input: AddUserToGroupInput) {\n return apiRequest<unknown>(`/groups/${groupId}/members`, {\n method: \"POST\",\n body: input as unknown as Record<string, unknown>,\n idempotencyKey: crypto.randomUUID(),\n });\n}\n\n// --- Messages ---\n\nexport interface SendMessageInput {\n channel: string;\n text: string;\n thread_ts?: string;\n}\n\n/**\n * Send a message to a Slack channel.\n * @param input - Channel, message text, and optional thread timestamp.\n * @returns The sent message details.\n */\nexport async function sendMessage(input: SendMessageInput) {\n return apiRequest<unknown>(\"/messages\", {\n method: \"POST\",\n body: input as unknown as Record<string, unknown>,\n idempotencyKey: crypto.randomUUID(),\n });\n}\n\n// --- Search ---\n\nexport interface SearchParams {\n q: string;\n type: \"post\" | \"comment\" | \"content_resource\";\n page?: number;\n per_page?: number;\n}\n\n/**\n * Search across community content (Beta).\n * @param params - Search query, content type, and optional pagination.\n * @returns Paginated search results.\n */\nexport async function search(params: SearchParams) {\n return apiRequest<{ data: unknown[]; page: number; per_page: number }>(\n \"/search\",\n { params: params as unknown as Record<string, string | number | boolean | undefined> }\n );\n}\n"],"mappings":"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","names":[]}
|