midnight-mcp 0.0.4 → 0.0.5
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/README.md +33 -52
- package/dist/tools/search.d.ts +2 -2
- package/dist/tools/search.js +70 -4
- package/dist/utils/config.d.ts +16 -12
- package/dist/utils/config.js +25 -8
- package/dist/utils/hosted-api.d.ts +61 -0
- package/dist/utils/hosted-api.js +106 -0
- package/dist/utils/index.d.ts +3 -1
- package/dist/utils/index.js +3 -1
- package/package.json +1 -2
package/README.md
CHANGED
|
@@ -17,29 +17,21 @@ Add to your `claude_desktop_config.json`:
|
|
|
17
17
|
}
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
-
Restart Claude Desktop.
|
|
21
|
-
|
|
22
|
-
> **Note:** Search features won't work well without the full setup below.
|
|
20
|
+
Restart Claude Desktop. All features work out of the box—no API keys or setup required.
|
|
23
21
|
|
|
24
22
|
---
|
|
25
23
|
|
|
26
|
-
##
|
|
27
|
-
|
|
28
|
-
To enable semantic search across Midnight contracts and docs:
|
|
29
|
-
|
|
30
|
-
### 1. Start ChromaDB
|
|
24
|
+
## How It Works
|
|
31
25
|
|
|
32
|
-
|
|
26
|
+
By default, the MCP uses a **hosted API** for semantic search:
|
|
33
27
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
28
|
+
- ✅ **Zero configuration** — just install and use
|
|
29
|
+
- ✅ **Semantic search** works immediately
|
|
30
|
+
- ✅ **No API keys** needed
|
|
37
31
|
|
|
38
|
-
###
|
|
32
|
+
### Local Mode (Optional)
|
|
39
33
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
### 3. Update your config
|
|
34
|
+
Run everything locally for privacy or offline use:
|
|
43
35
|
|
|
44
36
|
```json
|
|
45
37
|
{
|
|
@@ -48,6 +40,7 @@ Needed for generating embeddings. Get one at [platform.openai.com/api-keys](http
|
|
|
48
40
|
"command": "npx",
|
|
49
41
|
"args": ["-y", "midnight-mcp"],
|
|
50
42
|
"env": {
|
|
43
|
+
"MIDNIGHT_LOCAL": "true",
|
|
51
44
|
"OPENAI_API_KEY": "sk-...",
|
|
52
45
|
"CHROMA_URL": "http://localhost:8000"
|
|
53
46
|
}
|
|
@@ -56,15 +49,17 @@ Needed for generating embeddings. Get one at [platform.openai.com/api-keys](http
|
|
|
56
49
|
}
|
|
57
50
|
```
|
|
58
51
|
|
|
59
|
-
|
|
52
|
+
Local mode requires ChromaDB (`docker run -d -p 8000:8000 chromadb/chroma`) and an OpenAI API key.
|
|
53
|
+
|
|
54
|
+
### GitHub Token (Optional)
|
|
60
55
|
|
|
61
|
-
Add `"GITHUB_TOKEN": "ghp_..."`
|
|
56
|
+
Add `"GITHUB_TOKEN": "ghp_..."` for higher GitHub API rate limits (60 → 5000 requests/hour).
|
|
62
57
|
|
|
63
58
|
---
|
|
64
59
|
|
|
65
|
-
##
|
|
60
|
+
## Features
|
|
66
61
|
|
|
67
|
-
### Tools (
|
|
62
|
+
### Tools (16)
|
|
68
63
|
|
|
69
64
|
| Tool | Description |
|
|
70
65
|
| --------------------------------- | --------------------------------------- |
|
|
@@ -82,10 +77,12 @@ Add `"GITHUB_TOKEN": "ghp_..."` to increase API rate limits from 60 to 5000 requ
|
|
|
82
77
|
| `midnight-get-file-at-version` | Get file at specific version |
|
|
83
78
|
| `midnight-compare-syntax` | Compare files between versions |
|
|
84
79
|
| `midnight-get-latest-syntax` | Latest syntax reference |
|
|
80
|
+
| `midnight-health-check` | Check server health status |
|
|
81
|
+
| `midnight-get-status` | Get rate limits and cache stats |
|
|
85
82
|
|
|
86
|
-
### Resources (20
|
|
83
|
+
### Resources (20)
|
|
87
84
|
|
|
88
|
-
- `midnight://docs/*` — Documentation (Compact reference, SDK API, ZK concepts
|
|
85
|
+
- `midnight://docs/*` — Documentation (Compact reference, SDK API, ZK concepts)
|
|
89
86
|
- `midnight://code/*` — Examples, patterns, and templates
|
|
90
87
|
- `midnight://schema/*` — AST, transaction, and proof schemas
|
|
91
88
|
|
|
@@ -94,27 +91,14 @@ Add `"GITHUB_TOKEN": "ghp_..."` to increase API rate limits from 60 to 5000 requ
|
|
|
94
91
|
- `midnight-create-contract` — Create new contracts
|
|
95
92
|
- `midnight-review-contract` — Security review
|
|
96
93
|
- `midnight-explain-concept` — Learn Midnight concepts
|
|
94
|
+
- `midnight-compare-approaches` — Compare implementation approaches
|
|
97
95
|
- `midnight-debug-contract` — Debug issues
|
|
98
96
|
|
|
99
97
|
---
|
|
100
98
|
|
|
101
|
-
## How Environment Variables Work
|
|
102
|
-
|
|
103
|
-
The npm package contains no secrets. **You provide your own credentials** via the `env` block in your config:
|
|
104
|
-
|
|
105
|
-
| Variable | Required | Without It | With It |
|
|
106
|
-
| ---------------- | -------- | -------------------------------------- | -------------------- |
|
|
107
|
-
| `GITHUB_TOKEN` | No | 60 API calls/hour, may hit rate limits | 5,000 calls/hour |
|
|
108
|
-
| `OPENAI_API_KEY` | No | Keyword search only (no embeddings) | Semantic search |
|
|
109
|
-
| `CHROMA_URL` | No | In-memory search, no persistence | Persistent vector DB |
|
|
110
|
-
|
|
111
|
-
Your tokens stay on your machine and are only used to access services on your behalf.
|
|
112
|
-
|
|
113
|
-
---
|
|
114
|
-
|
|
115
99
|
## Developer Setup
|
|
116
100
|
|
|
117
|
-
For contributors
|
|
101
|
+
For contributors:
|
|
118
102
|
|
|
119
103
|
```bash
|
|
120
104
|
git clone https://github.com/Olanetsoft/midnight-mcp.git
|
|
@@ -124,26 +108,23 @@ npm run build
|
|
|
124
108
|
npm test
|
|
125
109
|
```
|
|
126
110
|
|
|
127
|
-
###
|
|
111
|
+
### Testing with Local API
|
|
112
|
+
|
|
113
|
+
To test against a local API server instead of production:
|
|
128
114
|
|
|
129
115
|
```bash
|
|
130
|
-
|
|
131
|
-
|
|
116
|
+
# Terminal 1: Start local API
|
|
117
|
+
cd api
|
|
118
|
+
npm install
|
|
119
|
+
npm run dev # Starts at http://localhost:8787
|
|
120
|
+
|
|
121
|
+
# Terminal 2: Run MCP with local API
|
|
122
|
+
MIDNIGHT_API_URL=http://localhost:8787 npm start
|
|
132
123
|
```
|
|
133
124
|
|
|
134
|
-
###
|
|
125
|
+
### API Backend
|
|
135
126
|
|
|
136
|
-
|
|
137
|
-
src/
|
|
138
|
-
├── index.ts # Entry point
|
|
139
|
-
├── server.ts # MCP server handlers
|
|
140
|
-
├── tools/ # Search, analysis, repository tools
|
|
141
|
-
├── resources/ # Docs, code, schema providers
|
|
142
|
-
├── prompts/ # Prompt templates
|
|
143
|
-
├── pipeline/ # GitHub sync & parsing
|
|
144
|
-
├── db/ # ChromaDB integration
|
|
145
|
-
└── utils/ # Config & logging
|
|
146
|
-
```
|
|
127
|
+
The hosted API runs on Cloudflare Workers + Vectorize. See [api/README.md](./api/README.md) for deployment and development instructions.
|
|
147
128
|
|
|
148
129
|
## License
|
|
149
130
|
|
package/dist/tools/search.d.ts
CHANGED
|
@@ -50,11 +50,11 @@ export declare const SearchDocsInputSchema: z.ZodObject<{
|
|
|
50
50
|
}, "strip", z.ZodTypeAny, {
|
|
51
51
|
query: string;
|
|
52
52
|
limit: number;
|
|
53
|
-
category: "
|
|
53
|
+
category: "all" | "guides" | "api" | "concepts";
|
|
54
54
|
}, {
|
|
55
55
|
query: string;
|
|
56
56
|
limit?: number | undefined;
|
|
57
|
-
category?: "
|
|
57
|
+
category?: "all" | "guides" | "api" | "concepts" | undefined;
|
|
58
58
|
}>;
|
|
59
59
|
export type SearchCompactInput = z.infer<typeof SearchCompactInputSchema>;
|
|
60
60
|
export type SearchTypeScriptInput = z.infer<typeof SearchTypeScriptInputSchema>;
|
package/dist/tools/search.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { vectorStore } from "../db/index.js";
|
|
3
|
-
import { logger, validateQuery, validateNumber, searchCache, createCacheKey, } from "../utils/index.js";
|
|
3
|
+
import { logger, validateQuery, validateNumber, searchCache, createCacheKey, isHostedMode, searchCompactHosted, searchTypeScriptHosted, searchDocsHosted, } from "../utils/index.js";
|
|
4
4
|
// Schema definitions for tool inputs
|
|
5
5
|
export const SearchCompactInputSchema = z.object({
|
|
6
6
|
query: z.string().describe("Natural language search query for Compact code"),
|
|
@@ -62,7 +62,7 @@ export async function searchCompact(input) {
|
|
|
62
62
|
const limit = limitValidation.value;
|
|
63
63
|
logger.debug("Searching Compact code", {
|
|
64
64
|
query: sanitizedQuery,
|
|
65
|
-
|
|
65
|
+
mode: isHostedMode() ? "hosted" : "local",
|
|
66
66
|
});
|
|
67
67
|
// Check cache first
|
|
68
68
|
const cacheKey = createCacheKey("compact", sanitizedQuery, limit, input.filter?.repository);
|
|
@@ -71,6 +71,26 @@ export async function searchCompact(input) {
|
|
|
71
71
|
logger.debug("Search cache hit", { cacheKey });
|
|
72
72
|
return cached;
|
|
73
73
|
}
|
|
74
|
+
// Use hosted API if in hosted mode
|
|
75
|
+
if (isHostedMode()) {
|
|
76
|
+
try {
|
|
77
|
+
const response = await searchCompactHosted(sanitizedQuery, limit);
|
|
78
|
+
searchCache.set(cacheKey, response);
|
|
79
|
+
return {
|
|
80
|
+
...response,
|
|
81
|
+
...(queryValidation.warnings.length > 0 && {
|
|
82
|
+
warnings: queryValidation.warnings,
|
|
83
|
+
}),
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
logger.warn("Hosted API search failed, falling back to local", {
|
|
88
|
+
error: String(error),
|
|
89
|
+
});
|
|
90
|
+
// Fall through to local search
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
// Local search (fallback or when in local mode)
|
|
74
94
|
const filter = {
|
|
75
95
|
language: "compact",
|
|
76
96
|
...input.filter,
|
|
@@ -118,7 +138,10 @@ export async function searchTypeScript(input) {
|
|
|
118
138
|
});
|
|
119
139
|
const sanitizedQuery = queryValidation.sanitized;
|
|
120
140
|
const limit = limitValidation.value;
|
|
121
|
-
logger.debug("Searching TypeScript code", {
|
|
141
|
+
logger.debug("Searching TypeScript code", {
|
|
142
|
+
query: sanitizedQuery,
|
|
143
|
+
mode: isHostedMode() ? "hosted" : "local",
|
|
144
|
+
});
|
|
122
145
|
// Check cache
|
|
123
146
|
const cacheKey = createCacheKey("typescript", sanitizedQuery, limit, input.includeTypes, input.includeExamples);
|
|
124
147
|
const cached = searchCache.get(cacheKey);
|
|
@@ -126,6 +149,26 @@ export async function searchTypeScript(input) {
|
|
|
126
149
|
logger.debug("Search cache hit", { cacheKey });
|
|
127
150
|
return cached;
|
|
128
151
|
}
|
|
152
|
+
// Use hosted API if in hosted mode
|
|
153
|
+
if (isHostedMode()) {
|
|
154
|
+
try {
|
|
155
|
+
const response = await searchTypeScriptHosted(sanitizedQuery, limit, input.includeTypes);
|
|
156
|
+
searchCache.set(cacheKey, response);
|
|
157
|
+
return {
|
|
158
|
+
...response,
|
|
159
|
+
...(queryValidation.warnings.length > 0 && {
|
|
160
|
+
warnings: queryValidation.warnings,
|
|
161
|
+
}),
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
catch (error) {
|
|
165
|
+
logger.warn("Hosted API search failed, falling back to local", {
|
|
166
|
+
error: String(error),
|
|
167
|
+
});
|
|
168
|
+
// Fall through to local search
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
// Local search (fallback or when in local mode)
|
|
129
172
|
const filter = {
|
|
130
173
|
language: "typescript",
|
|
131
174
|
};
|
|
@@ -177,7 +220,10 @@ export async function searchDocs(input) {
|
|
|
177
220
|
});
|
|
178
221
|
const sanitizedQuery = queryValidation.sanitized;
|
|
179
222
|
const limit = limitValidation.value;
|
|
180
|
-
logger.debug("Searching documentation", {
|
|
223
|
+
logger.debug("Searching documentation", {
|
|
224
|
+
query: sanitizedQuery,
|
|
225
|
+
mode: isHostedMode() ? "hosted" : "local",
|
|
226
|
+
});
|
|
181
227
|
// Check cache
|
|
182
228
|
const cacheKey = createCacheKey("docs", sanitizedQuery, limit, input.category);
|
|
183
229
|
const cached = searchCache.get(cacheKey);
|
|
@@ -185,6 +231,26 @@ export async function searchDocs(input) {
|
|
|
185
231
|
logger.debug("Search cache hit", { cacheKey });
|
|
186
232
|
return cached;
|
|
187
233
|
}
|
|
234
|
+
// Use hosted API if in hosted mode
|
|
235
|
+
if (isHostedMode()) {
|
|
236
|
+
try {
|
|
237
|
+
const response = await searchDocsHosted(sanitizedQuery, limit, input.category);
|
|
238
|
+
searchCache.set(cacheKey, response);
|
|
239
|
+
return {
|
|
240
|
+
...response,
|
|
241
|
+
...(queryValidation.warnings.length > 0 && {
|
|
242
|
+
warnings: queryValidation.warnings,
|
|
243
|
+
}),
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
catch (error) {
|
|
247
|
+
logger.warn("Hosted API search failed, falling back to local", {
|
|
248
|
+
error: String(error),
|
|
249
|
+
});
|
|
250
|
+
// Fall through to local search
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
// Local search (fallback or when in local mode)
|
|
188
254
|
const filter = {
|
|
189
255
|
language: "markdown",
|
|
190
256
|
};
|
package/dist/utils/config.d.ts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
declare const ConfigSchema: z.ZodObject<{
|
|
3
|
+
mode: z.ZodDefault<z.ZodEnum<["hosted", "local"]>>;
|
|
4
|
+
hostedApiUrl: z.ZodDefault<z.ZodString>;
|
|
3
5
|
githubToken: z.ZodOptional<z.ZodString>;
|
|
4
6
|
chromaUrl: z.ZodDefault<z.ZodString>;
|
|
5
|
-
qdrantUrl: z.ZodOptional<z.ZodString>;
|
|
6
|
-
pineconeApiKey: z.ZodOptional<z.ZodString>;
|
|
7
|
-
pineconeIndex: z.ZodOptional<z.ZodString>;
|
|
8
7
|
openaiApiKey: z.ZodOptional<z.ZodString>;
|
|
9
8
|
embeddingModel: z.ZodDefault<z.ZodString>;
|
|
10
9
|
logLevel: z.ZodDefault<z.ZodEnum<["debug", "info", "warn", "error"]>>;
|
|
@@ -13,6 +12,8 @@ declare const ConfigSchema: z.ZodObject<{
|
|
|
13
12
|
dataDir: z.ZodDefault<z.ZodString>;
|
|
14
13
|
cacheDir: z.ZodDefault<z.ZodString>;
|
|
15
14
|
}, "strip", z.ZodTypeAny, {
|
|
15
|
+
mode: "hosted" | "local";
|
|
16
|
+
hostedApiUrl: string;
|
|
16
17
|
chromaUrl: string;
|
|
17
18
|
embeddingModel: string;
|
|
18
19
|
logLevel: "debug" | "info" | "warn" | "error";
|
|
@@ -21,16 +22,12 @@ declare const ConfigSchema: z.ZodObject<{
|
|
|
21
22
|
dataDir: string;
|
|
22
23
|
cacheDir: string;
|
|
23
24
|
githubToken?: string | undefined;
|
|
24
|
-
qdrantUrl?: string | undefined;
|
|
25
|
-
pineconeApiKey?: string | undefined;
|
|
26
|
-
pineconeIndex?: string | undefined;
|
|
27
25
|
openaiApiKey?: string | undefined;
|
|
28
26
|
}, {
|
|
27
|
+
mode?: "hosted" | "local" | undefined;
|
|
28
|
+
hostedApiUrl?: string | undefined;
|
|
29
29
|
githubToken?: string | undefined;
|
|
30
30
|
chromaUrl?: string | undefined;
|
|
31
|
-
qdrantUrl?: string | undefined;
|
|
32
|
-
pineconeApiKey?: string | undefined;
|
|
33
|
-
pineconeIndex?: string | undefined;
|
|
34
31
|
openaiApiKey?: string | undefined;
|
|
35
32
|
embeddingModel?: string | undefined;
|
|
36
33
|
logLevel?: "debug" | "info" | "warn" | "error" | undefined;
|
|
@@ -41,6 +38,8 @@ declare const ConfigSchema: z.ZodObject<{
|
|
|
41
38
|
}>;
|
|
42
39
|
export type Config = z.infer<typeof ConfigSchema>;
|
|
43
40
|
export declare const config: {
|
|
41
|
+
mode: "hosted" | "local";
|
|
42
|
+
hostedApiUrl: string;
|
|
44
43
|
chromaUrl: string;
|
|
45
44
|
embeddingModel: string;
|
|
46
45
|
logLevel: "debug" | "info" | "warn" | "error";
|
|
@@ -49,11 +48,16 @@ export declare const config: {
|
|
|
49
48
|
dataDir: string;
|
|
50
49
|
cacheDir: string;
|
|
51
50
|
githubToken?: string | undefined;
|
|
52
|
-
qdrantUrl?: string | undefined;
|
|
53
|
-
pineconeApiKey?: string | undefined;
|
|
54
|
-
pineconeIndex?: string | undefined;
|
|
55
51
|
openaiApiKey?: string | undefined;
|
|
56
52
|
};
|
|
53
|
+
/**
|
|
54
|
+
* Check if running in hosted mode (default)
|
|
55
|
+
*/
|
|
56
|
+
export declare function isHostedMode(): boolean;
|
|
57
|
+
/**
|
|
58
|
+
* Check if running in local mode
|
|
59
|
+
*/
|
|
60
|
+
export declare function isLocalMode(): boolean;
|
|
57
61
|
export interface RepositoryConfig {
|
|
58
62
|
owner: string;
|
|
59
63
|
repo: string;
|
package/dist/utils/config.js
CHANGED
|
@@ -2,14 +2,17 @@ import { z } from "zod";
|
|
|
2
2
|
import dotenv from "dotenv";
|
|
3
3
|
dotenv.config();
|
|
4
4
|
const ConfigSchema = z.object({
|
|
5
|
+
// Mode: 'hosted' (default) or 'local'
|
|
6
|
+
mode: z.enum(["hosted", "local"]).default("hosted"),
|
|
7
|
+
// Hosted API URL (used when mode is 'hosted')
|
|
8
|
+
hostedApiUrl: z
|
|
9
|
+
.string()
|
|
10
|
+
.default("https://midnight-mcp-api.midnightmcp.workers.dev"),
|
|
5
11
|
// GitHub
|
|
6
12
|
githubToken: z.string().optional(),
|
|
7
|
-
// Vector Database
|
|
13
|
+
// Vector Database (only needed for local mode)
|
|
8
14
|
chromaUrl: z.string().default("http://localhost:8000"),
|
|
9
|
-
|
|
10
|
-
pineconeApiKey: z.string().optional(),
|
|
11
|
-
pineconeIndex: z.string().optional(),
|
|
12
|
-
// Embeddings
|
|
15
|
+
// Embeddings (only needed for local mode)
|
|
13
16
|
openaiApiKey: z.string().optional(),
|
|
14
17
|
embeddingModel: z.string().default("text-embedding-3-small"),
|
|
15
18
|
// Server
|
|
@@ -21,12 +24,14 @@ const ConfigSchema = z.object({
|
|
|
21
24
|
cacheDir: z.string().default("./cache"),
|
|
22
25
|
});
|
|
23
26
|
function loadConfig() {
|
|
27
|
+
// Determine mode: local if MIDNIGHT_LOCAL=true or if OPENAI_API_KEY is set
|
|
28
|
+
const isLocalMode = process.env.MIDNIGHT_LOCAL === "true" ||
|
|
29
|
+
(process.env.OPENAI_API_KEY && process.env.CHROMA_URL);
|
|
24
30
|
const rawConfig = {
|
|
31
|
+
mode: isLocalMode ? "local" : "hosted",
|
|
32
|
+
hostedApiUrl: process.env.MIDNIGHT_API_URL,
|
|
25
33
|
githubToken: process.env.GITHUB_TOKEN,
|
|
26
34
|
chromaUrl: process.env.CHROMA_URL,
|
|
27
|
-
qdrantUrl: process.env.QDRANT_URL,
|
|
28
|
-
pineconeApiKey: process.env.PINECONE_API_KEY,
|
|
29
|
-
pineconeIndex: process.env.PINECONE_INDEX,
|
|
30
35
|
openaiApiKey: process.env.OPENAI_API_KEY,
|
|
31
36
|
embeddingModel: process.env.EMBEDDING_MODEL,
|
|
32
37
|
logLevel: process.env.LOG_LEVEL,
|
|
@@ -42,6 +47,18 @@ function loadConfig() {
|
|
|
42
47
|
return ConfigSchema.parse(cleanConfig);
|
|
43
48
|
}
|
|
44
49
|
export const config = loadConfig();
|
|
50
|
+
/**
|
|
51
|
+
* Check if running in hosted mode (default)
|
|
52
|
+
*/
|
|
53
|
+
export function isHostedMode() {
|
|
54
|
+
return config.mode === "hosted";
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Check if running in local mode
|
|
58
|
+
*/
|
|
59
|
+
export function isLocalMode() {
|
|
60
|
+
return config.mode === "local";
|
|
61
|
+
}
|
|
45
62
|
export const DEFAULT_REPOSITORIES = [
|
|
46
63
|
// Core Language & SDK
|
|
47
64
|
{
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client for the hosted Midnight MCP API
|
|
3
|
+
* Used when running in hosted mode (default)
|
|
4
|
+
*/
|
|
5
|
+
export interface HostedSearchResult {
|
|
6
|
+
code?: string;
|
|
7
|
+
content?: string;
|
|
8
|
+
relevanceScore: number;
|
|
9
|
+
source: {
|
|
10
|
+
repository: string;
|
|
11
|
+
filePath: string;
|
|
12
|
+
lines?: string;
|
|
13
|
+
section?: string;
|
|
14
|
+
};
|
|
15
|
+
codeType?: string;
|
|
16
|
+
name?: string;
|
|
17
|
+
isExported?: boolean;
|
|
18
|
+
}
|
|
19
|
+
export interface HostedSearchResponse {
|
|
20
|
+
results: HostedSearchResult[];
|
|
21
|
+
totalResults: number;
|
|
22
|
+
query: string;
|
|
23
|
+
category?: string;
|
|
24
|
+
warnings?: string[];
|
|
25
|
+
}
|
|
26
|
+
export interface HostedSearchFilter {
|
|
27
|
+
language?: string;
|
|
28
|
+
repository?: string;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Search Compact code via hosted API
|
|
32
|
+
*/
|
|
33
|
+
export declare function searchCompactHosted(query: string, limit?: number): Promise<HostedSearchResponse>;
|
|
34
|
+
/**
|
|
35
|
+
* Search TypeScript code via hosted API
|
|
36
|
+
*/
|
|
37
|
+
export declare function searchTypeScriptHosted(query: string, limit?: number, includeTypes?: boolean): Promise<HostedSearchResponse>;
|
|
38
|
+
/**
|
|
39
|
+
* Search documentation via hosted API
|
|
40
|
+
*/
|
|
41
|
+
export declare function searchDocsHosted(query: string, limit?: number, category?: string): Promise<HostedSearchResponse>;
|
|
42
|
+
/**
|
|
43
|
+
* Generic search via hosted API
|
|
44
|
+
*/
|
|
45
|
+
export declare function searchHosted(query: string, limit?: number, filter?: HostedSearchFilter): Promise<HostedSearchResponse>;
|
|
46
|
+
/**
|
|
47
|
+
* Check if the hosted API is available
|
|
48
|
+
*/
|
|
49
|
+
export declare function checkHostedApiHealth(): Promise<{
|
|
50
|
+
available: boolean;
|
|
51
|
+
documentsIndexed?: number;
|
|
52
|
+
error?: string;
|
|
53
|
+
}>;
|
|
54
|
+
/**
|
|
55
|
+
* Get hosted API stats
|
|
56
|
+
*/
|
|
57
|
+
export declare function getHostedApiStats(): Promise<{
|
|
58
|
+
documentsIndexed: number;
|
|
59
|
+
repositories: number;
|
|
60
|
+
}>;
|
|
61
|
+
//# sourceMappingURL=hosted-api.d.ts.map
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client for the hosted Midnight MCP API
|
|
3
|
+
* Used when running in hosted mode (default)
|
|
4
|
+
*/
|
|
5
|
+
import { config, logger } from "./index.js";
|
|
6
|
+
const API_TIMEOUT = 10000; // 10 seconds
|
|
7
|
+
/**
|
|
8
|
+
* Make a request to the hosted API
|
|
9
|
+
*/
|
|
10
|
+
async function apiRequest(endpoint, options = {}) {
|
|
11
|
+
const url = `${config.hostedApiUrl}${endpoint}`;
|
|
12
|
+
const controller = new AbortController();
|
|
13
|
+
const timeout = setTimeout(() => controller.abort(), API_TIMEOUT);
|
|
14
|
+
try {
|
|
15
|
+
const response = await fetch(url, {
|
|
16
|
+
...options,
|
|
17
|
+
signal: controller.signal,
|
|
18
|
+
headers: {
|
|
19
|
+
"Content-Type": "application/json",
|
|
20
|
+
"User-Agent": "midnight-mcp",
|
|
21
|
+
...options.headers,
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
if (!response.ok) {
|
|
25
|
+
const errorData = (await response
|
|
26
|
+
.json()
|
|
27
|
+
.catch(() => ({ error: "Unknown error" })));
|
|
28
|
+
throw new Error(errorData.error || `API error: ${response.status}`);
|
|
29
|
+
}
|
|
30
|
+
return (await response.json());
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
34
|
+
throw new Error("API request timed out. The hosted service may be unavailable.");
|
|
35
|
+
}
|
|
36
|
+
throw error;
|
|
37
|
+
}
|
|
38
|
+
finally {
|
|
39
|
+
clearTimeout(timeout);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Search Compact code via hosted API
|
|
44
|
+
*/
|
|
45
|
+
export async function searchCompactHosted(query, limit = 10) {
|
|
46
|
+
logger.debug("Searching Compact code via hosted API", { query });
|
|
47
|
+
return apiRequest("/v1/search/compact", {
|
|
48
|
+
method: "POST",
|
|
49
|
+
body: JSON.stringify({ query, limit }),
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Search TypeScript code via hosted API
|
|
54
|
+
*/
|
|
55
|
+
export async function searchTypeScriptHosted(query, limit = 10, includeTypes = true) {
|
|
56
|
+
logger.debug("Searching TypeScript code via hosted API", { query });
|
|
57
|
+
return apiRequest("/v1/search/typescript", {
|
|
58
|
+
method: "POST",
|
|
59
|
+
body: JSON.stringify({ query, limit, includeTypes }),
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Search documentation via hosted API
|
|
64
|
+
*/
|
|
65
|
+
export async function searchDocsHosted(query, limit = 10, category = "all") {
|
|
66
|
+
logger.debug("Searching documentation via hosted API", { query });
|
|
67
|
+
return apiRequest("/v1/search/docs", {
|
|
68
|
+
method: "POST",
|
|
69
|
+
body: JSON.stringify({ query, limit, category }),
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Generic search via hosted API
|
|
74
|
+
*/
|
|
75
|
+
export async function searchHosted(query, limit = 10, filter) {
|
|
76
|
+
logger.debug("Searching via hosted API", { query, filter });
|
|
77
|
+
return apiRequest("/v1/search", {
|
|
78
|
+
method: "POST",
|
|
79
|
+
body: JSON.stringify({ query, limit, filter }),
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Check if the hosted API is available
|
|
84
|
+
*/
|
|
85
|
+
export async function checkHostedApiHealth() {
|
|
86
|
+
try {
|
|
87
|
+
const response = await apiRequest("/health");
|
|
88
|
+
return {
|
|
89
|
+
available: response.status === "healthy",
|
|
90
|
+
documentsIndexed: response.vectorStore?.documentsIndexed,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
return {
|
|
95
|
+
available: false,
|
|
96
|
+
error: error instanceof Error ? error.message : String(error),
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Get hosted API stats
|
|
102
|
+
*/
|
|
103
|
+
export async function getHostedApiStats() {
|
|
104
|
+
return apiRequest("/v1/stats");
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=hosted-api.js.map
|
package/dist/utils/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { config } from "./config.js";
|
|
1
|
+
export { config, isHostedMode, isLocalMode } from "./config.js";
|
|
2
2
|
export type { Config, RepositoryConfig } from "./config.js";
|
|
3
3
|
export { DEFAULT_REPOSITORIES } from "./config.js";
|
|
4
4
|
export { logger } from "./logger.js";
|
|
@@ -11,4 +11,6 @@ export { updateRateLimitFromHeaders, updateRateLimit, getRateLimitStatus, should
|
|
|
11
11
|
export type { RateLimitInfo, RateLimitStatus } from "./rate-limit.js";
|
|
12
12
|
export { Cache, createCacheKey, searchCache, fileCache, metadataCache, pruneAllCaches, } from "./cache.js";
|
|
13
13
|
export type { CacheOptions, CacheEntry, CacheStats } from "./cache.js";
|
|
14
|
+
export { searchCompactHosted, searchTypeScriptHosted, searchDocsHosted, searchHosted, checkHostedApiHealth, getHostedApiStats, } from "./hosted-api.js";
|
|
15
|
+
export type { HostedSearchResult, HostedSearchResponse, HostedSearchFilter, } from "./hosted-api.js";
|
|
14
16
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/utils/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { config } from "./config.js";
|
|
1
|
+
export { config, isHostedMode, isLocalMode } from "./config.js";
|
|
2
2
|
export { DEFAULT_REPOSITORIES } from "./config.js";
|
|
3
3
|
export { logger } from "./logger.js";
|
|
4
4
|
export { MCPError, ErrorCodes, createUserError, formatErrorResponse, withErrorHandling, } from "./errors.js";
|
|
@@ -10,4 +10,6 @@ export { getHealthStatus, getQuickHealthStatus } from "./health.js";
|
|
|
10
10
|
export { updateRateLimitFromHeaders, updateRateLimit, getRateLimitStatus, shouldProceedWithRequest, getTimeUntilReset, formatRateLimitStatus, decrementRemaining, } from "./rate-limit.js";
|
|
11
11
|
// Caching utilities
|
|
12
12
|
export { Cache, createCacheKey, searchCache, fileCache, metadataCache, pruneAllCaches, } from "./cache.js";
|
|
13
|
+
// Hosted API client
|
|
14
|
+
export { searchCompactHosted, searchTypeScriptHosted, searchDocsHosted, searchHosted, checkHostedApiHealth, getHostedApiStats, } from "./hosted-api.js";
|
|
13
15
|
//# sourceMappingURL=index.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "midnight-mcp",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.5",
|
|
4
4
|
"description": "Model Context Protocol Server for Midnight Blockchain Development",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -11,7 +11,6 @@
|
|
|
11
11
|
"build": "tsc",
|
|
12
12
|
"start": "node dist/index.js",
|
|
13
13
|
"dev": "tsx watch src/index.ts",
|
|
14
|
-
"index": "tsx src/scripts/index-repos.ts",
|
|
15
14
|
"test": "vitest",
|
|
16
15
|
"test:coverage": "vitest --coverage",
|
|
17
16
|
"lint": "eslint src/**/*.ts",
|