@thoughtfree/mcp-server 0.2.0 → 0.3.0

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.
package/dist/client.d.ts CHANGED
@@ -2,7 +2,7 @@
2
2
  * ThoughtFree REST API client.
3
3
  * Lightweight HTTP wrapper — no SvelteKit dependencies.
4
4
  */
5
- import type { Thought, Category, Stats, ListResponse, SearchResponse } from './types.js';
5
+ import type { Thought, Category, Stats, ListResponse, SearchResponse, Pipeline, PipelineRun, PipelineRunResult, WeeklyInsight, TranscribeResult, ResearchResult } from './types.js';
6
6
  export declare class ThoughtFreeClient {
7
7
  private baseUrl;
8
8
  private apiKey;
@@ -17,6 +17,7 @@ export declare class ThoughtFreeClient {
17
17
  isStarred?: boolean;
18
18
  isArchived?: boolean;
19
19
  deleted?: boolean;
20
+ parentThoughtId?: string;
20
21
  }): Promise<ListResponse<Thought>>;
21
22
  getThought(id: string): Promise<Thought>;
22
23
  createThought(data: {
@@ -29,6 +30,7 @@ export declare class ThoughtFreeClient {
29
30
  priority?: string;
30
31
  source?: string;
31
32
  autoClassify?: boolean;
33
+ parentThoughtId?: string;
32
34
  }): Promise<Thought>;
33
35
  updateThought(id: string, data: {
34
36
  content?: string;
@@ -62,4 +64,22 @@ export declare class ThoughtFreeClient {
62
64
  categories: Category[];
63
65
  }>;
64
66
  getStats(): Promise<Stats>;
67
+ listPipelines(): Promise<{
68
+ pipelines: Pipeline[];
69
+ }>;
70
+ runPipeline(id: string): Promise<PipelineRunResult>;
71
+ getPipelineRuns(id: string, params?: {
72
+ limit?: number;
73
+ cursor?: string;
74
+ }): Promise<{
75
+ runs: PipelineRun[];
76
+ nextCursor: string | null;
77
+ }>;
78
+ getWeeklyInsights(thoughts: {
79
+ content: string;
80
+ createdAt: string;
81
+ tags?: string[];
82
+ }[]): Promise<WeeklyInsight>;
83
+ transcribeYoutube(url: string): Promise<TranscribeResult>;
84
+ researchAnalyze(question: string, transcript: string, title?: string): Promise<ResearchResult>;
65
85
  }
package/dist/client.js CHANGED
@@ -44,6 +44,8 @@ export class ThoughtFreeClient {
44
44
  searchParams.set('isArchived', 'true');
45
45
  if (params?.deleted)
46
46
  searchParams.set('deleted', 'true');
47
+ if (params?.parentThoughtId)
48
+ searchParams.set('parentThoughtId', params.parentThoughtId);
47
49
  const qs = searchParams.toString();
48
50
  return this.request(`/api/v1/thoughts${qs ? `?${qs}` : ''}`);
49
51
  }
@@ -100,4 +102,42 @@ export class ThoughtFreeClient {
100
102
  async getStats() {
101
103
  return this.request('/api/v1/stats');
102
104
  }
105
+ // ─── Pipelines ────────────────────────────────────────────
106
+ async listPipelines() {
107
+ return this.request('/api/v1/pipelines');
108
+ }
109
+ async runPipeline(id) {
110
+ return this.request(`/api/v1/pipelines/${id}/run`, {
111
+ method: 'POST'
112
+ });
113
+ }
114
+ async getPipelineRuns(id, params) {
115
+ const searchParams = new URLSearchParams();
116
+ if (params?.limit)
117
+ searchParams.set('limit', String(params.limit));
118
+ if (params?.cursor)
119
+ searchParams.set('cursor', params.cursor);
120
+ const qs = searchParams.toString();
121
+ return this.request(`/api/v1/pipelines/${id}/runs${qs ? `?${qs}` : ''}`);
122
+ }
123
+ // ─── Weekly Insights ─────────────────────────────────────
124
+ async getWeeklyInsights(thoughts) {
125
+ return this.request('/api/ai/weekly-insights', {
126
+ method: 'POST',
127
+ body: JSON.stringify({ thoughts })
128
+ });
129
+ }
130
+ // ─── Research ────────────────────────────────────────────
131
+ async transcribeYoutube(url) {
132
+ return this.request('/api/research/transcribe-youtube', {
133
+ method: 'POST',
134
+ body: JSON.stringify({ url })
135
+ });
136
+ }
137
+ async researchAnalyze(question, transcript, title) {
138
+ return this.request('/api/research/analyze', {
139
+ method: 'POST',
140
+ body: JSON.stringify({ question, transcript, title })
141
+ });
142
+ }
103
143
  }
package/dist/index.js CHANGED
@@ -10,7 +10,7 @@ import { ThoughtFreeClient } from './client.js';
10
10
  import { registerAllMcpCapabilities } from './register.js';
11
11
  export async function main() {
12
12
  const apiKey = process.env.THOUGHTFREE_API_KEY;
13
- const apiUrl = process.env.THOUGHTFREE_API_URL || 'https://thoughtfree.io';
13
+ const apiUrl = process.env.THOUGHTFREE_API_URL || 'https://app.thoughtfree.io';
14
14
  if (!apiKey) {
15
15
  console.error('Error: THOUGHTFREE_API_KEY environment variable is required.');
16
16
  console.error('Create an API key at: ThoughtFree > Settings > API Keys');
@@ -27,7 +27,7 @@ export async function main() {
27
27
  await server.connect(transport);
28
28
  console.error('ThoughtFree MCP Server running on stdio');
29
29
  console.error(` API URL: ${apiUrl}`);
30
- console.error(` Tools: 10 | Resources: 3`);
30
+ console.error(` Tools: 18 | Resources: 3 | Prompts: 5`);
31
31
  }
32
32
  main().catch((err) => {
33
33
  console.error('Fatal error:', err);
@@ -0,0 +1,2 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare function registerDailyCapturePrompt(server: McpServer): void;
@@ -0,0 +1,20 @@
1
+ export function registerDailyCapturePrompt(server) {
2
+ server.prompt('daily_capture', 'Morning brain dump: conversationally capture scattered thoughts, ideas, and tasks, then organize them.', () => ({
3
+ messages: [
4
+ {
5
+ role: 'user',
6
+ content: {
7
+ type: 'text',
8
+ text: `I'd like to do a brain dump. Help me capture what's on my mind.
9
+
10
+ Ask me what I'm thinking about, then for each distinct thought, idea, or task I share:
11
+ 1. Use create_thought to save it with an appropriate type and category.
12
+ 2. If something sounds like a task, set a dueDate and priority.
13
+ 3. After I'm done capturing, give me a quick summary of what we captured and suggest any categories or tags to clean up.
14
+
15
+ Start by asking me: "What's on your mind?"`
16
+ }
17
+ }
18
+ ]
19
+ }));
20
+ }
@@ -0,0 +1,2 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare function registerOrganizeInboxPrompt(server: McpServer): void;
@@ -0,0 +1,21 @@
1
+ export function registerOrganizeInboxPrompt(server) {
2
+ server.prompt('organize_inbox', 'Triage uncategorized thoughts: review, categorize, star important ones, and archive or delete stale items.', () => ({
3
+ messages: [
4
+ {
5
+ role: 'user',
6
+ content: {
7
+ type: 'text',
8
+ text: `Help me organize my thought inbox.
9
+
10
+ 1. Use list_categories to see what categories are available.
11
+ 2. Use list_thoughts with limit 20 to find my recent uncategorized thoughts.
12
+ 3. For each thought, suggest a category. Group similar thoughts together.
13
+ 4. Present your suggestions and wait for my approval before making changes.
14
+ 5. Use update_thought to apply the categories I approve.
15
+ 6. Star anything that looks important, and ask if I want to archive anything old or irrelevant.
16
+ 7. Give me a summary of what we organized when we're done.`
17
+ }
18
+ }
19
+ ]
20
+ }));
21
+ }
@@ -0,0 +1,2 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare function registerPipelineStatusPrompt(server: McpServer): void;
@@ -0,0 +1,18 @@
1
+ export function registerPipelineStatusPrompt(server) {
2
+ server.prompt('pipeline_status', 'Check all your automation pipelines and their recent run status at a glance.', () => ({
3
+ messages: [
4
+ {
5
+ role: 'user',
6
+ content: {
7
+ type: 'text',
8
+ text: `Check on all my automation pipelines.
9
+
10
+ 1. Use list_pipelines to get all my pipelines.
11
+ 2. For each active pipeline, use get_pipeline_runs with limit 3 to check recent run status.
12
+ 3. Give me a health summary: which pipelines are running fine, which have recent failures, and which haven't run recently.
13
+ 4. If any pipeline has errors, suggest what might be wrong and whether I should re-run it.`
14
+ }
15
+ }
16
+ ]
17
+ }));
18
+ }
@@ -0,0 +1,2 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare function registerResearchVideoPrompt(server: McpServer): void;
@@ -0,0 +1,20 @@
1
+ import { z } from 'zod';
2
+ export function registerResearchVideoPrompt(server) {
3
+ server.prompt('research_video', 'Research a YouTube video: transcribe it, analyze the content, and save key insights as thoughts.', { url: z.string().describe('YouTube video URL') }, ({ url }) => ({
4
+ messages: [
5
+ {
6
+ role: 'user',
7
+ content: {
8
+ type: 'text',
9
+ text: `Research this YouTube video for me: ${url}
10
+
11
+ Here's what I'd like:
12
+ 1. Use transcribe_youtube to get the transcript.
13
+ 2. Use research_analyze to summarize the main points and key takeaways.
14
+ 3. Save the top 3-5 insights as individual thoughts using create_thought with category "insight" and the video title in tags.
15
+ 4. Ask me if I have any follow-up questions about the video content.`
16
+ }
17
+ }
18
+ ]
19
+ }));
20
+ }
@@ -0,0 +1,2 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare function registerWeeklyReviewPrompt(server: McpServer): void;
@@ -0,0 +1,19 @@
1
+ export function registerWeeklyReviewPrompt(server) {
2
+ server.prompt('weekly_review', 'Guided weekly reflection: review patterns in your thoughts, celebrate wins, and set intentions for next week.', () => ({
3
+ messages: [
4
+ {
5
+ role: 'user',
6
+ content: {
7
+ type: 'text',
8
+ text: `Help me review my week. Here's what I'd like you to do:
9
+
10
+ 1. Use get_stats to see my overall activity this week.
11
+ 2. Use get_weekly_insights with period "this_week" to analyze my thought patterns.
12
+ 3. Summarize the key themes, what's going well, and what I should watch out for.
13
+ 4. If there are any actionable takeaways, create a thought to capture them using create_thought with category "insight".
14
+ 5. End with one question to help me reflect deeper.`
15
+ }
16
+ }
17
+ ]
18
+ }));
19
+ }
package/dist/register.js CHANGED
@@ -15,11 +15,22 @@ import { registerRestoreTool } from './tools/restore.js';
15
15
  import { registerQueryBrainTool } from './tools/query-brain.js';
16
16
  import { registerCategoriesTool } from './tools/categories.js';
17
17
  import { registerStatsTool } from './tools/stats.js';
18
+ import { registerWeeklyInsightsTool } from './tools/weekly-insights.js';
19
+ import { registerPipelineTools } from './tools/pipelines.js';
20
+ import { registerCommentTools } from './tools/comments.js';
21
+ import { registerResearchTools } from './tools/research.js';
18
22
  // Resources
19
23
  import { registerRecentResource } from './resources/recent.js';
20
24
  import { registerStarredResource } from './resources/starred.js';
21
25
  import { registerByCategoryResource } from './resources/by-category.js';
26
+ // Prompts
27
+ import { registerWeeklyReviewPrompt } from './prompts/weekly-review.js';
28
+ import { registerDailyCapturePrompt } from './prompts/daily-capture.js';
29
+ import { registerResearchVideoPrompt } from './prompts/research-video.js';
30
+ import { registerOrganizeInboxPrompt } from './prompts/organize-inbox.js';
31
+ import { registerPipelineStatusPrompt } from './prompts/pipeline-status.js';
22
32
  export function registerAllMcpCapabilities(server, client) {
33
+ // Core tools (10)
23
34
  registerSearchTool(server, client);
24
35
  registerCreateTool(server, client);
25
36
  registerListTool(server, client);
@@ -30,7 +41,19 @@ export function registerAllMcpCapabilities(server, client) {
30
41
  registerQueryBrainTool(server, client);
31
42
  registerCategoriesTool(server, client);
32
43
  registerStatsTool(server, client);
44
+ // Expanded tools (8)
45
+ registerWeeklyInsightsTool(server, client);
46
+ registerPipelineTools(server, client); // 3 tools
47
+ registerCommentTools(server, client); // 2 tools
48
+ registerResearchTools(server, client); // 2 tools
49
+ // Resources (3)
33
50
  registerRecentResource(server, client);
34
51
  registerStarredResource(server, client);
35
52
  registerByCategoryResource(server, client);
53
+ // Prompts (5)
54
+ registerWeeklyReviewPrompt(server);
55
+ registerDailyCapturePrompt(server);
56
+ registerResearchVideoPrompt(server);
57
+ registerOrganizeInboxPrompt(server);
58
+ registerPipelineStatusPrompt(server);
36
59
  }
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import type { ThoughtFreeClient } from '../client.js';
3
+ export declare function registerCommentTools(server: McpServer, client: ThoughtFreeClient): void;
@@ -0,0 +1,48 @@
1
+ import { z } from 'zod';
2
+ export function registerCommentTools(server, client) {
3
+ server.registerTool('add_comment', {
4
+ title: 'Add Comment',
5
+ description: 'Add a comment (sub-thought) to an existing thought. Comments are threaded replies that add context or notes to a parent thought.',
6
+ inputSchema: z.object({
7
+ parentThoughtId: z.string().describe('The ID of the thought to comment on'),
8
+ content: z.string().describe('The comment text')
9
+ })
10
+ }, async ({ parentThoughtId, content }) => {
11
+ try {
12
+ const result = await client.createThought({
13
+ content,
14
+ type: 'text',
15
+ source: 'mcp',
16
+ parentThoughtId
17
+ });
18
+ return {
19
+ content: [{
20
+ type: 'text',
21
+ text: `Comment added to thought ${parentThoughtId}.\nComment ID: ${result.id}\nCreated: ${result.createdAt}`
22
+ }]
23
+ };
24
+ }
25
+ catch (err) {
26
+ return { content: [{ type: 'text', text: `Failed to add comment: ${err instanceof Error ? err.message : String(err)}` }], isError: true };
27
+ }
28
+ });
29
+ server.registerTool('get_comments', {
30
+ title: 'Get Comments',
31
+ description: 'List all comments (sub-thoughts) on a parent thought. Returns comments sorted by creation time.',
32
+ inputSchema: z.object({
33
+ parentThoughtId: z.string().describe('The ID of the parent thought')
34
+ })
35
+ }, async ({ parentThoughtId }) => {
36
+ try {
37
+ const result = await client.listThoughts({ parentThoughtId, limit: 100 });
38
+ if (result.data.length === 0) {
39
+ return { content: [{ type: 'text', text: 'No comments on this thought.' }] };
40
+ }
41
+ const formatted = result.data.map((c, i) => `${i + 1}. ${c.content.slice(0, 300)}${c.content.length > 300 ? '...' : ''}\n ID: ${c.id} | Created: ${c.createdAt}`).join('\n\n');
42
+ return { content: [{ type: 'text', text: `${result.data.length} comment(s):\n\n${formatted}` }] };
43
+ }
44
+ catch (err) {
45
+ return { content: [{ type: 'text', text: `Failed to get comments: ${err instanceof Error ? err.message : String(err)}` }], isError: true };
46
+ }
47
+ });
48
+ }
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import type { ThoughtFreeClient } from '../client.js';
3
+ export declare function registerPipelineTools(server: McpServer, client: ThoughtFreeClient): void;
@@ -0,0 +1,72 @@
1
+ import { z } from 'zod';
2
+ export function registerPipelineTools(server, client) {
3
+ server.registerTool('list_pipelines', {
4
+ title: 'List Pipelines',
5
+ description: 'List your automation pipelines. Pipelines run scheduled actions on categories of thoughts (summarize, digest, research, export). Requires Pro plan.',
6
+ inputSchema: z.object({})
7
+ }, async () => {
8
+ try {
9
+ const { pipelines } = await client.listPipelines();
10
+ if (pipelines.length === 0) {
11
+ return { content: [{ type: 'text', text: 'No pipelines configured. Create one in ThoughtFree Settings > Automations.' }] };
12
+ }
13
+ const formatted = pipelines.map((p, i) => `${i + 1}. **${p.name}** ${p.isActive ? '✓ Active' : '✗ Inactive'}\n Action: ${p.action} | Category: ${p.category}\n Last run: ${p.lastRunAt ? `${p.lastRunAt} (${p.lastRunStatus})` : 'Never'}\n ID: ${p.id}`).join('\n\n');
14
+ return { content: [{ type: 'text', text: `${pipelines.length} pipeline(s):\n\n${formatted}` }] };
15
+ }
16
+ catch (err) {
17
+ return { content: [{ type: 'text', text: `Failed to list pipelines: ${err instanceof Error ? err.message : String(err)}` }], isError: true };
18
+ }
19
+ });
20
+ server.registerTool('run_pipeline', {
21
+ title: 'Run Pipeline',
22
+ description: 'Manually trigger an automation pipeline. The pipeline must be active. Returns the run status and results. Requires Pro plan.',
23
+ inputSchema: z.object({
24
+ pipelineId: z.string().describe('The pipeline ID to run (use list_pipelines to find IDs)')
25
+ })
26
+ }, async ({ pipelineId }) => {
27
+ try {
28
+ const result = await client.runPipeline(pipelineId);
29
+ const parts = [
30
+ `Pipeline run ${result.status === 'success' ? 'completed successfully' : 'failed'}.`,
31
+ `Run ID: ${result.runId}`,
32
+ `Status: ${result.status}`,
33
+ `Processed: ${result.processedCount} thought(s)`,
34
+ `Duration: ${result.durationMs}ms`
35
+ ];
36
+ if (result.result) {
37
+ parts.push(`\nResult:\n${result.result}`);
38
+ }
39
+ if (result.error) {
40
+ parts.push(`\nError: ${result.error}`);
41
+ }
42
+ return { content: [{ type: 'text', text: parts.join('\n') }] };
43
+ }
44
+ catch (err) {
45
+ return { content: [{ type: 'text', text: `Failed to run pipeline: ${err instanceof Error ? err.message : String(err)}` }], isError: true };
46
+ }
47
+ });
48
+ server.registerTool('get_pipeline_runs', {
49
+ title: 'Pipeline Run History',
50
+ description: 'Get recent execution history for a pipeline. Shows status, duration, and results of past runs. Requires Pro plan.',
51
+ inputSchema: z.object({
52
+ pipelineId: z.string().describe('The pipeline ID'),
53
+ limit: z.number().min(1).max(50).default(10).describe('Number of runs to return')
54
+ })
55
+ }, async ({ pipelineId, limit }) => {
56
+ try {
57
+ const { runs } = await client.getPipelineRuns(pipelineId, { limit });
58
+ if (runs.length === 0) {
59
+ return { content: [{ type: 'text', text: 'No runs found for this pipeline.' }] };
60
+ }
61
+ const formatted = runs.map((r, i) => {
62
+ const status = r.status === 'completed' ? '✓' : r.status === 'failed' ? '✗' : '…';
63
+ const duration = r.durationMs ? `${r.durationMs}ms` : 'N/A';
64
+ return `${i + 1}. ${status} ${r.status} | ${r.triggeredBy} | ${r.processedCount ?? 0} thoughts | ${duration} | ${r.startedAt || r.createdAt}${r.error ? `\n Error: ${r.error}` : ''}`;
65
+ }).join('\n');
66
+ return { content: [{ type: 'text', text: `Recent runs:\n\n${formatted}` }] };
67
+ }
68
+ catch (err) {
69
+ return { content: [{ type: 'text', text: `Failed to get pipeline runs: ${err instanceof Error ? err.message : String(err)}` }], isError: true };
70
+ }
71
+ });
72
+ }
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import type { ThoughtFreeClient } from '../client.js';
3
+ export declare function registerResearchTools(server: McpServer, client: ThoughtFreeClient): void;
@@ -0,0 +1,60 @@
1
+ import { z } from 'zod';
2
+ export function registerResearchTools(server, client) {
3
+ server.registerTool('transcribe_youtube', {
4
+ title: 'Transcribe YouTube',
5
+ description: 'Extract the transcript (captions) from a YouTube video. Returns the video title and full transcript text. Use this before research_analyze to study a video.',
6
+ inputSchema: z.object({
7
+ url: z.string().describe('YouTube video URL (e.g., https://www.youtube.com/watch?v=...)')
8
+ })
9
+ }, async ({ url }) => {
10
+ try {
11
+ const result = await client.transcribeYoutube(url);
12
+ if (!result.transcript) {
13
+ return {
14
+ content: [{
15
+ type: 'text',
16
+ text: `Could not transcribe "${result.title}" (${result.videoId}): ${result.error || 'No captions available'}`
17
+ }]
18
+ };
19
+ }
20
+ const preview = result.transcript.length > 500
21
+ ? result.transcript.slice(0, 500) + '...'
22
+ : result.transcript;
23
+ return {
24
+ content: [{
25
+ type: 'text',
26
+ text: `**${result.title}** (${result.videoId})\nLanguage: ${result.language || 'unknown'}\nTranscript length: ${result.transcript.length} characters\n\n${preview}\n\n---\nFull transcript available. Use research_analyze to ask questions about this video.`
27
+ }]
28
+ };
29
+ }
30
+ catch (err) {
31
+ return { content: [{ type: 'text', text: `Failed to transcribe video: ${err instanceof Error ? err.message : String(err)}` }], isError: true };
32
+ }
33
+ });
34
+ server.registerTool('research_analyze', {
35
+ title: 'Research Analyze',
36
+ description: 'Ask a question about a transcript or text. Uses AI to analyze the content and return a detailed answer with key points and follow-up questions. Great for studying YouTube transcripts, articles, or any long text.',
37
+ inputSchema: z.object({
38
+ question: z.string().describe('The question to answer about the content'),
39
+ transcript: z.string().describe('The transcript or text to analyze'),
40
+ title: z.string().optional().describe('Title of the source material')
41
+ })
42
+ }, async ({ question, transcript, title }) => {
43
+ try {
44
+ const result = await client.researchAnalyze(question, transcript, title);
45
+ const parts = [
46
+ `## Answer\n${result.answer}\n`
47
+ ];
48
+ if (result.keyPoints.length > 0) {
49
+ parts.push(`## Key Points\n${result.keyPoints.map(p => `- ${p}`).join('\n')}\n`);
50
+ }
51
+ if (result.suggestedQuestions.length > 0) {
52
+ parts.push(`## Follow-up Questions\n${result.suggestedQuestions.map(q => `- ${q}`).join('\n')}`);
53
+ }
54
+ return { content: [{ type: 'text', text: parts.join('\n') }] };
55
+ }
56
+ catch (err) {
57
+ return { content: [{ type: 'text', text: `Research analysis failed: ${err instanceof Error ? err.message : String(err)}` }], isError: true };
58
+ }
59
+ });
60
+ }
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import type { ThoughtFreeClient } from '../client.js';
3
+ export declare function registerWeeklyInsightsTool(server: McpServer, client: ThoughtFreeClient): void;
@@ -0,0 +1,71 @@
1
+ import { z } from 'zod';
2
+ export function registerWeeklyInsightsTool(server, client) {
3
+ server.registerTool('get_weekly_insights', {
4
+ title: 'Weekly Insights',
5
+ description: 'Get AI-analyzed patterns, themes, and growth areas from your recent thoughts. Identifies recurring themes, emotional tone, concerns, and offers a gentle suggestion. Requires Pro plan.',
6
+ inputSchema: z.object({
7
+ period: z.enum(['this_week', 'last_week']).default('this_week').describe('Which week to analyze')
8
+ })
9
+ }, async ({ period }) => {
10
+ try {
11
+ // Calculate date range
12
+ const now = new Date();
13
+ const dayOfWeek = now.getDay(); // 0=Sun, 1=Mon, ...
14
+ const startOfThisWeek = new Date(now);
15
+ startOfThisWeek.setDate(now.getDate() - dayOfWeek);
16
+ startOfThisWeek.setHours(0, 0, 0, 0);
17
+ let from;
18
+ let to;
19
+ if (period === 'last_week') {
20
+ to = new Date(startOfThisWeek);
21
+ from = new Date(startOfThisWeek);
22
+ from.setDate(from.getDate() - 7);
23
+ }
24
+ else {
25
+ from = startOfThisWeek;
26
+ to = now;
27
+ }
28
+ // Fetch thoughts in the date range
29
+ const result = await client.listThoughts({ limit: 100 });
30
+ const thoughts = result.data
31
+ .filter(t => {
32
+ const created = new Date(t.createdAt);
33
+ return created >= from && created <= to;
34
+ })
35
+ .map(t => ({
36
+ content: t.content,
37
+ createdAt: t.createdAt,
38
+ tags: t.userTags
39
+ }));
40
+ if (thoughts.length === 0) {
41
+ return {
42
+ content: [{
43
+ type: 'text',
44
+ text: `No thoughts found for ${period === 'last_week' ? 'last week' : 'this week'}. Capture some thoughts first!`
45
+ }]
46
+ };
47
+ }
48
+ const insight = await client.getWeeklyInsights(thoughts);
49
+ const parts = [
50
+ `## Weekly Insights (${period === 'last_week' ? 'Last Week' : 'This Week'})`,
51
+ `**${thoughts.length} thoughts analyzed**\n`,
52
+ `### Summary\n${insight.summary}\n`,
53
+ `### Themes\n${insight.themes.map(t => `- ${t}`).join('\n')}\n`
54
+ ];
55
+ if (insight.patterns.emotionalTone) {
56
+ parts.push(`### Emotional Tone\n${insight.patterns.emotionalTone}${insight.patterns.emotionalScore ? ` (${insight.patterns.emotionalScore}/5)` : ''}\n`);
57
+ }
58
+ if (insight.concerns.length > 0) {
59
+ parts.push(`### Concerns\n${insight.concerns.map(c => `- ${c}`).join('\n')}\n`);
60
+ }
61
+ if (insight.growth.length > 0) {
62
+ parts.push(`### Growth\n${insight.growth.map(g => `- ${g}`).join('\n')}\n`);
63
+ }
64
+ parts.push(`### Suggestion\n${insight.suggestion}`);
65
+ return { content: [{ type: 'text', text: parts.join('\n') }] };
66
+ }
67
+ catch (err) {
68
+ return { content: [{ type: 'text', text: `Failed to get weekly insights: ${err instanceof Error ? err.message : String(err)}` }], isError: true };
69
+ }
70
+ });
71
+ }
package/dist/types.d.ts CHANGED
@@ -13,6 +13,7 @@ export interface Thought {
13
13
  priority: string | null;
14
14
  completedAt: string | null;
15
15
  attachments: unknown[];
16
+ parentThoughtId: string | null;
16
17
  createdAt: string;
17
18
  updatedAt: string;
18
19
  deletedAt?: string | null;
@@ -58,3 +59,63 @@ export interface SearchResponse {
58
59
  mode: string;
59
60
  total: number;
60
61
  }
62
+ export interface Pipeline {
63
+ id: string;
64
+ name: string;
65
+ description: string | null;
66
+ category: string;
67
+ action: string;
68
+ config: Record<string, unknown>;
69
+ isActive: boolean;
70
+ lastRunAt: string | null;
71
+ lastRunStatus: string | null;
72
+ createdAt: string;
73
+ updatedAt: string;
74
+ }
75
+ export interface PipelineRun {
76
+ id: string;
77
+ pipelineId: string;
78
+ status: string;
79
+ triggeredBy: string;
80
+ startedAt: string | null;
81
+ completedAt: string | null;
82
+ durationMs: number | null;
83
+ processedCount: number | null;
84
+ result: string | null;
85
+ resultMetadata: Record<string, unknown>;
86
+ error: string | null;
87
+ createdAt: string;
88
+ }
89
+ export interface PipelineRunResult {
90
+ runId: string;
91
+ status: string;
92
+ processedCount: number;
93
+ result: string | null;
94
+ error: string | null;
95
+ durationMs: number;
96
+ }
97
+ export interface WeeklyInsight {
98
+ summary: string;
99
+ themes: string[];
100
+ patterns: {
101
+ timeOfDay?: string | null;
102
+ emotionalTone?: string | null;
103
+ emotionalScore?: number | null;
104
+ topCategories?: string[];
105
+ };
106
+ concerns: string[];
107
+ growth: string[];
108
+ suggestion: string;
109
+ }
110
+ export interface TranscribeResult {
111
+ videoId: string;
112
+ title: string;
113
+ transcript: string | null;
114
+ language?: string;
115
+ error?: string;
116
+ }
117
+ export interface ResearchResult {
118
+ answer: string;
119
+ keyPoints: string[];
120
+ suggestedQuestions: string[];
121
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thoughtfree/mcp-server",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "MCP server for ThoughtFree — access your thought database from any AI agent",
5
5
  "type": "module",
6
6
  "bin": {