tomoshi 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/README.md +28 -0
- package/dist/auth-provider.d.ts +8 -0
- package/dist/auth-provider.d.ts.map +1 -0
- package/dist/auth-provider.js +89 -0
- package/dist/auth-provider.js.map +1 -0
- package/dist/client.d.ts +348 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +240 -0
- package/dist/client.js.map +1 -0
- package/dist/config.d.ts +39 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +57 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +151 -0
- package/dist/index.js.map +1 -0
- package/dist/server.d.ts +7 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +87 -0
- package/dist/server.js.map +1 -0
- package/dist/stdio.d.ts +3 -0
- package/dist/stdio.d.ts.map +1 -0
- package/dist/stdio.js +7 -0
- package/dist/stdio.js.map +1 -0
- package/dist/tools/discover.d.ts +52 -0
- package/dist/tools/discover.d.ts.map +1 -0
- package/dist/tools/discover.js +209 -0
- package/dist/tools/discover.js.map +1 -0
- package/dist/tools/extract.d.ts +147 -0
- package/dist/tools/extract.d.ts.map +1 -0
- package/dist/tools/extract.js +351 -0
- package/dist/tools/extract.js.map +1 -0
- package/dist/tools/monitor.d.ts +34 -0
- package/dist/tools/monitor.d.ts.map +1 -0
- package/dist/tools/monitor.js +95 -0
- package/dist/tools/monitor.js.map +1 -0
- package/package.json +53 -0
package/dist/client.js
ADDED
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
import { getConfig } from "./config.js";
|
|
2
|
+
// ---------------------------------------------------------------------------
|
|
3
|
+
// SSRF Prevention
|
|
4
|
+
// ---------------------------------------------------------------------------
|
|
5
|
+
/**
|
|
6
|
+
* Validate a URL to prevent Server-Side Request Forgery attacks.
|
|
7
|
+
* Blocks private IPs, localhost, and non-HTTP(S) protocols.
|
|
8
|
+
*/
|
|
9
|
+
function validateUrl(url) {
|
|
10
|
+
try {
|
|
11
|
+
const parsed = new URL(url);
|
|
12
|
+
// Must be HTTP or HTTPS
|
|
13
|
+
if (!["http:", "https:"].includes(parsed.protocol)) {
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
// Block private/internal hosts
|
|
17
|
+
const hostname = parsed.hostname.toLowerCase();
|
|
18
|
+
if (hostname === "localhost" ||
|
|
19
|
+
hostname === "127.0.0.1" ||
|
|
20
|
+
hostname === "0.0.0.0" ||
|
|
21
|
+
hostname.startsWith("10.") ||
|
|
22
|
+
hostname.startsWith("172.16.") ||
|
|
23
|
+
hostname.startsWith("192.168.") ||
|
|
24
|
+
hostname.endsWith(".local") ||
|
|
25
|
+
hostname.endsWith(".internal")) {
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
// Cinder API Client
|
|
36
|
+
// ---------------------------------------------------------------------------
|
|
37
|
+
/**
|
|
38
|
+
* Timeout configuration per endpoint type (milliseconds).
|
|
39
|
+
*
|
|
40
|
+
* These are deliberately generous: the Cinder backend runs on Fly.io with
|
|
41
|
+
* scale-to-zero, so a request may first trigger a ~10-15s cold start before
|
|
42
|
+
* the actual work begins. Tight timeouts turn cold starts into hard failures.
|
|
43
|
+
*/
|
|
44
|
+
export const CINDER_TIMEOUT = {
|
|
45
|
+
scrape: 60_000,
|
|
46
|
+
crawl: 30_000,
|
|
47
|
+
crawlStatus: 15_000,
|
|
48
|
+
search: 30_000,
|
|
49
|
+
monitor: 30_000,
|
|
50
|
+
monitorStatus: 15_000,
|
|
51
|
+
monitorDelete: 15_000,
|
|
52
|
+
map: 30_000,
|
|
53
|
+
batch: 30_000,
|
|
54
|
+
batchStatus: 15_000,
|
|
55
|
+
links: 60_000,
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* HTTP client for the Cinder API.
|
|
59
|
+
* Wraps all Cinder endpoints with type-safe methods, error handling, and SSRF prevention.
|
|
60
|
+
*/
|
|
61
|
+
export class CinderClient {
|
|
62
|
+
baseUrl;
|
|
63
|
+
apiKey;
|
|
64
|
+
constructor() {
|
|
65
|
+
const config = getConfig();
|
|
66
|
+
const rawUrl = config.TOMOSHIBI_API_URL || config.CINDER_API_URL;
|
|
67
|
+
this.baseUrl = rawUrl.replace(/\/+$/, "");
|
|
68
|
+
this.apiKey = config.CINDER_API_KEY;
|
|
69
|
+
}
|
|
70
|
+
get headers() {
|
|
71
|
+
const h = {
|
|
72
|
+
"Content-Type": "application/json",
|
|
73
|
+
};
|
|
74
|
+
if (this.apiKey) {
|
|
75
|
+
// Cinder expects the API key as `X-API-Key` (see API docs §8).
|
|
76
|
+
h["X-API-Key"] = this.apiKey;
|
|
77
|
+
}
|
|
78
|
+
return h;
|
|
79
|
+
}
|
|
80
|
+
async request(method, path, body, timeout) {
|
|
81
|
+
const url = `${this.baseUrl}${path}`;
|
|
82
|
+
const controller = new AbortController();
|
|
83
|
+
const timer = timeout
|
|
84
|
+
? setTimeout(() => controller.abort(), timeout)
|
|
85
|
+
: null;
|
|
86
|
+
try {
|
|
87
|
+
const response = await fetch(url, {
|
|
88
|
+
method,
|
|
89
|
+
headers: this.headers,
|
|
90
|
+
body: body ? JSON.stringify(body) : undefined,
|
|
91
|
+
signal: controller.signal,
|
|
92
|
+
});
|
|
93
|
+
// 204 No Content (e.g. DELETE /v1/monitor/:id) has no body to parse.
|
|
94
|
+
if (response.status === 204) {
|
|
95
|
+
return undefined;
|
|
96
|
+
}
|
|
97
|
+
if (!response.ok) {
|
|
98
|
+
const errorBody = await response.text().catch(() => "");
|
|
99
|
+
throw new CinderError(`Cinder API error: ${response.status} ${response.statusText}`, response.status, errorBody);
|
|
100
|
+
}
|
|
101
|
+
return (await response.json());
|
|
102
|
+
}
|
|
103
|
+
catch (err) {
|
|
104
|
+
if (err instanceof CinderError)
|
|
105
|
+
throw err;
|
|
106
|
+
if (err instanceof DOMException && err.name === "AbortError") {
|
|
107
|
+
throw new CinderError(`Request timed out after ${timeout}ms`, 408, "");
|
|
108
|
+
}
|
|
109
|
+
throw new CinderError(err instanceof Error ? err.message : "Unknown error", 0, "");
|
|
110
|
+
}
|
|
111
|
+
finally {
|
|
112
|
+
if (timer)
|
|
113
|
+
clearTimeout(timer);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Scrape a single webpage.
|
|
118
|
+
* POST /v1/scrape
|
|
119
|
+
*/
|
|
120
|
+
async scrape(params) {
|
|
121
|
+
if (!validateUrl(params.url)) {
|
|
122
|
+
throw new CinderError("Invalid or blocked URL. Only HTTP(S) URLs to public hosts are allowed.", 400, "");
|
|
123
|
+
}
|
|
124
|
+
return this.request("POST", "/v1/scrape", params, CINDER_TIMEOUT.scrape);
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Scrape multiple URLs synchronously (no Redis).
|
|
128
|
+
* POST /v1/scrape with { urls: [...] } — mirrors web_fetch_exa and
|
|
129
|
+
* Firecrawl POST /v2/batch/scrape sync. Max 10 URLs, errgroup limit 5.
|
|
130
|
+
*/
|
|
131
|
+
async scrapeMulti(params) {
|
|
132
|
+
for (const u of params.urls) {
|
|
133
|
+
if (!validateUrl(u)) {
|
|
134
|
+
throw new CinderError(`Invalid or blocked URL in multi-scrape: ${u}. Only HTTP(S) URLs to public hosts are allowed.`, 400, "");
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return this.request("POST", "/v1/scrape", params, CINDER_TIMEOUT.scrape);
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Enqueue an asynchronous crawl job.
|
|
141
|
+
* POST /v1/crawl
|
|
142
|
+
*/
|
|
143
|
+
async crawl(params) {
|
|
144
|
+
if (!validateUrl(params.url)) {
|
|
145
|
+
throw new CinderError("Invalid or blocked URL. Only HTTP(S) URLs to public hosts are allowed.", 400, "");
|
|
146
|
+
}
|
|
147
|
+
return this.request("POST", "/v1/crawl", params, CINDER_TIMEOUT.crawl);
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Get crawl job status.
|
|
151
|
+
* GET /v1/crawl/:id
|
|
152
|
+
*/
|
|
153
|
+
async getCrawlStatus(id) {
|
|
154
|
+
return this.request("GET", `/v1/crawl/${encodeURIComponent(id)}`, undefined, CINDER_TIMEOUT.crawlStatus);
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Search the web via SearXNG (primary) or Brave Search (fallback).
|
|
158
|
+
* POST /v1/search
|
|
159
|
+
*/
|
|
160
|
+
async search(params) {
|
|
161
|
+
return this.request("POST", "/v1/search", params, CINDER_TIMEOUT.search);
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Discover URLs on a site via sitemap/link traversal.
|
|
165
|
+
* POST /v1/map
|
|
166
|
+
*/
|
|
167
|
+
async map(params) {
|
|
168
|
+
if (!validateUrl(params.url)) {
|
|
169
|
+
throw new CinderError("Invalid or blocked URL. Only HTTP(S) URLs to public hosts are allowed.", 400, "");
|
|
170
|
+
}
|
|
171
|
+
return this.request("POST", "/v1/map", params, CINDER_TIMEOUT.map);
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Enqueue a batch scrape job (requires Redis).
|
|
175
|
+
* POST /v1/batch/scrape
|
|
176
|
+
*/
|
|
177
|
+
async batchScrape(params) {
|
|
178
|
+
for (const u of params.urls) {
|
|
179
|
+
if (!validateUrl(u)) {
|
|
180
|
+
throw new CinderError(`Invalid or blocked URL in batch: ${u}. Only HTTP(S) URLs to public hosts are allowed.`, 400, "");
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
return this.request("POST", "/v1/batch/scrape", params, CINDER_TIMEOUT.batch);
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Get batch scrape status (requires Redis).
|
|
187
|
+
* GET /v1/batch/:id
|
|
188
|
+
*/
|
|
189
|
+
async getBatchStatus(batchId) {
|
|
190
|
+
return this.request("GET", `/v1/batch/${encodeURIComponent(batchId)}`, undefined, CINDER_TIMEOUT.batchStatus);
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Extract links from a page (via scrape with include_links).
|
|
194
|
+
* Reuses POST /v1/scrape — same SSRF/timeouts as scrape.
|
|
195
|
+
*/
|
|
196
|
+
async links(url) {
|
|
197
|
+
if (!validateUrl(url)) {
|
|
198
|
+
throw new CinderError("Invalid or blocked URL. Only HTTP(S) URLs to public hosts are allowed.", 400, "");
|
|
199
|
+
}
|
|
200
|
+
return this.request("POST", "/v1/scrape", { url, include_links: true }, CINDER_TIMEOUT.links);
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Create a change-tracking monitor (requires Redis).
|
|
204
|
+
* POST /v1/monitor
|
|
205
|
+
*/
|
|
206
|
+
async createMonitor(params) {
|
|
207
|
+
if (!validateUrl(params.url)) {
|
|
208
|
+
throw new CinderError("Invalid or blocked URL. Only HTTP(S) URLs to public hosts are allowed.", 400, "");
|
|
209
|
+
}
|
|
210
|
+
return this.request("POST", "/v1/monitor", params, CINDER_TIMEOUT.monitor);
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Get monitor status (config + last hash + next check).
|
|
214
|
+
* GET /v1/monitor/:id
|
|
215
|
+
*/
|
|
216
|
+
async getMonitor(id) {
|
|
217
|
+
return this.request("GET", `/v1/monitor/${encodeURIComponent(id)}`, undefined, CINDER_TIMEOUT.monitorStatus);
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Stop monitoring and remove the monitor record.
|
|
221
|
+
* DELETE /v1/monitor/:id
|
|
222
|
+
*/
|
|
223
|
+
async deleteMonitor(id) {
|
|
224
|
+
await this.request("DELETE", `/v1/monitor/${encodeURIComponent(id)}`, undefined, CINDER_TIMEOUT.monitorDelete);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
// ---------------------------------------------------------------------------
|
|
228
|
+
// Custom Error
|
|
229
|
+
// ---------------------------------------------------------------------------
|
|
230
|
+
export class CinderError extends Error {
|
|
231
|
+
statusCode;
|
|
232
|
+
body;
|
|
233
|
+
constructor(message, statusCode, body) {
|
|
234
|
+
super(message);
|
|
235
|
+
this.statusCode = statusCode;
|
|
236
|
+
this.body = body;
|
|
237
|
+
this.name = "CinderError";
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import * as v from "valibot";
|
|
2
|
+
/**
|
|
3
|
+
* Environment configuration schema validated with Valibot.
|
|
4
|
+
* Provides typed access to all configuration values with sensible defaults.
|
|
5
|
+
*/
|
|
6
|
+
declare const ConfigSchema: v.ObjectSchema<{
|
|
7
|
+
/** Cinder API base URL — must point to your own Cinder instance */
|
|
8
|
+
readonly CINDER_API_URL: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.UrlAction<string, undefined>]>, "">;
|
|
9
|
+
/** Tomoshibi API URL (new name, preferred) */
|
|
10
|
+
readonly TOMOSHIBI_API_URL: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.UrlAction<string, undefined>]>, "">;
|
|
11
|
+
/** Optional API key if Cinder requires authentication */
|
|
12
|
+
readonly CINDER_API_KEY: v.OptionalSchema<v.StringSchema<undefined>, "">;
|
|
13
|
+
/** MCP server identity */
|
|
14
|
+
readonly MCP_SERVER_NAME: v.OptionalSchema<v.StringSchema<undefined>, "cinder-mcp">;
|
|
15
|
+
readonly MCP_SERVER_VERSION: v.OptionalSchema<v.StringSchema<undefined>, "1.0.0">;
|
|
16
|
+
/** HTTP server port */
|
|
17
|
+
readonly PORT: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TransformAction<any, number>]>, "7433">;
|
|
18
|
+
/** OAuth 2.1 configuration */
|
|
19
|
+
readonly OAUTH_ENABLED: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TransformAction<string, boolean>]>, "false">;
|
|
20
|
+
readonly OAUTH_ISSUER: v.OptionalSchema<v.StringSchema<undefined>, "">;
|
|
21
|
+
readonly OAUTH_AUDIENCE: v.OptionalSchema<v.StringSchema<undefined>, "">;
|
|
22
|
+
readonly OAUTH_SCOPES: v.OptionalSchema<v.StringSchema<undefined>, "scrape,crawl,search,monitor">;
|
|
23
|
+
/** Session management */
|
|
24
|
+
readonly REDIS_URL: v.OptionalSchema<v.StringSchema<undefined>, "">;
|
|
25
|
+
readonly MCP_SESSION_MANAGER: v.OptionalSchema<v.PicklistSchema<["memory", "redis"], undefined>, "memory">;
|
|
26
|
+
/** Rate limiting */
|
|
27
|
+
readonly RATE_LIMIT_WINDOW_MS: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TransformAction<any, number>]>, "60000">;
|
|
28
|
+
readonly RATE_LIMIT_MAX: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TransformAction<any, number>]>, "60">;
|
|
29
|
+
/** Logging */
|
|
30
|
+
readonly LOG_LEVEL: v.OptionalSchema<v.PicklistSchema<["debug", "info", "warn", "error"], undefined>, "info">;
|
|
31
|
+
}, undefined>;
|
|
32
|
+
type Config = v.InferOutput<typeof ConfigSchema>;
|
|
33
|
+
/**
|
|
34
|
+
* Get the application configuration.
|
|
35
|
+
* Parses environment variables once and caches the result.
|
|
36
|
+
*/
|
|
37
|
+
export declare function getConfig(): Config;
|
|
38
|
+
export type { Config };
|
|
39
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,SAAS,CAAC;AAE7B;;;GAGG;AACH,QAAA,MAAM,YAAY;IAChB,mEAAmE;;IAEnE,8CAA8C;;IAG9C,yDAAyD;;IAGzD,0BAA0B;;;IAI1B,uBAAuB;;IAGvB,8BAA8B;;;;;IAY9B,yBAAyB;;;IAIzB,oBAAoB;;;IAOpB,cAAc;;aAEd,CAAC;AAEH,KAAK,MAAM,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,YAAY,CAAC,CAAC;AAIjD;;;GAGG;AACH,wBAAgB,SAAS,IAAI,MAAM,CAwBlC;AAED,YAAY,EAAE,MAAM,EAAE,CAAC"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import * as v from "valibot";
|
|
2
|
+
/**
|
|
3
|
+
* Environment configuration schema validated with Valibot.
|
|
4
|
+
* Provides typed access to all configuration values with sensible defaults.
|
|
5
|
+
*/
|
|
6
|
+
const ConfigSchema = v.object({
|
|
7
|
+
/** Cinder API base URL — must point to your own Cinder instance */
|
|
8
|
+
CINDER_API_URL: v.optional(v.pipe(v.string(), v.url()), ""),
|
|
9
|
+
/** Tomoshibi API URL (new name, preferred) */
|
|
10
|
+
TOMOSHIBI_API_URL: v.optional(v.pipe(v.string(), v.url()), ""),
|
|
11
|
+
/** Optional API key if Cinder requires authentication */
|
|
12
|
+
CINDER_API_KEY: v.optional(v.string(), ""),
|
|
13
|
+
/** MCP server identity */
|
|
14
|
+
MCP_SERVER_NAME: v.optional(v.string(), "cinder-mcp"),
|
|
15
|
+
MCP_SERVER_VERSION: v.optional(v.string(), "1.0.0"),
|
|
16
|
+
/** HTTP server port */
|
|
17
|
+
PORT: v.optional(v.pipe(v.string(), v.transform(Number)), "7433"),
|
|
18
|
+
/** OAuth 2.1 configuration */
|
|
19
|
+
OAUTH_ENABLED: v.optional(v.pipe(v.string(), v.transform((s) => s === "true")), "false"),
|
|
20
|
+
OAUTH_ISSUER: v.optional(v.string(), ""),
|
|
21
|
+
OAUTH_AUDIENCE: v.optional(v.string(), ""),
|
|
22
|
+
OAUTH_SCOPES: v.optional(v.string(), "scrape,crawl,search,monitor"),
|
|
23
|
+
/** Session management */
|
|
24
|
+
REDIS_URL: v.optional(v.string(), ""),
|
|
25
|
+
MCP_SESSION_MANAGER: v.optional(v.picklist(["memory", "redis"]), "memory"),
|
|
26
|
+
/** Rate limiting */
|
|
27
|
+
RATE_LIMIT_WINDOW_MS: v.optional(v.pipe(v.string(), v.transform(Number)), "60000"),
|
|
28
|
+
RATE_LIMIT_MAX: v.optional(v.pipe(v.string(), v.transform(Number)), "60"),
|
|
29
|
+
/** Logging */
|
|
30
|
+
LOG_LEVEL: v.optional(v.picklist(["debug", "info", "warn", "error"]), "info"),
|
|
31
|
+
});
|
|
32
|
+
let config = null;
|
|
33
|
+
/**
|
|
34
|
+
* Get the application configuration.
|
|
35
|
+
* Parses environment variables once and caches the result.
|
|
36
|
+
*/
|
|
37
|
+
export function getConfig() {
|
|
38
|
+
if (config)
|
|
39
|
+
return config;
|
|
40
|
+
const parsed = v.safeParse(ConfigSchema, process.env);
|
|
41
|
+
if (!parsed.success) {
|
|
42
|
+
console.error("Invalid configuration:", v.flatten(parsed.issues));
|
|
43
|
+
process.exit(1);
|
|
44
|
+
}
|
|
45
|
+
config = parsed.output;
|
|
46
|
+
// TOMOSHIBI_API_URL is the new name, CINDER_API_URL is legacy compat
|
|
47
|
+
const apiUrl = config.TOMOSHIBI_API_URL || config.CINDER_API_URL;
|
|
48
|
+
if (!apiUrl) {
|
|
49
|
+
console.error("❌ TOMOSHIBI_API_URL (or CINDER_API_URL) is required. Set it in your .env or via `fly secrets set TOMOSHIBI_API_URL=https://your-tomoshibi.fly.dev`");
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
52
|
+
// Normalize so downstream code can use either
|
|
53
|
+
config.CINDER_API_URL = apiUrl;
|
|
54
|
+
config.TOMOSHIBI_API_URL = apiUrl;
|
|
55
|
+
return config;
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
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,151 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
import { serve } from "srvx";
|
|
3
|
+
import { StdioTransport } from "@tmcp/transport-stdio";
|
|
4
|
+
import { HttpTransport } from "@tmcp/transport-http";
|
|
5
|
+
import { SseTransport } from "@tmcp/transport-sse";
|
|
6
|
+
import { createServer } from "./server.js";
|
|
7
|
+
import { getConfig } from "./config.js";
|
|
8
|
+
import { oauth } from "./auth-provider.js";
|
|
9
|
+
// ---------------------------------------------------------------------------
|
|
10
|
+
// Initialize
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
const config = getConfig();
|
|
13
|
+
const server = createServer();
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
// HTTP + SSE Transport (for remote / production)
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
const http_transport = new HttpTransport(server, {
|
|
18
|
+
oauth: config.OAUTH_ENABLED ? oauth : undefined,
|
|
19
|
+
});
|
|
20
|
+
const sse_transport = new SseTransport(server, {
|
|
21
|
+
oauth: config.OAUTH_ENABLED ? oauth : undefined,
|
|
22
|
+
});
|
|
23
|
+
serve({
|
|
24
|
+
async fetch(request) {
|
|
25
|
+
// Bun kills idle connections after 10s by default (idleTimeout). MCP's
|
|
26
|
+
// Streamable HTTP (GET /mcp) and legacy SSE (GET /sse) are long-lived
|
|
27
|
+
// streams that sit idle between server→client notifications for minutes.
|
|
28
|
+
// Without this, Bun aborts the stream and tmcp's controller.enqueue()
|
|
29
|
+
// throws "Controller is already closed" → process crash → Docker restart loop.
|
|
30
|
+
// Mirrors effing-use/src/http.ts fix (idleTimeout: 0 + server.timeout(req,0)).
|
|
31
|
+
try {
|
|
32
|
+
const runtime = request.runtime;
|
|
33
|
+
const bunServer = runtime?.bun?.server;
|
|
34
|
+
if (bunServer) {
|
|
35
|
+
const { pathname } = new URL(request.url);
|
|
36
|
+
if (pathname === "/mcp" ||
|
|
37
|
+
pathname === "/sse" ||
|
|
38
|
+
pathname === "/message") {
|
|
39
|
+
bunServer.timeout(request, 0);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
// ignore — srvx may not expose runtime in all environments (e.g. tests)
|
|
45
|
+
}
|
|
46
|
+
// Compatibility: opencode's MCP client sends initialize without protocolVersion
|
|
47
|
+
// (causes tmcp validation: Expected "protocolVersion" but received undefined).
|
|
48
|
+
// Inject a default if missing so the handshake succeeds — other clients (VS Code, curl)
|
|
49
|
+
// already send it and are unchanged.
|
|
50
|
+
if (request.method === "POST") {
|
|
51
|
+
try {
|
|
52
|
+
const url = new URL(request.url);
|
|
53
|
+
if (url.pathname === "/mcp") {
|
|
54
|
+
const ct = request.headers.get("content-type") || "";
|
|
55
|
+
if (ct.includes("application/json")) {
|
|
56
|
+
const cloned = request.clone();
|
|
57
|
+
const body = await cloned.json();
|
|
58
|
+
const patch = (obj) => {
|
|
59
|
+
if (obj &&
|
|
60
|
+
obj.method === "initialize" &&
|
|
61
|
+
obj.params &&
|
|
62
|
+
!obj.params.protocolVersion) {
|
|
63
|
+
obj.params.protocolVersion = "2024-11-05";
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
return false;
|
|
67
|
+
};
|
|
68
|
+
let patched = false;
|
|
69
|
+
if (Array.isArray(body)) {
|
|
70
|
+
for (const item of body)
|
|
71
|
+
patched = patch(item) || patched;
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
patched = patch(body);
|
|
75
|
+
}
|
|
76
|
+
if (patched) {
|
|
77
|
+
request = new Request(request.url, {
|
|
78
|
+
method: request.method,
|
|
79
|
+
headers: request.headers,
|
|
80
|
+
body: JSON.stringify(body),
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
// ignore parse errors, fall through to normal handling
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
// Try HTTP transport (Streamable HTTP for MCP)
|
|
91
|
+
const http_response = await http_transport.respond(request);
|
|
92
|
+
if (http_response) {
|
|
93
|
+
return http_response;
|
|
94
|
+
}
|
|
95
|
+
// Try SSE transport (legacy fallback)
|
|
96
|
+
const sse_response = await sse_transport.respond(request);
|
|
97
|
+
if (sse_response) {
|
|
98
|
+
return sse_response;
|
|
99
|
+
}
|
|
100
|
+
// Root health check
|
|
101
|
+
const url = new URL(request.url);
|
|
102
|
+
if (url.pathname === "/" || url.pathname === "/health") {
|
|
103
|
+
return new Response(JSON.stringify({
|
|
104
|
+
service: "cinder-mcp",
|
|
105
|
+
status: "ok",
|
|
106
|
+
version: config.MCP_SERVER_VERSION,
|
|
107
|
+
endpoints: {
|
|
108
|
+
mcp: "/mcp",
|
|
109
|
+
sse: "/sse",
|
|
110
|
+
health: "/health",
|
|
111
|
+
},
|
|
112
|
+
}), {
|
|
113
|
+
status: 200,
|
|
114
|
+
headers: { "Content-Type": "application/json" },
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
return new Response(null, { status: 404 });
|
|
118
|
+
},
|
|
119
|
+
port: Number(config.PORT),
|
|
120
|
+
hostname: "0.0.0.0",
|
|
121
|
+
// Bun's default idleTimeout (10s) kills *any* idle connection, including
|
|
122
|
+
// long-lived MCP SSE streams (GET /mcp, GET /sse) and slow SearXNG searches.
|
|
123
|
+
// 60s was not enough — SSE sits idle for minutes between notifications.
|
|
124
|
+
// idleTimeout: 0 disables the global idle kill (safe: this is an MCP-only
|
|
125
|
+
// service). Per-request server.timeout(req,0) above is the belt; this is
|
|
126
|
+
// the suspenders. Matches effing-use fix (verified 25s+ stable).
|
|
127
|
+
bun: {
|
|
128
|
+
idleTimeout: 0,
|
|
129
|
+
},
|
|
130
|
+
});
|
|
131
|
+
// Graceful shutdown for Fly.io (sends SIGTERM on deploy/stop)
|
|
132
|
+
process.on("SIGTERM", () => {
|
|
133
|
+
console.log("🛑 SIGTERM received, shutting down...");
|
|
134
|
+
process.exit(0);
|
|
135
|
+
});
|
|
136
|
+
console.log(`🚀 Cinder MCP server running on port ${config.PORT}`);
|
|
137
|
+
console.log(` Health: http://localhost:${config.PORT}/health`);
|
|
138
|
+
console.log(` MCP: http://localhost:${config.PORT}/mcp`);
|
|
139
|
+
console.log(` SSE: http://localhost:${config.PORT}/sse`);
|
|
140
|
+
// ---------------------------------------------------------------------------
|
|
141
|
+
// STDIO Transport (only when not in Fly.io / production and when stdin is a TTY)
|
|
142
|
+
// In Docker the HTTP server is the only transport; stdio would compete for
|
|
143
|
+
// stdin and cause the process to exit when stdin closes (Docker's default).
|
|
144
|
+
// ---------------------------------------------------------------------------
|
|
145
|
+
const is_fly_io = process.env.FLY_APP_NAME !== undefined;
|
|
146
|
+
const has_tty = process.stdin.isTTY;
|
|
147
|
+
if (!is_fly_io && has_tty) {
|
|
148
|
+
const stdio_transport = new StdioTransport(server);
|
|
149
|
+
stdio_transport.listen();
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AAgBjC;;;GAGG;AACH,wBAAgB,YAAY,IAAI,SAAS,CAuFxC"}
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { McpServer } from "tmcp";
|
|
2
|
+
import { ValibotJsonSchemaAdapter } from "@tmcp/adapter-valibot";
|
|
3
|
+
import { getConfig } from "./config.js";
|
|
4
|
+
class FixedValibotAdapter extends ValibotJsonSchemaAdapter {
|
|
5
|
+
async toJsonSchema(schema) {
|
|
6
|
+
const s = await super.toJsonSchema(schema);
|
|
7
|
+
if (!s.type && (s.oneOf || s.anyOf))
|
|
8
|
+
s.type = "object";
|
|
9
|
+
return s;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
import { CinderClient } from "./client.js";
|
|
13
|
+
import { ExtractSchema, createExtractHandler } from "./tools/extract.js";
|
|
14
|
+
import { DiscoverSchema, createDiscoverHandler } from "./tools/discover.js";
|
|
15
|
+
import { MonitorSchema, createMonitorHandler } from "./tools/monitor.js";
|
|
16
|
+
/**
|
|
17
|
+
* Create and configure the McpServer instance.
|
|
18
|
+
* Registers all Cinder MCP tools with Valibot-validated schemas.
|
|
19
|
+
*/
|
|
20
|
+
export function createServer() {
|
|
21
|
+
const config = getConfig();
|
|
22
|
+
const client = new CinderClient();
|
|
23
|
+
const server = new McpServer({
|
|
24
|
+
name: config.MCP_SERVER_NAME,
|
|
25
|
+
version: config.MCP_SERVER_VERSION,
|
|
26
|
+
description: "Cinder MCP — web scraping, crawling, and search powered by Cinder API",
|
|
27
|
+
}, {
|
|
28
|
+
adapter: new FixedValibotAdapter(),
|
|
29
|
+
capabilities: {
|
|
30
|
+
tools: { listChanged: false },
|
|
31
|
+
},
|
|
32
|
+
instructions: [
|
|
33
|
+
'Cinder MCP — 3 resource-oriented tools (≤7 philosophy, arch.md "Why 7 Tools Instead of 17"): 1 tool per domain resource with `action` enum, not 1 tool per CRUD operation.',
|
|
34
|
+
"",
|
|
35
|
+
"## Tools (3 — resource-oriented multiplexing)",
|
|
36
|
+
"- `cinder_extract` — extraction resource: `scrape` (single page → markdown) | `scrape_multi` (sync multi-URL, max 10, no Redis) | `links` (hyperlinks only) | `batch` (enqueue 20 URLs, Redis) | `batch_status` (poll batch)",
|
|
37
|
+
"- `cinder_discover` — discovery resource: `search` (SearXNG/Brave) | `map` (sitemap/traversal) | `crawl` (enqueue BFS, Redis) | `crawl_status` (poll crawl)",
|
|
38
|
+
"- `cinder_monitor` — change-tracking resource: `create` | `status` | `delete` (all Redis)",
|
|
39
|
+
"",
|
|
40
|
+
"## Tips",
|
|
41
|
+
"- Use `cinder_discover` (search/map) first to find URLs, then `cinder_extract` (scrape/scrape_multi) to fetch them.",
|
|
42
|
+
"- Use `cinder_extract` action=links for lightweight hyperlink extraction (no markdown).",
|
|
43
|
+
"- Use `cinder_extract` action=scrape_multi for 2–10 URLs in one call (no Redis, mirrors web_fetch_exa).",
|
|
44
|
+
"- Async actions (crawl/crawl_status, batch/batch_status, monitor) require Redis-backed Cinder — poll their status actions until done.",
|
|
45
|
+
].join("\n"),
|
|
46
|
+
});
|
|
47
|
+
// Resource: extraction — 1 tool per domain resource with `action` enum (arch.md "Why 7 Instead of 17")
|
|
48
|
+
// Consolidates former cinder_scrape + cinder_links + cinder_batch_scrape (3→1) + scrape_multi (sync multi-URL)
|
|
49
|
+
server.tool({
|
|
50
|
+
name: "cinder_extract",
|
|
51
|
+
description: "Extraction resource (5 actions): `scrape` (single page → markdown, screenshots/images/summary/schema), `scrape_multi` (sync multi-URL max 10, no Redis, mirrors web_fetch_exa), `links` (hyperlinks only, no markdown), `batch` (enqueue 20 URLs async, Redis), `batch_status` (poll batch). Replaces cinder_scrape/cinder_links/cinder_batch_scrape.",
|
|
52
|
+
schema: ExtractSchema,
|
|
53
|
+
annotations: {
|
|
54
|
+
readOnlyHint: false,
|
|
55
|
+
openWorldHint: true,
|
|
56
|
+
idempotentHint: false,
|
|
57
|
+
destructiveHint: false,
|
|
58
|
+
},
|
|
59
|
+
}, createExtractHandler(client));
|
|
60
|
+
// Resource: discovery — 1 tool per domain resource with `action` enum
|
|
61
|
+
// Consolidates former cinder_search + cinder_map + cinder_crawl (3→1, crawl already merged start/status)
|
|
62
|
+
server.tool({
|
|
63
|
+
name: "cinder_discover",
|
|
64
|
+
description: "Discovery resource (4 actions): `search` (SearXNG/Brave, domain filters/pagination), `map` (sitemap/traversal), `crawl` (enqueue BFS async, Redis), `crawl_status` (poll crawl). Replaces cinder_search/cinder_map/cinder_crawl.",
|
|
65
|
+
schema: DiscoverSchema,
|
|
66
|
+
annotations: {
|
|
67
|
+
readOnlyHint: false,
|
|
68
|
+
openWorldHint: true,
|
|
69
|
+
idempotentHint: false,
|
|
70
|
+
destructiveHint: false,
|
|
71
|
+
},
|
|
72
|
+
}, createDiscoverHandler(client));
|
|
73
|
+
// Resource: change-tracking — already action-multiplexed (create|status|delete)
|
|
74
|
+
server.tool({
|
|
75
|
+
name: "cinder_monitor",
|
|
76
|
+
description: "Change-tracking resource (3 actions): `create` (hashes markdown, fires signed webhook on change), `status` (config/last hash/next check), `delete` (stop & remove). Requires Redis.",
|
|
77
|
+
schema: MonitorSchema,
|
|
78
|
+
annotations: {
|
|
79
|
+
readOnlyHint: false,
|
|
80
|
+
openWorldHint: true,
|
|
81
|
+
idempotentHint: false,
|
|
82
|
+
destructiveHint: false,
|
|
83
|
+
},
|
|
84
|
+
}, createMonitorHandler(client));
|
|
85
|
+
return server;
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AACjC,OAAO,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AACjE,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,MAAM,mBAAoB,SAAQ,wBAAwB;IACxD,KAAK,CAAC,YAAY,CAAC,MAAW;QAC5B,MAAM,CAAC,GAAQ,MAAM,KAAK,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;QAChD,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,KAAK,CAAC;YAAE,CAAC,CAAC,IAAI,GAAG,QAAQ,CAAC;QACvD,OAAO,CAAC,CAAC;IACX,CAAC;CACF;AACD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AACzE,OAAO,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAC5E,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAEzE;;;GAGG;AACH,MAAM,UAAU,YAAY;IAC1B,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,MAAM,MAAM,GAAG,IAAI,YAAY,EAAE,CAAC;IAElC,MAAM,MAAM,GAAG,IAAI,SAAS,CAC1B;QACE,IAAI,EAAE,MAAM,CAAC,eAAe;QAC5B,OAAO,EAAE,MAAM,CAAC,kBAAkB;QAClC,WAAW,EACT,uEAAuE;KAC1E,EACD;QACE,OAAO,EAAE,IAAI,mBAAmB,EAAE;QAClC,YAAY,EAAE;YACZ,KAAK,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE;SAC9B;QACD,YAAY,EAAE;YACZ,4KAA4K;YAC5K,EAAE;YACF,+CAA+C;YAC/C,8NAA8N;YAC9N,6JAA6J;YAC7J,2FAA2F;YAC3F,EAAE;YACF,SAAS;YACT,qHAAqH;YACrH,yFAAyF;YACzF,yGAAyG;YACzG,uIAAuI;SACxI,CAAC,IAAI,CAAC,IAAI,CAAC;KACb,CACF,CAAC;IAEF,uGAAuG;IACvG,+GAA+G;IAC/G,MAAM,CAAC,IAAI,CACT;QACE,IAAI,EAAE,gBAAgB;QACtB,WAAW,EACT,uVAAuV;QACzV,MAAM,EAAE,aAAa;QACrB,WAAW,EAAE;YACX,YAAY,EAAE,KAAK;YACnB,aAAa,EAAE,IAAI;YACnB,cAAc,EAAE,KAAK;YACrB,eAAe,EAAE,KAAK;SACvB;KACF,EACD,oBAAoB,CAAC,MAAM,CAAQ,CACpC,CAAC;IAEF,sEAAsE;IACtE,yGAAyG;IACzG,MAAM,CAAC,IAAI,CACT;QACE,IAAI,EAAE,iBAAiB;QACvB,WAAW,EACT,kOAAkO;QACpO,MAAM,EAAE,cAAc;QACtB,WAAW,EAAE;YACX,YAAY,EAAE,KAAK;YACnB,aAAa,EAAE,IAAI;YACnB,cAAc,EAAE,KAAK;YACrB,eAAe,EAAE,KAAK;SACvB;KACF,EACD,qBAAqB,CAAC,MAAM,CAAQ,CACrC,CAAC;IAEF,gFAAgF;IAChF,MAAM,CAAC,IAAI,CACT;QACE,IAAI,EAAE,gBAAgB;QACtB,WAAW,EACT,qLAAqL;QACvL,MAAM,EAAE,aAAa;QACrB,WAAW,EAAE;YACX,YAAY,EAAE,KAAK;YACnB,aAAa,EAAE,IAAI;YACnB,cAAc,EAAE,KAAK;YACrB,eAAe,EAAE,KAAK;SACvB;KACF,EACD,oBAAoB,CAAC,MAAM,CAAQ,CACpC,CAAC;IAEF,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
package/dist/stdio.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stdio.d.ts","sourceRoot":"","sources":["../src/stdio.ts"],"names":[],"mappings":""}
|