feat: add multi-index with description

This commit is contained in:
Marcus Schiesser
2025-03-23 13:14:07 +02:00
parent c33b21b1be
commit 127e82c918
2 changed files with 144 additions and 53 deletions
+26 -6
View File
@@ -1,16 +1,17 @@
# LlamaCloud MCP Server
A MCP server connecting to a managed index on [LlamaCloud](https://cloud.llamaindex.ai/)
A MCP server connecting to multiple managed indexes on [LlamaCloud](https://cloud.llamaindex.ai/)
This is a TypeScript-based MCP server that implements a connection to a managed index on LlamaCloud.
This is a TypeScript-based MCP server that creates multiple tools, each connected to a specific managed index on LlamaCloud. Each tool is defined through command-line arguments.
<a href="https://glama.ai/mcp/servers/o4fcj7x2cg"><img width="380" height="200" src="https://glama.ai/mcp/servers/o4fcj7x2cg/badge" alt="LlamaCloud Server MCP server" /></a>
## Features
### Tools
- `get_information` - Get information from your knowledge base to answer questions.
- Takes query as required parameters
- Creates a separate tool for each index you define
- Each tool provides a `query` parameter to search its specific index
- Auto-generates tool names like `get_information_index_name` based on index names
## Development
@@ -42,10 +43,11 @@ On Windows: `%APPDATA%/Claude/claude_desktop_config.json`
"llamacloud": {
"command": "node",
"args": [
"/path/to/llamacloud/build/index.js"
"/path/to/llamacloud/build/index.js",
"--index", "10k-SEC-Tesla", "--description", "10k SEC documents from 2023 for Tesla",
"--index", "10k-SEC-Apple", "--description", "10k SEC documents from 2023 for Apple"
],
"env": {
"LLAMA_CLOUD_INDEX_NAME": "<YOUR_INDEX_NAME>",
"LLAMA_CLOUD_PROJECT_NAME": "<YOUR_PROJECT_NAME>",
"LLAMA_CLOUD_API_KEY": "<YOUR_API_KEY>"
}
@@ -54,6 +56,24 @@ On Windows: `%APPDATA%/Claude/claude_desktop_config.json`
}
```
### Tool Definition Format
You can define multiple tools by providing pairs of `--index` and `--description` arguments. Each tool definition follows this format:
```
--index "IndexName" --description "Description text"
```
For example:
```bash
node build/index.js --index "10k-SEC-Tesla" --description "10k SEC documents from 2023 for Tesla" --index "10k-SEC-Apple" --description "10k SEC documents from 2023 for Apple"
```
This will create two tools:
1. `get_information_10k_sec_tesla` - For querying the 10k-SEC-Tesla index
2. `get_information_10k_sec_apple` - For querying the 10k-SEC-Apple index
### Debugging
Since MCP servers communicate over stdio, debugging can be challenging. We recommend using the [MCP Inspector](https://github.com/modelcontextprotocol/inspector), which is available as a package script:
+92 -21
View File
@@ -1,7 +1,8 @@
#!/usr/bin/env node
/**
* This is a MCP server that connects to a managed index on LlamaCloud.
* This is a MCP server that connects to multiple managed indexes on LlamaCloud.
* Each index is exposed as a separate tool.
*/
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
@@ -12,6 +13,58 @@ import {
ListToolsRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
// Define the tool definition interface
interface ToolDefinition {
indexName: string;
description: string;
toolName?: string;
}
// Parse command line arguments
function parseToolDefinitions(): ToolDefinition[] {
const args = process.argv.slice(2);
if (args.length === 0) {
console.error('No tool definitions provided. Use format: --index "IndexName" --description "Description"');
process.exit(1);
}
const toolDefinitions: ToolDefinition[] = [];
let currentIndexName: string | null = null;
for (let i = 0; i < args.length; i++) {
if (args[i] === '--index' && i + 1 < args.length) {
// Save the current index name. We'll wait for the description to complete the definition
currentIndexName = args[i + 1].trim();
i++; // Skip the next argument since we consumed it
} else if (args[i] === '--description' && i + 1 < args.length && currentIndexName) {
// We have both an index name and a description, so we can create a tool definition
const description = args[i + 1].trim();
const toolName = `get_information_${currentIndexName.toLowerCase().replace(/[^a-z0-9]/g, '_')}`;
toolDefinitions.push({
indexName: currentIndexName,
description,
toolName
});
// Reset for the next pair
currentIndexName = null;
i++; // Skip the next argument since we consumed it
}
}
// Check if we have an index without a description at the end
if (currentIndexName) {
console.warn(`Warning: Index '${currentIndexName}' was specified without a description.`);
}
if (toolDefinitions.length === 0) {
console.error('No valid tool definitions found. Use format: --index "IndexName" --description "Description"');
process.exit(1);
}
return toolDefinitions;
}
/**
* Create an MCP server with capabilities for tools
@@ -28,44 +81,62 @@ const server = new Server(
}
);
// Get the project name and API key from environment variables
const projectName = process.env.LLAMA_CLOUD_PROJECT_NAME || (() => { throw new Error('LLAMA_CLOUD_PROJECT_NAME is not set') })();
const apiKey = process.env.LLAMA_CLOUD_API_KEY || (() => { throw new Error('LLAMA_CLOUD_API_KEY is not set') })();
// Parse tool definitions from command line arguments
const toolDefinitions = parseToolDefinitions();
// Create indexes for each tool definition
const indexes = new Map<string, LlamaCloudIndex>();
for (const definition of toolDefinitions) {
const index = new LlamaCloudIndex({
name: process.env.LLAMA_CLOUD_INDEX_NAME || (() => { throw new Error('LLAMA_CLOUD_INDEX_NAME is not set') })(),
projectName: process.env.LLAMA_CLOUD_PROJECT_NAME || (() => { throw new Error('LLAMA_CLOUD_PROJECT_NAME is not set') })(),
apiKey: process.env.LLAMA_CLOUD_API_KEY || (() => { throw new Error('LLAMA_CLOUD_API_KEY is not set') })(),
name: definition.indexName,
projectName,
apiKey,
});
indexes.set(definition.toolName!, index);
console.log(`Created index for tool ${definition.toolName}: ${definition.indexName} - ${definition.description}`);
}
/**
* Handler that lists available tools.
* Exposes a single "get_information" tool that lets clients retrieve information from the LlamaIndex.
* Exposes a tool for each index that lets clients retrieve information.
*/
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: "get_information",
description: "Get information from your knowledge base to answer questions.",
tools: toolDefinitions.map(definition => ({
name: definition.toolName!,
description: `Get information from the ${definition.indexName} index. The index contains ${definition.description}`,
inputSchema: {
type: "object",
properties: {
query: {
type: "string",
description: "The query used to get information about your knowledge base."
description: `The query used to get information from the ${definition.indexName} index.`
},
},
required: ["query"]
}
}
]
}))
};
});
/**
* Handler for the get_information tool.
* Retrieves information from the LlamaIndex and returns the result as text.
* Handler for tool calls.
* Routes requests to the appropriate index based on the tool name.
*/
server.setRequestHandler(CallToolRequestSchema, async (request) => {
switch (request.params.name) {
case "get_information": {
const toolName = request.params.name;
const index = indexes.get(toolName);
if (!index) {
throw new Error(`Unknown tool: ${toolName}`);
}
const query = String(request.params.arguments?.query);
if (!query) {
throw new Error("query parameter is required");
@@ -83,11 +154,6 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
text: context,
}]
};
}
default:
throw new Error("Unknown tool");
}
});
@@ -97,6 +163,11 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
* This allows the server to communicate via standard input/output streams.
*/
async function main() {
console.log(`Starting MCP server with ${toolDefinitions.length} tools:`);
toolDefinitions.forEach(def => {
console.log(`- ${def.toolName}: ${def.indexName} - ${def.description}`);
});
const transport = new StdioServerTransport();
await server.connect(transport);
}