@datacules/agent-identity-mcp-client 0.11.0 → 0.11.1

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.
@@ -0,0 +1,148 @@
1
+ /**
2
+ * McpCredentialStore — CredentialStore implementation that fetches
3
+ * credentials from an external MCP server.
4
+ *
5
+ * Implements the full CredentialStore interface from @datacules/agent-identity
6
+ * so it can be dropped into any CredentialRouter without any other changes:
7
+ *
8
+ * import { McpCredentialStore } from '@datacules/agent-identity-mcp-client';
9
+ * import { createRouterFromStore } from '@datacules/agent-identity';
10
+ *
11
+ * const store = new McpCredentialStore({
12
+ * serverUrl: 'http://localhost:3002',
13
+ * authToken: process.env.MCP_AUTH_TOKEN,
14
+ * });
15
+ * const router = createRouterFromStore(store, rules, logger);
16
+ *
17
+ * The MCP server this client connects to MUST expose a `list_credentials`
18
+ * tool (i.e. another @datacules/agent-identity-mcp instance, a Vault MCP
19
+ * server, a 1Password MCP server, or any custom server following the same
20
+ * tool contract).
21
+ *
22
+ * Transport:
23
+ * - For a remote HTTP+SSE server: provide serverUrl
24
+ * - For an in-process stdio server (test / monorepo): provide serverProcess
25
+ */
26
+ import { Client } from '@modelcontextprotocol/sdk/client/index.js';
27
+ import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js';
28
+ import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
29
+ // ─── McpCredentialStore ─────────────────────────────────────────────────────────
30
+ /**
31
+ * CredentialStore implementation that pulls credentials from an external
32
+ * MCP server by calling its `list_credentials` tool.
33
+ *
34
+ * Credentials are cached in-memory for `cacheTtlMs` (default 60s) to avoid
35
+ * a round-trip on every router.resolve() call. Call invalidateCache() to
36
+ * force a fresh fetch on the next operation.
37
+ *
38
+ * The MCP client connection is lazy — the first store operation connects
39
+ * and caches the connection. Call disconnect() when the store is no longer
40
+ * needed (e.g. on process shutdown).
41
+ */
42
+ export class McpCredentialStore {
43
+ constructor(options) {
44
+ this.client = null;
45
+ this.cache = null;
46
+ this.connectPromise = null;
47
+ this.options = options;
48
+ this.cacheTtlMs = options.cacheTtlMs ?? 60000;
49
+ }
50
+ // ── Public CredentialStore interface ────────────────────────────────────────
51
+ async findByRef(ref) {
52
+ const all = await this.listActive();
53
+ return all.find((c) => c.ref === ref && c.status === 'active') ?? null;
54
+ }
55
+ async listActive() {
56
+ const cached = this.getFromCache();
57
+ if (cached)
58
+ return cached.filter((c) => c.status === 'active');
59
+ const fresh = await this.fetchFromServer();
60
+ return fresh.filter((c) => c.status === 'active');
61
+ }
62
+ async listByKind(kind) {
63
+ const all = await this.listActive();
64
+ return all.filter((c) => c.kind === kind);
65
+ }
66
+ // ── Cache management ──────────────────────────────────────────────────────
67
+ /** Force the next store operation to fetch fresh credentials from the server */
68
+ invalidateCache() {
69
+ this.cache = null;
70
+ }
71
+ getFromCache() {
72
+ if (!this.cache)
73
+ return null;
74
+ if (Date.now() > this.cache.expiresAt) {
75
+ this.cache = null;
76
+ return null;
77
+ }
78
+ return this.cache.credentials;
79
+ }
80
+ setCache(credentials) {
81
+ this.cache = { credentials, expiresAt: Date.now() + this.cacheTtlMs };
82
+ }
83
+ // ── MCP client lifecycle ─────────────────────────────────────────────────
84
+ async ensureConnected() {
85
+ if (this.client)
86
+ return;
87
+ // Serialize concurrent callers so we only connect once
88
+ if (!this.connectPromise)
89
+ this.connectPromise = this._connect();
90
+ await this.connectPromise;
91
+ this.connectPromise = null;
92
+ }
93
+ async _connect() {
94
+ const opts = this.options;
95
+ const clientName = opts.clientName ?? 'agent-identity-mcp-client';
96
+ const clientVersion = opts.clientVersion ?? '0.1.0';
97
+ this.client = new Client({ name: clientName, version: clientVersion }, { capabilities: {} });
98
+ if (opts.transport === 'http') {
99
+ const sseUrl = new URL('/sse', opts.serverUrl);
100
+ const headers = {};
101
+ if (opts.authToken)
102
+ headers['Authorization'] = `Bearer ${opts.authToken}`;
103
+ const transport = new SSEClientTransport(sseUrl, { requestInit: { headers } });
104
+ await this.client.connect(transport);
105
+ }
106
+ else {
107
+ const transport = new StdioClientTransport({
108
+ command: opts.command,
109
+ args: opts.args ?? [],
110
+ env: opts.env,
111
+ });
112
+ await this.client.connect(transport);
113
+ }
114
+ }
115
+ /** Disconnect the MCP client and clear the cache. Call on process shutdown. */
116
+ async disconnect() {
117
+ this.invalidateCache();
118
+ if (this.client) {
119
+ await this.client.close();
120
+ this.client = null;
121
+ }
122
+ }
123
+ // ── Remote fetch ───────────────────────────────────────────────────────────
124
+ async fetchFromServer() {
125
+ await this.ensureConnected();
126
+ const result = await this.client.callTool({
127
+ name: 'list_credentials',
128
+ arguments: {},
129
+ });
130
+ const text = result.content
131
+ .filter((c) => c.type === 'text')
132
+ .map((c) => c.text)
133
+ .join('');
134
+ let parsed;
135
+ try {
136
+ parsed = JSON.parse(text);
137
+ }
138
+ catch {
139
+ throw new Error(`[McpCredentialStore] MCP server returned non-JSON response from list_credentials: ${text.slice(0, 200)}`);
140
+ }
141
+ if (!Array.isArray(parsed.credentials)) {
142
+ throw new Error('[McpCredentialStore] MCP server list_credentials response missing credentials array');
143
+ }
144
+ this.setCache(parsed.credentials);
145
+ return parsed.credentials;
146
+ }
147
+ }
148
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * McpToolCaller — utility for calling arbitrary tools on a connected
3
+ * agent-identity MCP server from application code.
4
+ *
5
+ * While McpCredentialStore handles the CredentialStore contract,
6
+ * McpToolCaller lets you call any tool (resolve_credential,
7
+ * resolve_migration_credential, health, etc.) directly — useful
8
+ * when you want the MCP server to perform the resolution and return
9
+ * the result without going through a local CredentialRouter.
10
+ *
11
+ * Example:
12
+ * const caller = new McpToolCaller({ transport: 'http', serverUrl: 'http://localhost:3002' });
13
+ * const result = await caller.resolveCredential({ userId: 'u1', ... });
14
+ * await caller.disconnect();
15
+ */
16
+ import type { McpCredentialStoreOptions } from './store.js';
17
+ export type McpToolCallerOptions = McpCredentialStoreOptions;
18
+ export interface ResolvedCredentialResult {
19
+ ok: boolean;
20
+ credentialId: string;
21
+ kind: 'fixed' | 'user-delegated';
22
+ resolvedFor: string;
23
+ }
24
+ export interface ResolvedMigrationResult {
25
+ ok: boolean;
26
+ migrationId: string;
27
+ source: ResolvedCredentialResult;
28
+ target: ResolvedCredentialResult;
29
+ expiresAt: string | null;
30
+ }
31
+ export interface HealthResult {
32
+ status: 'ok' | 'error';
33
+ credentialsLoaded: number;
34
+ rulesLoaded: number;
35
+ timestamp: string;
36
+ }
37
+ /**
38
+ * Thin wrapper around the MCP SDK Client for calling agent-identity
39
+ * MCP tools directly. Connection is lazy and cached after first call.
40
+ */
41
+ export declare class McpToolCaller {
42
+ private client;
43
+ private connectPromise;
44
+ private readonly options;
45
+ constructor(options: McpToolCallerOptions);
46
+ /** Resolve a credential via the remote MCP server */
47
+ resolveCredential(ctx: Record<string, unknown>): Promise<ResolvedCredentialResult>;
48
+ /** Resolve a migration credential pair via the remote MCP server */
49
+ resolveMigrationCredential(ctx: Record<string, unknown>): Promise<ResolvedMigrationResult>;
50
+ /** Check the health of the remote agent-identity MCP server */
51
+ health(): Promise<HealthResult>;
52
+ callTool<T = unknown>(toolName: string, args: Record<string, unknown>): Promise<T>;
53
+ /** Disconnect from the remote MCP server */
54
+ disconnect(): Promise<void>;
55
+ private ensureConnected;
56
+ private _connect;
57
+ }
58
+ //# sourceMappingURL=caller.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"caller.d.ts","sourceRoot":"","sources":["../../src/caller.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAKH,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,YAAY,CAAC;AAE5D,MAAM,MAAM,oBAAoB,GAAG,yBAAyB,CAAC;AAE7D,MAAM,WAAW,wBAAwB;IACvC,EAAE,EAAE,OAAO,CAAC;IACZ,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,OAAO,GAAG,gBAAgB,CAAC;IACjC,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,uBAAuB;IACtC,EAAE,EAAE,OAAO,CAAC;IACZ,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,wBAAwB,CAAC;IACjC,MAAM,EAAE,wBAAwB,CAAC;IACjC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,IAAI,GAAG,OAAO,CAAC;IACvB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;GAGG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,cAAc,CAA8B;IACpD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAuB;gBAEnC,OAAO,EAAE,oBAAoB;IAMzC,qDAAqD;IAC/C,iBAAiB,CACrB,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC3B,OAAO,CAAC,wBAAwB,CAAC;IAIpC,oEAAoE;IAC9D,0BAA0B,CAC9B,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC3B,OAAO,CAAC,uBAAuB,CAAC;IAInC,+DAA+D;IACzD,MAAM,IAAI,OAAO,CAAC,YAAY,CAAC;IAM/B,QAAQ,CAAC,CAAC,GAAG,OAAO,EACxB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,OAAO,CAAC,CAAC,CAAC;IA0Bb,4CAA4C;IACtC,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;YASnB,eAAe;YAOf,QAAQ;CAsBvB"}
@@ -42,8 +42,8 @@
42
42
  * const result = await caller.resolveCredential({ userId: 'u1', ... });
43
43
  * await caller.disconnect();
44
44
  */
45
-
46
45
  export { McpCredentialStore } from './store.js';
47
46
  export type { McpCredentialStoreOptions, McpCredentialStoreHttpOptions, McpCredentialStoreStdioOptions } from './store.js';
48
47
  export { McpToolCaller } from './caller.js';
49
48
  export type { McpToolCallerOptions, ResolvedCredentialResult, ResolvedMigrationResult, HealthResult } from './caller.js';
49
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAChD,YAAY,EAAE,yBAAyB,EAAE,6BAA6B,EAAE,8BAA8B,EAAE,MAAM,YAAY,CAAC;AAC3H,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,YAAY,EAAE,oBAAoB,EAAE,wBAAwB,EAAE,uBAAuB,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,89 @@
1
+ /**
2
+ * McpCredentialStore — CredentialStore implementation that fetches
3
+ * credentials from an external MCP server.
4
+ *
5
+ * Implements the full CredentialStore interface from @datacules/agent-identity
6
+ * so it can be dropped into any CredentialRouter without any other changes:
7
+ *
8
+ * import { McpCredentialStore } from '@datacules/agent-identity-mcp-client';
9
+ * import { createRouterFromStore } from '@datacules/agent-identity';
10
+ *
11
+ * const store = new McpCredentialStore({
12
+ * serverUrl: 'http://localhost:3002',
13
+ * authToken: process.env.MCP_AUTH_TOKEN,
14
+ * });
15
+ * const router = createRouterFromStore(store, rules, logger);
16
+ *
17
+ * The MCP server this client connects to MUST expose a `list_credentials`
18
+ * tool (i.e. another @datacules/agent-identity-mcp instance, a Vault MCP
19
+ * server, a 1Password MCP server, or any custom server following the same
20
+ * tool contract).
21
+ *
22
+ * Transport:
23
+ * - For a remote HTTP+SSE server: provide serverUrl
24
+ * - For an in-process stdio server (test / monorepo): provide serverProcess
25
+ */
26
+ import type { Credential, CredentialStore } from '@datacules/agent-identity';
27
+ export interface McpCredentialStoreHttpOptions {
28
+ transport: 'http';
29
+ /**
30
+ * Base URL of the remote agent-identity MCP server.
31
+ * The SSE endpoint is expected at GET <serverUrl>/sse
32
+ * and messages at POST <serverUrl>/messages.
33
+ */
34
+ serverUrl: string;
35
+ /** Bearer token if the remote server requires auth */
36
+ authToken?: string;
37
+ /** Client name sent during MCP handshake (default: 'agent-identity-mcp-client') */
38
+ clientName?: string;
39
+ /** Client version (default: '0.1.0') */
40
+ clientVersion?: string;
41
+ /** TTL of the in-memory credential cache in ms (default: 60_000) */
42
+ cacheTtlMs?: number;
43
+ }
44
+ export interface McpCredentialStoreStdioOptions {
45
+ transport: 'stdio';
46
+ /** Command to spawn the MCP server process */
47
+ command: string;
48
+ /** Arguments passed to the spawned process */
49
+ args?: string[];
50
+ /** Environment variables for the spawned process */
51
+ env?: Record<string, string>;
52
+ clientName?: string;
53
+ clientVersion?: string;
54
+ cacheTtlMs?: number;
55
+ }
56
+ export type McpCredentialStoreOptions = McpCredentialStoreHttpOptions | McpCredentialStoreStdioOptions;
57
+ /**
58
+ * CredentialStore implementation that pulls credentials from an external
59
+ * MCP server by calling its `list_credentials` tool.
60
+ *
61
+ * Credentials are cached in-memory for `cacheTtlMs` (default 60s) to avoid
62
+ * a round-trip on every router.resolve() call. Call invalidateCache() to
63
+ * force a fresh fetch on the next operation.
64
+ *
65
+ * The MCP client connection is lazy — the first store operation connects
66
+ * and caches the connection. Call disconnect() when the store is no longer
67
+ * needed (e.g. on process shutdown).
68
+ */
69
+ export declare class McpCredentialStore implements CredentialStore {
70
+ private client;
71
+ private cache;
72
+ private readonly cacheTtlMs;
73
+ private readonly options;
74
+ private connectPromise;
75
+ constructor(options: McpCredentialStoreOptions);
76
+ findByRef(ref: string): Promise<Credential | null>;
77
+ listActive(): Promise<Credential[]>;
78
+ listByKind(kind: Credential['kind']): Promise<Credential[]>;
79
+ /** Force the next store operation to fetch fresh credentials from the server */
80
+ invalidateCache(): void;
81
+ private getFromCache;
82
+ private setCache;
83
+ private ensureConnected;
84
+ private _connect;
85
+ /** Disconnect the MCP client and clear the cache. Call on process shutdown. */
86
+ disconnect(): Promise<void>;
87
+ private fetchFromServer;
88
+ }
89
+ //# sourceMappingURL=store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAKH,OAAO,KAAK,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAI7E,MAAM,WAAW,6BAA6B;IAC5C,SAAS,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,SAAS,EAAE,MAAM,CAAC;IAClB,sDAAsD;IACtD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mFAAmF;IACnF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,wCAAwC;IACxC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,oEAAoE;IACpE,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,8BAA8B;IAC7C,SAAS,EAAE,OAAO,CAAC;IACnB,8CAA8C;IAC9C,OAAO,EAAE,MAAM,CAAC;IAChB,8CAA8C;IAC9C,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,oDAAoD;IACpD,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,MAAM,yBAAyB,GACjC,6BAA6B,GAC7B,8BAA8B,CAAC;AAWnC;;;;;;;;;;;GAWG;AACH,qBAAa,kBAAmB,YAAW,eAAe;IACxD,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,KAAK,CAA2B;IACxC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA4B;IACpD,OAAO,CAAC,cAAc,CAA8B;gBAExC,OAAO,EAAE,yBAAyB;IAOxC,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IAKlD,UAAU,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;IAOnC,UAAU,CAAC,IAAI,EAAE,UAAU,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;IAOjE,gFAAgF;IAChF,eAAe,IAAI,IAAI;IAIvB,OAAO,CAAC,YAAY;IAMpB,OAAO,CAAC,QAAQ;YAMF,eAAe;YAQf,QAAQ;IA2BtB,+EAA+E;IACzE,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;YAUnB,eAAe;CA+B9B"}
package/package.json CHANGED
@@ -1,17 +1,36 @@
1
1
  {
2
2
  "name": "@datacules/agent-identity-mcp-client",
3
- "version": "0.11.0",
3
+ "version": "0.11.1",
4
4
  "private": false,
5
5
  "description": "MCP client adapter for @datacules/agent-identity — consume external MCP servers as CredentialStores",
6
+ "author": "Datacules LLC",
7
+ "license": "SEE LICENSE IN LICENSE",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "https://github.com/hvrcharon1/agent-identity.git",
11
+ "directory": "packages/integrations/mcp-client"
12
+ },
6
13
  "main": "./dist/cjs/index.js",
7
14
  "module": "./dist/esm/index.js",
8
15
  "types": "./dist/types/index.d.ts",
16
+ "exports": {
17
+ ".": {
18
+ "import": "./dist/esm/index.js",
19
+ "require": "./dist/cjs/index.js",
20
+ "types": "./dist/types/index.d.ts"
21
+ }
22
+ },
23
+ "files": [
24
+ "dist",
25
+ "LICENSE",
26
+ "README.md"
27
+ ],
9
28
  "scripts": {
10
- "build": "tsc -p tsconfig.build.json",
29
+ "build": "tsc -p tsconfig.build.json && tsc -p tsconfig.cjs.json",
11
30
  "type-check": "tsc --noEmit"
12
31
  },
13
32
  "peerDependencies": {
14
- "@datacules/agent-identity": "^0.6.0"
33
+ "@datacules/agent-identity": "^0.11.1"
15
34
  },
16
35
  "dependencies": {
17
36
  "@modelcontextprotocol/sdk": "^1.10.0"
package/src/caller.ts DELETED
@@ -1,150 +0,0 @@
1
- /**
2
- * McpToolCaller — utility for calling arbitrary tools on a connected
3
- * agent-identity MCP server from application code.
4
- *
5
- * While McpCredentialStore handles the CredentialStore contract,
6
- * McpToolCaller lets you call any tool (resolve_credential,
7
- * resolve_migration_credential, health, etc.) directly — useful
8
- * when you want the MCP server to perform the resolution and return
9
- * the result without going through a local CredentialRouter.
10
- *
11
- * Example:
12
- * const caller = new McpToolCaller({ transport: 'http', serverUrl: 'http://localhost:3002' });
13
- * const result = await caller.resolveCredential({ userId: 'u1', ... });
14
- * await caller.disconnect();
15
- */
16
-
17
- import { Client } from '@modelcontextprotocol/sdk/client/index.js';
18
- import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js';
19
- import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
20
- import type { McpCredentialStoreOptions } from './store.js';
21
-
22
- export type McpToolCallerOptions = McpCredentialStoreOptions;
23
-
24
- export interface ResolvedCredentialResult {
25
- ok: boolean;
26
- credentialId: string;
27
- kind: 'fixed' | 'user-delegated';
28
- resolvedFor: string;
29
- }
30
-
31
- export interface ResolvedMigrationResult {
32
- ok: boolean;
33
- migrationId: string;
34
- source: ResolvedCredentialResult;
35
- target: ResolvedCredentialResult;
36
- expiresAt: string | null;
37
- }
38
-
39
- export interface HealthResult {
40
- status: 'ok' | 'error';
41
- credentialsLoaded: number;
42
- rulesLoaded: number;
43
- timestamp: string;
44
- }
45
-
46
- /**
47
- * Thin wrapper around the MCP SDK Client for calling agent-identity
48
- * MCP tools directly. Connection is lazy and cached after first call.
49
- */
50
- export class McpToolCaller {
51
- private client: Client | null = null;
52
- private connectPromise: Promise<void> | null = null;
53
- private readonly options: McpToolCallerOptions;
54
-
55
- constructor(options: McpToolCallerOptions) {
56
- this.options = options;
57
- }
58
-
59
- // ── High-level helpers ─────────────────────────────────────────────────────
60
-
61
- /** Resolve a credential via the remote MCP server */
62
- async resolveCredential(
63
- ctx: Record<string, unknown>
64
- ): Promise<ResolvedCredentialResult> {
65
- return this.callTool<ResolvedCredentialResult>('resolve_credential', ctx);
66
- }
67
-
68
- /** Resolve a migration credential pair via the remote MCP server */
69
- async resolveMigrationCredential(
70
- ctx: Record<string, unknown>
71
- ): Promise<ResolvedMigrationResult> {
72
- return this.callTool<ResolvedMigrationResult>('resolve_migration_credential', ctx);
73
- }
74
-
75
- /** Check the health of the remote agent-identity MCP server */
76
- async health(): Promise<HealthResult> {
77
- return this.callTool<HealthResult>('health', {});
78
- }
79
-
80
- // ── Generic tool call ────────────────────────────────────────────────────────
81
-
82
- async callTool<T = unknown>(
83
- toolName: string,
84
- args: Record<string, unknown>
85
- ): Promise<T> {
86
- await this.ensureConnected();
87
-
88
- const result = await this.client!.callTool({ name: toolName, arguments: args });
89
-
90
- const text = (result.content as Array<{ type: string; text: string }>)
91
- .filter((c) => c.type === 'text')
92
- .map((c) => c.text)
93
- .join('');
94
-
95
- let parsed: T;
96
- try {
97
- parsed = JSON.parse(text) as T;
98
- } catch {
99
- throw new Error(
100
- `[McpToolCaller] Tool "${toolName}" returned non-JSON: ${text.slice(0, 200)}`
101
- );
102
- }
103
-
104
- if ((parsed as any)?.error) {
105
- throw new Error(`[McpToolCaller] Tool "${toolName}" error: ${(parsed as any).error}`);
106
- }
107
-
108
- return parsed;
109
- }
110
-
111
- /** Disconnect from the remote MCP server */
112
- async disconnect(): Promise<void> {
113
- if (this.client) {
114
- await this.client.close();
115
- this.client = null;
116
- }
117
- }
118
-
119
- // ── Connection lifecycle ─────────────────────────────────────────────────
120
-
121
- private async ensureConnected(): Promise<void> {
122
- if (this.client) return;
123
- if (!this.connectPromise) this.connectPromise = this._connect();
124
- await this.connectPromise;
125
- this.connectPromise = null;
126
- }
127
-
128
- private async _connect(): Promise<void> {
129
- const opts = this.options;
130
- this.client = new Client(
131
- { name: opts.clientName ?? 'agent-identity-mcp-caller', version: opts.clientVersion ?? '0.1.0' },
132
- { capabilities: {} }
133
- );
134
-
135
- if (opts.transport === 'http') {
136
- const sseUrl = new URL('/sse', opts.serverUrl);
137
- const headers: Record<string, string> = {};
138
- if (opts.authToken) headers['Authorization'] = `Bearer ${opts.authToken}`;
139
- await this.client.connect(new SSEClientTransport(sseUrl, { headers }));
140
- } else {
141
- await this.client.connect(
142
- new StdioClientTransport({
143
- command: opts.command,
144
- args: opts.args ?? [],
145
- env: opts.env,
146
- })
147
- );
148
- }
149
- }
150
- }