@tigerdata/mcp-boilerplate 1.5.2 → 1.6.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/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/skills/utils.js +4 -0
- package/dist/skills/utils.spec.js +23 -2
- package/dist/store.d.ts +22 -0
- package/dist/{cache.js → store.js} +11 -1
- package/package.json +1 -1
- package/dist/cache.d.ts +0 -15
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
export { Cache } from './cache.js';
|
|
2
1
|
export { cliEntrypoint } from './cliEntrypoint.js';
|
|
3
2
|
export { httpServerFactory } from './httpServer.js';
|
|
4
3
|
export { log } from './logger.js';
|
|
@@ -6,5 +5,6 @@ export type { AdditionalSetupArgs } from './mcpServer.js';
|
|
|
6
5
|
export { registerExitHandlers } from './registerExitHandlers.js';
|
|
7
6
|
export { StatusError } from './StatusError.js';
|
|
8
7
|
export { stdioServerFactory } from './stdio.js';
|
|
8
|
+
export { ArrayStore, Store } from './store.js';
|
|
9
9
|
export { addAiResultToSpan, withSpan } from './tracing.js';
|
|
10
10
|
export type { ApiFactory, InferSchema, McpFeatureFlags, MigrationsConfig, ParsedQs, PromptFactory, ResourceFactory, } from './types.js';
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
export { Cache } from './cache.js';
|
|
2
1
|
export { cliEntrypoint } from './cliEntrypoint.js';
|
|
3
2
|
export { httpServerFactory } from './httpServer.js';
|
|
4
3
|
export { log } from './logger.js';
|
|
5
4
|
export { registerExitHandlers } from './registerExitHandlers.js';
|
|
6
5
|
export { StatusError } from './StatusError.js';
|
|
7
6
|
export { stdioServerFactory } from './stdio.js';
|
|
7
|
+
export { ArrayStore, Store } from './store.js';
|
|
8
8
|
export { addAiResultToSpan, withSpan } from './tracing.js';
|
package/dist/skills/utils.js
CHANGED
|
@@ -168,6 +168,8 @@ const doLoadSkills = async (octokit) => {
|
|
|
168
168
|
for (const entry of dirEntries) {
|
|
169
169
|
if (entry.isFile())
|
|
170
170
|
continue;
|
|
171
|
+
if (entry.name.startsWith('.'))
|
|
172
|
+
continue;
|
|
171
173
|
if (!entry.isDirectory()) {
|
|
172
174
|
log.warn(`Skipping non-directory entry in local_collection`, {
|
|
173
175
|
path: `${cfg.path}/${entry.name}`,
|
|
@@ -214,6 +216,8 @@ const doLoadSkills = async (octokit) => {
|
|
|
214
216
|
for (const entry of dirResponse.data) {
|
|
215
217
|
if (entry.type === 'file')
|
|
216
218
|
continue;
|
|
219
|
+
if (entry.name.startsWith('.'))
|
|
220
|
+
continue;
|
|
217
221
|
if (entry.type !== 'dir') {
|
|
218
222
|
log.warn(`Skipping non-directory entry in github_collection`, {
|
|
219
223
|
path: `${cfg.repo}/${entry.path}`,
|
|
@@ -6,7 +6,7 @@ describe('Skills API', () => {
|
|
|
6
6
|
describe('getAvailableSkillNames', () => {
|
|
7
7
|
it('returns a comma-separated list of visible skill names in alphabetical order when skills are loaded', async () => {
|
|
8
8
|
const names = await getAvailableSkillNames({});
|
|
9
|
-
expect(names).toBe('first-skill, second-skill');
|
|
9
|
+
expect(names).toBe('collection-a, collection-b, first-skill, second-skill');
|
|
10
10
|
});
|
|
11
11
|
it('returns "(none)" when flags filter out every skill (e.g. enabledSkills does not match any)', async () => {
|
|
12
12
|
const names = await getAvailableSkillNames({
|
|
@@ -36,11 +36,13 @@ describe('Skills API', () => {
|
|
|
36
36
|
expect(result).toContain('<available_skills>');
|
|
37
37
|
expect(result).toContain('first-skill');
|
|
38
38
|
expect(result).toContain('second-skill');
|
|
39
|
+
expect(result).toContain('collection-a');
|
|
40
|
+
expect(result).toContain('collection-b');
|
|
39
41
|
const inner = result
|
|
40
42
|
.split('<available_skills>')[1]
|
|
41
43
|
.split('</available_skills>')[0];
|
|
42
44
|
const lines = inner.trim().split('\n');
|
|
43
|
-
expect(lines).toHaveLength(
|
|
45
|
+
expect(lines).toHaveLength(5);
|
|
44
46
|
});
|
|
45
47
|
it('read valid skill: returns the content of the skill SKILL.md when name and path are valid', async () => {
|
|
46
48
|
const result = await viewSkillContent({
|
|
@@ -107,4 +109,23 @@ describe('Skills API', () => {
|
|
|
107
109
|
})).rejects.toThrow(InvalidPathError);
|
|
108
110
|
});
|
|
109
111
|
});
|
|
112
|
+
describe('local_collection', () => {
|
|
113
|
+
it('loads every real skill directory inside the collection', async () => {
|
|
114
|
+
const names = await getAvailableSkillNames({});
|
|
115
|
+
expect(names).toContain('collection-a');
|
|
116
|
+
expect(names).toContain('collection-b');
|
|
117
|
+
});
|
|
118
|
+
it('exposes collection skill content via viewSkillContent', async () => {
|
|
119
|
+
const result = await viewSkillContent({
|
|
120
|
+
name: 'collection-a',
|
|
121
|
+
path: 'SKILL.md',
|
|
122
|
+
});
|
|
123
|
+
expect(result).toBe('Collection skill A content\n');
|
|
124
|
+
});
|
|
125
|
+
it('skips dot-prefixed directories (e.g. .github) even when they contain a valid SKILL.md', async () => {
|
|
126
|
+
const names = await getAvailableSkillNames({});
|
|
127
|
+
expect(names).not.toContain('dot-github-trap');
|
|
128
|
+
await expect(viewSkillContent({ name: 'dot-github-trap', path: 'SKILL.md' })).rejects.toBeInstanceOf(SkillNotFoundError);
|
|
129
|
+
});
|
|
130
|
+
});
|
|
110
131
|
});
|
package/dist/store.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
interface StoreProps<T> {
|
|
2
|
+
fetch: () => Promise<T>;
|
|
3
|
+
ttl?: number;
|
|
4
|
+
}
|
|
5
|
+
export declare class Store<T> {
|
|
6
|
+
private contents;
|
|
7
|
+
private fetch;
|
|
8
|
+
private ttl?;
|
|
9
|
+
private expirationDateTime?;
|
|
10
|
+
constructor({ fetch, ttl }: StoreProps<T>);
|
|
11
|
+
get(): Promise<T>;
|
|
12
|
+
}
|
|
13
|
+
interface ArrayStoreProps<T> {
|
|
14
|
+
fetch: () => Promise<T[]>;
|
|
15
|
+
ttl?: number;
|
|
16
|
+
}
|
|
17
|
+
export declare class ArrayStore<T> extends Store<T[]> {
|
|
18
|
+
constructor({ fetch, ttl }: ArrayStoreProps<T>);
|
|
19
|
+
find(predicate: (item: T) => boolean): Promise<T | null>;
|
|
20
|
+
filter(predicate: (item: T) => boolean): Promise<T[]>;
|
|
21
|
+
}
|
|
22
|
+
export {};
|
|
@@ -1,20 +1,30 @@
|
|
|
1
|
-
export class
|
|
1
|
+
export class Store {
|
|
2
2
|
contents = null;
|
|
3
3
|
fetch;
|
|
4
|
+
ttl;
|
|
4
5
|
expirationDateTime;
|
|
5
6
|
constructor({ fetch, ttl }) {
|
|
6
7
|
this.fetch = fetch;
|
|
7
8
|
if (ttl) {
|
|
9
|
+
this.ttl = ttl;
|
|
8
10
|
this.expirationDateTime = Date.now() + ttl;
|
|
9
11
|
}
|
|
10
12
|
}
|
|
11
13
|
async get() {
|
|
12
14
|
if (this.expirationDateTime && Date.now() > this.expirationDateTime) {
|
|
13
15
|
this.contents = null;
|
|
16
|
+
if (this.ttl) {
|
|
17
|
+
this.expirationDateTime = Date.now() + this.ttl;
|
|
18
|
+
}
|
|
14
19
|
}
|
|
15
20
|
this.contents ??= this.fetch();
|
|
16
21
|
return this.contents;
|
|
17
22
|
}
|
|
23
|
+
}
|
|
24
|
+
export class ArrayStore extends Store {
|
|
25
|
+
constructor({ fetch, ttl }) {
|
|
26
|
+
super({ fetch, ttl });
|
|
27
|
+
}
|
|
18
28
|
async find(predicate) {
|
|
19
29
|
const items = await this.get();
|
|
20
30
|
return items.find(predicate) ?? null;
|
package/package.json
CHANGED
package/dist/cache.d.ts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
interface CacheProps<T> {
|
|
2
|
-
contents?: T;
|
|
3
|
-
fetch: () => Promise<T[]>;
|
|
4
|
-
ttl?: number;
|
|
5
|
-
}
|
|
6
|
-
export declare class Cache<T> {
|
|
7
|
-
private contents;
|
|
8
|
-
private fetch;
|
|
9
|
-
private expirationDateTime?;
|
|
10
|
-
constructor({ fetch, ttl }: CacheProps<T>);
|
|
11
|
-
get(): Promise<T[]>;
|
|
12
|
-
find(predicate: (item: T) => boolean): Promise<T | null>;
|
|
13
|
-
filter(predicate: (item: T) => boolean): Promise<T[]>;
|
|
14
|
-
}
|
|
15
|
-
export {};
|