ctxpkg 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +661 -0
- package/README.md +282 -0
- package/bin/cli.js +8 -0
- package/bin/daemon.js +7 -0
- package/package.json +70 -0
- package/src/agent/AGENTS.md +249 -0
- package/src/agent/agent.prompts.ts +66 -0
- package/src/agent/agent.test-runner.schemas.ts +158 -0
- package/src/agent/agent.test-runner.ts +436 -0
- package/src/agent/agent.ts +371 -0
- package/src/agent/agent.types.ts +94 -0
- package/src/backend/AGENTS.md +112 -0
- package/src/backend/backend.protocol.ts +95 -0
- package/src/backend/backend.schemas.ts +123 -0
- package/src/backend/backend.services.ts +151 -0
- package/src/backend/backend.ts +111 -0
- package/src/backend/backend.types.ts +34 -0
- package/src/cli/AGENTS.md +213 -0
- package/src/cli/cli.agent.ts +197 -0
- package/src/cli/cli.chat.ts +369 -0
- package/src/cli/cli.client.ts +55 -0
- package/src/cli/cli.collections.ts +491 -0
- package/src/cli/cli.config.ts +252 -0
- package/src/cli/cli.daemon.ts +160 -0
- package/src/cli/cli.documents.ts +413 -0
- package/src/cli/cli.mcp.ts +177 -0
- package/src/cli/cli.ts +28 -0
- package/src/cli/cli.utils.ts +122 -0
- package/src/client/AGENTS.md +135 -0
- package/src/client/client.adapters.ts +279 -0
- package/src/client/client.ts +86 -0
- package/src/client/client.types.ts +17 -0
- package/src/collections/AGENTS.md +185 -0
- package/src/collections/collections.schemas.ts +195 -0
- package/src/collections/collections.ts +1160 -0
- package/src/config/config.ts +118 -0
- package/src/daemon/AGENTS.md +168 -0
- package/src/daemon/daemon.config.ts +23 -0
- package/src/daemon/daemon.manager.ts +215 -0
- package/src/daemon/daemon.schemas.ts +22 -0
- package/src/daemon/daemon.ts +205 -0
- package/src/database/AGENTS.md +211 -0
- package/src/database/database.ts +64 -0
- package/src/database/migrations/migrations.001-init.ts +56 -0
- package/src/database/migrations/migrations.002-fts5.ts +32 -0
- package/src/database/migrations/migrations.ts +20 -0
- package/src/database/migrations/migrations.types.ts +9 -0
- package/src/documents/AGENTS.md +301 -0
- package/src/documents/documents.schemas.ts +190 -0
- package/src/documents/documents.ts +734 -0
- package/src/embedder/embedder.ts +53 -0
- package/src/exports.ts +0 -0
- package/src/mcp/AGENTS.md +264 -0
- package/src/mcp/mcp.ts +105 -0
- package/src/tools/AGENTS.md +228 -0
- package/src/tools/agent/agent.ts +45 -0
- package/src/tools/documents/documents.ts +401 -0
- package/src/tools/tools.langchain.ts +37 -0
- package/src/tools/tools.mcp.ts +46 -0
- package/src/tools/tools.types.ts +35 -0
- package/src/utils/utils.services.ts +46 -0
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { type FeatureExtractionPipeline, pipeline } from '@huggingface/transformers';
|
|
2
|
+
|
|
3
|
+
// Instruction prefix for query embeddings (mxbai-embed format)
|
|
4
|
+
const QUERY_INSTRUCTION = 'Represent this sentence for searching relevant passages: ';
|
|
5
|
+
|
|
6
|
+
class EmbedderService {
|
|
7
|
+
#pipeline?: Promise<FeatureExtractionPipeline>;
|
|
8
|
+
|
|
9
|
+
#setup = async () => {
|
|
10
|
+
const extractor = await pipeline('feature-extraction', 'mixedbread-ai/mxbai-embed-large-v1', {
|
|
11
|
+
dtype: 'fp32',
|
|
12
|
+
});
|
|
13
|
+
return extractor;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
public getExtractor = async () => {
|
|
17
|
+
if (!this.#pipeline) {
|
|
18
|
+
this.#pipeline = this.#setup();
|
|
19
|
+
}
|
|
20
|
+
return await this.#pipeline;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Create embeddings for documents (no instruction prefix).
|
|
25
|
+
* Use this when indexing document chunks.
|
|
26
|
+
*/
|
|
27
|
+
public createDocumentEmbeddings = async (inputs: string[]): Promise<number[][]> => {
|
|
28
|
+
const extractor = await this.getExtractor();
|
|
29
|
+
const output = await extractor(inputs, { pooling: 'cls' });
|
|
30
|
+
return output.tolist();
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Create embedding for a search query (with instruction prefix).
|
|
35
|
+
* Use this when searching for relevant documents.
|
|
36
|
+
*/
|
|
37
|
+
public createQueryEmbedding = async (query: string): Promise<number[]> => {
|
|
38
|
+
const extractor = await this.getExtractor();
|
|
39
|
+
const instructedQuery = `${QUERY_INSTRUCTION}${query}`;
|
|
40
|
+
const output = await extractor([instructedQuery], { pooling: 'cls' });
|
|
41
|
+
return output.tolist()[0];
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* @deprecated Use createDocumentEmbeddings or createQueryEmbedding instead.
|
|
46
|
+
* Kept for backwards compatibility.
|
|
47
|
+
*/
|
|
48
|
+
public createEmbeddings = async (inputs: string[]): Promise<number[][]> => {
|
|
49
|
+
return this.createDocumentEmbeddings(inputs);
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export { EmbedderService };
|
package/src/exports.ts
ADDED
|
File without changes
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
# MCP — Agent Guidelines
|
|
2
|
+
|
|
3
|
+
This document describes the MCP module architecture for AI agents working on this codebase.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
The MCP module provides [Model Context Protocol](https://modelcontextprotocol.io/) server integration. It creates MCP servers that expose ctxpkg's document tools to AI editors like Cursor, Claude Desktop, and other MCP-compatible clients. The server communicates over stdio transport.
|
|
8
|
+
|
|
9
|
+
## File Structure
|
|
10
|
+
|
|
11
|
+
| File | Purpose |
|
|
12
|
+
|------|---------|
|
|
13
|
+
| `mcp.ts` | MCP server creation and stdio runner |
|
|
14
|
+
|
|
15
|
+
## Architecture
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
19
|
+
│ AI Editor / Client │
|
|
20
|
+
│ (Cursor, Claude Desktop, etc.) │
|
|
21
|
+
└──────────────────────────┬──────────────────────────────────┘
|
|
22
|
+
│ stdio (JSON-RPC)
|
|
23
|
+
▼
|
|
24
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
25
|
+
│ MCP Server │
|
|
26
|
+
│ ┌───────────────────────────────────────────────────────┐ │
|
|
27
|
+
│ │ StdioServerTransport │ │
|
|
28
|
+
│ └───────────────────────────────────────────────────────┘ │
|
|
29
|
+
│ │ │
|
|
30
|
+
│ ┌───────────────────────▼───────────────────────────────┐ │
|
|
31
|
+
│ │ McpServer │ │
|
|
32
|
+
│ │ (from @modelcontextprotocol/sdk) │ │
|
|
33
|
+
│ └───────────────────────────────────────────────────────┘ │
|
|
34
|
+
│ │ │
|
|
35
|
+
│ ┌───────────────────────▼───────────────────────────────┐ │
|
|
36
|
+
│ │ Document Tools │ │
|
|
37
|
+
│ │ • documents_list_collections │ │
|
|
38
|
+
│ │ • documents_search │ │
|
|
39
|
+
│ │ • documents_get_document │ │
|
|
40
|
+
│ │ • documents_list_documents │ │
|
|
41
|
+
│ │ • documents_get_outline │ │
|
|
42
|
+
│ │ • documents_get_section │ │
|
|
43
|
+
│ │ • documents_search_batch │ │
|
|
44
|
+
│ │ • documents_find_related │ │
|
|
45
|
+
│ └───────────────────────────────────────────────────────┘ │
|
|
46
|
+
│ │ │
|
|
47
|
+
│ ┌───────────────────────▼───────────────────────────────┐ │
|
|
48
|
+
│ │ BackendClient │ │
|
|
49
|
+
│ │ (connects to daemon/direct) │ │
|
|
50
|
+
│ └───────────────────────────────────────────────────────┘ │
|
|
51
|
+
└─────────────────────────────────────────────────────────────┘
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Usage
|
|
55
|
+
|
|
56
|
+
### Starting the MCP Server
|
|
57
|
+
|
|
58
|
+
Via CLI:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
# Start with all collections
|
|
62
|
+
ctxpkg mcp documents
|
|
63
|
+
|
|
64
|
+
# Limit to specific collections
|
|
65
|
+
ctxpkg mcp documents -c my-docs langchain-docs
|
|
66
|
+
|
|
67
|
+
# Custom server name/version
|
|
68
|
+
ctxpkg mcp documents --name my-server --version 2.0.0
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Programmatic Usage
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
import { createDocumentsMcpServer, runMcpServer } from '#root/mcp/mcp.ts';
|
|
75
|
+
import { createClient } from '#root/client/client.ts';
|
|
76
|
+
|
|
77
|
+
const client = await createClient({ mode: 'daemon' });
|
|
78
|
+
|
|
79
|
+
const server = createDocumentsMcpServer({
|
|
80
|
+
client,
|
|
81
|
+
name: 'my-mcp-server',
|
|
82
|
+
version: '1.0.0',
|
|
83
|
+
aliasMap: new Map([['docs', 'pkg:file://./docs/manifest.json']]),
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
await runMcpServer(server);
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Editor Configuration
|
|
90
|
+
|
|
91
|
+
### Cursor
|
|
92
|
+
|
|
93
|
+
Add to `.cursor/mcp.json`:
|
|
94
|
+
|
|
95
|
+
```json
|
|
96
|
+
{
|
|
97
|
+
"mcpServers": {
|
|
98
|
+
"ctxpkg": {
|
|
99
|
+
"command": "ctxpkg",
|
|
100
|
+
"args": ["mcp", "documents"]
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Claude Desktop
|
|
107
|
+
|
|
108
|
+
Add to Claude Desktop config:
|
|
109
|
+
|
|
110
|
+
```json
|
|
111
|
+
{
|
|
112
|
+
"mcpServers": {
|
|
113
|
+
"ctxpkg": {
|
|
114
|
+
"command": "ctxpkg",
|
|
115
|
+
"args": ["mcp", "documents"]
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Server Modes
|
|
122
|
+
|
|
123
|
+
### Documents Mode (default)
|
|
124
|
+
|
|
125
|
+
Exposes all document tools individually. The calling agent decides which tools to use.
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
ctxpkg mcp documents
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### Agent Mode
|
|
132
|
+
|
|
133
|
+
Exposes a single `ask_documents` tool. An internal LangChain agent handles searching and synthesizes a single answer. This reduces token/context costs for the calling agent.
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
ctxpkg mcp agent
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Requires LLM configuration:
|
|
140
|
+
```bash
|
|
141
|
+
ctxpkg config set llm.apiKey sk-...
|
|
142
|
+
ctxpkg config set llm.model gpt-4o
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## Exposed Tools
|
|
146
|
+
|
|
147
|
+
### Documents Mode
|
|
148
|
+
|
|
149
|
+
The MCP server exposes these tools to AI agents:
|
|
150
|
+
|
|
151
|
+
| Tool | Description |
|
|
152
|
+
|------|-------------|
|
|
153
|
+
| `documents_list_collections` | List available document collections with descriptions and versions |
|
|
154
|
+
| `documents_search` | Semantic search across documents using hybrid vector + keyword matching |
|
|
155
|
+
| `documents_get_document` | Get full document content |
|
|
156
|
+
| `documents_list_documents` | List all documents in a collection (table of contents) |
|
|
157
|
+
| `documents_get_outline` | Get document heading structure without fetching full content |
|
|
158
|
+
| `documents_get_section` | Get a specific section of a document by heading |
|
|
159
|
+
| `documents_search_batch` | Execute multiple search queries in a single call (max 10) |
|
|
160
|
+
| `documents_find_related` | Find content semantically related to a document or chunk |
|
|
161
|
+
|
|
162
|
+
See `src/tools/documents/` for tool implementation details.
|
|
163
|
+
|
|
164
|
+
### Agent Mode
|
|
165
|
+
|
|
166
|
+
| Tool | Description |
|
|
167
|
+
|------|-------------|
|
|
168
|
+
| `ask_documents` | Ask a question with a use case; internal agent searches and synthesizes answer |
|
|
169
|
+
|
|
170
|
+
The `ask_documents` tool requires both a query and a use case to help the agent determine when sufficient information has been found.
|
|
171
|
+
|
|
172
|
+
See `src/tools/agent/` and `src/agent/` for implementation details.
|
|
173
|
+
|
|
174
|
+
## Key Components
|
|
175
|
+
|
|
176
|
+
### `createDocumentsMcpServer(options)`
|
|
177
|
+
|
|
178
|
+
Creates an MCP server instance with document tools:
|
|
179
|
+
|
|
180
|
+
```typescript
|
|
181
|
+
type DocumentsMcpServerOptions = {
|
|
182
|
+
client: BackendClient; // Required: backend connection
|
|
183
|
+
name?: string; // Server name (default: 'ctxpkg-documents')
|
|
184
|
+
version?: string; // Server version (default: '1.0.0')
|
|
185
|
+
collections?: string[]; // Limit to specific collections
|
|
186
|
+
aliasMap?: Map<string, string>; // Project alias → collection ID
|
|
187
|
+
};
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### `createAgentMcpServer(options)`
|
|
191
|
+
|
|
192
|
+
Creates an MCP server with agent mode (single `ask_documents` tool):
|
|
193
|
+
|
|
194
|
+
```typescript
|
|
195
|
+
type AgentMcpServerOptions = {
|
|
196
|
+
client: BackendClient; // Required: backend connection
|
|
197
|
+
llmConfig: LLMConfig; // Required: LLM configuration
|
|
198
|
+
name?: string; // Server name (default: 'ctxpkg-agent')
|
|
199
|
+
version?: string; // Server version (default: '1.0.0')
|
|
200
|
+
aliasMap?: Map<string, string>; // Project alias → collection ID
|
|
201
|
+
maxIterations?: number; // Max agent iterations (default: 15)
|
|
202
|
+
};
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### `runMcpServer(server)`
|
|
206
|
+
|
|
207
|
+
Connects the server to stdio transport and handles shutdown:
|
|
208
|
+
|
|
209
|
+
- Creates `StdioServerTransport`
|
|
210
|
+
- Connects server to transport
|
|
211
|
+
- Registers SIGINT/SIGTERM handlers for graceful shutdown
|
|
212
|
+
|
|
213
|
+
## Adding New MCP Servers
|
|
214
|
+
|
|
215
|
+
To create an MCP server with different tools:
|
|
216
|
+
|
|
217
|
+
```typescript
|
|
218
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
219
|
+
import { registerMcpTools } from '#root/tools/tools.mcp.ts';
|
|
220
|
+
|
|
221
|
+
const createMyMcpServer = (options: MyOptions) => {
|
|
222
|
+
const server = new McpServer({
|
|
223
|
+
name: options.name ?? 'my-server',
|
|
224
|
+
version: options.version ?? '1.0.0',
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
// Create tool definitions
|
|
228
|
+
const tools = createMyToolDefinitions(options);
|
|
229
|
+
|
|
230
|
+
// Register on MCP server
|
|
231
|
+
registerMcpTools(server, tools);
|
|
232
|
+
|
|
233
|
+
return server;
|
|
234
|
+
};
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
Then add a CLI command in `cli.mcp.ts` to start it.
|
|
238
|
+
|
|
239
|
+
## Key Patterns
|
|
240
|
+
|
|
241
|
+
### Alias Resolution
|
|
242
|
+
|
|
243
|
+
Project aliases (from `context.json`) are resolved to collection IDs:
|
|
244
|
+
|
|
245
|
+
```typescript
|
|
246
|
+
const aliasMap = new Map<string, string>();
|
|
247
|
+
for (const [alias, spec] of Object.entries(projectConfig.collections)) {
|
|
248
|
+
const collectionId = collectionsService.computeCollectionId(spec, cwd);
|
|
249
|
+
aliasMap.set(alias, collectionId);
|
|
250
|
+
}
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
This allows users to search by friendly names like `"langchain"` instead of `"pkg:https://..."`.
|
|
254
|
+
|
|
255
|
+
### Graceful Shutdown
|
|
256
|
+
|
|
257
|
+
The server handles shutdown signals to close cleanly:
|
|
258
|
+
|
|
259
|
+
```typescript
|
|
260
|
+
process.on('SIGINT', async () => {
|
|
261
|
+
await server.close();
|
|
262
|
+
process.exit(0);
|
|
263
|
+
});
|
|
264
|
+
```
|
package/src/mcp/mcp.ts
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
3
|
+
|
|
4
|
+
import { createDocumentAgent, type CreateDocumentAgentOptions } from '#root/agent/agent.ts';
|
|
5
|
+
import type { LLMConfig } from '#root/agent/agent.types.ts';
|
|
6
|
+
import type { BackendClient } from '#root/client/client.ts';
|
|
7
|
+
import { createAgentToolDefinitions } from '#root/tools/agent/agent.ts';
|
|
8
|
+
import { createDocumentToolDefinitions } from '#root/tools/documents/documents.ts';
|
|
9
|
+
import { registerMcpTools } from '#root/tools/tools.mcp.ts';
|
|
10
|
+
|
|
11
|
+
type McpServerOptions = {
|
|
12
|
+
/** Name of the MCP server */
|
|
13
|
+
name?: string;
|
|
14
|
+
/** Version of the MCP server */
|
|
15
|
+
version?: string;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
type DocumentsMcpServerOptions = McpServerOptions & {
|
|
19
|
+
/** Backend client for accessing the documents service */
|
|
20
|
+
client: BackendClient;
|
|
21
|
+
/** Collections to limit searches to (optional, uses cwd and default collections if not specified) */
|
|
22
|
+
collections?: string[];
|
|
23
|
+
/** Optional map of project aliases to collection IDs */
|
|
24
|
+
aliasMap?: Map<string, string>;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
type AgentMcpServerOptions = McpServerOptions & {
|
|
28
|
+
/** Backend client for accessing the documents service */
|
|
29
|
+
client: BackendClient;
|
|
30
|
+
/** LLM configuration for the agent */
|
|
31
|
+
llmConfig: LLMConfig;
|
|
32
|
+
/** Optional map of project aliases to collection IDs */
|
|
33
|
+
aliasMap?: Map<string, string>;
|
|
34
|
+
/** Maximum agent iterations */
|
|
35
|
+
maxIterations?: number;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Create an MCP server with document tools.
|
|
40
|
+
*/
|
|
41
|
+
const createDocumentsMcpServer = (options: DocumentsMcpServerOptions) => {
|
|
42
|
+
const { client, aliasMap, name = 'ctxpkg-documents', version = '1.0.0' } = options;
|
|
43
|
+
|
|
44
|
+
const server = new McpServer({
|
|
45
|
+
name,
|
|
46
|
+
version,
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
// Create and register document tools
|
|
50
|
+
const documentTools = createDocumentToolDefinitions({ client, aliasMap });
|
|
51
|
+
registerMcpTools(server, documentTools);
|
|
52
|
+
|
|
53
|
+
return server;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Create an MCP server with agent mode (single ask_documents tool).
|
|
58
|
+
* The internal agent uses LLM to search and synthesize answers.
|
|
59
|
+
*/
|
|
60
|
+
const createAgentMcpServer = (options: AgentMcpServerOptions) => {
|
|
61
|
+
const { client, aliasMap, llmConfig, maxIterations, name = 'ctxpkg-agent', version = '1.0.0' } = options;
|
|
62
|
+
|
|
63
|
+
const server = new McpServer({
|
|
64
|
+
name,
|
|
65
|
+
version,
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
// Create document agent
|
|
69
|
+
const agentOptions: CreateDocumentAgentOptions = {
|
|
70
|
+
client,
|
|
71
|
+
llmConfig,
|
|
72
|
+
aliasMap,
|
|
73
|
+
maxIterations,
|
|
74
|
+
};
|
|
75
|
+
const agent = createDocumentAgent(agentOptions);
|
|
76
|
+
|
|
77
|
+
// Create and register agent tools (just ask_documents)
|
|
78
|
+
const agentTools = createAgentToolDefinitions({ agent });
|
|
79
|
+
registerMcpTools(server, agentTools);
|
|
80
|
+
|
|
81
|
+
return server;
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Run an MCP server over stdio transport.
|
|
86
|
+
* This is the main entry point for running as a standalone MCP server.
|
|
87
|
+
*/
|
|
88
|
+
const runMcpServer = async (server: McpServer) => {
|
|
89
|
+
const transport = new StdioServerTransport();
|
|
90
|
+
await server.connect(transport);
|
|
91
|
+
|
|
92
|
+
// Handle graceful shutdown
|
|
93
|
+
process.on('SIGINT', async () => {
|
|
94
|
+
await server.close();
|
|
95
|
+
process.exit(0);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
process.on('SIGTERM', async () => {
|
|
99
|
+
await server.close();
|
|
100
|
+
process.exit(0);
|
|
101
|
+
});
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
export { createAgentMcpServer, createDocumentsMcpServer, runMcpServer };
|
|
105
|
+
export type { AgentMcpServerOptions, DocumentsMcpServerOptions, McpServerOptions };
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
# Tools — Agent Guidelines
|
|
2
|
+
|
|
3
|
+
This document describes the tools module architecture for AI agents working on this codebase.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
The tools module provides AI agent tools in a framework-agnostic format. Tools are defined once using a common format and can be adapted to different runtimes (MCP, LangChain). This allows the same tool logic to work across different AI frameworks.
|
|
8
|
+
|
|
9
|
+
## File Structure
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
src/tools/
|
|
13
|
+
├── tools.types.ts # Common tool definition types
|
|
14
|
+
├── tools.mcp.ts # MCP server adapter
|
|
15
|
+
├── tools.langchain.ts # LangChain adapter
|
|
16
|
+
├── documents/
|
|
17
|
+
│ └── documents.ts # Document tools
|
|
18
|
+
├── files/
|
|
19
|
+
│ └── files.ts # File system tools (legacy)
|
|
20
|
+
└── git/
|
|
21
|
+
└── git.ts # Git tools (legacy)
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Architecture
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
28
|
+
│ Tool Definitions │
|
|
29
|
+
│ (framework-agnostic format) │
|
|
30
|
+
│ │
|
|
31
|
+
│ defineTool({ │
|
|
32
|
+
│ name: 'tool_name', │
|
|
33
|
+
│ description: '...', │
|
|
34
|
+
│ schema: z.object({...}), │
|
|
35
|
+
│ handler: async (input) => {...} │
|
|
36
|
+
│ }) │
|
|
37
|
+
└─────────────────────────────────────────────────────────────┘
|
|
38
|
+
│
|
|
39
|
+
┌───────────────┴───────────────┐
|
|
40
|
+
▼ ▼
|
|
41
|
+
┌─────────────────────┐ ┌─────────────────────┐
|
|
42
|
+
│ tools.mcp.ts │ │ tools.langchain.ts │
|
|
43
|
+
│ registerMcpTools() │ │ toLangchainTools() │
|
|
44
|
+
└─────────────────────┘ └─────────────────────┘
|
|
45
|
+
│ │
|
|
46
|
+
▼ ▼
|
|
47
|
+
┌─────────────────────┐ ┌─────────────────────┐
|
|
48
|
+
│ MCP Server │ │ LangChain Agent │
|
|
49
|
+
└─────────────────────┘ └─────────────────────┘
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Tool Definition Format
|
|
53
|
+
|
|
54
|
+
Tools use a common format with Zod schemas:
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
import { defineTool } from '#root/tools/tools.types.ts';
|
|
58
|
+
import * as z from 'zod';
|
|
59
|
+
|
|
60
|
+
const myTool = defineTool({
|
|
61
|
+
name: 'my_tool_name',
|
|
62
|
+
description: 'What the tool does and when to use it',
|
|
63
|
+
schema: z.object({
|
|
64
|
+
query: z.string().describe('Parameter description'),
|
|
65
|
+
limit: z.number().optional().default(10),
|
|
66
|
+
}),
|
|
67
|
+
handler: async ({ query, limit }) => {
|
|
68
|
+
// Tool logic here
|
|
69
|
+
return { result: 'data' };
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Key Fields
|
|
75
|
+
|
|
76
|
+
| Field | Purpose |
|
|
77
|
+
|-------|---------|
|
|
78
|
+
| `name` | Unique identifier (use snake_case with category prefix) |
|
|
79
|
+
| `description` | Help AI understand when/how to use the tool |
|
|
80
|
+
| `schema` | Zod schema for input validation with `.describe()` on fields |
|
|
81
|
+
| `handler` | Async function that executes the tool logic |
|
|
82
|
+
|
|
83
|
+
## Using Tools
|
|
84
|
+
|
|
85
|
+
### With MCP Server
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
89
|
+
import { registerMcpTools } from '#root/tools/tools.mcp.ts';
|
|
90
|
+
import { createDocumentToolDefinitions } from '#root/tools/documents/documents.ts';
|
|
91
|
+
|
|
92
|
+
const server = new McpServer({ name: 'my-server', version: '1.0.0' });
|
|
93
|
+
const tools = createDocumentToolDefinitions({ client });
|
|
94
|
+
|
|
95
|
+
registerMcpTools(server, tools);
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### With LangChain
|
|
99
|
+
|
|
100
|
+
```typescript
|
|
101
|
+
import { toLangchainTools } from '#root/tools/tools.langchain.ts';
|
|
102
|
+
import { createDocumentToolDefinitions } from '#root/tools/documents/documents.ts';
|
|
103
|
+
|
|
104
|
+
const definitions = createDocumentToolDefinitions({ client });
|
|
105
|
+
const langchainTools = toLangchainTools(definitions);
|
|
106
|
+
|
|
107
|
+
// Use with LangChain agent
|
|
108
|
+
const agent = createToolCallingAgent({ tools: Object.values(langchainTools), ... });
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Adding New Tools
|
|
112
|
+
|
|
113
|
+
### 1. Create Tool Definitions
|
|
114
|
+
|
|
115
|
+
Create a new file in appropriate category folder:
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
// src/tools/myfeature/myfeature.ts
|
|
119
|
+
import * as z from 'zod';
|
|
120
|
+
import { defineTool, type ToolDefinitions } from '#root/tools/tools.types.ts';
|
|
121
|
+
|
|
122
|
+
type MyFeatureToolOptions = {
|
|
123
|
+
client: BackendClient;
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
const createMyFeatureToolDefinitions = (options: MyFeatureToolOptions): ToolDefinitions => {
|
|
127
|
+
const { client } = options;
|
|
128
|
+
|
|
129
|
+
const doSomething = defineTool({
|
|
130
|
+
name: 'myfeature_do_something',
|
|
131
|
+
description: 'Does something useful. Use this when...',
|
|
132
|
+
schema: z.object({
|
|
133
|
+
input: z.string().describe('The input to process'),
|
|
134
|
+
}),
|
|
135
|
+
handler: async ({ input }) => {
|
|
136
|
+
const result = await client.myFeature.process({ input });
|
|
137
|
+
return result;
|
|
138
|
+
},
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
return { doSomething };
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
export { createMyFeatureToolDefinitions };
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### 2. Register on MCP Server
|
|
148
|
+
|
|
149
|
+
In `src/mcp/mcp.ts` or relevant MCP setup:
|
|
150
|
+
|
|
151
|
+
```typescript
|
|
152
|
+
import { createMyFeatureToolDefinitions } from '#root/tools/myfeature/myfeature.ts';
|
|
153
|
+
|
|
154
|
+
const tools = createMyFeatureToolDefinitions({ client });
|
|
155
|
+
registerMcpTools(server, tools);
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## Tool Categories
|
|
159
|
+
|
|
160
|
+
### Document Tools (`documents/`)
|
|
161
|
+
|
|
162
|
+
Tools for searching and retrieving indexed documentation:
|
|
163
|
+
|
|
164
|
+
- `documents_list_collections` — List available collections with descriptions and versions
|
|
165
|
+
- `documents_search` — Semantic search across documents with hybrid vector + keyword matching
|
|
166
|
+
- `documents_get_document` — Get full document content
|
|
167
|
+
- `documents_list_documents` — List all documents in a collection (table of contents)
|
|
168
|
+
- `documents_get_outline` — Get document heading structure without fetching full content
|
|
169
|
+
- `documents_get_section` — Get a specific section of a document by heading
|
|
170
|
+
- `documents_search_batch` — Execute multiple search queries in a single call
|
|
171
|
+
- `documents_find_related` — Find content semantically related to a document or chunk
|
|
172
|
+
|
|
173
|
+
### File Tools (`files/`) — Legacy
|
|
174
|
+
|
|
175
|
+
Direct file system access tools (LangChain format):
|
|
176
|
+
|
|
177
|
+
- `file_get_content` — Read file content
|
|
178
|
+
- `file_glob_files` — Find files by glob pattern
|
|
179
|
+
- `file_search_multiline` — Search file contents with regex
|
|
180
|
+
- `file_get_stats` — Get file metadata
|
|
181
|
+
|
|
182
|
+
### Git Tools (`git/`) — Legacy
|
|
183
|
+
|
|
184
|
+
Git repository tools (LangChain format):
|
|
185
|
+
|
|
186
|
+
- `git_status` — Repository status
|
|
187
|
+
- `git_get_diff` — File diffs
|
|
188
|
+
- `git_get_log` — Commit history
|
|
189
|
+
|
|
190
|
+
## Best Practices
|
|
191
|
+
|
|
192
|
+
### Naming
|
|
193
|
+
|
|
194
|
+
- Use category prefix: `documents_`, `files_`, `git_`
|
|
195
|
+
- Use snake_case: `documents_list_collections`
|
|
196
|
+
- Be descriptive: `search` → `documents_search`
|
|
197
|
+
|
|
198
|
+
### Descriptions
|
|
199
|
+
|
|
200
|
+
Write descriptions that help AI agents understand:
|
|
201
|
+
- What the tool does
|
|
202
|
+
- When to use it
|
|
203
|
+
- What input it expects
|
|
204
|
+
- What output it returns
|
|
205
|
+
|
|
206
|
+
```typescript
|
|
207
|
+
description:
|
|
208
|
+
'Search reference documents using semantic similarity. ' +
|
|
209
|
+
'Returns the most relevant document chunks for the given query. ' +
|
|
210
|
+
'Use this to find information in documentation, guides, or other indexed reference materials.',
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### Schema Descriptions
|
|
214
|
+
|
|
215
|
+
Add `.describe()` to all schema fields:
|
|
216
|
+
|
|
217
|
+
```typescript
|
|
218
|
+
schema: z.object({
|
|
219
|
+
query: z.string().describe('The search query - describe what information you are looking for'),
|
|
220
|
+
limit: z.number().optional().default(10).describe('Maximum number of results to return'),
|
|
221
|
+
}),
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### Return Values
|
|
225
|
+
|
|
226
|
+
- Return structured data (objects/arrays) — adapters handle JSON serialization
|
|
227
|
+
- Return helpful error messages as strings
|
|
228
|
+
- Include relevant context in results
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import * as z from 'zod';
|
|
2
|
+
|
|
3
|
+
import type { DocumentAgent } from '#root/agent/agent.ts';
|
|
4
|
+
import { defineTool, type ToolDefinitions } from '#root/tools/tools.types.ts';
|
|
5
|
+
|
|
6
|
+
type AgentToolOptions = {
|
|
7
|
+
/** Document agent instance */
|
|
8
|
+
agent: DocumentAgent;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Creates the ask_documents tool definition for agent mode MCP.
|
|
13
|
+
* This exposes a single tool that uses an internal agent to search and synthesize.
|
|
14
|
+
*/
|
|
15
|
+
const createAgentToolDefinitions = (options: AgentToolOptions): ToolDefinitions => {
|
|
16
|
+
const { agent } = options;
|
|
17
|
+
|
|
18
|
+
const askDocuments = defineTool({
|
|
19
|
+
name: 'ask_documents',
|
|
20
|
+
description:
|
|
21
|
+
'Ask a question about the indexed documentation. An internal agent will search, ' +
|
|
22
|
+
'read relevant sections, and synthesize a comprehensive answer. Returns only the ' +
|
|
23
|
+
'final answer, not intermediate search results. Requires both a query and a use case ' +
|
|
24
|
+
'to help determine when sufficient information has been found.',
|
|
25
|
+
schema: z.object({
|
|
26
|
+
query: z.string().describe('The question to answer. Be specific about what information you need.'),
|
|
27
|
+
use_case: z
|
|
28
|
+
.string()
|
|
29
|
+
.describe(
|
|
30
|
+
'Why you need this information and how it will be used. ' +
|
|
31
|
+
'This helps determine when enough information has been found. ' +
|
|
32
|
+
'Example: "I need to understand authentication flow to implement login in my app"',
|
|
33
|
+
),
|
|
34
|
+
}),
|
|
35
|
+
handler: async ({ query, use_case }) => {
|
|
36
|
+
const response = await agent.ask(query, use_case);
|
|
37
|
+
return response;
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
return { askDocuments };
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export { createAgentToolDefinitions };
|
|
45
|
+
export type { AgentToolOptions };
|