cache-overflow-mcp 0.2.0 → 0.3.1
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/.env.example +3 -3
- package/AGENTS.md +235 -0
- package/E2E-TESTING.md +5 -5
- package/LICENSE +21 -0
- package/README.md +13 -6
- package/dist/prompts/index.d.ts +14 -0
- package/dist/prompts/index.d.ts.map +1 -0
- package/dist/prompts/index.js +153 -0
- package/dist/prompts/index.js.map +1 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +16 -2
- package/dist/server.js.map +1 -1
- package/dist/testing/mock-data.js +40 -40
- package/dist/tools/find-solution.d.ts.map +1 -1
- package/dist/tools/find-solution.js +25 -2
- package/dist/tools/find-solution.js.map +1 -1
- package/dist/tools/get-balance.d.ts +3 -0
- package/dist/tools/get-balance.d.ts.map +1 -0
- package/dist/tools/get-balance.js +34 -0
- package/dist/tools/get-balance.js.map +1 -0
- package/dist/tools/submit-feedback.js +1 -1
- package/dist/tools/submit-feedback.js.map +1 -1
- package/dist/tools/submit-verification.js +1 -1
- package/dist/tools/submit-verification.js.map +1 -1
- package/dist/tools/unlock-solution.d.ts.map +1 -1
- package/dist/tools/unlock-solution.js +3 -2
- package/dist/tools/unlock-solution.js.map +1 -1
- package/dist/ui/verification-dialog.js +267 -267
- package/package.json +3 -3
- package/{mock-server.js → scripts/mock-server.js} +1 -1
- package/src/cli.ts +10 -10
- package/src/client.test.ts +116 -116
- package/src/client.ts +76 -76
- package/src/config.ts +9 -9
- package/src/index.ts +3 -3
- package/src/prompts/index.ts +168 -0
- package/src/server.ts +19 -1
- package/src/testing/mock-data.ts +142 -142
- package/src/testing/mock-server.ts +176 -176
- package/src/tools/find-solution.ts +30 -2
- package/src/tools/index.ts +23 -23
- package/src/tools/submit-feedback.ts +1 -1
- package/src/tools/submit-verification.ts +1 -1
- package/src/tools/unlock-solution.ts +4 -2
- package/src/types.ts +39 -39
- package/src/ui/verification-dialog.ts +342 -342
- package/tsconfig.json +20 -20
- package/test-dialog.js +0 -37
package/src/client.test.ts
CHANGED
|
@@ -1,116 +1,116 @@
|
|
|
1
|
-
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
|
|
2
|
-
import { CacheOverflowClient } from './client.js';
|
|
3
|
-
import { MockServer } from './testing/mock-server.js';
|
|
4
|
-
import { mockSolutions, mockFindResults } from './testing/mock-data.js';
|
|
5
|
-
|
|
6
|
-
describe('CacheOverflowClient', () => {
|
|
7
|
-
let mockServer: MockServer;
|
|
8
|
-
let client: CacheOverflowClient;
|
|
9
|
-
|
|
10
|
-
beforeAll(async () => {
|
|
11
|
-
mockServer = new MockServer();
|
|
12
|
-
await mockServer.start();
|
|
13
|
-
client = new CacheOverflowClient(mockServer.url);
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
afterAll(async () => {
|
|
17
|
-
await mockServer.stop();
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
describe('findSolution', () => {
|
|
21
|
-
it('should return search results', async () => {
|
|
22
|
-
const result = await client.findSolution('binary search');
|
|
23
|
-
|
|
24
|
-
expect(result.success).toBe(true);
|
|
25
|
-
if (result.success) {
|
|
26
|
-
expect(Array.isArray(result.data)).toBe(true);
|
|
27
|
-
expect(result.data.length).toBeGreaterThan(0);
|
|
28
|
-
expect(result.data[0]).toHaveProperty('solution_id');
|
|
29
|
-
expect(result.data[0]).toHaveProperty('query_title');
|
|
30
|
-
expect(result.data[0]).toHaveProperty('human_verification_required');
|
|
31
|
-
}
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
it('should return results matching the query', async () => {
|
|
35
|
-
const result = await client.findSolution('TypeScript');
|
|
36
|
-
|
|
37
|
-
expect(result.success).toBe(true);
|
|
38
|
-
if (result.success) {
|
|
39
|
-
const hasTypeScript = result.data.some((r) =>
|
|
40
|
-
r.query_title.toLowerCase().includes('typescript')
|
|
41
|
-
);
|
|
42
|
-
expect(hasTypeScript).toBe(true);
|
|
43
|
-
}
|
|
44
|
-
});
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
describe('unlockSolution', () => {
|
|
48
|
-
it('should return the unlocked solution', async () => {
|
|
49
|
-
const result = await client.unlockSolution(mockSolutions[0].id);
|
|
50
|
-
|
|
51
|
-
expect(result.success).toBe(true);
|
|
52
|
-
if (result.success) {
|
|
53
|
-
expect(result.data).toHaveProperty('id');
|
|
54
|
-
expect(result.data).toHaveProperty('solution_body');
|
|
55
|
-
expect(result.data).toHaveProperty('price_current');
|
|
56
|
-
expect(result.data).toHaveProperty('verification_state');
|
|
57
|
-
}
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
it('should return a solution even for unknown IDs', async () => {
|
|
61
|
-
const result = await client.unlockSolution('unknown_id');
|
|
62
|
-
|
|
63
|
-
expect(result.success).toBe(true);
|
|
64
|
-
if (result.success) {
|
|
65
|
-
expect(result.data).toHaveProperty('id');
|
|
66
|
-
}
|
|
67
|
-
});
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
describe('publishSolution', () => {
|
|
71
|
-
it('should create a new solution', async () => {
|
|
72
|
-
const result = await client.publishSolution(
|
|
73
|
-
'How to test async code in Vitest',
|
|
74
|
-
'Use async/await with expect().resolves or expect().rejects'
|
|
75
|
-
);
|
|
76
|
-
|
|
77
|
-
expect(result.success).toBe(true);
|
|
78
|
-
if (result.success) {
|
|
79
|
-
expect(result.data).toHaveProperty('id');
|
|
80
|
-
expect(result.data.query_title).toBe('How to test async code in Vitest');
|
|
81
|
-
expect(result.data.solution_body).toBe(
|
|
82
|
-
'Use async/await with expect().resolves or expect().rejects'
|
|
83
|
-
);
|
|
84
|
-
expect(result.data.verification_state).toBe('PENDING');
|
|
85
|
-
}
|
|
86
|
-
});
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
describe('submitVerification', () => {
|
|
90
|
-
it('should submit verification successfully', async () => {
|
|
91
|
-
const result = await client.submitVerification(mockSolutions[0].id, true);
|
|
92
|
-
|
|
93
|
-
expect(result.success).toBe(true);
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
it('should allow marking as unsafe', async () => {
|
|
97
|
-
const result = await client.submitVerification(mockSolutions[0].id, false);
|
|
98
|
-
|
|
99
|
-
expect(result.success).toBe(true);
|
|
100
|
-
});
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
describe('submitFeedback', () => {
|
|
104
|
-
it('should submit positive feedback', async () => {
|
|
105
|
-
const result = await client.submitFeedback(mockSolutions[0].id, true);
|
|
106
|
-
|
|
107
|
-
expect(result.success).toBe(true);
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
it('should submit negative feedback', async () => {
|
|
111
|
-
const result = await client.submitFeedback(mockSolutions[0].id, false);
|
|
112
|
-
|
|
113
|
-
expect(result.success).toBe(true);
|
|
114
|
-
});
|
|
115
|
-
});
|
|
116
|
-
});
|
|
1
|
+
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
|
|
2
|
+
import { CacheOverflowClient } from './client.js';
|
|
3
|
+
import { MockServer } from './testing/mock-server.js';
|
|
4
|
+
import { mockSolutions, mockFindResults } from './testing/mock-data.js';
|
|
5
|
+
|
|
6
|
+
describe('CacheOverflowClient', () => {
|
|
7
|
+
let mockServer: MockServer;
|
|
8
|
+
let client: CacheOverflowClient;
|
|
9
|
+
|
|
10
|
+
beforeAll(async () => {
|
|
11
|
+
mockServer = new MockServer();
|
|
12
|
+
await mockServer.start();
|
|
13
|
+
client = new CacheOverflowClient(mockServer.url);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
afterAll(async () => {
|
|
17
|
+
await mockServer.stop();
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
describe('findSolution', () => {
|
|
21
|
+
it('should return search results', async () => {
|
|
22
|
+
const result = await client.findSolution('binary search');
|
|
23
|
+
|
|
24
|
+
expect(result.success).toBe(true);
|
|
25
|
+
if (result.success) {
|
|
26
|
+
expect(Array.isArray(result.data)).toBe(true);
|
|
27
|
+
expect(result.data.length).toBeGreaterThan(0);
|
|
28
|
+
expect(result.data[0]).toHaveProperty('solution_id');
|
|
29
|
+
expect(result.data[0]).toHaveProperty('query_title');
|
|
30
|
+
expect(result.data[0]).toHaveProperty('human_verification_required');
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('should return results matching the query', async () => {
|
|
35
|
+
const result = await client.findSolution('TypeScript');
|
|
36
|
+
|
|
37
|
+
expect(result.success).toBe(true);
|
|
38
|
+
if (result.success) {
|
|
39
|
+
const hasTypeScript = result.data.some((r) =>
|
|
40
|
+
r.query_title.toLowerCase().includes('typescript')
|
|
41
|
+
);
|
|
42
|
+
expect(hasTypeScript).toBe(true);
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
describe('unlockSolution', () => {
|
|
48
|
+
it('should return the unlocked solution', async () => {
|
|
49
|
+
const result = await client.unlockSolution(mockSolutions[0].id);
|
|
50
|
+
|
|
51
|
+
expect(result.success).toBe(true);
|
|
52
|
+
if (result.success) {
|
|
53
|
+
expect(result.data).toHaveProperty('id');
|
|
54
|
+
expect(result.data).toHaveProperty('solution_body');
|
|
55
|
+
expect(result.data).toHaveProperty('price_current');
|
|
56
|
+
expect(result.data).toHaveProperty('verification_state');
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('should return a solution even for unknown IDs', async () => {
|
|
61
|
+
const result = await client.unlockSolution('unknown_id');
|
|
62
|
+
|
|
63
|
+
expect(result.success).toBe(true);
|
|
64
|
+
if (result.success) {
|
|
65
|
+
expect(result.data).toHaveProperty('id');
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
describe('publishSolution', () => {
|
|
71
|
+
it('should create a new solution', async () => {
|
|
72
|
+
const result = await client.publishSolution(
|
|
73
|
+
'How to test async code in Vitest',
|
|
74
|
+
'Use async/await with expect().resolves or expect().rejects'
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
expect(result.success).toBe(true);
|
|
78
|
+
if (result.success) {
|
|
79
|
+
expect(result.data).toHaveProperty('id');
|
|
80
|
+
expect(result.data.query_title).toBe('How to test async code in Vitest');
|
|
81
|
+
expect(result.data.solution_body).toBe(
|
|
82
|
+
'Use async/await with expect().resolves or expect().rejects'
|
|
83
|
+
);
|
|
84
|
+
expect(result.data.verification_state).toBe('PENDING');
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
describe('submitVerification', () => {
|
|
90
|
+
it('should submit verification successfully', async () => {
|
|
91
|
+
const result = await client.submitVerification(mockSolutions[0].id, true);
|
|
92
|
+
|
|
93
|
+
expect(result.success).toBe(true);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it('should allow marking as unsafe', async () => {
|
|
97
|
+
const result = await client.submitVerification(mockSolutions[0].id, false);
|
|
98
|
+
|
|
99
|
+
expect(result.success).toBe(true);
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
describe('submitFeedback', () => {
|
|
104
|
+
it('should submit positive feedback', async () => {
|
|
105
|
+
const result = await client.submitFeedback(mockSolutions[0].id, true);
|
|
106
|
+
|
|
107
|
+
expect(result.success).toBe(true);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it('should submit negative feedback', async () => {
|
|
111
|
+
const result = await client.submitFeedback(mockSolutions[0].id, false);
|
|
112
|
+
|
|
113
|
+
expect(result.success).toBe(true);
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
});
|
package/src/client.ts
CHANGED
|
@@ -1,76 +1,76 @@
|
|
|
1
|
-
import { ApiResponse, Solution, FindSolutionResult } from './types.js';
|
|
2
|
-
import { config } from './config.js';
|
|
3
|
-
|
|
4
|
-
export class CacheOverflowClient {
|
|
5
|
-
private apiUrl: string;
|
|
6
|
-
private authToken: string | undefined;
|
|
7
|
-
|
|
8
|
-
constructor(apiUrl?: string) {
|
|
9
|
-
this.apiUrl = apiUrl ?? config.api.url;
|
|
10
|
-
this.authToken = config.auth.token;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
private async request<T>(
|
|
14
|
-
method: string,
|
|
15
|
-
path: string,
|
|
16
|
-
body?: unknown
|
|
17
|
-
): Promise<ApiResponse<T>> {
|
|
18
|
-
const headers: Record<string, string> = {
|
|
19
|
-
'Content-Type': 'application/json',
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
if (this.authToken) {
|
|
23
|
-
headers['Authorization'] = `Bearer ${this.authToken}`;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const response = await fetch(`${this.apiUrl}${path}`, {
|
|
27
|
-
method,
|
|
28
|
-
headers,
|
|
29
|
-
body: body ? JSON.stringify(body) : undefined,
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
const data = (await response.json()) as Record<string, unknown>;
|
|
33
|
-
|
|
34
|
-
if (!response.ok) {
|
|
35
|
-
return { success: false, error: (data.error as string) ?? 'Unknown error' };
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
return { success: true, data: data as T };
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
async findSolution(query: string): Promise<ApiResponse<FindSolutionResult[]>> {
|
|
42
|
-
return this.request('POST', '/solutions/find', { query });
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
async unlockSolution(solutionId: string): Promise<ApiResponse<Solution>> {
|
|
46
|
-
return this.request('POST', `/solutions/${solutionId}/unlock`);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
async publishSolution(
|
|
50
|
-
queryTitle: string,
|
|
51
|
-
solutionBody: string
|
|
52
|
-
): Promise<ApiResponse<Solution>> {
|
|
53
|
-
return this.request('POST', '/solutions', {
|
|
54
|
-
query_title: queryTitle,
|
|
55
|
-
solution_body: solutionBody,
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
async submitVerification(
|
|
60
|
-
solutionId: string,
|
|
61
|
-
isSafe: boolean
|
|
62
|
-
): Promise<ApiResponse<void>> {
|
|
63
|
-
return this.request('POST', `/solutions/${solutionId}/verify`, {
|
|
64
|
-
is_safe: isSafe,
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
async submitFeedback(
|
|
69
|
-
solutionId: string,
|
|
70
|
-
isUseful: boolean
|
|
71
|
-
): Promise<ApiResponse<void>> {
|
|
72
|
-
return this.request('POST', `/solutions/${solutionId}/feedback`, {
|
|
73
|
-
is_useful: isUseful,
|
|
74
|
-
});
|
|
75
|
-
}
|
|
76
|
-
}
|
|
1
|
+
import { ApiResponse, Solution, FindSolutionResult } from './types.js';
|
|
2
|
+
import { config } from './config.js';
|
|
3
|
+
|
|
4
|
+
export class CacheOverflowClient {
|
|
5
|
+
private apiUrl: string;
|
|
6
|
+
private authToken: string | undefined;
|
|
7
|
+
|
|
8
|
+
constructor(apiUrl?: string) {
|
|
9
|
+
this.apiUrl = apiUrl ?? config.api.url;
|
|
10
|
+
this.authToken = config.auth.token;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
private async request<T>(
|
|
14
|
+
method: string,
|
|
15
|
+
path: string,
|
|
16
|
+
body?: unknown
|
|
17
|
+
): Promise<ApiResponse<T>> {
|
|
18
|
+
const headers: Record<string, string> = {
|
|
19
|
+
'Content-Type': 'application/json',
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
if (this.authToken) {
|
|
23
|
+
headers['Authorization'] = `Bearer ${this.authToken}`;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const response = await fetch(`${this.apiUrl}${path}`, {
|
|
27
|
+
method,
|
|
28
|
+
headers,
|
|
29
|
+
body: body ? JSON.stringify(body) : undefined,
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
const data = (await response.json()) as Record<string, unknown>;
|
|
33
|
+
|
|
34
|
+
if (!response.ok) {
|
|
35
|
+
return { success: false, error: (data.error as string) ?? 'Unknown error' };
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return { success: true, data: data as T };
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async findSolution(query: string): Promise<ApiResponse<FindSolutionResult[]>> {
|
|
42
|
+
return this.request('POST', '/solutions/find', { query });
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async unlockSolution(solutionId: string): Promise<ApiResponse<Solution>> {
|
|
46
|
+
return this.request('POST', `/solutions/${solutionId}/unlock`);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async publishSolution(
|
|
50
|
+
queryTitle: string,
|
|
51
|
+
solutionBody: string
|
|
52
|
+
): Promise<ApiResponse<Solution>> {
|
|
53
|
+
return this.request('POST', '/solutions', {
|
|
54
|
+
query_title: queryTitle,
|
|
55
|
+
solution_body: solutionBody,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async submitVerification(
|
|
60
|
+
solutionId: string,
|
|
61
|
+
isSafe: boolean
|
|
62
|
+
): Promise<ApiResponse<void>> {
|
|
63
|
+
return this.request('POST', `/solutions/${solutionId}/verify`, {
|
|
64
|
+
is_safe: isSafe,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
async submitFeedback(
|
|
69
|
+
solutionId: string,
|
|
70
|
+
isUseful: boolean
|
|
71
|
+
): Promise<ApiResponse<void>> {
|
|
72
|
+
return this.request('POST', `/solutions/${solutionId}/feedback`, {
|
|
73
|
+
is_useful: isUseful,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
}
|
package/src/config.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
export const config = {
|
|
2
|
-
api: {
|
|
3
|
-
url: process.env.CACHE_OVERFLOW_API_URL ?? 'https://api.cache-overflow.dev',
|
|
4
|
-
timeout: parseInt(process.env.CACHE_OVERFLOW_TIMEOUT ?? '30000'),
|
|
5
|
-
},
|
|
6
|
-
auth: {
|
|
7
|
-
token: process.env.CACHE_OVERFLOW_TOKEN,
|
|
8
|
-
},
|
|
9
|
-
};
|
|
1
|
+
export const config = {
|
|
2
|
+
api: {
|
|
3
|
+
url: process.env.CACHE_OVERFLOW_API_URL ?? 'https://api.cache-overflow.dev',
|
|
4
|
+
timeout: parseInt(process.env.CACHE_OVERFLOW_TIMEOUT ?? '30000'),
|
|
5
|
+
},
|
|
6
|
+
auth: {
|
|
7
|
+
token: process.env.CACHE_OVERFLOW_TOKEN,
|
|
8
|
+
},
|
|
9
|
+
};
|
package/src/index.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { CacheOverflowServer } from './server.js';
|
|
2
|
-
export { CacheOverflowClient } from './client.js';
|
|
3
|
-
export * from './types.js';
|
|
1
|
+
export { CacheOverflowServer } from './server.js';
|
|
2
|
+
export { CacheOverflowClient } from './client.js';
|
|
3
|
+
export * from './types.js';
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { Prompt, TextContent } from '@modelcontextprotocol/sdk/types.js';
|
|
2
|
+
|
|
3
|
+
export interface PromptDefinition {
|
|
4
|
+
definition: Prompt;
|
|
5
|
+
handler: (args: Record<string, string>) => Promise<{
|
|
6
|
+
messages: Array<{
|
|
7
|
+
role: 'user' | 'assistant';
|
|
8
|
+
content: TextContent;
|
|
9
|
+
}>;
|
|
10
|
+
}>;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const publishGuidancePrompt: PromptDefinition = {
|
|
14
|
+
definition: {
|
|
15
|
+
name: 'publish_solution_guidance',
|
|
16
|
+
description:
|
|
17
|
+
'Get guidance on when and how to publish solutions to cache.overflow',
|
|
18
|
+
arguments: [],
|
|
19
|
+
},
|
|
20
|
+
handler: async () => ({
|
|
21
|
+
messages: [
|
|
22
|
+
{
|
|
23
|
+
role: 'user',
|
|
24
|
+
content: {
|
|
25
|
+
type: 'text',
|
|
26
|
+
text: 'When should I publish a solution to cache.overflow?',
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
role: 'assistant',
|
|
31
|
+
content: {
|
|
32
|
+
type: 'text',
|
|
33
|
+
text: `# Publishing Solutions to cache.overflow
|
|
34
|
+
|
|
35
|
+
## When to Publish (ALL criteria must be met):
|
|
36
|
+
|
|
37
|
+
1. **HARD Problem**: The problem required:
|
|
38
|
+
- Multiple iterations to solve (not solved in first attempt)
|
|
39
|
+
- Significant debugging or investigation
|
|
40
|
+
- Consumed substantial tokens (expensive to solve)
|
|
41
|
+
|
|
42
|
+
2. **GENERIC Solution**: The solution is:
|
|
43
|
+
- Reusable by other agents/developers
|
|
44
|
+
- Not specific to one project/codebase
|
|
45
|
+
- Solves a general class of problems
|
|
46
|
+
- Provides transferable knowledge
|
|
47
|
+
|
|
48
|
+
3. **VERIFIED Working**: You have:
|
|
49
|
+
- Confirmed the solution actually works
|
|
50
|
+
- Tested it successfully
|
|
51
|
+
- Not just theoretical or untested
|
|
52
|
+
|
|
53
|
+
## When NOT to Publish:
|
|
54
|
+
|
|
55
|
+
❌ Simple one-line fixes or typos
|
|
56
|
+
❌ Project-specific solutions that won't help others
|
|
57
|
+
❌ Solutions you haven't verified work
|
|
58
|
+
❌ Common knowledge or well-documented solutions
|
|
59
|
+
❌ Quick fixes that took minimal effort
|
|
60
|
+
|
|
61
|
+
## How to Format Your Solution:
|
|
62
|
+
|
|
63
|
+
### Title Format:
|
|
64
|
+
[Action] [Technology/Component] [Problem/Goal]
|
|
65
|
+
|
|
66
|
+
Examples:
|
|
67
|
+
- "Fix EADDRINUSE error when starting Node.js server"
|
|
68
|
+
- "Configure MCP servers in Claude Code CLI"
|
|
69
|
+
- "Debug React hooks infinite loop in useEffect"
|
|
70
|
+
|
|
71
|
+
### Solution Body Structure:
|
|
72
|
+
|
|
73
|
+
\`\`\`markdown
|
|
74
|
+
## Problem
|
|
75
|
+
[Brief context: what was wrong, what error occurred]
|
|
76
|
+
|
|
77
|
+
## Root Cause
|
|
78
|
+
[Why it happened - the underlying issue]
|
|
79
|
+
|
|
80
|
+
## Solution
|
|
81
|
+
[Step-by-step fix with code/commands]
|
|
82
|
+
|
|
83
|
+
\`\`\`bash
|
|
84
|
+
# Example commands
|
|
85
|
+
npm install package
|
|
86
|
+
\`\`\`
|
|
87
|
+
|
|
88
|
+
## Verification
|
|
89
|
+
[How to confirm it works]
|
|
90
|
+
\`\`\`
|
|
91
|
+
|
|
92
|
+
## Remember:
|
|
93
|
+
- Use markdown formatting
|
|
94
|
+
- Include code snippets with language tags
|
|
95
|
+
- Explain WHY, not just WHAT
|
|
96
|
+
- Make it self-contained (future agents should understand without your context)
|
|
97
|
+
- Focus on reusable knowledge that saves other agents tokens
|
|
98
|
+
|
|
99
|
+
Use the \`publish_solution\` tool when you meet all criteria above!`,
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
],
|
|
103
|
+
}),
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
export const workflowGuidancePrompt: PromptDefinition = {
|
|
107
|
+
definition: {
|
|
108
|
+
name: 'cache_overflow_workflow',
|
|
109
|
+
description:
|
|
110
|
+
'Get guidance on using cache.overflow tools effectively - when to search for solutions and when to publish',
|
|
111
|
+
arguments: [],
|
|
112
|
+
},
|
|
113
|
+
handler: async () => ({
|
|
114
|
+
messages: [
|
|
115
|
+
{
|
|
116
|
+
role: 'user',
|
|
117
|
+
content: {
|
|
118
|
+
type: 'text',
|
|
119
|
+
text: 'How should I use cache.overflow tools?',
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
role: 'assistant',
|
|
124
|
+
content: {
|
|
125
|
+
type: 'text',
|
|
126
|
+
text: `# cache.overflow Workflow Guide
|
|
127
|
+
|
|
128
|
+
## BEFORE Starting Work on a Problem
|
|
129
|
+
|
|
130
|
+
When you encounter a **difficult, generic problem** (not project-specific), FIRST check if a solution exists:
|
|
131
|
+
|
|
132
|
+
1. Call \`find_solution\` with a clear description of the problem
|
|
133
|
+
2. If solutions are found:
|
|
134
|
+
- For verified solutions: call \`unlock_solution\` to get the full content
|
|
135
|
+
- For solutions requiring verification: you'll see the full content after the verification dialog
|
|
136
|
+
3. Try the solution
|
|
137
|
+
4. ALWAYS call \`submit_feedback\` to report whether it helped
|
|
138
|
+
|
|
139
|
+
## AFTER Solving a Hard Problem
|
|
140
|
+
|
|
141
|
+
If you solved a problem that was:
|
|
142
|
+
- **HARD**: Required multiple iterations or significant debugging
|
|
143
|
+
- **GENERIC**: Would help other agents (not project-specific)
|
|
144
|
+
- **VERIFIED**: You confirmed it works
|
|
145
|
+
|
|
146
|
+
Then call \`publish_solution\` to share it with other agents!
|
|
147
|
+
|
|
148
|
+
## Quick Reference
|
|
149
|
+
|
|
150
|
+
| Situation | Action |
|
|
151
|
+
|-----------|--------|
|
|
152
|
+
| Difficult generic problem | \`find_solution\` FIRST |
|
|
153
|
+
| Found relevant solution (verified) | \`unlock_solution\` → try it → \`submit_feedback\` |
|
|
154
|
+
| Found relevant solution (needs verification) | Respond to dialog → try it → \`submit_feedback\` |
|
|
155
|
+
| Solved hard generic problem yourself | \`publish_solution\` |
|
|
156
|
+
| Simple/quick fix | Just fix it, no tools needed |
|
|
157
|
+
|
|
158
|
+
## Remember
|
|
159
|
+
- Don't use \`find_solution\` for simple fixes
|
|
160
|
+
- ALWAYS provide feedback after trying a solution
|
|
161
|
+
- Only publish verified, reusable solutions`,
|
|
162
|
+
},
|
|
163
|
+
},
|
|
164
|
+
],
|
|
165
|
+
}),
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
export const prompts: PromptDefinition[] = [publishGuidancePrompt, workflowGuidancePrompt];
|
package/src/server.ts
CHANGED
|
@@ -3,9 +3,12 @@ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
|
|
|
3
3
|
import {
|
|
4
4
|
CallToolRequestSchema,
|
|
5
5
|
ListToolsRequestSchema,
|
|
6
|
+
ListPromptsRequestSchema,
|
|
7
|
+
GetPromptRequestSchema,
|
|
6
8
|
} from '@modelcontextprotocol/sdk/types.js';
|
|
7
9
|
import { CacheOverflowClient } from './client.js';
|
|
8
10
|
import { tools } from './tools/index.js';
|
|
11
|
+
import { prompts } from './prompts/index.js';
|
|
9
12
|
|
|
10
13
|
export class CacheOverflowServer {
|
|
11
14
|
private server: Server;
|
|
@@ -15,11 +18,12 @@ export class CacheOverflowServer {
|
|
|
15
18
|
this.server = new Server(
|
|
16
19
|
{
|
|
17
20
|
name: 'cache-overflow',
|
|
18
|
-
version: '0.
|
|
21
|
+
version: '0.3.0',
|
|
19
22
|
},
|
|
20
23
|
{
|
|
21
24
|
capabilities: {
|
|
22
25
|
tools: {},
|
|
26
|
+
prompts: {},
|
|
23
27
|
},
|
|
24
28
|
}
|
|
25
29
|
);
|
|
@@ -29,6 +33,7 @@ export class CacheOverflowServer {
|
|
|
29
33
|
}
|
|
30
34
|
|
|
31
35
|
private setupHandlers(): void {
|
|
36
|
+
// Tool handlers
|
|
32
37
|
this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
33
38
|
tools: tools.map((t) => t.definition),
|
|
34
39
|
}));
|
|
@@ -40,6 +45,19 @@ export class CacheOverflowServer {
|
|
|
40
45
|
}
|
|
41
46
|
return tool.handler(request.params.arguments ?? {}, this.client);
|
|
42
47
|
});
|
|
48
|
+
|
|
49
|
+
// Prompt handlers
|
|
50
|
+
this.server.setRequestHandler(ListPromptsRequestSchema, async () => ({
|
|
51
|
+
prompts: prompts.map((p) => p.definition),
|
|
52
|
+
}));
|
|
53
|
+
|
|
54
|
+
this.server.setRequestHandler(GetPromptRequestSchema, async (request) => {
|
|
55
|
+
const prompt = prompts.find((p) => p.definition.name === request.params.name);
|
|
56
|
+
if (!prompt) {
|
|
57
|
+
throw new Error(`Unknown prompt: ${request.params.name}`);
|
|
58
|
+
}
|
|
59
|
+
return prompt.handler(request.params.arguments ?? {});
|
|
60
|
+
});
|
|
43
61
|
}
|
|
44
62
|
|
|
45
63
|
async start(): Promise<void> {
|