@topolo/mcp 0.13.1 → 0.13.3
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.js +73 -32
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// src/index.ts
|
|
4
4
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
5
5
|
|
|
6
|
-
// node_modules/.pnpm/@topolo+sdk@0.21.
|
|
6
|
+
// node_modules/.pnpm/@topolo+sdk@0.21.2/node_modules/@topolo/sdk/dist/index.js
|
|
7
7
|
function applyAuthHeaders(headers, credential) {
|
|
8
8
|
if (credential.kind === "api_key") {
|
|
9
9
|
headers.set("X-Api-Key", credential.apiKey);
|
|
@@ -3254,7 +3254,7 @@ function createTopolo(options) {
|
|
|
3254
3254
|
};
|
|
3255
3255
|
}
|
|
3256
3256
|
|
|
3257
|
-
// node_modules/.pnpm/@topolo+sdk@0.21.
|
|
3257
|
+
// node_modules/.pnpm/@topolo+sdk@0.21.2/node_modules/@topolo/sdk/dist/node/credential-store.js
|
|
3258
3258
|
import { mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2, chmod as chmod2, rm as rm2, stat } from "fs/promises";
|
|
3259
3259
|
import { existsSync as existsSync2 } from "fs";
|
|
3260
3260
|
import { homedir as homedir2, platform } from "os";
|
|
@@ -3671,6 +3671,8 @@ function topoloServiceOrigins2(serviceUrls, environment) {
|
|
|
3671
3671
|
);
|
|
3672
3672
|
}
|
|
3673
3673
|
var KEYCHAIN_SERVICE = "topolo-external-agent-installation";
|
|
3674
|
+
var MACOS_KEYCHAIN_CHUNK_SIZE = 96;
|
|
3675
|
+
var MACOS_KEYCHAIN_CHUNK_PREFIX = "topolo-keychain-chunks:v1:";
|
|
3674
3676
|
var MACOS_KEYCHAIN_WRITE_SCRIPT = [
|
|
3675
3677
|
"log_user 0",
|
|
3676
3678
|
"set timeout 10",
|
|
@@ -3711,40 +3713,73 @@ function createPlatformInstallationSecretBackend(options = {}) {
|
|
|
3711
3713
|
const spawn = options.spawn ?? ((command, args, spawnOptions) => spawnSync(command, args, spawnOptions));
|
|
3712
3714
|
const root = options.root ?? installationStorePath();
|
|
3713
3715
|
if (platform2 === "darwin") {
|
|
3716
|
+
const write = (account, value) => runOrThrow(spawn("/usr/bin/expect", ["-c", MACOS_KEYCHAIN_WRITE_SCRIPT], {
|
|
3717
|
+
input: `${value}
|
|
3718
|
+
`,
|
|
3719
|
+
encoding: "utf8",
|
|
3720
|
+
env: {
|
|
3721
|
+
...process.env,
|
|
3722
|
+
TOPOLO_KEYCHAIN_ACCOUNT: account,
|
|
3723
|
+
TOPOLO_KEYCHAIN_SERVICE: KEYCHAIN_SERVICE
|
|
3724
|
+
}
|
|
3725
|
+
}), "macOS Keychain write");
|
|
3726
|
+
const read = (account) => {
|
|
3727
|
+
const result = spawn("security", [
|
|
3728
|
+
"find-generic-password",
|
|
3729
|
+
"-a",
|
|
3730
|
+
account,
|
|
3731
|
+
"-s",
|
|
3732
|
+
KEYCHAIN_SERVICE,
|
|
3733
|
+
"-w"
|
|
3734
|
+
], { encoding: "utf8" });
|
|
3735
|
+
if (result.status === 44) return null;
|
|
3736
|
+
return runOrThrow(result, "macOS Keychain read");
|
|
3737
|
+
};
|
|
3738
|
+
const remove = (account) => {
|
|
3739
|
+
const result = spawn("security", [
|
|
3740
|
+
"delete-generic-password",
|
|
3741
|
+
"-a",
|
|
3742
|
+
account,
|
|
3743
|
+
"-s",
|
|
3744
|
+
KEYCHAIN_SERVICE
|
|
3745
|
+
], { encoding: "utf8" });
|
|
3746
|
+
if (result.status !== 44) runOrThrow(result, "macOS Keychain delete");
|
|
3747
|
+
};
|
|
3748
|
+
const chunkAccount = (account, index) => `${account}:chunk:${index}`;
|
|
3749
|
+
const chunkCount = (value) => {
|
|
3750
|
+
if (!value?.startsWith(MACOS_KEYCHAIN_CHUNK_PREFIX)) return 0;
|
|
3751
|
+
const count = Number(value.slice(MACOS_KEYCHAIN_CHUNK_PREFIX.length));
|
|
3752
|
+
if (!Number.isSafeInteger(count) || count < 1) throw new Error("macOS Keychain chunk manifest is invalid.");
|
|
3753
|
+
return count;
|
|
3754
|
+
};
|
|
3714
3755
|
return {
|
|
3715
3756
|
async set(account, value) {
|
|
3716
|
-
|
|
3717
|
-
|
|
3718
|
-
|
|
3719
|
-
|
|
3720
|
-
|
|
3721
|
-
|
|
3722
|
-
|
|
3723
|
-
|
|
3724
|
-
|
|
3725
|
-
}
|
|
3757
|
+
const previousCount = chunkCount(read(account));
|
|
3758
|
+
const chunks = Array.from(
|
|
3759
|
+
{ length: Math.max(1, Math.ceil(value.length / MACOS_KEYCHAIN_CHUNK_SIZE)) },
|
|
3760
|
+
(_, index) => value.slice(index * MACOS_KEYCHAIN_CHUNK_SIZE, (index + 1) * MACOS_KEYCHAIN_CHUNK_SIZE)
|
|
3761
|
+
);
|
|
3762
|
+
try {
|
|
3763
|
+
chunks.forEach((chunk, index) => write(chunkAccount(account, index), chunk));
|
|
3764
|
+
write(account, `${MACOS_KEYCHAIN_CHUNK_PREFIX}${chunks.length}`);
|
|
3765
|
+
for (let index = chunks.length; index < previousCount; index += 1) remove(chunkAccount(account, index));
|
|
3766
|
+
} catch (error) {
|
|
3767
|
+
chunks.forEach((_, index) => remove(chunkAccount(account, index)));
|
|
3768
|
+
throw error;
|
|
3769
|
+
}
|
|
3726
3770
|
},
|
|
3727
3771
|
async get(account) {
|
|
3728
|
-
const
|
|
3729
|
-
|
|
3730
|
-
|
|
3731
|
-
|
|
3732
|
-
|
|
3733
|
-
|
|
3734
|
-
"-w"
|
|
3735
|
-
], { encoding: "utf8" });
|
|
3736
|
-
if (result.status === 44) return null;
|
|
3737
|
-
return runOrThrow(result, "macOS Keychain read");
|
|
3772
|
+
const manifest = read(account);
|
|
3773
|
+
const count = chunkCount(manifest);
|
|
3774
|
+
if (!count) return manifest;
|
|
3775
|
+
const chunks = Array.from({ length: count }, (_, index) => read(chunkAccount(account, index)));
|
|
3776
|
+
if (chunks.some((chunk) => chunk === null)) throw new Error("macOS Keychain installation secret is incomplete.");
|
|
3777
|
+
return chunks.join("");
|
|
3738
3778
|
},
|
|
3739
3779
|
async delete(account) {
|
|
3740
|
-
const
|
|
3741
|
-
|
|
3742
|
-
|
|
3743
|
-
account,
|
|
3744
|
-
"-s",
|
|
3745
|
-
KEYCHAIN_SERVICE
|
|
3746
|
-
], { encoding: "utf8" });
|
|
3747
|
-
if (result.status !== 44) runOrThrow(result, "macOS Keychain delete");
|
|
3780
|
+
const count = chunkCount(read(account));
|
|
3781
|
+
for (let index = 0; index < count; index += 1) remove(chunkAccount(account, index));
|
|
3782
|
+
remove(account);
|
|
3748
3783
|
}
|
|
3749
3784
|
};
|
|
3750
3785
|
}
|
|
@@ -4933,6 +4968,10 @@ function audienceFor(context) {
|
|
|
4933
4968
|
}
|
|
4934
4969
|
return `app_topolo_${service.replace(/-/g, "_")}`;
|
|
4935
4970
|
}
|
|
4971
|
+
function scopeFor(context, audience) {
|
|
4972
|
+
if (context.service === "auth" && context.path === "/api/auth/me") return "app_topolo_auth:identity";
|
|
4973
|
+
return `${audience}:actions:execute`;
|
|
4974
|
+
}
|
|
4936
4975
|
function responseData(value) {
|
|
4937
4976
|
if (!value || typeof value !== "object") return {};
|
|
4938
4977
|
const record2 = value;
|
|
@@ -4950,22 +4989,24 @@ async function resolveExternalAgentInstallationCredential(environment, installat
|
|
|
4950
4989
|
const fetchImpl = options.fetch ?? fetch;
|
|
4951
4990
|
const now = options.now ?? Date.now;
|
|
4952
4991
|
const authBaseUrl = resolveServiceUrl("auth", options.serviceUrls);
|
|
4953
|
-
const tokenUrl = new URL("/
|
|
4992
|
+
const tokenUrl = new URL("/oauth/token", authBaseUrl).toString();
|
|
4954
4993
|
const cache = /* @__PURE__ */ new Map();
|
|
4955
4994
|
const credentialProvider = async (context) => {
|
|
4956
4995
|
const audience = audienceFor(context);
|
|
4996
|
+
const scope = scopeFor(context, audience);
|
|
4957
4997
|
const resource = context.resource ?? {
|
|
4958
4998
|
resourceType: "organization",
|
|
4959
4999
|
resourceId: stored.installation.organizationId
|
|
4960
5000
|
};
|
|
4961
5001
|
const boundTaskId = context.taskId?.trim() || taskId;
|
|
4962
|
-
const key = JSON.stringify({ audience, taskId: boundTaskId, resource });
|
|
5002
|
+
const key = JSON.stringify({ audience, scope, taskId: boundTaskId, resource });
|
|
4963
5003
|
const cached = cache.get(key);
|
|
4964
5004
|
if (cached && cached.expiresAt - 15e3 > now()) return cached.credential;
|
|
4965
5005
|
const body = new URLSearchParams({
|
|
4966
5006
|
grant_type: "client_credentials",
|
|
4967
5007
|
client_id: stored.installation.clientId,
|
|
4968
5008
|
client_secret: stored.secret.clientSecret,
|
|
5009
|
+
scope,
|
|
4969
5010
|
audience,
|
|
4970
5011
|
task_id: boundTaskId,
|
|
4971
5012
|
resource_type: resource.resourceType,
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@topolo/mcp",
|
|
3
3
|
"packageManager": "pnpm@10.17.1",
|
|
4
|
-
"version": "0.13.
|
|
5
|
-
"topoloPublishedVersion": "0.13.
|
|
4
|
+
"version": "0.13.3",
|
|
5
|
+
"topoloPublishedVersion": "0.13.3",
|
|
6
6
|
"description": "Model Context Protocol server for the Topolo platform. Exposes scope-gated tools that third-party agents (Claude, Codex, etc.) can call natively.",
|
|
7
7
|
"license": "UNLICENSED",
|
|
8
8
|
"author": "Topolo",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
39
|
-
"@topolo/sdk": "0.21.
|
|
39
|
+
"@topolo/sdk": "0.21.2"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@types/node": "^20.12.0",
|