@msegoviadev/api-mind-mcp 0.1.0
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 +21 -0
- package/README.md +245 -0
- package/dist/core/index.d.ts +4 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +20 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/loader.d.ts +23 -0
- package/dist/core/loader.d.ts.map +1 -0
- package/dist/core/loader.js +208 -0
- package/dist/core/loader.js.map +1 -0
- package/dist/core/parser.d.ts +17 -0
- package/dist/core/parser.d.ts.map +1 -0
- package/dist/core/parser.js +215 -0
- package/dist/core/parser.js.map +1 -0
- package/dist/core/types.d.ts +55 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +3 -0
- package/dist/core/types.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +172 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/node-bindings.d.ts +2 -0
- package/dist/lib/node-bindings.d.ts.map +1 -0
- package/dist/lib/node-bindings.js +17 -0
- package/dist/lib/node-bindings.js.map +1 -0
- package/dist/tools/get-endpoint-schema.d.ts +20 -0
- package/dist/tools/get-endpoint-schema.d.ts.map +1 -0
- package/dist/tools/get-endpoint-schema.js +90 -0
- package/dist/tools/get-endpoint-schema.js.map +1 -0
- package/dist/tools/list-apis.d.ts +9 -0
- package/dist/tools/list-apis.d.ts.map +1 -0
- package/dist/tools/list-apis.js +28 -0
- package/dist/tools/list-apis.js.map +1 -0
- package/dist/tools/list-endpoints.d.ts +11 -0
- package/dist/tools/list-endpoints.d.ts.map +1 -0
- package/dist/tools/list-endpoints.js +33 -0
- package/dist/tools/list-endpoints.js.map +1 -0
- package/package.json +54 -0
- package/setup-mcp.sh.example +41 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Marcos Segovia
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
# api-mind MCP Server
|
|
2
|
+
|
|
3
|
+
MCP server for API discovery from `.mind` spec files. Works with Claude Code, Claude Desktop, and any MCP-compatible AI assistant.
|
|
4
|
+
|
|
5
|
+
## Why
|
|
6
|
+
|
|
7
|
+
LLMs interacting with HTTP APIs need to discover endpoints, understand contracts, and make requests. api-mind provides 3 tools for discovery and context:
|
|
8
|
+
|
|
9
|
+
- **list_apis** - Discover available APIs
|
|
10
|
+
- **list_endpoints** - Find endpoints across APIs
|
|
11
|
+
- **get_endpoint_schema** - Get base URL, auth requirements, and schema
|
|
12
|
+
|
|
13
|
+
The LLM then constructs and executes curl commands with full transparency.
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
### Option 1: Command-line argument (Recommended)
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
claude mcp add --transport stdio api-mind \
|
|
21
|
+
-- npx -y @msegoviadev/api-mind-mcp /Users/YOUR/absolute/path/to/specs
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
**Important:** Use ABSOLUTE paths. Relative paths are not supported.
|
|
25
|
+
|
|
26
|
+
### Option 2: Environment variable
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
claude mcp add --transport stdio api-mind \
|
|
30
|
+
--env SPECS_DIR=/Users/YOUR/absolute/path/to/specs \
|
|
31
|
+
-- npx -y @msegoviadev/api-mind-mcp
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Option 3: Project configuration (Best for Teams)
|
|
35
|
+
|
|
36
|
+
Create `.mcp.json` in your project root:
|
|
37
|
+
|
|
38
|
+
```json
|
|
39
|
+
{
|
|
40
|
+
"mcpServers": {
|
|
41
|
+
"api-mind": {
|
|
42
|
+
"command": "npx",
|
|
43
|
+
"args": ["-y", "@msegoviadev/api-mind-mcp"],
|
|
44
|
+
"env": {
|
|
45
|
+
"SPECS_DIR": "/Users/yourname/projects/yourproject/specs"
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
**Note:** Each team member needs their own `.mcp.json` with their absolute path. Add `.mcp.json` to `.gitignore`.
|
|
53
|
+
|
|
54
|
+
### Setup Script for Teams
|
|
55
|
+
|
|
56
|
+
Create `setup-mcp.sh` in your project root:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
#!/bin/bash
|
|
60
|
+
PROJECT_ROOT="$(cd "$(dirname "$0")" && pwd)"
|
|
61
|
+
claude mcp add --transport stdio --scope project api-mind \
|
|
62
|
+
--env SPECS_DIR="${PROJECT_ROOT}/specs" \
|
|
63
|
+
-- npx -y @msegoviadev/api-mind-mcp
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Team members run once:
|
|
67
|
+
```bash
|
|
68
|
+
chmod +x setup-mcp.sh
|
|
69
|
+
./setup-mcp.sh
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Local Development
|
|
73
|
+
|
|
74
|
+
For testing locally:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
cd /path/to/api-mind-claude
|
|
78
|
+
npm install
|
|
79
|
+
npm run build
|
|
80
|
+
|
|
81
|
+
# Test with command-line argument
|
|
82
|
+
node dist/index.js /absolute/path/to/specs
|
|
83
|
+
|
|
84
|
+
# Test with environment variable
|
|
85
|
+
SPECS_DIR=/absolute/path/to/specs node dist/index.js
|
|
86
|
+
|
|
87
|
+
# Add to Claude Code for testing
|
|
88
|
+
claude mcp add --transport stdio api-mind-dev \
|
|
89
|
+
-- node /path/to/api-mind-claude/dist/index.js /absolute/path/to/specs
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Setup
|
|
93
|
+
|
|
94
|
+
### 1. Add OpenAPI specs
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
mkdir specs
|
|
98
|
+
# Copy your OpenAPI/Swagger YAML/JSON files to specs/
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### 2. Generate .mind files
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
npm install -g @msegoviadev/spec-mind
|
|
105
|
+
spec-mind sync --no-notation ./specs/
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### 3. Commit both files
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
git add specs/*.yaml specs/*.mind
|
|
112
|
+
git commit -m "Add API specs"
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### 4. Configure api-mind
|
|
116
|
+
|
|
117
|
+
Use one of the installation methods above to configure the specs directory.
|
|
118
|
+
|
|
119
|
+
## Tools
|
|
120
|
+
|
|
121
|
+
### list_apis
|
|
122
|
+
|
|
123
|
+
Lists all APIs loaded from the specs folder.
|
|
124
|
+
|
|
125
|
+
```
|
|
126
|
+
Input: none
|
|
127
|
+
Output: JSON with API names, titles, base URLs, and environments
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Call first to discover what APIs are available.
|
|
131
|
+
|
|
132
|
+
### list_endpoints
|
|
133
|
+
|
|
134
|
+
Lists endpoints across all APIs.
|
|
135
|
+
|
|
136
|
+
```
|
|
137
|
+
Input:
|
|
138
|
+
filter (optional): Substring match on method, path, or section
|
|
139
|
+
|
|
140
|
+
Output: JSON with environments and endpoint list
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Call to find specific endpoints.
|
|
144
|
+
|
|
145
|
+
### get_endpoint_schema
|
|
146
|
+
|
|
147
|
+
Returns full context for an endpoint.
|
|
148
|
+
|
|
149
|
+
```
|
|
150
|
+
Input:
|
|
151
|
+
api: API name
|
|
152
|
+
method: HTTP method
|
|
153
|
+
path: Endpoint path
|
|
154
|
+
|
|
155
|
+
Output: Text block with base URL, environments, auth, and schema
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Call before constructing curl to understand the endpoint.
|
|
159
|
+
|
|
160
|
+
## Workflow
|
|
161
|
+
|
|
162
|
+
```
|
|
163
|
+
list_apis → list_endpoints → get_endpoint_schema → [LLM constructs curl] → bash
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
1. `list_apis` - Discover available APIs
|
|
167
|
+
2. `list_endpoints` - Find relevant endpoints
|
|
168
|
+
3. `get_endpoint_schema` - Get context (URL, auth, schema)
|
|
169
|
+
4. LLM constructs curl command with proper URL and headers
|
|
170
|
+
5. LLM executes via `bash` tool
|
|
171
|
+
|
|
172
|
+
## Auth Patterns
|
|
173
|
+
|
|
174
|
+
When `get_endpoint_schema` shows auth requirements, construct headers:
|
|
175
|
+
|
|
176
|
+
| Auth in Schema | curl Header |
|
|
177
|
+
|----------------|-------------|
|
|
178
|
+
| `None` | No header |
|
|
179
|
+
| `bearer` | `-H 'Authorization: Bearer <TOKEN>'` |
|
|
180
|
+
| `oauth2 <scopes>` | `-H 'Authorization: Bearer <TOKEN>'` |
|
|
181
|
+
| `api_key <header>` | `-H '<header>: <KEY>'` |
|
|
182
|
+
| `basic` | `-H 'Authorization: Basic <base64>'` |
|
|
183
|
+
|
|
184
|
+
## Why Absolute Paths?
|
|
185
|
+
|
|
186
|
+
MCP servers run as standalone processes without project context. The working directory may be `/` or a system directory. Unlike plugins that receive project context, MCP servers must receive explicit configuration.
|
|
187
|
+
|
|
188
|
+
Always use absolute paths when configuring MCP servers.
|
|
189
|
+
|
|
190
|
+
## Example Usage
|
|
191
|
+
|
|
192
|
+
Once configured, use the tools directly in Claude Code:
|
|
193
|
+
|
|
194
|
+
```
|
|
195
|
+
User: "What APIs are available?"
|
|
196
|
+
Claude: *uses list_apis tool*
|
|
197
|
+
"I found 2 APIs loaded:
|
|
198
|
+
1. ecommerce - E-commerce API
|
|
199
|
+
2. payments - Payments API"
|
|
200
|
+
|
|
201
|
+
User: "Show me the endpoints for creating a payment"
|
|
202
|
+
Claude: *uses list_endpoints tool with filter="payment"*
|
|
203
|
+
"Here are payment endpoints:
|
|
204
|
+
POST /payments [auth: oauth2 payments:write]
|
|
205
|
+
..."
|
|
206
|
+
|
|
207
|
+
User: "Get the schema for POST /payments"
|
|
208
|
+
Claude: *uses get_endpoint_schema tool*
|
|
209
|
+
"POST /payments
|
|
210
|
+
Auth: oauth2 payments:write
|
|
211
|
+
Body: CreatePaymentRequest {...}
|
|
212
|
+
..."
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
## NOTATION Legend
|
|
216
|
+
|
|
217
|
+
The schema uses a compact notation:
|
|
218
|
+
|
|
219
|
+
```
|
|
220
|
+
? optional | [ro] readOnly | [w] writeOnly | =val default
|
|
221
|
+
^ header | ~ cookie | | enum | {*:T} map | ~~name~~ deprecated
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
## Development
|
|
225
|
+
|
|
226
|
+
### Build
|
|
227
|
+
|
|
228
|
+
```bash
|
|
229
|
+
npm run build
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
### Test Locally
|
|
233
|
+
|
|
234
|
+
```bash
|
|
235
|
+
node dist/index.js /absolute/path/to/specs
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
## Related
|
|
239
|
+
|
|
240
|
+
- [spec-mind](https://github.com/msegoviadev/spec-mind) - Generate `.mind` files from OpenAPI specs
|
|
241
|
+
- [api-mind](https://github.com/msegoviadev/api-mind) - OpenCode plugin version
|
|
242
|
+
|
|
243
|
+
## License
|
|
244
|
+
|
|
245
|
+
MIT
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAA;AACvB,cAAc,UAAU,CAAA;AACxB,cAAc,UAAU,CAAA"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./types"), exports);
|
|
18
|
+
__exportStar(require("./parser"), exports);
|
|
19
|
+
__exportStar(require("./loader"), exports);
|
|
20
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,0CAAuB;AACvB,2CAAwB;AACxB,2CAAwB"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { EndpointIndex, EndpointEntry, InitOptions, GetEndpointSchemaResult } from "./types";
|
|
2
|
+
export declare function initIndex(options: InitOptions): Promise<EndpointIndex>;
|
|
3
|
+
export declare function getIndex(): Promise<EndpointIndex>;
|
|
4
|
+
export declare function clearIndex(): void;
|
|
5
|
+
export declare function getSpecsDir(): string | null;
|
|
6
|
+
export declare function rebuildIndex(): Promise<EndpointIndex>;
|
|
7
|
+
export declare function listApis(): Promise<{
|
|
8
|
+
apis: Array<{
|
|
9
|
+
name: string;
|
|
10
|
+
title: string;
|
|
11
|
+
defaultUrl: string;
|
|
12
|
+
environments: Record<string, string>;
|
|
13
|
+
}>;
|
|
14
|
+
}>;
|
|
15
|
+
export declare function listEndpoints(filter?: string): Promise<{
|
|
16
|
+
environments: string[];
|
|
17
|
+
endpoints: EndpointEntry[];
|
|
18
|
+
}>;
|
|
19
|
+
export declare function getEndpointSchema(api: string, method: string, path: string): Promise<GetEndpointSchemaResult>;
|
|
20
|
+
export declare function setFileReader(fn: (path: string) => Promise<string>): void;
|
|
21
|
+
export declare function setDirReader(fn: (dir: string) => Promise<string[]>): void;
|
|
22
|
+
export declare function setPathJoiner(fn: (...parts: string[]) => string): void;
|
|
23
|
+
//# sourceMappingURL=loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/core/loader.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAW,aAAa,EAAE,WAAW,EAAE,uBAAuB,EAAE,MAAM,SAAS,CAAA;AAM1G,wBAAsB,SAAS,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,aAAa,CAAC,CAI5E;AAED,wBAAsB,QAAQ,IAAI,OAAO,CAAC,aAAa,CAAC,CAKvD;AAED,wBAAgB,UAAU,IAAI,IAAI,CAGjC;AAED,wBAAgB,WAAW,IAAI,MAAM,GAAG,IAAI,CAE3C;AAED,wBAAsB,YAAY,IAAI,OAAO,CAAC,aAAa,CAAC,CAK3D;AAgED,wBAAsB,QAAQ,IAAI,OAAO,CAAC;IAAE,IAAI,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,CAAC,CAAA;CAAE,CAAC,CASpJ;AAED,wBAAsB,aAAa,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAAE,YAAY,EAAE,MAAM,EAAE,CAAC;IAAC,SAAS,EAAE,aAAa,EAAE,CAAA;CAAE,CAAC,CAiBpH;AAED,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,uBAAuB,CAAC,CA8BnH;AAMD,wBAAgB,aAAa,CAAC,EAAE,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,GAAG,IAAI,CAEzE;AAED,wBAAgB,YAAY,CAAC,EAAE,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC,GAAG,IAAI,CAEzE;AAED,wBAAgB,aAAa,CAAC,EAAE,EAAE,CAAC,GAAG,KAAK,EAAE,MAAM,EAAE,KAAK,MAAM,GAAG,IAAI,CAEtE"}
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.initIndex = initIndex;
|
|
37
|
+
exports.getIndex = getIndex;
|
|
38
|
+
exports.clearIndex = clearIndex;
|
|
39
|
+
exports.getSpecsDir = getSpecsDir;
|
|
40
|
+
exports.rebuildIndex = rebuildIndex;
|
|
41
|
+
exports.listApis = listApis;
|
|
42
|
+
exports.listEndpoints = listEndpoints;
|
|
43
|
+
exports.getEndpointSchema = getEndpointSchema;
|
|
44
|
+
exports.setFileReader = setFileReader;
|
|
45
|
+
exports.setDirReader = setDirReader;
|
|
46
|
+
exports.setPathJoiner = setPathJoiner;
|
|
47
|
+
const parser_1 = require("./parser");
|
|
48
|
+
let indexPromise = null;
|
|
49
|
+
let currentSpecsDir = null;
|
|
50
|
+
async function initIndex(options) {
|
|
51
|
+
currentSpecsDir = options.specsDir;
|
|
52
|
+
indexPromise = buildIndex(options.specsDir);
|
|
53
|
+
return indexPromise;
|
|
54
|
+
}
|
|
55
|
+
async function getIndex() {
|
|
56
|
+
if (!indexPromise) {
|
|
57
|
+
throw new Error("Index not initialized. Call initIndex() first.");
|
|
58
|
+
}
|
|
59
|
+
return indexPromise;
|
|
60
|
+
}
|
|
61
|
+
function clearIndex() {
|
|
62
|
+
indexPromise = null;
|
|
63
|
+
currentSpecsDir = null;
|
|
64
|
+
}
|
|
65
|
+
function getSpecsDir() {
|
|
66
|
+
return currentSpecsDir;
|
|
67
|
+
}
|
|
68
|
+
async function rebuildIndex() {
|
|
69
|
+
if (!currentSpecsDir) {
|
|
70
|
+
throw new Error("No specs directory configured. Call initIndex() first.");
|
|
71
|
+
}
|
|
72
|
+
return initIndex({ specsDir: currentSpecsDir });
|
|
73
|
+
}
|
|
74
|
+
async function buildIndex(specsDir) {
|
|
75
|
+
const files = await scanMindFiles(specsDir);
|
|
76
|
+
const apis = {};
|
|
77
|
+
const allEndpoints = [];
|
|
78
|
+
const allEnvironments = new Set();
|
|
79
|
+
await Promise.all(files.map(async (filePath) => {
|
|
80
|
+
const content = await readFile(filePath);
|
|
81
|
+
const apiName = extractApiName(filePath);
|
|
82
|
+
const apiHeader = (0, parser_1.parseApiHeader)(content);
|
|
83
|
+
if (!apiHeader) {
|
|
84
|
+
console.error(`[api-mind] No API header found in ${filePath}`);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
const servers = (0, parser_1.parseServers)(content);
|
|
88
|
+
const parsedEndpoints = (0, parser_1.parseEndpoints)(content);
|
|
89
|
+
const endpoints = parsedEndpoints.map(ep => ({
|
|
90
|
+
api: apiName,
|
|
91
|
+
section: ep.section,
|
|
92
|
+
method: ep.method,
|
|
93
|
+
path: ep.path,
|
|
94
|
+
auth: ep.auth,
|
|
95
|
+
}));
|
|
96
|
+
apis[apiName] = {
|
|
97
|
+
filePath,
|
|
98
|
+
title: apiHeader.title,
|
|
99
|
+
defaultUrl: apiHeader.defaultUrl,
|
|
100
|
+
servers,
|
|
101
|
+
};
|
|
102
|
+
allEndpoints.push(...endpoints);
|
|
103
|
+
Object.keys(servers).forEach(env => allEnvironments.add(env.toLowerCase()));
|
|
104
|
+
}));
|
|
105
|
+
return {
|
|
106
|
+
environments: Array.from(allEnvironments).sort(),
|
|
107
|
+
apis,
|
|
108
|
+
endpoints: allEndpoints,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
async function scanMindFiles(dir) {
|
|
112
|
+
try {
|
|
113
|
+
const entries = await readDir(dir);
|
|
114
|
+
return entries
|
|
115
|
+
.filter(entry => entry.endsWith(".mind"))
|
|
116
|
+
.map(entry => joinPath(dir, entry));
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
console.debug(`[api-mind] Directory not found: ${dir}`);
|
|
120
|
+
return [];
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
function extractApiName(filePath) {
|
|
124
|
+
const fileName = filePath.split("/").pop() || "";
|
|
125
|
+
return fileName.replace(/\.mind$/, "");
|
|
126
|
+
}
|
|
127
|
+
async function listApis() {
|
|
128
|
+
const index = await getIndex();
|
|
129
|
+
const apis = Object.entries(index.apis).map(([name, meta]) => ({
|
|
130
|
+
name,
|
|
131
|
+
title: meta.title,
|
|
132
|
+
defaultUrl: meta.defaultUrl,
|
|
133
|
+
environments: meta.servers,
|
|
134
|
+
}));
|
|
135
|
+
return { apis };
|
|
136
|
+
}
|
|
137
|
+
async function listEndpoints(filter) {
|
|
138
|
+
const index = await getIndex();
|
|
139
|
+
let endpoints = index.endpoints;
|
|
140
|
+
if (filter) {
|
|
141
|
+
const lowerFilter = filter.toLowerCase();
|
|
142
|
+
endpoints = endpoints.filter(ep => ep.method.toLowerCase().includes(lowerFilter) ||
|
|
143
|
+
ep.path.toLowerCase().includes(lowerFilter) ||
|
|
144
|
+
ep.section.toLowerCase().includes(lowerFilter));
|
|
145
|
+
}
|
|
146
|
+
return {
|
|
147
|
+
environments: index.environments,
|
|
148
|
+
endpoints,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
async function getEndpointSchema(api, method, path) {
|
|
152
|
+
const index = await getIndex();
|
|
153
|
+
const apiMeta = index.apis[api];
|
|
154
|
+
if (!apiMeta) {
|
|
155
|
+
throw new Error(`API "${api}" not found. Available: ${Object.keys(index.apis).join(", ")}`);
|
|
156
|
+
}
|
|
157
|
+
const content = await readFile(apiMeta.filePath);
|
|
158
|
+
const { parseFullEndpoint } = await Promise.resolve().then(() => __importStar(require("./parser")));
|
|
159
|
+
const block = parseFullEndpoint(content, method, path);
|
|
160
|
+
if (!block) {
|
|
161
|
+
throw new Error(`Endpoint ${method} ${path} not found in API "${api}"`);
|
|
162
|
+
}
|
|
163
|
+
const endpoint = index.endpoints.find(ep => ep.api === api && ep.method === method && ep.path === path);
|
|
164
|
+
return {
|
|
165
|
+
api,
|
|
166
|
+
title: apiMeta.title,
|
|
167
|
+
defaultUrl: apiMeta.defaultUrl,
|
|
168
|
+
environments: apiMeta.servers,
|
|
169
|
+
method,
|
|
170
|
+
path,
|
|
171
|
+
auth: endpoint?.auth || null,
|
|
172
|
+
schema: block,
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
let _readFile = null;
|
|
176
|
+
let _readDir = null;
|
|
177
|
+
let _joinPath = null;
|
|
178
|
+
function setFileReader(fn) {
|
|
179
|
+
_readFile = fn;
|
|
180
|
+
}
|
|
181
|
+
function setDirReader(fn) {
|
|
182
|
+
_readDir = fn;
|
|
183
|
+
}
|
|
184
|
+
function setPathJoiner(fn) {
|
|
185
|
+
_joinPath = fn;
|
|
186
|
+
}
|
|
187
|
+
async function readFile(path) {
|
|
188
|
+
if (_readFile) {
|
|
189
|
+
return _readFile(path);
|
|
190
|
+
}
|
|
191
|
+
const fs = await Promise.resolve().then(() => __importStar(require("fs/promises")));
|
|
192
|
+
return fs.readFile(path, "utf-8");
|
|
193
|
+
}
|
|
194
|
+
async function readDir(dir) {
|
|
195
|
+
if (_readDir) {
|
|
196
|
+
return _readDir(dir);
|
|
197
|
+
}
|
|
198
|
+
const fs = await Promise.resolve().then(() => __importStar(require("fs/promises")));
|
|
199
|
+
const entries = await fs.readdir(dir);
|
|
200
|
+
return entries;
|
|
201
|
+
}
|
|
202
|
+
function joinPath(...parts) {
|
|
203
|
+
if (_joinPath) {
|
|
204
|
+
return _joinPath(...parts);
|
|
205
|
+
}
|
|
206
|
+
return parts.join("/").replace(/\/+/g, "/");
|
|
207
|
+
}
|
|
208
|
+
//# sourceMappingURL=loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/core/loader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ParsedApiHeader, ParsedEndpoint } from "./types";
|
|
2
|
+
export declare function parseApiHeader(content: string): ParsedApiHeader | null;
|
|
3
|
+
export declare function parseServers(content: string): Record<string, string>;
|
|
4
|
+
export declare function stripDeprecationWrapper(method: string): string;
|
|
5
|
+
export declare function normalizePath(path: string): string;
|
|
6
|
+
export declare function parseEndpointLine(line: string): {
|
|
7
|
+
method: string;
|
|
8
|
+
path: string;
|
|
9
|
+
auth?: string;
|
|
10
|
+
} | null;
|
|
11
|
+
export declare function parseEndpoints(content: string): ParsedEndpoint[];
|
|
12
|
+
export declare function findEndpointBlock(content: string, method: string, path: string): string | null;
|
|
13
|
+
export declare function extractSchemaRefs(block: string): string[];
|
|
14
|
+
export declare function findSchemaBlock(content: string, schemaName: string): string | null;
|
|
15
|
+
export declare function collectSchemas(content: string, endpointBlock: string): string;
|
|
16
|
+
export declare function parseFullEndpoint(content: string, method: string, path: string): string | null;
|
|
17
|
+
//# sourceMappingURL=parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/core/parser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAQ9D,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,CAYtE;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAiBpE;AAED,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAE9D;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAIlD;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAStG;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,cAAc,EAAE,CAgChE;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CA+B9F;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAWzD;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CA+BlF;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,CAsB7E;AAuBD,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAW9F"}
|