1
- #!/usr/bin/env node
1
+ /**
2
+ * This is a template MCP server that implements a simple notes system.
3
+ * It demonstrates core MCP concepts like resources and tools by allowing:
4
+ * - Listing notes as resources
5
+ * - Reading individual notes
6
+ * - Creating new notes via a tool
7
+ */
2
8
3
9
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
4
10
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
5
11
import {
12
+ CallToolRequestSchema,
6
13
ListResourcesRequestSchema,
7
14
ListToolsRequestSchema,
15
+ ReadResourceRequestSchema,
8
16
} from "@modelcontextprotocol/sdk/types.js";
9
17
18
+ /**
19
+ * Type alias for a note object.
20
+ */
21
+ type Note = { title: string, content: string };
22
+
23
+ /**
24
+ * Simple in-memory storage for notes.
25
+ * In a real implementation, this would likely be backed by a database.
26
+ */
27
+ const notes: { [id: string]: Note } = {
28
+ "1": { title: "First Note", content: "This is note 1" },
29
+ "2": { title: "Second Note", content: "This is note 2" }
30
+ };
31
+
32
+ /**
33
+ * Create an MCP server with capabilities for resources (to list/read notes)
34
+ * and tools (to create new notes).
35
+ */
10
36
const server = new Server(
11
37
{
12
38
name: "<%= name %> ",
@@ -17,41 +43,111 @@ const server = new Server(
17
43
resources: {},
18
44
tools: {},
19
45
},
20
- } ,
46
+ }
21
47
);
22
48
49
+ /**
50
+ * Handler for listing available notes as resources.
51
+ * Each note is exposed as a resource with:
52
+ * - A note:// URI scheme
53
+ * - Plain text MIME type
54
+ * - Human readable name and description (now including the note title)
55
+ */
23
56
server.setRequestHandler(ListResourcesRequestSchema, async () => {
24
57
return {
25
- resources : [
26
- {
27
- uri : "example://hello" ,
28
- mimeType : "text/plain" ,
29
- name : "Example resource" ,
30
- } ,
31
- ] ,
58
+ resources: Object.entries(notes).map(([id, note]) => ({
59
+ uri: `note:///${id}`,
60
+ mimeType: "text/plain",
61
+ name: note.title,
62
+ description: `A text note: ${note.title}`
63
+ }))
64
+ };
65
+ });
66
+
67
+ /**
68
+ * Handler for reading the contents of a specific note.
69
+ * Takes a note:// URI and returns the note content as plain text.
70
+ */
71
+ server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
72
+ const url = new URL(request.params.uri);
73
+ const id = url.pathname.replace(/^\//, '');
74
+ const note = notes[id];
75
+
76
+ if (!note) {
77
+ throw new Error(`Note ${id} not found`);
78
+ }
79
+
80
+ return {
81
+ contents: [{
82
+ uri: request.params.uri,
83
+ mimeType: "text/plain",
84
+ text: note.content
85
+ }]
32
86
};
33
87
});
34
88
89
+ /**
90
+ * Handler that lists available tools.
91
+ * Exposes a single "create_note" tool that lets clients create new notes.
92
+ */
35
93
server.setRequestHandler(ListToolsRequestSchema, async () => {
36
94
return {
37
95
tools: [
38
96
{
39
- name : "example " ,
40
- description : "An example tool " ,
97
+ name: "create_note ",
98
+ description: "Create a new note ",
41
99
inputSchema: {
42
100
type: "object",
43
101
properties: {
44
- message : {
102
+ title : {
45
103
type: "string",
46
- description : "Message to echo" ,
104
+ description: "Title of the note"
47
105
},
106
+ content: {
107
+ type: "string",
108
+ description: "Text content of the note"
109
+ }
48
110
},
49
- } ,
50
- } ,
51
- ] ,
111
+ required: ["title", "content"]
112
+ }
113
+ }
114
+ ]
52
115
};
53
116
});
54
117
118
+ /**
119
+ * Handler for the create_note tool.
120
+ * Creates a new note with the provided title and content, and returns success message.
121
+ */
122
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
123
+ switch (request.params.name) {
124
+ case "create_note": {
125
+ const title = String(request.params.arguments?.title);
126
+ const content = String(request.params.arguments?.content);
127
+ if (!title || !content) {
128
+ throw new Error("Title and content are required");
129
+ }
130
+
131
+ const id = String(Object.keys(notes).length + 1);
132
+ notes[id] = { title, content };
133
+
134
+ return {
135
+ content: [{
136
+ type: "text",
137
+ text: `Created note ${id}: ${title}`
138
+ }]
139
+ };
140
+ }
141
+
142
+ default:
143
+ throw new Error("Unknown tool");
144
+ }
145
+ });
146
+
147
+ /**
148
+ * Start the server using stdio transport.
149
+ * This allows the server to communicate via standard input/output streams.
150
+ */
55
151
async function main() {
56
152
const transport = new StdioServerTransport();
57
153
await server.connect(transport);
0 commit comments