Refactor/expand into a more substantial example
This commit is contained in:
parent
b9fd2fb444
commit
d8a8c6ee01
1 changed files with 112 additions and 16 deletions
|
|
@ -1,12 +1,38 @@
|
|||
#!/usr/bin/env node
|
||||
/**
|
||||
* This is a template MCP server that implements a simple notes system.
|
||||
* It demonstrates core MCP concepts like resources and tools by allowing:
|
||||
* - Listing notes as resources
|
||||
* - Reading individual notes
|
||||
* - Creating new notes via a tool
|
||||
*/
|
||||
|
||||
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
||||
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
||||
import {
|
||||
CallToolRequestSchema,
|
||||
ListResourcesRequestSchema,
|
||||
ListToolsRequestSchema,
|
||||
ReadResourceRequestSchema,
|
||||
} from "@modelcontextprotocol/sdk/types.js";
|
||||
|
||||
/**
|
||||
* Type alias for a note object.
|
||||
*/
|
||||
type Note = { title: string, content: string };
|
||||
|
||||
/**
|
||||
* Simple in-memory storage for notes.
|
||||
* In a real implementation, this would likely be backed by a database.
|
||||
*/
|
||||
const notes: { [id: string]: Note } = {
|
||||
"1": { title: "First Note", content: "This is note 1" },
|
||||
"2": { title: "Second Note", content: "This is note 2" }
|
||||
};
|
||||
|
||||
/**
|
||||
* Create an MCP server with capabilities for resources (to list/read notes)
|
||||
* and tools (to create new notes).
|
||||
*/
|
||||
const server = new Server(
|
||||
{
|
||||
name: "<%= name %>",
|
||||
|
|
@ -17,41 +43,111 @@ const server = new Server(
|
|||
resources: {},
|
||||
tools: {},
|
||||
},
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* Handler for listing available notes as resources.
|
||||
* Each note is exposed as a resource with:
|
||||
* - A note:// URI scheme
|
||||
* - Plain text MIME type
|
||||
* - Human readable name and description (now including the note title)
|
||||
*/
|
||||
server.setRequestHandler(ListResourcesRequestSchema, async () => {
|
||||
return {
|
||||
resources: [
|
||||
{
|
||||
uri: "example://hello",
|
||||
mimeType: "text/plain",
|
||||
name: "Example resource",
|
||||
},
|
||||
],
|
||||
resources: Object.entries(notes).map(([id, note]) => ({
|
||||
uri: `note:///${id}`,
|
||||
mimeType: "text/plain",
|
||||
name: note.title,
|
||||
description: `A text note: ${note.title}`
|
||||
}))
|
||||
};
|
||||
});
|
||||
|
||||
/**
|
||||
* Handler for reading the contents of a specific note.
|
||||
* Takes a note:// URI and returns the note content as plain text.
|
||||
*/
|
||||
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
||||
const url = new URL(request.params.uri);
|
||||
const id = url.pathname.replace(/^\//, '');
|
||||
const note = notes[id];
|
||||
|
||||
if (!note) {
|
||||
throw new Error(`Note ${id} not found`);
|
||||
}
|
||||
|
||||
return {
|
||||
contents: [{
|
||||
uri: request.params.uri,
|
||||
mimeType: "text/plain",
|
||||
text: note.content
|
||||
}]
|
||||
};
|
||||
});
|
||||
|
||||
/**
|
||||
* Handler that lists available tools.
|
||||
* Exposes a single "create_note" tool that lets clients create new notes.
|
||||
*/
|
||||
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
||||
return {
|
||||
tools: [
|
||||
{
|
||||
name: "example",
|
||||
description: "An example tool",
|
||||
name: "create_note",
|
||||
description: "Create a new note",
|
||||
inputSchema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
message: {
|
||||
title: {
|
||||
type: "string",
|
||||
description: "Message to echo",
|
||||
description: "Title of the note"
|
||||
},
|
||||
content: {
|
||||
type: "string",
|
||||
description: "Text content of the note"
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
required: ["title", "content"]
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
});
|
||||
|
||||
/**
|
||||
* Handler for the create_note tool.
|
||||
* Creates a new note with the provided title and content, and returns success message.
|
||||
*/
|
||||
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
||||
switch (request.params.name) {
|
||||
case "create_note": {
|
||||
const title = String(request.params.arguments?.title);
|
||||
const content = String(request.params.arguments?.content);
|
||||
if (!title || !content) {
|
||||
throw new Error("Title and content are required");
|
||||
}
|
||||
|
||||
const id = String(Object.keys(notes).length + 1);
|
||||
notes[id] = { title, content };
|
||||
|
||||
return {
|
||||
content: [{
|
||||
type: "text",
|
||||
text: `Created note ${id}: ${title}`
|
||||
}]
|
||||
};
|
||||
}
|
||||
|
||||
default:
|
||||
throw new Error("Unknown tool");
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Start the server using stdio transport.
|
||||
* This allows the server to communicate via standard input/output streams.
|
||||
*/
|
||||
async function main() {
|
||||
const transport = new StdioServerTransport();
|
||||
await server.connect(transport);
|
||||
|
|
|
|||
Loading…
Reference in a new issue