mirror of
https://github.com/run-llama/mcp-server-llamacloud.git
synced 2026-06-30 20:47:54 -04:00
add llamacloud server
This commit is contained in:
@@ -1,29 +1,14 @@
|
|||||||
# mcp-server-llamacloud MCP Server
|
# LlamaCloud MCP Server
|
||||||
|
|
||||||
A MCP server connecting to a managed index on LlamaCloud
|
A MCP server connecting to a managed index on [LlamaCloud](https://cloud.llamaindex.ai/)
|
||||||
|
|
||||||
This is a TypeScript-based MCP server that implements a simple notes system. It demonstrates core MCP concepts by providing:
|
This is a TypeScript-based MCP server that implements a connection to a managed index on LlamaCloud.
|
||||||
|
|
||||||
- Resources representing text notes with URIs and metadata
|
|
||||||
- Tools for creating new notes
|
|
||||||
- Prompts for generating summaries of notes
|
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
### Resources
|
|
||||||
- List and access notes via `note://` URIs
|
|
||||||
- Each note has a title, content and metadata
|
|
||||||
- Plain text mime type for simple content access
|
|
||||||
|
|
||||||
### Tools
|
### Tools
|
||||||
- `create_note` - Create new text notes
|
- `get_information` - Get information from your knowledge base to answer questions.
|
||||||
- Takes title and content as required parameters
|
- Takes query as required parameters
|
||||||
- Stores note in server state
|
|
||||||
|
|
||||||
### Prompts
|
|
||||||
- `summarize_notes` - Generate a summary of all stored notes
|
|
||||||
- Includes all note contents as embedded resources
|
|
||||||
- Returns structured prompt for LLM summarization
|
|
||||||
|
|
||||||
## Development
|
## Development
|
||||||
|
|
||||||
@@ -52,8 +37,16 @@ On Windows: `%APPDATA%/Claude/claude_desktop_config.json`
|
|||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"mcpServers": {
|
"mcpServers": {
|
||||||
"mcp-server-llamacloud": {
|
"llamacloud": {
|
||||||
"command": "/path/to/mcp-server-llamacloud/build/index.js"
|
"command": "node",
|
||||||
|
"args": [
|
||||||
|
"/path/to/llamacloud/build/index.js",
|
||||||
|
],
|
||||||
|
"env": {
|
||||||
|
"LLAMA_CLOUD_INDEX_NAME": "<YOUR_INDEX_NAME>",
|
||||||
|
"LLAMA_CLOUD_PROJECT_NAME": "<YOUR_PROJECT_NAME>",
|
||||||
|
"LLAMA_CLOUD_API_KEY": "<YOUR_API_KEY>"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Generated
+6676
File diff suppressed because it is too large
Load Diff
+7
-4
@@ -2,7 +2,9 @@
|
|||||||
"name": "mcp-server-llamacloud",
|
"name": "mcp-server-llamacloud",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"description": "A MCP server connecting to a managed index on LlamaCloud",
|
"description": "A MCP server connecting to a managed index on LlamaCloud",
|
||||||
"private": true,
|
"license": "MIT",
|
||||||
|
"author": "LlamaIndex Inc.",
|
||||||
|
"bugs": "https://github.com/run-llama/mcp-server-llamacloud/issues",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"bin": {
|
"bin": {
|
||||||
"mcp-server-llamacloud": "./build/index.js"
|
"mcp-server-llamacloud": "./build/index.js"
|
||||||
@@ -17,10 +19,11 @@
|
|||||||
"inspector": "npx @modelcontextprotocol/inspector build/index.js"
|
"inspector": "npx @modelcontextprotocol/inspector build/index.js"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@modelcontextprotocol/sdk": "0.6.0"
|
"@modelcontextprotocol/sdk": "0.6.0",
|
||||||
|
"llamaindex": "0.8.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^20.11.24",
|
"@types/node": "^22.9.3",
|
||||||
"typescript": "^5.3.3"
|
"typescript": "^5.6.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+26
-141
@@ -1,120 +1,58 @@
|
|||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is a template MCP server that implements a simple notes system.
|
* This is a MCP server that connects to a managed index on LlamaCloud.
|
||||||
* It demonstrates core MCP concepts like resources and tools by allowing:
|
|
||||||
* - Listing notes as resources
|
|
||||||
* - Reading individual notes
|
|
||||||
* - Creating new notes via a tool
|
|
||||||
* - Summarizing all notes via a prompt
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
||||||
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
||||||
|
import { LlamaCloudIndex, MetadataMode } from 'llamaindex';
|
||||||
import {
|
import {
|
||||||
CallToolRequestSchema,
|
CallToolRequestSchema,
|
||||||
ListResourcesRequestSchema,
|
|
||||||
ListToolsRequestSchema,
|
ListToolsRequestSchema,
|
||||||
ReadResourceRequestSchema,
|
|
||||||
ListPromptsRequestSchema,
|
|
||||||
GetPromptRequestSchema,
|
|
||||||
} from "@modelcontextprotocol/sdk/types.js";
|
} from "@modelcontextprotocol/sdk/types.js";
|
||||||
|
|
||||||
/**
|
|
||||||
* Type alias for a note object.
|
|
||||||
*/
|
|
||||||
type Note = { title: string, content: string };
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simple in-memory storage for notes.
|
* Create an MCP server with capabilities for tools
|
||||||
* 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),
|
|
||||||
* tools (to create new notes), and prompts (to summarize notes).
|
|
||||||
*/
|
*/
|
||||||
const server = new Server(
|
const server = new Server(
|
||||||
{
|
{
|
||||||
name: "mcp-server-llamacloud",
|
name: "llamacloud-mcp-server",
|
||||||
version: "0.1.0",
|
version: "0.1.0",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
capabilities: {
|
capabilities: {
|
||||||
resources: {},
|
|
||||||
tools: {},
|
tools: {},
|
||||||
prompts: {},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
const index = new LlamaCloudIndex({
|
||||||
* Handler for listing available notes as resources.
|
name: process.env.LLAMA_CLOUD_INDEX_NAME || (() => { throw new Error('LLAMA_CLOUD_INDEX_NAME is not set') })(),
|
||||||
* Each note is exposed as a resource with:
|
projectName: process.env.LLAMA_CLOUD_PROJECT_NAME || (() => { throw new Error('LLAMA_CLOUD_PROJECT_NAME is not set') })(),
|
||||||
* - A note:// URI scheme
|
apiKey: process.env.LLAMA_CLOUD_API_KEY || (() => { throw new Error('LLAMA_CLOUD_API_KEY is not set') })(),
|
||||||
* - Plain text MIME type
|
|
||||||
* - Human readable name and description (now including the note title)
|
|
||||||
*/
|
|
||||||
server.setRequestHandler(ListResourcesRequestSchema, async () => {
|
|
||||||
return {
|
|
||||||
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.
|
* Handler that lists available tools.
|
||||||
* Exposes a single "create_note" tool that lets clients create new notes.
|
* Exposes a single "get_information" tool that lets clients retrieve information from the LlamaIndex.
|
||||||
*/
|
*/
|
||||||
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
||||||
return {
|
return {
|
||||||
tools: [
|
tools: [
|
||||||
{
|
{
|
||||||
name: "create_note",
|
name: "get_information",
|
||||||
description: "Create a new note",
|
description: "Get information from your knowledge base to answer questions.",
|
||||||
inputSchema: {
|
inputSchema: {
|
||||||
type: "object",
|
type: "object",
|
||||||
properties: {
|
properties: {
|
||||||
title: {
|
query: {
|
||||||
type: "string",
|
type: "string",
|
||||||
description: "Title of the note"
|
description: "The query used to get information about your knowledge base."
|
||||||
},
|
},
|
||||||
content: {
|
|
||||||
type: "string",
|
|
||||||
description: "Text content of the note"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
required: ["title", "content"]
|
required: ["query"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -122,25 +60,27 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handler for the create_note tool.
|
* Handler for the get_information tool.
|
||||||
* Creates a new note with the provided title and content, and returns success message.
|
* Retrieves information from the LlamaIndex and returns the result as text.
|
||||||
*/
|
*/
|
||||||
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
||||||
switch (request.params.name) {
|
switch (request.params.name) {
|
||||||
case "create_note": {
|
case "get_information": {
|
||||||
const title = String(request.params.arguments?.title);
|
const query = String(request.params.arguments?.query);
|
||||||
const content = String(request.params.arguments?.content);
|
if (!query) {
|
||||||
if (!title || !content) {
|
throw new Error("query parameter is required");
|
||||||
throw new Error("Title and content are required");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const id = String(Object.keys(notes).length + 1);
|
const retriever = index.asRetriever();
|
||||||
notes[id] = { title, content };
|
const nodesWithScore = await retriever.retrieve({ query });
|
||||||
|
|
||||||
|
const nodes = nodesWithScore.map((node) => node.node);
|
||||||
|
const context = nodes.map((r) => r.getContent(MetadataMode.NONE)).join("\n\n");
|
||||||
|
|
||||||
return {
|
return {
|
||||||
content: [{
|
content: [{
|
||||||
type: "text",
|
type: "text",
|
||||||
text: `Created note ${id}: ${title}`
|
text: context,
|
||||||
}]
|
}]
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -150,62 +90,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
|
||||||
* Handler that lists available prompts.
|
|
||||||
* Exposes a single "summarize_notes" prompt that summarizes all notes.
|
|
||||||
*/
|
|
||||||
server.setRequestHandler(ListPromptsRequestSchema, async () => {
|
|
||||||
return {
|
|
||||||
prompts: [
|
|
||||||
{
|
|
||||||
name: "summarize_notes",
|
|
||||||
description: "Summarize all notes",
|
|
||||||
}
|
|
||||||
]
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handler for the summarize_notes prompt.
|
|
||||||
* Returns a prompt that requests summarization of all notes, with the notes' contents embedded as resources.
|
|
||||||
*/
|
|
||||||
server.setRequestHandler(GetPromptRequestSchema, async (request) => {
|
|
||||||
if (request.params.name !== "summarize_notes") {
|
|
||||||
throw new Error("Unknown prompt");
|
|
||||||
}
|
|
||||||
|
|
||||||
const embeddedNotes = Object.entries(notes).map(([id, note]) => ({
|
|
||||||
type: "resource" as const,
|
|
||||||
resource: {
|
|
||||||
uri: `note:///${id}`,
|
|
||||||
mimeType: "text/plain",
|
|
||||||
text: note.content
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
return {
|
|
||||||
messages: [
|
|
||||||
{
|
|
||||||
role: "user",
|
|
||||||
content: {
|
|
||||||
type: "text",
|
|
||||||
text: "Please summarize the following notes:"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
...embeddedNotes.map(note => ({
|
|
||||||
role: "user" as const,
|
|
||||||
content: note
|
|
||||||
})),
|
|
||||||
{
|
|
||||||
role: "user",
|
|
||||||
content: {
|
|
||||||
type: "text",
|
|
||||||
text: "Provide a concise summary of all the notes above."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start the server using stdio transport.
|
* Start the server using stdio transport.
|
||||||
|
|||||||
Reference in New Issue
Block a user