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+ */
28
39import { Server } from "@modelcontextprotocol/sdk/server/index.js";
410import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
511import {
12+ CallToolRequestSchema,
613 ListResourcesRequestSchema,
714 ListToolsRequestSchema,
15+ ReadResourceRequestSchema,
816} from "@modelcontextprotocol/sdk/types.js";
917
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+ */
1036const server = new Server(
1137 {
1238 name: "<%= name %> ",
@@ -17,41 +43,111 @@ const server = new Server(
1743 resources: {},
1844 tools: {},
1945 },
20- } ,
46+ }
2147);
2248
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+ */
2356server.setRequestHandler(ListResourcesRequestSchema, async () => {
2457 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+ }]
3286 };
3387});
3488
89+ /**
90+ * Handler that lists available tools.
91+ * Exposes a single "create_note" tool that lets clients create new notes.
92+ */
3593server.setRequestHandler(ListToolsRequestSchema, async () => {
3694 return {
3795 tools: [
3896 {
39- name : "example " ,
40- description : "An example tool " ,
97+ name: "create_note ",
98+ description: "Create a new note ",
4199 inputSchema: {
42100 type: "object",
43101 properties: {
44- message : {
102+ title : {
45103 type: "string",
46- description : "Message to echo" ,
104+ description: "Title of the note"
47105 },
106+ content: {
107+ type: "string",
108+ description: "Text content of the note"
109+ }
48110 },
49- } ,
50- } ,
51- ] ,
111+ required: ["title", "content"]
112+ }
113+ }
114+ ]
52115 };
53116});
54117
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+ */
55151async function main() {
56152 const transport = new StdioServerTransport();
57153 await server.connect(transport);
0 commit comments