Sign In

@toolstop/export-control

Package Overview
Dependencies
Maintainers
1
Versions
5
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@toolstop/export-control - npm Package Compare versions

Comparing version
0.3.1
to
0.4.0
+30
-0
dist/_shared/http.mjs

@@ -243,2 +243,19 @@ // Stateless MCP over HTTP, for Cloudflare Workers.

// --------------------------------------------------------------- maintainers
// Glama verifies a connector claim by matching these against the email on a
// Glama account, so a value that is merely well-formed verifies nothing: it has
// to be the account's own address or the file is served, fetched, and silently
// ignored. There is no error to observe when it is wrong.
//
// Fleet-wide rather than per-server because there is one maintainer, and three
// copies would be three chances to drift. Public by design: it is served from a
// public endpoint and asserts a claim rather than guarding one.
//
// Note the shape. Glama has two schemas and they disagree: `connector.json`,
// used here, wants objects carrying `email`, while the repo-root `server.json`
// wants bare GitHub username strings. Passing one where the other is expected
// validates as neither.
const MAINTAINERS = [{ email: "jhohbein@gmail.com" }];
// ------------------------------------------------------------- fetch handler

@@ -256,2 +273,15 @@

// The one well-known path that gets an answer instead of the 404 below.
// Glama's crawler fetches it to decide who may claim the connector, so
// without it a listing stays unclaimed however well it indexes. Serving it
// is not a courtesy to a crawler; it is the only way to assert ownership of
// a remote server, since the repo-root `glama.json` route covers only
// servers Glama found through GitHub.
if (read && url.pathname === "/.well-known/glama.json") {
return Response.json({
$schema: "https://glama.ai/mcp/schemas/connector.json",
maintainers: MAINTAINERS,
});
}
// A GET on the MCP endpoint is how a client opens the server-initiated SSE

@@ -258,0 +288,0 @@ // stream, and the spec says a server that does not offer one answers 405.

+24
-3

@@ -88,2 +88,3 @@ // Licence-requirement lookup against the Commerce Country Chart.

"export and is controlled separately; see 15 CFR 734.13.",
sourceEdition: SOURCE_EDITION,
};

@@ -158,2 +159,3 @@ }

notCovered: NOT_COVERED,
sourceEdition: SOURCE_EDITION,
};

@@ -181,2 +183,3 @@ }

message: `"${String(eccnRaw ?? "")}" is not an ECCN. An ECCN is a digit, a letter A to E, then three digits, for example 3A001.`,
sourceEdition: SOURCE_EDITION,
};

@@ -191,2 +194,3 @@ }

message: `${eccn} is not in the Commerce Control List edition of ${SOURCE_EDITION}. It may have been removed, or it may never have existed. Do not read this as "no licence required".`,
sourceEdition: SOURCE_EDITION,
};

@@ -206,2 +210,3 @@ }

: `"${String(countryRaw ?? "")}" is not a destination on the Commerce Country Chart.`,
sourceEdition: SOURCE_EDITION,
};

@@ -221,2 +226,3 @@ }

notCovered: NOT_COVERED,
sourceEdition: SOURCE_EDITION,
};

@@ -231,2 +237,3 @@ }

const marks = new Set(row.c);
const checked = [];
const triggered = [];

@@ -236,3 +243,9 @@ const notOnChart = [];

if (column) {
if (marks.has(column)) triggered.push({ reason: column.slice(0, 2), column, scope, reasonName: REASON_CODES[column.slice(0, 2)] ?? null });
const reason = column.slice(0, 2);
const marked = marks.has(column);
// Every chart-determined control is recorded with the cell that was read,
// marked or not. This is what makes a negative answer checkable: see
// `checked` below.
checked.push({ column, reason, reasonName: REASON_CODES[reason] ?? null, scope, marked });
if (marked) triggered.push({ reason, column, scope, reasonName: REASON_CODES[reason] ?? null });
} else {

@@ -250,2 +263,9 @@ notOnChart.push({ scope, requirement: chartText });

triggeredBy: triggered,
// The evidence for the verdict, and the reason this tool reports rather
// than rules. `triggeredBy` justifies a `true`; until this existed a
// `false` arrived as a bare boolean with an empty array beside it, which is
// the answer a caller acts on by shipping and the one they could not check
// without reading the chart themselves. `checked` names every cell that was
// read and what it held, so both verdicts cite the same grid.
checked,
controlsNotOnChart: notOnChart,

@@ -261,5 +281,5 @@ countryColumns: row.c,

const eccn = normalizeEccn(eccnRaw);
if (!eccn) return { status: "invalid_eccn", message: `"${String(eccnRaw ?? "")}" is not a well-formed ECCN.` };
if (!eccn) return { status: "invalid_eccn", message: `"${String(eccnRaw ?? "")}" is not a well-formed ECCN.`, sourceEdition: SOURCE_EDITION };
const e = ECCNS[eccn];
if (!e) return { status: "unknown_eccn", eccn, message: `${eccn} is not in the ${SOURCE_EDITION} Commerce Control List.` };
if (!e) return { status: "unknown_eccn", eccn, message: `${eccn} is not in the ${SOURCE_EDITION} Commerce Control List.`, sourceEdition: SOURCE_EDITION };
if (!e.c.some((c) => c[2])) {

@@ -292,2 +312,3 @@ return {

message: `"${String(countryRaw ?? "")}" did not resolve to exactly one destination on the chart.`,
sourceEdition: SOURCE_EDITION,
};

@@ -294,0 +315,0 @@ }

@@ -36,3 +36,3 @@ // The single source of truth for this server. Both transports import this and

name: "export-control",
version: "0.3.1",
version: "0.4.0",
instructions:

@@ -76,2 +76,12 @@ "Answers one question: does the Commerce Country Chart require an export " +

"licence exceptions that may change the answer in the other direction.\n\n" +
"**Report the citation, not just the verdict.** This server tells you what " +
"the tables say; it is not an authority on what you may do, and the " +
"difference matters because the exporter carries the liability either way. " +
"Every answer returns `checked`, which names each chart cell that was read " +
"and whether it was marked, and `sourceEdition`, which says how current the " +
"tables are. A negative answer is the one a caller acts on by shipping, so " +
"it is the one that most needs its evidence passed on rather than " +
"summarised. Where a row carries `footnotes`, say so: this server does not " +
"apply them, and footnote 6 alone covers the Russia and Belarus " +
"sanctions.\n\n" +
"If a lookup here disagrees with the current regulation, the data is a " +

@@ -99,3 +109,11 @@ "snapshot and the regulation is the authority. Report it at " +

"is an unanswered question rather than a negative answer. This tool " +
"cannot classify an item into an ECCN and will not try.",
"cannot classify an item into an ECCN and will not try.\n\n" +
"Every verdict carries its own evidence and you should report it " +
"rather than the boolean alone. `checked` lists each chart cell that " +
"was read and what it held, so a negative answer can be verified " +
"against 15 CFR part 738 Supplement No. 1 without trusting this " +
"server; `footnotes` carries row conditions this tool does not apply " +
"and which can change the answer; `sourceEdition` says which CFR " +
"edition the tables came from, and a snapshot older than the current " +
"regulation gives a stale answer that still reads as confident.",
annotations: { readOnlyHint: true, openWorldHint: false },

@@ -136,2 +154,12 @@ inputSchema: {

},
checked: {
type: "array",
description:
"Every chart-determined control on the entry, each with the column read, its reason code, " +
"the scope it applies to, and whether that column is marked for this destination. This is " +
"the citation for the verdict and it is the only way to check a `licenseRequired: false`, " +
"which otherwise arrives as a bare boolean. Verify it against 15 CFR part 738 Supplement " +
"No. 1 before relying on a negative answer.",
items: { type: "object" },
},
controlsNotOnChart: {

@@ -142,2 +170,20 @@ type: "array",

},
countryColumns: {
type: "array",
description: "Every control column marked for this destination on the chart row, whether or not it bears on this ECCN.",
items: { type: "string" },
},
footnotes: {
type: "array",
description:
"Footnotes on this chart row, each with its number and text. **They can change the answer " +
"and this tool does not apply them.** Footnote 6 is the Russia and Belarus sanctions and " +
"footnote 8 is Crimea. A `licenseRequired: false` on a row carrying footnotes is not a " +
"clear result until the footnote text has been read.",
items: { type: "object" },
},
sourceEdition: {
type: "string",
description: "The CFR edition the tables were taken from. Present on every response, including errors. Data older than the current regulation is a stale answer, not a wrong one, and the regulation is the authority.",
},
candidates: {

@@ -153,6 +199,6 @@ type: "array",

},
title: { type: "string", description: "The Control List entry heading, on an indeterminate result." },
title: { type: "string", description: "The Control List entry heading." },
message: { type: "string", description: "Why no verdict was returned, when status is not `ok`." },
},
required: ["status"],
required: ["status", "sourceEdition"],
},

@@ -159,0 +205,0 @@ examples: [

+1
-1
{
"name": "@toolstop/export-control",
"version": "0.3.1",
"version": "0.4.0",
"mcpName": "dev.toolstop/export-control",

@@ -5,0 +5,0 @@ "description": "MCP server that answers whether the US Commerce Country Chart requires an export licence for a given ECCN to a given destination, from the published CFR tables.",