@fleetx_io/fleetx-mcp-server 1.0.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/CHANGELOG.md +23 -0
- package/README.md +215 -0
- package/dist/apiDiscovery.d.ts +11 -0
- package/dist/apiDiscovery.d.ts.map +1 -0
- package/dist/apiDiscovery.js +83 -0
- package/dist/apiDiscovery.js.map +1 -0
- package/dist/auth.d.ts +7 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +65 -0
- package/dist/auth.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/mcpServer.d.ts +7 -0
- package/dist/mcpServer.d.ts.map +1 -0
- package/dist/mcpServer.js +125 -0
- package/dist/mcpServer.js.map +1 -0
- package/dist/proxyCaller.d.ts +9 -0
- package/dist/proxyCaller.d.ts.map +1 -0
- package/dist/proxyCaller.js +91 -0
- package/dist/proxyCaller.js.map +1 -0
- package/dist/schemaBuilder.d.ts +17 -0
- package/dist/schemaBuilder.d.ts.map +1 -0
- package/dist/schemaBuilder.js +74 -0
- package/dist/schemaBuilder.js.map +1 -0
- package/dist/toolGenerator.d.ts +16 -0
- package/dist/toolGenerator.d.ts.map +1 -0
- package/dist/toolGenerator.js +108 -0
- package/dist/toolGenerator.js.map +1 -0
- package/dist/types.d.ts +35 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/dist/utils.d.ts +8 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +20 -0
- package/dist/utils.js.map +1 -0
- package/package.json +63 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [1.0.0] - 2026-03-03
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- MCP server with stdio transport for local AI agent integration.
|
|
13
|
+
- `login` tool for authenticating with the FleetX API.
|
|
14
|
+
- Dynamic tool generation from FleetX API definitions after login.
|
|
15
|
+
- Zod-based input validation for all dynamically registered tools.
|
|
16
|
+
- Automatic Bearer token injection into downstream API calls.
|
|
17
|
+
- Token expiry handling — clears token and prompts re-login on 401/403.
|
|
18
|
+
- Support for path, query, and body parameters in proxied API calls.
|
|
19
|
+
- `npx` support — run directly with `npx @fleetx_io/fleetx-mcp-server`.
|
|
20
|
+
- Global install support via `npm install -g`.
|
|
21
|
+
- MCP Inspector compatibility for debugging and testing.
|
|
22
|
+
- Configuration via environment variables with sensible defaults.
|
|
23
|
+
- Cursor, Claude Desktop, and Windsurf integration examples in README.
|
package/README.md
ADDED
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
# @fleetx_io/fleetx-mcp-server
|
|
2
|
+
|
|
3
|
+
An MCP (Model Context Protocol) server that gives AI agents access to the FleetX REST API. Install it as an npm package and connect it to any MCP-compatible client — no code required.
|
|
4
|
+
|
|
5
|
+
## How it Works
|
|
6
|
+
|
|
7
|
+
1. Your AI agent (Cursor, Claude Desktop, Windsurf, etc.) launches this server as a subprocess.
|
|
8
|
+
2. The agent calls the `login` tool with your FleetX credentials.
|
|
9
|
+
3. The server authenticates and fetches all available API definitions.
|
|
10
|
+
4. Each API is dynamically registered as an MCP tool with validated inputs.
|
|
11
|
+
5. The agent can now call any FleetX API — the server handles auth, validation, and proxying automatically.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Quick Start
|
|
16
|
+
|
|
17
|
+
### Install
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install -g @fleetx_io/fleetx-mcp-server
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Or use it directly with `npx` (no install needed):
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npx @fleetx_io/fleetx-mcp-server
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Connect to Your AI Agent
|
|
32
|
+
|
|
33
|
+
### Cursor
|
|
34
|
+
|
|
35
|
+
Add to `.cursor/mcp.json` in your project root:
|
|
36
|
+
|
|
37
|
+
```json
|
|
38
|
+
{
|
|
39
|
+
"mcpServers": {
|
|
40
|
+
"fleetx": {
|
|
41
|
+
"command": "npx",
|
|
42
|
+
"args": ["-y", "@fleetx_io/fleetx-mcp-server"]
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Then restart Cursor. The server will appear in **Settings > MCP**.
|
|
49
|
+
|
|
50
|
+
### Claude Desktop
|
|
51
|
+
|
|
52
|
+
Add to your `claude_desktop_config.json`:
|
|
53
|
+
|
|
54
|
+
**macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
55
|
+
**Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
|
|
56
|
+
|
|
57
|
+
```json
|
|
58
|
+
{
|
|
59
|
+
"mcpServers": {
|
|
60
|
+
"fleetx": {
|
|
61
|
+
"command": "npx",
|
|
62
|
+
"args": ["-y", "@fleetx_io/fleetx-mcp-server"]
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Windsurf
|
|
69
|
+
|
|
70
|
+
Add to your Windsurf MCP config:
|
|
71
|
+
|
|
72
|
+
```json
|
|
73
|
+
{
|
|
74
|
+
"mcpServers": {
|
|
75
|
+
"fleetx": {
|
|
76
|
+
"command": "npx",
|
|
77
|
+
"args": ["-y", "@fleetx_io/fleetx-mcp-server"]
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Any MCP Client (Generic)
|
|
84
|
+
|
|
85
|
+
Run the server as a subprocess communicating over **stdio**:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
npx @fleetx_io/fleetx-mcp-server
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Or if installed globally:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
fleetx-mcp-server
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
The server speaks JSON-RPC over stdin/stdout. Logs go to stderr.
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## Usage
|
|
102
|
+
|
|
103
|
+
Once connected, ask your AI agent to:
|
|
104
|
+
|
|
105
|
+
1. **Log in:** _"Log in to FleetX with username X and password Y"_
|
|
106
|
+
2. **Use any tool:** _"Show me all vehicles"_, _"Create a new job"_, _"Get trip history for vehicle KA01AB1234"_
|
|
107
|
+
|
|
108
|
+
The `login` tool must be called first. After login, all FleetX API tools become available automatically.
|
|
109
|
+
|
|
110
|
+
### Available Tools (after login)
|
|
111
|
+
|
|
112
|
+
Tools are generated dynamically from your FleetX account's API definitions. Common examples:
|
|
113
|
+
|
|
114
|
+
| Tool | Description |
|
|
115
|
+
|------|-------------|
|
|
116
|
+
| `login` | Authenticate with FleetX (required first) |
|
|
117
|
+
| `vehicle_listing` | List all vehicles |
|
|
118
|
+
| `vehicle_realtime_api` | Get real-time vehicle data |
|
|
119
|
+
| `create_job` | Create a new job |
|
|
120
|
+
| `job_status_api` | Check job status |
|
|
121
|
+
| `get_trip_history_by_vehicle_within_a_given_time_range` | Trip history for a vehicle |
|
|
122
|
+
| `fetch_tagsfor_a_given_account` | Get all tags |
|
|
123
|
+
| `real_time_analytics_api_by_vehicle_number` | Analytics by vehicle |
|
|
124
|
+
|
|
125
|
+
The full list depends on your account's enabled APIs.
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## Configuration (Optional)
|
|
130
|
+
|
|
131
|
+
By default, the server connects to the FleetX production API. Override with environment variables if needed:
|
|
132
|
+
|
|
133
|
+
```json
|
|
134
|
+
{
|
|
135
|
+
"mcpServers": {
|
|
136
|
+
"fleetx": {
|
|
137
|
+
"command": "npx",
|
|
138
|
+
"args": ["-y", "@fleetx_io/fleetx-mcp-server"],
|
|
139
|
+
"env": {
|
|
140
|
+
"LOGIN_URL": "https://api.fleetx.io/api/v1/login",
|
|
141
|
+
"API_DEFINITION_URL": "https://app.fleetx.io/napp/api-reference/apis"
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
| Variable | Default | Description |
|
|
149
|
+
|----------|---------|-------------|
|
|
150
|
+
| `LOGIN_URL` | `https://api.fleetx.io/api/v1/login` | Authentication endpoint |
|
|
151
|
+
| `API_DEFINITION_URL` | `https://app.fleetx.io/napp/api-reference/apis` | API definitions endpoint |
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## Security
|
|
156
|
+
|
|
157
|
+
- Credentials are sent only to the FleetX login endpoint — never logged or stored on disk.
|
|
158
|
+
- The access token is held in memory for the session duration and never exposed in tool responses.
|
|
159
|
+
- Token is automatically cleared on 401/403 errors, requiring re-login.
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## Testing with MCP Inspector
|
|
164
|
+
|
|
165
|
+
For debugging and exploring available tools:
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
npx @modelcontextprotocol/inspector npx @fleetx_io/fleetx-mcp-server
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
This opens a web UI where you can connect, call `login`, browse all tools, and test them interactively.
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
## Development
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
git clone <repo-url>
|
|
179
|
+
cd fleetx-mcp-server
|
|
180
|
+
npm install
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
| Command | Description |
|
|
184
|
+
|---------|-------------|
|
|
185
|
+
| `npm run dev` | Start with hot-reload (ts-node-dev) |
|
|
186
|
+
| `npm run build` | Compile TypeScript to `dist/` |
|
|
187
|
+
| `npm start` | Run compiled output |
|
|
188
|
+
| `npm run startClient` | Launch with MCP Inspector (built) |
|
|
189
|
+
| `npm run startClientLive` | Launch with MCP Inspector (live reload) |
|
|
190
|
+
|
|
191
|
+
### Project Structure
|
|
192
|
+
|
|
193
|
+
```
|
|
194
|
+
src/
|
|
195
|
+
index.ts Stdio transport entrypoint
|
|
196
|
+
mcpServer.ts MCP server + login tool + dynamic tool registration
|
|
197
|
+
auth.ts Login flow + in-memory token store
|
|
198
|
+
apiDiscovery.ts Fetch API definitions from protected endpoint
|
|
199
|
+
toolGenerator.ts Convert API definitions into MCP tools
|
|
200
|
+
proxyCaller.ts Proxy calls to external APIs via Axios
|
|
201
|
+
schemaBuilder.ts Zod schema + JSON Schema generation from API metadata
|
|
202
|
+
utils.ts Logging + config helpers
|
|
203
|
+
types.ts Shared TypeScript interfaces
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
---
|
|
207
|
+
|
|
208
|
+
## Requirements
|
|
209
|
+
|
|
210
|
+
- Node.js >= 16
|
|
211
|
+
- npm or npx
|
|
212
|
+
|
|
213
|
+
## License
|
|
214
|
+
|
|
215
|
+
ISC
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ApiDefinition, TokenStore } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* Fetches API definitions from a protected endpoint.
|
|
4
|
+
* Requires a valid Bearer token in the token store.
|
|
5
|
+
*/
|
|
6
|
+
export declare function fetchApiDefinitions(apiDefinitionUrl: string, tokenStore: TokenStore): Promise<{
|
|
7
|
+
success: boolean;
|
|
8
|
+
definitions: ApiDefinition[];
|
|
9
|
+
message: string;
|
|
10
|
+
}>;
|
|
11
|
+
//# sourceMappingURL=apiDiscovery.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apiDiscovery.d.ts","sourceRoot":"","sources":["../src/apiDiscovery.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAEpD;;;GAGG;AACH,wBAAsB,mBAAmB,CACvC,gBAAgB,EAAE,MAAM,EACxB,UAAU,EAAE,UAAU,GACrB,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,WAAW,EAAE,aAAa,EAAE,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CA6C9E"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.fetchApiDefinitions = fetchApiDefinitions;
|
|
7
|
+
const axios_1 = __importDefault(require("axios"));
|
|
8
|
+
/**
|
|
9
|
+
* Fetches API definitions from a protected endpoint.
|
|
10
|
+
* Requires a valid Bearer token in the token store.
|
|
11
|
+
*/
|
|
12
|
+
async function fetchApiDefinitions(apiDefinitionUrl, tokenStore) {
|
|
13
|
+
const token = tokenStore.getToken();
|
|
14
|
+
if (!token) {
|
|
15
|
+
return { success: false, definitions: [], message: "Not authenticated. Call login first." };
|
|
16
|
+
}
|
|
17
|
+
try {
|
|
18
|
+
const response = await axios_1.default.get(apiDefinitionUrl, {
|
|
19
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
20
|
+
});
|
|
21
|
+
const data = response.data?.data;
|
|
22
|
+
const definitions = Array.isArray(data) ? data : [];
|
|
23
|
+
if (definitions.length === 0) {
|
|
24
|
+
return { success: true, definitions: [], message: "No API definitions returned." };
|
|
25
|
+
}
|
|
26
|
+
const normalized = definitions.map((d) => normalizeDefinition(d));
|
|
27
|
+
return {
|
|
28
|
+
success: true,
|
|
29
|
+
definitions: normalized,
|
|
30
|
+
message: `Fetched ${normalized.length} API definition(s).`,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
catch (err) {
|
|
34
|
+
const axiosErr = err;
|
|
35
|
+
const status = axiosErr.response?.status;
|
|
36
|
+
if (status === 401 || status === 403) {
|
|
37
|
+
tokenStore.clearToken();
|
|
38
|
+
return {
|
|
39
|
+
success: false,
|
|
40
|
+
definitions: [],
|
|
41
|
+
message: "Token expired or unauthorized. Please login again.",
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
return {
|
|
45
|
+
success: false,
|
|
46
|
+
definitions: [],
|
|
47
|
+
message: `Failed to fetch API definitions (HTTP ${status ?? "unknown"}): ${axiosErr.message}`,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
function normalizeDefinition(def) {
|
|
52
|
+
return {
|
|
53
|
+
name: String(def.name ?? "unnamed"),
|
|
54
|
+
description: String(def.description ?? ""),
|
|
55
|
+
method: normalizeMethod(def.method),
|
|
56
|
+
baseDomain: String(def.baseDomain ?? ""),
|
|
57
|
+
path: String(def.path ?? "/"),
|
|
58
|
+
queryParams: normalizeParams(def.queryParams),
|
|
59
|
+
bodyParams: normalizeParams(def.bodyParams),
|
|
60
|
+
pathParams: normalizeParams(def.pathParams),
|
|
61
|
+
headers: Array.isArray(def.headers) ? def.headers : [],
|
|
62
|
+
authType: def.authType === "None" ? "None" : "Bearer",
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
function normalizeMethod(raw) {
|
|
66
|
+
const m = String(raw).toUpperCase();
|
|
67
|
+
if (["GET", "POST", "PUT", "PATCH", "DELETE"].includes(m)) {
|
|
68
|
+
return m;
|
|
69
|
+
}
|
|
70
|
+
return "GET";
|
|
71
|
+
}
|
|
72
|
+
function normalizeParams(raw) {
|
|
73
|
+
if (!Array.isArray(raw))
|
|
74
|
+
return [];
|
|
75
|
+
return raw.map((p) => ({
|
|
76
|
+
name: String(p.name ?? ""),
|
|
77
|
+
type: ["string", "boolean", "number", "array"].includes(p.type) ? p.type : "string",
|
|
78
|
+
required: Boolean(p.required),
|
|
79
|
+
description: p.description ? String(p.description) : undefined,
|
|
80
|
+
default: p.default,
|
|
81
|
+
}));
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=apiDiscovery.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apiDiscovery.js","sourceRoot":"","sources":["../src/apiDiscovery.ts"],"names":[],"mappings":"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"}
|
package/dist/auth.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { TokenStore } from "./types";
|
|
2
|
+
export declare function createTokenStore(): TokenStore;
|
|
3
|
+
export declare function login(loginUrl: string, username: string, password: string, tokenStore: TokenStore): Promise<{
|
|
4
|
+
success: boolean;
|
|
5
|
+
message: string;
|
|
6
|
+
}>;
|
|
7
|
+
//# sourceMappingURL=auth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAGrC,wBAAgB,gBAAgB,IAAI,UAAU,CAoB7C;AAED,wBAAsB,KAAK,CACzB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,UAAU,GACrB,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAwChD"}
|
package/dist/auth.js
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.createTokenStore = createTokenStore;
|
|
7
|
+
exports.login = login;
|
|
8
|
+
const axios_1 = __importDefault(require("axios"));
|
|
9
|
+
const utils_1 = require("./utils");
|
|
10
|
+
function createTokenStore() {
|
|
11
|
+
let accessToken = null;
|
|
12
|
+
return {
|
|
13
|
+
get accessToken() {
|
|
14
|
+
return accessToken;
|
|
15
|
+
},
|
|
16
|
+
setToken(token) {
|
|
17
|
+
accessToken = token;
|
|
18
|
+
},
|
|
19
|
+
getToken() {
|
|
20
|
+
return accessToken;
|
|
21
|
+
},
|
|
22
|
+
clearToken() {
|
|
23
|
+
accessToken = null;
|
|
24
|
+
},
|
|
25
|
+
isAuthenticated() {
|
|
26
|
+
return accessToken !== null;
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
async function login(loginUrl, username, password, tokenStore) {
|
|
31
|
+
try {
|
|
32
|
+
const formData = new FormData();
|
|
33
|
+
formData.append("grant_type", "password");
|
|
34
|
+
formData.append("username", username);
|
|
35
|
+
formData.append("password", password);
|
|
36
|
+
(0, utils_1.log)("Login attempt for user:", username, "to URL:", loginUrl);
|
|
37
|
+
const response = await axios_1.default.post(loginUrl, formData, {
|
|
38
|
+
headers: {
|
|
39
|
+
clientId: "fleetxMcpClient",
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
const token = response.data?.access_token;
|
|
43
|
+
if (!token || typeof token !== "string") {
|
|
44
|
+
return {
|
|
45
|
+
success: false,
|
|
46
|
+
message: "Login succeeded but no access token found in response.",
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
tokenStore.setToken(token);
|
|
50
|
+
return { success: true, message: "Login successful. Tools are now available." };
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
const axiosErr = err;
|
|
54
|
+
const status = axiosErr.response?.status ?? "unknown";
|
|
55
|
+
const body = axiosErr.response?.data;
|
|
56
|
+
const detail = typeof body === "object" && body !== null && "message" in body
|
|
57
|
+
? body.message
|
|
58
|
+
: axiosErr.message;
|
|
59
|
+
return {
|
|
60
|
+
success: false,
|
|
61
|
+
message: `Login failed (HTTP ${status}): ${detail}`,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=auth.js.map
|
package/dist/auth.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":";;;;;AAIA,4CAoBC;AAED,sBA6CC;AAvED,kDAA0C;AAE1C,mCAA8B;AAE9B,SAAgB,gBAAgB;IAC9B,IAAI,WAAW,GAAkB,IAAI,CAAC;IAEtC,OAAO;QACL,IAAI,WAAW;YACb,OAAO,WAAW,CAAC;QACrB,CAAC;QACD,QAAQ,CAAC,KAAa;YACpB,WAAW,GAAG,KAAK,CAAC;QACtB,CAAC;QACD,QAAQ;YACN,OAAO,WAAW,CAAC;QACrB,CAAC;QACD,UAAU;YACR,WAAW,GAAG,IAAI,CAAC;QACrB,CAAC;QACD,eAAe;YACb,OAAO,WAAW,KAAK,IAAI,CAAC;QAC9B,CAAC;KACF,CAAC;AACJ,CAAC;AAEM,KAAK,UAAU,KAAK,CACzB,QAAgB,EAChB,QAAgB,EAChB,QAAgB,EAChB,UAAsB;IAEtB,IAAI,CAAC;QAEH,MAAM,QAAQ,GAAG,IAAI,QAAQ,EAAE,CAAC;QAChC,QAAQ,CAAC,MAAM,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC;QAC1C,QAAQ,CAAC,MAAM,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;QACtC,QAAQ,CAAC,MAAM,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;QACtC,IAAA,WAAG,EAAC,yBAAyB,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC;QAC9D,MAAM,QAAQ,GAAG,MAAM,eAAK,CAAC,IAAI,CAAC,QAAQ,EAAE,QAAQ,EAAE;YACpD,OAAO,EAAE;gBACP,QAAQ,EAAE,iBAAiB;aAC5B;SACF,CAAC,CAAC;QAEH,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAA;QAGzC,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YACxC,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,OAAO,EAAE,wDAAwD;aAClE,CAAC;QACJ,CAAC;QAED,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QAC3B,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,4CAA4C,EAAE,CAAC;IAClF,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,QAAQ,GAAG,GAAiB,CAAC;QACnC,MAAM,MAAM,GAAG,QAAQ,CAAC,QAAQ,EAAE,MAAM,IAAI,SAAS,CAAC;QACtD,MAAM,IAAI,GAAG,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAC;QACrC,MAAM,MAAM,GACV,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI,IAAI,SAAS,IAAI,IAAI;YAC5D,CAAC,CAAE,IAA4B,CAAC,OAAO;YACvC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC;QAEvB,OAAO;YACL,OAAO,EAAE,KAAK;YACd,OAAO,EAAE,sBAAsB,MAAM,MAAM,MAAM,EAAE;SACpD,CAAC;IACJ,CAAC;AACH,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
// Node will treat it as executable.
|
|
4
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
+
const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
6
|
+
const mcpServer_1 = require("./mcpServer");
|
|
7
|
+
const auth_1 = require("./auth");
|
|
8
|
+
const utils_1 = require("./utils");
|
|
9
|
+
async function main() {
|
|
10
|
+
const tokenStore = (0, auth_1.createTokenStore)();
|
|
11
|
+
const server = (0, mcpServer_1.createMcpServer)(tokenStore);
|
|
12
|
+
const transport = new stdio_js_1.StdioServerTransport();
|
|
13
|
+
await server.connect(transport);
|
|
14
|
+
(0, utils_1.log)("Running on stdio");
|
|
15
|
+
}
|
|
16
|
+
main().catch((err) => {
|
|
17
|
+
(0, utils_1.log)("Fatal error:", err);
|
|
18
|
+
process.exit(1);
|
|
19
|
+
});
|
|
20
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;AACA,oCAAoC;;AAEpC,wEAAiF;AACjF,2CAA8C;AAC9C,iCAA0C;AAC1C,mCAA8B;AAE9B,KAAK,UAAU,IAAI;IACjB,MAAM,UAAU,GAAG,IAAA,uBAAgB,GAAE,CAAC;IACtC,MAAM,MAAM,GAAG,IAAA,2BAAe,EAAC,UAAU,CAAC,CAAC;IAC3C,MAAM,SAAS,GAAG,IAAI,+BAAoB,EAAE,CAAC;IAE7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAChC,IAAA,WAAG,EAAC,kBAAkB,CAAC,CAAC;AAC1B,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACnB,IAAA,WAAG,EAAC,cAAc,EAAE,GAAG,CAAC,CAAC;IACzB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { TokenStore } from "./types";
|
|
3
|
+
/**
|
|
4
|
+
* Creates and configures the McpServer instance with login + dynamic tools.
|
|
5
|
+
*/
|
|
6
|
+
export declare function createMcpServer(tokenStore: TokenStore): McpServer;
|
|
7
|
+
//# sourceMappingURL=mcpServer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcpServer.d.ts","sourceRoot":"","sources":["../src/mcpServer.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,UAAU,EAAiB,MAAM,SAAS,CAAC;AAMpD;;GAEG;AACH,wBAAgB,eAAe,CAAC,UAAU,EAAE,UAAU,GAAG,SAAS,CASjE"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createMcpServer = createMcpServer;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
6
|
+
const auth_1 = require("./auth");
|
|
7
|
+
const apiDiscovery_1 = require("./apiDiscovery");
|
|
8
|
+
const toolGenerator_1 = require("./toolGenerator");
|
|
9
|
+
const utils_1 = require("./utils");
|
|
10
|
+
/**
|
|
11
|
+
* Creates and configures the McpServer instance with login + dynamic tools.
|
|
12
|
+
*/
|
|
13
|
+
function createMcpServer(tokenStore) {
|
|
14
|
+
const mcp = new mcp_js_1.McpServer({ name: "fleetx-mcp-server", version: "1.0.0" }, { capabilities: { tools: {} } });
|
|
15
|
+
registerLoginTool(mcp, tokenStore);
|
|
16
|
+
return mcp;
|
|
17
|
+
}
|
|
18
|
+
function registerLoginTool(mcp, tokenStore) {
|
|
19
|
+
mcp.tool("login", "Authenticate with the FleetX API. Must be called before any other tool.", {
|
|
20
|
+
username: zod_1.z.string().describe("Login username"),
|
|
21
|
+
password: zod_1.z.string().describe("Login password"),
|
|
22
|
+
}, async ({ username, password }) => {
|
|
23
|
+
const result = await (0, auth_1.login)((0, utils_1.getLoginURL)(), username, password, tokenStore);
|
|
24
|
+
if (!result.success) {
|
|
25
|
+
return {
|
|
26
|
+
content: [{ type: "text", text: result.message }],
|
|
27
|
+
isError: true,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
const discoveryResult = await (0, apiDiscovery_1.fetchApiDefinitions)((0, utils_1.getAPIDefinitionURL)(), tokenStore);
|
|
31
|
+
if (!discoveryResult.success) {
|
|
32
|
+
return {
|
|
33
|
+
content: [
|
|
34
|
+
{
|
|
35
|
+
type: "text",
|
|
36
|
+
text: `Login succeeded but failed to fetch API definitions: ${discoveryResult.message}`,
|
|
37
|
+
},
|
|
38
|
+
],
|
|
39
|
+
isError: true,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
const toolNames = registerDynamicTools(mcp, discoveryResult.definitions, tokenStore);
|
|
43
|
+
return {
|
|
44
|
+
content: [
|
|
45
|
+
{
|
|
46
|
+
type: "text",
|
|
47
|
+
text: [
|
|
48
|
+
result.message,
|
|
49
|
+
discoveryResult.message,
|
|
50
|
+
`Registered ${toolNames.length} tool(s): ${toolNames.join(", ")}`,
|
|
51
|
+
].join("\n"),
|
|
52
|
+
},
|
|
53
|
+
],
|
|
54
|
+
};
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
let registeredDynamicTools = [];
|
|
58
|
+
function registerDynamicTools(mcp, definitions, tokenStore) {
|
|
59
|
+
for (const rt of registeredDynamicTools) {
|
|
60
|
+
try {
|
|
61
|
+
rt.remove();
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
// tool may already have been removed
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
registeredDynamicTools = [];
|
|
68
|
+
const tools = (0, toolGenerator_1.generateTools)(definitions, tokenStore);
|
|
69
|
+
const registeredNames = [];
|
|
70
|
+
for (const tool of tools) {
|
|
71
|
+
if (tool.name === "login")
|
|
72
|
+
continue;
|
|
73
|
+
const shape = {};
|
|
74
|
+
for (const [key, propSchema] of Object.entries(tool.inputSchema.properties)) {
|
|
75
|
+
shape[key] = jsonSchemaPropertyToZod(propSchema, tool.inputSchema.required.includes(key));
|
|
76
|
+
}
|
|
77
|
+
try {
|
|
78
|
+
const registered = mcp.tool(tool.name, tool.description, shape, async (args) => {
|
|
79
|
+
const result = await tool.handler(args);
|
|
80
|
+
return result;
|
|
81
|
+
});
|
|
82
|
+
registeredDynamicTools.push(registered);
|
|
83
|
+
registeredNames.push(tool.name);
|
|
84
|
+
}
|
|
85
|
+
catch (err) {
|
|
86
|
+
(0, utils_1.log)(`Failed to register tool "${tool.name}":`, err);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
try {
|
|
90
|
+
mcp.sendToolListChanged();
|
|
91
|
+
}
|
|
92
|
+
catch (err) {
|
|
93
|
+
(0, utils_1.log)("sendToolListChanged failed:", err);
|
|
94
|
+
}
|
|
95
|
+
(0, utils_1.log)(`Registered ${registeredNames.length} dynamic tool(s): ${registeredNames.join(", ")}`);
|
|
96
|
+
return registeredNames;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Converts a single JSON-Schema property descriptor back to a Zod type
|
|
100
|
+
* for MCP tool registration.
|
|
101
|
+
*/
|
|
102
|
+
function jsonSchemaPropertyToZod(prop, required) {
|
|
103
|
+
const p = prop;
|
|
104
|
+
let schema;
|
|
105
|
+
switch (p.type) {
|
|
106
|
+
case "boolean":
|
|
107
|
+
schema = zod_1.z.boolean();
|
|
108
|
+
break;
|
|
109
|
+
case "number":
|
|
110
|
+
schema = zod_1.z.number();
|
|
111
|
+
break;
|
|
112
|
+
case "array":
|
|
113
|
+
schema = zod_1.z.array(zod_1.z.string());
|
|
114
|
+
break;
|
|
115
|
+
case "string":
|
|
116
|
+
default:
|
|
117
|
+
schema = zod_1.z.string();
|
|
118
|
+
break;
|
|
119
|
+
}
|
|
120
|
+
if (typeof p.description === "string") {
|
|
121
|
+
schema = schema.describe(p.description);
|
|
122
|
+
}
|
|
123
|
+
return required ? schema : schema.optional();
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=mcpServer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcpServer.js","sourceRoot":"","sources":["../src/mcpServer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ApiDefinition, TokenStore } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* Executes a proxied API call to the external service.
|
|
4
|
+
*/
|
|
5
|
+
export declare function proxyCall(apiDef: ApiDefinition, inputArgs: Record<string, unknown>, tokenStore: TokenStore): Promise<{
|
|
6
|
+
status: number;
|
|
7
|
+
data: unknown;
|
|
8
|
+
}>;
|
|
9
|
+
//# sourceMappingURL=proxyCaller.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxyCaller.d.ts","sourceRoot":"","sources":["../src/proxyCaller.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAiCpD;;GAEG;AACH,wBAAsB,SAAS,CAC7B,MAAM,EAAE,aAAa,EACrB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAClC,UAAU,EAAE,UAAU,GACrB,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC,CAuE5C"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.proxyCall = proxyCall;
|
|
7
|
+
const axios_1 = __importDefault(require("axios"));
|
|
8
|
+
/**
|
|
9
|
+
* Constructs the full URL by replacing path parameters and appending query parameters.
|
|
10
|
+
*/
|
|
11
|
+
function buildUrl(baseDomain, pathTemplate, pathParams, queryParams) {
|
|
12
|
+
let resolvedPath = pathTemplate;
|
|
13
|
+
for (const [key, value] of Object.entries(pathParams)) {
|
|
14
|
+
resolvedPath = resolvedPath.replace(`{{${key}}}`, encodeURIComponent(String(value)));
|
|
15
|
+
}
|
|
16
|
+
const base = baseDomain.endsWith("/") ? baseDomain.slice(0, -1) : baseDomain;
|
|
17
|
+
const path = resolvedPath.startsWith("/") ? resolvedPath : `/${resolvedPath}`;
|
|
18
|
+
const url = new URL(`${base}${path}`);
|
|
19
|
+
for (const [key, value] of Object.entries(queryParams)) {
|
|
20
|
+
if (value !== undefined && value !== null) {
|
|
21
|
+
if (Array.isArray(value)) {
|
|
22
|
+
value.forEach((v) => url.searchParams.append(key, String(v)));
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
url.searchParams.set(key, String(value));
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return url.toString();
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Executes a proxied API call to the external service.
|
|
33
|
+
*/
|
|
34
|
+
async function proxyCall(apiDef, inputArgs, tokenStore) {
|
|
35
|
+
const token = tokenStore.getToken();
|
|
36
|
+
if (!token && apiDef.authType === "Bearer") {
|
|
37
|
+
throw new Error("Not authenticated. Call login first.");
|
|
38
|
+
}
|
|
39
|
+
const pathParamNames = new Set((apiDef.pathParams ?? []).map((p) => p.name));
|
|
40
|
+
const queryParamNames = new Set((apiDef.queryParams ?? []).map((p) => p.name));
|
|
41
|
+
const bodyParamNames = new Set((apiDef.bodyParams ?? []).map((p) => p.name));
|
|
42
|
+
const pathValues = {};
|
|
43
|
+
const queryValues = {};
|
|
44
|
+
const bodyValues = {};
|
|
45
|
+
for (const [key, value] of Object.entries(inputArgs)) {
|
|
46
|
+
if (pathParamNames.has(key)) {
|
|
47
|
+
pathValues[key] = value;
|
|
48
|
+
}
|
|
49
|
+
else if (queryParamNames.has(key)) {
|
|
50
|
+
queryValues[key] = value;
|
|
51
|
+
}
|
|
52
|
+
else if (bodyParamNames.has(key)) {
|
|
53
|
+
bodyValues[key] = value;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
const url = buildUrl(apiDef.baseDomain, apiDef.path, pathValues, queryValues);
|
|
57
|
+
const headers = { "Content-Type": "application/json" };
|
|
58
|
+
if (apiDef.authType === "Bearer" && token) {
|
|
59
|
+
headers["Authorization"] = `Bearer ${token}`;
|
|
60
|
+
}
|
|
61
|
+
if (Array.isArray(apiDef.headers)) {
|
|
62
|
+
for (const h of apiDef.headers) {
|
|
63
|
+
if (h && typeof h === "object") {
|
|
64
|
+
Object.assign(headers, h);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
const config = {
|
|
69
|
+
method: apiDef.method.toLowerCase(),
|
|
70
|
+
url,
|
|
71
|
+
headers,
|
|
72
|
+
timeout: 30_000,
|
|
73
|
+
};
|
|
74
|
+
if (["POST", "PUT", "PATCH"].includes(apiDef.method) && Object.keys(bodyValues).length > 0) {
|
|
75
|
+
config.data = bodyValues;
|
|
76
|
+
}
|
|
77
|
+
try {
|
|
78
|
+
const response = await (0, axios_1.default)(config);
|
|
79
|
+
return { status: response.status, data: response.data };
|
|
80
|
+
}
|
|
81
|
+
catch (err) {
|
|
82
|
+
const axiosErr = err;
|
|
83
|
+
const status = axiosErr.response?.status ?? 500;
|
|
84
|
+
const data = axiosErr.response?.data ?? { message: axiosErr.message };
|
|
85
|
+
if (status === 401 || status === 403) {
|
|
86
|
+
tokenStore.clearToken();
|
|
87
|
+
}
|
|
88
|
+
return { status, data };
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=proxyCaller.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxyCaller.js","sourceRoot":"","sources":["../src/proxyCaller.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { z, ZodTypeAny } from "zod";
|
|
2
|
+
import { ApiParamDefinition } from "./types";
|
|
3
|
+
/**
|
|
4
|
+
* Builds a Zod object schema from a flat list of parameter definitions.
|
|
5
|
+
* Returns both the ZodObject and a JSON-Schema-compatible shape for MCP tool registration.
|
|
6
|
+
*/
|
|
7
|
+
export declare function buildZodSchema(params: ApiParamDefinition[]): z.ZodObject<Record<string, ZodTypeAny>>;
|
|
8
|
+
/**
|
|
9
|
+
* Converts a flat param list into a JSON Schema `properties` + `required` object
|
|
10
|
+
* suitable for MCP tool inputSchema registration.
|
|
11
|
+
*/
|
|
12
|
+
export declare function paramsToJsonSchema(params: ApiParamDefinition[]): {
|
|
13
|
+
type: "object";
|
|
14
|
+
properties: Record<string, object>;
|
|
15
|
+
required: string[];
|
|
16
|
+
};
|
|
17
|
+
//# sourceMappingURL=schemaBuilder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schemaBuilder.d.ts","sourceRoot":"","sources":["../src/schemaBuilder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,UAAU,EAAE,MAAM,KAAK,CAAC;AACpC,OAAO,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AA4B7C;;;GAGG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,kBAAkB,EAAE,GAAG,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAQpG;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,kBAAkB,EAAE,GAAG;IAChE,IAAI,EAAE,QAAQ,CAAC;IACf,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB,CAiCA"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildZodSchema = buildZodSchema;
|
|
4
|
+
exports.paramsToJsonSchema = paramsToJsonSchema;
|
|
5
|
+
const zod_1 = require("zod");
|
|
6
|
+
function primitiveToZod(param) {
|
|
7
|
+
let schema;
|
|
8
|
+
switch (param.type) {
|
|
9
|
+
case "boolean":
|
|
10
|
+
schema = zod_1.z.boolean();
|
|
11
|
+
break;
|
|
12
|
+
case "number":
|
|
13
|
+
schema = zod_1.z.number();
|
|
14
|
+
break;
|
|
15
|
+
case "array":
|
|
16
|
+
schema = zod_1.z.array(zod_1.z.string());
|
|
17
|
+
break;
|
|
18
|
+
case "string":
|
|
19
|
+
default:
|
|
20
|
+
schema = zod_1.z.string();
|
|
21
|
+
break;
|
|
22
|
+
}
|
|
23
|
+
if (param.description) {
|
|
24
|
+
schema = schema.describe(param.description);
|
|
25
|
+
}
|
|
26
|
+
return param.required ? schema : schema.optional();
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Builds a Zod object schema from a flat list of parameter definitions.
|
|
30
|
+
* Returns both the ZodObject and a JSON-Schema-compatible shape for MCP tool registration.
|
|
31
|
+
*/
|
|
32
|
+
function buildZodSchema(params) {
|
|
33
|
+
const shape = {};
|
|
34
|
+
for (const param of params) {
|
|
35
|
+
shape[param.name] = primitiveToZod(param);
|
|
36
|
+
}
|
|
37
|
+
return zod_1.z.object(shape);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Converts a flat param list into a JSON Schema `properties` + `required` object
|
|
41
|
+
* suitable for MCP tool inputSchema registration.
|
|
42
|
+
*/
|
|
43
|
+
function paramsToJsonSchema(params) {
|
|
44
|
+
const properties = {};
|
|
45
|
+
const required = [];
|
|
46
|
+
for (const param of params) {
|
|
47
|
+
const prop = {};
|
|
48
|
+
switch (param.type) {
|
|
49
|
+
case "boolean":
|
|
50
|
+
prop.type = "boolean";
|
|
51
|
+
break;
|
|
52
|
+
case "number":
|
|
53
|
+
prop.type = "number";
|
|
54
|
+
break;
|
|
55
|
+
case "array":
|
|
56
|
+
prop.type = "array";
|
|
57
|
+
prop.items = { type: "string" };
|
|
58
|
+
break;
|
|
59
|
+
case "string":
|
|
60
|
+
default:
|
|
61
|
+
prop.type = "string";
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
if (param.description)
|
|
65
|
+
prop.description = param.description;
|
|
66
|
+
if (param.default !== undefined)
|
|
67
|
+
prop.default = param.default;
|
|
68
|
+
properties[param.name] = prop;
|
|
69
|
+
if (param.required)
|
|
70
|
+
required.push(param.name);
|
|
71
|
+
}
|
|
72
|
+
return { type: "object", properties, required };
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=schemaBuilder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schemaBuilder.js","sourceRoot":"","sources":["../src/schemaBuilder.ts"],"names":[],"mappings":";;AAiCA,wCAQC;AAMD,gDAqCC;AApFD,6BAAoC;AAGpC,SAAS,cAAc,CAAC,KAAyB;IAC/C,IAAI,MAAkB,CAAC;IAEvB,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;QACnB,KAAK,SAAS;YACZ,MAAM,GAAG,OAAC,CAAC,OAAO,EAAE,CAAC;YACrB,MAAM;QACR,KAAK,QAAQ;YACX,MAAM,GAAG,OAAC,CAAC,MAAM,EAAE,CAAC;YACpB,MAAM;QACR,KAAK,OAAO;YACV,MAAM,GAAG,OAAC,CAAC,KAAK,CAAC,OAAC,CAAC,MAAM,EAAE,CAAC,CAAC;YAC7B,MAAM;QACR,KAAK,QAAQ,CAAC;QACd;YACE,MAAM,GAAG,OAAC,CAAC,MAAM,EAAE,CAAC;YACpB,MAAM;IACV,CAAC;IAED,IAAI,KAAK,CAAC,WAAW,EAAE,CAAC;QACtB,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IAC9C,CAAC;IAED,OAAO,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;AACrD,CAAC;AAED;;;GAGG;AACH,SAAgB,cAAc,CAAC,MAA4B;IACzD,MAAM,KAAK,GAA+B,EAAE,CAAC;IAE7C,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;IAC5C,CAAC;IAED,OAAO,OAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACzB,CAAC;AAED;;;GAGG;AACH,SAAgB,kBAAkB,CAAC,MAA4B;IAK7D,MAAM,UAAU,GAA2B,EAAE,CAAC;IAC9C,MAAM,QAAQ,GAAa,EAAE,CAAC;IAE9B,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,IAAI,GAA4B,EAAE,CAAC;QAEzC,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;YACnB,KAAK,SAAS;gBACZ,IAAI,CAAC,IAAI,GAAG,SAAS,CAAC;gBACtB,MAAM;YACR,KAAK,QAAQ;gBACX,IAAI,CAAC,IAAI,GAAG,QAAQ,CAAC;gBACrB,MAAM;YACR,KAAK,OAAO;gBACV,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC;gBACpB,IAAI,CAAC,KAAK,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;gBAChC,MAAM;YACR,KAAK,QAAQ,CAAC;YACd;gBACE,IAAI,CAAC,IAAI,GAAG,QAAQ,CAAC;gBACrB,MAAM;QACV,CAAC;QAED,IAAI,KAAK,CAAC,WAAW;YAAE,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC,WAAW,CAAC;QAC5D,IAAI,KAAK,CAAC,OAAO,KAAK,SAAS;YAAE,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC;QAE9D,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;QAE9B,IAAI,KAAK,CAAC,QAAQ;YAAE,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAChD,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC;AAClD,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { ApiDefinition, TokenStore, ToolInvocationResult } from "./types";
|
|
2
|
+
export interface GeneratedTool {
|
|
3
|
+
name: string;
|
|
4
|
+
description: string;
|
|
5
|
+
inputSchema: {
|
|
6
|
+
type: "object";
|
|
7
|
+
properties: Record<string, object>;
|
|
8
|
+
required: string[];
|
|
9
|
+
};
|
|
10
|
+
handler: (args: Record<string, unknown>) => Promise<ToolInvocationResult>;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Generates MCP tools for all API definitions.
|
|
14
|
+
*/
|
|
15
|
+
export declare function generateTools(apiDefinitions: ApiDefinition[], tokenStore: TokenStore): GeneratedTool[];
|
|
16
|
+
//# sourceMappingURL=toolGenerator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"toolGenerator.d.ts","sourceRoot":"","sources":["../src/toolGenerator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAsB,UAAU,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAI9F,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ,CAAC;QACf,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACnC,QAAQ,EAAE,MAAM,EAAE,CAAC;KACpB,CAAC;IACF,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,oBAAoB,CAAC,CAAC;CAC3E;AAgHD;;GAEG;AACH,wBAAgB,aAAa,CAC3B,cAAc,EAAE,aAAa,EAAE,EAC/B,UAAU,EAAE,UAAU,GACrB,aAAa,EAAE,CAEjB"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateTools = generateTools;
|
|
4
|
+
const schemaBuilder_1 = require("./schemaBuilder");
|
|
5
|
+
const proxyCaller_1 = require("./proxyCaller");
|
|
6
|
+
/**
|
|
7
|
+
* Convert an API name like "Get Vehicle Location" to "get_vehicle_location".
|
|
8
|
+
*/
|
|
9
|
+
function toSnakeCase(name) {
|
|
10
|
+
return name
|
|
11
|
+
.trim()
|
|
12
|
+
.replace(/[^a-zA-Z0-9\s]/g, "")
|
|
13
|
+
.replace(/\s+/g, "_")
|
|
14
|
+
.toLowerCase();
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Merges all param groups into a single flat list, de-duplicating by name.
|
|
18
|
+
*/
|
|
19
|
+
function mergeParams(apiDef) {
|
|
20
|
+
const seen = new Set();
|
|
21
|
+
const merged = [];
|
|
22
|
+
const groups = [
|
|
23
|
+
apiDef.pathParams ?? [],
|
|
24
|
+
apiDef.queryParams ?? [],
|
|
25
|
+
apiDef.bodyParams ?? [],
|
|
26
|
+
];
|
|
27
|
+
for (const group of groups) {
|
|
28
|
+
for (const param of group) {
|
|
29
|
+
if (!seen.has(param.name)) {
|
|
30
|
+
seen.add(param.name);
|
|
31
|
+
merged.push(param);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return merged;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Generates a single MCP-compatible tool from an API definition.
|
|
39
|
+
*/
|
|
40
|
+
function generateTool(apiDef, tokenStore) {
|
|
41
|
+
const allParams = mergeParams(apiDef);
|
|
42
|
+
const zodSchema = (0, schemaBuilder_1.buildZodSchema)(allParams);
|
|
43
|
+
const jsonSchema = (0, schemaBuilder_1.paramsToJsonSchema)(allParams);
|
|
44
|
+
const toolName = toSnakeCase(apiDef.name);
|
|
45
|
+
const handler = async (rawArgs) => {
|
|
46
|
+
if (!tokenStore.isAuthenticated()) {
|
|
47
|
+
return {
|
|
48
|
+
content: [{ type: "text", text: "Not authenticated. Please call the login tool first." }],
|
|
49
|
+
isError: true,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
const validation = zodSchema.safeParse(rawArgs);
|
|
53
|
+
if (!validation.success) {
|
|
54
|
+
const errors = validation.error.issues.map((issue) => `${issue.path.join(".")}: ${issue.message}`);
|
|
55
|
+
return {
|
|
56
|
+
content: [
|
|
57
|
+
{
|
|
58
|
+
type: "text",
|
|
59
|
+
text: `Validation failed:\n${errors.join("\n")}`,
|
|
60
|
+
},
|
|
61
|
+
],
|
|
62
|
+
isError: true,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
try {
|
|
66
|
+
const result = await (0, proxyCaller_1.proxyCall)(apiDef, validation.data, tokenStore);
|
|
67
|
+
if (result.status === 401 || result.status === 403) {
|
|
68
|
+
return {
|
|
69
|
+
content: [
|
|
70
|
+
{
|
|
71
|
+
type: "text",
|
|
72
|
+
text: "Authentication expired. Please call the login tool again.",
|
|
73
|
+
},
|
|
74
|
+
],
|
|
75
|
+
isError: true,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
return {
|
|
79
|
+
content: [
|
|
80
|
+
{
|
|
81
|
+
type: "text",
|
|
82
|
+
text: JSON.stringify(result.data, null, 2),
|
|
83
|
+
},
|
|
84
|
+
],
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
catch (err) {
|
|
88
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
89
|
+
return {
|
|
90
|
+
content: [{ type: "text", text: `API call failed: ${message}` }],
|
|
91
|
+
isError: true,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
return {
|
|
96
|
+
name: toolName,
|
|
97
|
+
description: apiDef.description || `Invoke ${apiDef.name}`,
|
|
98
|
+
inputSchema: jsonSchema,
|
|
99
|
+
handler,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Generates MCP tools for all API definitions.
|
|
104
|
+
*/
|
|
105
|
+
function generateTools(apiDefinitions, tokenStore) {
|
|
106
|
+
return apiDefinitions.map((def) => generateTool(def, tokenStore));
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=toolGenerator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"toolGenerator.js","sourceRoot":"","sources":["../src/toolGenerator.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export interface ApiParamDefinition {
|
|
2
|
+
name: string;
|
|
3
|
+
type: "string" | "boolean" | "number" | "array";
|
|
4
|
+
required: boolean;
|
|
5
|
+
description?: string;
|
|
6
|
+
default?: unknown;
|
|
7
|
+
}
|
|
8
|
+
export interface ApiDefinition {
|
|
9
|
+
name: string;
|
|
10
|
+
description: string;
|
|
11
|
+
method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
|
|
12
|
+
baseDomain: string;
|
|
13
|
+
path: string;
|
|
14
|
+
queryParams: ApiParamDefinition[];
|
|
15
|
+
bodyParams: ApiParamDefinition[];
|
|
16
|
+
pathParams: ApiParamDefinition[];
|
|
17
|
+
headers: Record<string, string>[];
|
|
18
|
+
authType: "Bearer" | "None";
|
|
19
|
+
}
|
|
20
|
+
export interface TokenStore {
|
|
21
|
+
accessToken: string | null;
|
|
22
|
+
setToken(token: string): void;
|
|
23
|
+
getToken(): string | null;
|
|
24
|
+
clearToken(): void;
|
|
25
|
+
isAuthenticated(): boolean;
|
|
26
|
+
}
|
|
27
|
+
export interface ToolInvocationResult {
|
|
28
|
+
[key: string]: unknown;
|
|
29
|
+
content: Array<{
|
|
30
|
+
type: "text";
|
|
31
|
+
text: string;
|
|
32
|
+
}>;
|
|
33
|
+
isError?: boolean;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,QAAQ,GAAG,SAAS,GAAG,QAAQ,GAAG,OAAO,CAAC;IAChD,QAAQ,EAAE,OAAO,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,CAAC;IACpD,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,kBAAkB,EAAE,CAAC;IAClC,UAAU,EAAE,kBAAkB,EAAE,CAAC;IACjC,UAAU,EAAE,kBAAkB,EAAE,CAAC;IACjC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC;IAClC,QAAQ,EAAE,QAAQ,GAAG,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,UAAU;IACzB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,QAAQ,IAAI,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,IAAI,IAAI,CAAC;IACnB,eAAe,IAAI,OAAO,CAAC;CAC5B;AAED,MAAM,WAAW,oBAAoB;IACnC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IACvB,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/C,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* All logging goes to stderr so stdout stays clean for the stdio JSON-RPC transport.
|
|
3
|
+
* Use log() everywhere instead of console.log / console.error.
|
|
4
|
+
*/
|
|
5
|
+
export declare function log(...args: unknown[]): void;
|
|
6
|
+
export declare function getAPIDefinitionURL(): string;
|
|
7
|
+
export declare function getLoginURL(): string;
|
|
8
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,wBAAgB,GAAG,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,QAIrC;AAED,wBAAgB,mBAAmB,IAAI,MAAM,CAE5C;AAED,wBAAgB,WAAW,IAAI,MAAM,CAEpC"}
|
package/dist/utils.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.log = log;
|
|
4
|
+
exports.getAPIDefinitionURL = getAPIDefinitionURL;
|
|
5
|
+
exports.getLoginURL = getLoginURL;
|
|
6
|
+
/**
|
|
7
|
+
* All logging goes to stderr so stdout stays clean for the stdio JSON-RPC transport.
|
|
8
|
+
* Use log() everywhere instead of console.log / console.error.
|
|
9
|
+
*/
|
|
10
|
+
function log(...args) {
|
|
11
|
+
const msg = args.map((a) => (typeof a === "string" ? a : JSON.stringify(a))).join(" ");
|
|
12
|
+
console.error(`[FleetX MCP] ${msg}`);
|
|
13
|
+
}
|
|
14
|
+
function getAPIDefinitionURL() {
|
|
15
|
+
return process.env.API_DEFINITION_URL ?? "https://app.fleetx.io/napp/api-reference/apis";
|
|
16
|
+
}
|
|
17
|
+
function getLoginURL() {
|
|
18
|
+
return process.env.LOGIN_URL ?? "https://api.fleetx.io/api/v1/login";
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":";;AAIA,kBAIC;AAED,kDAEC;AAED,kCAEC;AAhBD;;;GAGG;AACH,SAAgB,GAAG,CAAC,GAAG,IAAe;IACpC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACvF,OAAO,CAAC,KAAK,CAAC,gBAAgB,GAAG,EAAE,CAAC,CAAC;AAEvC,CAAC;AAED,SAAgB,mBAAmB;IACjC,OAAO,OAAO,CAAC,GAAG,CAAC,kBAAmB,IAAI,+CAA+C,CAAC;AAC5F,CAAC;AAED,SAAgB,WAAW;IACzB,OAAO,OAAO,CAAC,GAAG,CAAC,SAAU,IAAI,oCAAoC,CAAC;AACxE,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@fleetx_io/fleetx-mcp-server",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "MCP server that gives AI agents access to the FleetX REST API. Works with Cursor, Claude Desktop, Windsurf, and any MCP-compatible client.",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"bin": {
|
|
8
|
+
"fleetx-mcp-server": "dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist",
|
|
12
|
+
"README.md",
|
|
13
|
+
"CHANGELOG.md",
|
|
14
|
+
"LICENSE"
|
|
15
|
+
],
|
|
16
|
+
"publishConfig": {
|
|
17
|
+
"access": "public"
|
|
18
|
+
},
|
|
19
|
+
"scripts": {
|
|
20
|
+
"dev": "ts-node-dev --respawn --transpile-only ./src/index.ts",
|
|
21
|
+
"build": "tsc",
|
|
22
|
+
"publish": "npm run build && npm publish --access public",
|
|
23
|
+
"start": "node dist/index.js",
|
|
24
|
+
"startClientLive": "npx @modelcontextprotocol/inspector ts-node-dev --respawn --transpile-only ./src/index.ts",
|
|
25
|
+
"startClient": "npx @modelcontextprotocol/inspector node dist/index.js"
|
|
26
|
+
},
|
|
27
|
+
"keywords": [
|
|
28
|
+
"mcp",
|
|
29
|
+
"model-context-protocol",
|
|
30
|
+
"fleetx",
|
|
31
|
+
"ai",
|
|
32
|
+
"agent",
|
|
33
|
+
"fleet-management",
|
|
34
|
+
"cursor",
|
|
35
|
+
"claude",
|
|
36
|
+
"windsurf",
|
|
37
|
+
"stdio",
|
|
38
|
+
"api-gateway"
|
|
39
|
+
],
|
|
40
|
+
"author": "FleetX <satish@fleetx.io> (https://fleetx.io)",
|
|
41
|
+
"license": "ISC",
|
|
42
|
+
"repository": {
|
|
43
|
+
"type": "git",
|
|
44
|
+
"url": "https://gitlab.stg-fleetx.io/fleetxdev/fleetx-mcp-server.git"
|
|
45
|
+
},
|
|
46
|
+
"homepage": "https://gitlab.stg-fleetx.io/fleetxdev/fleetx-mcp-server#readme",
|
|
47
|
+
"bugs": {
|
|
48
|
+
"url": "https://gitlab.stg-fleetx.io/fleetxdev/fleetx-mcp-server/issues"
|
|
49
|
+
},
|
|
50
|
+
"engines": {
|
|
51
|
+
"node": ">=20.0.0"
|
|
52
|
+
},
|
|
53
|
+
"dependencies": {
|
|
54
|
+
"@modelcontextprotocol/sdk": "^1.27.1",
|
|
55
|
+
"axios": "^1.13.6",
|
|
56
|
+
"zod": "^4.3.6"
|
|
57
|
+
},
|
|
58
|
+
"devDependencies": {
|
|
59
|
+
"@types/node": "^25.3.3",
|
|
60
|
+
"ts-node-dev": "^2.0.0",
|
|
61
|
+
"typescript": "^5.9.3"
|
|
62
|
+
}
|
|
63
|
+
}
|