@typeship-ax/mcp 0.6.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/api.json +5597 -3010
- package/api.md +433 -54
- package/dist/core/http.d.ts +6 -92
- package/dist/core/http.d.ts.map +1 -1
- package/dist/core/http.js +70 -209
- package/dist/core/pagination.d.ts.map +1 -1
- package/dist/core/pagination.js +6 -34
- package/dist/dates.d.ts +0 -2
- package/dist/dates.d.ts.map +1 -1
- package/dist/dates.js +0 -1
- package/dist/docs.d.ts +11 -0
- package/dist/docs.d.ts.map +1 -0
- package/dist/docs.js +114 -0
- package/dist/errors.d.ts +27 -27
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +7 -7
- package/dist/index.d.ts +19 -11
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +23 -13
- package/dist/mcp-protocol.d.ts +19 -24
- package/dist/mcp-protocol.d.ts.map +1 -1
- package/dist/mcp-protocol.js +160 -124
- package/dist/mcp.js +16 -19
- package/dist/ops.d.ts +5 -0
- package/dist/ops.d.ts.map +1 -1
- package/dist/ops.js +31 -17
- package/dist/resources/account.d.ts +2 -2
- package/dist/resources/account.d.ts.map +1 -1
- package/dist/resources/api-keys.d.ts +10 -5
- package/dist/resources/api-keys.d.ts.map +1 -1
- package/dist/resources/api-keys.js +3 -1
- package/dist/resources/definition-revisions.d.ts +58 -0
- package/dist/resources/definition-revisions.d.ts.map +1 -0
- package/dist/resources/definition-revisions.js +110 -0
- package/dist/resources/definitions.d.ts +24 -0
- package/dist/resources/definitions.d.ts.map +1 -0
- package/dist/resources/definitions.js +51 -0
- package/dist/resources/generate.d.ts +5 -5
- package/dist/resources/generate.d.ts.map +1 -1
- package/dist/resources/generate.js +3 -3
- package/dist/resources/generations.d.ts +3 -3
- package/dist/resources/generations.d.ts.map +1 -1
- package/dist/resources/generations.js +1 -1
- package/dist/resources/projects.d.ts +66 -26
- package/dist/resources/projects.d.ts.map +1 -1
- package/dist/resources/projects.js +87 -13
- package/dist/resources/targets.d.ts +86 -0
- package/dist/resources/targets.d.ts.map +1 -0
- package/dist/resources/targets.js +184 -0
- package/dist/schemas.d.ts.map +1 -1
- package/dist/schemas.js +119 -62
- package/dist/types.d.ts +1761 -222
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +9 -3
- package/package.json +1 -1
- package/src/core/http.ts +75 -293
- package/src/core/pagination.ts +6 -30
- package/src/dates.ts +0 -1
- package/src/docs.ts +101 -0
- package/src/errors.ts +30 -30
- package/src/index.ts +23 -13
- package/src/mcp-protocol.ts +170 -120
- package/src/mcp.ts +22 -22
- package/src/ops.ts +43 -17
- package/src/resources/account.ts +3 -3
- package/src/resources/api-keys.ts +22 -7
- package/src/resources/definition-revisions.ts +198 -0
- package/src/resources/definitions.ts +97 -0
- package/src/resources/generate.ts +6 -6
- package/src/resources/generations.ts +4 -4
- package/src/resources/projects.ts +182 -37
- package/src/resources/targets.ts +346 -0
- package/src/schemas.ts +119 -62
- package/src/types.ts +1947 -281
- package/dist/resources/spec-revisions.d.ts +0 -47
- package/dist/resources/spec-revisions.d.ts.map +0 -1
- package/dist/resources/spec-revisions.js +0 -90
- package/src/resources/spec-revisions.ts +0 -150
package/dist/mcp-protocol.js
CHANGED
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
* Spec: https://modelcontextprotocol.io/specification/2026-07-28
|
|
16
16
|
*/
|
|
17
17
|
import { dateKindOf, relativeDate } from "./dates.js";
|
|
18
|
+
import { resolveDocsContentUrl } from "./docs.js";
|
|
18
19
|
export const MCP_PROTOCOL_VERSION = "2026-07-28";
|
|
19
20
|
/** Revisions served. Legacy (initialize-handshake) revisions are not; an
|
|
20
21
|
* initialize request gets an error naming this list, as the spec asks of
|
|
@@ -185,7 +186,7 @@ export async function handleRpc(server, incoming) {
|
|
|
185
186
|
const started = Date.now();
|
|
186
187
|
const outcome = await server.callTool(name, args);
|
|
187
188
|
if (outcome === undefined)
|
|
188
|
-
return rpcError(id, -32602, "Unknown tool: " + name, 400);
|
|
189
|
+
return rpcError(id, -32602, server.unknownToolMessage?.(name) ?? "Unknown tool: " + name, 400);
|
|
189
190
|
if (server.afterToolCall)
|
|
190
191
|
await server.afterToolCall(name, outcome, Date.now() - started);
|
|
191
192
|
// A tool that declares an outputSchema MUST return structuredContent,
|
|
@@ -275,8 +276,18 @@ export function exampleFromSchema(schema, field = "value", depth = 0) {
|
|
|
275
276
|
return node.examples[0];
|
|
276
277
|
if (node.default !== undefined)
|
|
277
278
|
return node.default;
|
|
278
|
-
if (Array.isArray(node.enum) && node.enum.length > 0)
|
|
279
|
+
if (Array.isArray(node.enum) && node.enum.length > 0) {
|
|
280
|
+
if (typeof node.pattern === "string") {
|
|
281
|
+
try {
|
|
282
|
+
const pattern = new RegExp(node.pattern);
|
|
283
|
+
const matching = node.enum.find((value) => typeof value === "string" && pattern.test(value));
|
|
284
|
+
if (matching !== undefined)
|
|
285
|
+
return matching;
|
|
286
|
+
}
|
|
287
|
+
catch { /* malformed patterns are ignored for examples */ }
|
|
288
|
+
}
|
|
279
289
|
return node.enum.find((v) => v !== null) ?? node.enum[0];
|
|
290
|
+
}
|
|
280
291
|
const variants = (Array.isArray(node.oneOf) ? node.oneOf : Array.isArray(node.anyOf) ? node.anyOf : null);
|
|
281
292
|
if (variants) {
|
|
282
293
|
const useful = variants.find((v) => v && typeof v === "object" && v.type !== "null") ?? variants[0];
|
|
@@ -316,7 +327,10 @@ export function exampleFromSchema(schema, field = "value", depth = 0) {
|
|
|
316
327
|
if (type === "string" || type === undefined) {
|
|
317
328
|
const format = typeof node.format === "string" ? node.format : "";
|
|
318
329
|
const lower = field.toLowerCase();
|
|
319
|
-
|
|
330
|
+
const min = typeof node.minLength === "number" ? node.minLength : 0;
|
|
331
|
+
const max = typeof node.maxLength === "number" ? node.maxLength : undefined;
|
|
332
|
+
const patterned = typeof node.pattern === "string" ? exampleMatchingPattern(node.pattern, min, max) : null;
|
|
333
|
+
let value = patterned ?? (format === "date-time" ? "2026-01-15T12:00:00Z"
|
|
320
334
|
: format === "date" ? "2026-01-15"
|
|
321
335
|
: format === "email" || lower.includes("email") ? "person@example.com"
|
|
322
336
|
: (format === "uri" || format === "url" || lower.endsWith("url")) && (lower.includes("webhook") || lower.includes("callback")) ? "https://example.com/webhook"
|
|
@@ -327,16 +341,47 @@ export function exampleFromSchema(schema, field = "value", depth = 0) {
|
|
|
327
341
|
: lower.includes("version") ? "1.0.0"
|
|
328
342
|
: /(^|_)id$|Id$/.test(field) ? (lower === "id" ? "id" : field.replace(/[_-]?id$/i, "")) + "_123"
|
|
329
343
|
: lower.includes("name") ? "example"
|
|
330
|
-
: "value";
|
|
331
|
-
const min = typeof node.minLength === "number" ? node.minLength : 0;
|
|
344
|
+
: "value");
|
|
332
345
|
while (value.length < min)
|
|
333
346
|
value += "x";
|
|
334
|
-
if (
|
|
335
|
-
value = value.slice(0,
|
|
347
|
+
if (max !== undefined)
|
|
348
|
+
value = value.slice(0, max);
|
|
336
349
|
return value;
|
|
337
350
|
}
|
|
338
351
|
return null;
|
|
339
352
|
}
|
|
353
|
+
/** A useful value for the common API-id pattern (`^agt_`, `^src_[a-z0-9]+$`).
|
|
354
|
+
* Full regex generation would be surprising and heavyweight; an anchored
|
|
355
|
+
* literal prefix plus ordinary id suffix covers the schemas that use a
|
|
356
|
+
* pattern to communicate a typed identifier. Every candidate is checked by
|
|
357
|
+
* the actual RegExp before it is returned. */
|
|
358
|
+
function exampleMatchingPattern(pattern, minLength, maxLength) {
|
|
359
|
+
let regex;
|
|
360
|
+
try {
|
|
361
|
+
regex = new RegExp(pattern);
|
|
362
|
+
}
|
|
363
|
+
catch {
|
|
364
|
+
return null;
|
|
365
|
+
}
|
|
366
|
+
const match = /^\^((?:\\.|[A-Za-z0-9_-])+)/.exec(pattern);
|
|
367
|
+
const prefix = match?.[1]?.replace(/\\(.)/g, "$1") ?? "";
|
|
368
|
+
const fit = (candidate) => {
|
|
369
|
+
let value = candidate;
|
|
370
|
+
while (value.length < minLength)
|
|
371
|
+
value += "x";
|
|
372
|
+
if (maxLength !== undefined)
|
|
373
|
+
value = value.slice(0, maxLength);
|
|
374
|
+
return value;
|
|
375
|
+
};
|
|
376
|
+
const candidates = [prefix + "123", prefix + "example", prefix, "example", "value"];
|
|
377
|
+
for (const candidate of candidates) {
|
|
378
|
+
const value = fit(candidate);
|
|
379
|
+
regex.lastIndex = 0;
|
|
380
|
+
if (regex.test(value))
|
|
381
|
+
return value;
|
|
382
|
+
}
|
|
383
|
+
return null;
|
|
384
|
+
}
|
|
340
385
|
export function exampleArgumentsFromSchema(inputSchema) {
|
|
341
386
|
const value = exampleFromSchema(inputSchema, "arguments");
|
|
342
387
|
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
@@ -400,7 +445,7 @@ export const EXECUTE_TOOL = {
|
|
|
400
445
|
inputSchema: {
|
|
401
446
|
type: "object",
|
|
402
447
|
properties: {
|
|
403
|
-
operation: { type: "string", description: "Operation tool name
|
|
448
|
+
operation: { type: "string", description: "Operation tool name returned by search_docs" },
|
|
404
449
|
arguments: { type: "object", description: "Operation arguments keyed by parameter name" },
|
|
405
450
|
confirm: { type: "boolean", description: "Required and must be true for destructive operations. Omit for reads and ordinary writes." },
|
|
406
451
|
},
|
|
@@ -433,36 +478,23 @@ export function parseIncludeList(value) {
|
|
|
433
478
|
* three-tool "meta" shape (search_docs, read_docs, execute) that keeps huge
|
|
434
479
|
* APIs from flooding an agent's context. Deterministic order.
|
|
435
480
|
*/
|
|
436
|
-
export function toolDefinitions(ops, mode) {
|
|
481
|
+
export function toolDefinitions(ops, mode, omittedOps = []) {
|
|
437
482
|
if (mode === "meta") {
|
|
483
|
+
const execute = structuredClone(EXECUTE_TOOL);
|
|
484
|
+
const operation = execute.inputSchema.properties.operation;
|
|
485
|
+
if (ops[0])
|
|
486
|
+
operation.examples = [ops[0].tool];
|
|
487
|
+
const coverage = omittedOps.length > 0
|
|
488
|
+
? " Generated " + ops.length + " of " + (ops.length + omittedOps.length) + " operations; search_docs names operations omitted by the plan limit."
|
|
489
|
+
: "";
|
|
438
490
|
return [
|
|
439
|
-
{ ...SEARCH_DOCS_TOOL, description: "Search this API's " + ops.length + " operations and, when a docs site is configured, its guides. Start here to find the operation you need." },
|
|
491
|
+
{ ...SEARCH_DOCS_TOOL, description: "Search this API's " + ops.length + " generated operations and, when a docs site is configured, its guides. Start here to find the operation you need." + coverage },
|
|
440
492
|
{ ...READ_DOCS_TOOL, description: "Read an operation's full reference (arguments, schemas, authentication, safety and example) by tool name, or a docs-site guide page." },
|
|
441
|
-
|
|
493
|
+
execute,
|
|
442
494
|
];
|
|
443
495
|
}
|
|
444
496
|
return [...ops.map(operationTool), SEARCH_DOCS_TOOL, READ_DOCS_TOOL];
|
|
445
497
|
}
|
|
446
|
-
/** How big a tools/list is, as agents pay for it. Characters of JSON and a
|
|
447
|
-
* rough token count (one token per four characters, the usual estimate for
|
|
448
|
-
* JSON). Generation and `<bin> mcp` report it. */
|
|
449
|
-
export function toolsListSize(tools) {
|
|
450
|
-
const chars = JSON.stringify(tools).length;
|
|
451
|
-
return { tools: tools.length, chars, approxTokens: Math.round(chars / 4) };
|
|
452
|
-
}
|
|
453
|
-
/** Keep automatic per-operation discovery under roughly 10k tokens. The
|
|
454
|
-
* schema, not merely the operation count, determines what an agent pays. */
|
|
455
|
-
export const MCP_AUTO_MAX_TOOLS_LIST_CHARS = 40_000;
|
|
456
|
-
export function resolveToolMode(ops, requested = "auto") {
|
|
457
|
-
if (requested === "operations" || requested === "meta") {
|
|
458
|
-
return { mode: requested, ...toolsListSize(toolDefinitions(ops, requested)) };
|
|
459
|
-
}
|
|
460
|
-
const operations = toolsListSize(toolDefinitions(ops, "operations"));
|
|
461
|
-
const mode = ops.length > 100 || operations.chars > MCP_AUTO_MAX_TOOLS_LIST_CHARS ? "meta" : "operations";
|
|
462
|
-
return mode === "operations"
|
|
463
|
-
? { mode, ...operations }
|
|
464
|
-
: { mode, ...toolsListSize(toolDefinitions(ops, mode)) };
|
|
465
|
-
}
|
|
466
498
|
/** Resolve an operation by tool name or dotted resource.method. */
|
|
467
499
|
export function findOperation(ops, wanted) {
|
|
468
500
|
return ops.find((o) => o.tool === wanted)
|
|
@@ -480,6 +512,10 @@ export function serverInstructions(input) {
|
|
|
480
512
|
parts.push(input.mode === "meta"
|
|
481
513
|
? input.title + " as MCP tools: search_docs, read_docs and execute over " + input.toolCount + " operations. Start with search_docs to find an operation, read_docs <tool> for its full argument reference, then execute it by name. Destructive operations require confirm: true on execute."
|
|
482
514
|
: input.title + " as MCP tools: one tool per operation (" + input.toolCount + "), plus search_docs to find operations and read_docs <tool> for an operation's full argument reference.");
|
|
515
|
+
if (input.omittedOps?.length) {
|
|
516
|
+
const generated = input.generatedOperationCount ?? input.toolCount;
|
|
517
|
+
parts.push("Plan-limited generation: generated " + generated + " of " + (generated + input.omittedOps.length) + " operations. Omitted operations: " + input.omittedOps.map((op) => op.tool + " (" + op.httpMethod + " " + op.path + ")").join(", ") + ". Calling or searching for one returns PLAN_LIMIT with upgrade next_steps.");
|
|
518
|
+
}
|
|
483
519
|
parts.push("Arguments use the API's wire names; an unknown, mistyped or missing argument returns an isError result listing each problem (nothing is dropped silently), and obvious forms are coerced (\"true\" to boolean, \"3\" to number, enum case).");
|
|
484
520
|
parts.push("Paginated tools return items, hasMore and nextPage (the exact arguments for the following page). Pass fields (dotted paths) to keep only the result keys you need; oversized results are cut to whole items or keys with a truncated note saying how to ask for less.");
|
|
485
521
|
parts.push("Errors carry error, code, message, status, the API's body and next_steps.");
|
|
@@ -786,12 +822,17 @@ export function pageOutcome(items, nextPage, options = {}) {
|
|
|
786
822
|
const fields = options.fields ?? null;
|
|
787
823
|
const maxChars = options.maxChars ?? DEFAULT_MAX_RESULT_CHARS;
|
|
788
824
|
const shown = projectFields(items, fields);
|
|
789
|
-
const full = {
|
|
825
|
+
const full = {
|
|
826
|
+
items: shown,
|
|
827
|
+
hasMore: nextPage !== null,
|
|
828
|
+
...(nextPage !== null ? { nextPage } : {}),
|
|
829
|
+
...(options.requestId ? { request_id: options.requestId } : {}),
|
|
830
|
+
};
|
|
790
831
|
const text = JSON.stringify(full);
|
|
791
832
|
if (text.length <= maxChars) {
|
|
792
833
|
return { text, isError: false, structured: full };
|
|
793
834
|
}
|
|
794
|
-
const overhead = JSON.stringify({ items: [], hasMore: true, nextPage: nextPage ?? {}, truncated: { omitted: 0, of: 0, reason: "x".repeat(160), next_steps: ["x".repeat(220), "x".repeat(120)] } }).length;
|
|
835
|
+
const overhead = JSON.stringify({ items: [], hasMore: true, nextPage: nextPage ?? {}, ...(options.requestId ? { request_id: options.requestId } : {}), truncated: { omitted: 0, of: 0, reason: "x".repeat(160), next_steps: ["x".repeat(220), "x".repeat(120)] } }).length;
|
|
795
836
|
const k = itemsThatFit(shown, Math.max(0, maxChars - overhead));
|
|
796
837
|
const omitted = shown.length - k;
|
|
797
838
|
const pg = options.pagination;
|
|
@@ -818,6 +859,7 @@ export function pageOutcome(items, nextPage, options = {}) {
|
|
|
818
859
|
items: shown.slice(0, k),
|
|
819
860
|
hasMore: resume !== null ? true : nextPage !== null,
|
|
820
861
|
...(resume !== null ? { nextPage: resume } : nextPage !== null ? { nextPage } : {}),
|
|
862
|
+
...(options.requestId ? { request_id: options.requestId } : {}),
|
|
821
863
|
truncated: {
|
|
822
864
|
omitted,
|
|
823
865
|
of: shown.length,
|
|
@@ -961,6 +1003,7 @@ export function classifyError(error, context = {}) {
|
|
|
961
1003
|
return { code: "NETWORK_ERROR", nextSteps: ["The API could not be reached (network, DNS, TLS or timeout). Retry once with backoff; do not loop."] };
|
|
962
1004
|
}
|
|
963
1005
|
const status = typeof e.status === "number" ? e.status : 0;
|
|
1006
|
+
const body = e.body;
|
|
964
1007
|
const auth = context.authHint ? context.authHint.trim().replace(/[.]?$/, ".") : null;
|
|
965
1008
|
if (status === 401) {
|
|
966
1009
|
return context.hadCredential
|
|
@@ -977,6 +1020,15 @@ export function classifyError(error, context = {}) {
|
|
|
977
1020
|
const retryAfter = extractRetryAfter(e);
|
|
978
1021
|
return { code: "RATE_LIMITED", nextSteps: [retryAfter ? "Wait " + retryAfter + " seconds, then call again." : "Back off and retry once; the request was already retried with the server's Retry-After."] };
|
|
979
1022
|
}
|
|
1023
|
+
if (status === 422 && body?.errors?.[0]?.code === "spec_error") {
|
|
1024
|
+
return {
|
|
1025
|
+
code: "SPEC_INVALID",
|
|
1026
|
+
nextSteps: [
|
|
1027
|
+
"The API rejected the spec it was given; its error message names the invalid part.",
|
|
1028
|
+
context.docsUrl ? "Use search_docs with the error message, fix the spec, then call again." : "Fix the spec, then call again.",
|
|
1029
|
+
],
|
|
1030
|
+
};
|
|
1031
|
+
}
|
|
980
1032
|
if (status === 400 || status === 409 || status === 413 || status === 422) {
|
|
981
1033
|
return { code: "INVALID_REQUEST", nextSteps: ["Read body for the field the API named, fix that argument and call again."] };
|
|
982
1034
|
}
|
|
@@ -1003,11 +1055,16 @@ function notFoundNextSteps(message, body) {
|
|
|
1003
1055
|
export function errorOutcome(error, context = {}) {
|
|
1004
1056
|
const e = error;
|
|
1005
1057
|
const { code, nextSteps } = classifyError(error, context);
|
|
1058
|
+
const bodyRequestId = e?.body && typeof e.body === "object" && !Array.isArray(e.body)
|
|
1059
|
+
? e.body.request_id ?? e.body.requestId
|
|
1060
|
+
: undefined;
|
|
1061
|
+
const requestId = e?.response?.requestId ?? (typeof bodyRequestId === "string" ? bodyRequestId : undefined);
|
|
1006
1062
|
const structured = {
|
|
1007
1063
|
error: e?.name ?? "Error",
|
|
1008
1064
|
code,
|
|
1009
1065
|
message: e?.message,
|
|
1010
1066
|
...(typeof e?.status === "number" ? { status: e.status } : {}),
|
|
1067
|
+
...(requestId ? { request_id: requestId } : {}),
|
|
1011
1068
|
...(e?.body !== undefined ? { body: e.body } : {}),
|
|
1012
1069
|
...(context.docsUrl ? { docs_url: context.docsUrl } : {}),
|
|
1013
1070
|
next_steps: nextSteps,
|
|
@@ -1018,32 +1075,29 @@ export function textError(text, code = "CALL_FAILED", nextSteps = []) {
|
|
|
1018
1075
|
const structured = { error: "Error", code, message: text, next_steps: nextSteps };
|
|
1019
1076
|
return { text: JSON.stringify(structured), isError: true, structured };
|
|
1020
1077
|
}
|
|
1021
|
-
function docsPageUrl(source, pathOrFile) {
|
|
1022
|
-
const base = source.docsUrl();
|
|
1023
|
-
if (base === null)
|
|
1024
|
-
return null;
|
|
1025
|
-
try {
|
|
1026
|
-
const baseUrl = new URL(base);
|
|
1027
|
-
if (baseUrl.protocol !== "https:" && baseUrl.protocol !== "http:")
|
|
1028
|
-
return null;
|
|
1029
|
-
const target = /^https?:\/\//.test(pathOrFile)
|
|
1030
|
-
? new URL(pathOrFile)
|
|
1031
|
-
: new URL(pathOrFile.replace(/^\/+/, ""), baseUrl.toString().replace(/\/+$/, "") + "/");
|
|
1032
|
-
// llms.txt commonly contains absolute links, but a docs tool is not a
|
|
1033
|
-
// general-purpose URL fetcher. Keeping every page on the configured
|
|
1034
|
-
// origin prevents an agent from turning hosted MCP into an SSRF proxy.
|
|
1035
|
-
if (target.origin !== baseUrl.origin || target.username || target.password)
|
|
1036
|
-
return null;
|
|
1037
|
-
return target.toString();
|
|
1038
|
-
}
|
|
1039
|
-
catch {
|
|
1040
|
-
return null;
|
|
1041
|
-
}
|
|
1042
|
-
}
|
|
1043
1078
|
async function fetchDocs(source, pathOrFile) {
|
|
1044
|
-
const url =
|
|
1079
|
+
const url = resolveDocsContentUrl(source.docsUrl(), source.docsIndexUrl?.() ?? null, pathOrFile);
|
|
1045
1080
|
return url === null ? null : source.fetchText(url);
|
|
1046
1081
|
}
|
|
1082
|
+
function coverageText(source) {
|
|
1083
|
+
const omitted = source.omittedOps ?? [];
|
|
1084
|
+
const generated = source.generatedOperationCount ?? source.ops.length;
|
|
1085
|
+
return omitted.length > 0
|
|
1086
|
+
? "Coverage: generated " + generated + " of " + (generated + omitted.length) + " operations. Omitted by the plan limit: " + omitted.map((op) => op.tool + " (" + op.httpMethod + " " + op.path + ")").join(", ") + "."
|
|
1087
|
+
: null;
|
|
1088
|
+
}
|
|
1089
|
+
function omittedPlanLimit(ops, requested) {
|
|
1090
|
+
const structured = {
|
|
1091
|
+
error: "PlanLimitError",
|
|
1092
|
+
code: "PLAN_LIMIT",
|
|
1093
|
+
message: requested
|
|
1094
|
+
? "The operation " + requested + " exists in the API Definition but was omitted from this generated package by its plan limit."
|
|
1095
|
+
: "Matching operations exist in the API Definition but were omitted from this generated package by its plan limit.",
|
|
1096
|
+
omitted_operations: ops.map((op) => ({ tool: op.tool, method: op.httpMethod, path: op.path })),
|
|
1097
|
+
next_steps: ["Upgrade at https://typeship.dev/pricing and regenerate the package without the operation cap.", "Do not invent or retry an omitted operation against this generated package."],
|
|
1098
|
+
};
|
|
1099
|
+
return { text: JSON.stringify(structured), isError: true, structured };
|
|
1100
|
+
}
|
|
1047
1101
|
export function referenceText(op) {
|
|
1048
1102
|
const safety = operationSafety(op);
|
|
1049
1103
|
const example = op.exampleArguments ?? exampleArgumentsFromSchema(op.inputSchema);
|
|
@@ -1114,12 +1168,20 @@ export function searchScore(op, query) {
|
|
|
1114
1168
|
return score;
|
|
1115
1169
|
}
|
|
1116
1170
|
export async function docsSearch(source, query, page = 1) {
|
|
1117
|
-
const term = query.toLowerCase();
|
|
1171
|
+
const term = query.trim().toLowerCase();
|
|
1172
|
+
const terms = searchTerms(query);
|
|
1118
1173
|
const sections = [];
|
|
1119
1174
|
const ranked = source.ops
|
|
1120
1175
|
.map((op) => ({ op, score: searchScore(op, query) }))
|
|
1121
1176
|
.filter((r) => r.score > 0)
|
|
1122
1177
|
.sort((a, b) => b.score - a.score || a.op.tool.localeCompare(b.op.tool));
|
|
1178
|
+
const omittedRanked = (source.omittedOps ?? [])
|
|
1179
|
+
.map((op) => ({ op, score: searchScore(op, query) }))
|
|
1180
|
+
.filter((result) => result.score > 0)
|
|
1181
|
+
.sort((a, b) => b.score - a.score || a.op.tool.localeCompare(b.op.tool));
|
|
1182
|
+
const exactOmitted = findOperation(source.omittedOps ?? [], query);
|
|
1183
|
+
if (exactOmitted)
|
|
1184
|
+
return omittedPlanLimit([exactOmitted], exactOmitted.tool);
|
|
1123
1185
|
const pageIndex = Math.max(1, Math.floor(page)) - 1;
|
|
1124
1186
|
const slice = ranked.slice(pageIndex * SEARCH_PAGE_SIZE, (pageIndex + 1) * SEARCH_PAGE_SIZE);
|
|
1125
1187
|
if (slice.length > 0) {
|
|
@@ -1132,31 +1194,56 @@ export async function docsSearch(source, query, page = 1) {
|
|
|
1132
1194
|
sections.push("No reference matches on page " + (pageIndex + 1) + "; there are " + Math.ceil(ranked.length / SEARCH_PAGE_SIZE) + " pages.");
|
|
1133
1195
|
}
|
|
1134
1196
|
const prose = await fetchDocs(source, "llms-full.txt");
|
|
1197
|
+
let proseMatchCount = 0;
|
|
1135
1198
|
if (prose !== null) {
|
|
1136
1199
|
let heading = "";
|
|
1137
1200
|
const proseMatches = [];
|
|
1138
1201
|
for (const line of prose.split("\n")) {
|
|
1139
1202
|
if (/^#{1,3} /.test(line))
|
|
1140
1203
|
heading = line.replace(/^#+ /, "").trim();
|
|
1141
|
-
else
|
|
1142
|
-
|
|
1204
|
+
else {
|
|
1205
|
+
const lowerHeading = heading.toLowerCase();
|
|
1206
|
+
const lowerLine = line.toLowerCase();
|
|
1207
|
+
const matched = terms.filter((word) => lowerHeading.includes(word) || lowerLine.includes(word));
|
|
1208
|
+
if (matched.length > 0) {
|
|
1209
|
+
const allTerms = matched.length === terms.length;
|
|
1210
|
+
proseMatches.push({
|
|
1211
|
+
heading,
|
|
1212
|
+
excerpt: line.trim().slice(0, 160),
|
|
1213
|
+
score: matched.length * 10 + (allTerms ? 50 : 0) + (lowerHeading.includes(term) || lowerLine.includes(term) ? 25 : 0),
|
|
1214
|
+
});
|
|
1215
|
+
}
|
|
1143
1216
|
}
|
|
1144
1217
|
}
|
|
1145
|
-
|
|
1146
|
-
|
|
1218
|
+
proseMatches.sort((a, b) => b.score - a.score || a.heading.localeCompare(b.heading) || a.excerpt.localeCompare(b.excerpt));
|
|
1219
|
+
proseMatchCount = proseMatches.length;
|
|
1220
|
+
if (proseMatches.length > 0) {
|
|
1221
|
+
sections.push("Guide matches (best first):\n" + proseMatches.slice(0, 15).map((match) => "- [" + match.heading + "] " + match.excerpt).join("\n"));
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
if (omittedRanked.length > 0 && ranked.length === 0 && proseMatchCount === 0) {
|
|
1225
|
+
return omittedPlanLimit(omittedRanked.map((result) => result.op));
|
|
1147
1226
|
}
|
|
1227
|
+
if (omittedRanked.length > 0) {
|
|
1228
|
+
sections.push("Operations omitted by the plan limit:\n" + omittedRanked.slice(0, SEARCH_PAGE_SIZE).map((result) => "- " + result.op.tool + ": " + (result.op.summary ?? result.op.httpMethod + " " + result.op.path)).join("\n"));
|
|
1229
|
+
}
|
|
1230
|
+
const coverage = coverageText(source);
|
|
1148
1231
|
if (sections.length === 0) {
|
|
1149
1232
|
return {
|
|
1150
|
-
text: "No matches for: " + query + (source.docsUrl() === null ? " (
|
|
1233
|
+
text: (coverage ? coverage + "\n\n" : "") + "No matches for: " + query + (source.docsUrl() === null && (source.docsIndexUrl?.() ?? null) === null ? " (a docs URL was not provided at generate time; only the API reference was searched)" : ""),
|
|
1151
1234
|
isError: false,
|
|
1152
1235
|
};
|
|
1153
1236
|
}
|
|
1154
|
-
return { text: sections.join("\n\n"), isError: false };
|
|
1237
|
+
return { text: [...(coverage ? [coverage] : []), ...sections].join("\n\n"), isError: false };
|
|
1155
1238
|
}
|
|
1156
1239
|
export async function docsRead(source, page) {
|
|
1157
1240
|
const opMatch = findOperation(source.ops, page);
|
|
1241
|
+
const coverage = coverageText(source);
|
|
1158
1242
|
if (opMatch)
|
|
1159
|
-
return { text: referenceText(opMatch), isError: false };
|
|
1243
|
+
return { text: [...(coverage ? [coverage] : []), referenceText(opMatch)].join("\n\n"), isError: false };
|
|
1244
|
+
const omittedMatch = findOperation(source.omittedOps ?? [], page);
|
|
1245
|
+
if (omittedMatch)
|
|
1246
|
+
return omittedPlanLimit([omittedMatch], omittedMatch.tool);
|
|
1160
1247
|
let target = page;
|
|
1161
1248
|
if (!/^https?:\/\//.test(target)) {
|
|
1162
1249
|
const index = await fetchDocs(source, "llms.txt");
|
|
@@ -1167,11 +1254,11 @@ export async function docsRead(source, page) {
|
|
|
1167
1254
|
}
|
|
1168
1255
|
const text = await fetchDocs(source, target);
|
|
1169
1256
|
if (text === null) {
|
|
1170
|
-
return textError(source.docsUrl() === null
|
|
1171
|
-
? "
|
|
1257
|
+
return textError(source.docsUrl() === null && (source.docsIndexUrl?.() ?? null) === null
|
|
1258
|
+
? "A docs URL was not provided at generate time, and no generated operation matches \"" + page + "\"."
|
|
1172
1259
|
: "Couldn't fetch \"" + page + "\". Use search_docs to find pages.", "NOT_FOUND", ["search_docs finds operations and guide pages."]);
|
|
1173
1260
|
}
|
|
1174
|
-
return { text, isError: false };
|
|
1261
|
+
return { text: [...(coverage ? [coverage] : []), text].join("\n\n"), isError: false };
|
|
1175
1262
|
}
|
|
1176
1263
|
/**
|
|
1177
1264
|
* Dispatch for the shared tools (search_docs, read_docs, execute); returns
|
|
@@ -1193,8 +1280,12 @@ export async function callSharedTool(name, args, source, runOperation) {
|
|
|
1193
1280
|
if (typeof args.operation !== "string")
|
|
1194
1281
|
return argumentsError({ tool: name }, [{ code: "MISSING_ARGUMENT", argument: "operation", message: "execute requires an operation name." }]);
|
|
1195
1282
|
const target = findOperation(source.ops, args.operation);
|
|
1196
|
-
if (!target)
|
|
1197
|
-
|
|
1283
|
+
if (!target) {
|
|
1284
|
+
const omitted = findOperation(source.omittedOps ?? [], args.operation);
|
|
1285
|
+
return omitted
|
|
1286
|
+
? omittedPlanLimit([omitted], omitted.tool)
|
|
1287
|
+
: textError("Unknown operation: " + args.operation + ".", "NOT_FOUND", ["search_docs finds operations by name, path or description."]);
|
|
1288
|
+
}
|
|
1198
1289
|
if (operationSafety(target) === "destructive" && args.confirm !== true) {
|
|
1199
1290
|
return textError("The destructive operation " + target.tool + " requires explicit confirmation.", "CONFIRMATION_REQUIRED", ["Review read_docs " + target.tool + ", then retry execute with confirm: true if the destructive effect is intended."]);
|
|
1200
1291
|
}
|
|
@@ -1205,58 +1296,3 @@ export async function callSharedTool(name, args, source, runOperation) {
|
|
|
1205
1296
|
}
|
|
1206
1297
|
return undefined;
|
|
1207
1298
|
}
|
|
1208
|
-
/** A fetch for docs pages: markdown preferred, same-origin redirects only,
|
|
1209
|
-
* a 10s deadline, and a 2 MB streaming cap. The caller already constrained
|
|
1210
|
-
* the first URL to its configured docs origin; redirects must not escape it. */
|
|
1211
|
-
export const MAX_DOCS_TEXT_BYTES = 2_000_000;
|
|
1212
|
-
export async function fetchDocsText(url) {
|
|
1213
|
-
try {
|
|
1214
|
-
const allowedOrigin = new URL(url).origin;
|
|
1215
|
-
let current = url;
|
|
1216
|
-
const signal = AbortSignal.timeout(10_000);
|
|
1217
|
-
for (let redirects = 0; redirects <= 3; redirects += 1) {
|
|
1218
|
-
const response = await fetch(current, {
|
|
1219
|
-
headers: { Accept: "text/markdown, text/plain, */*" },
|
|
1220
|
-
redirect: "manual",
|
|
1221
|
-
signal,
|
|
1222
|
-
});
|
|
1223
|
-
if (response.status >= 300 && response.status < 400) {
|
|
1224
|
-
const location = response.headers.get("location");
|
|
1225
|
-
if (!location || redirects === 3)
|
|
1226
|
-
return null;
|
|
1227
|
-
const next = new URL(location, current);
|
|
1228
|
-
if (next.origin !== allowedOrigin || next.username || next.password)
|
|
1229
|
-
return null;
|
|
1230
|
-
current = next.toString();
|
|
1231
|
-
continue;
|
|
1232
|
-
}
|
|
1233
|
-
if (!response.ok)
|
|
1234
|
-
return null;
|
|
1235
|
-
const declared = Number(response.headers.get("content-length"));
|
|
1236
|
-
if (Number.isFinite(declared) && declared > MAX_DOCS_TEXT_BYTES)
|
|
1237
|
-
return null;
|
|
1238
|
-
if (!response.body)
|
|
1239
|
-
return "";
|
|
1240
|
-
const reader = response.body.getReader();
|
|
1241
|
-
const decoder = new TextDecoder();
|
|
1242
|
-
let bytes = 0;
|
|
1243
|
-
let text = "";
|
|
1244
|
-
for (;;) {
|
|
1245
|
-
const chunk = await reader.read();
|
|
1246
|
-
if (chunk.done)
|
|
1247
|
-
break;
|
|
1248
|
-
bytes += chunk.value.byteLength;
|
|
1249
|
-
if (bytes > MAX_DOCS_TEXT_BYTES) {
|
|
1250
|
-
await reader.cancel();
|
|
1251
|
-
return null;
|
|
1252
|
-
}
|
|
1253
|
-
text += decoder.decode(chunk.value, { stream: true });
|
|
1254
|
-
}
|
|
1255
|
-
return text + decoder.decode();
|
|
1256
|
-
}
|
|
1257
|
-
return null;
|
|
1258
|
-
}
|
|
1259
|
-
catch {
|
|
1260
|
-
return null;
|
|
1261
|
-
}
|
|
1262
|
-
}
|
package/dist/mcp.js
CHANGED
|
@@ -20,12 +20,13 @@ import { homedir, tmpdir } from "node:os";
|
|
|
20
20
|
import { basename, join } from "node:path";
|
|
21
21
|
import { fileURLToPath } from "node:url";
|
|
22
22
|
import { TypeshipClient, formatDebugEvent } from "./index.js";
|
|
23
|
-
import { GLOBALS, OPS, buildArgs } from "./ops.js";
|
|
24
|
-
import { DEFAULT_MAX_RESULT_CHARS, SUPPORTED_PROTOCOL_VERSIONS, argumentsError, asJsonRpc, binaryOutcome, callSharedTool, checkRequestHeaders, dataOutcome, errorOutcome,
|
|
23
|
+
import { GLOBALS, OMITTED_OPS, OPS, buildArgs } from "./ops.js";
|
|
24
|
+
import { DEFAULT_MAX_RESULT_CHARS, SUPPORTED_PROTOCOL_VERSIONS, argumentsError, asJsonRpc, binaryOutcome, callSharedTool, checkRequestHeaders, dataOutcome, errorOutcome, handleRpc, isRpcOutcome, pageOutcome, parseIncludeList, prepareCall, serverInstructions, takeCancelled, textError, toolDefinitions, visibleOps, } from "./mcp-protocol.js";
|
|
25
|
+
import { fetchDocsText } from "./docs.js";
|
|
25
26
|
const BIN = "typeship";
|
|
26
27
|
const PKG_NAME = "@typeship-ax/mcp";
|
|
27
28
|
const SERVER_NAME = "typeship-mcp";
|
|
28
|
-
const SERVER_VERSION = "0.
|
|
29
|
+
const SERVER_VERSION = "0.8.0";
|
|
29
30
|
/** The MCP client's announced name (clientInfo in request _meta), for the User-Agent. */
|
|
30
31
|
let MCP_CLIENT_NAME = null;
|
|
31
32
|
function noteClientInfo(message) {
|
|
@@ -39,9 +40,9 @@ function noteClientInfo(message) {
|
|
|
39
40
|
const DEFAULT_BASE_URL = "https://typeship.dev/api/v1";
|
|
40
41
|
const AUTH_SCALARS = [{ "option": "bearerToken", "flag": "token", "env": "TYPESHIP_TOKEN" }];
|
|
41
42
|
const BASIC = null;
|
|
42
|
-
const OAUTH_TOKEN_URL = null;
|
|
43
43
|
const ENVIRONMENTS = {};
|
|
44
44
|
const DOCS_URL_DEFAULT = "https://typeship.dev";
|
|
45
|
+
const DOCS_INDEX_URL_DEFAULT = null;
|
|
45
46
|
/** "meta" collapses per-operation tools into search/read/execute so huge
|
|
46
47
|
* APIs don't flood agent context with hundreds of tools. */
|
|
47
48
|
const TOOL_MODE = "meta";
|
|
@@ -78,7 +79,6 @@ function readJson(file) {
|
|
|
78
79
|
function makeClient() {
|
|
79
80
|
const stored = readJson("credentials.json");
|
|
80
81
|
const config = readJson("config.json");
|
|
81
|
-
const options = {};
|
|
82
82
|
const baseUrl = process.env["TYPESHIP_BASE_URL"]
|
|
83
83
|
?? config?.baseUrl
|
|
84
84
|
?? (config?.environment !== undefined ? ENVIRONMENTS[config.environment] : undefined)
|
|
@@ -88,7 +88,7 @@ function makeClient() {
|
|
|
88
88
|
// instead of a server that vanished mid-conversation.
|
|
89
89
|
throw new Error("No base URL configured: set TYPESHIP_BASE_URL in the MCP server's environment, or run '" + BIN + " config set base-url <url>'.");
|
|
90
90
|
}
|
|
91
|
-
options
|
|
91
|
+
const options = { baseUrl };
|
|
92
92
|
for (const a of AUTH_SCALARS) {
|
|
93
93
|
const v = process.env[a.env] ?? stored?.scalars?.[a.option];
|
|
94
94
|
if (v !== undefined)
|
|
@@ -100,17 +100,6 @@ function makeClient() {
|
|
|
100
100
|
if (username !== undefined && password !== undefined)
|
|
101
101
|
options.basicAuth = { username, password };
|
|
102
102
|
}
|
|
103
|
-
const oauthClientId = process.env["TYPESHIP_CLIENT_ID"];
|
|
104
|
-
const oauthClientSecret = process.env["TYPESHIP_CLIENT_SECRET"];
|
|
105
|
-
if ((oauthClientId === undefined) !== (oauthClientSecret === undefined)) {
|
|
106
|
-
throw new Error("OAuth client credentials are incomplete: set both TYPESHIP_CLIENT_ID and TYPESHIP_CLIENT_SECRET in the MCP server's environment.");
|
|
107
|
-
}
|
|
108
|
-
if (oauthClientId !== undefined && oauthClientSecret !== undefined) {
|
|
109
|
-
const tokenUrl = process.env["TYPESHIP_TOKEN_URL"] ?? OAUTH_TOKEN_URL ?? undefined;
|
|
110
|
-
if (!tokenUrl)
|
|
111
|
-
throw new Error("OAuth client credentials need a token URL: set TYPESHIP_TOKEN_URL in the MCP server's environment.");
|
|
112
|
-
options.clientCredentials = { clientId: oauthClientId, clientSecret: oauthClientSecret, tokenUrl };
|
|
113
|
-
}
|
|
114
103
|
if (options.bearerToken === undefined && stored?.oauth?.accessToken !== undefined) {
|
|
115
104
|
options.bearerToken = stored.oauth.accessToken;
|
|
116
105
|
}
|
|
@@ -187,7 +176,7 @@ async function callOperation(op, rawArgs, authHeader) {
|
|
|
187
176
|
return errorOutcome(result.error, errorContext);
|
|
188
177
|
if (op.paginated) {
|
|
189
178
|
const page = result.data;
|
|
190
|
-
return pageOutcome(page.items, page.nextPageParams(), shape);
|
|
179
|
+
return pageOutcome(page.items, page.nextPageParams(), { ...shape, requestId: page.response.requestId });
|
|
191
180
|
}
|
|
192
181
|
// A binary body (the SDK hands back a Blob): an image block, or a file
|
|
193
182
|
// on disk, never "{}".
|
|
@@ -224,7 +213,10 @@ function saveBinary(bytes, _mediaType, suggestedName) {
|
|
|
224
213
|
}
|
|
225
214
|
const docsSource = {
|
|
226
215
|
ops: MCP_OPS,
|
|
216
|
+
omittedOps: OMITTED_OPS,
|
|
217
|
+
generatedOperationCount: OPS.length,
|
|
227
218
|
docsUrl: () => readJson("config.json")?.docsUrl ?? DOCS_URL_DEFAULT,
|
|
219
|
+
docsIndexUrl: () => readJson("config.json")?.docsUrl ? null : DOCS_INDEX_URL_DEFAULT,
|
|
228
220
|
fetchText: fetchDocsText,
|
|
229
221
|
};
|
|
230
222
|
/** The MCP server for one request context (the HTTP transport passes the
|
|
@@ -236,6 +228,8 @@ function serverFor(authHeader) {
|
|
|
236
228
|
instructions: serverInstructions({
|
|
237
229
|
title: "typeship",
|
|
238
230
|
toolCount: MCP_OPS.length,
|
|
231
|
+
generatedOperationCount: OPS.length,
|
|
232
|
+
omittedOps: docsSource.omittedOps,
|
|
239
233
|
mode: TOOL_MODE,
|
|
240
234
|
readOnly: READ_ONLY,
|
|
241
235
|
hiddenWrites: HIDDEN_WRITES,
|
|
@@ -245,7 +239,10 @@ function serverFor(authHeader) {
|
|
|
245
239
|
custom: CUSTOM_INSTRUCTIONS,
|
|
246
240
|
}),
|
|
247
241
|
toolsTtlMs: TOOLS_TTL_MS,
|
|
248
|
-
listTools: () => toolDefinitions(docsSource.ops, TOOL_MODE),
|
|
242
|
+
listTools: () => toolDefinitions(docsSource.ops, TOOL_MODE, docsSource.omittedOps),
|
|
243
|
+
unknownToolMessage: TOOL_MODE === "meta"
|
|
244
|
+
? (name) => "Unknown tool: " + name + ". This server uses compact mode; call search_docs to discover an operation, then call execute with operation: \"" + name + "\"."
|
|
245
|
+
: undefined,
|
|
249
246
|
callTool: async (name, args) => {
|
|
250
247
|
const shared = await callSharedTool(name, args, docsSource, (op, opArgs) => callOperation(op, opArgs, authHeader));
|
|
251
248
|
if (shared !== undefined)
|
package/dist/ops.d.ts
CHANGED
|
@@ -96,6 +96,11 @@ export interface OpSpec {
|
|
|
96
96
|
outputSchema?: Record<string, unknown>;
|
|
97
97
|
}
|
|
98
98
|
export declare const OPS: OpSpec[];
|
|
99
|
+
/** Operations present in the API Definition but omitted by this
|
|
100
|
+
* generation's operation cap. Kept deliberately small: enough for honest
|
|
101
|
+
* discovery and PLAN_LIMIT errors, never enough to call an absent method. */
|
|
102
|
+
export type OmittedOpSpec = Pick<OpSpec, "resource" | "method" | "command" | "commandAlias" | "tool" | "httpMethod" | "path" | "summary" | "description" | "toolDescription" | "paginated" | "select" | "safety" | "auth" | "params" | "inputSchema">;
|
|
103
|
+
export declare const OMITTED_OPS: OmittedOpSpec[];
|
|
99
104
|
/** Parameters settable once on the client (globals option): CLI/MCP fill
|
|
100
105
|
* them from flags or environment; the SDK falls back per request. */
|
|
101
106
|
export declare const GLOBALS: {
|
package/dist/ops.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ops.d.ts","sourceRoot":"","sources":["../src/ops.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"ops.d.ts","sourceRoot":"","sources":["../src/ops.ts"],"names":[],"mappings":"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"}
|