Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion src/mcp.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,21 @@ export function isRemoteTarget(target) {
return /^https?:\/\//i.test(String(target));
}

// Second-level labels that are part of a multi-part public suffix rather than a
// name, as in co.uk / com.au / co.za. Dropping only the TLD would leave these.
const SUFFIX_LABELS = ["co", "com", "net", "org", "gov", "edu", "ac"];

/** Derive a sane server name from a remote URL's host (e.g. mcp.sentry.dev → sentry). */
export function deriveName(target) {
const sanitize = (s) => String(s).toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/^-+|-+$/g, "");
try {
const labels = new URL(target).hostname.split(".").filter(Boolean);
const withoutTld = labels.slice(0, -1); // drop the TLD
let withoutTld = labels.slice(0, -1); // drop the TLD
// ...and the generic label of a multi-part suffix, as long as a real name
// still precedes it (a bare "co.uk" host has nothing better to offer).
if (withoutTld.length > 1 && SUFFIX_LABELS.includes(withoutTld[withoutTld.length - 1])) {
withoutTld = withoutTld.slice(0, -1);
}
const meaningful = withoutTld.filter((l) => !["mcp", "www", "api", "app"].includes(l));
const pick = meaningful[meaningful.length - 1] || withoutTld[withoutTld.length - 1] || labels[0];
return sanitize(pick) || "server";
Expand Down
13 changes: 13 additions & 0 deletions test/mcp.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,19 @@ test("deriveName pulls a sane name from a remote host", () => {
assert.equal(deriveName("not a url"), "server");
});

test("deriveName skips the generic label of a multi-part suffix", () => {
assert.equal(deriveName("https://mcp.acme.co.uk/sse"), "acme");
assert.equal(deriveName("https://api.example.com.au/mcp"), "example");
assert.equal(deriveName("https://widgets.co.za/mcp"), "widgets");
// A .co TLD is still just a TLD, and a bare suffix host keeps its fallback.
assert.equal(deriveName("https://mcp.example.co/sse"), "example");
assert.equal(deriveName("https://co.uk/mcp"), "co");
});

test("deriveName gives distinct multi-part-suffix hosts distinct names", () => {
assert.notEqual(deriveName("https://mcp.acme.co.uk/sse"), deriveName("https://mcp.widgets.co.za/sse"));
});

test("isRemoteTarget distinguishes URLs from commands", () => {
assert.equal(isRemoteTarget("https://x.dev/mcp"), true);
assert.equal(isRemoteTarget("npx"), false);
Expand Down
Loading