-
Notifications
You must be signed in to change notification settings - Fork 0
Add dynamic MCP tools: list_indexes, index_repo, delete_index #15
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
4981a79
427a1bc
6447099
0592040
2ea4cdf
35f06b1
94d91f1
4316cd4
e0fc0f7
975991f
bbed4fc
b781515
44d7569
dcf2386
81b4dbf
c932344
ba57527
2c37861
c9eed14
c9c4ea1
5c35f78
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -37,21 +37,23 @@ import { | |
| CallToolRequestSchema, | ||
| ListToolsRequestSchema, | ||
| } from "@modelcontextprotocol/sdk/types.js"; | ||
| import type { IndexStoreReader } from "../stores/types.js"; | ||
| import type { IndexStoreReader, IndexStore } from "../stores/types.js"; | ||
| import type { Source } from "../sources/types.js"; | ||
| import { MultiIndexRunner } from "./multi-index-runner.js"; | ||
| import { buildClientUserAgent, type MCPClientInfo } from "../core/utils.js"; | ||
| import { | ||
| SEARCH_DESCRIPTION, | ||
| LIST_FILES_DESCRIPTION, | ||
| READ_FILE_DESCRIPTION, | ||
| withListIndexesReference, | ||
| withIndexList, | ||
| } from "./tool-descriptions.js"; | ||
| /** | ||
| * Configuration for the MCP server. | ||
| */ | ||
| export interface MCPServerConfig { | ||
| /** Store to load indexes from */ | ||
| store: IndexStoreReader; | ||
| /** Store to load indexes from (accepts both reader-only and full store) */ | ||
| store: IndexStoreReader | IndexStore; | ||
| /** | ||
| * Index names to expose. If undefined, all indexes in the store are exposed. | ||
| */ | ||
|
|
@@ -71,6 +73,13 @@ export interface MCPServerConfig { | |
| * @default "0.1.0" | ||
| */ | ||
| version?: string; | ||
| /** | ||
| * Discovery mode flag. | ||
| * When true: use withListIndexesReference (no enum in schemas), dynamic index list | ||
| * When false/undefined: use withIndexList (include enum in schemas), static index list | ||
| * @default false | ||
| */ | ||
| discovery?: boolean; | ||
| } | ||
| /** | ||
| * Create an MCP server instance. | ||
|
|
@@ -104,6 +113,7 @@ export async function createMCPServer( | |
| searchOnly: config.searchOnly, | ||
| clientUserAgent, | ||
| }); | ||
|
|
||
| const { indexNames, indexes } = runner; | ||
| const searchOnly = !runner.hasFileOperations(); | ||
| // Format index list for tool descriptions | ||
|
|
@@ -146,13 +156,35 @@ export async function createMCPServer( | |
| required?: string[]; | ||
| }; | ||
| }; | ||
| // Tool descriptions with available indexes (from shared module) | ||
| const searchDescription = withIndexList(SEARCH_DESCRIPTION, indexListStr); | ||
| const listFilesDescription = withIndexList(LIST_FILES_DESCRIPTION, indexListStr); | ||
| const readFileDescription = withIndexList(READ_FILE_DESCRIPTION, indexListStr); | ||
|
|
||
| // Tool descriptions: use enum in fixed mode, reference in discovery mode | ||
| let searchDescription: string; | ||
| let listFilesDescription: string; | ||
| let readFileDescription: string; | ||
|
|
||
| if (config.discovery) { | ||
| // Discovery mode: use reference to list_indexes (no enum) | ||
| searchDescription = withListIndexesReference(SEARCH_DESCRIPTION); | ||
| listFilesDescription = withListIndexesReference(LIST_FILES_DESCRIPTION); | ||
| readFileDescription = withListIndexesReference(READ_FILE_DESCRIPTION); | ||
| } else { | ||
| // Fixed mode: include enum with index list | ||
| searchDescription = withIndexList(SEARCH_DESCRIPTION, indexListStr); | ||
| listFilesDescription = withIndexList(LIST_FILES_DESCRIPTION, indexListStr); | ||
| readFileDescription = withIndexList(READ_FILE_DESCRIPTION, indexListStr); | ||
| } | ||
| // List available tools | ||
| server.setRequestHandler(ListToolsRequestSchema, async () => { | ||
| const tools: Tool[] = [ | ||
| { | ||
| name: "list_indexes", | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The new Severity: low 🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage. |
||
| description: "List all available indexes with their metadata. Call this to discover what indexes are available before using search, list_files, or read_file tools.", | ||
| inputSchema: { | ||
| type: "object", | ||
| properties: {}, | ||
| required: [], | ||
| }, | ||
| }, | ||
| { | ||
| name: "search", | ||
| description: searchDescription, | ||
|
|
@@ -162,7 +194,7 @@ export async function createMCPServer( | |
| index_name: { | ||
| type: "string", | ||
| description: "Name of the index to search.", | ||
| enum: indexNames, | ||
| ...(config.discovery ? {} : { enum: runner.indexes.map(i => i.name) }), | ||
| }, | ||
| query: { | ||
| type: "string", | ||
|
|
@@ -189,7 +221,7 @@ export async function createMCPServer( | |
| index_name: { | ||
| type: "string", | ||
| description: "Name of the index.", | ||
| enum: indexNames, | ||
| ...(config.discovery ? {} : { enum: runner.indexes.map(i => i.name) }), | ||
| }, | ||
| directory: { | ||
| type: "string", | ||
|
|
@@ -220,7 +252,7 @@ export async function createMCPServer( | |
| index_name: { | ||
| type: "string", | ||
| description: "Name of the index.", | ||
| enum: indexNames, | ||
| ...(config.discovery ? {} : { enum: runner.indexes.map(i => i.name) }), | ||
| }, | ||
| path: { | ||
| type: "string", | ||
|
|
@@ -261,6 +293,31 @@ export async function createMCPServer( | |
| // Handle tool calls | ||
| server.setRequestHandler(CallToolRequestSchema, async (request) => { | ||
| const { name, arguments: args } = request.params; | ||
|
|
||
| // Handle list_indexes separately (no index_name required) | ||
| if (name === "list_indexes") { | ||
| try { | ||
| await runner.refreshIndexList(); | ||
| const { indexes } = runner; | ||
| if (indexes.length === 0) { | ||
| return { | ||
| content: [{ type: "text", text: "No indexes available. Use `ctxc index` CLI to create one." }], | ||
| }; | ||
| } | ||
| const lines = indexes.map((i) => | ||
| `- ${i.name} (${i.type}://${i.identifier}) - synced ${i.syncedAt}` | ||
| ); | ||
| return { | ||
| content: [{ type: "text", text: `Available indexes:\n${lines.join("\n")}` }], | ||
| }; | ||
| } catch (error) { | ||
| return { | ||
| content: [{ type: "text", text: `Error listing indexes: ${error}` }], | ||
| isError: true, | ||
| }; | ||
| } | ||
| } | ||
|
|
||
| try { | ||
| const indexName = args?.index_name as string; | ||
| const client = await runner.getClient(indexName); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This branch sets up discovery mode without requiring any indexes, but
MultiIndexRunner.create()still throws when the store has zero valid indexes, soctxc mcp ...can still fail to start on a fresh install. If discovery mode is intended to allow “start empty and index later”, consider aligning runner/server startup behavior with that expectation.Severity: high
Other Locations
src/bin/cmd-mcp.ts:106🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.