@ontosdk/mcp 1.1.1 → 1.3.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/dist/index.d.ts CHANGED
@@ -84,6 +84,75 @@ interface ReadAndScoreResponse {
84
84
  ttl_seconds: number;
85
85
  };
86
86
  }
87
+ interface BatchResult {
88
+ url: string;
89
+ ok: boolean;
90
+ error?: {
91
+ code: string;
92
+ message: string;
93
+ };
94
+ title?: string;
95
+ aio_score?: number;
96
+ grade?: string;
97
+ hallucination_risk?: 'low' | 'medium' | 'high';
98
+ reduction_percent?: number;
99
+ markdown?: string;
100
+ structured?: {
101
+ jsonLd: unknown[];
102
+ openGraph: Record<string, string>;
103
+ meta: Record<string, string>;
104
+ };
105
+ counts?: {
106
+ json_ld: number;
107
+ open_graph: number;
108
+ meta: number;
109
+ };
110
+ }
111
+ interface BatchResponse {
112
+ status: 'success';
113
+ mode: 'read' | 'read-and-score' | 'extract';
114
+ source: 'urls' | 'site';
115
+ requested: number;
116
+ succeeded: number;
117
+ results: BatchResult[];
118
+ cache: {
119
+ hit: boolean;
120
+ ttl_seconds: number;
121
+ };
122
+ }
123
+ interface MapResponse {
124
+ status: 'success';
125
+ url: string;
126
+ source: 'sitemap' | 'links';
127
+ count: number;
128
+ urls: string[];
129
+ cache: {
130
+ hit: boolean;
131
+ ttl_seconds: number;
132
+ };
133
+ }
134
+ interface ExtractResponse {
135
+ status: 'success';
136
+ url: string;
137
+ title: string;
138
+ aio_score: number;
139
+ grade: string;
140
+ hallucination_risk: 'low' | 'medium' | 'high';
141
+ structured: {
142
+ jsonLd: unknown[];
143
+ openGraph: Record<string, string>;
144
+ meta: Record<string, string>;
145
+ };
146
+ counts: {
147
+ json_ld: number;
148
+ open_graph: number;
149
+ meta: number;
150
+ };
151
+ cache: {
152
+ hit: boolean;
153
+ ttl_seconds: number;
154
+ };
155
+ }
87
156
 
88
157
  declare const scoreUrlInputSchema: z.ZodObject<{
89
158
  url: z.ZodString;
@@ -108,6 +177,58 @@ declare const readAndScoreInputSchema: z.ZodObject<{
108
177
  type ReadAndScoreInput = z.infer<typeof readAndScoreInputSchema>;
109
178
  declare function readAndScore(input: ReadAndScoreInput): Promise<CallToolResult>;
110
179
 
180
+ declare const batchInputSchema: z.ZodEffects<z.ZodObject<{
181
+ urls: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
182
+ site: z.ZodOptional<z.ZodString>;
183
+ mode: z.ZodOptional<z.ZodEnum<["read", "read-and-score", "extract"]>>;
184
+ limit: z.ZodOptional<z.ZodNumber>;
185
+ }, "strip", z.ZodTypeAny, {
186
+ urls?: string[] | undefined;
187
+ site?: string | undefined;
188
+ mode?: "read" | "read-and-score" | "extract" | undefined;
189
+ limit?: number | undefined;
190
+ }, {
191
+ urls?: string[] | undefined;
192
+ site?: string | undefined;
193
+ mode?: "read" | "read-and-score" | "extract" | undefined;
194
+ limit?: number | undefined;
195
+ }>, {
196
+ urls?: string[] | undefined;
197
+ site?: string | undefined;
198
+ mode?: "read" | "read-and-score" | "extract" | undefined;
199
+ limit?: number | undefined;
200
+ }, {
201
+ urls?: string[] | undefined;
202
+ site?: string | undefined;
203
+ mode?: "read" | "read-and-score" | "extract" | undefined;
204
+ limit?: number | undefined;
205
+ }>;
206
+ type BatchInput = z.infer<typeof batchInputSchema>;
207
+ declare function batchRead(input: BatchInput): Promise<CallToolResult>;
208
+
209
+ declare const mapInputSchema: z.ZodObject<{
210
+ url: z.ZodString;
211
+ limit: z.ZodOptional<z.ZodNumber>;
212
+ }, "strip", z.ZodTypeAny, {
213
+ url: string;
214
+ limit?: number | undefined;
215
+ }, {
216
+ url: string;
217
+ limit?: number | undefined;
218
+ }>;
219
+ type MapInput = z.infer<typeof mapInputSchema>;
220
+ declare function mapSite(input: MapInput): Promise<CallToolResult>;
221
+
222
+ declare const extractInputSchema: z.ZodObject<{
223
+ url: z.ZodString;
224
+ }, "strip", z.ZodTypeAny, {
225
+ url: string;
226
+ }, {
227
+ url: string;
228
+ }>;
229
+ type ExtractInput = z.infer<typeof extractInputSchema>;
230
+ declare function extractData(input: ExtractInput): Promise<CallToolResult>;
231
+
111
232
  declare class OntoApiError extends Error {
112
233
  readonly status: number;
113
234
  readonly code?: string | undefined;
@@ -119,6 +240,6 @@ interface CallOptions {
119
240
  }
120
241
  declare function callOntoApi<T>(endpoint: string, options: CallOptions): Promise<T>;
121
242
 
122
- declare const version = "1.1.1";
243
+ declare const version = "1.3.0";
123
244
 
124
- export { OntoApiError, type ReadAndScoreInput, type ReadAndScoreResponse, type ReadResponse, type ReadUrlInput, type Recommendation, type ScoreResponse, type ScoreUrlInput, callOntoApi, readAndScore, readAndScoreInputSchema, readUrl, readUrlInputSchema, scoreUrl, scoreUrlInputSchema, version };
245
+ export { type BatchInput, type BatchResponse, type BatchResult, type ExtractInput, type ExtractResponse, type MapInput, type MapResponse, OntoApiError, type ReadAndScoreInput, type ReadAndScoreResponse, type ReadResponse, type ReadUrlInput, type Recommendation, type ScoreResponse, type ScoreUrlInput, batchInputSchema, batchRead, callOntoApi, extractData, extractInputSchema, mapInputSchema, mapSite, readAndScore, readAndScoreInputSchema, readUrl, readUrlInputSchema, scoreUrl, scoreUrlInputSchema, version };
package/dist/index.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import { z } from "zod";
3
3
 
4
4
  // src/lib/version.ts
5
- var version = "1.1.1";
5
+ var version = "1.3.0";
6
6
 
7
7
  // src/lib/api-client.ts
8
8
  var DEFAULT_BASE = "https://api.buildonto.dev";
@@ -123,6 +123,33 @@ Troubleshooting:
123
123
  };
124
124
  }
125
125
 
126
+ // src/lib/report.ts
127
+ var BYTES_PER_TOKEN = 4;
128
+ function estimateTokensSaved(rawKb, cleanKb) {
129
+ const savedBytes = Math.max(0, (rawKb - cleanKb) * 1024);
130
+ return Math.round(savedBytes / BYTES_PER_TOKEN);
131
+ }
132
+ function compact(n) {
133
+ if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
134
+ if (n >= 1e4) return `${Math.round(n / 1e3)}K`;
135
+ if (n >= 1e3) return `${(n / 1e3).toFixed(1)}K`;
136
+ return `${n}`;
137
+ }
138
+ function ontoReport(input) {
139
+ const parts = [];
140
+ if (input.rawKb != null && input.cleanKb != null) {
141
+ parts.push(`${input.rawKb}KB \u2192 ${input.cleanKb}KB`);
142
+ if (input.reductionPercent != null) parts.push(`${input.reductionPercent}% smaller`);
143
+ parts.push(`~${compact(estimateTokensSaved(input.rawKb, input.cleanKb))} tokens saved`);
144
+ } else if (input.reductionPercent != null) {
145
+ parts.push(`${input.reductionPercent}% smaller`);
146
+ }
147
+ if (input.aioScore != null) {
148
+ parts.push(`AIO ${input.aioScore}/100${input.risk ? ` (${input.risk} risk)` : ""}`);
149
+ }
150
+ return `\u26A1 Onto \xB7 ${parts.join(" \xB7 ")} \xB7 buildonto.dev`;
151
+ }
152
+
126
153
  // src/tools/read.ts
127
154
  var readUrlInputSchema = z.object({
128
155
  url: z.string().url(),
@@ -152,7 +179,13 @@ async function readUrl(input) {
152
179
  ---
153
180
 
154
181
  **Source metadata (from Onto):**
155
- ${metaLines}`
182
+ ${metaLines}
183
+
184
+ ${ontoReport({
185
+ rawKb: result.stats.raw_html_size_kb,
186
+ cleanKb: result.stats.markdown_size_kb,
187
+ reductionPercent: result.stats.reduction_percent
188
+ })}`
156
189
  }
157
190
  ]
158
191
  };
@@ -214,6 +247,8 @@ function formatScoreSummary(result) {
214
247
  lines.push(`- Raw size: ${result.stats.raw_size}`);
215
248
  lines.push(`- Efficiency: ${result.stats.efficiency}`);
216
249
  lines.push(`- Extraction time: ${result.stats.extraction_time_ms} ms`);
250
+ lines.push("");
251
+ lines.push(ontoReport({ aioScore: result.aio_score, risk: result.hallucination_risk }));
217
252
  return lines.join("\n");
218
253
  }
219
254
  function describeRecommendation(rec) {
@@ -245,7 +280,15 @@ async function readAndScore(input) {
245
280
  `- Reduction: ${result.stats.reduction_percent}% (${result.stats.raw_html_size_kb} KB \u2192 ${result.stats.markdown_size_kb} KB)`,
246
281
  `- Cache: ${result.cache.hit ? "HIT" : "MISS"}`,
247
282
  "",
248
- trustHint
283
+ trustHint,
284
+ "",
285
+ ontoReport({
286
+ rawKb: result.stats.raw_html_size_kb,
287
+ cleanKb: result.stats.markdown_size_kb,
288
+ reductionPercent: result.stats.reduction_percent,
289
+ aioScore: result.aio_score,
290
+ risk: result.hallucination_risk
291
+ })
249
292
  ];
250
293
  return {
251
294
  content: [
@@ -270,9 +313,124 @@ function trustLine(score, risk) {
270
313
  }
271
314
  return "Trust signal: high \u2014 source is well-structured for AI consumption.";
272
315
  }
316
+
317
+ // src/tools/batch.ts
318
+ import { z as z4 } from "zod";
319
+ var batchInputSchema = z4.object({
320
+ urls: z4.array(z4.string().url()).min(1).max(50).optional(),
321
+ site: z4.string().url().optional(),
322
+ mode: z4.enum(["read", "read-and-score", "extract"]).optional(),
323
+ limit: z4.number().int().min(1).max(50).optional()
324
+ }).refine((v) => v.urls && v.urls.length > 0 || v.site, {
325
+ message: 'Provide either "urls" (array) or "site" (string).'
326
+ });
327
+ function renderResult(r) {
328
+ if (!r.ok) {
329
+ return `### ${r.url}
330
+ _skipped \u2014 ${r.error?.code}: ${r.error?.message}_`;
331
+ }
332
+ const head = [`### ${r.title || r.url}`, r.url];
333
+ if (r.aio_score != null) {
334
+ head.push(`AIO ${r.aio_score}/100 (${r.grade}, ${r.hallucination_risk} risk)`);
335
+ }
336
+ if (r.reduction_percent != null) head.push(`${r.reduction_percent}% smaller`);
337
+ const lines = [head.join(" \xB7 ")];
338
+ if (r.structured) {
339
+ lines.push("", `JSON-LD: ${r.counts?.json_ld ?? 0} \xB7 OG: ${r.counts?.open_graph ?? 0} \xB7 meta: ${r.counts?.meta ?? 0}`);
340
+ if (r.structured.jsonLd.length > 0) {
341
+ lines.push("```json", JSON.stringify(r.structured.jsonLd, null, 2), "```");
342
+ }
343
+ } else if (r.markdown) {
344
+ lines.push("", r.markdown);
345
+ }
346
+ return lines.join("\n");
347
+ }
348
+ async function batchRead(input) {
349
+ try {
350
+ const result = await callOntoApi("/v1/batch", {
351
+ body: { urls: input.urls, site: input.site, mode: input.mode, limit: input.limit }
352
+ });
353
+ const header = result.source === "site" ? `# Batch ${result.mode} \u2014 site discovery` : `# Batch ${result.mode} \u2014 ${result.requested} URL(s)`;
354
+ const lines = [
355
+ header,
356
+ `${result.succeeded}/${result.requested} succeeded.`,
357
+ "",
358
+ ...result.results.map(renderResult).flatMap((block) => [block, ""]),
359
+ `\u26A1 Onto \xB7 ${result.succeeded}/${result.requested} URLs in one call \xB7 buildonto.dev`
360
+ ];
361
+ return { content: [{ type: "text", text: lines.join("\n") }] };
362
+ } catch (error) {
363
+ return formatToolError(error);
364
+ }
365
+ }
366
+
367
+ // src/tools/map.ts
368
+ import { z as z5 } from "zod";
369
+ var mapInputSchema = z5.object({
370
+ url: z5.string().url(),
371
+ limit: z5.number().int().min(1).max(1e3).optional()
372
+ });
373
+ async function mapSite(input) {
374
+ try {
375
+ const result = await callOntoApi("/v1/map", {
376
+ body: { url: input.url, limit: input.limit }
377
+ });
378
+ const lines = [
379
+ `# Sitemap for ${result.url}`,
380
+ `Discovered ${result.count} URL(s) via ${result.source}.`,
381
+ "",
382
+ ...result.urls.map((u) => `- ${u}`),
383
+ "",
384
+ `\u26A1 Onto \xB7 ${result.count} URLs mapped (${result.source}) \xB7 buildonto.dev`
385
+ ];
386
+ return { content: [{ type: "text", text: lines.join("\n") }] };
387
+ } catch (error) {
388
+ return formatToolError(error);
389
+ }
390
+ }
391
+
392
+ // src/tools/extract.ts
393
+ import { z as z6 } from "zod";
394
+ var extractInputSchema = z6.object({
395
+ url: z6.string().url()
396
+ });
397
+ async function extractData(input) {
398
+ try {
399
+ const result = await callOntoApi("/v1/extract", {
400
+ body: { url: input.url }
401
+ });
402
+ const og = Object.entries(result.structured.openGraph);
403
+ const meta = Object.entries(result.structured.meta);
404
+ const lines = [
405
+ `# Structured data for ${result.url}`,
406
+ result.title ? `Title: ${result.title}` : "",
407
+ `Found ${result.counts.json_ld} JSON-LD object(s), ${result.counts.open_graph} OpenGraph tag(s), ${result.counts.meta} meta tag(s).`,
408
+ "",
409
+ "## JSON-LD",
410
+ result.structured.jsonLd.length > 0 ? "```json\n" + JSON.stringify(result.structured.jsonLd, null, 2) + "\n```" : "(none declared)",
411
+ "",
412
+ "## OpenGraph",
413
+ og.length > 0 ? og.map(([k, v]) => `- ${k}: ${v}`).join("\n") : "(none)",
414
+ "",
415
+ "## Meta",
416
+ meta.length > 0 ? meta.map(([k, v]) => `- ${k}: ${v}`).join("\n") : "(none)",
417
+ "",
418
+ ontoReport({ aioScore: result.aio_score, risk: result.hallucination_risk })
419
+ ].filter((line) => line !== "");
420
+ return { content: [{ type: "text", text: lines.join("\n") }] };
421
+ } catch (error) {
422
+ return formatToolError(error);
423
+ }
424
+ }
273
425
  export {
274
426
  OntoApiError,
427
+ batchInputSchema,
428
+ batchRead,
275
429
  callOntoApi,
430
+ extractData,
431
+ extractInputSchema,
432
+ mapInputSchema,
433
+ mapSite,
276
434
  readAndScore,
277
435
  readAndScoreInputSchema,
278
436
  readUrl,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/tools/read.ts","../src/lib/version.ts","../src/lib/api-client.ts","../src/lib/errors.ts","../src/tools/score.ts","../src/tools/read-and-score.ts"],"sourcesContent":["import { z } from 'zod';\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';\nimport { callOntoApi } from '../lib/api-client.js';\nimport { formatToolError } from '../lib/errors.js';\nimport type { ReadResponse } from '../lib/types.js';\n\nexport const readUrlInputSchema = z.object({\n url: z.string().url(),\n fresh: z.boolean().optional().default(false),\n});\n\nexport type ReadUrlInput = z.infer<typeof readUrlInputSchema>;\n\nexport async function readUrl(input: ReadUrlInput): Promise<CallToolResult> {\n try {\n const result = await callOntoApi<ReadResponse>('/v1/read', {\n body: { url: input.url, fresh: input.fresh },\n });\n\n const metaLines = [\n `- URL: ${result.url}`,\n `- Title: ${result.metadata.title || '(none)'}`,\n `- Original size: ${result.stats.raw_html_size_kb} KB`,\n `- Cleaned size: ${result.stats.markdown_size_kb} KB`,\n `- Reduction: ${result.stats.reduction_percent}%`,\n `- Extraction time: ${result.stats.extraction_time_ms} ms`,\n `- Cache: ${result.cache.hit ? 'HIT' : 'MISS'}`,\n ].join('\\n');\n\n return {\n content: [\n { type: 'text' as const, text: result.markdown },\n {\n type: 'text' as const,\n text: `\\n\\n---\\n\\n**Source metadata (from Onto):**\\n${metaLines}`,\n },\n ],\n };\n } catch (error) {\n return formatToolError(error);\n }\n}\n","export const version = '1.1.1';\n","/* Thin HTTP wrapper around the Onto Read API. Reads ONTO_API_KEY at call time\n * (not module-load) so server.ts can fail with a clean error message first. */\n\nimport { version as PACKAGE_VERSION } from './version.js';\nimport type { ApiErrorBody } from './types.js';\n\nconst DEFAULT_BASE = 'https://api.buildonto.dev';\nconst REQUEST_TIMEOUT_MS = 15_000;\n\nexport class OntoApiError extends Error {\n constructor(\n message: string,\n public readonly status: number,\n public readonly code?: string,\n ) {\n super(message);\n this.name = 'OntoApiError';\n }\n}\n\ninterface CallOptions {\n body: unknown;\n signal?: AbortSignal;\n}\n\nexport async function callOntoApi<T>(endpoint: string, options: CallOptions): Promise<T> {\n const apiKey = process.env.ONTO_API_KEY;\n if (!apiKey) {\n throw new OntoApiError(\n 'ONTO_API_KEY environment variable is not set. Get a key at https://app.buildonto.dev/read/keys',\n 0,\n 'NO_API_KEY',\n );\n }\n\n const base = process.env.ONTO_API_BASE ?? DEFAULT_BASE;\n const url = `${base}${endpoint}`;\n\n const timeout = AbortSignal.timeout(REQUEST_TIMEOUT_MS);\n const signal = options.signal\n ? AbortSignal.any([options.signal, timeout])\n : timeout;\n\n let response: Response;\n try {\n response = await fetch(url, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${apiKey}`,\n 'Content-Type': 'application/json',\n 'User-Agent': `@ontosdk/mcp/${PACKAGE_VERSION}`,\n },\n body: JSON.stringify(options.body),\n signal,\n });\n } catch (err) {\n if (err instanceof DOMException && err.name === 'TimeoutError') {\n throw new OntoApiError(\n `Onto API request timed out after ${REQUEST_TIMEOUT_MS / 1000}s. The target site may be slow or unreachable.`,\n 0,\n 'TIMEOUT',\n );\n }\n throw new OntoApiError(\n `Failed to reach Onto API at ${base}: ${(err as Error).message}`,\n 0,\n 'NETWORK_ERROR',\n );\n }\n\n const rawBody = await response.text();\n\n if (!response.ok) {\n let parsed: Partial<ApiErrorBody> = {};\n try {\n parsed = JSON.parse(rawBody) as Partial<ApiErrorBody>;\n } catch {\n // Body wasn't JSON; fall through with status-code-only error\n }\n\n const message = humanizeError(response.status, parsed);\n throw new OntoApiError(message, response.status, parsed.error);\n }\n\n try {\n return JSON.parse(rawBody) as T;\n } catch (err) {\n throw new OntoApiError(\n `Onto API returned invalid JSON: ${(err as Error).message}`,\n response.status,\n 'INVALID_RESPONSE',\n );\n }\n}\n\nfunction humanizeError(status: number, body: Partial<ApiErrorBody>): string {\n if (status === 401) {\n return 'Invalid Onto API key. Verify your key at https://app.buildonto.dev/read/keys';\n }\n if (status === 402) {\n return (\n body.message ??\n 'Monthly plan quota exceeded and credit balance is empty. Top up credits at https://app.buildonto.dev/read/billing'\n );\n }\n if (status === 403) {\n if (body.error === 'ROBOTS_BLOCKED') {\n return body.message ?? 'The target site blocks AI crawlers via robots.txt.';\n }\n return body.message ?? 'Forbidden.';\n }\n if (status === 429) {\n return (\n body.message ??\n 'Onto API rate limit exceeded. Upgrade your tier at https://app.buildonto.dev/read/billing or wait for the monthly reset.'\n );\n }\n if (status >= 500) {\n return body.message ?? `Onto API server error (${status}). Try again in a moment.`;\n }\n return body.message ?? `Onto API returned ${status}.`;\n}\n","/* Format errors as MCP tool responses. We don't throw McpError for\n * tool-call failures — the AI host shows tool errors to the user as\n * unhelpful internal-error messages. Returning isError: true with a\n * text body lets the model see what went wrong and recover. */\n\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';\nimport { OntoApiError } from './api-client.js';\n\nexport function formatToolError(error: unknown): CallToolResult {\n if (error instanceof OntoApiError) {\n return {\n content: [{ type: 'text', text: error.message }],\n isError: true,\n };\n }\n\n const message = error instanceof Error ? error.message : String(error);\n return {\n content: [\n {\n type: 'text',\n text: `Onto MCP error: ${message}\\n\\nTroubleshooting:\\n- Verify ONTO_API_KEY is set and valid (https://app.buildonto.dev/read/keys)\\n- Check the target URL is publicly accessible\\n- Check your monthly quota at https://app.buildonto.dev/read/usage`,\n },\n ],\n isError: true,\n };\n}\n","import { z } from 'zod';\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';\nimport { callOntoApi } from '../lib/api-client.js';\nimport { formatToolError } from '../lib/errors.js';\nimport type { ScoreResponse, Recommendation } from '../lib/types.js';\n\nexport const scoreUrlInputSchema = z.object({\n url: z.string().url(),\n});\n\nexport type ScoreUrlInput = z.infer<typeof scoreUrlInputSchema>;\n\nexport async function scoreUrl(input: ScoreUrlInput): Promise<CallToolResult> {\n try {\n const result = await callOntoApi<ScoreResponse>('/v1/score', {\n body: { url: input.url },\n });\n\n return {\n content: [{ type: 'text' as const, text: formatScoreSummary(result) }],\n };\n } catch (error) {\n return formatToolError(error);\n }\n}\n\nexport function formatScoreSummary(result: ScoreResponse): string {\n const lines: string[] = [\n `**AIO Score:** ${result.aio_score}/100 (${result.grade})`,\n `**Hallucination risk:** ${result.hallucination_risk}`,\n `**URL:** ${result.url}`,\n '',\n ];\n\n if (result.benefits.length > 0) {\n lines.push('**What works well:**');\n for (const item of result.benefits) lines.push(`- ${item}`);\n lines.push('');\n }\n\n if (result.penalties.length > 0) {\n lines.push('**What hurts AI readability:**');\n for (const item of result.penalties) lines.push(`- ${item}`);\n lines.push('');\n }\n\n const insightEntries = Object.entries(result.insights ?? {});\n if (insightEntries.length > 0) {\n lines.push('**Insights:**');\n for (const [key, value] of insightEntries) {\n lines.push(`- ${key}: ${value ? 'yes' : 'no'}`);\n }\n lines.push('');\n }\n\n if (result.recommendations.length > 0) {\n lines.push('**Recommendations:**');\n for (const rec of result.recommendations) {\n lines.push(describeRecommendation(rec));\n }\n lines.push('');\n }\n\n lines.push('**Stats:**');\n lines.push(`- Raw size: ${result.stats.raw_size}`);\n lines.push(`- Efficiency: ${result.stats.efficiency}`);\n lines.push(`- Extraction time: ${result.stats.extraction_time_ms} ms`);\n\n return lines.join('\\n');\n}\n\nfunction describeRecommendation(rec: Recommendation): string {\n if (typeof rec === 'string') return `- ${rec}`;\n if (rec.title) {\n const head = rec.priority ? `**${rec.title}** _(priority: ${rec.priority})_` : `**${rec.title}**`;\n return rec.description ? `- ${head} — ${rec.description}` : `- ${head}`;\n }\n if (rec.description) return `- ${rec.description}`;\n return `- ${JSON.stringify(rec)}`;\n}\n","import { z } from 'zod';\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';\nimport { callOntoApi } from '../lib/api-client.js';\nimport { formatToolError } from '../lib/errors.js';\nimport type { ReadAndScoreResponse } from '../lib/types.js';\n\nexport const readAndScoreInputSchema = z.object({\n url: z.string().url(),\n fresh: z.boolean().optional().default(false),\n});\n\nexport type ReadAndScoreInput = z.infer<typeof readAndScoreInputSchema>;\n\nexport async function readAndScore(input: ReadAndScoreInput): Promise<CallToolResult> {\n try {\n const result = await callOntoApi<ReadAndScoreResponse>('/v1/read-and-score', {\n body: { url: input.url, fresh: input.fresh },\n });\n\n const trustHint = trustLine(result.aio_score, result.hallucination_risk);\n const summaryLines = [\n `**Source quality assessment (from Onto):**`,\n `- AIO Score: ${result.aio_score}/100 (${result.grade})`,\n `- Hallucination risk: ${result.hallucination_risk}`,\n `- Reduction: ${result.stats.reduction_percent}% (${result.stats.raw_html_size_kb} KB → ${result.stats.markdown_size_kb} KB)`,\n `- Cache: ${result.cache.hit ? 'HIT' : 'MISS'}`,\n '',\n trustHint,\n ];\n\n return {\n content: [\n { type: 'text' as const, text: result.markdown },\n { type: 'text' as const, text: `\\n\\n---\\n\\n${summaryLines.join('\\n')}` },\n ],\n };\n } catch (error) {\n return formatToolError(error);\n }\n}\n\nfunction trustLine(score: number, risk: 'low' | 'medium' | 'high'): string {\n if (risk === 'high' || score < 40) {\n return 'Trust signal: low — this source is poorly structured for AI consumption. Verify any facts before relying on them.';\n }\n if (risk === 'medium' || score < 70) {\n return 'Trust signal: medium — source is partially AI-readable. Cross-check critical claims.';\n }\n return 'Trust signal: high — source is well-structured for AI consumption.';\n}\n"],"mappings":"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","names":["z","z","z","z"]}
1
+ {"version":3,"sources":["../src/tools/read.ts","../src/lib/version.ts","../src/lib/api-client.ts","../src/lib/errors.ts","../src/lib/report.ts","../src/tools/score.ts","../src/tools/read-and-score.ts","../src/tools/batch.ts","../src/tools/map.ts","../src/tools/extract.ts"],"sourcesContent":["import { z } from 'zod';\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';\nimport { callOntoApi } from '../lib/api-client.js';\nimport { formatToolError } from '../lib/errors.js';\nimport { ontoReport } from '../lib/report.js';\nimport type { ReadResponse } from '../lib/types.js';\n\nexport const readUrlInputSchema = z.object({\n url: z.string().url(),\n fresh: z.boolean().optional().default(false),\n});\n\nexport type ReadUrlInput = z.infer<typeof readUrlInputSchema>;\n\nexport async function readUrl(input: ReadUrlInput): Promise<CallToolResult> {\n try {\n const result = await callOntoApi<ReadResponse>('/v1/read', {\n body: { url: input.url, fresh: input.fresh },\n });\n\n const metaLines = [\n `- URL: ${result.url}`,\n `- Title: ${result.metadata.title || '(none)'}`,\n `- Original size: ${result.stats.raw_html_size_kb} KB`,\n `- Cleaned size: ${result.stats.markdown_size_kb} KB`,\n `- Reduction: ${result.stats.reduction_percent}%`,\n `- Extraction time: ${result.stats.extraction_time_ms} ms`,\n `- Cache: ${result.cache.hit ? 'HIT' : 'MISS'}`,\n ].join('\\n');\n\n return {\n content: [\n { type: 'text' as const, text: result.markdown },\n {\n type: 'text' as const,\n text: `\\n\\n---\\n\\n**Source metadata (from Onto):**\\n${metaLines}\\n\\n${ontoReport({\n rawKb: result.stats.raw_html_size_kb,\n cleanKb: result.stats.markdown_size_kb,\n reductionPercent: result.stats.reduction_percent,\n })}`,\n },\n ],\n };\n } catch (error) {\n return formatToolError(error);\n }\n}\n","export const version = '1.3.0';\n","/* Thin HTTP wrapper around the Onto Read API. Reads ONTO_API_KEY at call time\n * (not module-load) so server.ts can fail with a clean error message first. */\n\nimport { version as PACKAGE_VERSION } from './version.js';\nimport type { ApiErrorBody } from './types.js';\n\nconst DEFAULT_BASE = 'https://api.buildonto.dev';\nconst REQUEST_TIMEOUT_MS = 15_000;\n\nexport class OntoApiError extends Error {\n constructor(\n message: string,\n public readonly status: number,\n public readonly code?: string,\n ) {\n super(message);\n this.name = 'OntoApiError';\n }\n}\n\ninterface CallOptions {\n body: unknown;\n signal?: AbortSignal;\n}\n\nexport async function callOntoApi<T>(endpoint: string, options: CallOptions): Promise<T> {\n const apiKey = process.env.ONTO_API_KEY;\n if (!apiKey) {\n throw new OntoApiError(\n 'ONTO_API_KEY environment variable is not set. Get a key at https://app.buildonto.dev/read/keys',\n 0,\n 'NO_API_KEY',\n );\n }\n\n const base = process.env.ONTO_API_BASE ?? DEFAULT_BASE;\n const url = `${base}${endpoint}`;\n\n const timeout = AbortSignal.timeout(REQUEST_TIMEOUT_MS);\n const signal = options.signal\n ? AbortSignal.any([options.signal, timeout])\n : timeout;\n\n let response: Response;\n try {\n response = await fetch(url, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${apiKey}`,\n 'Content-Type': 'application/json',\n 'User-Agent': `@ontosdk/mcp/${PACKAGE_VERSION}`,\n },\n body: JSON.stringify(options.body),\n signal,\n });\n } catch (err) {\n if (err instanceof DOMException && err.name === 'TimeoutError') {\n throw new OntoApiError(\n `Onto API request timed out after ${REQUEST_TIMEOUT_MS / 1000}s. The target site may be slow or unreachable.`,\n 0,\n 'TIMEOUT',\n );\n }\n throw new OntoApiError(\n `Failed to reach Onto API at ${base}: ${(err as Error).message}`,\n 0,\n 'NETWORK_ERROR',\n );\n }\n\n const rawBody = await response.text();\n\n if (!response.ok) {\n let parsed: Partial<ApiErrorBody> = {};\n try {\n parsed = JSON.parse(rawBody) as Partial<ApiErrorBody>;\n } catch {\n // Body wasn't JSON; fall through with status-code-only error\n }\n\n const message = humanizeError(response.status, parsed);\n throw new OntoApiError(message, response.status, parsed.error);\n }\n\n try {\n return JSON.parse(rawBody) as T;\n } catch (err) {\n throw new OntoApiError(\n `Onto API returned invalid JSON: ${(err as Error).message}`,\n response.status,\n 'INVALID_RESPONSE',\n );\n }\n}\n\nfunction humanizeError(status: number, body: Partial<ApiErrorBody>): string {\n if (status === 401) {\n return 'Invalid Onto API key. Verify your key at https://app.buildonto.dev/read/keys';\n }\n if (status === 402) {\n return (\n body.message ??\n 'Monthly plan quota exceeded and credit balance is empty. Top up credits at https://app.buildonto.dev/read/billing'\n );\n }\n if (status === 403) {\n if (body.error === 'ROBOTS_BLOCKED') {\n return body.message ?? 'The target site blocks AI crawlers via robots.txt.';\n }\n return body.message ?? 'Forbidden.';\n }\n if (status === 429) {\n return (\n body.message ??\n 'Onto API rate limit exceeded. Upgrade your tier at https://app.buildonto.dev/read/billing or wait for the monthly reset.'\n );\n }\n if (status >= 500) {\n return body.message ?? `Onto API server error (${status}). Try again in a moment.`;\n }\n return body.message ?? `Onto API returned ${status}.`;\n}\n","/* Format errors as MCP tool responses. We don't throw McpError for\n * tool-call failures — the AI host shows tool errors to the user as\n * unhelpful internal-error messages. Returning isError: true with a\n * text body lets the model see what went wrong and recover. */\n\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';\nimport { OntoApiError } from './api-client.js';\n\nexport function formatToolError(error: unknown): CallToolResult {\n if (error instanceof OntoApiError) {\n return {\n content: [{ type: 'text', text: error.message }],\n isError: true,\n };\n }\n\n const message = error instanceof Error ? error.message : String(error);\n return {\n content: [\n {\n type: 'text',\n text: `Onto MCP error: ${message}\\n\\nTroubleshooting:\\n- Verify ONTO_API_KEY is set and valid (https://app.buildonto.dev/read/keys)\\n- Check the target URL is publicly accessible\\n- Check your monthly quota at https://app.buildonto.dev/read/usage`,\n },\n ],\n isError: true,\n };\n}\n","/* The \"Onto report\" — a single branded summary line appended to the end of\n * every tool response. This is a deliberate growth surface: every agent call\n * leaves Onto's value (reduction, tokens saved, trust score) visible in the\n * host's context, and stamps the brand. Keep it to ONE line, always the same\n * shape so it becomes recognizable.\n *\n * Token estimate uses 4 bytes/token — the same heuristic the dashboard uses\n * for its \"tokens saved\" stat, so numbers stay consistent across surfaces.\n */\n\nconst BYTES_PER_TOKEN = 4;\n\nexport interface OntoReportInput {\n /** Raw HTML size in KB (before Onto cleaned it). */\n rawKb?: number;\n /** Clean Markdown size in KB (what the agent actually consumes). */\n cleanKb?: number;\n /** Percentage shrink from raw → clean. */\n reductionPercent?: number;\n /** AIO readability score 0–100, when available. */\n aioScore?: number;\n /** Hallucination-risk band, when available. */\n risk?: 'low' | 'medium' | 'high';\n}\n\n/** Estimated input tokens saved by serving Markdown instead of raw HTML. */\nexport function estimateTokensSaved(rawKb: number, cleanKb: number): number {\n const savedBytes = Math.max(0, (rawKb - cleanKb) * 1024);\n return Math.round(savedBytes / BYTES_PER_TOKEN);\n}\n\n/** Compact, human-friendly token count: 1234 → \"1.2K\", 199000 → \"199K\". */\nfunction compact(n: number): string {\n if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`;\n if (n >= 10_000) return `${Math.round(n / 1_000)}K`;\n if (n >= 1_000) return `${(n / 1_000).toFixed(1)}K`;\n return `${n}`;\n}\n\n/**\n * Build the single-line Onto report. Only the fields that are present get\n * rendered, so the same helper works for read_url (no score) and\n * read_and_score / score_url (with score).\n */\nexport function ontoReport(input: OntoReportInput): string {\n const parts: string[] = [];\n\n if (input.rawKb != null && input.cleanKb != null) {\n parts.push(`${input.rawKb}KB → ${input.cleanKb}KB`);\n if (input.reductionPercent != null) parts.push(`${input.reductionPercent}% smaller`);\n parts.push(`~${compact(estimateTokensSaved(input.rawKb, input.cleanKb))} tokens saved`);\n } else if (input.reductionPercent != null) {\n parts.push(`${input.reductionPercent}% smaller`);\n }\n\n if (input.aioScore != null) {\n parts.push(`AIO ${input.aioScore}/100${input.risk ? ` (${input.risk} risk)` : ''}`);\n }\n\n return `⚡ Onto · ${parts.join(' · ')} · buildonto.dev`;\n}\n","import { z } from 'zod';\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';\nimport { callOntoApi } from '../lib/api-client.js';\nimport { formatToolError } from '../lib/errors.js';\nimport { ontoReport } from '../lib/report.js';\nimport type { ScoreResponse, Recommendation } from '../lib/types.js';\n\nexport const scoreUrlInputSchema = z.object({\n url: z.string().url(),\n});\n\nexport type ScoreUrlInput = z.infer<typeof scoreUrlInputSchema>;\n\nexport async function scoreUrl(input: ScoreUrlInput): Promise<CallToolResult> {\n try {\n const result = await callOntoApi<ScoreResponse>('/v1/score', {\n body: { url: input.url },\n });\n\n return {\n content: [{ type: 'text' as const, text: formatScoreSummary(result) }],\n };\n } catch (error) {\n return formatToolError(error);\n }\n}\n\nexport function formatScoreSummary(result: ScoreResponse): string {\n const lines: string[] = [\n `**AIO Score:** ${result.aio_score}/100 (${result.grade})`,\n `**Hallucination risk:** ${result.hallucination_risk}`,\n `**URL:** ${result.url}`,\n '',\n ];\n\n if (result.benefits.length > 0) {\n lines.push('**What works well:**');\n for (const item of result.benefits) lines.push(`- ${item}`);\n lines.push('');\n }\n\n if (result.penalties.length > 0) {\n lines.push('**What hurts AI readability:**');\n for (const item of result.penalties) lines.push(`- ${item}`);\n lines.push('');\n }\n\n const insightEntries = Object.entries(result.insights ?? {});\n if (insightEntries.length > 0) {\n lines.push('**Insights:**');\n for (const [key, value] of insightEntries) {\n lines.push(`- ${key}: ${value ? 'yes' : 'no'}`);\n }\n lines.push('');\n }\n\n if (result.recommendations.length > 0) {\n lines.push('**Recommendations:**');\n for (const rec of result.recommendations) {\n lines.push(describeRecommendation(rec));\n }\n lines.push('');\n }\n\n lines.push('**Stats:**');\n lines.push(`- Raw size: ${result.stats.raw_size}`);\n lines.push(`- Efficiency: ${result.stats.efficiency}`);\n lines.push(`- Extraction time: ${result.stats.extraction_time_ms} ms`);\n lines.push('');\n lines.push(ontoReport({ aioScore: result.aio_score, risk: result.hallucination_risk }));\n\n return lines.join('\\n');\n}\n\nfunction describeRecommendation(rec: Recommendation): string {\n if (typeof rec === 'string') return `- ${rec}`;\n if (rec.title) {\n const head = rec.priority ? `**${rec.title}** _(priority: ${rec.priority})_` : `**${rec.title}**`;\n return rec.description ? `- ${head} — ${rec.description}` : `- ${head}`;\n }\n if (rec.description) return `- ${rec.description}`;\n return `- ${JSON.stringify(rec)}`;\n}\n","import { z } from 'zod';\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';\nimport { callOntoApi } from '../lib/api-client.js';\nimport { formatToolError } from '../lib/errors.js';\nimport { ontoReport } from '../lib/report.js';\nimport type { ReadAndScoreResponse } from '../lib/types.js';\n\nexport const readAndScoreInputSchema = z.object({\n url: z.string().url(),\n fresh: z.boolean().optional().default(false),\n});\n\nexport type ReadAndScoreInput = z.infer<typeof readAndScoreInputSchema>;\n\nexport async function readAndScore(input: ReadAndScoreInput): Promise<CallToolResult> {\n try {\n const result = await callOntoApi<ReadAndScoreResponse>('/v1/read-and-score', {\n body: { url: input.url, fresh: input.fresh },\n });\n\n const trustHint = trustLine(result.aio_score, result.hallucination_risk);\n const summaryLines = [\n `**Source quality assessment (from Onto):**`,\n `- AIO Score: ${result.aio_score}/100 (${result.grade})`,\n `- Hallucination risk: ${result.hallucination_risk}`,\n `- Reduction: ${result.stats.reduction_percent}% (${result.stats.raw_html_size_kb} KB → ${result.stats.markdown_size_kb} KB)`,\n `- Cache: ${result.cache.hit ? 'HIT' : 'MISS'}`,\n '',\n trustHint,\n '',\n ontoReport({\n rawKb: result.stats.raw_html_size_kb,\n cleanKb: result.stats.markdown_size_kb,\n reductionPercent: result.stats.reduction_percent,\n aioScore: result.aio_score,\n risk: result.hallucination_risk,\n }),\n ];\n\n return {\n content: [\n { type: 'text' as const, text: result.markdown },\n { type: 'text' as const, text: `\\n\\n---\\n\\n${summaryLines.join('\\n')}` },\n ],\n };\n } catch (error) {\n return formatToolError(error);\n }\n}\n\nfunction trustLine(score: number, risk: 'low' | 'medium' | 'high'): string {\n if (risk === 'high' || score < 40) {\n return 'Trust signal: low — this source is poorly structured for AI consumption. Verify any facts before relying on them.';\n }\n if (risk === 'medium' || score < 70) {\n return 'Trust signal: medium — source is partially AI-readable. Cross-check critical claims.';\n }\n return 'Trust signal: high — source is well-structured for AI consumption.';\n}\n","import { z } from 'zod';\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';\nimport { callOntoApi } from '../lib/api-client.js';\nimport { formatToolError } from '../lib/errors.js';\nimport type { BatchResponse, BatchResult } from '../lib/types.js';\n\nexport const batchInputSchema = z\n .object({\n urls: z.array(z.string().url()).min(1).max(50).optional(),\n site: z.string().url().optional(),\n mode: z.enum(['read', 'read-and-score', 'extract']).optional(),\n limit: z.number().int().min(1).max(50).optional(),\n })\n .refine((v) => (v.urls && v.urls.length > 0) || v.site, {\n message: 'Provide either \"urls\" (array) or \"site\" (string).',\n });\n\nexport type BatchInput = z.infer<typeof batchInputSchema>;\n\nfunction renderResult(r: BatchResult): string {\n if (!r.ok) {\n return `### ${r.url}\\n_skipped — ${r.error?.code}: ${r.error?.message}_`;\n }\n const head = [`### ${r.title || r.url}`, r.url];\n if (r.aio_score != null) {\n head.push(`AIO ${r.aio_score}/100 (${r.grade}, ${r.hallucination_risk} risk)`);\n }\n if (r.reduction_percent != null) head.push(`${r.reduction_percent}% smaller`);\n const lines = [head.join(' · ')];\n\n if (r.structured) {\n lines.push('', `JSON-LD: ${r.counts?.json_ld ?? 0} · OG: ${r.counts?.open_graph ?? 0} · meta: ${r.counts?.meta ?? 0}`);\n if (r.structured.jsonLd.length > 0) {\n lines.push('```json', JSON.stringify(r.structured.jsonLd, null, 2), '```');\n }\n } else if (r.markdown) {\n lines.push('', r.markdown);\n }\n return lines.join('\\n');\n}\n\nexport async function batchRead(input: BatchInput): Promise<CallToolResult> {\n try {\n const result = await callOntoApi<BatchResponse>('/v1/batch', {\n body: { urls: input.urls, site: input.site, mode: input.mode, limit: input.limit },\n });\n\n const header =\n result.source === 'site'\n ? `# Batch ${result.mode} — site discovery`\n : `# Batch ${result.mode} — ${result.requested} URL(s)`;\n\n const lines = [\n header,\n `${result.succeeded}/${result.requested} succeeded.`,\n '',\n ...result.results.map(renderResult).flatMap((block) => [block, '']),\n `⚡ Onto · ${result.succeeded}/${result.requested} URLs in one call · buildonto.dev`,\n ];\n\n return { content: [{ type: 'text' as const, text: lines.join('\\n') }] };\n } catch (error) {\n return formatToolError(error);\n }\n}\n","import { z } from 'zod';\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';\nimport { callOntoApi } from '../lib/api-client.js';\nimport { formatToolError } from '../lib/errors.js';\nimport type { MapResponse } from '../lib/types.js';\n\nexport const mapInputSchema = z.object({\n url: z.string().url(),\n limit: z.number().int().min(1).max(1000).optional(),\n});\n\nexport type MapInput = z.infer<typeof mapInputSchema>;\n\nexport async function mapSite(input: MapInput): Promise<CallToolResult> {\n try {\n const result = await callOntoApi<MapResponse>('/v1/map', {\n body: { url: input.url, limit: input.limit },\n });\n\n const lines: string[] = [\n `# Sitemap for ${result.url}`,\n `Discovered ${result.count} URL(s) via ${result.source}.`,\n '',\n ...result.urls.map((u) => `- ${u}`),\n '',\n `⚡ Onto · ${result.count} URLs mapped (${result.source}) · buildonto.dev`,\n ];\n\n return { content: [{ type: 'text' as const, text: lines.join('\\n') }] };\n } catch (error) {\n return formatToolError(error);\n }\n}\n","import { z } from 'zod';\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';\nimport { callOntoApi } from '../lib/api-client.js';\nimport { formatToolError } from '../lib/errors.js';\nimport { ontoReport } from '../lib/report.js';\nimport type { ExtractResponse } from '../lib/types.js';\n\nexport const extractInputSchema = z.object({\n url: z.string().url(),\n});\n\nexport type ExtractInput = z.infer<typeof extractInputSchema>;\n\nexport async function extractData(input: ExtractInput): Promise<CallToolResult> {\n try {\n const result = await callOntoApi<ExtractResponse>('/v1/extract', {\n body: { url: input.url },\n });\n\n const og = Object.entries(result.structured.openGraph);\n const meta = Object.entries(result.structured.meta);\n\n const lines: string[] = [\n `# Structured data for ${result.url}`,\n result.title ? `Title: ${result.title}` : '',\n `Found ${result.counts.json_ld} JSON-LD object(s), ${result.counts.open_graph} OpenGraph tag(s), ${result.counts.meta} meta tag(s).`,\n '',\n '## JSON-LD',\n result.structured.jsonLd.length > 0\n ? '```json\\n' + JSON.stringify(result.structured.jsonLd, null, 2) + '\\n```'\n : '(none declared)',\n '',\n '## OpenGraph',\n og.length > 0 ? og.map(([k, v]) => `- ${k}: ${v}`).join('\\n') : '(none)',\n '',\n '## Meta',\n meta.length > 0 ? meta.map(([k, v]) => `- ${k}: ${v}`).join('\\n') : '(none)',\n '',\n ontoReport({ aioScore: result.aio_score, risk: result.hallucination_risk }),\n ].filter((line) => line !== '');\n\n return { content: [{ type: 'text' as const, text: lines.join('\\n') }] };\n } catch (error) {\n return formatToolError(error);\n }\n}\n"],"mappings":"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","names":["z","z","z","z","z","z","z","z","z","z"]}
package/dist/server.js CHANGED
@@ -14,7 +14,7 @@ import {
14
14
  import { z } from "zod";
15
15
 
16
16
  // src/lib/version.ts
17
- var version = "1.1.1";
17
+ var version = "1.3.0";
18
18
 
19
19
  // src/lib/api-client.ts
20
20
  var DEFAULT_BASE = "https://api.buildonto.dev";
@@ -135,6 +135,33 @@ Troubleshooting:
135
135
  };
136
136
  }
137
137
 
138
+ // src/lib/report.ts
139
+ var BYTES_PER_TOKEN = 4;
140
+ function estimateTokensSaved(rawKb, cleanKb) {
141
+ const savedBytes = Math.max(0, (rawKb - cleanKb) * 1024);
142
+ return Math.round(savedBytes / BYTES_PER_TOKEN);
143
+ }
144
+ function compact(n) {
145
+ if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
146
+ if (n >= 1e4) return `${Math.round(n / 1e3)}K`;
147
+ if (n >= 1e3) return `${(n / 1e3).toFixed(1)}K`;
148
+ return `${n}`;
149
+ }
150
+ function ontoReport(input) {
151
+ const parts = [];
152
+ if (input.rawKb != null && input.cleanKb != null) {
153
+ parts.push(`${input.rawKb}KB \u2192 ${input.cleanKb}KB`);
154
+ if (input.reductionPercent != null) parts.push(`${input.reductionPercent}% smaller`);
155
+ parts.push(`~${compact(estimateTokensSaved(input.rawKb, input.cleanKb))} tokens saved`);
156
+ } else if (input.reductionPercent != null) {
157
+ parts.push(`${input.reductionPercent}% smaller`);
158
+ }
159
+ if (input.aioScore != null) {
160
+ parts.push(`AIO ${input.aioScore}/100${input.risk ? ` (${input.risk} risk)` : ""}`);
161
+ }
162
+ return `\u26A1 Onto \xB7 ${parts.join(" \xB7 ")} \xB7 buildonto.dev`;
163
+ }
164
+
138
165
  // src/tools/read.ts
139
166
  var readUrlInputSchema = z.object({
140
167
  url: z.string().url(),
@@ -164,7 +191,13 @@ async function readUrl(input) {
164
191
  ---
165
192
 
166
193
  **Source metadata (from Onto):**
167
- ${metaLines}`
194
+ ${metaLines}
195
+
196
+ ${ontoReport({
197
+ rawKb: result.stats.raw_html_size_kb,
198
+ cleanKb: result.stats.markdown_size_kb,
199
+ reductionPercent: result.stats.reduction_percent
200
+ })}`
168
201
  }
169
202
  ]
170
203
  };
@@ -226,6 +259,8 @@ function formatScoreSummary(result) {
226
259
  lines.push(`- Raw size: ${result.stats.raw_size}`);
227
260
  lines.push(`- Efficiency: ${result.stats.efficiency}`);
228
261
  lines.push(`- Extraction time: ${result.stats.extraction_time_ms} ms`);
262
+ lines.push("");
263
+ lines.push(ontoReport({ aioScore: result.aio_score, risk: result.hallucination_risk }));
229
264
  return lines.join("\n");
230
265
  }
231
266
  function describeRecommendation(rec) {
@@ -257,7 +292,15 @@ async function readAndScore(input) {
257
292
  `- Reduction: ${result.stats.reduction_percent}% (${result.stats.raw_html_size_kb} KB \u2192 ${result.stats.markdown_size_kb} KB)`,
258
293
  `- Cache: ${result.cache.hit ? "HIT" : "MISS"}`,
259
294
  "",
260
- trustHint
295
+ trustHint,
296
+ "",
297
+ ontoReport({
298
+ rawKb: result.stats.raw_html_size_kb,
299
+ cleanKb: result.stats.markdown_size_kb,
300
+ reductionPercent: result.stats.reduction_percent,
301
+ aioScore: result.aio_score,
302
+ risk: result.hallucination_risk
303
+ })
261
304
  ];
262
305
  return {
263
306
  content: [
@@ -283,6 +326,115 @@ function trustLine(score, risk) {
283
326
  return "Trust signal: high \u2014 source is well-structured for AI consumption.";
284
327
  }
285
328
 
329
+ // src/tools/batch.ts
330
+ import { z as z4 } from "zod";
331
+ var batchInputSchema = z4.object({
332
+ urls: z4.array(z4.string().url()).min(1).max(50).optional(),
333
+ site: z4.string().url().optional(),
334
+ mode: z4.enum(["read", "read-and-score", "extract"]).optional(),
335
+ limit: z4.number().int().min(1).max(50).optional()
336
+ }).refine((v) => v.urls && v.urls.length > 0 || v.site, {
337
+ message: 'Provide either "urls" (array) or "site" (string).'
338
+ });
339
+ function renderResult(r) {
340
+ if (!r.ok) {
341
+ return `### ${r.url}
342
+ _skipped \u2014 ${r.error?.code}: ${r.error?.message}_`;
343
+ }
344
+ const head = [`### ${r.title || r.url}`, r.url];
345
+ if (r.aio_score != null) {
346
+ head.push(`AIO ${r.aio_score}/100 (${r.grade}, ${r.hallucination_risk} risk)`);
347
+ }
348
+ if (r.reduction_percent != null) head.push(`${r.reduction_percent}% smaller`);
349
+ const lines = [head.join(" \xB7 ")];
350
+ if (r.structured) {
351
+ lines.push("", `JSON-LD: ${r.counts?.json_ld ?? 0} \xB7 OG: ${r.counts?.open_graph ?? 0} \xB7 meta: ${r.counts?.meta ?? 0}`);
352
+ if (r.structured.jsonLd.length > 0) {
353
+ lines.push("```json", JSON.stringify(r.structured.jsonLd, null, 2), "```");
354
+ }
355
+ } else if (r.markdown) {
356
+ lines.push("", r.markdown);
357
+ }
358
+ return lines.join("\n");
359
+ }
360
+ async function batchRead(input) {
361
+ try {
362
+ const result = await callOntoApi("/v1/batch", {
363
+ body: { urls: input.urls, site: input.site, mode: input.mode, limit: input.limit }
364
+ });
365
+ const header = result.source === "site" ? `# Batch ${result.mode} \u2014 site discovery` : `# Batch ${result.mode} \u2014 ${result.requested} URL(s)`;
366
+ const lines = [
367
+ header,
368
+ `${result.succeeded}/${result.requested} succeeded.`,
369
+ "",
370
+ ...result.results.map(renderResult).flatMap((block) => [block, ""]),
371
+ `\u26A1 Onto \xB7 ${result.succeeded}/${result.requested} URLs in one call \xB7 buildonto.dev`
372
+ ];
373
+ return { content: [{ type: "text", text: lines.join("\n") }] };
374
+ } catch (error) {
375
+ return formatToolError(error);
376
+ }
377
+ }
378
+
379
+ // src/tools/map.ts
380
+ import { z as z5 } from "zod";
381
+ var mapInputSchema = z5.object({
382
+ url: z5.string().url(),
383
+ limit: z5.number().int().min(1).max(1e3).optional()
384
+ });
385
+ async function mapSite(input) {
386
+ try {
387
+ const result = await callOntoApi("/v1/map", {
388
+ body: { url: input.url, limit: input.limit }
389
+ });
390
+ const lines = [
391
+ `# Sitemap for ${result.url}`,
392
+ `Discovered ${result.count} URL(s) via ${result.source}.`,
393
+ "",
394
+ ...result.urls.map((u) => `- ${u}`),
395
+ "",
396
+ `\u26A1 Onto \xB7 ${result.count} URLs mapped (${result.source}) \xB7 buildonto.dev`
397
+ ];
398
+ return { content: [{ type: "text", text: lines.join("\n") }] };
399
+ } catch (error) {
400
+ return formatToolError(error);
401
+ }
402
+ }
403
+
404
+ // src/tools/extract.ts
405
+ import { z as z6 } from "zod";
406
+ var extractInputSchema = z6.object({
407
+ url: z6.string().url()
408
+ });
409
+ async function extractData(input) {
410
+ try {
411
+ const result = await callOntoApi("/v1/extract", {
412
+ body: { url: input.url }
413
+ });
414
+ const og = Object.entries(result.structured.openGraph);
415
+ const meta = Object.entries(result.structured.meta);
416
+ const lines = [
417
+ `# Structured data for ${result.url}`,
418
+ result.title ? `Title: ${result.title}` : "",
419
+ `Found ${result.counts.json_ld} JSON-LD object(s), ${result.counts.open_graph} OpenGraph tag(s), ${result.counts.meta} meta tag(s).`,
420
+ "",
421
+ "## JSON-LD",
422
+ result.structured.jsonLd.length > 0 ? "```json\n" + JSON.stringify(result.structured.jsonLd, null, 2) + "\n```" : "(none declared)",
423
+ "",
424
+ "## OpenGraph",
425
+ og.length > 0 ? og.map(([k, v]) => `- ${k}: ${v}`).join("\n") : "(none)",
426
+ "",
427
+ "## Meta",
428
+ meta.length > 0 ? meta.map(([k, v]) => `- ${k}: ${v}`).join("\n") : "(none)",
429
+ "",
430
+ ontoReport({ aioScore: result.aio_score, risk: result.hallucination_risk })
431
+ ].filter((line) => line !== "");
432
+ return { content: [{ type: "text", text: lines.join("\n") }] };
433
+ } catch (error) {
434
+ return formatToolError(error);
435
+ }
436
+ }
437
+
286
438
  // src/server.ts
287
439
  if (!process.env.ONTO_API_KEY) {
288
440
  console.error("[onto-mcp] ONTO_API_KEY environment variable is required.");
@@ -346,6 +498,65 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
346
498
  },
347
499
  required: ["url"]
348
500
  }
501
+ },
502
+ {
503
+ name: "batch",
504
+ description: 'Process many URLs in ONE call (billed as one request) \u2014 so you do not spend a credit per URL. Give either "urls" (an explicit list, up to 50) or "site" (a base URL whose pages are auto-discovered via sitemap). "mode" picks what to do per URL: "read" (Markdown), "read-and-score" (Markdown + AIO trust score, default), or "extract" (JSON-LD + OpenGraph + meta + score). Use this for full-site reads or bulk URL processing.',
505
+ inputSchema: {
506
+ type: "object",
507
+ properties: {
508
+ urls: {
509
+ type: "array",
510
+ items: { type: "string" },
511
+ description: 'Explicit list of URLs to process (up to 50). Use this OR "site".'
512
+ },
513
+ site: {
514
+ type: "string",
515
+ description: 'Base URL of a site whose pages will be auto-discovered. Use this OR "urls".'
516
+ },
517
+ mode: {
518
+ type: "string",
519
+ enum: ["read", "read-and-score", "extract"],
520
+ description: 'What to do per URL. Default "read-and-score".'
521
+ },
522
+ limit: {
523
+ type: "number",
524
+ description: "Site mode only: max pages to discover (default 25, max 50)."
525
+ }
526
+ }
527
+ }
528
+ },
529
+ {
530
+ name: "map_site",
531
+ description: "Discover a site's URLs (from sitemap.xml, falling back to on-page links) without reading them. Fast and cheap \u2014 use it to plan which pages to read or crawl next.",
532
+ inputSchema: {
533
+ type: "object",
534
+ properties: {
535
+ url: {
536
+ type: "string",
537
+ description: "The site URL to map."
538
+ },
539
+ limit: {
540
+ type: "number",
541
+ description: "Max URLs to return (default 100, max 1000)."
542
+ }
543
+ },
544
+ required: ["url"]
545
+ }
546
+ },
547
+ {
548
+ name: "extract_data",
549
+ description: "Extract the structured data a page already declares \u2014 JSON-LD (schema.org), OpenGraph cards, and meta tags \u2014 plus the AIO trust score. Deterministic, no AI: returns only data present in the page. Use for fast, reliable facts (prices, products, articles) when the site publishes structured data.",
550
+ inputSchema: {
551
+ type: "object",
552
+ properties: {
553
+ url: {
554
+ type: "string",
555
+ description: "The URL to extract structured data from."
556
+ }
557
+ },
558
+ required: ["url"]
559
+ }
349
560
  }
350
561
  ]
351
562
  }));
@@ -365,6 +576,18 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
365
576
  const validated = readAndScoreInputSchema.parse(args ?? {});
366
577
  return await readAndScore(validated);
367
578
  }
579
+ case "batch": {
580
+ const validated = batchInputSchema.parse(args ?? {});
581
+ return await batchRead(validated);
582
+ }
583
+ case "map_site": {
584
+ const validated = mapInputSchema.parse(args ?? {});
585
+ return await mapSite(validated);
586
+ }
587
+ case "extract_data": {
588
+ const validated = extractInputSchema.parse(args ?? {});
589
+ return await extractData(validated);
590
+ }
368
591
  default:
369
592
  throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
370
593
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/server.ts","../src/tools/read.ts","../src/lib/version.ts","../src/lib/api-client.ts","../src/lib/errors.ts","../src/tools/score.ts","../src/tools/read-and-score.ts"],"sourcesContent":["/* Onto MCP Server — exposes the Onto Read API as Model Context Protocol tools.\n *\n * Tools: read_url, score_url, read_and_score.\n * Reads ONTO_API_KEY from env. Defaults base URL to https://api.buildonto.dev.\n *\n * Install in Claude Code:\n * \"mcpServers\": {\n * \"onto\": {\n * \"command\": \"npx\",\n * \"args\": [\"-y\", \"@ontosdk/mcp\"],\n * \"env\": { \"ONTO_API_KEY\": \"onto_sk_live_...\" }\n * }\n * }\n */\n\nimport { Server } from '@modelcontextprotocol/sdk/server/index.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport {\n CallToolRequestSchema,\n ListToolsRequestSchema,\n ErrorCode,\n McpError,\n} from '@modelcontextprotocol/sdk/types.js';\n\nimport { readUrl, readUrlInputSchema } from './tools/read.js';\nimport { scoreUrl, scoreUrlInputSchema } from './tools/score.js';\nimport { readAndScore, readAndScoreInputSchema } from './tools/read-and-score.js';\nimport { version } from './lib/version.js';\n\nif (!process.env.ONTO_API_KEY) {\n console.error('[onto-mcp] ONTO_API_KEY environment variable is required.');\n console.error('[onto-mcp] Create a key at https://app.buildonto.dev/read/keys');\n process.exit(1);\n}\n\nconst server = new Server(\n { name: 'onto', version },\n { capabilities: { tools: {} } },\n);\n\nserver.setRequestHandler(ListToolsRequestSchema, async () => ({\n tools: [\n {\n name: 'read_url',\n description:\n 'Read any URL and return clean, agent-ready Markdown. Strips HTML noise, preserves semantic content, and returns content optimized for AI consumption. Use this when you need to extract content from a website for an AI agent to process.',\n inputSchema: {\n type: 'object',\n properties: {\n url: {\n type: 'string',\n description: 'The URL to read. Must be a publicly accessible HTTP or HTTPS URL.',\n },\n fresh: {\n type: 'boolean',\n description: 'If true, bypass cache and fetch fresh content. Default false.',\n default: false,\n },\n },\n required: ['url'],\n },\n },\n {\n name: 'score_url',\n description:\n 'Get the AIO (AI-readability) score for any URL. Returns a 0-100 score plus a list of penalties, benefits, and recommendations describing why the source is or is not well-suited for AI consumption. Use this to evaluate source quality before relying on it.',\n inputSchema: {\n type: 'object',\n properties: {\n url: {\n type: 'string',\n description: 'The URL to score.',\n },\n },\n required: ['url'],\n },\n },\n {\n name: 'read_and_score',\n description:\n 'Read any URL and return both clean Markdown AND the AIO accuracy score in one call. The recommended default for most AI workflows — gives both content and quality assessment together, so the AI agent can decide how much to trust the content.',\n inputSchema: {\n type: 'object',\n properties: {\n url: {\n type: 'string',\n description: 'The URL to read and score.',\n },\n fresh: {\n type: 'boolean',\n description: 'If true, bypass cache and fetch fresh content. Default false.',\n default: false,\n },\n },\n required: ['url'],\n },\n },\n ],\n}));\n\nserver.setRequestHandler(CallToolRequestSchema, async (request) => {\n const { name, arguments: args } = request.params;\n\n try {\n switch (name) {\n case 'read_url': {\n const validated = readUrlInputSchema.parse(args ?? {});\n return await readUrl(validated);\n }\n case 'score_url': {\n const validated = scoreUrlInputSchema.parse(args ?? {});\n return await scoreUrl(validated);\n }\n case 'read_and_score': {\n const validated = readAndScoreInputSchema.parse(args ?? {});\n return await readAndScore(validated);\n }\n default:\n throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`);\n }\n } catch (error) {\n if (error instanceof McpError) throw error;\n const message = error instanceof Error ? error.message : String(error);\n return {\n content: [{ type: 'text' as const, text: `Tool '${name}' failed: ${message}` }],\n isError: true,\n };\n }\n});\n\nasync function main() {\n const transport = new StdioServerTransport();\n await server.connect(transport);\n // stderr (not stdout) — stdout is reserved for MCP protocol frames\n console.error(`[onto-mcp] v${version} listening on stdio`);\n}\n\nmain().catch((err) => {\n console.error('[onto-mcp] fatal:', err);\n process.exit(1);\n});\n","import { z } from 'zod';\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';\nimport { callOntoApi } from '../lib/api-client.js';\nimport { formatToolError } from '../lib/errors.js';\nimport type { ReadResponse } from '../lib/types.js';\n\nexport const readUrlInputSchema = z.object({\n url: z.string().url(),\n fresh: z.boolean().optional().default(false),\n});\n\nexport type ReadUrlInput = z.infer<typeof readUrlInputSchema>;\n\nexport async function readUrl(input: ReadUrlInput): Promise<CallToolResult> {\n try {\n const result = await callOntoApi<ReadResponse>('/v1/read', {\n body: { url: input.url, fresh: input.fresh },\n });\n\n const metaLines = [\n `- URL: ${result.url}`,\n `- Title: ${result.metadata.title || '(none)'}`,\n `- Original size: ${result.stats.raw_html_size_kb} KB`,\n `- Cleaned size: ${result.stats.markdown_size_kb} KB`,\n `- Reduction: ${result.stats.reduction_percent}%`,\n `- Extraction time: ${result.stats.extraction_time_ms} ms`,\n `- Cache: ${result.cache.hit ? 'HIT' : 'MISS'}`,\n ].join('\\n');\n\n return {\n content: [\n { type: 'text' as const, text: result.markdown },\n {\n type: 'text' as const,\n text: `\\n\\n---\\n\\n**Source metadata (from Onto):**\\n${metaLines}`,\n },\n ],\n };\n } catch (error) {\n return formatToolError(error);\n }\n}\n","export const version = '1.1.1';\n","/* Thin HTTP wrapper around the Onto Read API. Reads ONTO_API_KEY at call time\n * (not module-load) so server.ts can fail with a clean error message first. */\n\nimport { version as PACKAGE_VERSION } from './version.js';\nimport type { ApiErrorBody } from './types.js';\n\nconst DEFAULT_BASE = 'https://api.buildonto.dev';\nconst REQUEST_TIMEOUT_MS = 15_000;\n\nexport class OntoApiError extends Error {\n constructor(\n message: string,\n public readonly status: number,\n public readonly code?: string,\n ) {\n super(message);\n this.name = 'OntoApiError';\n }\n}\n\ninterface CallOptions {\n body: unknown;\n signal?: AbortSignal;\n}\n\nexport async function callOntoApi<T>(endpoint: string, options: CallOptions): Promise<T> {\n const apiKey = process.env.ONTO_API_KEY;\n if (!apiKey) {\n throw new OntoApiError(\n 'ONTO_API_KEY environment variable is not set. Get a key at https://app.buildonto.dev/read/keys',\n 0,\n 'NO_API_KEY',\n );\n }\n\n const base = process.env.ONTO_API_BASE ?? DEFAULT_BASE;\n const url = `${base}${endpoint}`;\n\n const timeout = AbortSignal.timeout(REQUEST_TIMEOUT_MS);\n const signal = options.signal\n ? AbortSignal.any([options.signal, timeout])\n : timeout;\n\n let response: Response;\n try {\n response = await fetch(url, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${apiKey}`,\n 'Content-Type': 'application/json',\n 'User-Agent': `@ontosdk/mcp/${PACKAGE_VERSION}`,\n },\n body: JSON.stringify(options.body),\n signal,\n });\n } catch (err) {\n if (err instanceof DOMException && err.name === 'TimeoutError') {\n throw new OntoApiError(\n `Onto API request timed out after ${REQUEST_TIMEOUT_MS / 1000}s. The target site may be slow or unreachable.`,\n 0,\n 'TIMEOUT',\n );\n }\n throw new OntoApiError(\n `Failed to reach Onto API at ${base}: ${(err as Error).message}`,\n 0,\n 'NETWORK_ERROR',\n );\n }\n\n const rawBody = await response.text();\n\n if (!response.ok) {\n let parsed: Partial<ApiErrorBody> = {};\n try {\n parsed = JSON.parse(rawBody) as Partial<ApiErrorBody>;\n } catch {\n // Body wasn't JSON; fall through with status-code-only error\n }\n\n const message = humanizeError(response.status, parsed);\n throw new OntoApiError(message, response.status, parsed.error);\n }\n\n try {\n return JSON.parse(rawBody) as T;\n } catch (err) {\n throw new OntoApiError(\n `Onto API returned invalid JSON: ${(err as Error).message}`,\n response.status,\n 'INVALID_RESPONSE',\n );\n }\n}\n\nfunction humanizeError(status: number, body: Partial<ApiErrorBody>): string {\n if (status === 401) {\n return 'Invalid Onto API key. Verify your key at https://app.buildonto.dev/read/keys';\n }\n if (status === 402) {\n return (\n body.message ??\n 'Monthly plan quota exceeded and credit balance is empty. Top up credits at https://app.buildonto.dev/read/billing'\n );\n }\n if (status === 403) {\n if (body.error === 'ROBOTS_BLOCKED') {\n return body.message ?? 'The target site blocks AI crawlers via robots.txt.';\n }\n return body.message ?? 'Forbidden.';\n }\n if (status === 429) {\n return (\n body.message ??\n 'Onto API rate limit exceeded. Upgrade your tier at https://app.buildonto.dev/read/billing or wait for the monthly reset.'\n );\n }\n if (status >= 500) {\n return body.message ?? `Onto API server error (${status}). Try again in a moment.`;\n }\n return body.message ?? `Onto API returned ${status}.`;\n}\n","/* Format errors as MCP tool responses. We don't throw McpError for\n * tool-call failures — the AI host shows tool errors to the user as\n * unhelpful internal-error messages. Returning isError: true with a\n * text body lets the model see what went wrong and recover. */\n\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';\nimport { OntoApiError } from './api-client.js';\n\nexport function formatToolError(error: unknown): CallToolResult {\n if (error instanceof OntoApiError) {\n return {\n content: [{ type: 'text', text: error.message }],\n isError: true,\n };\n }\n\n const message = error instanceof Error ? error.message : String(error);\n return {\n content: [\n {\n type: 'text',\n text: `Onto MCP error: ${message}\\n\\nTroubleshooting:\\n- Verify ONTO_API_KEY is set and valid (https://app.buildonto.dev/read/keys)\\n- Check the target URL is publicly accessible\\n- Check your monthly quota at https://app.buildonto.dev/read/usage`,\n },\n ],\n isError: true,\n };\n}\n","import { z } from 'zod';\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';\nimport { callOntoApi } from '../lib/api-client.js';\nimport { formatToolError } from '../lib/errors.js';\nimport type { ScoreResponse, Recommendation } from '../lib/types.js';\n\nexport const scoreUrlInputSchema = z.object({\n url: z.string().url(),\n});\n\nexport type ScoreUrlInput = z.infer<typeof scoreUrlInputSchema>;\n\nexport async function scoreUrl(input: ScoreUrlInput): Promise<CallToolResult> {\n try {\n const result = await callOntoApi<ScoreResponse>('/v1/score', {\n body: { url: input.url },\n });\n\n return {\n content: [{ type: 'text' as const, text: formatScoreSummary(result) }],\n };\n } catch (error) {\n return formatToolError(error);\n }\n}\n\nexport function formatScoreSummary(result: ScoreResponse): string {\n const lines: string[] = [\n `**AIO Score:** ${result.aio_score}/100 (${result.grade})`,\n `**Hallucination risk:** ${result.hallucination_risk}`,\n `**URL:** ${result.url}`,\n '',\n ];\n\n if (result.benefits.length > 0) {\n lines.push('**What works well:**');\n for (const item of result.benefits) lines.push(`- ${item}`);\n lines.push('');\n }\n\n if (result.penalties.length > 0) {\n lines.push('**What hurts AI readability:**');\n for (const item of result.penalties) lines.push(`- ${item}`);\n lines.push('');\n }\n\n const insightEntries = Object.entries(result.insights ?? {});\n if (insightEntries.length > 0) {\n lines.push('**Insights:**');\n for (const [key, value] of insightEntries) {\n lines.push(`- ${key}: ${value ? 'yes' : 'no'}`);\n }\n lines.push('');\n }\n\n if (result.recommendations.length > 0) {\n lines.push('**Recommendations:**');\n for (const rec of result.recommendations) {\n lines.push(describeRecommendation(rec));\n }\n lines.push('');\n }\n\n lines.push('**Stats:**');\n lines.push(`- Raw size: ${result.stats.raw_size}`);\n lines.push(`- Efficiency: ${result.stats.efficiency}`);\n lines.push(`- Extraction time: ${result.stats.extraction_time_ms} ms`);\n\n return lines.join('\\n');\n}\n\nfunction describeRecommendation(rec: Recommendation): string {\n if (typeof rec === 'string') return `- ${rec}`;\n if (rec.title) {\n const head = rec.priority ? `**${rec.title}** _(priority: ${rec.priority})_` : `**${rec.title}**`;\n return rec.description ? `- ${head} — ${rec.description}` : `- ${head}`;\n }\n if (rec.description) return `- ${rec.description}`;\n return `- ${JSON.stringify(rec)}`;\n}\n","import { z } from 'zod';\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';\nimport { callOntoApi } from '../lib/api-client.js';\nimport { formatToolError } from '../lib/errors.js';\nimport type { ReadAndScoreResponse } from '../lib/types.js';\n\nexport const readAndScoreInputSchema = z.object({\n url: z.string().url(),\n fresh: z.boolean().optional().default(false),\n});\n\nexport type ReadAndScoreInput = z.infer<typeof readAndScoreInputSchema>;\n\nexport async function readAndScore(input: ReadAndScoreInput): Promise<CallToolResult> {\n try {\n const result = await callOntoApi<ReadAndScoreResponse>('/v1/read-and-score', {\n body: { url: input.url, fresh: input.fresh },\n });\n\n const trustHint = trustLine(result.aio_score, result.hallucination_risk);\n const summaryLines = [\n `**Source quality assessment (from Onto):**`,\n `- AIO Score: ${result.aio_score}/100 (${result.grade})`,\n `- Hallucination risk: ${result.hallucination_risk}`,\n `- Reduction: ${result.stats.reduction_percent}% (${result.stats.raw_html_size_kb} KB → ${result.stats.markdown_size_kb} KB)`,\n `- Cache: ${result.cache.hit ? 'HIT' : 'MISS'}`,\n '',\n trustHint,\n ];\n\n return {\n content: [\n { type: 'text' as const, text: result.markdown },\n { type: 'text' as const, text: `\\n\\n---\\n\\n${summaryLines.join('\\n')}` },\n ],\n };\n } catch (error) {\n return formatToolError(error);\n }\n}\n\nfunction trustLine(score: number, risk: 'low' | 'medium' | 'high'): string {\n if (risk === 'high' || score < 40) {\n return 'Trust signal: low — this source is poorly structured for AI consumption. Verify any facts before relying on them.';\n }\n if (risk === 'medium' || score < 70) {\n return 'Trust signal: medium — source is partially AI-readable. Cross-check critical claims.';\n }\n return 'Trust signal: high — source is well-structured for AI consumption.';\n}\n"],"mappings":"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","names":["z","z","z","z"]}
1
+ {"version":3,"sources":["../src/server.ts","../src/tools/read.ts","../src/lib/version.ts","../src/lib/api-client.ts","../src/lib/errors.ts","../src/lib/report.ts","../src/tools/score.ts","../src/tools/read-and-score.ts","../src/tools/batch.ts","../src/tools/map.ts","../src/tools/extract.ts"],"sourcesContent":["/* Onto MCP Server — exposes the Onto Read API as Model Context Protocol tools.\n *\n * Tools: read_url, score_url, read_and_score.\n * Reads ONTO_API_KEY from env. Defaults base URL to https://api.buildonto.dev.\n *\n * Install in Claude Code:\n * \"mcpServers\": {\n * \"onto\": {\n * \"command\": \"npx\",\n * \"args\": [\"-y\", \"@ontosdk/mcp\"],\n * \"env\": { \"ONTO_API_KEY\": \"onto_sk_live_...\" }\n * }\n * }\n */\n\nimport { Server } from '@modelcontextprotocol/sdk/server/index.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport {\n CallToolRequestSchema,\n ListToolsRequestSchema,\n ErrorCode,\n McpError,\n} from '@modelcontextprotocol/sdk/types.js';\n\nimport { readUrl, readUrlInputSchema } from './tools/read.js';\nimport { scoreUrl, scoreUrlInputSchema } from './tools/score.js';\nimport { readAndScore, readAndScoreInputSchema } from './tools/read-and-score.js';\nimport { batchRead, batchInputSchema } from './tools/batch.js';\nimport { mapSite, mapInputSchema } from './tools/map.js';\nimport { extractData, extractInputSchema } from './tools/extract.js';\nimport { version } from './lib/version.js';\n\nif (!process.env.ONTO_API_KEY) {\n console.error('[onto-mcp] ONTO_API_KEY environment variable is required.');\n console.error('[onto-mcp] Create a key at https://app.buildonto.dev/read/keys');\n process.exit(1);\n}\n\nconst server = new Server(\n { name: 'onto', version },\n { capabilities: { tools: {} } },\n);\n\nserver.setRequestHandler(ListToolsRequestSchema, async () => ({\n tools: [\n {\n name: 'read_url',\n description:\n 'Read any URL and return clean, agent-ready Markdown. Strips HTML noise, preserves semantic content, and returns content optimized for AI consumption. Use this when you need to extract content from a website for an AI agent to process.',\n inputSchema: {\n type: 'object',\n properties: {\n url: {\n type: 'string',\n description: 'The URL to read. Must be a publicly accessible HTTP or HTTPS URL.',\n },\n fresh: {\n type: 'boolean',\n description: 'If true, bypass cache and fetch fresh content. Default false.',\n default: false,\n },\n },\n required: ['url'],\n },\n },\n {\n name: 'score_url',\n description:\n 'Get the AIO (AI-readability) score for any URL. Returns a 0-100 score plus a list of penalties, benefits, and recommendations describing why the source is or is not well-suited for AI consumption. Use this to evaluate source quality before relying on it.',\n inputSchema: {\n type: 'object',\n properties: {\n url: {\n type: 'string',\n description: 'The URL to score.',\n },\n },\n required: ['url'],\n },\n },\n {\n name: 'read_and_score',\n description:\n 'Read any URL and return both clean Markdown AND the AIO accuracy score in one call. The recommended default for most AI workflows — gives both content and quality assessment together, so the AI agent can decide how much to trust the content.',\n inputSchema: {\n type: 'object',\n properties: {\n url: {\n type: 'string',\n description: 'The URL to read and score.',\n },\n fresh: {\n type: 'boolean',\n description: 'If true, bypass cache and fetch fresh content. Default false.',\n default: false,\n },\n },\n required: ['url'],\n },\n },\n {\n name: 'batch',\n description:\n 'Process many URLs in ONE call (billed as one request) — so you do not spend a credit per URL. Give either \"urls\" (an explicit list, up to 50) or \"site\" (a base URL whose pages are auto-discovered via sitemap). \"mode\" picks what to do per URL: \"read\" (Markdown), \"read-and-score\" (Markdown + AIO trust score, default), or \"extract\" (JSON-LD + OpenGraph + meta + score). Use this for full-site reads or bulk URL processing.',\n inputSchema: {\n type: 'object',\n properties: {\n urls: {\n type: 'array',\n items: { type: 'string' },\n description: 'Explicit list of URLs to process (up to 50). Use this OR \"site\".',\n },\n site: {\n type: 'string',\n description: 'Base URL of a site whose pages will be auto-discovered. Use this OR \"urls\".',\n },\n mode: {\n type: 'string',\n enum: ['read', 'read-and-score', 'extract'],\n description: 'What to do per URL. Default \"read-and-score\".',\n },\n limit: {\n type: 'number',\n description: 'Site mode only: max pages to discover (default 25, max 50).',\n },\n },\n },\n },\n {\n name: 'map_site',\n description:\n 'Discover a site\\'s URLs (from sitemap.xml, falling back to on-page links) without reading them. Fast and cheap — use it to plan which pages to read or crawl next.',\n inputSchema: {\n type: 'object',\n properties: {\n url: {\n type: 'string',\n description: 'The site URL to map.',\n },\n limit: {\n type: 'number',\n description: 'Max URLs to return (default 100, max 1000).',\n },\n },\n required: ['url'],\n },\n },\n {\n name: 'extract_data',\n description:\n 'Extract the structured data a page already declares — JSON-LD (schema.org), OpenGraph cards, and meta tags — plus the AIO trust score. Deterministic, no AI: returns only data present in the page. Use for fast, reliable facts (prices, products, articles) when the site publishes structured data.',\n inputSchema: {\n type: 'object',\n properties: {\n url: {\n type: 'string',\n description: 'The URL to extract structured data from.',\n },\n },\n required: ['url'],\n },\n },\n ],\n}));\n\nserver.setRequestHandler(CallToolRequestSchema, async (request) => {\n const { name, arguments: args } = request.params;\n\n try {\n switch (name) {\n case 'read_url': {\n const validated = readUrlInputSchema.parse(args ?? {});\n return await readUrl(validated);\n }\n case 'score_url': {\n const validated = scoreUrlInputSchema.parse(args ?? {});\n return await scoreUrl(validated);\n }\n case 'read_and_score': {\n const validated = readAndScoreInputSchema.parse(args ?? {});\n return await readAndScore(validated);\n }\n case 'batch': {\n const validated = batchInputSchema.parse(args ?? {});\n return await batchRead(validated);\n }\n case 'map_site': {\n const validated = mapInputSchema.parse(args ?? {});\n return await mapSite(validated);\n }\n case 'extract_data': {\n const validated = extractInputSchema.parse(args ?? {});\n return await extractData(validated);\n }\n default:\n throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`);\n }\n } catch (error) {\n if (error instanceof McpError) throw error;\n const message = error instanceof Error ? error.message : String(error);\n return {\n content: [{ type: 'text' as const, text: `Tool '${name}' failed: ${message}` }],\n isError: true,\n };\n }\n});\n\nasync function main() {\n const transport = new StdioServerTransport();\n await server.connect(transport);\n // stderr (not stdout) — stdout is reserved for MCP protocol frames\n console.error(`[onto-mcp] v${version} listening on stdio`);\n}\n\nmain().catch((err) => {\n console.error('[onto-mcp] fatal:', err);\n process.exit(1);\n});\n","import { z } from 'zod';\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';\nimport { callOntoApi } from '../lib/api-client.js';\nimport { formatToolError } from '../lib/errors.js';\nimport { ontoReport } from '../lib/report.js';\nimport type { ReadResponse } from '../lib/types.js';\n\nexport const readUrlInputSchema = z.object({\n url: z.string().url(),\n fresh: z.boolean().optional().default(false),\n});\n\nexport type ReadUrlInput = z.infer<typeof readUrlInputSchema>;\n\nexport async function readUrl(input: ReadUrlInput): Promise<CallToolResult> {\n try {\n const result = await callOntoApi<ReadResponse>('/v1/read', {\n body: { url: input.url, fresh: input.fresh },\n });\n\n const metaLines = [\n `- URL: ${result.url}`,\n `- Title: ${result.metadata.title || '(none)'}`,\n `- Original size: ${result.stats.raw_html_size_kb} KB`,\n `- Cleaned size: ${result.stats.markdown_size_kb} KB`,\n `- Reduction: ${result.stats.reduction_percent}%`,\n `- Extraction time: ${result.stats.extraction_time_ms} ms`,\n `- Cache: ${result.cache.hit ? 'HIT' : 'MISS'}`,\n ].join('\\n');\n\n return {\n content: [\n { type: 'text' as const, text: result.markdown },\n {\n type: 'text' as const,\n text: `\\n\\n---\\n\\n**Source metadata (from Onto):**\\n${metaLines}\\n\\n${ontoReport({\n rawKb: result.stats.raw_html_size_kb,\n cleanKb: result.stats.markdown_size_kb,\n reductionPercent: result.stats.reduction_percent,\n })}`,\n },\n ],\n };\n } catch (error) {\n return formatToolError(error);\n }\n}\n","export const version = '1.3.0';\n","/* Thin HTTP wrapper around the Onto Read API. Reads ONTO_API_KEY at call time\n * (not module-load) so server.ts can fail with a clean error message first. */\n\nimport { version as PACKAGE_VERSION } from './version.js';\nimport type { ApiErrorBody } from './types.js';\n\nconst DEFAULT_BASE = 'https://api.buildonto.dev';\nconst REQUEST_TIMEOUT_MS = 15_000;\n\nexport class OntoApiError extends Error {\n constructor(\n message: string,\n public readonly status: number,\n public readonly code?: string,\n ) {\n super(message);\n this.name = 'OntoApiError';\n }\n}\n\ninterface CallOptions {\n body: unknown;\n signal?: AbortSignal;\n}\n\nexport async function callOntoApi<T>(endpoint: string, options: CallOptions): Promise<T> {\n const apiKey = process.env.ONTO_API_KEY;\n if (!apiKey) {\n throw new OntoApiError(\n 'ONTO_API_KEY environment variable is not set. Get a key at https://app.buildonto.dev/read/keys',\n 0,\n 'NO_API_KEY',\n );\n }\n\n const base = process.env.ONTO_API_BASE ?? DEFAULT_BASE;\n const url = `${base}${endpoint}`;\n\n const timeout = AbortSignal.timeout(REQUEST_TIMEOUT_MS);\n const signal = options.signal\n ? AbortSignal.any([options.signal, timeout])\n : timeout;\n\n let response: Response;\n try {\n response = await fetch(url, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${apiKey}`,\n 'Content-Type': 'application/json',\n 'User-Agent': `@ontosdk/mcp/${PACKAGE_VERSION}`,\n },\n body: JSON.stringify(options.body),\n signal,\n });\n } catch (err) {\n if (err instanceof DOMException && err.name === 'TimeoutError') {\n throw new OntoApiError(\n `Onto API request timed out after ${REQUEST_TIMEOUT_MS / 1000}s. The target site may be slow or unreachable.`,\n 0,\n 'TIMEOUT',\n );\n }\n throw new OntoApiError(\n `Failed to reach Onto API at ${base}: ${(err as Error).message}`,\n 0,\n 'NETWORK_ERROR',\n );\n }\n\n const rawBody = await response.text();\n\n if (!response.ok) {\n let parsed: Partial<ApiErrorBody> = {};\n try {\n parsed = JSON.parse(rawBody) as Partial<ApiErrorBody>;\n } catch {\n // Body wasn't JSON; fall through with status-code-only error\n }\n\n const message = humanizeError(response.status, parsed);\n throw new OntoApiError(message, response.status, parsed.error);\n }\n\n try {\n return JSON.parse(rawBody) as T;\n } catch (err) {\n throw new OntoApiError(\n `Onto API returned invalid JSON: ${(err as Error).message}`,\n response.status,\n 'INVALID_RESPONSE',\n );\n }\n}\n\nfunction humanizeError(status: number, body: Partial<ApiErrorBody>): string {\n if (status === 401) {\n return 'Invalid Onto API key. Verify your key at https://app.buildonto.dev/read/keys';\n }\n if (status === 402) {\n return (\n body.message ??\n 'Monthly plan quota exceeded and credit balance is empty. Top up credits at https://app.buildonto.dev/read/billing'\n );\n }\n if (status === 403) {\n if (body.error === 'ROBOTS_BLOCKED') {\n return body.message ?? 'The target site blocks AI crawlers via robots.txt.';\n }\n return body.message ?? 'Forbidden.';\n }\n if (status === 429) {\n return (\n body.message ??\n 'Onto API rate limit exceeded. Upgrade your tier at https://app.buildonto.dev/read/billing or wait for the monthly reset.'\n );\n }\n if (status >= 500) {\n return body.message ?? `Onto API server error (${status}). Try again in a moment.`;\n }\n return body.message ?? `Onto API returned ${status}.`;\n}\n","/* Format errors as MCP tool responses. We don't throw McpError for\n * tool-call failures — the AI host shows tool errors to the user as\n * unhelpful internal-error messages. Returning isError: true with a\n * text body lets the model see what went wrong and recover. */\n\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';\nimport { OntoApiError } from './api-client.js';\n\nexport function formatToolError(error: unknown): CallToolResult {\n if (error instanceof OntoApiError) {\n return {\n content: [{ type: 'text', text: error.message }],\n isError: true,\n };\n }\n\n const message = error instanceof Error ? error.message : String(error);\n return {\n content: [\n {\n type: 'text',\n text: `Onto MCP error: ${message}\\n\\nTroubleshooting:\\n- Verify ONTO_API_KEY is set and valid (https://app.buildonto.dev/read/keys)\\n- Check the target URL is publicly accessible\\n- Check your monthly quota at https://app.buildonto.dev/read/usage`,\n },\n ],\n isError: true,\n };\n}\n","/* The \"Onto report\" — a single branded summary line appended to the end of\n * every tool response. This is a deliberate growth surface: every agent call\n * leaves Onto's value (reduction, tokens saved, trust score) visible in the\n * host's context, and stamps the brand. Keep it to ONE line, always the same\n * shape so it becomes recognizable.\n *\n * Token estimate uses 4 bytes/token — the same heuristic the dashboard uses\n * for its \"tokens saved\" stat, so numbers stay consistent across surfaces.\n */\n\nconst BYTES_PER_TOKEN = 4;\n\nexport interface OntoReportInput {\n /** Raw HTML size in KB (before Onto cleaned it). */\n rawKb?: number;\n /** Clean Markdown size in KB (what the agent actually consumes). */\n cleanKb?: number;\n /** Percentage shrink from raw → clean. */\n reductionPercent?: number;\n /** AIO readability score 0–100, when available. */\n aioScore?: number;\n /** Hallucination-risk band, when available. */\n risk?: 'low' | 'medium' | 'high';\n}\n\n/** Estimated input tokens saved by serving Markdown instead of raw HTML. */\nexport function estimateTokensSaved(rawKb: number, cleanKb: number): number {\n const savedBytes = Math.max(0, (rawKb - cleanKb) * 1024);\n return Math.round(savedBytes / BYTES_PER_TOKEN);\n}\n\n/** Compact, human-friendly token count: 1234 → \"1.2K\", 199000 → \"199K\". */\nfunction compact(n: number): string {\n if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`;\n if (n >= 10_000) return `${Math.round(n / 1_000)}K`;\n if (n >= 1_000) return `${(n / 1_000).toFixed(1)}K`;\n return `${n}`;\n}\n\n/**\n * Build the single-line Onto report. Only the fields that are present get\n * rendered, so the same helper works for read_url (no score) and\n * read_and_score / score_url (with score).\n */\nexport function ontoReport(input: OntoReportInput): string {\n const parts: string[] = [];\n\n if (input.rawKb != null && input.cleanKb != null) {\n parts.push(`${input.rawKb}KB → ${input.cleanKb}KB`);\n if (input.reductionPercent != null) parts.push(`${input.reductionPercent}% smaller`);\n parts.push(`~${compact(estimateTokensSaved(input.rawKb, input.cleanKb))} tokens saved`);\n } else if (input.reductionPercent != null) {\n parts.push(`${input.reductionPercent}% smaller`);\n }\n\n if (input.aioScore != null) {\n parts.push(`AIO ${input.aioScore}/100${input.risk ? ` (${input.risk} risk)` : ''}`);\n }\n\n return `⚡ Onto · ${parts.join(' · ')} · buildonto.dev`;\n}\n","import { z } from 'zod';\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';\nimport { callOntoApi } from '../lib/api-client.js';\nimport { formatToolError } from '../lib/errors.js';\nimport { ontoReport } from '../lib/report.js';\nimport type { ScoreResponse, Recommendation } from '../lib/types.js';\n\nexport const scoreUrlInputSchema = z.object({\n url: z.string().url(),\n});\n\nexport type ScoreUrlInput = z.infer<typeof scoreUrlInputSchema>;\n\nexport async function scoreUrl(input: ScoreUrlInput): Promise<CallToolResult> {\n try {\n const result = await callOntoApi<ScoreResponse>('/v1/score', {\n body: { url: input.url },\n });\n\n return {\n content: [{ type: 'text' as const, text: formatScoreSummary(result) }],\n };\n } catch (error) {\n return formatToolError(error);\n }\n}\n\nexport function formatScoreSummary(result: ScoreResponse): string {\n const lines: string[] = [\n `**AIO Score:** ${result.aio_score}/100 (${result.grade})`,\n `**Hallucination risk:** ${result.hallucination_risk}`,\n `**URL:** ${result.url}`,\n '',\n ];\n\n if (result.benefits.length > 0) {\n lines.push('**What works well:**');\n for (const item of result.benefits) lines.push(`- ${item}`);\n lines.push('');\n }\n\n if (result.penalties.length > 0) {\n lines.push('**What hurts AI readability:**');\n for (const item of result.penalties) lines.push(`- ${item}`);\n lines.push('');\n }\n\n const insightEntries = Object.entries(result.insights ?? {});\n if (insightEntries.length > 0) {\n lines.push('**Insights:**');\n for (const [key, value] of insightEntries) {\n lines.push(`- ${key}: ${value ? 'yes' : 'no'}`);\n }\n lines.push('');\n }\n\n if (result.recommendations.length > 0) {\n lines.push('**Recommendations:**');\n for (const rec of result.recommendations) {\n lines.push(describeRecommendation(rec));\n }\n lines.push('');\n }\n\n lines.push('**Stats:**');\n lines.push(`- Raw size: ${result.stats.raw_size}`);\n lines.push(`- Efficiency: ${result.stats.efficiency}`);\n lines.push(`- Extraction time: ${result.stats.extraction_time_ms} ms`);\n lines.push('');\n lines.push(ontoReport({ aioScore: result.aio_score, risk: result.hallucination_risk }));\n\n return lines.join('\\n');\n}\n\nfunction describeRecommendation(rec: Recommendation): string {\n if (typeof rec === 'string') return `- ${rec}`;\n if (rec.title) {\n const head = rec.priority ? `**${rec.title}** _(priority: ${rec.priority})_` : `**${rec.title}**`;\n return rec.description ? `- ${head} — ${rec.description}` : `- ${head}`;\n }\n if (rec.description) return `- ${rec.description}`;\n return `- ${JSON.stringify(rec)}`;\n}\n","import { z } from 'zod';\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';\nimport { callOntoApi } from '../lib/api-client.js';\nimport { formatToolError } from '../lib/errors.js';\nimport { ontoReport } from '../lib/report.js';\nimport type { ReadAndScoreResponse } from '../lib/types.js';\n\nexport const readAndScoreInputSchema = z.object({\n url: z.string().url(),\n fresh: z.boolean().optional().default(false),\n});\n\nexport type ReadAndScoreInput = z.infer<typeof readAndScoreInputSchema>;\n\nexport async function readAndScore(input: ReadAndScoreInput): Promise<CallToolResult> {\n try {\n const result = await callOntoApi<ReadAndScoreResponse>('/v1/read-and-score', {\n body: { url: input.url, fresh: input.fresh },\n });\n\n const trustHint = trustLine(result.aio_score, result.hallucination_risk);\n const summaryLines = [\n `**Source quality assessment (from Onto):**`,\n `- AIO Score: ${result.aio_score}/100 (${result.grade})`,\n `- Hallucination risk: ${result.hallucination_risk}`,\n `- Reduction: ${result.stats.reduction_percent}% (${result.stats.raw_html_size_kb} KB → ${result.stats.markdown_size_kb} KB)`,\n `- Cache: ${result.cache.hit ? 'HIT' : 'MISS'}`,\n '',\n trustHint,\n '',\n ontoReport({\n rawKb: result.stats.raw_html_size_kb,\n cleanKb: result.stats.markdown_size_kb,\n reductionPercent: result.stats.reduction_percent,\n aioScore: result.aio_score,\n risk: result.hallucination_risk,\n }),\n ];\n\n return {\n content: [\n { type: 'text' as const, text: result.markdown },\n { type: 'text' as const, text: `\\n\\n---\\n\\n${summaryLines.join('\\n')}` },\n ],\n };\n } catch (error) {\n return formatToolError(error);\n }\n}\n\nfunction trustLine(score: number, risk: 'low' | 'medium' | 'high'): string {\n if (risk === 'high' || score < 40) {\n return 'Trust signal: low — this source is poorly structured for AI consumption. Verify any facts before relying on them.';\n }\n if (risk === 'medium' || score < 70) {\n return 'Trust signal: medium — source is partially AI-readable. Cross-check critical claims.';\n }\n return 'Trust signal: high — source is well-structured for AI consumption.';\n}\n","import { z } from 'zod';\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';\nimport { callOntoApi } from '../lib/api-client.js';\nimport { formatToolError } from '../lib/errors.js';\nimport type { BatchResponse, BatchResult } from '../lib/types.js';\n\nexport const batchInputSchema = z\n .object({\n urls: z.array(z.string().url()).min(1).max(50).optional(),\n site: z.string().url().optional(),\n mode: z.enum(['read', 'read-and-score', 'extract']).optional(),\n limit: z.number().int().min(1).max(50).optional(),\n })\n .refine((v) => (v.urls && v.urls.length > 0) || v.site, {\n message: 'Provide either \"urls\" (array) or \"site\" (string).',\n });\n\nexport type BatchInput = z.infer<typeof batchInputSchema>;\n\nfunction renderResult(r: BatchResult): string {\n if (!r.ok) {\n return `### ${r.url}\\n_skipped — ${r.error?.code}: ${r.error?.message}_`;\n }\n const head = [`### ${r.title || r.url}`, r.url];\n if (r.aio_score != null) {\n head.push(`AIO ${r.aio_score}/100 (${r.grade}, ${r.hallucination_risk} risk)`);\n }\n if (r.reduction_percent != null) head.push(`${r.reduction_percent}% smaller`);\n const lines = [head.join(' · ')];\n\n if (r.structured) {\n lines.push('', `JSON-LD: ${r.counts?.json_ld ?? 0} · OG: ${r.counts?.open_graph ?? 0} · meta: ${r.counts?.meta ?? 0}`);\n if (r.structured.jsonLd.length > 0) {\n lines.push('```json', JSON.stringify(r.structured.jsonLd, null, 2), '```');\n }\n } else if (r.markdown) {\n lines.push('', r.markdown);\n }\n return lines.join('\\n');\n}\n\nexport async function batchRead(input: BatchInput): Promise<CallToolResult> {\n try {\n const result = await callOntoApi<BatchResponse>('/v1/batch', {\n body: { urls: input.urls, site: input.site, mode: input.mode, limit: input.limit },\n });\n\n const header =\n result.source === 'site'\n ? `# Batch ${result.mode} — site discovery`\n : `# Batch ${result.mode} — ${result.requested} URL(s)`;\n\n const lines = [\n header,\n `${result.succeeded}/${result.requested} succeeded.`,\n '',\n ...result.results.map(renderResult).flatMap((block) => [block, '']),\n `⚡ Onto · ${result.succeeded}/${result.requested} URLs in one call · buildonto.dev`,\n ];\n\n return { content: [{ type: 'text' as const, text: lines.join('\\n') }] };\n } catch (error) {\n return formatToolError(error);\n }\n}\n","import { z } from 'zod';\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';\nimport { callOntoApi } from '../lib/api-client.js';\nimport { formatToolError } from '../lib/errors.js';\nimport type { MapResponse } from '../lib/types.js';\n\nexport const mapInputSchema = z.object({\n url: z.string().url(),\n limit: z.number().int().min(1).max(1000).optional(),\n});\n\nexport type MapInput = z.infer<typeof mapInputSchema>;\n\nexport async function mapSite(input: MapInput): Promise<CallToolResult> {\n try {\n const result = await callOntoApi<MapResponse>('/v1/map', {\n body: { url: input.url, limit: input.limit },\n });\n\n const lines: string[] = [\n `# Sitemap for ${result.url}`,\n `Discovered ${result.count} URL(s) via ${result.source}.`,\n '',\n ...result.urls.map((u) => `- ${u}`),\n '',\n `⚡ Onto · ${result.count} URLs mapped (${result.source}) · buildonto.dev`,\n ];\n\n return { content: [{ type: 'text' as const, text: lines.join('\\n') }] };\n } catch (error) {\n return formatToolError(error);\n }\n}\n","import { z } from 'zod';\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';\nimport { callOntoApi } from '../lib/api-client.js';\nimport { formatToolError } from '../lib/errors.js';\nimport { ontoReport } from '../lib/report.js';\nimport type { ExtractResponse } from '../lib/types.js';\n\nexport const extractInputSchema = z.object({\n url: z.string().url(),\n});\n\nexport type ExtractInput = z.infer<typeof extractInputSchema>;\n\nexport async function extractData(input: ExtractInput): Promise<CallToolResult> {\n try {\n const result = await callOntoApi<ExtractResponse>('/v1/extract', {\n body: { url: input.url },\n });\n\n const og = Object.entries(result.structured.openGraph);\n const meta = Object.entries(result.structured.meta);\n\n const lines: string[] = [\n `# Structured data for ${result.url}`,\n result.title ? `Title: ${result.title}` : '',\n `Found ${result.counts.json_ld} JSON-LD object(s), ${result.counts.open_graph} OpenGraph tag(s), ${result.counts.meta} meta tag(s).`,\n '',\n '## JSON-LD',\n result.structured.jsonLd.length > 0\n ? '```json\\n' + JSON.stringify(result.structured.jsonLd, null, 2) + '\\n```'\n : '(none declared)',\n '',\n '## OpenGraph',\n og.length > 0 ? og.map(([k, v]) => `- ${k}: ${v}`).join('\\n') : '(none)',\n '',\n '## Meta',\n meta.length > 0 ? meta.map(([k, v]) => `- ${k}: ${v}`).join('\\n') : '(none)',\n '',\n ontoReport({ aioScore: result.aio_score, risk: result.hallucination_risk }),\n ].filter((line) => line !== '');\n\n return { content: [{ type: 'text' as const, text: lines.join('\\n') }] };\n } catch (error) {\n return formatToolError(error);\n }\n}\n"],"mappings":"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","names":["z","z","z","z","z","z","z","z","z","z"]}
package/package.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "@ontosdk/mcp",
3
- "version": "1.1.1",
3
+ "version": "1.3.0",
4
+ "mcpName": "io.github.ravixalgorithm/onto",
4
5
  "description": "Official Onto MCP server — clean Markdown and AIO scoring for any URL, available as MCP tools for Claude Code, Cursor, and any MCP client.",
5
6
  "type": "module",
6
7
  "main": "./dist/index.js",