Skip to content

Commit 576d549

Browse files
committed
Add list_gist_prompts tool
1 parent b3cfa2e commit 576d549

File tree

10 files changed

+66
-29
lines changed

10 files changed

+66
-29
lines changed

.vscode/mcp.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@
44
"type": "promptString",
55
"password": true,
66
"id": "github_token",
7-
"description": "Github token"
7+
"description": "Github PAT w/gist scope"
88
}
99
],
1010
"servers": {
11-
"gistpad": {
11+
"GistPad (Dev)": {
1212
"type": "stdio",
1313
"command": "node",
1414
"args": ["build/index.js"],

.vscode/settings.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,6 @@
22
"editor.formatOnSave": true,
33
"editor.codeActionsOnSave": {
44
"source.organizeImports": "explicit"
5-
}
5+
},
6+
"gistpad.mcp.enabled": false
67
}

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 📆 v0.4.8 (07/07/2025)
2+
3+
- Added a `list_gist_prompts` tool
4+
15
## 📆 v0.4.7 (06/18/2025)
26

37
- Renamed the prompt tools to include `gist` in the name: `add_prompt` -> `add_gist_prompt`, `delete_prompt` -> `delete_gist_prompt`.

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ Once your client it setup, you can start having fun with gists + MCP! 🥳 For e
118118

119119
### Prompts
120120

121+
- `list_gist_prompts` - List the prompts in your prompts collection.
121122
- `add_gist_prompt` - Add a new prompt to your prompts collection.
122123
- `delete_gist_prompt` - Delete a prompt from your collection.
123124

package-lock.json

Lines changed: 7 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "gistpad-mcp",
3-
"version": "0.4.7",
3+
"version": "0.4.8",
44
"description": "An MCP server for managing your personal knowledge, daily notes, and reusable prompts via GitHub Gists.",
55
"type": "module",
66
"bin": {
@@ -25,7 +25,7 @@
2525
"inspector": "npx @modelcontextprotocol/inspector build/index.js"
2626
},
2727
"dependencies": {
28-
"@modelcontextprotocol/sdk": "^1.12.3",
28+
"@modelcontextprotocol/sdk": "^1.15.0",
2929
"axios": "^1.10.0",
3030
"gray-matter": "^4.0.3"
3131
},

src/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ class GistpadServer {
4747
this.server = new Server(
4848
{
4949
name: "gistpad",
50-
version: "0.4.7",
50+
version: "0.4.8",
5151
},
5252
{
5353
capabilities: {
@@ -71,7 +71,7 @@ class GistpadServer {
7171
listChanged: true,
7272
},
7373
},
74-
instructions: `GistPad allows you to manage your personal knowledge/daily notes/todos, and create re-usable AI prompts, using GitHub Gists.
74+
instructions: `GistPad allows you to manage your personal knowledge/daily notes/todos, and create re-usable prompts, using GitHub Gists.
7575
To read gists, notes, and gist comments, prefer using the available resources vs. tools. And then use the available tools to create, update, delete, archive, star, etc. your gists.`,
7676
}
7777
);

src/resources/gists.ts

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {
66
mcpGist,
77
} from "../utils.js";
88

9-
const RESOURCE_PREFIX = "gist://";
9+
const RESOURCE_PREFIX = "gist:///";
1010

1111
export const resourceHandlers: ResourceHandlers = {
1212
listResourceTemplates: () => ({
@@ -48,15 +48,17 @@ export const resourceHandlers: ResourceHandlers = {
4848
let name = gist.description?.trim();
4949
if (!name) {
5050
const firstFile = Object.keys(gist.files)[0];
51-
if (firstFile !== "README.md") {
52-
// Strip the extension of markdown files, since
53-
// we'll treat those as pseudo descriptions.
54-
name = firstFile.replace(/\.md$/i, "");
55-
} else {
51+
if (!firstFile) {
52+
name = "Empty";
53+
} else if (firstFile === "README.md") {
5654
// Explicity mark this as "Untitled", since the file
5755
// name isn't unique enough to be used as a name, and
5856
// we want to draw attention to it.
5957
name = "Untitled";
58+
} else {
59+
// Strip the extension off markdown files, since
60+
// we'll treat those as pseudo descriptions.
61+
name = firstFile.replace(/\.md$/i, "");
6062
}
6163
}
6264

@@ -70,11 +72,9 @@ export const resourceHandlers: ResourceHandlers = {
7072
},
7173

7274
readResource: async (uri, context) => {
73-
const url = new URL(uri);
74-
const path = url.host + (url.pathname ? "/" + url.pathname : "");
75-
76-
if (path.endsWith("/comments")) {
77-
const response = await context.axiosInstance.get(`/${url.host}/comments`);
75+
const { pathname } = new URL(uri);
76+
if (pathname.endsWith("/comments")) {
77+
const response = await context.axiosInstance.get(pathname);
7878
return {
7979
contents: [
8080
{
@@ -86,7 +86,7 @@ export const resourceHandlers: ResourceHandlers = {
8686
};
8787
}
8888

89-
const { data: gist } = await context.axiosInstance.get(`/${path}`);
89+
const { data: gist } = await context.axiosInstance.get(pathname);
9090
context.gistStore.update(gist);
9191

9292
const resource = {
@@ -96,7 +96,7 @@ export const resourceHandlers: ResourceHandlers = {
9696
};
9797

9898
// Note: Nothing uses this at the moment, but it could be useful in the future.
99-
if (path.endsWith("/raw")) {
99+
if (pathname.endsWith("/raw")) {
100100
const mainFile: GistFile =
101101
gist.files["README.md"] || Object.keys(gist.files)[0]!;
102102

src/store.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,10 +80,17 @@ export abstract class GistStore {
8080
const oldGist = this.cache[index];
8181
this.cache[index] = gist;
8282

83+
// If the gist didn't actually change, we don't need to notify.
84+
if (oldGist.updated_at === gist.updated_at) {
85+
return;
86+
}
87+
8388
if (isPromptGist(gist)) {
8489
this.notifyPromptListChanged();
8590
} else {
86-
// If the description changed, the list of resources has changed
91+
// The resource list only includes the gist ID and
92+
// description, so we only need to notify clients to
93+
// update the list when a gist's description changes.
8794
if (oldGist.description !== gist.description) {
8895
this.notifyResourceListChanged();
8996
}

src/tools/prompts.ts

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,15 @@ interface AddPromptArgs {
1616

1717
export default {
1818
definitions: [
19+
{
20+
name: "list_gist_prompts",
21+
description: "List the prompts in your gist-based prompts collection",
22+
inputSchema: {
23+
type: "object",
24+
properties: {},
25+
required: [],
26+
},
27+
},
1928
{
2029
name: "delete_gist_prompt",
2130
description: "Delete a prompt from your gist-based prompts collection",
@@ -75,6 +84,22 @@ export default {
7584
],
7685

7786
handlers: {
87+
list_gist_prompts: async (_, context) => {
88+
const promptsGist = await context.gistStore.getPrompts();
89+
if (!promptsGist) {
90+
return {
91+
prompts: [],
92+
}
93+
}
94+
95+
const prompts = Object.keys(promptsGist.files)
96+
.map(filename => filename.replace(/\.md$/, ""));
97+
98+
return {
99+
prompts,
100+
};
101+
},
102+
78103
delete_gist_prompt: async (args: unknown, context) => {
79104
const { name } = args as { name: string };
80105

@@ -188,8 +213,6 @@ export default {
188213
context.gistStore.update(updatedGist);
189214
}
190215

191-
await context.server.sendPromptListChanged();
192-
193216
return `Successfully added prompt "${name}" to prompts collection`;
194217
},
195218
},

0 commit comments

Comments
 (0)